Scripts/Instance: The Stonecore

(cherry picked from commit 50bf6cad6a)
This commit is contained in:
Mihapro
2014-10-25 17:37:55 +02:00
committed by DDuarte
parent efaf82a239
commit e5e8da85a1
10 changed files with 3155 additions and 0 deletions

View File

@@ -9,6 +9,13 @@
set(scripts_STAT_SRCS
${scripts_STAT_SRCS}
Maelstrom/kezan.cpp
Maelstrom/Stonecore/instance_stonecore.cpp
Maelstrom/Stonecore/stonecore.cpp
Maelstrom/Stonecore/stonecore.h
Maelstrom/Stonecore/boss_corborus.cpp
Maelstrom/Stonecore/boss_slabhide.cpp
Maelstrom/Stonecore/boss_ozruk.cpp
Maelstrom/Stonecore/boss_high_priestess_azil.cpp
)
message(" -> Prepared: The Maelstrom")

View File

@@ -0,0 +1,319 @@
/*
* Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "CreatureGroups.h"
#include "stonecore.h"
// TO-DO:
// Find heroic sniffs and script spawning Crystal Shards on heroic mode.
enum Spells
{
// Corborus intro
SPELL_TWILIGHT_DOCUMENTS = 93167,
SPELL_RING_WYRM_CHARGE = 81237,
SPELL_DOOR_BREAK = 81232, // cast by World Trigger 22515
// Corborus boss
SPELL_DAMPENING_WAVE = 82415,
SPELL_CRYSTAL_BARRAGE = 86881, // 81638 triggers 81637
// SPELL_CRYSTAL_BARRAGE_SHARD = 92012, // heroic only, summons Crystal Shard (TO-DO!)
SPELL_CLEAR_ALL_DEBUFFS = 34098,
SPELL_SUBMERGE = 81629,
SPELL_TRASHING_CHARGE_TELEPORT = 81839, // triggers 81864
// SPELL_TRASHING_CHARGE_TELEPORT_2= 81838, // dummy, targets all players, threat update packet follows
SPELL_SUMMON_TRASHING_CHARGE = 81816,
SPELL_TRASHING_CHARGE_VISUAL = 81801, // cast time 3.5 sec
SPELL_TRASHING_CHARGE_EFFECT = 81828, // 40 yard radius
SPELL_EMERGE = 81948,
// Rock Borer npc (43917)
SPELL_ROCK_BORER_EMERGE = 82185,
SPELL_ROCK_BORE = 80028,
};
enum NPCs
{
NPC_TRASHING_CHARGE = 43743,
// NPC_CRYSTAL_SHARD = 49267, // 49473
};
enum Events
{
EVENT_NONE,
// Corborus intro
EVENT_CORBORUS_CHARGE,
EVENT_CORBORUS_KNOCKBACK,
EVENT_CORBORUS_FACEPLAYERS,
// Corborus boss
EVENT_DAMPENING_WAVE,
EVENT_CRYSTAL_BARRAGE,
EVENT_SUBMERGE,
EVENT_TELEPORT,
EVENT_TRASHING_CHARGE,
EVENT_SUMMON_BEETLE,
EVENT_EMERGE,
EVENT_ATTACK,
// Rock Borer
EVENT_EMERGED,
EVENT_ROCK_BORE,
};
class boss_corborus : public CreatureScript
{
public:
boss_corborus() : CreatureScript("boss_corborus") { }
struct boss_corborusAI : public BossAI
{
boss_corborusAI(Creature* creature) : BossAI(creature, DATA_CORBORUS)
{
stateIntro = NOT_STARTED;
}
void Reset() override
{
_Reset();
countTrashingCharge = 0;
events.ScheduleEvent(EVENT_DAMPENING_WAVE, 10000);
events.ScheduleEvent(EVENT_CRYSTAL_BARRAGE, 15000);
events.ScheduleEvent(EVENT_SUBMERGE, 36000);
}
void DoAction(int32 action) override
{
switch (action)
{
case ACTION_CORBORUS_INTRO: // Executes Corborus intro event
{
if (stateIntro != NOT_STARTED)
return;
stateIntro = IN_PROGRESS;
if (Creature* Millhouse = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_MILLHOUSE_MANASTORM)))
{
Millhouse->InterruptNonMeleeSpells(true);
Millhouse->RemoveAllAuras();
Millhouse->HandleEmoteCommand(EMOTE_ONESHOT_KNOCKDOWN);
}
events.ScheduleEvent(EVENT_CORBORUS_CHARGE, 1000);
break;
}
default:
break;
}
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim() && stateIntro != IN_PROGRESS)
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_CORBORUS_CHARGE:
// Face Millhouse and other mobs
instance->SetData(DATA_MILLHOUSE_EVENT_FACE, 0);
// Open rock gate and cast visual from nearby worldtrigger
instance->HandleGameObject(instance->GetGuidData(GAMEOBJECT_CORBORUS_ROCKDOOR), true);
if (Creature* worldtrigger = me->FindNearestCreature(NPC_WORLDTRIGGER, 60.0f))
worldtrigger->CastSpell(worldtrigger, SPELL_DOOR_BREAK, true);
// Make Corborus charge
me->CastSpell(me, SPELL_RING_WYRM_CHARGE, true);
events.ScheduleEvent(EVENT_CORBORUS_KNOCKBACK, 1000);
break;
case EVENT_CORBORUS_KNOCKBACK:
// Spawn Twilight Documents (quest gameobject)
if (Creature* Millhouse = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_MILLHOUSE_MANASTORM)))
Millhouse->CastSpell(Millhouse, SPELL_TWILIGHT_DOCUMENTS, true);
// Knockback Millhouse and other mobs
instance->SetData(DATA_MILLHOUSE_EVENT_KNOCKBACK, 0);
events.ScheduleEvent(EVENT_CORBORUS_FACEPLAYERS, 2000);
break;
case EVENT_CORBORUS_FACEPLAYERS:
// Face Corborus to players and set new home position
me->SetFacingTo(3.176499f);
me->SetHomePosition(1154.55f, 878.843f, 284.963f, 3.176499f);
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC);
// Despawn Millhouse and all trash
instance->SetData(DATA_MILLHOUSE_EVENT_DESPAWN, 0);
stateIntro = DONE;
break;
case EVENT_DAMPENING_WAVE:
DoCastVictim(SPELL_DAMPENING_WAVE);
events.ScheduleEvent(EVENT_DAMPENING_WAVE, 15000);
break;
case EVENT_CRYSTAL_BARRAGE:
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true))
DoCast(target, SPELL_CRYSTAL_BARRAGE);
events.ScheduleEvent(EVENT_CRYSTAL_BARRAGE, 10000);
break;
case EVENT_SUBMERGE:
events.RescheduleEvent(EVENT_DAMPENING_WAVE, 35000);
events.RescheduleEvent(EVENT_CRYSTAL_BARRAGE, 30000);
events.RescheduleEvent(EVENT_SUBMERGE, 100000);
me->SetReactState(REACT_PASSIVE);
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
DoCast(me, SPELL_CLEAR_ALL_DEBUFFS);
me->AttackStop();
DoCast(me, SPELL_SUBMERGE);
countTrashingCharge = 0;
events.ScheduleEvent(EVENT_TELEPORT, 500);
break;
case EVENT_TELEPORT:
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true))
DoCast(target, SPELL_TRASHING_CHARGE_TELEPORT);
countTrashingCharge += 1;
if (countTrashingCharge <= 4)
events.ScheduleEvent(EVENT_TRASHING_CHARGE, 1000);
else
events.ScheduleEvent(EVENT_EMERGE, 2500);
break;
case EVENT_TRASHING_CHARGE:
DoCast(me, SPELL_SUMMON_TRASHING_CHARGE);
DoCast(me, SPELL_TRASHING_CHARGE_VISUAL);
events.ScheduleEvent(EVENT_TELEPORT, 5000);
break;
case EVENT_EMERGE:
me->RemoveAllAuras();
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
DoCast(me, SPELL_EMERGE);
events.ScheduleEvent(EVENT_ATTACK, 2500);
break;
case EVENT_ATTACK:
me->SetReactState(REACT_AGGRESSIVE);
break;
default:
break;
}
}
DoMeleeAttackIfReady();
}
void JustSummoned(Creature* summon) override
{
if (summon->GetEntry() != NPC_TRASHING_CHARGE)
return;
summon->SetReactState(REACT_PASSIVE);
summon->CastSpell(summon, SPELL_TRASHING_CHARGE_EFFECT);
summon->DespawnOrUnsummon(6000);
}
private:
EncounterState stateIntro;
uint32 countTrashingCharge;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetInstanceAI<boss_corborusAI>(creature);
}
};
// 43391 - Rock Borer
class npc_rock_borer : public CreatureScript
{
public:
npc_rock_borer() : CreatureScript("npc_rock_borer") { }
struct npc_rock_borerAI : public ScriptedAI
{
npc_rock_borerAI(Creature* creature) : ScriptedAI(creature)
{
me->SetDisableGravity(true);
me->SetReactState(REACT_PASSIVE);
events.ScheduleEvent(EVENT_EMERGED, 1200);
events.ScheduleEvent(EVENT_ROCK_BORE, urand(15000, 20000)); // Need sniffs for this timer
}
void IsSummonedBy(Unit* summoner) override
{
me->SetInCombatState(false, summoner);
DoCast(SPELL_ROCK_BORER_EMERGE);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim() && me->GetReactState() != REACT_PASSIVE)
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_EMERGED:
me->RemoveAurasDueToSpell(SPELL_ROCK_BORER_EMERGE);
me->SetReactState(REACT_AGGRESSIVE);
break;
case EVENT_ROCK_BORE:
DoCast(SPELL_ROCK_BORE);
events.ScheduleEvent(EVENT_ROCK_BORE, urand(15000, 20000)); // Need sniffs for this timer
break;
default:
break;
}
}
DoMeleeAttackIfReady();
}
private:
EventMap events;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetInstanceAI<npc_rock_borerAI>(creature);
}
};
void AddSC_boss_corborus()
{
new boss_corborus();
new npc_rock_borer();
}

View File

@@ -0,0 +1,807 @@
/*
* Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "SpellScript.h"
#include "Vehicle.h"
#include "stonecore.h"
enum Spells
{
SPELL_ENERGY_SHIELD = 82858,
SPELL_CURSE_OF_BLOOD = 79345,
SPELL_FORCE_GRIP = 79351,
SPELL_SUMMON_GRAVITY_WELL = 79340,
SPELL_EARTH_FURY_ENERGY_SHIELD = 79050,
// Gravity Well
SPELL_GRAVITY_WELL_VISUAL = 79245,
SPELL_GRAVITY_WELL_AURA_DAMAGE = 79244,
SPELL_GRAVITY_WELL_AURA_PULL = 79333,
SPELL_GRAVITY_WELL_DAMAGE = 79249,
SPELL_GRAVITY_WELL_PULL = 79332,
// Fury of Earth phase
SPELL_EARTH_FURY_CASTING_VISUAL = 79002,
SPELL_SEISMIC_SHARD_SUMMON_1 = 86860,
SPELL_SEISMIC_SHARD_SUMMON_2 = 86858,
SPELL_SEISMIC_SHARD_SUMMON_3 = 86856,
SPELL_SEISMIC_SHARD_VISUAL = 79009,
SPELL_SEISMIC_SHARD_PREPARE = 86862,
SPELL_SEISMIC_SHARD_TARGETING = 80511,
SPELL_SEISMIC_SHARD_LAUNCH = 79015,
SPELL_SEISMIC_SHARD_MISSLE = 79014,
SPELL_EJECT_ALL_PASSENGERS = 68576,
// Add wave spells
SPELL_SUMMON_WAVE_SOUTH = 79200,
SPELL_SUMMON_WAVE_WEST = 79196,
SPELL_SUMMON_ADD_SOUTH = 79193,
SPELL_SUMMON_ADD_WEST = 79199,
};
enum NPCs
{
NPC_DEVOUT_FOLLOWER = 42428,
NPC_SEISMIC_SHARD = 42355,
};
enum Texts
{
SAY_AGGRO = 0,
SAY_PHASE_TWO = 1,
SAY_DEATH = 2,
};
enum Events
{
EVENT_NONE,
EVENT_INTRO_MOVE,
EVENT_CURSE_OF_BLOOD,
EVENT_FORCE_GRIP,
EVENT_SUMMON_GRAVITY_WELL,
EVENT_ENERGY_SHIELD,
EVENT_EARTH_FURY,
EVENT_SUMMON_WAVE_SOUTH,
EVENT_SUMMON_WAVE_WEST,
EVENT_GRAVITY_WELL_AURA_DAMAGE,
EVENT_GRAVITY_WELL_AURA_PULL,
// Phase 2: Fury of Earth
EVENT_EARTH_FURY_FLY_UP,
EVENT_EARTH_FURY_FLY_ABOVE_PLATFORM,
EVENT_EARTH_FURY_CHECK_SEAT0,
EVENT_EARTH_FURY_LAUNCH_SHARD,
EVENT_EARTH_FURY_FLY_DOWN,
EVENT_START_ATTACK,
EVENT_LAUNCH,
EVENT_SEISMIC_SHARD_MOUNT
};
enum EventGroups
{
EVENT_GROUP_PHASE_ONE,
EVENT_GROUP_ADDS,
};
enum Points
{
POINT_NONE,
POINT_INTRO_MOVE,
POINT_FLY_UP,
POINT_ABOVE_PLATFORM,
POINT_PLATFORM,
POINT_GROUND,
};
Position const GroundPos = { 1331.82f, 980.314f, 207.542f };
Position const AbovePlatformPos = { 1336.21f, 960.813f, 215.0f };
// TO-DO:
// - Find out why NPCs summoned by boss are usually two times bigger than their normal size.
// - Find more sniffs and script Force Grip spell (79351)
class boss_high_priestess_azil : public CreatureScript
{
public:
boss_high_priestess_azil() : CreatureScript("boss_high_priestess_azil") { }
struct boss_high_priestess_azilAI : public BossAI
{
boss_high_priestess_azilAI(Creature* creature) : BossAI(creature, DATA_HIGH_PRIESTESS_AZIL), vehicle(creature->GetVehicleKit())
{
ASSERT(vehicle);
}
Vehicle* vehicle;
void Reset() override
{
_Reset();
me->SetCanFly(false);
me->SetDisableGravity(false);
me->SetReactState(REACT_PASSIVE);
events.ScheduleEvent(EVENT_INTRO_MOVE, 2000);
events.ScheduleEvent(EVENT_CURSE_OF_BLOOD, 6000, EVENT_GROUP_PHASE_ONE);
events.ScheduleEvent(EVENT_FORCE_GRIP, urand(8000,10000), EVENT_GROUP_PHASE_ONE);
events.ScheduleEvent(EVENT_SUMMON_GRAVITY_WELL, 16000, EVENT_GROUP_PHASE_ONE);
events.ScheduleEvent(EVENT_ENERGY_SHIELD, urand(35000,36000));
events.ScheduleEvent(EVENT_SUMMON_WAVE_SOUTH, 0);
events.ScheduleEvent(EVENT_SUMMON_WAVE_WEST, 40000);
}
void EnterCombat(Unit* /*victim*/) override
{
_EnterCombat();
DoCast(SPELL_ENERGY_SHIELD);
Talk(SAY_AGGRO);
}
void JustDied(Unit* killer) override
{
me->Say(SAY_DEATH);
}
/*
void PassengerBoarded(Unit* who, int8 seatId, bool apply) override
{
if (!apply || who->GetEntry() != NPC_SEISMIC_SHARD)
return;
Movement::MoveSplineInit init(who);
init.DisableTransportPathTransformations();
if (seatId == 0)
init.MoveTo(12.13748f, 0.0f, 2.442475f);
else if (seatId == 1)
init.MoveTo(12.13748f, 17.5f, 11.19248f);
else
init.MoveTo(12.13748f, -17.5f, 11.19248f);
init.Launch();
}
*/
void MovementInform(uint32 type, uint32 id) override
{
if (type != POINT_MOTION_TYPE && id != POINT_INTRO_MOVE)
return;
switch (id)
{
case POINT_INTRO_MOVE:
me->RemoveAurasDueToSpell(SPELL_ENERGY_SHIELD);
me->SetReactState(REACT_AGGRESSIVE);
break;
case POINT_FLY_UP:
me->SetCanFly(true);
me->SetDisableGravity(true);
events.ScheduleEvent(EVENT_EARTH_FURY_FLY_ABOVE_PLATFORM, 1000);
break;
case POINT_ABOVE_PLATFORM:
me->SetFacingTo(5.218534f);
DoCast(SPELL_EARTH_FURY_CASTING_VISUAL);
DoCast(SPELL_SEISMIC_SHARD_SUMMON_1);
DoCast(SPELL_SEISMIC_SHARD_SUMMON_2);
DoCast(SPELL_SEISMIC_SHARD_SUMMON_3);
events.ScheduleEvent(EVENT_EARTH_FURY_CHECK_SEAT0, 6700);
break;
case POINT_GROUND:
DoCast(SPELL_EJECT_ALL_PASSENGERS);
me->SetCanFly(false);
me->SetDisableGravity(false);
me->SetReactState(REACT_AGGRESSIVE);
// Find more sniffs to correct these timers, this was copied from Reset() void.
events.ScheduleEvent(EVENT_CURSE_OF_BLOOD, 6000, EVENT_GROUP_PHASE_ONE);
events.ScheduleEvent(EVENT_FORCE_GRIP, urand(8000, 10000), EVENT_GROUP_PHASE_ONE);
events.ScheduleEvent(EVENT_SUMMON_GRAVITY_WELL, 16000, EVENT_GROUP_PHASE_ONE);
break;
default:
break;
}
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_INTRO_MOVE:
me->GetMotionMaster()->MoveJump(GroundPos, me->GetSpeed(MOVE_FLIGHT), 1.918408f, POINT_INTRO_MOVE);
break;
case EVENT_CURSE_OF_BLOOD:
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true))
DoCast(target, SPELL_CURSE_OF_BLOOD);
events.ScheduleEvent(EVENT_CURSE_OF_BLOOD, urand(13000, 15000), EVENT_GROUP_PHASE_ONE);
break;
case EVENT_FORCE_GRIP:
DoCastVictim(SPELL_FORCE_GRIP);
events.ScheduleEvent(EVENT_CURSE_OF_BLOOD, urand(13000, 15000), EVENT_GROUP_PHASE_ONE);
break;
case EVENT_SUMMON_GRAVITY_WELL:
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true))
DoCast(target, SPELL_SUMMON_GRAVITY_WELL);
events.ScheduleEvent(EVENT_SUMMON_GRAVITY_WELL, urand(13000, 15000), EVENT_GROUP_PHASE_ONE);
break;
case EVENT_ENERGY_SHIELD:
events.CancelEventGroup(EVENT_GROUP_PHASE_ONE);
DoCast(SPELL_EARTH_FURY_ENERGY_SHIELD);
events.ScheduleEvent(EVENT_EARTH_FURY, 0);
break;
case EVENT_EARTH_FURY:
countSeismicShard = 3;
me->SetReactState(REACT_PASSIVE);
me->SetFacingTo(5.862942f);
events.ScheduleEvent(EVENT_EARTH_FURY_FLY_UP, 1600);
break;
case EVENT_EARTH_FURY_FLY_UP:
Talk(SAY_PHASE_TWO);
me->GetMotionMaster()->MovePoint(POINT_FLY_UP, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ() + 5);
break;
case EVENT_EARTH_FURY_FLY_ABOVE_PLATFORM:
me->GetMotionMaster()->MovePoint(POINT_ABOVE_PLATFORM, AbovePlatformPos);
break;
case EVENT_EARTH_FURY_CHECK_SEAT0:
if (!vehicle->GetPassenger(0))
DoCast(SPELL_SEISMIC_SHARD_PREPARE);
events.ScheduleEvent(EVENT_EARTH_FURY_LAUNCH_SHARD, 1800);
break;
case EVENT_EARTH_FURY_LAUNCH_SHARD:
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true))
{
me->SetFacingToObject(target);
DoCast(target, SPELL_SEISMIC_SHARD_TARGETING);
DoCast(SPELL_SEISMIC_SHARD_LAUNCH);
countSeismicShard -= 1;
}
events.ScheduleEvent(countSeismicShard > 0 ? EVENT_EARTH_FURY_CHECK_SEAT0 : EVENT_EARTH_FURY_FLY_DOWN, 4800);
break;
case EVENT_EARTH_FURY_FLY_DOWN:
{
me->RemoveAurasDueToSpell(SPELL_EARTH_FURY_CASTING_VISUAL);
me->RemoveAurasDueToSpell(SPELL_EARTH_FURY_ENERGY_SHIELD);
Position pos = me->GetPosition();
pos.m_positionZ = me->GetMap()->GetHeight(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ());
me->GetMotionMaster()->MovePoint(POINT_GROUND, pos);
break;
}
case EVENT_SUMMON_WAVE_SOUTH:
if (Creature* worldtrigger = me->FindNearestCreature(NPC_WORLDTRIGGER, 150.0f))
worldtrigger->CastSpell(worldtrigger, SPELL_SUMMON_WAVE_SOUTH);
events.ScheduleEvent(EVENT_SUMMON_WAVE_SOUTH, 12000);
break;
case EVENT_SUMMON_WAVE_WEST:
if (Creature* worldtrigger = me->FindNearestCreature(NPC_WORLDTRIGGER, 150.0f))
worldtrigger->CastSpell(worldtrigger, SPELL_SUMMON_WAVE_WEST);
events.ScheduleEvent(EVENT_SUMMON_WAVE_WEST, 20000);
break;
default:
break;
}
}
DoMeleeAttackIfReady();
}
private:
uint8 countSeismicShard;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetInstanceAI<boss_high_priestess_azilAI>(creature);
}
};
// 42428 - Devout Follower
class npc_devout_follower : public CreatureScript
{
public:
npc_devout_follower() : CreatureScript("npc_devout_follower") { }
struct npc_devout_followerAI : public ScriptedAI
{
npc_devout_followerAI(Creature* creature) : ScriptedAI(creature) { }
void IsSummonedBy(Unit* summoner) override
{
if (summoner->GetEntry() != NPC_WORLDTRIGGER)
return;
if (Unit* target = me->SelectNearestPlayer(200.0f))
{
me->AddThreat(target, 0.0f);
me->SetInCombatWith(target);
target->SetInCombatWith(me);
DoStartMovement(target);
me->Attack(target, true);
}
else
me->GetMotionMaster()->MovePoint(POINT_NONE, summoner->GetPosition());
}
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetInstanceAI<npc_devout_followerAI>(creature);
}
};
// 42499 - Gravity Well
class npc_gravity_well : public CreatureScript
{
public:
npc_gravity_well() : CreatureScript("npc_gravity_well") { }
struct npc_gravity_wellAI : public ScriptedAI
{
npc_gravity_wellAI(Creature* creature) : ScriptedAI(creature)
{
me->SetReactState(REACT_PASSIVE);
DoCast(SPELL_GRAVITY_WELL_VISUAL);
events.ScheduleEvent(EVENT_GRAVITY_WELL_AURA_DAMAGE, 3200);
events.ScheduleEvent(EVENT_GRAVITY_WELL_AURA_PULL, 4500);
if (!me->GetMap()->IsHeroic())
me->DespawnOrUnsummon(23200);
}
void KilledUnit(Unit* victim) override
{
if (victim->GetEntry() != NPC_DEVOUT_FOLLOWER)
return;
me->SetObjectScale(me->GetObjectScale() - 0.25f);
if (me->GetObjectScale() <= 0.0f)
me->DespawnOrUnsummon(1000);
}
void UpdateAI(uint32 diff) override
{
events.Update(diff);
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_GRAVITY_WELL_AURA_DAMAGE:
me->RemoveAurasDueToSpell(SPELL_GRAVITY_WELL_VISUAL);
DoCast(SPELL_GRAVITY_WELL_AURA_DAMAGE);
break;
case EVENT_GRAVITY_WELL_AURA_PULL:
DoCast(SPELL_GRAVITY_WELL_AURA_PULL);
break;
default:
break;
}
}
}
private:
EventMap events;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetInstanceAI<npc_gravity_wellAI>(creature);
}
};
// 42355 - Seismic Shard
class npc_seismic_shard : public CreatureScript
{
public:
npc_seismic_shard() : CreatureScript("npc_seismic_shard") { }
struct npc_seismic_shardAI : public ScriptedAI
{
npc_seismic_shardAI(Creature* creature) : ScriptedAI(creature)
{
instance = creature->GetInstanceScript();
me->SetDisableGravity(true);
me->SetReactState(REACT_PASSIVE);
DoCast(SPELL_SEISMIC_SHARD_VISUAL);
Movement::MoveSplineInit init(me);
FillPath(me->GetPosition(), init.Path());
init.SetFly();
init.Launch();
events.ScheduleEvent(EVENT_SEISMIC_SHARD_MOUNT, 2400);
}
void UpdateAI(uint32 diff) override
{
events.Update(diff);
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_SEISMIC_SHARD_MOUNT:
if (Creature* highPriestAzil = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_HIGH_PRIESTESS_AZIL)))
if (Vehicle* vehicle = highPriestAzil->GetVehicleKit())
me->EnterVehicle(highPriestAzil, vehicle->GetNextEmptySeat(0, false)->first);
break;
default:
break;
}
}
}
private:
void FillPath(Position const& pos, Movement::PointsArray& path)
{
G3D::Vector3 point;
point.x = pos.GetPositionX();
point.y = pos.GetPositionY();
point.z = pos.GetPositionZ();
point.x -= 1.0f;
path.push_back(point);
point.x += 1.0f;
path.push_back(point);
point.z += 25.0f;
path.push_back(point);
path.push_back(point);
}
InstanceScript* instance;
EventMap events;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetInstanceAI<npc_seismic_shardAI>(creature);
}
};
// 79200 - Summon Follower
class spell_summon_wave_south : public SpellScriptLoader
{
public:
spell_summon_wave_south() : SpellScriptLoader("spell_summon_wave_south") { }
class spell_summon_wave_south_SpellScript : public SpellScript
{
PrepareSpellScript(spell_summon_wave_south_SpellScript);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
if (!sSpellMgr->GetSpellInfo(SPELL_SUMMON_ADD_SOUTH))
return false;
return true;
}
void HandleScript(SpellEffIndex /*effIndex*/)
{
Unit* caster = GetCaster();
for (uint8 i = 0; i < 3; i++)
GetCaster()->CastSpell(GetCaster(), SPELL_SUMMON_ADD_SOUTH, true);
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_summon_wave_south_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
}
};
SpellScript* GetSpellScript() const override
{
return new spell_summon_wave_south_SpellScript();
}
};
// 79196 - Summon Follower
class spell_summon_wave_west : public SpellScriptLoader
{
public:
spell_summon_wave_west() : SpellScriptLoader("spell_summon_wave_west") { }
class spell_summon_wave_west_SpellScript : public SpellScript
{
PrepareSpellScript(spell_summon_wave_west_SpellScript);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
if (!sSpellMgr->GetSpellInfo(SPELL_SUMMON_ADD_WEST))
return false;
return true;
}
void HandleScript(SpellEffIndex /*effIndex*/)
{
Unit* caster = GetCaster();
for (uint8 i = 0; i < 10; i++)
GetCaster()->CastSpell(GetCaster(), SPELL_SUMMON_ADD_WEST, true);
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_summon_wave_west_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
}
};
SpellScript* GetSpellScript() const override
{
return new spell_summon_wave_west_SpellScript();
}
};
// 79251 - Gravity Well (casts damage spell on units within 10 yards)
class PlayerPetOrDevoutFollowerCheck
{
public:
bool operator()(WorldObject* object) const
{
// Valid targets are players, pets and Devout Followers
if (Creature* creature = object->ToCreature())
return (!creature->ToPet() && object->GetEntry() != NPC_DEVOUT_FOLLOWER);
return (!object->ToPlayer());
}
};
class spell_gravity_well_damage_nearby : public SpellScriptLoader
{
public:
spell_gravity_well_damage_nearby() : SpellScriptLoader("spell_gravity_well_damage_nearby") { }
class spell_gravity_well_damage_nearby_SpellScript : public SpellScript
{
PrepareSpellScript(spell_gravity_well_damage_nearby_SpellScript);
void SetRadiusMod()
{
GetSpell()->SetSpellValue(SPELLVALUE_RADIUS_MOD, int32(GetCaster()->GetObjectScale() * 10000 * 2 / 3));
}
void FilterTargets(std::list<WorldObject*>& unitList)
{
unitList.remove_if(PlayerPetOrDevoutFollowerCheck());
}
void HandleScript(SpellEffIndex /*effIndex*/)
{
GetCaster()->CastSpell(GetHitUnit(), SPELL_GRAVITY_WELL_DAMAGE, true);
}
void Register() override
{
BeforeCast += SpellCastFn(spell_gravity_well_damage_nearby_SpellScript::SetRadiusMod);
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_gravity_well_damage_nearby_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
OnEffectHitTarget += SpellEffectFn(spell_gravity_well_damage_nearby_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
}
};
SpellScript* GetSpellScript() const override
{
return new spell_gravity_well_damage_nearby_SpellScript();
}
};
// 79249 - Gravity Well (damage)
class spell_gravity_well_damage : public SpellScriptLoader
{
public:
spell_gravity_well_damage() : SpellScriptLoader("spell_gravity_well_damage") { }
class spell_gravity_well_damage_SpellScript : public SpellScript
{
PrepareSpellScript(spell_gravity_well_damage_SpellScript);
void CalculateDamage(SpellEffIndex /*effIndex*/)
{
Unit* target = GetHitUnit();
if (!target)
return;
float distance = GetCaster()->GetDistance2d(target);
if (target->GetEntry() == NPC_DEVOUT_FOLLOWER)
SetHitDamage(int32(200000 - (1000 * distance))); //need more research on this formula, damage values from sniffs: 189264, 190318, 190478, 196134, 197672, 199735
else
SetHitDamage(int32(4000 - (200 * distance)));
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_gravity_well_damage_SpellScript::CalculateDamage, EFFECT_0, SPELL_EFFECT_SCHOOL_DAMAGE);
}
};
SpellScript* GetSpellScript() const override
{
return new spell_gravity_well_damage_SpellScript();
}
};
// 79332 - Gravity Well (pull units within 10 yards)
class PulledRecentlyCheck
{
public:
bool operator()(WorldObject* object) const
{
return (object->ToUnit() && object->ToUnit()->HasAura(SPELL_GRAVITY_WELL_PULL));
}
};
class spell_gravity_well_pull : public SpellScriptLoader
{
public:
spell_gravity_well_pull() : SpellScriptLoader("spell_gravity_well_pull") { }
class spell_gravity_well_pull_SpellScript : public SpellScript
{
PrepareSpellScript(spell_gravity_well_pull_SpellScript);
void SetRadiusMod()
{
GetSpell()->SetSpellValue(SPELLVALUE_RADIUS_MOD, int32(GetCaster()->GetObjectScale() * 10000 * 2 / 3));
}
void FilterTargets(std::list<WorldObject*>& unitList)
{
unitList.remove_if(PulledRecentlyCheck());
}
void Register() override
{
BeforeCast += SpellCastFn(spell_gravity_well_pull_SpellScript::SetRadiusMod);
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_gravity_well_pull_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
}
};
SpellScript* GetSpellScript() const override
{
return new spell_gravity_well_pull_SpellScript();
}
};
// 86862 - Seismic Shard (forces target to cast 86863)
class spell_seismic_shard_prepare : public SpellScriptLoader
{
public:
spell_seismic_shard_prepare() : SpellScriptLoader("spell_seismic_shard_prepare") { }
class spell_seismic_shard_prepare_SpellScript : public SpellScript
{
PrepareSpellScript(spell_seismic_shard_prepare_SpellScript);
void SetTarget(WorldObject*& target)
{
target = GetCaster()->FindNearestCreature(NPC_SEISMIC_SHARD, 50.0f);
}
void Register() override
{
OnObjectTargetSelect += SpellObjectTargetSelectFn(spell_seismic_shard_prepare_SpellScript::SetTarget, EFFECT_0, TARGET_UNIT_NEARBY_ENTRY);
}
};
SpellScript* GetSpellScript() const override
{
return new spell_seismic_shard_prepare_SpellScript();
}
};
// 86863 - Seismic Shard (moves shard to seat 0)
class spell_seismic_shard_change_seat : public SpellScriptLoader
{
public:
spell_seismic_shard_change_seat() : SpellScriptLoader("spell_seismic_shard_change_seat") { }
class spell_seismic_shard_change_seat_SpellScript : public SpellScript
{
PrepareSpellScript(spell_seismic_shard_change_seat_SpellScript);
void SetTarget(WorldObject*& target)
{
if (InstanceScript* instance = GetCaster()->GetInstanceScript())
target = ObjectAccessor::GetCreature(*GetCaster(), instance->GetGuidData(DATA_HIGH_PRIESTESS_AZIL));
}
void ChangeSeat(SpellEffIndex /*effIndex*/)
{
GetCaster()->ExitVehicle();
if (GetHitUnit()->IsVehicle())
GetCaster()->EnterVehicle(GetHitUnit(), 0);
}
void Register() override
{
OnObjectTargetSelect += SpellObjectTargetSelectFn(spell_seismic_shard_change_seat_SpellScript::SetTarget, EFFECT_0, TARGET_UNIT_NEARBY_ENTRY);
OnEffectHitTarget += SpellEffectFn(spell_seismic_shard_change_seat_SpellScript::ChangeSeat, EFFECT_0, SPELL_EFFECT_APPLY_AURA);
}
};
SpellScript* GetSpellScript() const override
{
return new spell_seismic_shard_change_seat_SpellScript();
}
};
// 79015 - Seismic Shard (launches shard)
class spell_seismic_shard : public SpellScriptLoader
{
public:
spell_seismic_shard() : SpellScriptLoader("spell_seismic_shard") { }
class spell_seismic_shard_SpellScript : public SpellScript
{
PrepareSpellScript(spell_seismic_shard_SpellScript);
void HandleScript(SpellEffIndex /*effIndex*/)
{
Creature* target = GetHitUnit()->ToCreature();
if (!target)
return;
target->ExitVehicle();
DynamicObject* dynamicObject = GetCaster()->GetDynObject(SPELL_SEISMIC_SHARD_TARGETING);
target->CastSpell(dynamicObject->GetPositionX(), dynamicObject->GetPositionY(), dynamicObject->GetPositionZ(), SPELL_SEISMIC_SHARD_MISSLE, true);
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_seismic_shard_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
}
};
SpellScript* GetSpellScript() const override
{
return new spell_seismic_shard_SpellScript();
}
};
void AddSC_boss_high_priestess_azil()
{
new boss_high_priestess_azil();
new npc_devout_follower();
new npc_gravity_well();
new npc_seismic_shard();
new spell_summon_wave_south();
new spell_summon_wave_west();
new spell_gravity_well_damage_nearby();
new spell_gravity_well_damage();
new spell_gravity_well_pull();
new spell_seismic_shard_prepare();
new spell_seismic_shard_change_seat();
new spell_seismic_shard();
}

View File

@@ -0,0 +1,287 @@
/*
* Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "SpellScript.h"
#include "SpellAuraEffects.h"
#include "Vehicle.h"
#include "stonecore.h"
enum Spells
{
SPELL_ELEMENTIUM_BULWARK = 78939,
SPELL_GROUND_SLAM = 78903,
SPELL_ELEMENTIUM_SPIKE_SHIELD = 78835,
SPELL_SHATTER = 78807,
SPELL_ENRAGE = 80467,
// Rupture Controller and Rupture
SPELL_RUPTURE = 92393,
// SPELL_RUPTURE_SUMMON_CENTER? = 95669, // summons rupture 8 yards front
// SPELL_RUPTURE_SUMMON_LEFT? = 95348, // summons rupture 3 yards left?
// SPELL_RUPTURE_SUMMON_RIGHT? = 92383, // summons rupture 3 yards right?
SPELL_RUPTURE_DAMAGE = 92381,
};
enum NPCs
{
NPC_BOUNCER_SPIKE = 42189,
NPC_RUPTURE_CONTROLLER = 49597,
NPC_RUPTURE = 49576,
};
enum Texts
{
SAY_AGGRO = 0,
SAY_ELEMENTIUM_BULWARK = 1,
SAY_ELEMENTIUM_SPIKE_SHIELD = 2,
SAY_ENRAGE = 3,
SAY_DEATH = 4,
};
enum Events
{
EVENT_NONE,
EVENT_ELEMENTIUM_BULWARK,
EVENT_GROUND_SLAM,
EVENT_ELEMENTIUM_SPIKE_SHIELD,
EVENT_SHATTER,
EVENT_ENRAGE,
EVENT_START_ATTACK,
};
// TO-DO:
// - Find heroic sniffs and spawn Ruptures using spells commented above.
// - Make Bouncer Spikes enter ozruk without jump animation.
class boss_ozruk : public CreatureScript
{
public:
boss_ozruk() : CreatureScript("boss_ozruk") { }
struct boss_ozrukAI : public BossAI
{
boss_ozrukAI(Creature* creature) : BossAI(creature, DATA_OZRUK) { }
void Reset() override
{
_Reset();
me->SetReactState(REACT_AGGRESSIVE);
events.ScheduleEvent(EVENT_ELEMENTIUM_BULWARK, 5000);
events.ScheduleEvent(EVENT_GROUND_SLAM, 10000);
events.ScheduleEvent(EVENT_ELEMENTIUM_SPIKE_SHIELD, 13000);
RemoveBouncerSpikes();
}
void EnterCombat(Unit* /*victim*/) override
{
_EnterCombat();
Talk(SAY_AGGRO);
}
void JustSummoned(Creature* summon) override
{
if (summon->GetEntry() != NPC_RUPTURE_CONTROLLER)
return;
summon->SetReactState(REACT_PASSIVE);
summon->CastSpell(summon, SPELL_RUPTURE, true);
summon->DespawnOrUnsummon(10000);
}
void DamageTaken(Unit* /*attacker*/, uint32 &damage) override
{
if (!me->HealthBelowPctDamaged(25, damage) || me->HasAura(SPELL_ENRAGE))
return;
DoCast(me, SPELL_ENRAGE);
me->Say(SAY_ENRAGE);
}
void JustDied(Unit* killer) override
{
me->Say(SAY_DEATH, killer); // receiver is the killer, sniff source!
RemoveBouncerSpikes();
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING) || me->HasAura(SPELL_ELEMENTIUM_SPIKE_SHIELD))
return;
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_ELEMENTIUM_BULWARK:
DoCast(me, SPELL_ELEMENTIUM_BULWARK);
Talk(SAY_ELEMENTIUM_BULWARK);
break;
case EVENT_GROUND_SLAM:
me->SetReactState(REACT_PASSIVE);
me->AttackStop();
DoCast(me, SPELL_GROUND_SLAM);
events.ScheduleEvent(EVENT_START_ATTACK, 4600);
break;
case EVENT_ELEMENTIUM_SPIKE_SHIELD:
DoCast(me, SPELL_ELEMENTIUM_SPIKE_SHIELD);
Talk(SAY_ELEMENTIUM_SPIKE_SHIELD);
events.ScheduleEvent(EVENT_SHATTER, 10000);
break;
case EVENT_SHATTER:
RemoveBouncerSpikes();
me->SetReactState(REACT_PASSIVE);
me->AttackStop();
DoCast(me, SPELL_SHATTER);
events.ScheduleEvent(EVENT_START_ATTACK, 4600);
// Spells are cast in same order everytime after Shatter, so we schedule them here
events.ScheduleEvent(EVENT_ELEMENTIUM_BULWARK, urand(3000,4000));
events.ScheduleEvent(EVENT_GROUND_SLAM, urand(7000,9000));
events.ScheduleEvent(EVENT_ELEMENTIUM_SPIKE_SHIELD, urand(10000,12000));
break;
case EVENT_START_ATTACK:
me->SetReactState(REACT_AGGRESSIVE);
break;
default:
break;
}
}
DoMeleeAttackIfReady();
}
void RemoveBouncerSpikes()
{
Vehicle* vehicle = me->GetVehicleKit();
if (!vehicle)
return;
for (uint8 i = 0; i < vehicle->GetAvailableSeatCount(); i++)
if (Unit* passenger = vehicle->GetPassenger(i))
if (Creature* creature = passenger->ToCreature())
creature->RemoveFromWorld();
}
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetInstanceAI<boss_ozrukAI>(creature);
}
};
// 92393 - Rupture
class spell_rupture : public SpellScriptLoader
{
public:
spell_rupture() : SpellScriptLoader("spell_rupture") { }
class spell_rupture_AuraScript : public AuraScript
{
PrepareAuraScript(spell_rupture_AuraScript);
void HandleEffectPeriodic(AuraEffect const* aurEff)
{
Unit* caster = GetCaster();
float dist = aurEff->GetTickNumber() * 8.0f;
// probably hack, should use spells (see Spells enum above)
Position pos = caster->GetNearPosition(dist, 0.0f);
SummonRupture(caster, pos);
pos = caster->GetNearPosition(dist, 0.2f);
SummonRupture(caster, pos);
pos = caster->GetNearPosition(dist, -0.2f);
SummonRupture(caster, pos);
}
void SummonRupture(Unit* caster, Position pos)
{
Creature* rupture = caster->SummonCreature(NPC_RUPTURE, pos, TEMPSUMMON_TIMED_DESPAWN, 2500);
if (!rupture)
return;
rupture->SetReactState(REACT_PASSIVE);
rupture->CastSpell(rupture, SPELL_RUPTURE_DAMAGE, true);
}
void Register()
{
OnEffectPeriodic += AuraEffectPeriodicFn(spell_rupture_AuraScript::HandleEffectPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL);
}
};
AuraScript* GetAuraScript() const
{
return new spell_rupture_AuraScript();
}
};
// 78835 - Elementium Spike Shield
class spell_elementium_spike_shield : public SpellScriptLoader
{
public:
spell_elementium_spike_shield() : SpellScriptLoader("spell_elementium_spike_shield") { }
class spell_elementium_spike_shield_SpellScript : public SpellScript
{
PrepareSpellScript(spell_elementium_spike_shield_SpellScript);
void HandleBouncerSpikes()
{
Unit* caster = GetCaster();
Vehicle* vehicle = caster->GetVehicleKit();
if (!vehicle)
return;
for (uint8 i = 0; i < vehicle->GetAvailableSeatCount(); i++)
if (Creature* summon = caster->SummonCreature(NPC_BOUNCER_SPIKE, caster->GetPosition(), TEMPSUMMON_TIMED_DESPAWN, 10000))
summon->EnterVehicle(caster, i);
}
void Register() override
{
OnCast += SpellCastFn(spell_elementium_spike_shield_SpellScript::HandleBouncerSpikes);
}
};
SpellScript* GetSpellScript() const override
{
return new spell_elementium_spike_shield_SpellScript();
}
};
void AddSC_boss_ozruk()
{
new boss_ozruk();
new spell_rupture();
new spell_elementium_spike_shield();
}

View File

@@ -0,0 +1,599 @@
/*
* Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "SpellScript.h"
#include "stonecore.h"
enum Spells
{
SPELL_FACE_RANDOM_PLAYER = 82530,
// Stalactite Trigger - Trash, On Ground
SPELL_STALACTITE_SUMMON_TRIGGER = 81028,
// Slabhide
SPELL_LAVA_FISSURE = 80803,
SPELL_SAND_BLAST = 80807,
SPELL_STALACTITE_SUMMON = 80656,
// SPELL_COOLDOWN_5S = 95323, Cooldown: Creature Special 1 (5s)?
SPELL_CRYSTAL_STORM = 92305,
SPELL_CRYSTAL_STORM_TRIGGER = 92265,
// Lava Fissure
SPELL_LAVA_FISSURE_CRACK = 80798,
SPELL_LAVA_FISSURE_ERUPTION = 80800,
// Stalactite Trigger - Boss
SPELL_STALACTITE_SHADE = 80654,
SPELL_STALACTITE_MISSLE = 80643,
SPELL_STALACTITE_CREATE = 80647,
};
enum Entries
{
NPC_LAVA_FISSURE = 43242,
NPC_STALACTITE_TRIGGER_GROUND = 43357,
NPC_STALACTITE_TRIGGER = 43159,
GO_STALACTITE = 204337,
};
enum Actions
{
ACTION_STALACTITE_MISSLE,
};
enum Events
{
EVENT_NONE,
// Intro events
EVENT_ROAR_EMOTE,
// Slabhide combat
EVENT_HANDLE_ROCK_WALLS,
EVENT_LAVA_FISSURE,
EVENT_SAND_BLAST,
EVENT_AIR_PHASE,
EVENT_TAKEOFF,
EVENT_STALACTITE,
EVENT_LAND,
EVENT_ATTACK,
// Lava Fissure
EVENT_LAVA_FISSURE_ERUPTION,
// Stalactite Trigger - Boss
EVENT_STALACTITE_MISSLE,
};
enum MovementPoints
{
POINT_NONE,
POINT_SLABHIDE_INTRO,
POINT_SLABHIDE_INTRO_LAND,
POINT_SLABHIDE_MIDDLE,
POINT_SLABHIDE_IN_AIR,
POINT_SLABHIDE_LAND,
};
Position const SlabhideIntroPos = { 1292.27f, 1226.16f, 265.573f };
Position const SlabhideIntroLandPos = { 1292.352f, 1226.478f, 247.6368f, 3.630285f };
Position const SlabhideMiddlePos = { 1280.73f, 1212.31f, 247.3837f };
Position const SlabhideInAirPos = { 1280.73f, 1212.31f, 257.3837f };
Position const SlabhideLandPos = { 1282.7f, 1229.77f, 247.155f, 3.82227f };
class boss_slabhide : public CreatureScript
{
public:
boss_slabhide() : CreatureScript("boss_slabhide") { }
struct boss_slabhideAI : public BossAI
{
boss_slabhideAI(Creature* creature) : BossAI(creature, DATA_SLABHIDE)
{
me->setActive(true);
me->SetCanFly(true);
me->SetDisableGravity(true);
me->SetByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER);
me->SetReactState(REACT_PASSIVE);
instance->SetData(DATA_SLABHIDE_INTRO, NOT_STARTED);
}
void Reset()
{
if (instance->GetData(DATA_SLABHIDE_INTRO) == NOT_STARTED)
return;
_Reset();
DespawnAll();
me->SetCanFly(false);
me->SetDisableGravity(false);
me->RemoveByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER);
me->SetReactState(REACT_AGGRESSIVE);
}
void EnterCombat(Unit* /*victim*/) override
{
_EnterCombat();
events.ScheduleEvent(EVENT_HANDLE_ROCK_WALLS, 4000);
events.ScheduleEvent(EVENT_LAVA_FISSURE, urand(6000, 8000));
events.ScheduleEvent(EVENT_SAND_BLAST, urand(8000, 10000));
events.ScheduleEvent(EVENT_AIR_PHASE, 10000);
}
void JustDied(Unit* /*killer*/) override
{
_JustDied();
// Despawn related npcs and gameobjects
DespawnAll();
}
void DoAction(int32 action) override
{
switch (action)
{
case ACTION_SLABHIDE_INTRO:
{
if (instance->GetData(DATA_SLABHIDE_INTRO) != NOT_STARTED)
return;
instance->SetData(DATA_SLABHIDE_INTRO, IN_PROGRESS);
// Execute Slabhide intro event
me->GetMotionMaster()->MovePoint(POINT_SLABHIDE_INTRO, SlabhideIntroPos);
break;
}
default:
break;
}
}
void MovementInform(uint32 type, uint32 id) override
{
if (type != POINT_MOTION_TYPE && type != EFFECT_MOTION_TYPE)
return;
switch (id)
{
case POINT_SLABHIDE_INTRO:
me->SetFacingTo(SlabhideIntroLandPos.GetOrientation());
me->GetMotionMaster()->MoveLand(POINT_SLABHIDE_INTRO_LAND, SlabhideIntroLandPos);
break;
case POINT_SLABHIDE_INTRO_LAND:
me->SetCanFly(false);
me->SetDisableGravity(false);
me->RemoveByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER);
me->SetHover(false);
me->SetHomePosition(SlabhideIntroLandPos);
me->HandleEmoteCommand(EMOTE_ONESHOT_ROAR);
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
me->SetReactState(REACT_AGGRESSIVE);
instance->SetData(DATA_SLABHIDE_INTRO, DONE);
break;
case POINT_SLABHIDE_MIDDLE:
events.ScheduleEvent(EVENT_TAKEOFF, 100);
break;
case POINT_SLABHIDE_IN_AIR:
events.ScheduleEvent(EVENT_STALACTITE, 400);
break;
case POINT_SLABHIDE_LAND:
//DoCast(SPELL_COOLDOWN_5S); // unknown purpose
events.ScheduleEvent(EVENT_ATTACK, 1200);
break;
default:
break;
}
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_HANDLE_ROCK_WALLS: // Close rock walls
instance->SetData(DATA_SLABHIDE_ROCK_WALL, false);
break;
case EVENT_LAVA_FISSURE:
DoCast(SPELL_LAVA_FISSURE);
events.ScheduleEvent(EVENT_LAVA_FISSURE, urand(6000, 8000));
break;
case EVENT_SAND_BLAST:
DoCast(SPELL_SAND_BLAST);
events.ScheduleEvent(EVENT_SAND_BLAST, urand(8000, 11000));
break;
case EVENT_AIR_PHASE:
events.Reset();
me->SetReactState(REACT_PASSIVE);
me->AttackStop();
me->GetMotionMaster()->MovePoint(POINT_SLABHIDE_MIDDLE, SlabhideMiddlePos);
events.ScheduleEvent(EVENT_AIR_PHASE, 60000);
break;
case EVENT_TAKEOFF:
me->GetMotionMaster()->MoveTakeoff(POINT_SLABHIDE_IN_AIR, SlabhideInAirPos);
break;
case EVENT_STALACTITE:
me->SetCanFly(true);
me->SetDisableGravity(true);
me->SetByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER);
me->SetHover(true);
DoCast(SPELL_STALACTITE_SUMMON);
events.ScheduleEvent(EVENT_LAND, 8000);
break;
case EVENT_LAND:
{
Position pos = me->GetPosition();
pos.m_positionZ = me->GetMap()->GetHeight(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ());
me->GetMotionMaster()->MoveLand(POINT_SLABHIDE_LAND, pos);
break;
}
case EVENT_ATTACK:
me->SetCanFly(false);
me->SetDisableGravity(false);
me->RemoveByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER);
me->SetHover(false);
events.ScheduleEvent(EVENT_LAVA_FISSURE, urand(6000, 8000));
events.ScheduleEvent(EVENT_SAND_BLAST, urand(8000, 10000));
DoCast(SPELL_CRYSTAL_STORM);
me->SetReactState(REACT_AGGRESSIVE);
break;
default:
break;
}
}
DoMeleeAttackIfReady();
}
private:
void DespawnAll()
{
// Despawn stalactite triggers npcs
std::list<Creature*> listStalactiteTrigger;
me->GetCreatureListWithEntryInGrid(listStalactiteTrigger, NPC_STALACTITE_TRIGGER, 200.0f);
if (!listStalactiteTrigger.empty())
for (std::list<Creature*>::const_iterator itr = listStalactiteTrigger.begin(); itr != listStalactiteTrigger.end(); ++itr)
(*itr)->DespawnOrUnsummon();
// Despawn stalactite objects
std::list<GameObject*> listStalactite;
me->GetGameObjectListWithEntryInGrid(listStalactite, GO_STALACTITE, 200.0f);
if (!listStalactite.empty())
for (std::list<GameObject*>::const_iterator itr = listStalactite.begin(); itr != listStalactite.end(); ++itr)
(*itr)->Delete();
}
EventMap events;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetInstanceAI<boss_slabhideAI>(creature);
}
};
// 43242 - Lava Fissure
class npc_lava_fissure : public CreatureScript
{
public:
npc_lava_fissure() : CreatureScript("npc_lava_fissure") { }
struct npc_lava_fissureAI : public ScriptedAI
{
npc_lava_fissureAI(Creature* creature) : ScriptedAI(creature)
{
me->SetReactState(REACT_PASSIVE);
me->CastSpell(me, SPELL_LAVA_FISSURE_CRACK, true);
events.ScheduleEvent(EVENT_LAVA_FISSURE_ERUPTION, 6000);
}
void UpdateAI(uint32 diff) override
{
events.Update(diff);
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_LAVA_FISSURE_ERUPTION:
me->RemoveAurasDueToSpell(SPELL_LAVA_FISSURE_CRACK);
me->CastSpell(me, SPELL_LAVA_FISSURE_ERUPTION, true);
me->DespawnOrUnsummon(14000);
break;
default:
break;
}
}
}
private:
EventMap events;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetInstanceAI<npc_lava_fissureAI>(creature);
}
};
// 43159 - Stalactite Trigger - Boss
class npc_stalactite_trigger : public CreatureScript
{
public:
npc_stalactite_trigger() : CreatureScript("npc_stalactite_trigger") { }
struct npc_stalactite_triggerAI : public ScriptedAI
{
npc_stalactite_triggerAI(Creature* creature) : ScriptedAI(creature)
{
me->SetReactState(REACT_PASSIVE);
me->SetDisableGravity(true);
me->CastSpell(me, SPELL_STALACTITE_SHADE, true);
events.ScheduleEvent(EVENT_STALACTITE_MISSLE, 5600);
}
void UpdateAI(uint32 diff) override
{
events.Update(diff);
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_STALACTITE_MISSLE:
DoCast(SPELL_STALACTITE_MISSLE);
me->DespawnOrUnsummon(11000);
break;
default:
break;
}
}
}
private:
EventMap events;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetInstanceAI<npc_stalactite_triggerAI>(creature);
}
};
// 81035 - Stalactite (check if player is near to summon stalactite)
class NotPlayerCheck
{
public:
bool operator()(WorldObject* object) const
{
return (object->GetTypeId() != TYPEID_PLAYER);
}
};
class spell_s81035_stalactite : public SpellScriptLoader
{
public:
spell_s81035_stalactite() : SpellScriptLoader("spell_s81035_stalactite") { }
class spell_s81035_stalactite_SpellScript : public SpellScript
{
PrepareSpellScript(spell_s81035_stalactite_SpellScript);
void FilterTargets(std::list<WorldObject*>& targets)
{
targets.remove_if(NotPlayerCheck());
}
void SummonStalactiteTrigger()
{
Unit* caster = GetCaster();
caster->CastSpell(caster, SPELL_STALACTITE_SUMMON_TRIGGER, true);
}
void Register() override
{
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_s81035_stalactite_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
OnHit += SpellHitFn(spell_s81035_stalactite_SpellScript::SummonStalactiteTrigger);
}
};
SpellScript* GetSpellScript() const override
{
return new spell_s81035_stalactite_SpellScript();
}
};
// 81028 - Stalactite (summons "Stalactite Trigger - Boss", 20 yard radius)
// 80650 - Stalactite (summons "Stalactite Trigger - Boss", 40 yard radius)
class spell_s81028_s80650_stalactite : public SpellScriptLoader
{
public:
spell_s81028_s80650_stalactite() : SpellScriptLoader("spell_s81028_s80650_stalactite") { }
class spell_s81028_s80650_stalactite_SpellScript : public SpellScript
{
PrepareSpellScript(spell_s81028_s80650_stalactite_SpellScript);
void ModDestHeight(SpellDestination& dest)
{
// All stalactite triggers should have Z position 301.3837f, but no way to relocate (not relocateoffset!) height only.
Position offset = { 0.0f, 0.0f, 50.0f, 0.0f };
dest.RelocateOffset(offset);
}
void Register() override
{
OnDestinationTargetSelect += SpellDestinationTargetSelectFn(spell_s81028_s80650_stalactite_SpellScript::ModDestHeight, EFFECT_0, TARGET_DEST_CASTER_RANDOM);
}
};
SpellScript* GetSpellScript() const override
{
return new spell_s81028_s80650_stalactite_SpellScript();
}
};
// 80654 - Stalactite (creates visual shade on ground)
// 80643/92653 - Stalactite (launches missle to the ground)
// 80647/92309 - Stalactite (creates stalactite object)
class spell_stalactite_mod_dest_height : public SpellScriptLoader
{
public:
spell_stalactite_mod_dest_height() : SpellScriptLoader("spell_stalactite_mod_dest_height") { }
class spell_stalactite_mod_dest_height_SpellScript : public SpellScript
{
PrepareSpellScript(spell_stalactite_mod_dest_height_SpellScript);
void ModDestHeight(SpellDestination& dest)
{
Unit* caster = GetCaster();
Position pos = caster->GetPosition();
pos.m_positionZ = caster->GetMap()->GetHeight(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), true, 100.0f);
dest.Relocate(pos);
}
void Register() override
{
OnDestinationTargetSelect += SpellDestinationTargetSelectFn(spell_stalactite_mod_dest_height_SpellScript::ModDestHeight, EFFECT_0, TARGET_DEST_CASTER);
}
};
SpellScript* GetSpellScript() const override
{
return new spell_stalactite_mod_dest_height_SpellScript();
}
};
// 92306 - Crystal storm (heroic mode check)
class spell_s92306_crystal_storm : public SpellScriptLoader
{
public:
spell_s92306_crystal_storm() : SpellScriptLoader("spell_s92306_crystal_storm") { }
class spell_s92306_crystal_storm_SpellScript : public SpellScript
{
PrepareSpellScript(spell_s92306_crystal_storm_SpellScript);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
if (!sSpellMgr->GetSpellInfo(SPELL_CRYSTAL_STORM_TRIGGER))
return false;
return true;
}
void HandleDummyEffect(SpellEffIndex /*eff*/)
{
Unit* caster = GetCaster();
if (caster->GetMap()->IsHeroic())
caster->CastSpell(caster, SPELL_CRYSTAL_STORM_TRIGGER, true);
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_s92306_crystal_storm_SpellScript::HandleDummyEffect, EFFECT_0, SPELL_EFFECT_APPLY_AURA);
}
};
SpellScript* GetSpellScript() const override
{
return new spell_s92306_crystal_storm_SpellScript();
}
};
// 92300 - Crystal Storm (damage)
class BehindObjectCheck
{
public:
BehindObjectCheck(Unit* caster, std::list<GameObject*> objectList) : caster(caster), objectList(objectList) { }
bool operator()(WorldObject* unit)
{
for (std::list<GameObject*>::const_iterator itr = objectList.begin(); itr != objectList.end(); ++itr)
if (!(*itr)->IsInvisibleDueToDespawn() && (*itr)->IsInBetween(caster, unit, 1.5f))
return true;
return false;
}
private:
Unit* caster;
std::list<GameObject*> objectList;
};
class spell_s92300_crystal_storm : public SpellScriptLoader
{
public:
spell_s92300_crystal_storm() : SpellScriptLoader("spell_s92300_crystal_storm") { }
class spell_s92300_crystal_storm_SpellScript : public SpellScript
{
PrepareSpellScript(spell_s92300_crystal_storm_SpellScript);
void FilterTargets(std::list<WorldObject*>& unitList)
{
Unit* caster = GetCaster();
std::list<GameObject*> goList;
caster->GetGameObjectListWithEntryInGrid(goList, GO_STALACTITE, 40.0f);
if (goList.empty())
return;
unitList.remove_if(BehindObjectCheck(caster, goList));
}
void Register() override
{
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_s92300_crystal_storm_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
}
};
SpellScript* GetSpellScript() const override
{
return new spell_s92300_crystal_storm_SpellScript();
}
};
void AddSC_boss_slabhide()
{
new boss_slabhide();
new npc_lava_fissure();
new npc_stalactite_trigger();
new spell_s81035_stalactite();
new spell_s81028_s80650_stalactite();
new spell_stalactite_mod_dest_height();
new spell_s92306_crystal_storm();
new spell_s92300_crystal_storm();
}

View File

@@ -0,0 +1,262 @@
/*
* Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
* Copyright (C) 2006-2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "ScriptMgr.h"
#include "Player.h"
#include "CreatureGroups.h"
#include "InstanceScript.h"
#include "stonecore.h"
#define MAX_ENCOUNTER 4
/* Stonecore encounters:
0 - Corborus
1 - Slabhide
2 - Ozruk
3 - High Priestess Azil
*/
// TO-DO:
// - Find out spell IDs for both Stonecore Teleporters (spellclick).
class instance_stonecore : public InstanceMapScript
{
public:
instance_stonecore() : InstanceMapScript(SCScriptName, 725) { }
struct instance_stonecore_InstanceScript : public InstanceScript
{
instance_stonecore_InstanceScript(Map* map) : InstanceScript(map)
{
SetHeaders(DataHeader);
SetBossNumber(MAX_ENCOUNTER);
}
void OnGameObjectCreate(GameObject* go) override
{
switch (go->GetEntry())
{
case GAMEOBJECT_CORBORUS_ROCKDOOR:
corborusRockDoorGUID = go->GetGUID();
go->SetGoState(GetBossState(DATA_CORBORUS) != DONE ? GO_STATE_READY : GO_STATE_ACTIVE);
break;
case GAMEOBJECT_SLABHIDE_ROCK_WALL:
slabhideRockWallGUIDs.push_back(go->GetGUID());
break;
default:
break;
}
}
void OnCreatureCreate(Creature* creature) override
{
switch (creature->GetEntry())
{
case NPC_MILLHOUSE_MANASTORM:
millhouseGUID = creature->GetGUID();
break;
case NPC_CORBORUS:
corobrusGUID = creature->GetGUID();
break;
case NPC_SLABHIDE:
slabhideGUID = creature->GetGUID();
break;
case NPC_HIGH_PRIESTESS_AZIL:
highPriestessAzilGUID = creature->GetGUID();
break;
case NPC_STONECORE_TELEPORTER:
case NPC_STONECORE_TELEPORTER_2:
if (GetBossState(DATA_SLABHIDE) != DONE)
stonecoreTeleporterGUID[creature->GetEntry() - NPC_STONECORE_TELEPORTER] = creature->GetGUID();
else // If Slabhide is already dead, no need to store teleporter guids
{
creature->CastSpell(creature, SPELL_TELEPORTER_ACTIVE_VISUAL, true);
creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK);
}
break;
default:
break;
}
// Check if creature is part of Millhouse event
creature->SearchFormation();
if (CreatureGroup* group = creature->GetFormation()) // TO-DO: Fix formations
{
switch (group->GetId())
{
case CREATURE_FORMATION_MILLHOUSE_EVENT_TRASH:
millhouseTrashGUIDs.push_back(creature->GetGUID());
break;
case CREATURE_FORMATION_MILLHOUSE_EVENT_LAST_GROUP:
millhouseLastGroupGUIDs.push_back(creature->GetGUID());
creature->SetReactState(REACT_PASSIVE);
creature->SetMeleeAnimKitId(ANIM_READY2H);
break;
}
}
}
bool SetBossState(uint32 type, EncounterState state) override
{
switch (type)
{
case DATA_SLABHIDE:
// Open rock walls (Slabhide AI handles closing because it must be delayed)
if (state != IN_PROGRESS)
SetData(DATA_SLABHIDE_ROCK_WALL, true);
// Activate teleporters
if (state == DONE)
{
for (int8 i = 0; i < MAX_STONECORE_TELEPORTERS; i++)
{
if (Creature* teleporter = GetCreature(stonecoreTeleporterGUID[i]))
{
teleporter->CastSpell(teleporter, SPELL_TELEPORTER_ACTIVE_VISUAL, true);
teleporter->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK);
}
}
}
break;
default:
break;
}
return InstanceScript::SetBossState(type, state);
}
uint32 GetData(uint32 type) const override
{
switch (type)
{
case DATA_SLABHIDE_INTRO:
return slabhideIntro;
default:
break;
}
return 0;
}
void SetData(uint32 type, uint32 data) override
{
switch (type)
{
case DATA_MILLHOUSE_EVENT_FACE:
MillhouseEvent_Face();
break;
case DATA_MILLHOUSE_EVENT_KNOCKBACK:
MillhouseEvent_Knockback();
break;
case DATA_MILLHOUSE_EVENT_DESPAWN:
MillhouseEvent_Despawn();
break;
case DATA_SLABHIDE_INTRO:
slabhideIntro = EncounterState(data);
break;
case DATA_SLABHIDE_ROCK_WALL: // Handles rock walls
for (std::vector<ObjectGuid>::iterator itr = slabhideRockWallGUIDs.begin(); itr != slabhideRockWallGUIDs.end(); ++itr)
HandleGameObject((*itr), data ? true : false);
break;
default:
break;
}
}
ObjectGuid GetGuidData(uint32 type) const override
{
switch (type)
{
case DATA_MILLHOUSE_MANASTORM:
return millhouseGUID;
case GAMEOBJECT_CORBORUS_ROCKDOOR:
return corborusRockDoorGUID;
case DATA_CORBORUS:
return corobrusGUID;
case DATA_SLABHIDE:
return slabhideGUID;
case DATA_HIGH_PRIESTESS_AZIL:
return highPriestessAzilGUID;
case NPC_STONECORE_TELEPORTER:
case NPC_STONECORE_TELEPORTER_2:
return stonecoreTeleporterGUID[type - NPC_STONECORE_TELEPORTER];
default:
break;
}
return ObjectGuid::Empty;
}
private:
// Face Millhouse and other nearby mobs to Corborus
void MillhouseEvent_Face()
{
if (Creature* Millhouse = instance->GetCreature(millhouseGUID))
Millhouse->SetFacingTo(1.570796f);
for (GuidVector::const_iterator i = millhouseLastGroupGUIDs.begin(); i != millhouseLastGroupGUIDs.end(); ++i)
if (Creature* creature = instance->GetCreature(*i))
creature->SetFacingTo(1.570796f);
}
// Knock back Millhouse and other mobs
void MillhouseEvent_Knockback()
{
if (Creature* Millhouse = instance->GetCreature(millhouseGUID))
Millhouse->CastSpell(Millhouse, SPELL_RING_WYRM_KNOCKBACK, true);
for (GuidVector::const_iterator itr = millhouseLastGroupGUIDs.begin(); itr != millhouseLastGroupGUIDs.end(); ++itr)
if (Creature* creature = instance->GetCreature(*itr))
creature->CastSpell(creature, SPELL_RING_WYRM_KNOCKBACK, true);
}
// Despawn all mobs
void MillhouseEvent_Despawn()
{
if (Creature* Millhouse = instance->GetCreature(millhouseGUID))
Millhouse->DespawnOrUnsummon(3000);
for (GuidVector::const_iterator itr = millhouseTrashGUIDs.begin(); itr != millhouseTrashGUIDs.end(); ++itr)
if (Creature* creature = instance->GetCreature(*itr))
creature->DespawnOrUnsummon(3000);
for (GuidVector::const_iterator itr = millhouseLastGroupGUIDs.begin(); itr != millhouseLastGroupGUIDs.end(); ++itr)
if (Creature* creature = instance->GetCreature(*itr))
creature->DespawnOrUnsummon(3000);
}
ObjectGuid millhouseGUID;
GuidVector millhouseTrashGUIDs;
GuidVector millhouseLastGroupGUIDs;
ObjectGuid corborusRockDoorGUID;
ObjectGuid corobrusGUID;
ObjectGuid slabhideGUID;
ObjectGuid highPriestessAzilGUID;
ObjectGuid stonecoreTeleporterGUID[2];
GuidVector slabhideRockWallGUIDs;
EncounterState slabhideIntro;
};
InstanceScript* GetInstanceScript(InstanceMap* map) const override
{
return new instance_stonecore_InstanceScript(map);
}
};
void AddSC_instance_stonecore()
{
new instance_stonecore();
}

View File

@@ -0,0 +1,440 @@
/*
* Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "ObjectGuid.h"
#include "ObjectMgr.h"
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "stonecore.h"
enum Texts
{
// Millhouse Manastorm
SAY_MILLHOUSE_EVENT_1 = 0,
SAY_MILLHOUSE_EVENT_2 = 1,
};
enum NPCs
{
NPC_GENERIC_TRIGGER_LAB = 40350,
};
enum Spells
{
// Millhouse Manastorm
SPELL_SHADOW_BOLT = 81439,
SPELL_FROSTBOLT_VOLLEY = 81440,
SPELL_SHADOWFURY = 81441,
SPELL_FEAR = 81442,
// SPELL_MILLHOUSE_SAFE_CHECK = 81213, // unknown purpose
SPELL_CLEAR_ALL_DEBUFFS = 34098,
SPELL_BLUR = 81216,
SPELL_ANCHOR_HERE = 45313,
SPELL_TIGULE_AND_FORORS_SPECIAL_BLEND = 81220,
SPELL_IMPENDING_DOOM = 86838,
SPELL_IMPENDING_DOOM_CHANNEL = 86830,
// SPELL_PORTAL_VISUAL = 79754,
};
enum Events
{
EVENT_NONE,
// Millhouse Manastorm
EVENT_FROSTBOLT_VOLLEY,
EVENT_SHADOWFURY,
EVENT_FEAR,
EVENT_READY_FOR_COMBAT,
EVENT_CAST_IMPENDING_DOOM,
EVENT_INTERRUPT_IMPENDING_DOOM,
};
enum Phase
{
PHASE_NONE,
PHASE_MILLHOUSE_GROUP_1,
PHASE_MILLHOUSE_GROUP_2,
PHASE_MILLHOUSE_GROUP_3,
PHASE_MILLHOUSE_GROUP_4,
PHASE_MASK_MILLHOUSE_GROUP_1 = (1 << (PHASE_MILLHOUSE_GROUP_1 - 1)),
PHASE_MASK_MILLHOUSE_GROUP_2 = (1 << (PHASE_MILLHOUSE_GROUP_2 - 1)),
PHASE_MASK_MILLHOUSE_GROUP_3 = (1 << (PHASE_MILLHOUSE_GROUP_3 - 1)),
PHASE_MASK_MILLHOUSE_GROUP_4 = (1 << (PHASE_MILLHOUSE_GROUP_4 - 1)),
};
enum MovementPoints
{
POINT_NONE,
POINT_MILLHOUSE_GROUP_2,
POINT_MILLHOUSE_GROUP_3,
POINT_MILLHOUSE_GROUP_4,
};
// Millhouse trash groups
Position const MillhousePointGroup2 = { 977.3045f, 895.2347f, 306.3298f };
Position const MillhousePointGroup3 = { 1049.823f, 871.4349f, 295.006f };
Position const MillhousePointGroup4 = { 1149.04f, 884.431f, 284.9406f };
// 43391 - Millhouse Manastorm
class npc_sc_millhouse_manastorm : public CreatureScript
{
public:
npc_sc_millhouse_manastorm() : CreatureScript("npc_sc_millhouse_manastorm") { }
struct npc_sc_millhouse_manastormAI : public ScriptedAI
{
npc_sc_millhouse_manastormAI(Creature* creature) : ScriptedAI(creature),
_instance(creature->GetInstanceScript())
{
events.SetPhase(PHASE_MILLHOUSE_GROUP_1);
}
void ScheduleEvents()
{
events.ScheduleEvent(EVENT_SHADOWFURY, 3000);
events.ScheduleEvent(EVENT_FROSTBOLT_VOLLEY, 5000);
events.ScheduleEvent(EVENT_FEAR, 8000);
}
void DamageTaken(Unit* /*attacker*/, uint32& damage) override
{
if (damage >= me->GetHealth())
damage = me->GetHealth() - 1;
if (!HealthBelowPct(50) || me->HasAura(SPELL_BLUR))
return;
switch (events.GetPhaseMask())
{
case PHASE_MASK_MILLHOUSE_GROUP_1:
events.Reset();
events.SetPhase(PHASE_MILLHOUSE_GROUP_2);
me->SetReactState(REACT_PASSIVE);
me->InterruptNonMeleeSpells(true);
DoCast(me, SPELL_CLEAR_ALL_DEBUFFS);
DoCast(me, SPELL_BLUR);
Talk(SAY_MILLHOUSE_EVENT_1);
me->GetMotionMaster()->MovePoint(POINT_MILLHOUSE_GROUP_2, MillhousePointGroup2);
break;
case PHASE_MASK_MILLHOUSE_GROUP_2:
events.Reset();
events.SetPhase(PHASE_MILLHOUSE_GROUP_3);
me->SetReactState(REACT_PASSIVE);
me->InterruptNonMeleeSpells(true);
DoCast(me, SPELL_CLEAR_ALL_DEBUFFS);
DoCast(me, SPELL_BLUR);
Talk(SAY_MILLHOUSE_EVENT_1);
me->GetMotionMaster()->MovePoint(POINT_MILLHOUSE_GROUP_3, MillhousePointGroup3);
break;
case PHASE_MASK_MILLHOUSE_GROUP_3:
events.Reset();
events.SetPhase(PHASE_MILLHOUSE_GROUP_4);
me->SetReactState(REACT_PASSIVE);
me->InterruptNonMeleeSpells(true);
DoCast(me, SPELL_CLEAR_ALL_DEBUFFS);
DoCast(me, SPELL_BLUR);
me->GetMotionMaster()->MovePoint(POINT_MILLHOUSE_GROUP_4, MillhousePointGroup4);
break;
default:
break;
}
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT);
}
void MovementInform(uint32 type, uint32 pointId) override
{
if (type != POINT_MOTION_TYPE)
return;
if (pointId < POINT_MILLHOUSE_GROUP_2 || pointId > POINT_MILLHOUSE_GROUP_4)
return;
me->RemoveAllAuras();
me->CombatStop(true);
me->DeleteThreatList();
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT);
me->SetReactState(REACT_AGGRESSIVE);
switch (pointId)
{
case POINT_MILLHOUSE_GROUP_2:
if (Creature* worldtrigger = me->FindNearestCreature(NPC_WORLDTRIGGER, 150.0f))
me->SetFacingToObject(worldtrigger); // o: 5.497359f (sniff data)
me->CastSpell(me, SPELL_ANCHOR_HERE, true);
me->AddAura(SPELL_TIGULE_AND_FORORS_SPECIAL_BLEND, me);
events.ScheduleEvent(EVENT_READY_FOR_COMBAT, 10000);
break;
case POINT_MILLHOUSE_GROUP_3:
me->SetFacingTo(5.931499f);
me->CastSpell(me, SPELL_ANCHOR_HERE, true);
me->AddAura(SPELL_TIGULE_AND_FORORS_SPECIAL_BLEND, me);
events.ScheduleEvent(EVENT_READY_FOR_COMBAT, 10000);
break;
case POINT_MILLHOUSE_GROUP_4:
me->SetFacingTo(3.455752f);
me->CastSpell(me, SPELL_ANCHOR_HERE, true);
Talk(SAY_MILLHOUSE_EVENT_2);
events.ScheduleEvent(EVENT_CAST_IMPENDING_DOOM, 1000);
break;
default:
break;
}
}
void UpdateAI(uint32 diff) override
{
// Only update events if Millhouse is aggressive
if (me->GetReactState() != REACT_AGGRESSIVE)
return;
events.Update(diff);
// Impending Doom is exception because it needs to be interrupted.
if (me->HasUnitState(UNIT_STATE_CASTING) && !me->GetCurrentSpell(SPELL_IMPENDING_DOOM))
return;
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_FROSTBOLT_VOLLEY:
DoCast(SPELL_FROSTBOLT_VOLLEY);
events.ScheduleEvent(EVENT_FROSTBOLT_VOLLEY, 7000);
break;
case EVENT_SHADOWFURY:
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true))
DoCast(target, SPELL_SHADOWFURY);
events.ScheduleEvent(EVENT_SHADOWFURY, 7000);
break;
case EVENT_FEAR:
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true))
DoCast(target, SPELL_FEAR);
events.ScheduleEvent(EVENT_FEAR, 18000);
break;
case EVENT_READY_FOR_COMBAT:
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT);
me->SetReactState(REACT_AGGRESSIVE);
ScheduleEvents();
break;
case EVENT_CAST_IMPENDING_DOOM:
DoCast(SPELL_IMPENDING_DOOM);
DoCast(SPELL_IMPENDING_DOOM_CHANNEL);
events.ScheduleEvent(EVENT_INTERRUPT_IMPENDING_DOOM, urand(15000,20000));
break;
case EVENT_INTERRUPT_IMPENDING_DOOM:
me->InterruptNonMeleeSpells(true);
me->RemoveAllAuras();
me->HandleEmoteCommand(EMOTE_ONESHOT_KNOCKDOWN);
events.ScheduleEvent(EVENT_CAST_IMPENDING_DOOM, 3000);
break;
default:
break;
}
}
DoSpellAttackIfReady(SPELL_SHADOW_BOLT);
}
private:
InstanceScript* _instance;
EventMap events;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetInstanceAI<npc_sc_millhouse_manastormAI>(creature);
}
};
// 81459 - Force of Earth
class spell_force_of_earth : public SpellScriptLoader
{
public:
spell_force_of_earth() : SpellScriptLoader("spell_force_of_earth") { }
class spell_force_of_earth_SpellScript : public SpellScript
{
PrepareSpellScript(spell_force_of_earth_SpellScript);
void DummyEffect(SpellEffIndex /*effIndex*/)
{
GetCaster()->SetDisplayId(26693); // can be moved to SAI part, need sniffs to see what this dummy does (note: npc 43552)
}
void Register()
{
OnEffectLaunch += SpellEffectFn(spell_force_of_earth_SpellScript::DummyEffect, EFFECT_0, SPELL_EFFECT_DUMMY);
}
};
SpellScript* GetSpellScript() const override
{
return new spell_force_of_earth_SpellScript();
}
};
// 45313 - Anchor Here
class spell_sc_anchor_here : public SpellScriptLoader
{
public:
spell_sc_anchor_here() : SpellScriptLoader("spell_sc_anchor_here") { }
class spell_sc_anchor_here_SpellScript : public SpellScript
{
PrepareSpellScript(spell_sc_anchor_here_SpellScript);
void HandleScript(SpellEffIndex /*effIndex*/)
{
if (Creature* creature = GetHitUnit()->ToCreature())
creature->SetHomePosition(creature->GetPositionX(), creature->GetPositionY(), creature->GetPositionZ(), creature->GetOrientation());
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_sc_anchor_here_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
}
};
SpellScript* GetSpellScript() const override
{
return new spell_sc_anchor_here_SpellScript();
}
};
// 93167 - Twilight Documents
class spell_sc_twilight_documents : public SpellScriptLoader
{
public:
spell_sc_twilight_documents() : SpellScriptLoader("spell_sc_twilight_documents") { }
class spell_sc_twilight_documents_SpellScript : public SpellScript
{
PrepareSpellScript(spell_sc_twilight_documents_SpellScript);
bool Validate(SpellInfo const* /*spell*/) override
{
if (!sObjectMgr->GetGameObjectTemplate(GAMEOBJECT_TWILIGHT_DOCUMENTS))
return false;
return true;
}
void SetTarget(WorldObject*& target)
{
target = GetCaster()->FindNearestCreature(NPC_GENERIC_TRIGGER_LAB, 100.0f);
}
void SpawnGameObject(SpellEffIndex /*effIndex*/)
{
if (WorldLocation* loc = GetHitDest())
GetCaster()->SummonGameObject(GAMEOBJECT_TWILIGHT_DOCUMENTS, loc->GetPositionX(), loc->GetPositionY(), loc->GetPositionZ(), loc->GetOrientation(), 0, 0, 0, 0, 7200);
}
void Register() override
{
OnObjectTargetSelect += SpellObjectTargetSelectFn(spell_sc_twilight_documents_SpellScript::SetTarget, EFFECT_0, TARGET_DEST_NEARBY_ENTRY);
OnEffectHit += SpellEffectFn(spell_sc_twilight_documents_SpellScript::SpawnGameObject, EFFECT_0, SPELL_EFFECT_DUMMY);
}
};
SpellScript* GetSpellScript() const override
{
return new spell_sc_twilight_documents_SpellScript();
}
};
// 81008 - Quake
class JumpCheck
{
public:
bool operator()(WorldObject* object) const
{
Player* player = object->ToPlayer();
return (player && player->HasUnitState(UNIT_STATE_JUMPING));
}
};
class spell_sc_quake : public SpellScriptLoader
{
public:
spell_sc_quake() : SpellScriptLoader("spell_sc_quake") { }
class spell_sc_quake_SpellScript : public SpellScript
{
PrepareSpellScript(spell_sc_quake_SpellScript);
void FilterTargets(std::list<WorldObject*>& unitList)
{
unitList.remove_if(JumpCheck());
}
void Register() override
{
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_sc_quake_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
}
};
SpellScript* GetSpellScript() const override
{
return new spell_sc_quake_SpellScript();
}
};
class at_sc_corborus_intro : public AreaTriggerScript
{
public:
at_sc_corborus_intro() : AreaTriggerScript("at_sc_corborus_intro") { }
bool OnTrigger(Player* player, AreaTriggerEntry const* /*areaTrigger*/) override
{
if (InstanceScript* instance = player->GetInstanceScript())
if (Creature* corborus = ObjectAccessor::GetCreature(*player, instance->GetGuidData(DATA_CORBORUS)))
corborus->AI()->DoAction(ACTION_CORBORUS_INTRO);
return true;
}
};
class at_sc_slabhide_intro : public AreaTriggerScript
{
public:
at_sc_slabhide_intro() : AreaTriggerScript("at_sc_slabhide_intro") { }
bool OnTrigger(Player* player, AreaTriggerEntry const* /*areaTrigger*/) override
{
if (InstanceScript* instance = player->GetInstanceScript())
if (Creature* slabhide = ObjectAccessor::GetCreature(*player, instance->GetGuidData(DATA_SLABHIDE)))
slabhide->AI()->DoAction(ACTION_SLABHIDE_INTRO);
return true;
}
};
void AddSC_stonecore()
{
new npc_sc_millhouse_manastorm();
new spell_force_of_earth();
new spell_sc_anchor_here();
new spell_sc_twilight_documents();
new spell_sc_quake();
new at_sc_corborus_intro();
new at_sc_slabhide_intro();
}

View File

@@ -0,0 +1,72 @@
/*
* Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef DEF_STONECORE_H
#define DEF_STONECORE_H
#define SCScriptName "instance_stonecore"
#define DataHeader "SC"
enum DataTypes
{
// Encounter States/Boss GUIDs
DATA_CORBORUS,
DATA_SLABHIDE,
DATA_OZRUK,
DATA_HIGH_PRIESTESS_AZIL,
// Additional Data
DATA_MILLHOUSE_MANASTORM,
DATA_MILLHOUSE_EVENT_FACE,
DATA_MILLHOUSE_EVENT_KNOCKBACK,
DATA_MILLHOUSE_EVENT_DESPAWN,
DATA_SLABHIDE_INTRO,
DATA_SLABHIDE_ROCK_WALL,
};
enum Misc
{
ACTION_CORBORUS_INTRO,
ACTION_SLABHIDE_INTRO,
NPC_WORLDTRIGGER = 22515,
NPC_MILLHOUSE_MANASTORM = 43391,
NPC_CORBORUS = 43438,
NPC_SLABHIDE = 43214,
NPC_OZRUK = 42188,
NPC_HIGH_PRIESTESS_AZIL = 42333,
// Stonecore Teleporter misc
MAX_STONECORE_TELEPORTERS = 2,
NPC_STONECORE_TELEPORTER = 51396, // Entrance teleporter
NPC_STONECORE_TELEPORTER_2 = 51397, // Slabhide teleporter
SPELL_TELEPORTER_ACTIVE_VISUAL = 95298,
GAMEOBJECT_TWILIGHT_DOCUMENTS = 207415,
GAMEOBJECT_CORBORUS_ROCKDOOR = 207343,
GAMEOBJECT_SLABHIDE_ROCK_WALL = 204381,
SPELL_RING_WYRM_KNOCKBACK = 81235,
// Creature Formation IDs
CREATURE_FORMATION_MILLHOUSE_EVENT_TRASH = 340418,
CREATURE_FORMATION_MILLHOUSE_EVENT_LAST_GROUP = 340492,
};
#endif // DEF_STONECORE