diff options
author | tibbi <tibbi@centrum.sk> | 2012-11-19 00:42:25 +0000 |
---|---|---|
committer | Nay <dnpd.dd@gmail.com> | 2012-11-19 00:42:25 +0000 |
commit | 1f9db80b69379f3abc4b2f8bb5dbc26ec971cc92 (patch) | |
tree | d1eba882ba9c99ea2ecceb250f1984427c4af00f | |
parent | aea5fec30dd2b2f5d1709e11949913764dcdae35 (diff) |
Scripts/ToC: Trial of the Crusader rewrite
Closes #8272
Closes #7013
Closes #7552
Closes #5561
Closes #4221
Closes #2701
Closes #2079
Closes #5082
Closes #6503
Closes #6784
Signed-off-by: Nay <dnpd.dd@gmail.com>
10 files changed, 4707 insertions, 3859 deletions
diff --git a/sql/updates/world/2012_11_18_02_world_toc.sql b/sql/updates/world/2012_11_18_02_world_toc.sql new file mode 100644 index 00000000000..b28a2f5cc64 --- /dev/null +++ b/sql/updates/world/2012_11_18_02_world_toc.sql @@ -0,0 +1,151 @@ +-- Trial of the Crusader Death knight Death grip scriptname +DELETE FROM `spell_script_names` WHERE `spell_id` IN (66017, 68753, 68754, 68755); +INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES +(66017, 'spell_faction_champion_death_grip'), +(68753, 'spell_faction_champion_death_grip'), +(68754, 'spell_faction_champion_death_grip'), +(68755, 'spell_faction_champion_death_grip'); + +-- Trial of the Crusader shaman heroism/bloodlust +DELETE FROM `spell_script_names` WHERE `spell_id` IN (65983, 65980); +INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES +(65983, 'spell_toc_heroism'), +(65980, 'spell_toc_bloodlust'); + +-- impale scriptname +DELETE FROM `spell_script_names` WHERE `spell_id`=65919; +INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES +(65919, 'spell_impale'); + +-- firebomb scriptname and modelid (ToC Gormok encounter) +UPDATE `creature_template` SET `ScriptName`="npc_firebomb" WHERE `entry`=34854; + +-- frost sphere corrections +UPDATE `creature_template` SET `minlevel`=80, `InhabitType`=4, `RegenHealth`=0 WHERE `entry` IN (34606, 34649); + +-- Dark / Light essence removing +DELETE FROM `spell_linked_spell` WHERE `spell_trigger` IN (-67222, -67223, -67224, -65686, -67176, -67177, -67178, -65684); +INSERT INTO `spell_linked_spell` (`spell_trigger`, `spell_effect`, `type`, `comment`) VALUES +(-67222, -67511, 0, 'Light Essence 25M'), +(-67223, -67512, 0, 'Light Essence 10M H'), +(-67224, -67513, 0, 'Light Essence 25M H'), +(-65686, -65811, 0, 'Light Essence 10M'), +(-67176, -67179, 0, 'Dark Essence 25M'), +(-67177, -67180, 0, 'Dark Essence 10M H'), +(-67178, -67181, 0, 'Dark Essence 25M H'), +(-65684, -65827, 0, 'Dark Essence 10M'); + +-- Gormoks Fire Bomb scriptname +DELETE FROM `spell_script_names` WHERE `spell_id`=66313; +INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES +(66313, 'spell_gormok_fire_bomb'); + +-- correcting hitbox of Anub'Arak +UPDATE `creature_model_info` SET `bounding_radius`=1.085, `combat_reach`=10.5 WHERE `modelid`=29268; + +-- correcting hitbox of Acidmaw +UPDATE `creature_model_info` SET `bounding_radius`=1.24, `combat_reach`=12 WHERE `modelid`=29815; + +-- spawn the Anub'arak gate in all versions of the instance +UPDATE `gameobject` SET `spawnMask`=15 WHERE `guid`=151192; + +-- adding ToC boss immunities +UPDATE `creature_template` SET `mechanic_immune_mask`=`mechanic_immune_mask` | 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128 | 256 | 512 | 1024 | 2048 | 4096 | 8192 | 65536 | 131072 | 524288 | 4194304 | 8388608 | 67108864 | 536870912 + WHERE `entry` IN (34796, 35438, 35439, 35440, 34799, 35514, 35515, 35516, 35144, 35511, 35512, 35513, 34797, 35447, 35448, 35449, 34780, 35216, 35268, 35269, 36066, 35347, 35348, 35349, 34497, 35350, 35351, 35352, 34564, 34566, 35615, 35616); + +-- adding Teleport locations to Trial of the Crusader/champion for GMs +DELETE FROM `game_tele` WHERE `name` LIKE '%TrialOfTheCrusader%' OR `name` LIKE '%TrialOfTheChampion%'; +INSERT INTO `game_tele` (`position_x`, `position_y`, `position_z`, `orientation`, `map`, `name`) VALUES +(8515.63, 714.174, 558.248, 1.57298, 571, 'TrialOfTheCrusader'), +(8588.42, 791.888, 558.236, 3.23819, 571, 'TrialOfTheChampion'); + +-- misc fixes for higher boss brackets +UPDATE `creature_template` SET `dmg_multiplier`=70 WHERE `entry` IN (35440, 35513, 35516, 35449, 35269, 35352, 35349, 35616, 35664, 35670, 35673, 35676, 35682, 35685, 35688, 35691, 35694, 35697, 35701, 35704, 35707, 35710, 35713, 35716, 35720, 35723, 35726, 35730, 35733, 35736, 35739, 35742, 35745, 35748, 35749); +UPDATE `creature_template` SET `flags_extra`=`flags_extra` | 1 WHERE `entry` IN (35438, 35439, 35440, 35511, 35512, 35513, 35514, 35515, 35516, 35662, 35663, 35664, 35665, 35666, 35667, 35668, 35669, 35670, 35671, 35672, 35673, 35674, 35675, 35676, 35680, 35681, 35682, 35683, 35684, 35685, 35686, 35687, 35688, 35689, 35690, 35691, 35692, 35693, 35694, 35695, 35696, 35697, 35699, 35700, 35701, 35702, 35703, 35704, 35705, 35706, 35707, 35708, 35709, 35710, 35711, 35712, 35713, 35714, 35715, 35716, 35718, 35719, 35720, 35721, 35722, 35723, 35724, 35725, 35726, 35728, 35729, 35730, 35731, 35732, 35733, 35734, 35735, 35736, 35737, 35738, 35739, 35740, 35741, 35742, 35743, 35744, 35745, 35746, 35747, 35748, 34442, 34443, 35749); +UPDATE `creature_template` SET `speed_walk`=2.8, `speed_run`=1.71429 WHERE `entry` IN (35350, 35351, 35352, 35347, 35348, 35349); +UPDATE `creature_template` SET `speed_walk`=2, `speed_run`=1.14286 WHERE `entry` IN (34566, 35615, 35616); +UPDATE `creature_template` SET `skinloot`=34797 WHERE `entry` IN (35447, 35448, 35449); +UPDATE `creature_template` SET `skinloot`=70214 WHERE `entry` IN (34566, 35615, 35616); +UPDATE `creature_template` SET `mindmg`=388, `maxdmg`=583, `attackpower`=146 WHERE `entry` IN (35711, 35712, 35713); +UPDATE `creature_template` SET `mindmg`=468, `maxdmg`=702, `attackpower`=175 WHERE `entry` IN (35699, 35700, 35701); +UPDATE `creature_template` SET `dmg_multiplier`=35 WHERE `entry` IN (34472, 34454); +UPDATE `creature_template` SET `unit_class`=1 WHERE `entry` IN (34461, 35743, 35744, 35745); + +-- adding Jaraxxus add immunities +UPDATE `creature_template` SET `mechanic_immune_mask`=`mechanic_immune_mask` | 1024 | 2048 WHERE `entry` IN (34815, 35262, 35263, 35264, 34826, 35270, 35271, 35272); +UPDATE `creature_template` SET `mechanic_immune_mask`=`mechanic_immune_mask` | 262144 WHERE `entry` IN (35263, 35264); +-- adding Nether portal and Infernal volcano immunities to knockout/grip +UPDATE `creature_template` SET `mechanic_immune_mask`=`mechanic_immune_mask` | 32 | 8192 WHERE `entry` IN (34825, 35278, 35279, 35280, 34813, 35265, 35266, 35267); + +-- cast Forbearance together with Divine shield (ToC Faction Champions paladin) +DELETE FROM `spell_linked_spell` WHERE `spell_trigger`=66010; +INSERT INTO `spell_linked_spell` (`spell_trigger`, `spell_effect`, `type`, `comment`) VALUES +(66010, 25771, 0, 'Divine Shield - Forbearance'); + +-- make all Diminishing returns rules apply in faction champions +UPDATE `creature_template` SET `flags_extra`=`flags_extra` | 1048576 WHERE `entry` IN +(34445,35705,35706,35707, +34459,35686,35687,35688, +34447,35683,35684,35685, +34455,35680,35681,35682, +34453,35718,35719,35720, +34458,35692,35693,35694, +34454,35711,35712,35713, +34448,35724,35725,35726, +34441,34442,34443,35749, +34450,35695,35696,35697, +35610,35774,35775,35776, +35465,36301,36302,36303, +34451,35671,35672,35673, +34449,35689,35690,35691, +34444,35740,35741,35742, +34456,35708,35709,35710, +34460,35702,35703,35704, +34461,35743,35744,35745, +34463,35734,35735,35736, +34465,35746,35747,35748, +34466,35665,35666,35667, +34467,35662,35663,35664, +34468,35721,35722,35723, +34469,35714,35715,35716, +34470,35728,35729,35730, +34473,35674,35675,35676, +34474,35731,35732,35733, +34475,35737,35738,35739, +34471,35668,35669,35670, +34472,35699,35700,35701); + +-- correcting faction champions dmg multipliers +UPDATE `creature_template` SET `dmg_multiplier`=10.8 WHERE `entry` IN (34445,34459,34447,34455,34453,34458,34454,34448,34441,34450,35610,35465,34451,34449,34444,34456,34460,34461,34463,34465,34466,34467,34468,34469,34470,34473,34474,34475,34472, 34471); +UPDATE `creature_template` SET `dmg_multiplier`=16.1 WHERE `entry` IN (35705,35706,35686,35687,35683,35684,35680,35681,35718,35719,35692,35693,35711,35712,35724,35725,34442,34443,35695,35696,35774,35775,36301,36302,35671,35672,35689,35690,35740,35741,35708,35709,35702,35703,35743,35744,35734,35735,35746,35747,35665,35666,35662,35663,35721,35722,35714,35715,35728,35729,35674,35675,35731,35732,35737,35738,35699,35700, 35668, 35669); +UPDATE `creature_template` SET `dmg_multiplier`=21.5 WHERE `entry` IN (35707,35688,35685,35682,35720,35694,35713,35726,35749,35697,35776,36303,35673,35691,35742,35710,35704,35745,35736,35748,35667,35664,35723,35716,35730,35676,35733,35739,35701, 35670); + +-- ToC warlock pet db corrections +UPDATE `creature_template` SET `minlevel`=80, `maxlevel`=80, `exp`=2, `faction_A`=16, `faction_H`=16, `mindmg`=417, `maxdmg`=582, `attackpower`=608, `unit_class`=2, `dynamicflags`=8, `minrangedmg`=341, `maxrangedmg`=506, `rangedattackpower`=80 WHERE `entry` IN (36301, 36302, 36303); +UPDATE `creature_template` SET `faction_A`=16, `faction_H`=16, `difficulty_entry_1`=36301, `difficulty_entry_2`=36302, `difficulty_entry_3`=36303 WHERE `entry`=35465; +UPDATE `creature_template` SET `name`="Zhaagrym (1)" WHERE `entry`=36301; + +-- Jaraxxus Mistress Kiss +DELETE FROM `spell_script_names` WHERE `ScriptName`='spell_mistress_kiss_area'; +INSERT INTO `spell_script_names` (spell_id, `ScriptName`) VALUES +(66336, 'spell_mistress_kiss_area'), +(67076, 'spell_mistress_kiss_area'), +(67077, 'spell_mistress_kiss_area'), +(67078, 'spell_mistress_kiss_area'); + +DELETE FROM `spell_script_names` WHERE `ScriptName` = 'spell_mistress_kiss'; +INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES +(66334, 'spell_mistress_kiss'), +(67905, 'spell_mistress_kiss'), +(67906, 'spell_mistress_kiss'), +(67907, 'spell_mistress_kiss'); + +-- Gormoks Rising anger targeting +DELETE FROM `conditions` WHERE `SourceEntry`=66636; +INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `ConditionTypeOrReference`, `ConditionValue1`, `ConditionValue2`, `Comment`) VALUES +(13, 1, 66636, 31, 3, 34796, 'Rising Anger'); + +-- Twins loot correction +UPDATE `creature_loot_template` SET `maxcount`=1 WHERE `entry`=34497 AND `mincountOrRef` IN (-34296, -34302); +-- Anubarak loot correction +UPDATE `creature_loot_template` SET `maxcount`=2 WHERE `entry`=34564 AND `mincountOrRef` IN (-34298, -34304); diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp index f3317f3a424..1edb8eab103 100755 --- a/src/server/game/Spells/SpellMgr.cpp +++ b/src/server/game/Spells/SpellMgr.cpp @@ -81,6 +81,9 @@ DiminishingGroup GetDiminishingReturnsGroupForSpell(SpellInfo const* spellproto, // Gnaw else if (spellproto->Id == 47481) return DIMINISHING_CONTROLLED_STUN; + // ToC Icehowl Arctic Breath + else if (spellproto->SpellVisual[0] == 14153) + return DIMINISHING_NONE; break; } // Event spells diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_anubarak_trial.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_anubarak_trial.cpp index 0f33c3866dd..1108c6ffc85 100755 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_anubarak_trial.cpp +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_anubarak_trial.cpp @@ -16,25 +16,15 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -/* ScriptData -SDName: boss_anubarak_trial -SD%Complete: ??% -SDComment: based on /dev/rsa -SDCategory: -EndScriptData */ - // Known bugs: // Anubarak - underground phase partially not worked // - tele after impale hit a permafrost doesn't work (the entire tele spell should be better) -// Burrow - visual is vanishing -// Burrower - Spider Frenzy not working as it should (frenzy not stacking) // Scarab - Kill credit isn't crediting? -// FrostSph - often they are casting Permafrost a little above the ground #include "ScriptMgr.h" #include "ScriptedCreature.h" #include "trial_of_the_crusader.h" -#include "Player.h" +#include <limits> enum Yells { @@ -48,7 +38,7 @@ enum Yells SAY_KILL_PLAYER = 7, SAY_DEATH = 8, - EMOTE_SPIKE = 0, + EMOTE_SPIKE = 0 }; enum Summons @@ -57,7 +47,7 @@ enum Summons NPC_BURROW = 34862, NPC_BURROWER = 34607, NPC_SCARAB = 34605, - NPC_SPIKE = 34660, + NPC_SPIKE = 34660 }; enum BossSpells @@ -87,8 +77,9 @@ enum BossSpells SPELL_EXPOSE_WEAKNESS = 67720, //Passive - Triggered SPELL_SHADOW_STRIKE = 66134, SPELL_SUBMERGE_EFFECT = 68394, - SPELL_EMERGE_EFFECT = 65982, SPELL_AWAKENED = 66311, + SPELL_EMERGE_EFFECT = 65982, + SPELL_PERSISTENT_DIRT = 68048, SUMMON_SCARAB = NPC_SCARAB, @@ -108,15 +99,15 @@ enum BossSpells SPELL_SPIKE_SPEED2 = 65922, SPELL_SPIKE_SPEED3 = 65923, SPELL_SPIKE_FAIL = 66181, - SPELL_SPIKE_TELE = 66170, + SPELL_SPIKE_TELE = 66170 }; #define SPELL_PERMAFROST_HELPER RAID_MODE<uint32>(66193, 67855, 67856, 67857) enum SummonActions { - ACTION_SHADOW_STRIKE, - ACTION_SCARAB_SUBMERGE, + ACTION_SHADOW_STRIKE = 0, + ACTION_SCARAB_SUBMERGE = 1 }; const Position SphereSpawn[6] = @@ -134,446 +125,468 @@ enum MovementPoints POINT_FALL_GROUND = 1 }; -class boss_anubarak_trial : public CreatureScript +enum PursuingSpikesPhases { -public: - boss_anubarak_trial() : CreatureScript("boss_anubarak_trial") { } + PHASE_NO_MOVEMENT = 0, + PHASE_IMPALE_NORMAL = 1, + PHASE_IMPALE_MIDDLE = 2, + PHASE_IMPALE_FAST = 3 +}; - CreatureAI* GetAI(Creature* creature) const - { - return new boss_anubarak_trialAI(creature); - }; +enum Events +{ + // Anub'arak + EVENT_FREEZE_SLASH = 1, + EVENT_PENETRATING_COLD = 2, + EVENT_SUMMON_NERUBIAN = 3, + EVENT_NERUBIAN_SHADOW_STRIKE = 4, + EVENT_SUBMERGE = 5, + EVENT_EMERGE = 6, + EVENT_PURSUING_SPIKE = 7, + EVENT_SUMMON_SCARAB = 8, + EVENT_SUMMON_FROST_SPHERE = 9, + EVENT_BERSERK = 10 +}; - struct boss_anubarak_trialAI : public ScriptedAI - { - boss_anubarak_trialAI(Creature* creature) : ScriptedAI(creature), Summons(me) - { - instance = creature->GetInstanceScript(); - } +enum Phases +{ + // Anub'arak + PHASE_MELEE = 1, + PHASE_SUBMERGED = 2, - InstanceScript* instance; - - SummonList Summons; - std::list<uint64> m_vBurrowGUID; - uint64 m_aSphereGUID[6]; - - uint32 m_uiFreezeSlashTimer; - uint32 m_uiPenetratingColdTimer; - uint32 m_uiSummonNerubianTimer; - uint32 m_uiNerubianShadowStrikeTimer; - uint32 m_uiSubmergeTimer; - uint32 m_uiPursuingSpikeTimer; - uint32 m_uiSummonScarabTimer; - uint32 m_uiSummonFrostSphereTimer; - uint32 m_uiBerserkTimer; - - uint8 m_uiStage; - bool m_bIntro; - bool m_bReachedPhase3; - uint64 m_uiTargetGUID; - uint8 m_uiScarabSummoned; - - void Reset() - { - m_uiFreezeSlashTimer = 15*IN_MILLISECONDS; - m_uiPenetratingColdTimer = 20*IN_MILLISECONDS; - m_uiNerubianShadowStrikeTimer = 30*IN_MILLISECONDS; - m_uiSummonNerubianTimer = 10*IN_MILLISECONDS; - m_uiSubmergeTimer = 80*IN_MILLISECONDS; - - m_uiPursuingSpikeTimer = 2*IN_MILLISECONDS; - m_uiSummonScarabTimer = 2*IN_MILLISECONDS; - - m_uiSummonFrostSphereTimer = 20*IN_MILLISECONDS; - - m_uiBerserkTimer = 10*MINUTE*IN_MILLISECONDS; - m_uiStage = 0; - m_uiScarabSummoned = 0; - m_bIntro = true; - m_bReachedPhase3 = false; - m_uiTargetGUID = 0; - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); - Summons.DespawnAll(); - m_vBurrowGUID.clear(); - } + PHASE_MASK_MELEE = 1 << PHASE_MELEE +}; - void KilledUnit(Unit* who) +class boss_anubarak_trial : public CreatureScript +{ + public: + boss_anubarak_trial() : CreatureScript("boss_anubarak_trial") { } + + struct boss_anubarak_trialAI : public BossAI { - if (who->GetTypeId() == TYPEID_PLAYER) + boss_anubarak_trialAI(Creature* creature) : BossAI(creature, BOSS_ANUBARAK) { - Talk(SAY_KILL_PLAYER); - if (instance) - instance->SetData(DATA_TRIBUTE_TO_IMMORTALITY_ELEGIBLE, 0); } - } - void MoveInLineOfSight(Unit* /*who*/) - { - if (!m_bIntro) + void Reset() { - Talk(SAY_INTRO); - m_bIntro = false; + _Reset(); + events.SetPhase(PHASE_MELEE); + events.ScheduleEvent(EVENT_FREEZE_SLASH, 15*IN_MILLISECONDS, 0, PHASE_MELEE); + events.ScheduleEvent(EVENT_PENETRATING_COLD, 20*IN_MILLISECONDS, PHASE_MELEE); + events.ScheduleEvent(EVENT_SUMMON_NERUBIAN, 10*IN_MILLISECONDS, 0, PHASE_MELEE); + events.ScheduleEvent(EVENT_SUBMERGE, 80*IN_MILLISECONDS, 0, PHASE_MELEE); + events.ScheduleEvent(EVENT_BERSERK, 10*MINUTE*IN_MILLISECONDS); + if (IsHeroic()) + events.ScheduleEvent(EVENT_NERUBIAN_SHADOW_STRIKE, 30*IN_MILLISECONDS, 0, PHASE_MELEE); + + if (!IsHeroic()) + events.ScheduleEvent(EVENT_SUMMON_FROST_SPHERE, 20*IN_MILLISECONDS); + + _intro = true; + _reachedPhase3 = false; + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); + // clean up spawned Frost Spheres + std::list<Creature*> FrostSphereList; + me->GetCreatureListWithEntryInGrid(FrostSphereList, NPC_FROST_SPHERE, 150.0f); + if (!FrostSphereList.empty()) + for (std::list<Creature*>::iterator itr = FrostSphereList.begin(); itr != FrostSphereList.end(); itr++) + (*itr)->DespawnOrUnsummon(); + + _burrowGUID.clear(); } - } - void JustReachedHome() - { - if (instance) - instance->SetData(TYPE_ANUBARAK, FAIL); - //Summon Scarab Swarms neutral at random places - for (int i=0; i < 10; i++) - if (Creature* temp = me->SummonCreature(NPC_SCARAB, AnubarakLoc[1].GetPositionX()+urand(0, 50)-25, AnubarakLoc[1].GetPositionY()+urand(0, 50)-25, AnubarakLoc[1].GetPositionZ())) + void KilledUnit(Unit* who) + { + if (who->GetTypeId() == TYPEID_PLAYER) { - temp->setFaction(31); - temp->GetMotionMaster()->MoveRandom(10); + Talk(SAY_KILL_PLAYER); + if (instance) + instance->SetData(DATA_TRIBUTE_TO_IMMORTALITY_ELEGIBLE, 0); } - } - - void JustDied(Unit* /*killer*/) - { - Summons.DespawnAll(); - Talk(SAY_DEATH); - if (instance) - instance->SetData(TYPE_ANUBARAK, DONE); - } - - void JustSummoned(Creature* summoned) - { - Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0, true); - switch (summoned->GetEntry()) - { - case NPC_BURROW: - m_vBurrowGUID.push_back(summoned->GetGUID()); - summoned->SetReactState(REACT_PASSIVE); - summoned->CastSpell(summoned, SPELL_CHURNING_GROUND, false); - break; - case NPC_SPIKE: - summoned->CombatStart(target); - Talk(EMOTE_SPIKE, target->GetGUID()); - break; - } - Summons.Summon(summoned); - } + } - void SummonedCreatureDespawn(Creature* summoned) - { - switch (summoned->GetEntry()) + void MoveInLineOfSight(Unit* /*who*/) { - case NPC_SPIKE: - m_uiPursuingSpikeTimer = 2*IN_MILLISECONDS; - break; + if (!_intro) + { + Talk(SAY_INTRO); + _intro = false; + } } - } - - void EnterCombat(Unit* /*who*/) - { - Talk(SAY_AGGRO); - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); - me->SetInCombatWithZone(); - if (instance) - instance->SetData(TYPE_ANUBARAK, IN_PROGRESS); - //Despawn Scarab Swarms neutral - EntryCheckPredicate pred(NPC_SCARAB); - Summons.DoAction(ACTION_SCARAB_SUBMERGE, pred); - //Spawn Burrow - for (int i=0; i < 4; i++) - me->SummonCreature(NPC_BURROW, AnubarakLoc[i+2]); - //Spawn Frost Spheres - for (int i=0; i < 6; i++) - if (Unit* summoned = me->SummonCreature(NPC_FROST_SPHERE, SphereSpawn[i])) - m_aSphereGUID[i] = summoned->GetGUID(); - } - void UpdateAI(const uint32 uiDiff) - { - if (!UpdateVictim()) - return; + void JustReachedHome() + { + if (instance) + instance->SetBossState(BOSS_ANUBARAK, FAIL); + //Summon Scarab Swarms neutral at random places + for (int i = 0; i < 10; i++) + if (Creature* temp = me->SummonCreature(NPC_SCARAB, AnubarakLoc[1].GetPositionX()+urand(0, 50)-25, AnubarakLoc[1].GetPositionY()+urand(0, 50)-25, AnubarakLoc[1].GetPositionZ())) + { + temp->setFaction(31); + temp->GetMotionMaster()->MoveRandom(10); + } + } - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; + void JustDied(Unit* /*killer*/) + { + _JustDied(); + Talk(SAY_DEATH); + + // despawn frostspheres and Burrowers on death + std::list<Creature*> AddList; + me->GetCreatureListWithEntryInGrid(AddList, NPC_FROST_SPHERE, 150.0f); + me->GetCreatureListWithEntryInGrid(AddList, NPC_BURROWER, 150.0f); + if (!AddList.empty()) + for (std::list<Creature*>::iterator itr = AddList.begin(); itr != AddList.end(); itr++) + (*itr)->DespawnOrUnsummon(); + } - switch (m_uiStage) + void JustSummoned(Creature* summoned) { - case 0: - if (m_uiFreezeSlashTimer <= uiDiff) - { - DoCastVictim(SPELL_FREEZE_SLASH); - m_uiFreezeSlashTimer = 15*IN_MILLISECONDS; - } else m_uiFreezeSlashTimer -= uiDiff; + Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true); + switch (summoned->GetEntry()) + { + case NPC_BURROW: + _burrowGUID.push_back(summoned->GetGUID()); + summoned->SetReactState(REACT_PASSIVE); + summoned->CastSpell(summoned, SPELL_CHURNING_GROUND, false); + summoned->SetDisplayId(summoned->GetCreatureTemplate()->Modelid2); + break; + case NPC_SPIKE: + summoned->CombatStart(target); + summoned->SetDisplayId(summoned->GetCreatureTemplate()->Modelid1); + Talk(EMOTE_SPIKE, target->GetGUID()); + break; + default: + break; + } + summons.Summon(summoned); + } - if (m_uiPenetratingColdTimer <= uiDiff) - { - me->CastCustomSpell(SPELL_PENETRATING_COLD, SPELLVALUE_MAX_TARGETS, RAID_MODE(2, 5, 2, 5)); - m_uiPenetratingColdTimer = 20*IN_MILLISECONDS; - } else m_uiPenetratingColdTimer -= uiDiff; + void EnterCombat(Unit* /*who*/) + { + _EnterCombat(); + Talk(SAY_AGGRO); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); + + // Despawn Scarab Swarms neutral + EntryCheckPredicate pred(NPC_SCARAB); + summons.DoAction(ACTION_SCARAB_SUBMERGE, pred); + + // Spawn Burrow + for (int i = 0; i < 4; i++) + me->SummonCreature(NPC_BURROW, AnubarakLoc[i + 2]); + + // Spawn 6 Frost Spheres at start + for (int i = 0; i < 6; i++) + if (Unit* summoned = me->SummonCreature(NPC_FROST_SPHERE, SphereSpawn[i])) + _sphereGUID[i] = summoned->GetGUID(); + } - if (m_uiSummonNerubianTimer <= uiDiff && (IsHeroic() || !m_bReachedPhase3)) - { - me->CastCustomSpell(SPELL_SUMMON_BURROWER, SPELLVALUE_MAX_TARGETS, RAID_MODE(1, 2, 2, 4)); - m_uiSummonNerubianTimer = 45*IN_MILLISECONDS; - } else m_uiSummonNerubianTimer -= uiDiff; + void UpdateAI(const uint32 diff) + { + if (!UpdateVictim()) + return; - if (IsHeroic() && m_uiNerubianShadowStrikeTimer <= uiDiff) - { - EntryCheckPredicate pred(NPC_BURROWER); - Summons.DoAction(ACTION_SHADOW_STRIKE, pred); - m_uiNerubianShadowStrikeTimer = 30*IN_MILLISECONDS; - } else m_uiNerubianShadowStrikeTimer -= uiDiff; + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; - if (m_uiSubmergeTimer <= uiDiff && !m_bReachedPhase3 && !me->HasAura(SPELL_BERSERK)) - { - m_uiStage = 1; - m_uiSubmergeTimer = 60*IN_MILLISECONDS; - } else m_uiSubmergeTimer -= uiDiff; - break; - case 1: - DoCast(me, SPELL_SUBMERGE_ANUBARAK); - DoCast(me, SPELL_CLEAR_ALL_DEBUFFS); - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); - Talk(EMOTE_BURROWER); - m_uiScarabSummoned = 0; - m_uiSummonScarabTimer = 4*IN_MILLISECONDS; - m_uiStage = 2; - break; - case 2: - if (m_uiPursuingSpikeTimer <= uiDiff) - { - DoCast(SPELL_SPIKE_CALL); - // Just to make sure it won't happen again in this phase - m_uiPursuingSpikeTimer = 90*IN_MILLISECONDS; - } else m_uiPursuingSpikeTimer -= uiDiff; + events.Update(diff); - if (m_uiSummonScarabTimer <= uiDiff) - { - /* WORKAROUND - * - The correct implementation is more likely the comment below but it needs spell knowledge - */ - std::list<uint64>::iterator i = m_vBurrowGUID.begin(); - uint32 at = urand(0, m_vBurrowGUID.size()-1); - for (uint32 k = 0; k < at; k++) - ++i; - if (Creature* pBurrow = Unit::GetCreature(*me, *i)) - pBurrow->CastSpell(pBurrow, 66340, false); - m_uiScarabSummoned++; - m_uiSummonScarabTimer = 4*IN_MILLISECONDS; - if (m_uiScarabSummoned == 4) m_uiSummonScarabTimer = RAID_MODE(4, 20)*IN_MILLISECONDS; - - /*It seems that this spell have something more that needs to be taken into account - //Need more sniff info - DoCast(SPELL_SUMMON_BEATLES); - // Just to make sure it won't happen again in this phase - m_uiSummonScarabTimer = 90*IN_MILLISECONDS;*/ - } else m_uiSummonScarabTimer -= uiDiff; - - if (m_uiSubmergeTimer <= uiDiff) - { - m_uiStage = 3; - m_uiSubmergeTimer = 80*IN_MILLISECONDS; - } else m_uiSubmergeTimer -= uiDiff; - break; - case 3: - m_uiStage = 0; - DoCast(SPELL_SPIKE_TELE); - Summons.DespawnEntry(NPC_SPIKE); - me->RemoveAurasDueToSpell(SPELL_SUBMERGE_ANUBARAK); - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); - DoCast(me, SPELL_EMERGE_ANUBARAK); - me->GetMotionMaster()->MoveChase(me->getVictim()); - m_uiSummonNerubianTimer = 10*IN_MILLISECONDS; - m_uiNerubianShadowStrikeTimer = 30*IN_MILLISECONDS; - m_uiSummonScarabTimer = 2*IN_MILLISECONDS; - break; - } - - if (!IsHeroic()) - { - if (m_uiSummonFrostSphereTimer <= uiDiff) + while (uint32 eventId = events.ExecuteEvent()) { - uint8 startAt = urand(0, 5); - uint8 i = startAt; - do + switch (eventId) { - if (Unit* pSphere = Unit::GetCreature(*me, m_aSphereGUID[i])) + case EVENT_FREEZE_SLASH: + DoCastVictim(SPELL_FREEZE_SLASH); + events.ScheduleEvent(EVENT_FREEZE_SLASH, 15*IN_MILLISECONDS, 0, PHASE_MELEE); + return; + case EVENT_PENETRATING_COLD: + me->CastCustomSpell(SPELL_PENETRATING_COLD, SPELLVALUE_MAX_TARGETS, RAID_MODE(2, 5, 2, 5)); + events.ScheduleEvent(EVENT_PENETRATING_COLD, 20*IN_MILLISECONDS, 0, PHASE_MELEE); + return; + case EVENT_SUMMON_NERUBIAN: + if (IsHeroic() || !_reachedPhase3) + me->CastCustomSpell(SPELL_SUMMON_BURROWER, SPELLVALUE_MAX_TARGETS, RAID_MODE(1, 2, 2, 4)); + events.ScheduleEvent(EVENT_SUMMON_NERUBIAN, 45*IN_MILLISECONDS, 0, PHASE_MELEE); + return; + case EVENT_NERUBIAN_SHADOW_STRIKE: { - if (!pSphere->HasAura(SPELL_FROST_SPHERE)) + EntryCheckPredicate pred(NPC_BURROWER); + summons.DoAction(ACTION_SHADOW_STRIKE, pred); + events.ScheduleEvent(EVENT_NERUBIAN_SHADOW_STRIKE, 30*IN_MILLISECONDS, 0, PHASE_MELEE); + break; + } + case EVENT_SUBMERGE: + if (!_reachedPhase3 && !me->HasAura(SPELL_BERSERK)) { - if (Creature* summon = me->SummonCreature(NPC_FROST_SPHERE, SphereSpawn[i])) - m_aSphereGUID[i] = summon->GetGUID(); - break; + DoCast(me, SPELL_SUBMERGE_ANUBARAK); + DoCast(me, SPELL_CLEAR_ALL_DEBUFFS); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); + Talk(EMOTE_BURROWER); + events.SetPhase(PHASE_SUBMERGED); + events.ScheduleEvent(EVENT_PURSUING_SPIKE, 2*IN_MILLISECONDS, 0, PHASE_SUBMERGED); + events.ScheduleEvent(EVENT_SUMMON_SCARAB, 4*IN_MILLISECONDS, 0, PHASE_SUBMERGED); + events.ScheduleEvent(EVENT_EMERGE, 1*MINUTE*IN_MILLISECONDS, 0, PHASE_SUBMERGED); } + break; + case EVENT_PURSUING_SPIKE: + DoCast(SPELL_SPIKE_CALL); + break; + case EVENT_SUMMON_SCARAB: + { + /* WORKAROUND + * - The correct implementation is more likely the comment below but it needs spell knowledge + */ + std::list<uint64>::iterator i = _burrowGUID.begin(); + uint32 at = urand(0, _burrowGUID.size()-1); + for (uint32 k = 0; k < at; k++) + ++i; + if (Creature* pBurrow = Unit::GetCreature(*me, *i)) + pBurrow->CastSpell(pBurrow, 66340, false); + + events.ScheduleEvent(EVENT_SUMMON_SCARAB, 4*IN_MILLISECONDS, 0, PHASE_SUBMERGED); + + /*It seems that this spell have something more that needs to be taken into account + //Need more sniff info + DoCast(SPELL_SUMMON_BEATLES); + // Just to make sure it won't happen again in this phase + m_uiSummonScarabTimer = 90*IN_MILLISECONDS;*/ + break; } - i = (i+1)%6; - } while (i != startAt); - m_uiSummonFrostSphereTimer = urand(20, 30)*IN_MILLISECONDS; - } else m_uiSummonFrostSphereTimer -= uiDiff; - } + case EVENT_EMERGE: + events.ScheduleEvent(EVENT_SUBMERGE, 80*IN_MILLISECONDS, 0, PHASE_MELEE); + DoCast(SPELL_SPIKE_TELE); + summons.DespawnEntry(NPC_SPIKE); + me->RemoveAurasDueToSpell(SPELL_SUBMERGE_ANUBARAK); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); + DoCast(me, SPELL_EMERGE_ANUBARAK); + events.SetPhase(PHASE_MELEE); + events.ScheduleEvent(EVENT_FREEZE_SLASH, 15*IN_MILLISECONDS, 0, PHASE_MELEE); + events.ScheduleEvent(EVENT_PENETRATING_COLD, 20*IN_MILLISECONDS, PHASE_MELEE); + events.ScheduleEvent(EVENT_SUMMON_NERUBIAN, 10*IN_MILLISECONDS, 0, PHASE_MELEE); + events.ScheduleEvent(EVENT_SUBMERGE, 80*IN_MILLISECONDS, 0, PHASE_MELEE); + if (IsHeroic()) + events.ScheduleEvent(EVENT_NERUBIAN_SHADOW_STRIKE, 30*IN_MILLISECONDS, 0, PHASE_MELEE); + return; + case EVENT_SUMMON_FROST_SPHERE: + { + uint8 startAt = urand(0, 5); + uint8 i = startAt; + do + { + if (Unit* pSphere = Unit::GetCreature(*me, _sphereGUID[i])) + { + if (!pSphere->HasAura(SPELL_FROST_SPHERE)) + { + if (Creature* summon = me->SummonCreature(NPC_FROST_SPHERE, SphereSpawn[i])) + _sphereGUID[i] = summon->GetGUID(); + break; + } + } + i = (i + 1) % 6; + } + while + (i != startAt); + events.ScheduleEvent(EVENT_SUMMON_FROST_SPHERE, urand(20*IN_MILLISECONDS, 30*IN_MILLISECONDS)); + break; + } + case EVENT_BERSERK: + DoCast(me, SPELL_BERSERK); + break; + default: + break; + } - if (HealthBelowPct(30) && m_uiStage == 0 && !m_bReachedPhase3) - { - m_bReachedPhase3 = true; - DoCastAOE(SPELL_LEECHING_SWARM); - Talk(EMOTE_LEECHING_SWARM); - Talk(SAY_LEECHING_SWARM); - } + } - if (m_uiBerserkTimer <= uiDiff && !me->HasAura(SPELL_BERSERK)) - { - DoCast(me, SPELL_BERSERK); - } else m_uiBerserkTimer -= uiDiff; + if (HealthBelowPct(30) && events.GetPhaseMask() & PHASE_MASK_MELEE && !_reachedPhase3) + { + _reachedPhase3 = true; + DoCastAOE(SPELL_LEECHING_SWARM); + Talk(EMOTE_LEECHING_SWARM); + Talk(SAY_LEECHING_SWARM); + } - DoMeleeAttackIfReady(); - } - }; + if (events.GetPhaseMask() & PHASE_MASK_MELEE) + DoMeleeAttackIfReady(); + } + private: + std::list<uint64> _burrowGUID; + uint64 _sphereGUID[6]; + bool _intro; + bool _reachedPhase3; + uint32 _frostSphereTimer; + uint32 _berserkTimer; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new boss_anubarak_trialAI(creature); + }; }; class mob_swarm_scarab : public CreatureScript { -public: - mob_swarm_scarab() : CreatureScript("mob_swarm_scarab") { } - - CreatureAI* GetAI(Creature* creature) const - { - return new mob_swarm_scarabAI(creature); - }; - - struct mob_swarm_scarabAI : public ScriptedAI - { - mob_swarm_scarabAI(Creature* creature) : ScriptedAI(creature) - { - instance = creature->GetInstanceScript(); - } - - InstanceScript* instance; - - uint32 m_uiDeterminationTimer; + public: + mob_swarm_scarab() : CreatureScript("mob_swarm_scarab") { } - void Reset() + struct mob_swarm_scarabAI : public ScriptedAI { - me->SetCorpseDelay(0); - m_uiDeterminationTimer = urand(5*IN_MILLISECONDS, 60*IN_MILLISECONDS); - DoCast(me, SPELL_ACID_MANDIBLE); - me->SetInCombatWithZone(); - if (me->isInCombat()) - if (Creature* Anubarak = ObjectAccessor::GetCreature(*me, instance->GetData64(NPC_ANUBARAK))) - Anubarak->AI()->JustSummoned(me); - } + mob_swarm_scarabAI(Creature* creature) : ScriptedAI(creature) + { + _instance = creature->GetInstanceScript(); + } - void DoAction(const int32 actionId) - { - switch (actionId) + void Reset() { - case ACTION_SCARAB_SUBMERGE: - DoCast(SPELL_SUBMERGE_EFFECT); - me->DespawnOrUnsummon(1000); - break; + me->SetCorpseDelay(0); + _determinationTimer = urand(5*IN_MILLISECONDS, 60*IN_MILLISECONDS); + DoCast(me, SPELL_ACID_MANDIBLE); + me->SetInCombatWithZone(); + if (me->isInCombat()) + if (Creature* Anubarak = ObjectAccessor::GetCreature(*me, _instance->GetData64(NPC_ANUBARAK))) + Anubarak->AI()->JustSummoned(me); } - } - void JustDied(Unit* killer) - { - DoCast(killer, RAID_MODE(SPELL_TRAITOR_KING_10, SPELL_TRAITOR_KING_25)); - } + void DoAction(const int32 actionId) + { + switch (actionId) + { + case ACTION_SCARAB_SUBMERGE: + DoCast(SPELL_SUBMERGE_EFFECT); + me->DespawnOrUnsummon(1*IN_MILLISECONDS); + break; + default: + break; + } + } - void UpdateAI(const uint32 uiDiff) - { - if (!UpdateVictim()) - return; + void JustDied(Unit* killer) + { + DoCast(killer, RAID_MODE(SPELL_TRAITOR_KING_10, SPELL_TRAITOR_KING_25)); + } - /* Bosskillers don't recognize */ - if (m_uiDeterminationTimer <= uiDiff) + void UpdateAI(const uint32 diff) { - DoCast(me, SPELL_DETERMINATION); - m_uiDeterminationTimer = urand(10*IN_MILLISECONDS, 60*IN_MILLISECONDS); - } else m_uiDeterminationTimer -= uiDiff; + if (_instance && _instance->GetBossState(BOSS_ANUBARAK) != IN_PROGRESS) + me->DisappearAndDie(); - DoMeleeAttackIfReady(); - } - }; + if (!UpdateVictim()) + return; -}; + /* Bosskillers don't recognize */ + if (_determinationTimer <= diff) + { + DoCast(me, SPELL_DETERMINATION); + _determinationTimer = urand(10*IN_MILLISECONDS, 60*IN_MILLISECONDS); + } + else + _determinationTimer -= diff; -class mob_nerubian_burrower : public CreatureScript -{ -public: - mob_nerubian_burrower() : CreatureScript("mob_nerubian_burrower") { } + DoMeleeAttackIfReady(); + } - CreatureAI* GetAI(Creature* creature) const - { - return new mob_nerubian_burrowerAI(creature); - }; + private: + InstanceScript* _instance; + uint32 _determinationTimer; + }; - struct mob_nerubian_burrowerAI : public ScriptedAI - { - mob_nerubian_burrowerAI(Creature* creature) : ScriptedAI(creature) + CreatureAI* GetAI(Creature* creature) const { - instance = creature->GetInstanceScript(); - } - - InstanceScript* instance; - - uint32 m_uiSpiderFrenzyTimer; - uint32 m_uiSubmergeTimer; + return new mob_swarm_scarabAI(creature); + }; +}; - void Reset() - { - me->SetCorpseDelay(10); - m_uiSpiderFrenzyTimer = urand(10*IN_MILLISECONDS, 20*IN_MILLISECONDS); - m_uiSubmergeTimer = 30*IN_MILLISECONDS; - DoCast(me, SPELL_EXPOSE_WEAKNESS); - DoCast(me, SPELL_SPIDER_FRENZY); - DoCast(me, SPELL_AWAKENED); - me->SetInCombatWithZone(); - if (me->isInCombat()) - if (Creature* Anubarak = ObjectAccessor::GetCreature(*me, instance->GetData64(NPC_ANUBARAK))) - Anubarak->AI()->JustSummoned(me); - } +class mob_nerubian_burrower : public CreatureScript +{ + public: + mob_nerubian_burrower() : CreatureScript("mob_nerubian_burrower") { } - void DoAction(const int32 actionId) + struct mob_nerubian_burrowerAI : public ScriptedAI { - switch (actionId) + mob_nerubian_burrowerAI(Creature* creature) : ScriptedAI(creature) { - case ACTION_SHADOW_STRIKE: - if (!me->HasAura(SPELL_AWAKENED)) - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) - DoCast(target, SPELL_SHADOW_STRIKE); - break; + _instance = creature->GetInstanceScript(); } - } - - void UpdateAI(const uint32 uiDiff) - { - if (!UpdateVictim()) - return; - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; + void Reset() + { + me->SetCorpseDelay(10); + _submergeTimer = 30*IN_MILLISECONDS; + DoCast(me, SPELL_EXPOSE_WEAKNESS); + DoCast(me, SPELL_SPIDER_FRENZY); + DoCast(me, SPELL_AWAKENED); + me->SetInCombatWithZone(); + if (me->isInCombat()) + if (Creature* Anubarak = ObjectAccessor::GetCreature(*me, _instance->GetData64(NPC_ANUBARAK))) + Anubarak->AI()->JustSummoned(me); + } - if ((m_uiSubmergeTimer <= uiDiff) && HealthBelowPct(80)) + void DoAction(const int32 actionId) { - if (me->HasAura(SPELL_SUBMERGE_EFFECT)) + switch (actionId) { - me->RemoveAurasDueToSpell(SPELL_SUBMERGE_EFFECT); - DoCast(me, SPELL_EMERGE_EFFECT); - DoCast(me, SPELL_AWAKENED); - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + case ACTION_SHADOW_STRIKE: + if (!me->HasAura(SPELL_AWAKENED)) + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) + DoCast(target, SPELL_SHADOW_STRIKE); + break; + default: + break; } - else + } + + void UpdateAI(const uint32 diff) + { + if (_instance && _instance->GetBossState(BOSS_ANUBARAK) != IN_PROGRESS) + me->DisappearAndDie(); + + if (!UpdateVictim() && !me->HasAura(SPELL_SUBMERGE_EFFECT)) + return; + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + if ((_submergeTimer <= diff) && HealthBelowPct(80)) { - if (!me->HasAura(SPELL_PERMAFROST_HELPER)) + if (me->HasAura(SPELL_SUBMERGE_EFFECT)) { - DoCast(me, SPELL_SUBMERGE_EFFECT); - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - DoCast(me, SPELL_PERSISTENT_DIRT, true); + me->RemoveAurasDueToSpell(SPELL_SUBMERGE_EFFECT); + DoCast(me, SPELL_EMERGE_EFFECT); + DoCast(me, SPELL_AWAKENED); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + } + else + { + if (!me->HasAura(SPELL_PERMAFROST_HELPER)) + { + DoCast(me, SPELL_SUBMERGE_EFFECT); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + DoCast(me, SPELL_PERSISTENT_DIRT, true); + } } + _submergeTimer = 20*IN_MILLISECONDS; } - m_uiSubmergeTimer = 20*IN_MILLISECONDS; - } else m_uiSubmergeTimer -= uiDiff; + else + _submergeTimer -= diff; - DoMeleeAttackIfReady(); - } - }; + DoMeleeAttackIfReady(); + } + + private: + uint32 _submergeTimer; + Phases _phase; + EventMap _events; + InstanceScript* _instance; + }; + CreatureAI* GetAI(Creature* creature) const + { + return new mob_nerubian_burrowerAI(creature); + }; }; class mob_frost_sphere : public CreatureScript @@ -637,6 +650,8 @@ class mob_frost_sphere : public CreatureScript DoCast(SPELL_PERMAFROST); me->SetObjectScale(2.0f); break; + default: + break; } } }; @@ -649,92 +664,180 @@ class mob_frost_sphere : public CreatureScript class mob_anubarak_spike : public CreatureScript { -public: - mob_anubarak_spike() : CreatureScript("mob_anubarak_spike") { } - - CreatureAI* GetAI(Creature* creature) const - { - return new mob_anubarak_spikeAI(creature); - }; + public: + mob_anubarak_spike() : CreatureScript("mob_anubarak_spike") { } - struct mob_anubarak_spikeAI : public ScriptedAI - { - mob_anubarak_spikeAI(Creature* creature) : ScriptedAI(creature) + struct mob_anubarak_spikeAI : public ScriptedAI { - instance = creature->GetInstanceScript(); - } - - InstanceScript* instance; - uint32 m_uiIncreaseSpeedTimer; - uint8 m_uiSpeed; - uint64 m_uiTargetGUID; + mob_anubarak_spikeAI(Creature* creature) : ScriptedAI(creature) + { + } - void Reset() - { - // For an unknown reason this npc isn't recognize the Aura of Permafrost with this flags =/ - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_IMMUNE_TO_PC); - m_uiTargetGUID = 0; - } + void Reset() + { + _phase = PHASE_NO_MOVEMENT; + _phaseSwitchTimer = 1; + // make sure the spike has everyone on threat list + me->SetInCombatWithZone(); + } - bool CanAIAttack(Unit const* victim) const - { - return victim->GetTypeId() == TYPEID_PLAYER; - } + bool CanAIAttack(Unit const* victim) const + { + return victim->GetTypeId() == TYPEID_PLAYER; + } - void EnterCombat(Unit* who) - { - m_uiTargetGUID = who->GetGUID(); - DoCast(who, SPELL_MARK); - Talk(EMOTE_SPIKE, who->GetGUID()); - me->SetSpeed(MOVE_RUN, 0.5f); - m_uiSpeed = 0; - m_uiIncreaseSpeedTimer = 1*IN_MILLISECONDS; - me->TauntApply(who); - } + void EnterCombat(Unit* who) + { + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true)) + { + StartChase(target); + Talk(EMOTE_SPIKE, who->GetGUID()); + } + } - void DamageTaken(Unit* /*who*/, uint32& uiDamage) - { - uiDamage = 0; - } + void DamageTaken(Unit* /*who*/, uint32& uiDamage) + { + uiDamage = 0; + } - void UpdateAI(const uint32 uiDiff) - { - Unit* target = Unit::GetPlayer(*me, m_uiTargetGUID); - if (!target || !target->isAlive() || !target->HasAura(SPELL_MARK)) + void UpdateAI(const uint32 diff) { - if (Creature* pAnubarak = Unit::GetCreature((*me), instance->GetData64(NPC_ANUBARAK))) - pAnubarak->CastSpell(pAnubarak, SPELL_SPIKE_TELE, false); - me->DisappearAndDie(); - return; + if (!UpdateVictim()) + { + me->DisappearAndDie(); + return; + } + + if (_phaseSwitchTimer) + { + if (_phaseSwitchTimer <= diff) + { + switch (_phase) + { + case PHASE_NO_MOVEMENT: + DoCast(me, SPELL_SPIKE_SPEED1); + DoCast(me, SPELL_SPIKE_TRAIL); + _phase = PHASE_IMPALE_NORMAL; + if (Unit* target2 = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true)) + { + StartChase(target2); + Talk(EMOTE_SPIKE, target2->GetGUID()); + } + _phaseSwitchTimer = 7*IN_MILLISECONDS; + return; + case PHASE_IMPALE_NORMAL: + DoCast(me, SPELL_SPIKE_SPEED2); + _phase = PHASE_IMPALE_MIDDLE; + _phaseSwitchTimer = 7*IN_MILLISECONDS; + return; + case PHASE_IMPALE_MIDDLE: + DoCast(me, SPELL_SPIKE_SPEED3); + _phase = PHASE_IMPALE_FAST; + _phaseSwitchTimer = 0; + return; + default: + return; + } + } + else + _phaseSwitchTimer -= diff; + } } - if (m_uiIncreaseSpeedTimer) + void MoveInLineOfSight(Unit* pWho) { - if (m_uiIncreaseSpeedTimer <= uiDiff) + if (!pWho) + return; + + if (pWho->GetEntry() != NPC_FROST_SPHERE) + return; + + if (_phase == PHASE_NO_MOVEMENT) + return; + + if (me->IsWithinDist(pWho, 7.0f)) { - switch (m_uiSpeed) + switch (_phase) { - case 0: - DoCast(me, SPELL_SPIKE_SPEED1); - DoCast(me, SPELL_SPIKE_TRAIL); - m_uiSpeed = 1; - m_uiIncreaseSpeedTimer = 7*IN_MILLISECONDS; + case PHASE_IMPALE_NORMAL: + me->RemoveAurasDueToSpell(SPELL_SPIKE_SPEED1); + break; + case PHASE_IMPALE_MIDDLE: + me->RemoveAurasDueToSpell(SPELL_SPIKE_SPEED2); break; - case 1: - DoCast(me, SPELL_SPIKE_SPEED2); - m_uiSpeed = 2; - m_uiIncreaseSpeedTimer = 7*IN_MILLISECONDS; + case PHASE_IMPALE_FAST: + me->RemoveAurasDueToSpell(SPELL_SPIKE_SPEED3); break; - case 2: - DoCast(me, SPELL_SPIKE_SPEED3); - m_uiIncreaseSpeedTimer = 0; + default: break; } - } else m_uiIncreaseSpeedTimer -= uiDiff; + + me->CastSpell(me, SPELL_SPIKE_FAIL, true); + + pWho->ToCreature()->DespawnOrUnsummon(3*IN_MILLISECONDS); + + // After the spikes hit the icy surface they can't move for about ~5 seconds + _phase = PHASE_NO_MOVEMENT; + _phaseSwitchTimer = 5*IN_MILLISECONDS; + SetCombatMovement(false); + me->GetMotionMaster()->MoveIdle(); + me->GetMotionMaster()->Clear(); + } + } + + void StartChase(Unit* who) + { + DoCast(who, SPELL_MARK); + me->SetSpeed(MOVE_RUN, 0.5f); + // make sure the Spine will really follow the one he should + me->getThreatManager().clearReferences(); + me->SetInCombatWithZone(); + me->getThreatManager().addThreat(who, std::numeric_limits<float>::max()); + me->GetMotionMaster()->Clear(true); + me->GetMotionMaster()->MoveChase(who); + me->TauntApply(who); + } + + private: + uint32 _phaseSwitchTimer; + PursuingSpikesPhases _phase; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new mob_anubarak_spikeAI(creature); + }; +}; + +class spell_impale : public SpellScriptLoader +{ + public: + spell_impale() : SpellScriptLoader("spell_impale") { } + + class spell_impale_SpellScript : public SpellScript + { + PrepareSpellScript(spell_impale_SpellScript); + + void HandleDamageCalc(SpellEffIndex /*effIndex*/) + { + Unit* target = GetHitUnit(); + uint32 permafrost = sSpellMgr->GetSpellIdForDifficulty(SPELL_PERMAFROST, target); + + // make sure Impale doesnt do damage if we are standing on permafrost + if (target && target->HasAura(permafrost)) + SetHitDamage(0); } - } - }; + void Register() + { + OnEffectHitTarget += SpellEffectFn(spell_impale_SpellScript::HandleDamageCalc, EFFECT_0, SPELL_EFFECT_SCHOOL_DAMAGE); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_impale_SpellScript(); + } }; void AddSC_boss_anubarak_trial() @@ -744,4 +847,6 @@ void AddSC_boss_anubarak_trial() new mob_nerubian_burrower(); new mob_anubarak_spike(); new mob_frost_sphere(); + + new spell_impale(); } diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_faction_champions.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_faction_champions.cpp index e376a97dd36..63966e5f204 100755 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_faction_champions.cpp +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_faction_champions.cpp @@ -16,17 +16,6 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -/* ScriptData -SDName: faction_champions -SD%Complete: ??% -SDComment: Scripts by Selector, modified by /dev/rsa -SDCategory: Crusader Coliseum -EndScriptData */ - -// Known bugs: -// All - untested -// Pets aren't being summoned by their masters - #include "ScriptMgr.h" #include "ScriptedCreature.h" #include "SpellScript.h" @@ -36,7 +25,7 @@ EndScriptData */ enum Yells { - SAY_KILL_PLAYER = 6, + SAY_KILL_PLAYER = 6 }; enum eAIs @@ -44,234 +33,527 @@ enum eAIs AI_MELEE = 0, AI_RANGED = 1, AI_HEALER = 2, - AI_PET = 3, + AI_PET = 3 }; enum eSpells { - SPELL_ANTI_AOE = 68595, - SPELL_PVP_TRINKET = 65547, + // generic + SPELL_ANTI_AOE = 68595, + SPELL_PVP_TRINKET = 65547, + + // druid healer + SPELL_LIFEBLOOM = 66093, + SPELL_NOURISH = 66066, + SPELL_REGROWTH = 66067, + SPELL_REJUVENATION = 66065, + SPELL_TRANQUILITY = 66086, + SPELL_BARKSKIN = 65860, + SPELL_THORNS = 66068, + SPELL_NATURE_GRASP = 66071, + + // shaman healer + SPELL_HEALING_WAVE = 66055, + SPELL_RIPTIDE = 66053, + SPELL_SPIRIT_CLEANSE = 66056, //friendly only + SPELL_HEROISM = 65983, + SPELL_BLOODLUST = 65980, + SPELL_HEX = 66054, + SPELL_EARTH_SHIELD = 66063, + SPELL_EARTH_SHOCK = 65973, + AURA_EXHAUSTION = 57723, + AURA_SATED = 57724, + + // paladin healer + SPELL_HAND_OF_FREEDOM = 68757, + SPELL_DIVINE_SHIELD = 66010, + SPELL_CLEANSE = 66116, + SPELL_FLASH_OF_LIGHT = 66113, + SPELL_HOLY_LIGHT = 66112, + SPELL_HOLY_SHOCK = 66114, + SPELL_HAND_OF_PROTECTION = 66009, + SPELL_HAMMER_OF_JUSTICE = 66613, + SPELL_FORBEARANCE = 25771, + + // priest healer + SPELL_RENEW = 66177, + SPELL_SHIELD = 66099, + SPELL_FLASH_HEAL = 66104, + SPELL_DISPEL = 65546, + SPELL_PSYCHIC_SCREAM = 65543, + SPELL_MANA_BURN = 66100, + SPELL_PENANCE = 66097, + + // priest dps + SPELL_SILENCE = 65542, + SPELL_VAMPIRIC_TOUCH = 65490, + SPELL_SW_PAIN = 65541, + SPELL_MIND_FLAY = 65488, + SPELL_MIND_BLAST = 65492, + SPELL_HORROR = 65545, + SPELL_DISPERSION = 65544, + SPELL_SHADOWFORM = 16592, + + // warlock + SPELL_HELLFIRE = 65816, + SPELL_CORRUPTION = 65810, + SPELL_CURSE_OF_AGONY = 65814, + SPELL_CURSE_OF_EXHAUSTION = 65815, + SPELL_FEAR = 65809, + SPELL_SEARING_PAIN = 65819, + SPELL_SHADOW_BOLT = 65821, + SPELL_UNSTABLE_AFFLICTION = 65812, + SPELL_UNSTABLE_AFFLICTION_DISPEL = 65813, + SPELL_SUMMON_FELHUNTER = 67514, + + // mage + SPELL_ARCANE_BARRAGE = 65799, + SPELL_ARCANE_BLAST = 65791, + SPELL_ARCANE_EXPLOSION = 65800, + SPELL_BLINK = 65793, + SPELL_COUNTERSPELL = 65790, + SPELL_FROST_NOVA = 65792, + SPELL_FROSTBOLT = 65807, + SPELL_ICE_BLOCK = 65802, + SPELL_POLYMORPH = 65801, + + // hunter + SPELL_AIMED_SHOT = 65883, + SPELL_DETERRENCE = 65871, + SPELL_DISENGAGE = 65869, + SPELL_EXPLOSIVE_SHOT = 65866, + SPELL_FROST_TRAP = 65880, + SPELL_SHOOT = 65868, + SPELL_STEADY_SHOT = 65867, + SPELL_WING_CLIP = 66207, + SPELL_WYVERN_STING = 65877, + SPELL_CALL_PET = 67777, + + // druid dps + SPELL_CYCLONE = 65859, + SPELL_ENTANGLING_ROOTS = 65857, + SPELL_FAERIE_FIRE = 65863, + SPELL_FORCE_OF_NATURE = 65861, + SPELL_INSECT_SWARM = 65855, + SPELL_MOONFIRE = 65856, + SPELL_STARFIRE = 65854, + SPELL_WRATH = 65862, + + // warrior + SPELL_BLADESTORM = 65947, + SPELL_INTIMIDATING_SHOUT = 65930, + SPELL_MORTAL_STRIKE = 65926, + SPELL_CHARGE = 68764, + SPELL_DISARM = 65935, + SPELL_OVERPOWER = 65924, + SPELL_SUNDER_ARMOR = 65936, + SPELL_SHATTERING_THROW = 65940, + SPELL_RETALIATION = 65932, + + // death knight + SPELL_CHAINS_OF_ICE = 66020, + SPELL_DEATH_COIL = 66019, + SPELL_DEATH_GRIP = 66017, + SPELL_FROST_STRIKE = 66047, + SPELL_ICEBOUND_FORTITUDE = 66023, + SPELL_ICY_TOUCH = 66021, + SPELL_STRANGULATE = 66018, + SPELL_DEATH_GRIP_PULL = 64431, // used at spellscript + + // rogue + SPELL_FAN_OF_KNIVES = 65955, + SPELL_BLIND = 65960, + SPELL_CLOAK = 65961, + SPELL_BLADE_FLURRY = 65956, + SPELL_SHADOWSTEP = 66178, + SPELL_HEMORRHAGE = 65954, + SPELL_EVISCERATE = 65957, + SPELL_WOUND_POISON = 65962, + + // shaman dps (some spells taken from shaman healer) + SPELL_LAVA_LASH = 65974, + SPELL_STORMSTRIKE = 65970, + SPELL_WINDFURY = 65976, + + // paladin dps + SPELL_AVENGING_WRATH = 66011, + SPELL_CRUSADER_STRIKE = 66003, + SPELL_DIVINE_STORM = 66006, + SPELL_HAMMER_OF_JUSTICE_RET = 66007, + SPELL_JUDGEMENT_OF_COMMAND = 66005, + SPELL_REPENTANCE = 66008, + SPELL_SEAL_OF_COMMAND = 66004, + + // warlock pet + SPELL_DEVOUR_MAGIC = 67518, + SPELL_SPELL_LOCK = 67519, + + // hunter pet + SPELL_CLAW = 67793 }; -class boss_toc_champion_controller : public CreatureScript +enum Events { -public: - boss_toc_champion_controller() : CreatureScript("boss_toc_champion_controller") { } - - CreatureAI* GetAI(Creature* creature) const - { - return new boss_toc_champion_controllerAI (creature); - } - - struct boss_toc_champion_controllerAI : public ScriptedAI - { - boss_toc_champion_controllerAI(Creature* creature) : ScriptedAI(creature), Summons(me) - { - instance = creature->GetInstanceScript(); - } + // generic + EVENT_THREAT = 1, + EVENT_REMOVE_CC = 2, + + // druid healer + EVENT_LIFEBLOOM = 1, + EVENT_NOURISH = 2, + EVENT_REGROWTH = 3, + EVENT_REJUVENATION = 4, + EVENT_TRANQUILITY = 5, + EVENT_HEAL_BARKSKIN = 6, + EVENT_THORNS = 7, + EVENT_NATURE_GRASP = 8, + + // shaman healer + EVENT_HEALING_WAVE = 1, + EVENT_RIPTIDE = 2, + EVENT_SPIRIT_CLEANSE = 3, + EVENT_HEAL_BLOODLUST_HEROISM = 4, + EVENT_HEX = 5, + EVENT_EARTH_SHIELD = 6, + EVENT_HEAL_EARTH_SHOCK = 7, + + // paladin healer + EVENT_HAND_OF_FREEDOM = 1, + EVENT_HEAL_DIVINE_SHIELD = 2, + EVENT_CLEANSE = 3, + EVENT_FLASH_OF_LIGHT = 4, + EVENT_HOLY_LIGHT = 5, + EVENT_HOLY_SHOCK = 6, + EVENT_HEAL_HAND_OF_PROTECTION = 7, + EVENT_HAMMER_OF_JUSTICE = 8, + + // priest healer + EVENT_RENEW = 1, + EVENT_SHIELD = 2, + EVENT_FLASH_HEAL = 3, + EVENT_HEAL_DISPEL = 4, + EVENT_HEAL_PSYCHIC_SCREAM = 5, + EVENT_MANA_BURN = 6, + EVENT_PENANCE = 7, + + // priest dps + EVENT_SILENCE = 1, + EVENT_VAMPIRIC_TOUCH = 2, + EVENT_SW_PAIN = 3, + EVENT_MIND_BLAST = 4, + EVENT_HORROR = 5, + EVENT_DISPERSION = 6, + EVENT_DPS_DISPEL = 7, + EVENT_DPS_PSYCHIC_SCREAM = 8, + + // warlock + EVENT_HELLFIRE = 1, + EVENT_CORRUPTION = 2, + EVENT_CURSE_OF_AGONY = 3, + EVENT_CURSE_OF_EXHAUSTION = 4, + EVENT_FEAR = 5, + EVENT_SEARING_PAIN = 6, + EVENT_UNSTABLE_AFFLICTION = 7, + + // mage + EVENT_ARCANE_BARRAGE = 1, + EVENT_ARCANE_BLAST = 2, + EVENT_ARCANE_EXPLOSION = 3, + EVENT_BLINK = 4, + EVENT_COUNTERSPELL = 5, + EVENT_FROST_NOVA = 6, + EVENT_ICE_BLOCK = 7, + EVENT_POLYMORPH = 8, + + // hunter + EVENT_AIMED_SHOT = 1, + EVENT_DETERRENCE = 2, + EVENT_DISENGAGE = 3, + EVENT_EXPLOSIVE_SHOT = 4, + EVENT_FROST_TRAP = 5, + EVENT_STEADY_SHOT = 6, + EVENT_WING_CLIP = 7, + EVENT_WYVERN_STING = 8, + + // druid dps + EVENT_CYCLONE = 1, + EVENT_ENTANGLING_ROOTS = 2, + EVENT_FAERIE_FIRE = 3, + EVENT_FORCE_OF_NATURE = 4, + EVENT_INSECT_SWARM = 5, + EVENT_MOONFIRE = 6, + EVENT_STARFIRE = 7, + EVENT_DPS_BARKSKIN = 8, + + // warrior + EVENT_BLADESTORM = 1, + EVENT_INTIMIDATING_SHOUT = 2, + EVENT_MORTAL_STRIKE = 3, + EVENT_WARR_CHARGE = 4, + EVENT_DISARM = 5, + EVENT_OVERPOWER = 6, + EVENT_SUNDER_ARMOR = 7, + EVENT_SHATTERING_THROW = 8, + EVENT_RETALIATION = 9, + + // death knight + EVENT_CHAINS_OF_ICE = 1, + EVENT_DEATH_COIL = 2, + EVENT_DEATH_GRIP = 3, + EVENT_FROST_STRIKE = 4, + EVENT_ICEBOUND_FORTITUDE = 5, + EVENT_ICY_TOUCH = 6, + EVENT_STRANGULATE = 7, + + // rogue + EVENT_FAN_OF_KNIVES = 1, + EVENT_BLIND = 2, + EVENT_CLOAK = 3, + EVENT_BLADE_FLURRY = 4, + EVENT_SHADOWSTEP = 5, + EVENT_HEMORRHAGE = 6, + EVENT_EVISCERATE = 7, + EVENT_WOUND_POISON = 8, + + // shaman dps + EVENT_DPS_EARTH_SHOCK = 1, + EVENT_LAVA_LASH = 2, + EVENT_STORMSTRIKE = 3, + EVENT_DPS_BLOODLUST_HEROISM = 4, + EVENT_DEPLOY_TOTEM = 5, + EVENT_WINDFURY = 6, + + // paladin dps + EVENT_AVENGING_WRATH = 1, + EVENT_CRUSADER_STRIKE = 2, + EVENT_DIVINE_STORM = 3, + EVENT_HAMMER_OF_JUSTICE_RET = 4, + EVENT_JUDGEMENT_OF_COMMAND = 5, + EVENT_REPENTANCE = 6, + EVENT_DPS_HAND_OF_PROTECTION = 7, + EVENT_DPS_DIVINE_SHIELD = 8, + + // warlock pet + EVENT_DEVOUR_MAGIC = 1, + EVENT_SPELL_LOCK = 2 +}; - InstanceScript* instance; - SummonList Summons; - uint32 m_uiChampionsNotStarted; - uint32 m_uiChampionsFailed; - uint32 m_uiChampionsKilled; - bool m_bInProgress; +class boss_toc_champion_controller : public CreatureScript +{ + public: + boss_toc_champion_controller() : CreatureScript("boss_toc_champion_controller") { } - void Reset() + struct boss_toc_champion_controllerAI : public ScriptedAI { - m_uiChampionsNotStarted = 0; - m_uiChampionsFailed = 0; - m_uiChampionsKilled = 0; - m_bInProgress = false; - } + boss_toc_champion_controllerAI(Creature* creature) : ScriptedAI(creature), _summons(me) + { + _instance = creature->GetInstanceScript(); + } - std::vector<uint32> SelectChampions(Team playerTeam) - { - std::vector<uint32> vHealersEntries; - vHealersEntries.clear(); - vHealersEntries.push_back(playerTeam == ALLIANCE ? NPC_HORDE_DRUID_RESTORATION : NPC_ALLIANCE_DRUID_RESTORATION); - vHealersEntries.push_back(playerTeam == ALLIANCE ? NPC_HORDE_PALADIN_HOLY : NPC_ALLIANCE_PALADIN_HOLY); - vHealersEntries.push_back(playerTeam == ALLIANCE ? NPC_HORDE_PRIEST_DISCIPLINE : NPC_ALLIANCE_PRIEST_DISCIPLINE); - vHealersEntries.push_back(playerTeam == ALLIANCE ? NPC_HORDE_SHAMAN_RESTORATION : NPC_ALLIANCE_SHAMAN_RESTORATION); - - std::vector<uint32> vOtherEntries; - vOtherEntries.clear(); - vOtherEntries.push_back(playerTeam == ALLIANCE ? NPC_HORDE_DEATH_KNIGHT : NPC_ALLIANCE_DEATH_KNIGHT); - vOtherEntries.push_back(playerTeam == ALLIANCE ? NPC_HORDE_HUNTER : NPC_ALLIANCE_HUNTER); - vOtherEntries.push_back(playerTeam == ALLIANCE ? NPC_HORDE_MAGE : NPC_ALLIANCE_MAGE); - vOtherEntries.push_back(playerTeam == ALLIANCE ? NPC_HORDE_ROGUE : NPC_ALLIANCE_ROGUE); - vOtherEntries.push_back(playerTeam == ALLIANCE ? NPC_HORDE_WARLOCK : NPC_ALLIANCE_WARLOCK); - vOtherEntries.push_back(playerTeam == ALLIANCE ? NPC_HORDE_WARRIOR : NPC_ALLIANCE_WARRIOR); - - uint8 healersSubtracted = 2; - if (instance->instance->GetSpawnMode() == RAID_DIFFICULTY_25MAN_NORMAL || instance->instance->GetSpawnMode() == RAID_DIFFICULTY_25MAN_HEROIC) - healersSubtracted = 1; - for (uint8 i = 0; i < healersSubtracted; ++i) + void Reset() { - uint8 pos = urand(0, vHealersEntries.size()-1); - switch (vHealersEntries[pos]) + _championsNotStarted = 0; + _championsFailed = 0; + _championsKilled = 0; + _inProgress = false; + } + + std::vector<uint32> SelectChampions(Team playerTeam) + { + std::vector<uint32> vHealersEntries; + vHealersEntries.clear(); + vHealersEntries.push_back(playerTeam == ALLIANCE ? NPC_HORDE_DRUID_RESTORATION : NPC_ALLIANCE_DRUID_RESTORATION); + vHealersEntries.push_back(playerTeam == ALLIANCE ? NPC_HORDE_PALADIN_HOLY : NPC_ALLIANCE_PALADIN_HOLY); + vHealersEntries.push_back(playerTeam == ALLIANCE ? NPC_HORDE_PRIEST_DISCIPLINE : NPC_ALLIANCE_PRIEST_DISCIPLINE); + vHealersEntries.push_back(playerTeam == ALLIANCE ? NPC_HORDE_SHAMAN_RESTORATION : NPC_ALLIANCE_SHAMAN_RESTORATION); + + std::vector<uint32> vOtherEntries; + vOtherEntries.clear(); + vOtherEntries.push_back(playerTeam == ALLIANCE ? NPC_HORDE_DEATH_KNIGHT : NPC_ALLIANCE_DEATH_KNIGHT); + vOtherEntries.push_back(playerTeam == ALLIANCE ? NPC_HORDE_HUNTER : NPC_ALLIANCE_HUNTER); + vOtherEntries.push_back(playerTeam == ALLIANCE ? NPC_HORDE_MAGE : NPC_ALLIANCE_MAGE); + vOtherEntries.push_back(playerTeam == ALLIANCE ? NPC_HORDE_ROGUE : NPC_ALLIANCE_ROGUE); + vOtherEntries.push_back(playerTeam == ALLIANCE ? NPC_HORDE_WARLOCK : NPC_ALLIANCE_WARLOCK); + vOtherEntries.push_back(playerTeam == ALLIANCE ? NPC_HORDE_WARRIOR : NPC_ALLIANCE_WARRIOR); + + uint8 healersSubtracted = 2; + if (_instance->instance->GetSpawnMode() == RAID_DIFFICULTY_25MAN_NORMAL || _instance->instance->GetSpawnMode() == RAID_DIFFICULTY_25MAN_HEROIC) + healersSubtracted = 1; + for (uint8 i = 0; i < healersSubtracted; ++i) { - case NPC_ALLIANCE_DRUID_RESTORATION: - vOtherEntries.push_back(NPC_ALLIANCE_DRUID_BALANCE); - break; - case NPC_HORDE_DRUID_RESTORATION: - vOtherEntries.push_back(NPC_HORDE_DRUID_BALANCE); - break; - case NPC_ALLIANCE_PALADIN_HOLY: - vOtherEntries.push_back(NPC_ALLIANCE_PALADIN_RETRIBUTION); - break; - case NPC_HORDE_PALADIN_HOLY: - vOtherEntries.push_back(NPC_HORDE_PALADIN_RETRIBUTION); - break; - case NPC_ALLIANCE_PRIEST_DISCIPLINE: - vOtherEntries.push_back(NPC_ALLIANCE_PRIEST_SHADOW); - break; - case NPC_HORDE_PRIEST_DISCIPLINE: - vOtherEntries.push_back(NPC_HORDE_PRIEST_SHADOW); - break; - case NPC_ALLIANCE_SHAMAN_RESTORATION: - vOtherEntries.push_back(NPC_ALLIANCE_SHAMAN_ENHANCEMENT); - break; - case NPC_HORDE_SHAMAN_RESTORATION: - vOtherEntries.push_back(NPC_HORDE_SHAMAN_ENHANCEMENT); - break; + uint8 pos = urand(0, vHealersEntries.size() - 1); + switch (vHealersEntries[pos]) + { + case NPC_ALLIANCE_DRUID_RESTORATION: + vOtherEntries.push_back(NPC_ALLIANCE_DRUID_BALANCE); + break; + case NPC_HORDE_DRUID_RESTORATION: + vOtherEntries.push_back(NPC_HORDE_DRUID_BALANCE); + break; + case NPC_ALLIANCE_PALADIN_HOLY: + vOtherEntries.push_back(NPC_ALLIANCE_PALADIN_RETRIBUTION); + break; + case NPC_HORDE_PALADIN_HOLY: + vOtherEntries.push_back(NPC_HORDE_PALADIN_RETRIBUTION); + break; + case NPC_ALLIANCE_PRIEST_DISCIPLINE: + vOtherEntries.push_back(NPC_ALLIANCE_PRIEST_SHADOW); + break; + case NPC_HORDE_PRIEST_DISCIPLINE: + vOtherEntries.push_back(NPC_HORDE_PRIEST_SHADOW); + break; + case NPC_ALLIANCE_SHAMAN_RESTORATION: + vOtherEntries.push_back(NPC_ALLIANCE_SHAMAN_ENHANCEMENT); + break; + case NPC_HORDE_SHAMAN_RESTORATION: + vOtherEntries.push_back(NPC_HORDE_SHAMAN_ENHANCEMENT); + break; + default: + break; + } + vHealersEntries.erase(vHealersEntries.begin() + pos); } - vHealersEntries.erase(vHealersEntries.begin()+pos); - } - if (instance->instance->GetSpawnMode() == RAID_DIFFICULTY_10MAN_NORMAL || instance->instance->GetSpawnMode() == RAID_DIFFICULTY_10MAN_HEROIC) - for (uint8 i = 0; i < 4; ++i) - vOtherEntries.erase(vOtherEntries.begin()+urand(0, vOtherEntries.size()-1)); + if (_instance->instance->GetSpawnMode() == RAID_DIFFICULTY_10MAN_NORMAL || _instance->instance->GetSpawnMode() == RAID_DIFFICULTY_10MAN_HEROIC) + for (uint8 i = 0; i < 4; ++i) + vOtherEntries.erase(vOtherEntries.begin() + urand(0, vOtherEntries.size() - 1)); - std::vector<uint32> vChampionEntries; - vChampionEntries.clear(); - for (uint8 i = 0; i < vHealersEntries.size(); ++i) - vChampionEntries.push_back(vHealersEntries[i]); - for (uint8 i = 0; i < vOtherEntries.size(); ++i) - vChampionEntries.push_back(vOtherEntries[i]); + std::vector<uint32> vChampionEntries; + vChampionEntries.clear(); + for (uint8 i = 0; i < vHealersEntries.size(); ++i) + vChampionEntries.push_back(vHealersEntries[i]); + for (uint8 i = 0; i < vOtherEntries.size(); ++i) + vChampionEntries.push_back(vOtherEntries[i]); - return vChampionEntries; - } + return vChampionEntries; + } - void SummonChampions(Team playerTeam) - { - std::vector<Position> vChampionJumpOrigin; - if (playerTeam == ALLIANCE) - for (uint8 i = 0; i < 5; i++) - vChampionJumpOrigin.push_back(FactionChampionLoc[i]); - else - for (uint8 i = 5; i < 10; i++) - vChampionJumpOrigin.push_back(FactionChampionLoc[i]); + void SummonChampions(Team playerTeam) + { + std::vector<Position> vChampionJumpOrigin; + if (playerTeam == ALLIANCE) + for (uint8 i = 0; i < 5; i++) + vChampionJumpOrigin.push_back(FactionChampionLoc[i]); + else + for (uint8 i = 5; i < 10; i++) + vChampionJumpOrigin.push_back(FactionChampionLoc[i]); - std::vector<Position> vChampionJumpTarget; - for (uint8 i = 10; i < 20; i++) - vChampionJumpTarget.push_back(FactionChampionLoc[i]); - std::vector<uint32> vChampionEntries = SelectChampions(playerTeam); + std::vector<Position> vChampionJumpTarget; + for (uint8 i = 10; i < 20; i++) + vChampionJumpTarget.push_back(FactionChampionLoc[i]); + std::vector<uint32> vChampionEntries = SelectChampions(playerTeam); - for (uint8 i = 0; i < vChampionEntries.size(); ++i) - { - uint8 pos = urand(0, vChampionJumpTarget.size()-1); - if (Creature* temp = me->SummonCreature(vChampionEntries[i], vChampionJumpOrigin[urand(0, vChampionJumpOrigin.size()-1)], TEMPSUMMON_MANUAL_DESPAWN)) + for (uint8 i = 0; i < vChampionEntries.size(); ++i) { - Summons.Summon(temp); - temp->SetReactState(REACT_PASSIVE); - temp->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_IMMUNE_TO_PC); - if (playerTeam == ALLIANCE) + uint8 pos = urand(0, vChampionJumpTarget.size()-1); + if (Creature* temp = me->SummonCreature(vChampionEntries[i], vChampionJumpOrigin[urand(0, vChampionJumpOrigin.size()-1)], TEMPSUMMON_MANUAL_DESPAWN)) { - temp->SetHomePosition(vChampionJumpTarget[pos].GetPositionX(), vChampionJumpTarget[pos].GetPositionY(), vChampionJumpTarget[pos].GetPositionZ(), 0); - temp->GetMotionMaster()->MoveJump(vChampionJumpTarget[pos].GetPositionX(), vChampionJumpTarget[pos].GetPositionY(), vChampionJumpTarget[pos].GetPositionZ(), 20.0f, 20.0f); - temp->SetOrientation(0); - } - else - { - temp->SetHomePosition((ToCCommonLoc[1].GetPositionX()*2)-vChampionJumpTarget[pos].GetPositionX(), vChampionJumpTarget[pos].GetPositionY(), vChampionJumpTarget[pos].GetPositionZ(), 3); - temp->GetMotionMaster()->MoveJump((ToCCommonLoc[1].GetPositionX()*2)-vChampionJumpTarget[pos].GetPositionX(), vChampionJumpTarget[pos].GetPositionY(), vChampionJumpTarget[pos].GetPositionZ(), 20.0f, 20.0f); - temp->SetOrientation(3); + _summons.Summon(temp); + temp->SetReactState(REACT_PASSIVE); + temp->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_IMMUNE_TO_PC); + if (playerTeam == ALLIANCE) + { + temp->SetHomePosition(vChampionJumpTarget[pos].GetPositionX(), vChampionJumpTarget[pos].GetPositionY(), vChampionJumpTarget[pos].GetPositionZ(), 0); + temp->GetMotionMaster()->MoveJump(vChampionJumpTarget[pos].GetPositionX(), vChampionJumpTarget[pos].GetPositionY(), vChampionJumpTarget[pos].GetPositionZ(), 20.0f, 20.0f); + temp->SetOrientation(0); + } + else + { + temp->SetHomePosition((ToCCommonLoc[1].GetPositionX()*2)-vChampionJumpTarget[pos].GetPositionX(), vChampionJumpTarget[pos].GetPositionY(), vChampionJumpTarget[pos].GetPositionZ(), 3); + temp->GetMotionMaster()->MoveJump((ToCCommonLoc[1].GetPositionX()*2)-vChampionJumpTarget[pos].GetPositionX(), vChampionJumpTarget[pos].GetPositionY(), vChampionJumpTarget[pos].GetPositionZ(), 20.0f, 20.0f); + temp->SetOrientation(3); + } } + vChampionJumpTarget.erase(vChampionJumpTarget.begin()+pos); } - vChampionJumpTarget.erase(vChampionJumpTarget.begin()+pos); } - } - void SetData(uint32 uiType, uint32 uiData) - { - switch (uiType) + void SetData(uint32 uiType, uint32 uiData) { - case 0: - SummonChampions((Team)uiData); - break; - case 1: - for (std::list<uint64>::iterator i = Summons.begin(); i != Summons.end(); ++i) - { - if (Creature* temp = Unit::GetCreature(*me, *i)) + switch (uiType) + { + case 0: + SummonChampions((Team)uiData); + break; + case 1: + for (std::list<uint64>::iterator i = _summons.begin(); i != _summons.end(); ++i) { - temp->SetReactState(REACT_AGGRESSIVE); - temp->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_IMMUNE_TO_PC); - } - } - break; - case 2: - switch (uiData) - { - case FAIL: - m_uiChampionsFailed++; - if (m_uiChampionsFailed + m_uiChampionsKilled >= Summons.size()) - { - instance->SetData(TYPE_CRUSADERS, FAIL); - Summons.DespawnAll(); - me->DespawnOrUnsummon(); - } - break; - case IN_PROGRESS: - if (!m_bInProgress) - { - m_uiChampionsNotStarted = 0; - m_uiChampionsFailed = 0; - m_uiChampionsKilled = 0; - m_bInProgress = true; - Summons.DoZoneInCombat(); - instance->SetData(TYPE_CRUSADERS, IN_PROGRESS); - } - break; - case DONE: - m_uiChampionsKilled++; - if (m_uiChampionsKilled == 1) - instance->SetData(TYPE_CRUSADERS, SPECIAL); - else if (m_uiChampionsKilled >= Summons.size()) + if (Creature* temp = Unit::GetCreature(*me, *i)) { - instance->SetData(TYPE_CRUSADERS, DONE); - Summons.DespawnAll(); - me->DespawnOrUnsummon(); + temp->SetReactState(REACT_AGGRESSIVE); + temp->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_IMMUNE_TO_PC); } - break; - } - break; + } + break; + case 2: + switch (uiData) + { + case FAIL: + _championsFailed++; + if (_championsFailed + _championsKilled >= _summons.size()) + { + _instance->SetBossState(BOSS_CRUSADERS, FAIL); + _summons.DespawnAll(); + me->DespawnOrUnsummon(); + } + break; + case IN_PROGRESS: + if (!_inProgress) + { + _championsNotStarted = 0; + _championsFailed = 0; + _championsKilled = 0; + _inProgress = true; + _summons.DoZoneInCombat(); + _instance->SetBossState(BOSS_CRUSADERS, IN_PROGRESS); + } + break; + case DONE: + _championsKilled++; + if (_championsKilled == 1) + _instance->SetBossState(BOSS_CRUSADERS, SPECIAL); + else if (_championsKilled >= _summons.size()) + { + _instance->SetBossState(BOSS_CRUSADERS, DONE); + _summons.DespawnAll(); + me->DespawnOrUnsummon(); + } + break; + default: + break; + } + break; + default: + break; + } } - } - }; + private: + InstanceScript* _instance; + SummonList _summons; + uint32 _championsNotStarted; + uint32 _championsFailed; + uint32 _championsKilled; + bool _inProgress; + }; + CreatureAI* GetAI(Creature* creature) const + { + return new boss_toc_champion_controllerAI (creature); + } }; -struct boss_faction_championsAI : public ScriptedAI +struct boss_faction_championsAI : public BossAI { - boss_faction_championsAI(Creature* creature, uint32 aitype) : ScriptedAI(creature) + boss_faction_championsAI(Creature* creature, uint32 aitype) : BossAI(creature, BOSS_CRUSADERS) { - instance = creature->GetInstanceScript(); - mAIType = aitype; + _aiType = aitype; } - InstanceScript* instance; - - uint64 championControllerGUID; - uint32 mAIType; - uint32 ThreatTimer; - uint32 CCTimer; - void Reset() { - championControllerGUID = 0; - CCTimer = rand()%10000; - ThreatTimer = 5000; + _events.ScheduleEvent(EVENT_THREAT, 5*IN_MILLISECONDS); + if (IsHeroic() && (_aiType != AI_PET)) + _events.ScheduleEvent(EVENT_REMOVE_CC, 5*IN_MILLISECONDS); } void JustReachedHome() @@ -284,9 +566,9 @@ struct boss_faction_championsAI : public ScriptedAI float CalculateThreat(float distance, float armor, uint32 health) { - float dist_mod = (mAIType == AI_MELEE || mAIType == AI_PET) ? 15.0f/(15.0f + distance) : 1.0f; - float armor_mod = (mAIType == AI_MELEE || mAIType == AI_PET) ? armor / 16635.0f : 0.0f; - float eh = (health+1) * (1.0f + armor_mod); + float dist_mod = (_aiType == AI_MELEE || _aiType == AI_PET) ? 15.0f / (15.0f + distance) : 1.0f; + float armor_mod = (_aiType == AI_MELEE || _aiType == AI_PET) ? armor / 16635.0f : 0.0f; + float eh = (health + 1) * (1.0f + armor_mod); return dist_mod * 30000.0f / eh; } @@ -298,7 +580,7 @@ struct boss_faction_championsAI : public ScriptedAI Unit* unit = Unit::GetUnit(*me, (*itr)->getUnitGuid()); if (unit && me->getThreatManager().getThreat(unit)) { - if (unit->GetTypeId()==TYPEID_PLAYER) + if (unit->GetTypeId() == TYPEID_PLAYER) { float threat = CalculateThreat(me->GetDistance2d(unit), (float)unit->GetArmor(), unit->GetHealth()); me->getThreatManager().modifyThreatPercent(unit, -100); @@ -312,8 +594,6 @@ struct boss_faction_championsAI : public ScriptedAI { if (me->getPowerType() == POWER_MANA) me->ModifyPower(POWER_MANA, me->GetMaxPower(POWER_MANA) / 3); - //else if (me->getPowerType() == POWER_ENERGY) - // me->ModifyPower(POWER_ENERGY, 100); } void RemoveCC() @@ -328,7 +608,7 @@ struct boss_faction_championsAI : public ScriptedAI void JustDied(Unit* /*killer*/) { - if (mAIType != AI_PET) + if (_aiType != AI_PET) if (instance) if (Creature* pChampionController = Unit::GetCreature((*me), instance->GetData64(NPC_CHAMPIONS_CONTROLLER))) pChampionController->AI()->SetData(2, DONE); @@ -337,7 +617,7 @@ struct boss_faction_championsAI : public ScriptedAI void EnterCombat(Unit* /*who*/) { DoCast(me, SPELL_ANTI_AOE, true); - me->SetInCombatWithZone(); + _EnterCombat(); if (instance) if (Creature* pChampionController = Unit::GetCreature((*me), instance->GetData64(NPC_CHAMPIONS_CONTROLLER))) pChampionController->AI()->SetData(2, IN_PROGRESS); @@ -377,7 +657,7 @@ struct boss_faction_championsAI : public ScriptedAI std::list<Creature*>::const_iterator itr = lst.begin(); if (lst.empty()) return NULL; - advance(itr, rand()%lst.size()); + advance(itr, rand() % lst.size()); return (*itr); } @@ -401,7 +681,7 @@ struct boss_faction_championsAI : public ScriptedAI std::list<HostileReference*>::const_iterator iter; uint32 count = 0; Unit* target; - for (iter = tList.begin(); iter!=tList.end(); ++iter) + for (iter = tList.begin(); iter != tList.end(); ++iter) { target = Unit::GetUnit(*me, (*iter)->getUnitGuid()); if (target && me->GetDistance2d(target) < distance) @@ -421,7 +701,7 @@ struct boss_faction_championsAI : public ScriptedAI me->SetInCombatWith(who); who->SetInCombatWith(me); - if (mAIType == AI_MELEE || mAIType == AI_PET) + if (_aiType == AI_MELEE || _aiType == AI_PET) DoStartMovement(who); else DoStartMovement(who, 20.0f); @@ -429,1642 +709,1666 @@ struct boss_faction_championsAI : public ScriptedAI } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 diff) { - if (ThreatTimer < uiDiff) - { - UpdatePower(); - UpdateThreat(); - ThreatTimer = 4000; - } - else ThreatTimer -= uiDiff; + _events.Update(diff); - if (mAIType != AI_PET) + while (uint32 eventId = _events.ExecuteEvent()) { - if (CCTimer < uiDiff) - { - RemoveCC(); - CCTimer = 8000+rand()%2000; + switch (eventId) + { + case EVENT_THREAT: + UpdatePower(); + UpdateThreat(); + _events.ScheduleEvent(EVENT_THREAT, 4*IN_MILLISECONDS); + return; + case EVENT_REMOVE_CC: + if (me->HasBreakableByDamageCrowdControlAura()) + { + RemoveCC(); + _events.RescheduleEvent(EVENT_REMOVE_CC, 2*MINUTE*IN_MILLISECONDS); + } + else + _events.RescheduleEvent(EVENT_REMOVE_CC, 3*IN_MILLISECONDS); + return; + default: + return; } - else CCTimer -= uiDiff; } - if (mAIType == AI_MELEE || mAIType == AI_PET) DoMeleeAttackIfReady(); + if (_aiType == AI_MELEE || _aiType == AI_PET) + DoMeleeAttackIfReady(); } + + private: + uint32 _aiType; + // make sure that every bosses separate events dont mix with these _events + EventMap _events; }; /******************************************************************** HEALERS ********************************************************************/ -enum eDruidSpells -{ - SPELL_LIFEBLOOM = 66093, - SPELL_NOURISH = 66066, - SPELL_REGROWTH = 66067, - SPELL_REJUVENATION = 66065, - SPELL_TRANQUILITY = 66086, - SPELL_BARKSKIN = 65860, //1 min cd - SPELL_THORNS = 66068, - SPELL_NATURE_GRASP = 66071, //1 min cd, self buff -}; - class mob_toc_druid : public CreatureScript { -public: - mob_toc_druid() : CreatureScript("mob_toc_druid") { } - - CreatureAI* GetAI(Creature* creature) const - { - return new mob_toc_druidAI (creature); - } - - struct mob_toc_druidAI : public boss_faction_championsAI - { - mob_toc_druidAI(Creature* creature) : boss_faction_championsAI(creature, AI_HEALER) {} - - uint32 m_uiNatureGraspTimer; - uint32 m_uiTranquilityTimer; - uint32 m_uiBarkskinTimer; - uint32 m_uiCommonTimer; - - void Reset() - { - boss_faction_championsAI::Reset(); - m_uiNatureGraspTimer = IN_MILLISECONDS; - m_uiTranquilityTimer = IN_MILLISECONDS; - m_uiBarkskinTimer = IN_MILLISECONDS; - m_uiCommonTimer = IN_MILLISECONDS; - SetEquipmentSlots(false, 51799, EQUIP_NO_CHANGE, EQUIP_NO_CHANGE); - } + public: + mob_toc_druid() : CreatureScript("mob_toc_druid") { } - void UpdateAI(const uint32 uiDiff) + struct mob_toc_druidAI : public boss_faction_championsAI { - if (!UpdateVictim()) - return; + mob_toc_druidAI(Creature* creature) : boss_faction_championsAI(creature, AI_HEALER) {} + + void Reset() + { + boss_faction_championsAI::Reset(); + events.ScheduleEvent(EVENT_LIFEBLOOM, urand(5*IN_MILLISECONDS, 15*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_NOURISH, urand(5*IN_MILLISECONDS, 15*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_REGROWTH, urand(5*IN_MILLISECONDS, 15*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_REJUVENATION, urand(5*IN_MILLISECONDS, 15*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_TRANQUILITY, urand(5*IN_MILLISECONDS, 20*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_HEAL_BARKSKIN, urand(15*IN_MILLISECONDS, 25*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_THORNS, 2*IN_MILLISECONDS); + events.ScheduleEvent(EVENT_NATURE_GRASP, urand(3*IN_MILLISECONDS, 20*IN_MILLISECONDS)); + SetEquipmentSlots(false, 51799, EQUIP_NO_CHANGE, EQUIP_NO_CHANGE); + } - if (m_uiNatureGraspTimer <= uiDiff) + void UpdateAI(const uint32 diff) { - DoCast(me, SPELL_NATURE_GRASP); - m_uiNatureGraspTimer = urand(40*IN_MILLISECONDS, 80*IN_MILLISECONDS); - } else m_uiNatureGraspTimer -= uiDiff; + if (!UpdateVictim()) + return; - if (m_uiTranquilityTimer <= uiDiff) - { - DoCastAOE(SPELL_TRANQUILITY); - m_uiTranquilityTimer = urand(40*IN_MILLISECONDS, 90*IN_MILLISECONDS); - } else m_uiTranquilityTimer -= uiDiff; + events.Update(diff); + boss_faction_championsAI::UpdateAI(diff); - if (m_uiBarkskinTimer <= uiDiff) - { - if (HealthBelowPct(50)) - DoCast(me, SPELL_BARKSKIN); - m_uiBarkskinTimer = urand(45*IN_MILLISECONDS, 90*IN_MILLISECONDS); - } else m_uiBarkskinTimer -= uiDiff; + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; - if (m_uiCommonTimer <= uiDiff) - { - switch (urand(0, 4)) + while (uint32 eventId = events.ExecuteEvent()) { - case 0: - DoCast(me, SPELL_LIFEBLOOM); - break; - case 1: - DoCast(me, SPELL_NOURISH); - break; - case 2: - DoCast(me, SPELL_REGROWTH); - break; - case 3: - DoCast(me, SPELL_REJUVENATION); - break; - case 4: - if (Creature* target = SelectRandomFriendlyMissingBuff(SPELL_THORNS)) - DoCast(target, SPELL_THORNS); - break; + switch (eventId) + { + case EVENT_LIFEBLOOM: + if (Unit* target = DoSelectLowestHpFriendly(40.0f)) + DoCast(target, SPELL_LIFEBLOOM); + events.ScheduleEvent(EVENT_LIFEBLOOM, urand(5*IN_MILLISECONDS, 15*IN_MILLISECONDS)); + return; + case EVENT_NOURISH: + if (Unit* target = DoSelectLowestHpFriendly(40.0f)) + DoCast(target, SPELL_NOURISH); + events.ScheduleEvent(EVENT_NOURISH, urand(5*IN_MILLISECONDS, 15*IN_MILLISECONDS)); + return; + case EVENT_REGROWTH: + if (Unit* target = DoSelectLowestHpFriendly(40.0f)) + DoCast(target, SPELL_REGROWTH); + events.ScheduleEvent(EVENT_REGROWTH, urand(5*IN_MILLISECONDS, 15*IN_MILLISECONDS)); + return; + case EVENT_REJUVENATION: + if (Unit* target = DoSelectLowestHpFriendly(40.0f)) + DoCast(target, SPELL_REJUVENATION); + events.ScheduleEvent(EVENT_REJUVENATION, urand(5*IN_MILLISECONDS, 15*IN_MILLISECONDS)); + return; + case EVENT_TRANQUILITY: + DoCastAOE(SPELL_TRANQUILITY); + events.ScheduleEvent(EVENT_TRANQUILITY, urand(15*IN_MILLISECONDS, 40*IN_MILLISECONDS)); + return; + case EVENT_HEAL_BARKSKIN: + if (HealthBelowPct(30)) + { + DoCast(me, SPELL_BARKSKIN); + events.RescheduleEvent(EVENT_HEAL_BARKSKIN, 60*IN_MILLISECONDS); + } + else + events.RescheduleEvent(EVENT_HEAL_BARKSKIN, 3*IN_MILLISECONDS); + return; + case EVENT_THORNS: + if (Creature* target = SelectRandomFriendlyMissingBuff(SPELL_THORNS)) + DoCast(target, SPELL_THORNS); + events.ScheduleEvent(EVENT_THORNS, urand(25*IN_MILLISECONDS, 40*IN_MILLISECONDS)); + return; + case EVENT_NATURE_GRASP: + DoCast(me, SPELL_NATURE_GRASP); + events.ScheduleEvent(EVENT_NATURE_GRASP, 60*IN_MILLISECONDS); + return; + default: + return; + } } - m_uiCommonTimer = urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS); - } else m_uiCommonTimer -= uiDiff; + } + }; - boss_faction_championsAI::UpdateAI(uiDiff); + CreatureAI* GetAI(Creature* creature) const + { + return new mob_toc_druidAI (creature); } - }; - -}; - -enum eShamanSpells -{ - SPELL_HEALING_WAVE = 66055, - SPELL_RIPTIDE = 66053, - SPELL_SPIRIT_CLEANSE = 66056, //friendly only - SPELL_HEROISM = 65983, - SPELL_BLOODLUST = 65980, - SPELL_HEX = 66054, - SPELL_EARTH_SHIELD = 66063, - SPELL_EARTH_SHOCK = 65973, - AURA_EXHAUSTION = 57723, - AURA_SATED = 57724, }; class mob_toc_shaman : public CreatureScript { -public: - mob_toc_shaman() : CreatureScript("mob_toc_shaman") { } - - CreatureAI* GetAI(Creature* creature) const - { - return new mob_toc_shamanAI (creature); - } - - struct mob_toc_shamanAI : public boss_faction_championsAI - { - mob_toc_shamanAI(Creature* creature) : boss_faction_championsAI(creature, AI_HEALER) {} - - uint32 m_uiHeroismOrBloodlustTimer; - uint32 m_uiHexTimer; - uint32 m_uiCommonTimer; - - void Reset() - { - boss_faction_championsAI::Reset(); - m_uiHeroismOrBloodlustTimer = IN_MILLISECONDS; - m_uiHexTimer = IN_MILLISECONDS; - m_uiCommonTimer = IN_MILLISECONDS; - SetEquipmentSlots(false, 49992, EQUIP_NO_CHANGE, EQUIP_NO_CHANGE); - } + public: + mob_toc_shaman() : CreatureScript("mob_toc_shaman") { } - void UpdateAI(const uint32 uiDiff) + struct mob_toc_shamanAI : public boss_faction_championsAI { - if (!UpdateVictim()) - return; + mob_toc_shamanAI(Creature* creature) : boss_faction_championsAI(creature, AI_HEALER) {} + + void Reset() + { + boss_faction_championsAI::Reset(); + events.ScheduleEvent(EVENT_HEALING_WAVE, urand(5*IN_MILLISECONDS, 10*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_RIPTIDE, urand(5*IN_MILLISECONDS, 20*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_SPIRIT_CLEANSE, urand(15*IN_MILLISECONDS, 25*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_HEAL_BLOODLUST_HEROISM, 20*IN_MILLISECONDS); + events.ScheduleEvent(EVENT_HEX, urand(5*IN_MILLISECONDS, 30*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_EARTH_SHIELD, 1*IN_MILLISECONDS); + events.ScheduleEvent(EVENT_HEAL_EARTH_SHOCK, urand(5*IN_MILLISECONDS, 30*IN_MILLISECONDS)); + SetEquipmentSlots(false, 49992, EQUIP_NO_CHANGE, EQUIP_NO_CHANGE); + } - if (m_uiHeroismOrBloodlustTimer <= uiDiff) + void UpdateAI(const uint32 diff) { - if (me->getFaction()) //Am i alliance? - { - if (!me->HasAura(AURA_EXHAUSTION)) - DoCastAOE(SPELL_HEROISM); - } - else - if (!me->HasAura(AURA_SATED)) - DoCastAOE(SPELL_BLOODLUST); - m_uiHeroismOrBloodlustTimer = 300*IN_MILLISECONDS; - } else m_uiHeroismOrBloodlustTimer -= uiDiff; + if (!UpdateVictim()) + return; - if (m_uiHexTimer <= uiDiff) - { - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) - DoCast(target, SPELL_HEX); - m_uiHexTimer = urand(10*IN_MILLISECONDS, 40*IN_MILLISECONDS); - } else m_uiHexTimer -= uiDiff; + events.Update(diff); + boss_faction_championsAI::UpdateAI(diff); - if (m_uiCommonTimer <= uiDiff) - { - switch (urand(0, 5)) + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) { - case 0: case 1: - DoCast(me, SPELL_HEALING_WAVE); - break; - case 2: - DoCast(me, SPELL_RIPTIDE); - break; - case 3: - DoCast(me, SPELL_EARTH_SHOCK); - break; - case 4: - DoCast(me, SPELL_SPIRIT_CLEANSE); - break; - case 5: - if (Unit* target = SelectRandomFriendlyMissingBuff(SPELL_EARTH_SHIELD)) - DoCast(target, SPELL_EARTH_SHIELD); - break; + switch (eventId) + { + case EVENT_HEALING_WAVE: + if (Unit* target = DoSelectLowestHpFriendly(40.0f)) + DoCast(target, SPELL_HEALING_WAVE); + events.ScheduleEvent(EVENT_HEALING_WAVE, urand(3*IN_MILLISECONDS, 5*IN_MILLISECONDS)); + return; + case EVENT_RIPTIDE: + if (Unit* target = DoSelectLowestHpFriendly(40.0f)) + DoCast(target, SPELL_RIPTIDE); + events.ScheduleEvent(EVENT_RIPTIDE, urand(5*IN_MILLISECONDS, 15*IN_MILLISECONDS)); + return; + case EVENT_SPIRIT_CLEANSE: + if (Unit* target = DoSelectLowestHpFriendly(40.0f)) + DoCast(target, SPELL_SPIRIT_CLEANSE); + events.ScheduleEvent(EVENT_SPIRIT_CLEANSE, urand(15*IN_MILLISECONDS, 35*IN_MILLISECONDS)); + return; + case EVENT_HEAL_BLOODLUST_HEROISM: + if (me->getFaction()) // alliance = 1 + { + if (!me->HasAura(AURA_EXHAUSTION)) + DoCastAOE(SPELL_HEROISM); + } + else + { + if (!me->HasAura(AURA_SATED)) + DoCastAOE(SPELL_BLOODLUST); + } + events.ScheduleEvent(EVENT_HEAL_BLOODLUST_HEROISM, 5*MINUTE*IN_MILLISECONDS); + return; + case EVENT_HEX: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, NonTankTargetSelector(me))) + DoCast(target, SPELL_HEX); + events.ScheduleEvent(EVENT_HEX, urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS)); + return; + case EVENT_EARTH_SHIELD: + if (Creature* target = SelectRandomFriendlyMissingBuff(SPELL_EARTH_SHIELD)) + DoCast(target, SPELL_EARTH_SHIELD); + events.ScheduleEvent(EVENT_EARTH_SHIELD, urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS)); + return; + case EVENT_HEAL_EARTH_SHOCK: + if (Unit* target = SelectEnemyCaster(true)) + DoCast(target, SPELL_EARTH_SHOCK); + events.ScheduleEvent(EVENT_HEAL_EARTH_SHOCK, urand(10*IN_MILLISECONDS, 20*IN_MILLISECONDS)); + return; + default: + return; + } } - m_uiCommonTimer = urand(5*IN_MILLISECONDS, 15*IN_MILLISECONDS); - } else m_uiCommonTimer -= uiDiff; + } + }; - boss_faction_championsAI::UpdateAI(uiDiff); + CreatureAI* GetAI(Creature* creature) const + { + return new mob_toc_shamanAI (creature); } - }; - -}; - -enum ePaladinSpells -{ - SPELL_HAND_OF_FREEDOM = 68757, //25 sec cd - SPELL_BUBBLE = 66010, //5 min cd - SPELL_CLEANSE = 66116, - SPELL_FLASH_OF_LIGHT = 66113, - SPELL_HOLY_LIGHT = 66112, - SPELL_HOLY_SHOCK = 66114, - SPELL_HAND_OF_PROTECTION = 66009, - SPELL_HAMMER_OF_JUSTICE = 66613, }; class mob_toc_paladin : public CreatureScript { -public: - mob_toc_paladin() : CreatureScript("mob_toc_paladin") { } - - CreatureAI* GetAI(Creature* creature) const - { - return new mob_toc_paladinAI (creature); - } - - struct mob_toc_paladinAI : public boss_faction_championsAI - { - mob_toc_paladinAI(Creature* creature) : boss_faction_championsAI(creature, AI_HEALER) {} - - uint32 m_uiBubbleTimer; - uint32 m_uiHandOfProtectionTimer; - uint32 m_uiHolyShockTimer; - uint32 m_uiHandOfFreedomTimer; - uint32 m_uiHammerOfJusticeTimer; - uint32 m_uiCommonTimer; - - void Reset() - { - boss_faction_championsAI::Reset(); - m_uiBubbleTimer = urand(0*IN_MILLISECONDS, 360*IN_MILLISECONDS); - m_uiHandOfProtectionTimer = urand(0*IN_MILLISECONDS, 360*IN_MILLISECONDS); - m_uiHolyShockTimer = urand(6*IN_MILLISECONDS, 15*IN_MILLISECONDS); - m_uiHandOfFreedomTimer = urand(25*IN_MILLISECONDS, 40*IN_MILLISECONDS); - m_uiHammerOfJusticeTimer = urand(5*IN_MILLISECONDS, 15*IN_MILLISECONDS); - m_uiCommonTimer = urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS); - SetEquipmentSlots(false, 50771, 47079, EQUIP_NO_CHANGE); - } + public: + mob_toc_paladin() : CreatureScript("mob_toc_paladin") { } - void UpdateAI(const uint32 uiDiff) + struct mob_toc_paladinAI : public boss_faction_championsAI { - if (!UpdateVictim()) - return; - - if (m_uiBubbleTimer <= uiDiff) - { - //cast bubble at 20% hp - if (HealthBelowPct(20)) - DoCast(me, SPELL_BUBBLE); - m_uiBubbleTimer = urand(0*IN_MILLISECONDS, 360*IN_MILLISECONDS); - } else m_uiBubbleTimer -= uiDiff; + mob_toc_paladinAI(Creature* creature) : boss_faction_championsAI(creature, AI_HEALER) {} + + void Reset() + { + boss_faction_championsAI::Reset(); + events.ScheduleEvent(EVENT_HAND_OF_FREEDOM, urand(10*IN_MILLISECONDS, 20*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_HEAL_DIVINE_SHIELD, 20*IN_MILLISECONDS); + events.ScheduleEvent(EVENT_CLEANSE, urand(20*IN_MILLISECONDS, 30*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_FLASH_OF_LIGHT, urand(5*IN_MILLISECONDS, 10*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_HOLY_LIGHT, urand(10*IN_MILLISECONDS, 15*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_HOLY_SHOCK, urand(10*IN_MILLISECONDS, 15*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_HEAL_HAND_OF_PROTECTION, urand(30*IN_MILLISECONDS, 60*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_HAMMER_OF_JUSTICE, urand(10*IN_MILLISECONDS, 30*IN_MILLISECONDS)); + SetEquipmentSlots(false, 50771, 47079, EQUIP_NO_CHANGE); + } - if (m_uiHandOfProtectionTimer <= uiDiff) + void UpdateAI(const uint32 diff) { - if (Unit* target = DoSelectLowestHpFriendly(40.0f)) - if (target->HealthBelowPct(15)) - DoCast(target, SPELL_HAND_OF_PROTECTION); - m_uiHandOfProtectionTimer = urand(0*IN_MILLISECONDS, 360*IN_MILLISECONDS); - } else m_uiHandOfProtectionTimer -= uiDiff; + if (!UpdateVictim()) + return; - if (m_uiHolyShockTimer <= uiDiff) - { - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) - DoCast(target, SPELL_HOLY_SHOCK); - m_uiHolyShockTimer = urand(6*IN_MILLISECONDS, 15*IN_MILLISECONDS); - } else m_uiHolyShockTimer -= uiDiff; + events.Update(diff); + boss_faction_championsAI::UpdateAI(diff); - if (m_uiHandOfFreedomTimer <= uiDiff) - { - if (Unit* target = SelectRandomFriendlyMissingBuff(SPELL_HAND_OF_FREEDOM)) - DoCast(target, SPELL_HAND_OF_FREEDOM); - m_uiHandOfFreedomTimer = urand(25*IN_MILLISECONDS, 40*IN_MILLISECONDS); - } else m_uiHandOfFreedomTimer -= uiDiff; + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; - if (m_uiHammerOfJusticeTimer <= uiDiff) - { - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) - DoCast(target, SPELL_HAMMER_OF_JUSTICE); - m_uiHammerOfJusticeTimer = urand(5*IN_MILLISECONDS, 15*IN_MILLISECONDS); - } else m_uiHammerOfJusticeTimer -= uiDiff; - - if (m_uiCommonTimer <= uiDiff) - { - switch (urand(0, 4)) + while (uint32 eventId = events.ExecuteEvent()) { - case 0: case 1: - DoCast(me, SPELL_FLASH_OF_LIGHT); - break; - case 2: case 3: - DoCast(me, SPELL_HOLY_LIGHT); - break; - case 4: - DoCast(me, SPELL_CLEANSE); - break; + switch (eventId) + { + case EVENT_HAND_OF_FREEDOM: + if (Unit* target = SelectRandomFriendlyMissingBuff(SPELL_HAND_OF_FREEDOM)) + DoCast(target, SPELL_HAND_OF_FREEDOM); + events.ScheduleEvent(EVENT_HAND_OF_FREEDOM, urand(15*IN_MILLISECONDS, 35*IN_MILLISECONDS)); + return; + case EVENT_HEAL_DIVINE_SHIELD: + if (HealthBelowPct(30) && !me->HasAura(SPELL_FORBEARANCE)) + { + DoCast(me, SPELL_DIVINE_SHIELD); + events.RescheduleEvent(EVENT_HEAL_DIVINE_SHIELD, 5*MINUTE*IN_MILLISECONDS); + } + else + events.RescheduleEvent(EVENT_HEAL_DIVINE_SHIELD, 5*IN_MILLISECONDS); + return; + case EVENT_CLEANSE: + if (Unit* target = DoSelectLowestHpFriendly(40.0f)) + DoCast(target, SPELL_CLEANSE); + events.ScheduleEvent(EVENT_CLEANSE, urand(10*IN_MILLISECONDS, 30*IN_MILLISECONDS)); + return; + case EVENT_FLASH_OF_LIGHT: + if (Unit* target = DoSelectLowestHpFriendly(40.0f)) + DoCast(target, SPELL_FLASH_OF_LIGHT); + events.ScheduleEvent(EVENT_FLASH_OF_LIGHT, urand(3*IN_MILLISECONDS, 5*IN_MILLISECONDS)); + return; + case EVENT_HOLY_LIGHT: + if (Unit* target = DoSelectLowestHpFriendly(40.0f)) + DoCast(target, SPELL_HOLY_LIGHT); + events.ScheduleEvent(EVENT_HOLY_LIGHT, urand(5*IN_MILLISECONDS, 10*IN_MILLISECONDS)); + return; + case EVENT_HOLY_SHOCK: + if (Unit* target = DoSelectLowestHpFriendly(40.0f)) + DoCast(target, SPELL_HOLY_SHOCK); + events.ScheduleEvent(EVENT_HOLY_SHOCK, urand(10*IN_MILLISECONDS, 15*IN_MILLISECONDS)); + return; + case EVENT_HEAL_HAND_OF_PROTECTION: + if (Unit* target = DoSelectLowestHpFriendly(30.0f)) + { + if (!target->HasAura(SPELL_FORBEARANCE)) + { + DoCast(target, SPELL_HAND_OF_PROTECTION); + events.RescheduleEvent(EVENT_HEAL_HAND_OF_PROTECTION, 5*MINUTE*IN_MILLISECONDS); + } + else + events.RescheduleEvent(EVENT_HEAL_HAND_OF_PROTECTION, 3*IN_MILLISECONDS); + } + else + events.RescheduleEvent(EVENT_HEAL_HAND_OF_PROTECTION, 10*IN_MILLISECONDS); + return; + case EVENT_HAMMER_OF_JUSTICE: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 15.0f, true)) + DoCast(target, SPELL_HAMMER_OF_JUSTICE); + events.ScheduleEvent(EVENT_HAMMER_OF_JUSTICE, 40*IN_MILLISECONDS); + return; + default: + return; + } } - m_uiCommonTimer = urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS); - } else m_uiCommonTimer -= uiDiff; + } + }; - boss_faction_championsAI::UpdateAI(uiDiff); + CreatureAI* GetAI(Creature* creature) const + { + return new mob_toc_paladinAI (creature); } - }; - -}; - -enum ePriestSpells -{ - SPELL_RENEW = 66177, - SPELL_SHIELD = 66099, - SPELL_FLASH_HEAL = 66104, - SPELL_DISPEL = 65546, - SPELL_PSYCHIC_SCREAM = 65543, - SPELL_MANA_BURN = 66100, }; class mob_toc_priest : public CreatureScript { -public: - mob_toc_priest() : CreatureScript("mob_toc_priest") { } - - CreatureAI* GetAI(Creature* creature) const - { - return new mob_toc_priestAI (creature); - } - - struct mob_toc_priestAI : public boss_faction_championsAI - { - mob_toc_priestAI(Creature* creature) : boss_faction_championsAI(creature, AI_HEALER) {} - - uint32 m_uiPsychicScreamTimer; - uint32 m_uiCommonTimer; - - void Reset() - { - boss_faction_championsAI::Reset(); - m_uiPsychicScreamTimer = IN_MILLISECONDS; - m_uiCommonTimer = urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS); - SetEquipmentSlots(false, 49992, EQUIP_NO_CHANGE, EQUIP_NO_CHANGE); - } + public: + mob_toc_priest() : CreatureScript("mob_toc_priest") { } - void UpdateAI(const uint32 uiDiff) + struct mob_toc_priestAI : public boss_faction_championsAI { - if (!UpdateVictim()) - return; + mob_toc_priestAI(Creature* creature) : boss_faction_championsAI(creature, AI_HEALER) {} + + void Reset() + { + boss_faction_championsAI::Reset(); + events.ScheduleEvent(EVENT_RENEW, urand(3*IN_MILLISECONDS, 10*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_SHIELD, urand(5*IN_MILLISECONDS, 15*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_FLASH_HEAL, urand(5*IN_MILLISECONDS, 10*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_HEAL_DISPEL, urand(10*IN_MILLISECONDS, 20*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_HEAL_PSYCHIC_SCREAM, urand(10*IN_MILLISECONDS, 30*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_MANA_BURN, urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_PENANCE, urand(10*IN_MILLISECONDS, 20*IN_MILLISECONDS)); + SetEquipmentSlots(false, 49992, EQUIP_NO_CHANGE, EQUIP_NO_CHANGE); + } - if (m_uiPsychicScreamTimer <= uiDiff) + void UpdateAI(const uint32 diff) { - if (EnemiesInRange(10.0f) > 2) - DoCastAOE(SPELL_PSYCHIC_SCREAM); - m_uiPsychicScreamTimer = urand(5*IN_MILLISECONDS, 25*IN_MILLISECONDS); - } else m_uiPsychicScreamTimer -= uiDiff; + if (!UpdateVictim()) + return; - if (m_uiCommonTimer <= uiDiff) - { - switch (urand(0, 5)) + events.Update(diff); + boss_faction_championsAI::UpdateAI(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) { - case 0: - DoCast(me, SPELL_RENEW); - break; - case 1: - DoCast(me, SPELL_SHIELD); - break; - case 2: case 3: - DoCast(me, SPELL_FLASH_HEAL); - break; - case 4: - if (Unit* target = urand(0, 1) ? SelectTarget(SELECT_TARGET_RANDOM, 0) : DoSelectLowestHpFriendly(40.0f)) - DoCast(target, SPELL_DISPEL); - break; - case 5: - DoCast(me, SPELL_MANA_BURN); - break; + switch (eventId) + { + case EVENT_RENEW: + if (Unit* target = DoSelectLowestHpFriendly(40.0f)) + DoCast(target, SPELL_RENEW); + events.ScheduleEvent(EVENT_RENEW, urand(3*IN_MILLISECONDS, 5*IN_MILLISECONDS)); + return; + case EVENT_SHIELD: + if (Unit* target = DoSelectLowestHpFriendly(40.0f)) + DoCast(target, SPELL_SHIELD); + events.ScheduleEvent(EVENT_SHIELD, urand(15*IN_MILLISECONDS, 35*IN_MILLISECONDS)); + return; + case EVENT_FLASH_HEAL: + if (Unit* target = DoSelectLowestHpFriendly(40.0f)) + DoCast(target, SPELL_FLASH_HEAL); + events.ScheduleEvent(EVENT_FLASH_HEAL, urand(3*IN_MILLISECONDS, 5*IN_MILLISECONDS)); + return; + case EVENT_HEAL_DISPEL: + if (Unit* target = urand(0, 1) ? SelectTarget(SELECT_TARGET_RANDOM, 0, 30.0f, true) : DoSelectLowestHpFriendly(40.0f)) + DoCast(target, SPELL_DISPEL); + events.ScheduleEvent(EVENT_HEAL_DISPEL, urand(10*IN_MILLISECONDS, 20*IN_MILLISECONDS)); + return; + case EVENT_HEAL_PSYCHIC_SCREAM: + if (EnemiesInRange(10.0f) >= 2) + DoCastAOE(SPELL_PSYCHIC_SCREAM); + events.ScheduleEvent(EVENT_HEAL_PSYCHIC_SCREAM, urand(10*IN_MILLISECONDS, 25*IN_MILLISECONDS)); + return; + case EVENT_MANA_BURN: + if (Unit* target = SelectEnemyCaster(false)) + DoCast(target, SPELL_MANA_BURN); + events.ScheduleEvent(EVENT_MANA_BURN, urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS)); + return; + case EVENT_PENANCE: + if (Unit* target = DoSelectLowestHpFriendly(40.0f)) + DoCast(target, SPELL_PENANCE); + events.ScheduleEvent(EVENT_PENANCE, urand(10*IN_MILLISECONDS, 20*IN_MILLISECONDS)); + return; + default: + return; + } } - m_uiCommonTimer = urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS); - } else m_uiCommonTimer -= uiDiff; + } + }; - boss_faction_championsAI::UpdateAI(uiDiff); + CreatureAI* GetAI(Creature* creature) const + { + return new mob_toc_priestAI (creature); } - }; - }; /******************************************************************** RANGED ********************************************************************/ -enum eShadowPriestSpells -{ - SPELL_SILENCE = 65542, - SPELL_VAMPIRIC_TOUCH = 65490, - SPELL_SW_PAIN = 65541, - SPELL_MIND_FLAY = 65488, - SPELL_MIND_BLAST = 65492, - SPELL_HORROR = 65545, - SPELL_DISPERSION = 65544, - SPELL_SHADOWFORM = 16592, -}; - class mob_toc_shadow_priest : public CreatureScript { -public: - mob_toc_shadow_priest() : CreatureScript("mob_toc_shadow_priest") { } - - CreatureAI* GetAI(Creature* creature) const - { - return new mob_toc_shadow_priestAI (creature); - } - - struct mob_toc_shadow_priestAI : public boss_faction_championsAI - { - mob_toc_shadow_priestAI(Creature* creature) : boss_faction_championsAI(creature, AI_RANGED) {} - - uint32 m_uiPsychicScreamTimer; - uint32 m_uiDispersionTimer; - uint32 m_uiSilenceTimer; - uint32 m_uiMindBlastTimer; - uint32 m_uiCommonTimer; - - void Reset() - { - boss_faction_championsAI::Reset(); - m_uiPsychicScreamTimer = urand(5*IN_MILLISECONDS, 25*IN_MILLISECONDS); - m_uiDispersionTimer = urand(1*IN_MILLISECONDS, 180*IN_MILLISECONDS); - m_uiSilenceTimer = urand(8*IN_MILLISECONDS, 15*IN_MILLISECONDS); - m_uiMindBlastTimer = urand(3*IN_MILLISECONDS, 8*IN_MILLISECONDS); - m_uiCommonTimer = urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS); - SetEquipmentSlots(false, 50040, EQUIP_NO_CHANGE, EQUIP_NO_CHANGE); - DoCast(me, SPELL_SHADOWFORM); - } - - void EnterCombat(Unit* who) - { - boss_faction_championsAI::EnterCombat(who); - } + public: + mob_toc_shadow_priest() : CreatureScript("mob_toc_shadow_priest") { } - void UpdateAI(const uint32 uiDiff) + struct mob_toc_shadow_priestAI : public boss_faction_championsAI { - if (!UpdateVictim()) - return; - - if (m_uiPsychicScreamTimer <= uiDiff) - { - if (EnemiesInRange(10.0f) > 2) - DoCastAOE(SPELL_PSYCHIC_SCREAM); - m_uiPsychicScreamTimer = urand(5*IN_MILLISECONDS, 25*IN_MILLISECONDS); - } else m_uiPsychicScreamTimer -= uiDiff; + mob_toc_shadow_priestAI(Creature* creature) : boss_faction_championsAI(creature, AI_RANGED) {} + + void Reset() + { + boss_faction_championsAI::Reset(); + events.ScheduleEvent(EVENT_SILENCE, urand(10*IN_MILLISECONDS, 25*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_VAMPIRIC_TOUCH, urand(5*IN_MILLISECONDS, 15*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_SW_PAIN, urand(3*IN_MILLISECONDS, 10*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_MIND_BLAST, urand(5*IN_MILLISECONDS, 15*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_HORROR, urand(10*IN_MILLISECONDS, 25*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_DISPERSION, urand(20*IN_MILLISECONDS, 40*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_DPS_DISPEL, urand(10*IN_MILLISECONDS, 20*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_DPS_PSYCHIC_SCREAM, urand(10*IN_MILLISECONDS, 30*IN_MILLISECONDS)); + SetEquipmentSlots(false, 50040, EQUIP_NO_CHANGE, EQUIP_NO_CHANGE); + DoCast(me, SPELL_SHADOWFORM); + } - if (m_uiDispersionTimer <= uiDiff) + void UpdateAI(const uint32 diff) { - if (HealthBelowPct(20)) - DoCast(me, SPELL_DISPERSION); - m_uiDispersionTimer = urand(1*IN_MILLISECONDS, 180*IN_MILLISECONDS); - } else m_uiDispersionTimer -= uiDiff; + if (!UpdateVictim()) + return; - if (m_uiSilenceTimer <= uiDiff) - { - if (Unit* target = SelectEnemyCaster(false)) - DoCast(target, SPELL_SILENCE); - m_uiSilenceTimer = urand(8*IN_MILLISECONDS, 15*IN_MILLISECONDS); - } else m_uiSilenceTimer -= uiDiff; + events.Update(diff); + boss_faction_championsAI::UpdateAI(diff); - if (m_uiMindBlastTimer <= uiDiff) - { - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) - DoCast(target, SPELL_MIND_BLAST); - m_uiMindBlastTimer = urand(3*IN_MILLISECONDS, 8*IN_MILLISECONDS); - } else m_uiMindBlastTimer -= uiDiff; + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; - if (m_uiCommonTimer <= uiDiff) - { - switch (urand(0, 4)) + while (uint32 eventId = events.ExecuteEvent()) { - case 0: case 1: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) - DoCast(target, SPELL_MIND_FLAY); - break; - case 2: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) - DoCast(target, SPELL_VAMPIRIC_TOUCH); - break; - case 3: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) - DoCast(target, SPELL_SW_PAIN); - break; - case 4: - if (Unit* target = urand(0, 1) ? SelectTarget(SELECT_TARGET_RANDOM, 0) : DoSelectLowestHpFriendly(40.0f)) - DoCast(target, SPELL_DISPEL); - break; + switch (eventId) + { + case EVENT_SILENCE: + if (Unit* target = SelectEnemyCaster(true)) + DoCast(target, SPELL_SILENCE); + events.ScheduleEvent(EVENT_SILENCE, urand(10*IN_MILLISECONDS, 25*IN_MILLISECONDS)); + return; + case EVENT_VAMPIRIC_TOUCH: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 30.0f, true)) + DoCast(target, SPELL_VAMPIRIC_TOUCH); + events.ScheduleEvent(EVENT_VAMPIRIC_TOUCH, urand(10*IN_MILLISECONDS, 35*IN_MILLISECONDS)); + return; + case EVENT_SW_PAIN: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 40.0f, true)) + DoCast(target, SPELL_SW_PAIN); + events.ScheduleEvent(EVENT_SW_PAIN, urand(10*IN_MILLISECONDS, 35*IN_MILLISECONDS)); + return; + case EVENT_MIND_BLAST: + DoCastVictim(SPELL_MIND_BLAST); + events.ScheduleEvent(EVENT_MIND_BLAST, urand(10*IN_MILLISECONDS, 20*IN_MILLISECONDS)); + return; + case EVENT_HORROR: + DoCastVictim(SPELL_HORROR); + events.ScheduleEvent(EVENT_HORROR, urand(15*IN_MILLISECONDS, 35*IN_MILLISECONDS)); + return; + case EVENT_DISPERSION: + if (HealthBelowPct(40)) + { + DoCast(me, SPELL_DISPERSION); + events.RescheduleEvent(EVENT_DISPERSION, 180*IN_MILLISECONDS); + } + else + events.RescheduleEvent(EVENT_DISPERSION, 5*IN_MILLISECONDS); + return; + case EVENT_DPS_DISPEL: + if (Unit* target = urand(0, 1) ? SelectTarget(SELECT_TARGET_RANDOM, 0, 30.0f, true) : DoSelectLowestHpFriendly(40.0f)) + DoCast(target, SPELL_DISPEL); + events.ScheduleEvent(EVENT_DPS_DISPEL, urand(10*IN_MILLISECONDS, 20*IN_MILLISECONDS)); + return; + case EVENT_DPS_PSYCHIC_SCREAM: + if (EnemiesInRange(10.0f) >= 2) + DoCastAOE(SPELL_PSYCHIC_SCREAM); + events.ScheduleEvent(EVENT_DPS_PSYCHIC_SCREAM, urand(10*IN_MILLISECONDS, 25*IN_MILLISECONDS)); + return; + default: + return; + } } - m_uiCommonTimer = urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS); - } else m_uiCommonTimer -= uiDiff; + DoSpellAttackIfReady(SPELL_MIND_FLAY); + } + }; - boss_faction_championsAI::UpdateAI(uiDiff); + CreatureAI* GetAI(Creature* creature) const + { + return new mob_toc_shadow_priestAI (creature); } - }; - -}; - -enum WarlockSpells -{ - SPELL_HELLFIRE = 65816, - SPELL_CORRUPTION = 65810, - SPELL_CURSE_OF_AGONY = 65814, - SPELL_CURSE_OF_EXHAUSTION = 65815, - SPELL_FEAR = 65809, // 8s - SPELL_SEARING_PAIN = 65819, - SPELL_SHADOW_BOLT = 65821, - SPELL_UNSTABLE_AFFLICTION = 65812, // 15s - SPELL_UNSTABLE_AFFLICTION_DISPEL = 65813, - SPELL_SUMMON_FELHUNTER = 67514, }; class mob_toc_warlock : public CreatureScript { -public: - mob_toc_warlock() : CreatureScript("mob_toc_warlock") { } - - CreatureAI* GetAI(Creature* creature) const - { - return new mob_toc_warlockAI (creature); - } - - struct mob_toc_warlockAI : public boss_faction_championsAI - { - mob_toc_warlockAI(Creature* creature) : boss_faction_championsAI(creature, AI_RANGED), Summons(me) {} - - SummonList Summons; - - uint32 m_uiFearTimer; - uint32 m_uiHellfireTimer; - uint32 m_uiUnstableAfflictionTimer; - uint32 m_uiCommonTimer; - uint32 m_uiSummonPetTimer; - - void Reset() - { - boss_faction_championsAI::Reset(); - m_uiFearTimer = urand(4*IN_MILLISECONDS, 15*IN_MILLISECONDS); - m_uiHellfireTimer = urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS); - m_uiUnstableAfflictionTimer = urand(2*IN_MILLISECONDS, 10*IN_MILLISECONDS); - m_uiCommonTimer = urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS); - SetEquipmentSlots(false, 49992, EQUIP_NO_CHANGE, EQUIP_NO_CHANGE); - - m_uiSummonPetTimer = urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS); - DoCast(SPELL_SUMMON_FELHUNTER); - } + public: + mob_toc_warlock() : CreatureScript("mob_toc_warlock") { } - void UpdateAI(const uint32 uiDiff) + struct mob_toc_warlockAI : public boss_faction_championsAI { - if (!UpdateVictim()) - return; + mob_toc_warlockAI(Creature* creature) : boss_faction_championsAI(creature, AI_RANGED) {} + + void Reset() + { + boss_faction_championsAI::Reset(); + events.ScheduleEvent(EVENT_HELLFIRE, urand(10*IN_MILLISECONDS, 30*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_CORRUPTION, urand(2*IN_MILLISECONDS, 5*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_CURSE_OF_AGONY, urand(5*IN_MILLISECONDS, 10*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_CURSE_OF_EXHAUSTION, urand(5*IN_MILLISECONDS, 10*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_FEAR, urand(5*IN_MILLISECONDS, 15*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_SEARING_PAIN, urand(5*IN_MILLISECONDS, 12*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_UNSTABLE_AFFLICTION, urand(7*IN_MILLISECONDS, 15*IN_MILLISECONDS)); + SetEquipmentSlots(false, 49992, EQUIP_NO_CHANGE, EQUIP_NO_CHANGE); + } - if (m_uiFearTimer <= uiDiff) + void EnterCombat(Unit* who) { - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) - DoCast(target, SPELL_FEAR); - m_uiFearTimer = urand(4*IN_MILLISECONDS, 15*IN_MILLISECONDS); - } else m_uiFearTimer -= uiDiff; + boss_faction_championsAI::EnterCombat(who); + DoCast(SPELL_SUMMON_FELHUNTER); + } - if (m_uiHellfireTimer <= uiDiff) + void UpdateAI(const uint32 diff) { - if (EnemiesInRange(10.0f) > 2) - DoCastAOE(SPELL_HELLFIRE); - m_uiHellfireTimer = urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS); - } else m_uiHellfireTimer -= uiDiff; + if (!UpdateVictim()) + return; - if (m_uiUnstableAfflictionTimer <= uiDiff) - { - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) - DoCast(target, SPELL_UNSTABLE_AFFLICTION); - m_uiUnstableAfflictionTimer = urand(2*IN_MILLISECONDS, 10*IN_MILLISECONDS); - } else m_uiUnstableAfflictionTimer -= uiDiff; + events.Update(diff); + boss_faction_championsAI::UpdateAI(diff); - if (m_uiSummonPetTimer <= uiDiff) - { - m_uiSummonPetTimer = urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS); - } else m_uiSummonPetTimer -= uiDiff; + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; - if (m_uiCommonTimer <= uiDiff) - { - switch (urand(0, 5)) + while (uint32 eventId = events.ExecuteEvent()) { - case 0: case 1: - DoCastVictim(SPELL_SHADOW_BOLT); - break; - case 2: - DoCastVictim(SPELL_SEARING_PAIN); - break; - case 3: - DoCastVictim(SPELL_CORRUPTION); - break; - case 4: - DoCastVictim(SPELL_CURSE_OF_AGONY); - break; - case 5: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) - DoCast(target, SPELL_CURSE_OF_EXHAUSTION); - break; + switch (eventId) + { + case EVENT_HELLFIRE: + if (EnemiesInRange(10.0f) >= 2) + DoCastAOE(SPELL_HELLFIRE); + events.ScheduleEvent(EVENT_HELLFIRE, urand(10*IN_MILLISECONDS, 30*IN_MILLISECONDS)); + return; + case EVENT_CORRUPTION: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 30.0f)) + DoCast(target, SPELL_CORRUPTION); + events.ScheduleEvent(EVENT_CORRUPTION, urand(15*IN_MILLISECONDS, 25*IN_MILLISECONDS)); + return; + case EVENT_CURSE_OF_AGONY: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 30.0f)) + DoCast(target, SPELL_CURSE_OF_AGONY); + events.ScheduleEvent(EVENT_CURSE_OF_AGONY, urand(20*IN_MILLISECONDS, 35*IN_MILLISECONDS)); + return; + case EVENT_CURSE_OF_EXHAUSTION: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 30.0f)) + DoCast(target, SPELL_CURSE_OF_EXHAUSTION); + events.ScheduleEvent(EVENT_CURSE_OF_EXHAUSTION, urand(20*IN_MILLISECONDS, 35*IN_MILLISECONDS)); + return; + case EVENT_FEAR: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 20.0f, true)) + DoCast(target, SPELL_FEAR); + events.ScheduleEvent(EVENT_FEAR, urand(5*IN_MILLISECONDS, 20*IN_MILLISECONDS)); + return; + case EVENT_SEARING_PAIN: + DoCastVictim(SPELL_SEARING_PAIN); + events.ScheduleEvent(EVENT_SEARING_PAIN, urand(10*IN_MILLISECONDS, 25*IN_MILLISECONDS)); + return; + case EVENT_UNSTABLE_AFFLICTION: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 30.0f, true)) + DoCast(target, SPELL_UNSTABLE_AFFLICTION); + events.ScheduleEvent(EVENT_UNSTABLE_AFFLICTION, urand(10*IN_MILLISECONDS, 25*IN_MILLISECONDS)); + return; + default: + return; + } } - m_uiCommonTimer = urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS); - } else m_uiCommonTimer -= uiDiff; - boss_faction_championsAI::UpdateAI(uiDiff); - } - }; - -}; + DoSpellAttackIfReady(SPELL_SHADOW_BOLT); + } + }; -enum eMageSpells -{ - SPELL_ARCANE_BARRAGE = 65799, //3s - SPELL_ARCANE_BLAST = 65791, - SPELL_ARCANE_EXPLOSION = 65800, - SPELL_BLINK = 65793, //15s - SPELL_COUNTERSPELL = 65790, //24s - SPELL_FROST_NOVA = 65792, //25s - SPELL_FROSTBOLT = 65807, - SPELL_ICE_BLOCK = 65802, //5min - SPELL_POLYMORPH = 65801, //15s + CreatureAI* GetAI(Creature* creature) const + { + return new mob_toc_warlockAI (creature); + } }; class mob_toc_mage : public CreatureScript { -public: - mob_toc_mage() : CreatureScript("mob_toc_mage") { } - - CreatureAI* GetAI(Creature* creature) const - { - return new mob_toc_mageAI (creature); - } - - struct mob_toc_mageAI : public boss_faction_championsAI - { - mob_toc_mageAI(Creature* creature) : boss_faction_championsAI(creature, AI_RANGED) {} - - uint32 m_uiCounterspellTimer; - uint32 m_uiBlinkTimer; - uint32 m_uiIceBlockTimer; - uint32 m_uiPolymorphTimer; - uint32 m_uiCommonTimer; - - void Reset() - { - boss_faction_championsAI::Reset(); - m_uiCounterspellTimer = urand(5*IN_MILLISECONDS, 15*IN_MILLISECONDS); - m_uiBlinkTimer = urand(7*IN_MILLISECONDS, 25*IN_MILLISECONDS); - m_uiIceBlockTimer = urand(0*IN_MILLISECONDS, 360*IN_MILLISECONDS); - m_uiPolymorphTimer = urand(15*IN_MILLISECONDS, 40*IN_MILLISECONDS); - m_uiCommonTimer = urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS); - SetEquipmentSlots(false, 47524, EQUIP_NO_CHANGE, EQUIP_NO_CHANGE); - } + public: + mob_toc_mage() : CreatureScript("mob_toc_mage") { } - void UpdateAI(const uint32 uiDiff) + struct mob_toc_mageAI : public boss_faction_championsAI { - if (!UpdateVictim()) - return; + mob_toc_mageAI(Creature* creature) : boss_faction_championsAI(creature, AI_RANGED) {} + + void Reset() + { + boss_faction_championsAI::Reset(); + events.ScheduleEvent(EVENT_ARCANE_BARRAGE, urand(1*IN_MILLISECONDS, 5*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_ARCANE_BLAST, urand(3*IN_MILLISECONDS, 5*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_ARCANE_EXPLOSION, urand(5*IN_MILLISECONDS, 15*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_BLINK, urand(15*IN_MILLISECONDS, 20*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_COUNTERSPELL, urand(10*IN_MILLISECONDS, 20*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_FROST_NOVA, urand(5*IN_MILLISECONDS, 20*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_ICE_BLOCK, urand(10*IN_MILLISECONDS, 20*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_POLYMORPH, urand(5*IN_MILLISECONDS, 15*IN_MILLISECONDS)); + SetEquipmentSlots(false, 47524, EQUIP_NO_CHANGE, EQUIP_NO_CHANGE); + } - if (m_uiCounterspellTimer <= uiDiff) + void UpdateAI(const uint32 diff) { - if (Unit* target = SelectEnemyCaster(false)) - DoCast(target, SPELL_COUNTERSPELL); - m_uiCounterspellTimer = urand(5*IN_MILLISECONDS, 15*IN_MILLISECONDS); - } else m_uiCounterspellTimer -= uiDiff; + if (!UpdateVictim()) + return; - if (m_uiBlinkTimer <= uiDiff) - { - if (HealthBelowPct(50) && EnemiesInRange(10.0f) > 3) - { - DoCastAOE(SPELL_FROST_NOVA); - DoCast(SPELL_BLINK); - } - m_uiBlinkTimer = urand(7*IN_MILLISECONDS, 25*IN_MILLISECONDS); - } else m_uiBlinkTimer -= uiDiff; + events.Update(diff); + boss_faction_championsAI::UpdateAI(diff); - if (m_uiIceBlockTimer <= uiDiff) - { - if (HealthBelowPct(20)) - DoCast(me, SPELL_ICE_BLOCK); - m_uiIceBlockTimer = urand(0*IN_MILLISECONDS, 360*IN_MILLISECONDS); - } else m_uiIceBlockTimer -= uiDiff; - - if (m_uiPolymorphTimer <= uiDiff) - { - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) - DoCast(target, SPELL_POLYMORPH); - m_uiPolymorphTimer = urand(15*IN_MILLISECONDS, 40*IN_MILLISECONDS); - } else m_uiPolymorphTimer -= uiDiff; + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; - if (m_uiCommonTimer <= uiDiff) - { - switch (urand(0, 2)) + while (uint32 eventId = events.ExecuteEvent()) { - case 0: - DoCast(me, SPELL_ARCANE_BARRAGE); - break; - case 1: - DoCastVictim(SPELL_ARCANE_BLAST); - break; - case 2: - DoCastVictim(SPELL_FROSTBOLT); - break; + switch (eventId) + { + case EVENT_ARCANE_BARRAGE: + DoCastVictim(SPELL_ARCANE_BARRAGE); + events.ScheduleEvent(EVENT_ARCANE_BARRAGE, urand(5*IN_MILLISECONDS, 7*IN_MILLISECONDS)); + return; + case EVENT_ARCANE_BLAST: + DoCastVictim(SPELL_ARCANE_BLAST); + events.ScheduleEvent(EVENT_ARCANE_BLAST, urand(5*IN_MILLISECONDS, 15*IN_MILLISECONDS)); + return; + case EVENT_ARCANE_EXPLOSION: + if (EnemiesInRange(10.0f) >= 2) + DoCastAOE(SPELL_ARCANE_EXPLOSION); + events.ScheduleEvent(EVENT_ARCANE_EXPLOSION, urand(10*IN_MILLISECONDS, 30*IN_MILLISECONDS)); + return; + case EVENT_BLINK: + if (EnemiesInRange(10.0f) >= 2) + DoCast(SPELL_BLINK); + events.ScheduleEvent(EVENT_BLINK, urand(10*IN_MILLISECONDS, 30*IN_MILLISECONDS)); + return; + case EVENT_COUNTERSPELL: + if (Unit* target = SelectEnemyCaster(true)) + DoCast(target, SPELL_COUNTERSPELL); + events.ScheduleEvent(EVENT_COUNTERSPELL, 24*IN_MILLISECONDS); + return; + case EVENT_FROST_NOVA: + if (EnemiesInRange(10.0f) >= 2) + DoCastAOE(SPELL_FROST_NOVA); + events.ScheduleEvent(EVENT_FROST_NOVA, 25*IN_MILLISECONDS); + return; + case EVENT_ICE_BLOCK: + if (HealthBelowPct(30)) + { + DoCast(SPELL_ICE_BLOCK); + events.RescheduleEvent(EVENT_ICE_BLOCK, 5*MINUTE*IN_MILLISECONDS); + } + else + events.RescheduleEvent(EVENT_ICE_BLOCK, 5*IN_MILLISECONDS); + return; + case EVENT_POLYMORPH: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, NonTankTargetSelector(me))) + DoCast(target, SPELL_POLYMORPH); + events.ScheduleEvent(EVENT_POLYMORPH, urand(10*IN_MILLISECONDS, 30*IN_MILLISECONDS)); + return; + default: + return; + } } - m_uiCommonTimer = urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS); - } else m_uiCommonTimer -= uiDiff; + DoSpellAttackIfReady(SPELL_FROSTBOLT); + } + }; - boss_faction_championsAI::UpdateAI(uiDiff); + CreatureAI* GetAI(Creature* creature) const + { + return new mob_toc_mageAI (creature); } - }; - -}; - -enum eHunterSpells -{ - SPELL_AIMED_SHOT = 65883, - SPELL_DETERRENCE = 65871, //90s - SPELL_DISENGAGE = 65869, //30s - SPELL_EXPLOSIVE_SHOT = 65866, - SPELL_FROST_TRAP = 65880, //30s - SPELL_SHOOT = 65868, //1.7s - SPELL_STEADY_SHOT = 65867, //3s - SPELL_WING_CLIP = 66207, //6s - SPELL_WYVERN_STING = 65877, //60s - SPELL_CALL_PET = 67777, }; class mob_toc_hunter : public CreatureScript { -public: - mob_toc_hunter() : CreatureScript("mob_toc_hunter") { } - - CreatureAI* GetAI(Creature* creature) const - { - return new mob_toc_hunterAI (creature); - } - - struct mob_toc_hunterAI : public boss_faction_championsAI - { - mob_toc_hunterAI(Creature* creature) : boss_faction_championsAI(creature, AI_RANGED), Summons(me) {} - - SummonList Summons; - - uint32 m_uiDisengageTimer; - uint32 m_uiDeterrenceTimer; - uint32 m_uiWyvernStingTimer; - uint32 m_uiFrostTrapTimer; - uint32 m_uiWingClipTimer; - uint32 m_uiCommonTimer; - uint32 m_uiSummonPetTimer; - - void Reset() - { - boss_faction_championsAI::Reset(); - m_uiDisengageTimer = urand(12*IN_MILLISECONDS, 20*IN_MILLISECONDS); - m_uiDeterrenceTimer = urand(20*IN_MILLISECONDS, 120*IN_MILLISECONDS); - m_uiWyvernStingTimer = urand(7*IN_MILLISECONDS, 60*IN_MILLISECONDS); - m_uiFrostTrapTimer = urand(12*IN_MILLISECONDS, 30*IN_MILLISECONDS); - m_uiWingClipTimer = urand(4*IN_MILLISECONDS, 8*IN_MILLISECONDS); - m_uiCommonTimer = urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS); - SetEquipmentSlots(false, 47156, EQUIP_NO_CHANGE, 48711); - - m_uiSummonPetTimer = urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS); - DoCast(SPELL_CALL_PET); - } + public: + mob_toc_hunter() : CreatureScript("mob_toc_hunter") { } - void UpdateAI(const uint32 uiDiff) + struct mob_toc_hunterAI : public boss_faction_championsAI { - if (!UpdateVictim()) - return; - - if (m_uiDisengageTimer <= uiDiff) - { - if (EnemiesInRange(10.0f) > 3) - DoCast(SPELL_DISENGAGE); - m_uiDisengageTimer = urand(12*IN_MILLISECONDS, 20*IN_MILLISECONDS); - } else m_uiDisengageTimer -= uiDiff; + mob_toc_hunterAI(Creature* creature) : boss_faction_championsAI(creature, AI_RANGED) {} + + void Reset() + { + boss_faction_championsAI::Reset(); + events.ScheduleEvent(EVENT_AIMED_SHOT, urand(5*IN_MILLISECONDS, 10*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_DETERRENCE, urand(10*IN_MILLISECONDS, 20*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_DISENGAGE, urand(10*IN_MILLISECONDS, 20*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_EXPLOSIVE_SHOT, urand(3*IN_MILLISECONDS, 5*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_FROST_TRAP, urand(10*IN_MILLISECONDS, 20*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_STEADY_SHOT, urand(5*IN_MILLISECONDS, 10*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_WING_CLIP, urand(10*IN_MILLISECONDS, 20*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_WYVERN_STING, urand(10*IN_MILLISECONDS, 25*IN_MILLISECONDS)); + SetEquipmentSlots(false, 47156, EQUIP_NO_CHANGE, 48711); + } - if (m_uiDeterrenceTimer <= uiDiff) + void EnterCombat(Unit* who) { - if (HealthBelowPct(20)) - DoCast(SPELL_DETERRENCE); - m_uiDeterrenceTimer = urand(20*IN_MILLISECONDS, 120*IN_MILLISECONDS); - } else m_uiDeterrenceTimer -= uiDiff; + boss_faction_championsAI::EnterCombat(who); + DoCast(SPELL_CALL_PET); + } - if (m_uiWyvernStingTimer <= uiDiff) + void UpdateAI(const uint32 diff) { - DoCastVictim(SPELL_WYVERN_STING); - m_uiWyvernStingTimer = urand(7*IN_MILLISECONDS, 60*IN_MILLISECONDS); - } else m_uiWyvernStingTimer -= uiDiff; + if (!UpdateVictim()) + return; - if (m_uiFrostTrapTimer <= uiDiff) - { - DoCast(SPELL_FROST_TRAP); - m_uiFrostTrapTimer = urand(12*IN_MILLISECONDS, 30*IN_MILLISECONDS); - } else m_uiFrostTrapTimer -= uiDiff; + events.Update(diff); + boss_faction_championsAI::UpdateAI(diff); - if (m_uiWingClipTimer <= uiDiff) - { - if (me->GetDistance2d(me->getVictim()) < 5.0f) - DoCastVictim(SPELL_WING_CLIP); - m_uiWingClipTimer = urand(4*IN_MILLISECONDS, 8*IN_MILLISECONDS); - } else m_uiWingClipTimer -= uiDiff; + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; - if (m_uiSummonPetTimer <= uiDiff) - { - m_uiSummonPetTimer = urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS); - } else m_uiSummonPetTimer -= uiDiff; - - if (m_uiCommonTimer <= uiDiff) - { - switch (urand(0, 3)) + while (uint32 eventId = events.ExecuteEvent()) { - case 0: case 1: - DoCastVictim(SPELL_SHOOT); - break; - case 2: - DoCastVictim(SPELL_EXPLOSIVE_SHOT); - break; - case 3: - DoCastVictim(SPELL_AIMED_SHOT); - break; + switch (eventId) + { + case EVENT_AIMED_SHOT: + DoCastVictim(SPELL_AIMED_SHOT); + events.ScheduleEvent(EVENT_AIMED_SHOT, urand(10*IN_MILLISECONDS, 15*IN_MILLISECONDS)); + return; + case EVENT_DETERRENCE: + if (HealthBelowPct(30)) + { + DoCast(SPELL_DETERRENCE); + events.RescheduleEvent(EVENT_DETERRENCE, 150*IN_MILLISECONDS); + } + else + events.RescheduleEvent(EVENT_DETERRENCE, 10*IN_MILLISECONDS); + return; + case EVENT_DISENGAGE: + if (EnemiesInRange(10.0f) >= 2) + DoCast(SPELL_DISENGAGE); + events.ScheduleEvent(EVENT_DISENGAGE, 30*IN_MILLISECONDS); + return; + case EVENT_EXPLOSIVE_SHOT: + DoCastVictim(SPELL_EXPLOSIVE_SHOT); + events.ScheduleEvent(EVENT_EXPLOSIVE_SHOT, urand(6*IN_MILLISECONDS, 10*IN_MILLISECONDS)); + return; + case EVENT_FROST_TRAP: + if (EnemiesInRange(10.0f) >= 2) + DoCastAOE(SPELL_FROST_TRAP); + events.ScheduleEvent(EVENT_FROST_TRAP, 30*IN_MILLISECONDS); + return; + case EVENT_STEADY_SHOT: + DoCastVictim(SPELL_STEADY_SHOT); + events.ScheduleEvent(EVENT_STEADY_SHOT, urand(5*IN_MILLISECONDS, 15*IN_MILLISECONDS)); + return; + case EVENT_WING_CLIP: + if (me->GetDistance2d(me->getVictim()) < 6.0f) + DoCastVictim(SPELL_WING_CLIP); + events.ScheduleEvent(EVENT_WING_CLIP, urand(15*IN_MILLISECONDS, 25*IN_MILLISECONDS)); + return; + case EVENT_WYVERN_STING: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, NonTankTargetSelector(me))) + DoCast(target, SPELL_WYVERN_STING); + events.ScheduleEvent(EVENT_WYVERN_STING, urand(10*IN_MILLISECONDS, 30*IN_MILLISECONDS)); + return; + default: + return; + } } - m_uiCommonTimer = urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS); - } else m_uiCommonTimer -= uiDiff; + DoSpellAttackIfReady(SPELL_SHOOT); + } + }; - boss_faction_championsAI::UpdateAI(uiDiff); + CreatureAI* GetAI(Creature* creature) const + { + return new mob_toc_hunterAI (creature); } - }; - -}; - -enum eBoomkinSpells -{ - SPELL_CYCLONE = 65859, //6s - SPELL_ENTANGLING_ROOTS = 65857, //10s - SPELL_FAERIE_FIRE = 65863, - SPELL_FORCE_OF_NATURE = 65861, //180s - SPELL_INSECT_SWARM = 65855, - SPELL_MOONFIRE = 65856, //5s - SPELL_STARFIRE = 65854, - SPELL_WRATH = 65862, }; class mob_toc_boomkin : public CreatureScript { -public: - mob_toc_boomkin() : CreatureScript("mob_toc_boomkin") { } - - CreatureAI* GetAI(Creature* creature) const - { - return new mob_toc_boomkinAI (creature); - } - - struct mob_toc_boomkinAI : public boss_faction_championsAI - { - mob_toc_boomkinAI(Creature* creature) : boss_faction_championsAI(creature, AI_RANGED) {} - - uint32 m_uiBarkskinTimer; - uint32 m_uiCycloneTimer; - uint32 m_uiEntanglingRootsTimer; - uint32 m_uiFaerieFireTimer; - uint32 m_uiCommonTimer; - - void Reset() - { - boss_faction_championsAI::Reset(); - m_uiBarkskinTimer = urand(5*IN_MILLISECONDS, 120*IN_MILLISECONDS); - m_uiCycloneTimer = urand(5*IN_MILLISECONDS, 40*IN_MILLISECONDS); - m_uiEntanglingRootsTimer = urand(5*IN_MILLISECONDS, 40*IN_MILLISECONDS); - m_uiFaerieFireTimer = urand(10*IN_MILLISECONDS, 40*IN_MILLISECONDS); - m_uiCommonTimer = urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS); - SetEquipmentSlots(false, 50966, EQUIP_NO_CHANGE, EQUIP_NO_CHANGE); - } + public: + mob_toc_boomkin() : CreatureScript("mob_toc_boomkin") { } - void UpdateAI(const uint32 uiDiff) + struct mob_toc_boomkinAI : public boss_faction_championsAI { - if (!UpdateVictim()) - return; + mob_toc_boomkinAI(Creature* creature) : boss_faction_championsAI(creature, AI_RANGED) {} - if (m_uiBarkskinTimer <= uiDiff) + void Reset() { - if (HealthBelowPct(50)) - DoCast(me, SPELL_BARKSKIN); - m_uiBarkskinTimer = urand(5*IN_MILLISECONDS, 120*IN_MILLISECONDS); - } else m_uiBarkskinTimer -= uiDiff; + boss_faction_championsAI::Reset(); + events.ScheduleEvent(EVENT_CYCLONE, urand(10*IN_MILLISECONDS, 20*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_ENTANGLING_ROOTS, urand(10*IN_MILLISECONDS, 20*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_FAERIE_FIRE, urand(2*IN_MILLISECONDS, 5*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_FORCE_OF_NATURE, urand(20*IN_MILLISECONDS, 30*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_INSECT_SWARM, urand(5*IN_MILLISECONDS, 10*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_MOONFIRE, urand(10*IN_MILLISECONDS, 20*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_STARFIRE, urand(10*IN_MILLISECONDS, 20*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_DPS_BARKSKIN, urand(20*IN_MILLISECONDS, 30*IN_MILLISECONDS)); - if (m_uiCycloneTimer <= uiDiff) - { - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) - DoCast(target, SPELL_CYCLONE); - m_uiCycloneTimer = urand(5*IN_MILLISECONDS, 40*IN_MILLISECONDS); - } else m_uiCycloneTimer -= uiDiff; + SetEquipmentSlots(false, 50966, EQUIP_NO_CHANGE, EQUIP_NO_CHANGE); + } - if (m_uiEntanglingRootsTimer <= uiDiff) + void UpdateAI(const uint32 diff) { - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) - DoCast(target, SPELL_ENTANGLING_ROOTS); - m_uiEntanglingRootsTimer = urand(5*IN_MILLISECONDS, 40*IN_MILLISECONDS); - } else m_uiEntanglingRootsTimer -= uiDiff; + if (!UpdateVictim()) + return; - if (m_uiFaerieFireTimer <= uiDiff) - { - DoCastVictim(SPELL_FAERIE_FIRE); - m_uiFaerieFireTimer = urand(10*IN_MILLISECONDS, 40*IN_MILLISECONDS); - } else m_uiFaerieFireTimer -= uiDiff; + events.Update(diff); + boss_faction_championsAI::UpdateAI(diff); - if (m_uiCommonTimer <= uiDiff) - { - switch (urand(0, 6)) + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) { - case 0: case 1: - DoCastVictim(SPELL_MOONFIRE); - break; - case 2: - DoCastVictim(SPELL_INSECT_SWARM); - break; - case 3: - DoCastVictim(SPELL_STARFIRE); - break; - case 4: case 5: case 6: - DoCastVictim(SPELL_WRATH); - break; + switch (eventId) + { + case EVENT_CYCLONE: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, NonTankTargetSelector(me))) + DoCast(target, SPELL_CYCLONE); + events.ScheduleEvent(EVENT_CYCLONE, urand(10*IN_MILLISECONDS, 20*IN_MILLISECONDS)); + return; + case EVENT_ENTANGLING_ROOTS: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 30.0f, true)) + DoCast(target, SPELL_ENTANGLING_ROOTS); + events.ScheduleEvent(EVENT_ENTANGLING_ROOTS, urand(10*IN_MILLISECONDS, 20*IN_MILLISECONDS)); + return; + case EVENT_FAERIE_FIRE: + DoCastVictim(SPELL_FAERIE_FIRE); + events.ScheduleEvent(EVENT_FAERIE_FIRE, urand(30*IN_MILLISECONDS, 40*IN_MILLISECONDS)); + return; + case EVENT_FORCE_OF_NATURE: + DoCastVictim(SPELL_FORCE_OF_NATURE); + events.ScheduleEvent(EVENT_FORCE_OF_NATURE, 180*IN_MILLISECONDS); + return; + case EVENT_INSECT_SWARM: + DoCastVictim(SPELL_INSECT_SWARM); + events.ScheduleEvent(EVENT_INSECT_SWARM, urand(15*IN_MILLISECONDS, 25*IN_MILLISECONDS)); + return; + case EVENT_MOONFIRE: + DoCastVictim(SPELL_MOONFIRE); + events.ScheduleEvent(EVENT_MOONFIRE, urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS)); + return; + case EVENT_STARFIRE: + DoCastVictim(SPELL_STARFIRE); + events.ScheduleEvent(EVENT_STARFIRE, urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS)); + return; + case EVENT_DPS_BARKSKIN: + if (HealthBelowPct(30)) + { + DoCast(me, SPELL_BARKSKIN); + events.RescheduleEvent(EVENT_DPS_BARKSKIN, 60*IN_MILLISECONDS); + } + else + events.RescheduleEvent(EVENT_DPS_BARKSKIN, 5*IN_MILLISECONDS); + return; + default: + return; + } } - m_uiCommonTimer = urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS); - } else m_uiCommonTimer -= uiDiff; + DoSpellAttackIfReady(SPELL_WRATH); + } + }; - boss_faction_championsAI::UpdateAI(uiDiff); + CreatureAI* GetAI(Creature* creature) const + { + return new mob_toc_boomkinAI (creature); } - }; - }; /******************************************************************** MELEE ********************************************************************/ -enum eWarriorSpells -{ - SPELL_BLADESTORM = 65947, - SPELL_INTIMIDATING_SHOUT = 65930, - SPELL_MORTAL_STRIKE = 65926, - SPELL_CHARGE = 68764, - SPELL_DISARM = 65935, - SPELL_OVERPOWER = 65924, - SPELL_SUNDER_ARMOR = 65936, - SPELL_SHATTERING_THROW = 65940, - SPELL_RETALIATION = 65932, -}; - class mob_toc_warrior : public CreatureScript { -public: - mob_toc_warrior() : CreatureScript("mob_toc_warrior") { } - - CreatureAI* GetAI(Creature* creature) const - { - return new mob_toc_warriorAI (creature); - } - - struct mob_toc_warriorAI : public boss_faction_championsAI - { - mob_toc_warriorAI(Creature* creature) : boss_faction_championsAI(creature, AI_MELEE) {} - - uint32 m_uiBladestormTimer; - uint32 m_uiIntimidatingShoutTimer; - uint32 m_uiMortalStrikeTimer; - uint32 m_uiSunderArmorTimer; - uint32 m_uiChargeTimer; - uint32 m_uiRetaliationTimer; - uint32 m_uiOverpowerTimer; - uint32 m_uiShatteringThrowTimer; - uint32 m_uiDisarmTimer; - - void Reset() - { - boss_faction_championsAI::Reset(); - m_uiBladestormTimer = urand(20*IN_MILLISECONDS, 30*IN_MILLISECONDS); - m_uiIntimidatingShoutTimer = urand(10*IN_MILLISECONDS, 60*IN_MILLISECONDS); - m_uiMortalStrikeTimer = urand(6*IN_MILLISECONDS, 25*IN_MILLISECONDS); - m_uiSunderArmorTimer = urand(5*IN_MILLISECONDS, 25*IN_MILLISECONDS); - m_uiChargeTimer = urand(3*IN_MILLISECONDS, 25*IN_MILLISECONDS); - m_uiRetaliationTimer = urand(30*IN_MILLISECONDS, 60*IN_MILLISECONDS); - m_uiOverpowerTimer = urand(30*IN_MILLISECONDS, 90*IN_MILLISECONDS); - m_uiShatteringThrowTimer = urand(10*IN_MILLISECONDS, 25*IN_MILLISECONDS); - m_uiDisarmTimer = urand(20*IN_MILLISECONDS, 80*IN_MILLISECONDS); - SetEquipmentSlots(false, 47427, 46964, EQUIP_NO_CHANGE); - } + public: + mob_toc_warrior() : CreatureScript("mob_toc_warrior") { } - void UpdateAI(const uint32 uiDiff) + struct mob_toc_warriorAI : public boss_faction_championsAI { - if (!UpdateVictim()) - return; - - if (m_uiBladestormTimer <= uiDiff) - { - DoCastVictim(SPELL_BLADESTORM); - m_uiBladestormTimer = urand(20*IN_MILLISECONDS, 30*IN_MILLISECONDS); - } else m_uiBladestormTimer -= uiDiff; - - if (m_uiIntimidatingShoutTimer <= uiDiff) - { - DoCast(me, SPELL_INTIMIDATING_SHOUT); - m_uiIntimidatingShoutTimer = urand(10*IN_MILLISECONDS, 60*IN_MILLISECONDS); - } else m_uiIntimidatingShoutTimer -= uiDiff; - - if (m_uiMortalStrikeTimer <= uiDiff) - { - DoCastVictim(SPELL_MORTAL_STRIKE); - m_uiMortalStrikeTimer = urand(6*IN_MILLISECONDS, 25*IN_MILLISECONDS); - } else m_uiMortalStrikeTimer -= uiDiff; - - if (m_uiSunderArmorTimer <= uiDiff) - { - DoCastVictim(SPELL_SUNDER_ARMOR); - m_uiSunderArmorTimer = urand(5*IN_MILLISECONDS, 25*IN_MILLISECONDS); - } else m_uiSunderArmorTimer -= uiDiff; - - if (m_uiChargeTimer <= uiDiff) - { - DoCastVictim(SPELL_CHARGE); - m_uiChargeTimer = urand(3*IN_MILLISECONDS, 25*IN_MILLISECONDS); - } else m_uiChargeTimer -= uiDiff; + mob_toc_warriorAI(Creature* creature) : boss_faction_championsAI(creature, AI_MELEE) {} + + void Reset() + { + boss_faction_championsAI::Reset(); + events.ScheduleEvent(EVENT_BLADESTORM, urand(10*IN_MILLISECONDS, 15*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_INTIMIDATING_SHOUT, urand(20*IN_MILLISECONDS, 25*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_MORTAL_STRIKE, urand(5*IN_MILLISECONDS, 20*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_WARR_CHARGE, 1*IN_MILLISECONDS); + events.ScheduleEvent(EVENT_DISARM, urand(5*IN_MILLISECONDS, 20*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_OVERPOWER, urand(10*IN_MILLISECONDS, 20*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_SUNDER_ARMOR, urand(5*IN_MILLISECONDS, 10*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_SHATTERING_THROW, urand(20*IN_MILLISECONDS, 40*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_RETALIATION, urand(5*IN_MILLISECONDS, 20*IN_MILLISECONDS)); + SetEquipmentSlots(false, 47427, 46964, EQUIP_NO_CHANGE); + } - if (m_uiRetaliationTimer <= uiDiff) + void UpdateAI(const uint32 diff) { - DoCastVictim(SPELL_RETALIATION); - m_uiRetaliationTimer = urand(30*IN_MILLISECONDS, 60*IN_MILLISECONDS); - } else m_uiRetaliationTimer -= uiDiff; + if (!UpdateVictim()) + return; - if (m_uiOverpowerTimer <= uiDiff) - { - DoCastVictim(SPELL_OVERPOWER); - m_uiOverpowerTimer = urand(30*IN_MILLISECONDS, 90*IN_MILLISECONDS); - } else m_uiOverpowerTimer -= uiDiff; + events.Update(diff); + boss_faction_championsAI::UpdateAI(diff); - if (m_uiShatteringThrowTimer <= uiDiff) - { - DoCastVictim(SPELL_SHATTERING_THROW); - m_uiShatteringThrowTimer = urand(10*IN_MILLISECONDS, 25*IN_MILLISECONDS); - } else m_uiShatteringThrowTimer -= uiDiff; + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; - if (m_uiDisarmTimer <= uiDiff) - { - DoCastVictim(SPELL_DISARM); - m_uiDisarmTimer = urand(20*IN_MILLISECONDS, 80*IN_MILLISECONDS); - } else m_uiDisarmTimer -= uiDiff; + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_BLADESTORM: + DoCastVictim(SPELL_BLADESTORM); + events.ScheduleEvent(EVENT_BLADESTORM, 150*IN_MILLISECONDS); + return; + case EVENT_INTIMIDATING_SHOUT: + DoCastAOE(SPELL_INTIMIDATING_SHOUT); + events.ScheduleEvent(EVENT_INTIMIDATING_SHOUT, 120*IN_MILLISECONDS); + return; + case EVENT_MORTAL_STRIKE: + DoCastVictim(SPELL_MORTAL_STRIKE); + events.ScheduleEvent(EVENT_MORTAL_STRIKE, urand(10*IN_MILLISECONDS, 25*IN_MILLISECONDS)); + return; + case EVENT_WARR_CHARGE: + DoCastVictim(SPELL_CHARGE); + events.ScheduleEvent(EVENT_WARR_CHARGE, urand(10*IN_MILLISECONDS, 20*IN_MILLISECONDS)); + return; + case EVENT_DISARM: + DoCastVictim(SPELL_DISARM); + events.ScheduleEvent(EVENT_DISARM, urand(15*IN_MILLISECONDS, 35*IN_MILLISECONDS)); + return; + case EVENT_OVERPOWER: + DoCastVictim(SPELL_OVERPOWER); + events.ScheduleEvent(EVENT_OVERPOWER, urand(20*IN_MILLISECONDS, 40*IN_MILLISECONDS)); + return; + case EVENT_SUNDER_ARMOR: + DoCastVictim(SPELL_SUNDER_ARMOR); + events.ScheduleEvent(EVENT_SUNDER_ARMOR, urand(2*IN_MILLISECONDS, 5*IN_MILLISECONDS)); + return; + case EVENT_SHATTERING_THROW: + if (me->getVictim()->HasAuraWithMechanic(1<<MECHANIC_IMMUNE_SHIELD)) + { + DoCastVictim(SPELL_SHATTERING_THROW); + events.RescheduleEvent(EVENT_SHATTERING_THROW, 5*MINUTE*IN_MILLISECONDS); + } + else + events.RescheduleEvent(EVENT_SHATTERING_THROW, 3*IN_MILLISECONDS); + return; + case EVENT_RETALIATION: + if (HealthBelowPct(50)) + { + DoCast(SPELL_RETALIATION); + events.RescheduleEvent(EVENT_RETALIATION, 5*MINUTE*IN_MILLISECONDS); + } + else + events.RescheduleEvent(EVENT_RETALIATION, 5*IN_MILLISECONDS); + return; + default: + return; + } + } + } + }; - boss_faction_championsAI::UpdateAI(uiDiff); + CreatureAI* GetAI(Creature* creature) const + { + return new mob_toc_warriorAI (creature); } - }; - -}; - -enum eDeathKnightSpells -{ - SPELL_CHAINS_OF_ICE = 66020, //8sec - SPELL_DEATH_COIL = 66019, //5sec - SPELL_DEATH_GRIP = 66017, //35sec - SPELL_FROST_STRIKE = 66047, //6sec - SPELL_ICEBOUND_FORTITUDE = 66023, //1min - SPELL_ICY_TOUCH = 66021, //8sec - SPELL_STRANGULATE = 66018, //2min }; class mob_toc_dk : public CreatureScript { -public: - mob_toc_dk() : CreatureScript("mob_toc_dk") { } - - CreatureAI* GetAI(Creature* creature) const - { - return new mob_toc_dkAI (creature); - } - - struct mob_toc_dkAI : public boss_faction_championsAI - { - mob_toc_dkAI(Creature* creature) : boss_faction_championsAI(creature, AI_MELEE) {} - - uint32 m_uiIceboundFortitudeTimer; - uint32 m_uiChainsOfIceTimer; - uint32 m_uiDeathCoilTimer; - uint32 m_uiStrangulateTimer; - uint32 m_uiFrostStrikeTimer; - uint32 m_uiIcyTouchTimer; - uint32 m_uiDeathGripTimer; - - void Reset() - { - boss_faction_championsAI::Reset(); - m_uiIceboundFortitudeTimer = urand(5*IN_MILLISECONDS, 90*IN_MILLISECONDS); - m_uiChainsOfIceTimer = urand(5*IN_MILLISECONDS, 15*IN_MILLISECONDS); - m_uiDeathCoilTimer = urand(5*IN_MILLISECONDS, 15*IN_MILLISECONDS); - m_uiStrangulateTimer = urand(10*IN_MILLISECONDS, 90*IN_MILLISECONDS); - m_uiFrostStrikeTimer = urand(5*IN_MILLISECONDS, 15*IN_MILLISECONDS); - m_uiIcyTouchTimer = urand(8*IN_MILLISECONDS, 12*IN_MILLISECONDS); - m_uiDeathGripTimer = urand(5*IN_MILLISECONDS, 15*IN_MILLISECONDS); - SetEquipmentSlots(false, 47518, 51021, EQUIP_NO_CHANGE); - } + public: + mob_toc_dk() : CreatureScript("mob_toc_dk") { } - void UpdateAI(const uint32 uiDiff) + struct mob_toc_dkAI : public boss_faction_championsAI { - if (!UpdateVictim()) - return; - - if (m_uiIceboundFortitudeTimer <= uiDiff) - { - if (HealthBelowPct(50)) - DoCast(me, SPELL_ICEBOUND_FORTITUDE); - m_uiIceboundFortitudeTimer = urand(5*IN_MILLISECONDS, 90*IN_MILLISECONDS); - } else m_uiIceboundFortitudeTimer -= uiDiff; - - if (m_uiChainsOfIceTimer <= uiDiff) - { - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) - DoCast(target, SPELL_CHAINS_OF_ICE); - m_uiChainsOfIceTimer = urand(5*IN_MILLISECONDS, 15*IN_MILLISECONDS); - } else m_uiChainsOfIceTimer -= uiDiff; - - if (m_uiDeathCoilTimer <= uiDiff) - { - DoCastVictim(SPELL_DEATH_COIL); - m_uiDeathCoilTimer = urand(5*IN_MILLISECONDS, 15*IN_MILLISECONDS); - } else m_uiDeathCoilTimer -= uiDiff; + mob_toc_dkAI(Creature* creature) : boss_faction_championsAI(creature, AI_MELEE) {} + + void Reset() + { + boss_faction_championsAI::Reset(); + events.ScheduleEvent(EVENT_CHAINS_OF_ICE, urand(5*IN_MILLISECONDS, 15*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_DEATH_COIL, urand(10*IN_MILLISECONDS, 20*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_DEATH_GRIP, urand(15*IN_MILLISECONDS, 25*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_FROST_STRIKE, urand(5*IN_MILLISECONDS, 10*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_ICEBOUND_FORTITUDE, urand(25*IN_MILLISECONDS, 35*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_ICY_TOUCH, urand(10*IN_MILLISECONDS, 20*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_STRANGULATE, urand(5*IN_MILLISECONDS, 25*IN_MILLISECONDS)); + SetEquipmentSlots(false, 47518, 51021, EQUIP_NO_CHANGE); + } - if (m_uiStrangulateTimer <= uiDiff) + void UpdateAI(const uint32 diff) { - if (Unit* target = SelectEnemyCaster(false)) - DoCast(target, SPELL_STRANGULATE); - m_uiStrangulateTimer = urand(10*IN_MILLISECONDS, 90*IN_MILLISECONDS); - } else m_uiStrangulateTimer -= uiDiff; + if (!UpdateVictim()) + return; - if (m_uiFrostStrikeTimer <= uiDiff) - { - DoCastVictim(SPELL_FROST_STRIKE); - m_uiFrostStrikeTimer = urand(5*IN_MILLISECONDS, 15*IN_MILLISECONDS); - } else m_uiFrostStrikeTimer -= uiDiff; + events.Update(diff); + boss_faction_championsAI::UpdateAI(diff); - if (m_uiIcyTouchTimer <= uiDiff) - { - DoCastVictim(SPELL_ICY_TOUCH); - m_uiIcyTouchTimer = urand(8*IN_MILLISECONDS, 12*IN_MILLISECONDS); - } else m_uiIcyTouchTimer -= uiDiff; + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; - if (m_uiDeathGripTimer <= uiDiff) - { - if (me->IsInRange(me->getVictim(), 10.0f, 30.0f, false)) - DoCastVictim(SPELL_DEATH_GRIP); - m_uiDeathGripTimer = urand(5*IN_MILLISECONDS, 15*IN_MILLISECONDS); - } else m_uiDeathGripTimer -= uiDiff; + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_CHAINS_OF_ICE: + DoCastVictim(SPELL_CHAINS_OF_ICE); + events.ScheduleEvent(EVENT_CHAINS_OF_ICE, urand(15*IN_MILLISECONDS, 25*IN_MILLISECONDS)); + return; + case EVENT_DEATH_COIL: + DoCastVictim(SPELL_DEATH_COIL); + events.ScheduleEvent(EVENT_DEATH_COIL, urand(5*IN_MILLISECONDS, 15*IN_MILLISECONDS)); + return; + case EVENT_DEATH_GRIP: + if (me->IsInRange(me->getVictim(), 5.0f, 30.0f, false)) + { + DoCast(me->getVictim(), SPELL_DEATH_GRIP); + events.RescheduleEvent(EVENT_DEATH_GRIP, 35*IN_MILLISECONDS); + } + else + events.RescheduleEvent(EVENT_DEATH_GRIP, 3*IN_MILLISECONDS); + return; + case EVENT_FROST_STRIKE: + DoCastVictim(SPELL_FROST_STRIKE); + events.ScheduleEvent(EVENT_FROST_STRIKE, urand(6*IN_MILLISECONDS, 10*IN_MILLISECONDS)); + return; + case EVENT_ICEBOUND_FORTITUDE: + if (HealthBelowPct(50)) + { + DoCast(SPELL_ICEBOUND_FORTITUDE); + events.RescheduleEvent(EVENT_ICEBOUND_FORTITUDE, 60*IN_MILLISECONDS); + } + else + events.RescheduleEvent(EVENT_ICEBOUND_FORTITUDE, 5*IN_MILLISECONDS); + return; + case EVENT_ICY_TOUCH: + DoCastVictim(SPELL_ICY_TOUCH); + events.ScheduleEvent(EVENT_ICY_TOUCH, urand(10*IN_MILLISECONDS, 15*IN_MILLISECONDS)); + return; + case EVENT_STRANGULATE: + if (Unit* target = SelectEnemyCaster(false)) + { + DoCast(target, SPELL_STRANGULATE); + events.RescheduleEvent(EVENT_STRANGULATE, 120*IN_MILLISECONDS); + } + else + events.RescheduleEvent(EVENT_STRANGULATE, 5*IN_MILLISECONDS); + return; + default: + return; + } + } + } + }; - boss_faction_championsAI::UpdateAI(uiDiff); + CreatureAI* GetAI(Creature* creature) const + { + return new mob_toc_dkAI (creature); } - }; - -}; - -enum eRogueSpells -{ - SPELL_FAN_OF_KNIVES = 65955, //2sec - SPELL_BLIND = 65960, //2min - SPELL_CLOAK = 65961, //90sec - SPELL_BLADE_FLURRY = 65956, //2min - SPELL_SHADOWSTEP = 66178, //30sec - SPELL_HEMORRHAGE = 65954, - SPELL_EVISCERATE = 65957, }; class mob_toc_rogue : public CreatureScript { -public: - mob_toc_rogue() : CreatureScript("mob_toc_rogue") { } + public: + mob_toc_rogue() : CreatureScript("mob_toc_rogue") { } - CreatureAI* GetAI(Creature* creature) const - { - return new mob_toc_rogueAI (creature); - } + struct mob_toc_rogueAI : public boss_faction_championsAI + { + mob_toc_rogueAI(Creature* creature) : boss_faction_championsAI(creature, AI_MELEE) {} + + void Reset() + { + boss_faction_championsAI::Reset(); + events.ScheduleEvent(EVENT_FAN_OF_KNIVES, urand(5*IN_MILLISECONDS, 10*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_BLIND, urand(10*IN_MILLISECONDS, 20*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_CLOAK, urand(20*IN_MILLISECONDS, 30*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_BLADE_FLURRY, urand(10*IN_MILLISECONDS, 20*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_SHADOWSTEP, urand(20*IN_MILLISECONDS, 30*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_HEMORRHAGE, urand(3*IN_MILLISECONDS, 10*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_EVISCERATE, urand(20*IN_MILLISECONDS, 40*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_WOUND_POISON, urand(5*IN_MILLISECONDS, 10*IN_MILLISECONDS)); + SetEquipmentSlots(false, 47422, 49982, EQUIP_NO_CHANGE); + me->setPowerType(POWER_ENERGY); + me->SetMaxPower(POWER_ENERGY, 100); + } - struct mob_toc_rogueAI : public boss_faction_championsAI - { - mob_toc_rogueAI(Creature* creature) : boss_faction_championsAI(creature, AI_MELEE) {} + void UpdateAI(const uint32 diff) + { + if (!UpdateVictim()) + return; + + events.Update(diff); + boss_faction_championsAI::UpdateAI(diff); - uint32 m_uiFanOfKnivesTimer; - uint32 m_uiHemorrhageTimer; - uint32 m_uiEviscerateTimer; - uint32 m_uiShadowstepTimer; - uint32 m_uiBlindTimer; - uint32 m_uiCloakTimer; - uint32 m_uiBladeFlurryTimer; + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_FAN_OF_KNIVES: + if (EnemiesInRange(10.0f) >= 2) + DoCastAOE(SPELL_FAN_OF_KNIVES); + events.ScheduleEvent(EVENT_FAN_OF_KNIVES, urand(10*IN_MILLISECONDS, 20*IN_MILLISECONDS)); + return; + case EVENT_BLIND: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, NonTankTargetSelector(me))) + DoCast(target, SPELL_BLIND); + events.ScheduleEvent(EVENT_BLIND, urand(10*IN_MILLISECONDS, 30*IN_MILLISECONDS)); + return; + case EVENT_CLOAK: + if (HealthBelowPct(50)) + { + DoCast(SPELL_CLOAK); + events.RescheduleEvent(EVENT_CLOAK, 90*IN_MILLISECONDS); + } + else + events.RescheduleEvent(EVENT_CLOAK, 5*IN_MILLISECONDS); + return; + case EVENT_BLADE_FLURRY: + if (EnemiesInRange(10.0f) >= 2) + { + DoCast(SPELL_BLADE_FLURRY); + events.RescheduleEvent(EVENT_BLADE_FLURRY, 120*IN_MILLISECONDS); + } + else + events.RescheduleEvent(EVENT_BLADE_FLURRY, 5*IN_MILLISECONDS); + return; + case EVENT_SHADOWSTEP: + if (me->IsInRange(me->getVictim(), 10.0f, 40.0f, false)) + { + DoCast(me->getVictim(), SPELL_SHADOWSTEP); + events.RescheduleEvent(EVENT_SHADOWSTEP, 30*IN_MILLISECONDS); + } + else + events.RescheduleEvent(EVENT_SHADOWSTEP, 5*IN_MILLISECONDS); + return; + case EVENT_HEMORRHAGE: + DoCastVictim(SPELL_HEMORRHAGE); + events.ScheduleEvent(EVENT_HEMORRHAGE, urand(3*IN_MILLISECONDS, 10*IN_MILLISECONDS)); + return; + case EVENT_EVISCERATE: + DoCastVictim(SPELL_EVISCERATE); + events.ScheduleEvent(EVENT_EVISCERATE, urand(30*IN_MILLISECONDS, 40*IN_MILLISECONDS)); + return; + case EVENT_WOUND_POISON: + DoCastVictim(SPELL_WOUND_POISON); + events.ScheduleEvent(EVENT_WOUND_POISON, urand(10*IN_MILLISECONDS, 20*IN_MILLISECONDS)); + return; + default: + return; + } + } + } + }; - void Reset() + CreatureAI* GetAI(Creature* creature) const { - boss_faction_championsAI::Reset(); - m_uiFanOfKnivesTimer = urand(8*IN_MILLISECONDS, 10*IN_MILLISECONDS); - m_uiHemorrhageTimer = urand(5*IN_MILLISECONDS, 8*IN_MILLISECONDS); - m_uiEviscerateTimer = urand(15*IN_MILLISECONDS, 20*IN_MILLISECONDS); - m_uiShadowstepTimer = urand(10*IN_MILLISECONDS, 80*IN_MILLISECONDS); - m_uiBlindTimer = urand(7*IN_MILLISECONDS, 8*IN_MILLISECONDS); - m_uiCloakTimer = urand(20*IN_MILLISECONDS, 120*IN_MILLISECONDS); - m_uiBladeFlurryTimer = urand(12*IN_MILLISECONDS, 120*IN_MILLISECONDS); - SetEquipmentSlots(false, 47422, 49982, EQUIP_NO_CHANGE); + return new mob_toc_rogueAI (creature); } +}; + +class mob_toc_enh_shaman : public CreatureScript +{ + public: + mob_toc_enh_shaman() : CreatureScript("mob_toc_enh_shaman") { } - void UpdateAI(const uint32 uiDiff) + struct mob_toc_enh_shamanAI : public boss_faction_championsAI { - if (!UpdateVictim()) - return; + mob_toc_enh_shamanAI(Creature* creature) : boss_faction_championsAI(creature, AI_MELEE) {} + + void Reset() + { + boss_faction_championsAI::Reset(); + events.ScheduleEvent(EVENT_DPS_EARTH_SHOCK, urand(5*IN_MILLISECONDS, 10*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_LAVA_LASH, urand(3*IN_MILLISECONDS, 5*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_STORMSTRIKE, urand(2*IN_MILLISECONDS, 5*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_DPS_BLOODLUST_HEROISM, 20*IN_MILLISECONDS); + events.ScheduleEvent(EVENT_DEPLOY_TOTEM, 1*IN_MILLISECONDS); + events.ScheduleEvent(EVENT_WINDFURY, urand(20*IN_MILLISECONDS, 50*IN_MILLISECONDS)); + + _totemCount = 0; + _totemOldCenterX = me->GetPositionX(); + _totemOldCenterY = me->GetPositionY(); + SetEquipmentSlots(false, 51803, 48013, EQUIP_NO_CHANGE); + summons.DespawnAll(); + } - if (m_uiFanOfKnivesTimer <= uiDiff) + void JustSummoned(Creature* summoned) { - if (EnemiesInRange(15.0f) > 2) - DoCastAOE(SPELL_FAN_OF_KNIVES); - m_uiFanOfKnivesTimer = urand(8*IN_MILLISECONDS, 10*IN_MILLISECONDS); - } else m_uiFanOfKnivesTimer -= uiDiff; + summons.Summon(summoned); + } - if (m_uiHemorrhageTimer <= uiDiff) + void SummonedCreatureDespawn(Creature* /*pSummoned*/) { - DoCastVictim(SPELL_HEMORRHAGE); - m_uiHemorrhageTimer = urand(5*IN_MILLISECONDS, 8*IN_MILLISECONDS); - } else m_uiHemorrhageTimer -= uiDiff; + --_totemCount; + } - if (m_uiEviscerateTimer <= uiDiff) + void DeployTotem() { - DoCastVictim(SPELL_EVISCERATE); - m_uiEviscerateTimer = urand(15*IN_MILLISECONDS, 20*IN_MILLISECONDS); - } else m_uiEviscerateTimer -= uiDiff; + _totemCount = 4; + _totemOldCenterX = me->GetPositionX(); + _totemOldCenterY = me->GetPositionY(); + /* + -Windfury (16% melee haste) + -Grounding (redirects one harmful magic spell to the totem) - if (m_uiShadowstepTimer <= uiDiff) - { - if (me->IsInRange(me->getVictim(), 10.0f, 40.0f)) - DoCastVictim(SPELL_SHADOWSTEP); - m_uiShadowstepTimer = urand(10*IN_MILLISECONDS, 80*IN_MILLISECONDS); - } else m_uiShadowstepTimer -= uiDiff; + -Healing Stream (unable to find amount of healing in our logs) - if (m_uiBlindTimer <= uiDiff) - { - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1)) - if (me->IsInRange(target, 0.0f, 15.0f, false)) - DoCast(target, SPELL_BLIND); - m_uiBlindTimer = urand(7*IN_MILLISECONDS, 8*IN_MILLISECONDS); - } else m_uiBlindTimer -= uiDiff; + -Tremor (prevents fear effects) + -Strength of Earth (155 strength and agil for the opposing team) - if (m_uiCloakTimer <= uiDiff) - { - if (HealthBelowPct(50)) - DoCast(me, SPELL_CLOAK); - m_uiCloakTimer = urand(20*IN_MILLISECONDS, 120*IN_MILLISECONDS); - } else m_uiCloakTimer -= uiDiff; + -Searing (average ~3500 damage on a random target every ~3.5 seconds) + */ + } - if (m_uiBladeFlurryTimer <= uiDiff) + void JustDied(Unit* killer) { - DoCastVictim(SPELL_BLADE_FLURRY); - m_uiBladeFlurryTimer = urand(12*IN_MILLISECONDS, 120*IN_MILLISECONDS); - } else m_uiBladeFlurryTimer -= uiDiff; - - boss_faction_championsAI::UpdateAI(uiDiff); - } - }; - -}; - -enum eEnhShamanSpells -{ - SPELL_EARTH_SHOCK_ENH = 65973, - SPELL_LAVA_LASH = 65974, - SPELL_STORMSTRIKE = 65970, -}; - -class mob_toc_enh_shaman : public CreatureScript -{ -public: - mob_toc_enh_shaman() : CreatureScript("mob_toc_enh_shaman") { } + boss_faction_championsAI::JustDied(killer); + summons.DespawnAll(); + } - CreatureAI* GetAI(Creature* creature) const - { - return new mob_toc_enh_shamanAI (creature); - } + void UpdateAI(const uint32 diff) + { + if (!UpdateVictim()) + return; - struct mob_toc_enh_shamanAI : public boss_faction_championsAI - { - mob_toc_enh_shamanAI(Creature* creature) : boss_faction_championsAI(creature, AI_MELEE), Summons(me) {} + events.Update(diff); + boss_faction_championsAI::UpdateAI(diff); - SummonList Summons; + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; - uint32 m_uiHeroismOrBloodlustTimer; - uint32 m_uiEarthShockTimer; - uint32 m_uiStormstrikeTimer; - uint32 m_uiLavaLashTimer; - uint32 m_uiDeployTotemTimer; - uint8 m_uiTotemCount; - float m_fTotemOldCenterX, m_fTotemOldCenterY; + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_DPS_EARTH_SHOCK: + if (Unit* target = SelectEnemyCaster(true)) + DoCast(target, SPELL_EARTH_SHOCK); + events.ScheduleEvent(EVENT_DPS_EARTH_SHOCK, urand(10*IN_MILLISECONDS, 15*IN_MILLISECONDS)); + return; + case EVENT_LAVA_LASH: + DoCastVictim(SPELL_LAVA_LASH); + events.ScheduleEvent(EVENT_LAVA_LASH, urand(5*IN_MILLISECONDS, 15*IN_MILLISECONDS)); + return; + case EVENT_STORMSTRIKE: + DoCastVictim(SPELL_STORMSTRIKE); + events.ScheduleEvent(EVENT_STORMSTRIKE, urand(8*IN_MILLISECONDS, 10*IN_MILLISECONDS)); + return; + case EVENT_DPS_BLOODLUST_HEROISM: + if (me->getFaction()) //Am i alliance? + { + if (!me->HasAura(AURA_EXHAUSTION)) + DoCastAOE(SPELL_HEROISM); + } + else + { + if (!me->HasAura(AURA_SATED)) + DoCastAOE(SPELL_BLOODLUST); + } + events.ScheduleEvent(EVENT_DPS_BLOODLUST_HEROISM, 5*MINUTE*IN_MILLISECONDS); + return; + case EVENT_DEPLOY_TOTEM: + if (_totemCount < 4 || me->GetDistance2d(_totemOldCenterX, _totemOldCenterY) > 20.0f) + DeployTotem(); + events.ScheduleEvent(EVENT_DEPLOY_TOTEM, 1*IN_MILLISECONDS); + return; + case EVENT_WINDFURY: + DoCastVictim(SPELL_WINDFURY); + events.ScheduleEvent(EVENT_WINDFURY, urand(20*IN_MILLISECONDS, 60*IN_MILLISECONDS)); + return; + default: + return; + } + } + } + private: + uint8 _totemCount; + float _totemOldCenterX, _totemOldCenterY; + }; - void Reset() + CreatureAI* GetAI(Creature* creature) const { - boss_faction_championsAI::Reset(); - m_uiHeroismOrBloodlustTimer = urand(25*IN_MILLISECONDS, 60*IN_MILLISECONDS); - m_uiEarthShockTimer = urand(5*IN_MILLISECONDS, 8*IN_MILLISECONDS); - m_uiStormstrikeTimer = urand(5*IN_MILLISECONDS, 90*IN_MILLISECONDS); - m_uiLavaLashTimer = urand(5*IN_MILLISECONDS, 8*IN_MILLISECONDS); - m_uiDeployTotemTimer = urand(1*IN_MILLISECONDS, 3*IN_MILLISECONDS); - m_uiTotemCount = 0; - m_fTotemOldCenterX = me->GetPositionX(); - m_fTotemOldCenterY = me->GetPositionY(); - SetEquipmentSlots(false, 51803, 48013, EQUIP_NO_CHANGE); - Summons.DespawnAll(); + return new mob_toc_enh_shamanAI (creature); } +}; - void JustSummoned(Creature* summoned) - { - Summons.Summon(summoned); - } +class mob_toc_retro_paladin : public CreatureScript +{ + public: + mob_toc_retro_paladin() : CreatureScript("mob_toc_retro_paladin") { } - void SummonedCreatureDespawn(Creature* /*pSummoned*/) + struct mob_toc_retro_paladinAI : public boss_faction_championsAI { - --m_uiTotemCount; - } + mob_toc_retro_paladinAI(Creature* creature) : boss_faction_championsAI(creature, AI_MELEE) {} + + void Reset() + { + boss_faction_championsAI::Reset(); + events.ScheduleEvent(EVENT_AVENGING_WRATH, urand(25*IN_MILLISECONDS, 35*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_CRUSADER_STRIKE, urand(5*IN_MILLISECONDS, 10*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_DIVINE_STORM, urand(10*IN_MILLISECONDS, 20*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_HAMMER_OF_JUSTICE_RET, urand(10*IN_MILLISECONDS, 30*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_JUDGEMENT_OF_COMMAND, urand(5*IN_MILLISECONDS, 15*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_REPENTANCE, urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_DPS_HAND_OF_PROTECTION, urand(20*IN_MILLISECONDS, 30*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_DPS_DIVINE_SHIELD, urand(20*IN_MILLISECONDS, 30*IN_MILLISECONDS)); + SetEquipmentSlots(false, 47519, EQUIP_NO_CHANGE, EQUIP_NO_CHANGE); + } - void DeployTotem() - { - m_uiTotemCount = 4; - m_fTotemOldCenterX = me->GetPositionX(); - m_fTotemOldCenterY = me->GetPositionY(); - /* - -Windfury (16% melee haste) - -Grounding (redirects one harmful magic spell to the totem) + void EnterCombat(Unit* who) + { + boss_faction_championsAI::EnterCombat(who); + DoCast(SPELL_SEAL_OF_COMMAND); + } - -Healing Stream (unable to find amount of healing in our logs) + void UpdateAI(const uint32 diff) + { + if (!UpdateVictim()) + return; - -Tremor (prevents fear effects) - -Strength of Earth (155 strength and agil for the opposing team) + events.Update(diff); + boss_faction_championsAI::UpdateAI(diff); - -Searing (average ~3500 damage on a random target every ~3.5 seconds) - */ - } + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_AVENGING_WRATH: + DoCast(SPELL_AVENGING_WRATH); + events.ScheduleEvent(EVENT_AVENGING_WRATH, 180*IN_MILLISECONDS); + return; + case EVENT_CRUSADER_STRIKE: + DoCastVictim(SPELL_CRUSADER_STRIKE); + events.ScheduleEvent(EVENT_CRUSADER_STRIKE, urand(10*IN_MILLISECONDS, 15*IN_MILLISECONDS)); + return; + case EVENT_DIVINE_STORM: + if (EnemiesInRange(10.0f) >= 2) + DoCast(SPELL_DIVINE_STORM); + events.ScheduleEvent(EVENT_DIVINE_STORM, urand(10*IN_MILLISECONDS, 20*IN_MILLISECONDS)); + return; + case EVENT_HAMMER_OF_JUSTICE_RET: + DoCastVictim(SPELL_HAMMER_OF_JUSTICE_RET); + events.ScheduleEvent(EVENT_HAMMER_OF_JUSTICE_RET, 40*IN_MILLISECONDS); + return; + case EVENT_JUDGEMENT_OF_COMMAND: + DoCastVictim(SPELL_JUDGEMENT_OF_COMMAND); + events.ScheduleEvent(EVENT_JUDGEMENT_OF_COMMAND, urand(10*IN_MILLISECONDS, 15*IN_MILLISECONDS)); + return; + case EVENT_REPENTANCE: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, NonTankTargetSelector(me))) + DoCast(target, SPELL_REPENTANCE); + events.ScheduleEvent(EVENT_REPENTANCE, 60*IN_MILLISECONDS); + return; + case EVENT_DPS_HAND_OF_PROTECTION: + if (Unit* target = DoSelectLowestHpFriendly(30.0f)) + { + if (!target->HasAura(SPELL_FORBEARANCE)) + { + DoCast(target, SPELL_HAND_OF_PROTECTION); + events.RescheduleEvent(EVENT_DPS_HAND_OF_PROTECTION, 5*MINUTE*IN_MILLISECONDS); + } + else + events.RescheduleEvent(EVENT_DPS_HAND_OF_PROTECTION, 5*IN_MILLISECONDS); + } + else + events.RescheduleEvent(EVENT_DPS_HAND_OF_PROTECTION, 5*IN_MILLISECONDS); + return; + case EVENT_DPS_DIVINE_SHIELD: + if (HealthBelowPct(30) && !me->HasAura(SPELL_FORBEARANCE)) + { + DoCast(me, SPELL_DIVINE_SHIELD); + events.RescheduleEvent(EVENT_DPS_DIVINE_SHIELD, 5*MINUTE*IN_MILLISECONDS); + } + else + events.RescheduleEvent(EVENT_DPS_DIVINE_SHIELD, 5*IN_MILLISECONDS); + return; + default: + return; + } + } + } + }; - void JustDied(Unit* killer) + CreatureAI* GetAI(Creature* creature) const { - boss_faction_championsAI::JustDied(killer); - Summons.DespawnAll(); + return new mob_toc_retro_paladinAI (creature); } +}; - void UpdateAI(const uint32 uiDiff) +class mob_toc_pet_warlock : public CreatureScript +{ + public: + mob_toc_pet_warlock() : CreatureScript("mob_toc_pet_warlock") { } + + struct mob_toc_pet_warlockAI : public boss_faction_championsAI { - if (!UpdateVictim()) - return; + mob_toc_pet_warlockAI(Creature* creature) : boss_faction_championsAI(creature, AI_PET) {} - if (m_uiHeroismOrBloodlustTimer <= uiDiff) + void Reset() { - if (me->getFaction()) //Am i alliance? - { - if (!me->HasAura(AURA_EXHAUSTION)) - DoCastAOE(SPELL_HEROISM); - } - else - if (!me->HasAura(AURA_SATED)) - DoCastAOE(SPELL_BLOODLUST); - m_uiHeroismOrBloodlustTimer = urand(25*IN_MILLISECONDS, 60*IN_MILLISECONDS); - } else m_uiHeroismOrBloodlustTimer -= uiDiff; + boss_faction_championsAI::Reset(); + events.ScheduleEvent(EVENT_DEVOUR_MAGIC, urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_SPELL_LOCK, urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS)); + } - if (m_uiEarthShockTimer <= uiDiff) + void UpdateAI(const uint32 diff) { - DoCastVictim(SPELL_EARTH_SHOCK_ENH); - m_uiEarthShockTimer = urand(5*IN_MILLISECONDS, 8*IN_MILLISECONDS); - } else m_uiEarthShockTimer -= uiDiff; + if (!UpdateVictim()) + return; - if (m_uiStormstrikeTimer <= uiDiff) - { - DoCastVictim(SPELL_STORMSTRIKE); - m_uiStormstrikeTimer = urand(5*IN_MILLISECONDS, 90*IN_MILLISECONDS); - } else m_uiStormstrikeTimer -= uiDiff; + events.Update(diff); + boss_faction_championsAI::UpdateAI(diff); - if (m_uiLavaLashTimer <= uiDiff) - { - DoCastVictim(SPELL_LAVA_LASH); - m_uiLavaLashTimer = urand(5*IN_MILLISECONDS, 8*IN_MILLISECONDS); - } else m_uiLavaLashTimer -= uiDiff; + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; - if (m_uiDeployTotemTimer <= uiDiff) - { - if (m_uiTotemCount < 4 || me->GetDistance2d(m_fTotemOldCenterX, m_fTotemOldCenterY) > 20.0f) - DeployTotem(); - m_uiDeployTotemTimer = urand(1*IN_MILLISECONDS, 3*IN_MILLISECONDS); - } else m_uiDeployTotemTimer -= uiDiff; + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_DEVOUR_MAGIC: + DoCastVictim(SPELL_DEVOUR_MAGIC); + events.ScheduleEvent(EVENT_DEVOUR_MAGIC, urand(8*IN_MILLISECONDS, 10*IN_MILLISECONDS)); + return; + case EVENT_SPELL_LOCK: + DoCast(SPELL_SPELL_LOCK); + events.ScheduleEvent(EVENT_SPELL_LOCK, urand(24*IN_MILLISECONDS, 30*IN_MILLISECONDS)); + return; + default: + return; + } + } + } + }; - boss_faction_championsAI::UpdateAI(uiDiff); + CreatureAI* GetAI(Creature* creature) const + { + return new mob_toc_pet_warlockAI (creature); } - }; - }; -enum eRetroPaladinSpells +class mob_toc_pet_hunter : public CreatureScript { - SPELL_AVENGING_WRATH = 66011, //3min cd - SPELL_CRUSADER_STRIKE = 66003, //6sec cd - SPELL_DIVINE_SHIELD = 66010, //5min cd - SPELL_DIVINE_STORM = 66006, //10sec cd - SPELL_HAMMER_OF_JUSTICE_RET = 66007, //40sec cd - SPELL_HAND_OF_PROTECTION_RET = 66009, //5min cd - SPELL_JUDGEMENT_OF_COMMAND = 66005, //8sec cd - SPELL_REPENTANCE = 66008, //60sec cd - SPELL_SEAL_OF_COMMAND = 66004, //no cd -}; + public: + mob_toc_pet_hunter() : CreatureScript("mob_toc_pet_hunter") { } -class mob_toc_retro_paladin : public CreatureScript -{ -public: - mob_toc_retro_paladin() : CreatureScript("mob_toc_retro_paladin") { } + struct mob_toc_pet_hunterAI : public boss_faction_championsAI + { + mob_toc_pet_hunterAI(Creature* creature) : boss_faction_championsAI(creature, AI_PET) {} - CreatureAI* GetAI(Creature* creature) const - { - return new mob_toc_retro_paladinAI (creature); - } + void Reset() + { + boss_faction_championsAI::Reset(); + _clawTimer = urand(5*IN_MILLISECONDS, 10*IN_MILLISECONDS); + } - struct mob_toc_retro_paladinAI : public boss_faction_championsAI - { - mob_toc_retro_paladinAI(Creature* creature) : boss_faction_championsAI(creature, AI_MELEE) {} + void UpdateAI(const uint32 diff) + { + if (!UpdateVictim()) + return; - uint32 m_uiRepeteanceTimer; - uint32 m_uiCrusaderStrikeTimer; - uint32 m_uiAvengingWrathTimer; - uint32 m_uiDivineShieldTimer; - uint32 m_uiDivineStormTimer; - uint32 m_uiJudgementOfCommandTimer; + boss_faction_championsAI::UpdateAI(diff); - void Reset() - { - boss_faction_championsAI::Reset(); - m_uiRepeteanceTimer = 60*IN_MILLISECONDS; - m_uiCrusaderStrikeTimer = urand(6*IN_MILLISECONDS, 18*IN_MILLISECONDS); - m_uiAvengingWrathTimer = 180*IN_MILLISECONDS; - m_uiDivineShieldTimer = urand(0*IN_MILLISECONDS, 360*IN_MILLISECONDS); - m_uiDivineStormTimer = 10*IN_MILLISECONDS; - m_uiJudgementOfCommandTimer = urand(8*IN_MILLISECONDS, 15*IN_MILLISECONDS); - SetEquipmentSlots(false, 47519, EQUIP_NO_CHANGE, EQUIP_NO_CHANGE); - } + if (_clawTimer <= diff) + { + DoCastVictim(SPELL_CLAW); + _clawTimer = urand(5*IN_MILLISECONDS, 10*IN_MILLISECONDS); + } + else + _clawTimer -= diff; + } + private: + uint32 _clawTimer; + }; - void EnterCombat(Unit* who) + CreatureAI* GetAI(Creature* creature) const { - boss_faction_championsAI::EnterCombat(who); - DoCast(SPELL_SEAL_OF_COMMAND); + return new mob_toc_pet_hunterAI (creature); } +}; - void UpdateAI(const uint32 uiDiff) - { - if (!UpdateVictim()) - return; - - if (m_uiRepeteanceTimer <= uiDiff) - { - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) - DoCast(target, SPELL_REPENTANCE); - m_uiRepeteanceTimer = 60*IN_MILLISECONDS; - } else m_uiRepeteanceTimer -= uiDiff; - - if (m_uiCrusaderStrikeTimer <= uiDiff) - { - DoCastVictim(SPELL_CRUSADER_STRIKE); - m_uiCrusaderStrikeTimer = urand(6*IN_MILLISECONDS, 18*IN_MILLISECONDS); - } else m_uiCrusaderStrikeTimer -= uiDiff; +class spell_faction_champion_warl_unstable_affliction : public SpellScriptLoader +{ + public: + spell_faction_champion_warl_unstable_affliction() : SpellScriptLoader("spell_faction_champion_warl_unstable_affliction") { } - if (m_uiAvengingWrathTimer <= uiDiff) - { - DoCastVictim(SPELL_AVENGING_WRATH); - m_uiAvengingWrathTimer = 180*IN_MILLISECONDS; - } else m_uiAvengingWrathTimer -= uiDiff; + class spell_faction_champion_warl_unstable_affliction_AuraScript : public AuraScript + { + PrepareAuraScript(spell_faction_champion_warl_unstable_affliction_AuraScript); - if (m_uiDivineShieldTimer <= uiDiff) + bool Validate(SpellInfo const* /*spell*/) { - if (HealthBelowPct(20)) - DoCast(me, SPELL_DIVINE_SHIELD); - m_uiDivineShieldTimer = urand(0*IN_MILLISECONDS, 360*IN_MILLISECONDS); - } else m_uiDivineShieldTimer -= uiDiff; + if (!sSpellMgr->GetSpellInfo(SPELL_UNSTABLE_AFFLICTION_DISPEL)) + return false; + return true; + } - if (m_uiDivineStormTimer <= uiDiff) + void HandleDispel(DispelInfo* dispelInfo) { - DoCastVictim(SPELL_DIVINE_STORM); - m_uiDivineStormTimer = 10*IN_MILLISECONDS; - } else m_uiDivineStormTimer -= uiDiff; + if (Unit* caster = GetCaster()) + caster->CastSpell(dispelInfo->GetDispeller(), SPELL_UNSTABLE_AFFLICTION_DISPEL, true, NULL, GetEffect(EFFECT_0)); + } - if (m_uiJudgementOfCommandTimer <= uiDiff) + void Register() { - DoCastVictim(SPELL_JUDGEMENT_OF_COMMAND); - m_uiJudgementOfCommandTimer = urand(8*IN_MILLISECONDS, 15*IN_MILLISECONDS); - } else m_uiJudgementOfCommandTimer -= uiDiff; + AfterDispel += AuraDispelFn(spell_faction_champion_warl_unstable_affliction_AuraScript::HandleDispel); + } + }; - boss_faction_championsAI::UpdateAI(uiDiff); + AuraScript* GetAuraScript() const + { + return new spell_faction_champion_warl_unstable_affliction_AuraScript(); } - }; - -}; - -enum eWarlockPetSpells -{ - SPELL_DEVOUR_MAGIC = 67518, - SPELL_SPELL_LOCK = 67519, }; -class mob_toc_pet_warlock : public CreatureScript +class spell_faction_champion_death_grip : public SpellScriptLoader { -public: - mob_toc_pet_warlock() : CreatureScript("mob_toc_pet_warlock") { } - - CreatureAI* GetAI(Creature* creature) const - { - return new mob_toc_pet_warlockAI (creature); - } - - struct mob_toc_pet_warlockAI : public boss_faction_championsAI - { - mob_toc_pet_warlockAI(Creature* creature) : boss_faction_championsAI(creature, AI_PET) {} - - uint32 m_uiDevourMagicTimer; - uint32 m_uiSpellLockTimer; - - void Reset() - { - boss_faction_championsAI::Reset(); - m_uiDevourMagicTimer = urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS); - m_uiSpellLockTimer = urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS); - } + public: + spell_faction_champion_death_grip() : SpellScriptLoader("spell_faction_champion_death_grip") { } - void UpdateAI(const uint32 uiDiff) + class spell_faction_champion_death_grip_SpellScript : public SpellScript { - if (!UpdateVictim()) - return; + PrepareSpellScript(spell_faction_champion_death_grip_SpellScript); - if (m_uiDevourMagicTimer <= uiDiff) + bool Validate(SpellInfo const* /*spell*/) { - DoCastVictim(SPELL_DEVOUR_MAGIC); - m_uiDevourMagicTimer = urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS); - } else m_uiDevourMagicTimer -= uiDiff; + if (!sSpellMgr->GetSpellInfo(SPELL_DEATH_GRIP_PULL)) + return false; + return true; + } - if (m_uiSpellLockTimer <= uiDiff) + void HandleDummy(SpellEffIndex /*effIndex*/) { - DoCastVictim(SPELL_SPELL_LOCK); - m_uiSpellLockTimer = urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS); - } else m_uiSpellLockTimer -= uiDiff; + if (Unit* target = GetHitUnit()) + { + if (Unit* caster = GetCaster()) + target->CastSpell(caster, SPELL_DEATH_GRIP_PULL); + } + } - boss_faction_championsAI::UpdateAI(uiDiff); - } - }; + void Register() + { + OnEffectHitTarget += SpellEffectFn(spell_faction_champion_death_grip_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); + } -}; + }; -enum eHunterPetSpells -{ - SPELL_CLAW = 67793, + SpellScript* GetSpellScript() const + { + return new spell_faction_champion_death_grip_SpellScript(); + } }; -class mob_toc_pet_hunter : public CreatureScript +class spell_toc_bloodlust : public SpellScriptLoader { -public: - mob_toc_pet_hunter() : CreatureScript("mob_toc_pet_hunter") { } - - CreatureAI* GetAI(Creature* creature) const - { - return new mob_toc_pet_hunterAI (creature); - } + public: + spell_toc_bloodlust() : SpellScriptLoader("spell_toc_bloodlust") { } - struct mob_toc_pet_hunterAI : public boss_faction_championsAI - { - mob_toc_pet_hunterAI(Creature* creature) : boss_faction_championsAI(creature, AI_PET) {} + class spell_toc_bloodlust_SpellScript : public SpellScript + { + PrepareSpellScript(spell_toc_bloodlust_SpellScript); - uint32 m_uiClawTimer; + bool Validate(SpellInfo const* /*spellEntry*/) + { + if (!sSpellMgr->GetSpellInfo(AURA_SATED)) + return false; + return true; + } - void Reset() - { - boss_faction_championsAI::Reset(); - m_uiClawTimer = urand(5*IN_MILLISECONDS, 10*IN_MILLISECONDS); - } + void RemoveInvalidTargets(std::list<WorldObject*>& targets) + { + targets.remove_if(Trinity::UnitAuraCheck(true, AURA_SATED)); + } - void UpdateAI(const uint32 uiDiff) - { - if (!UpdateVictim()) - return; + void ApplyDebuff() + { + if (Unit* target = GetHitUnit()) + target->CastSpell(target, AURA_SATED, true); + } - if (m_uiClawTimer <= uiDiff) + void Register() { - DoCastVictim(SPELL_CLAW); - m_uiClawTimer = urand(5*IN_MILLISECONDS, 10*IN_MILLISECONDS); - } else m_uiClawTimer -= uiDiff; + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_toc_bloodlust_SpellScript::RemoveInvalidTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ALLY); + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_toc_bloodlust_SpellScript::RemoveInvalidTargets, EFFECT_1, TARGET_UNIT_SRC_AREA_ALLY); + AfterHit += SpellHitFn(spell_toc_bloodlust_SpellScript::ApplyDebuff); + } + }; - boss_faction_championsAI::UpdateAI(uiDiff); + SpellScript* GetSpellScript() const + { + return new spell_toc_bloodlust_SpellScript(); } - }; }; -class spell_faction_champion_warl_unstable_affliction : public SpellScriptLoader +class spell_toc_heroism : public SpellScriptLoader { public: - spell_faction_champion_warl_unstable_affliction() : SpellScriptLoader("spell_faction_champion_warl_unstable_affliction") { } + spell_toc_heroism() : SpellScriptLoader("spell_toc_heroism") { } - class spell_faction_champion_warl_unstable_affliction_AuraScript : public AuraScript + class spell_toc_heroism_SpellScript : public SpellScript { - PrepareAuraScript(spell_faction_champion_warl_unstable_affliction_AuraScript); + PrepareSpellScript(spell_toc_heroism_SpellScript); - bool Validate(SpellInfo const* /*spell*/) + bool Validate(SpellInfo const* /*spellEntry*/) { - if (!sSpellMgr->GetSpellInfo(SPELL_UNSTABLE_AFFLICTION_DISPEL)) + if (!sSpellMgr->GetSpellInfo(AURA_EXHAUSTION)) return false; return true; } - void HandleDispel(DispelInfo* dispelInfo) + void RemoveInvalidTargets(std::list<WorldObject*>& targets) { - if (Unit* caster = GetCaster()) - caster->CastSpell(dispelInfo->GetDispeller(), SPELL_UNSTABLE_AFFLICTION_DISPEL, true, NULL, GetEffect(EFFECT_0)); + targets.remove_if(Trinity::UnitAuraCheck(true, AURA_EXHAUSTION)); + } + + void ApplyDebuff() + { + if (Unit* target = GetHitUnit()) + target->CastSpell(target, AURA_EXHAUSTION, true); } void Register() { - AfterDispel += AuraDispelFn(spell_faction_champion_warl_unstable_affliction_AuraScript::HandleDispel); + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_toc_heroism_SpellScript::RemoveInvalidTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ALLY); + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_toc_heroism_SpellScript::RemoveInvalidTargets, EFFECT_1, TARGET_UNIT_SRC_AREA_ALLY); + AfterHit += SpellHitFn(spell_toc_heroism_SpellScript::ApplyDebuff); } }; - AuraScript* GetAuraScript() const + SpellScript* GetSpellScript() const { - return new spell_faction_champion_warl_unstable_affliction_AuraScript(); + return new spell_toc_heroism_SpellScript(); } }; @@ -2087,5 +2391,9 @@ void AddSC_boss_faction_champions() new mob_toc_retro_paladin(); new mob_toc_pet_warlock(); new mob_toc_pet_hunter(); + new spell_faction_champion_warl_unstable_affliction(); + new spell_faction_champion_death_grip(); + new spell_toc_bloodlust(); + new spell_toc_heroism(); } diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_lord_jaraxxus.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_lord_jaraxxus.cpp index 87e7801566e..3f2fee303eb 100755 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_lord_jaraxxus.cpp +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_lord_jaraxxus.cpp @@ -16,20 +16,6 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -/* ScriptData -SDName: trial_of_the_crusader -SD%Complete: ??% -SDComment: based on /dev/rsa -SDCategory: Crusader Coliseum -EndScriptData */ - -// Known bugs: -// Some visuals aren't appearing right sometimes -// -// TODO: -// Redone summon's scripts in SAI -// Add immunities to the boss and summons - #include "ScriptMgr.h" #include "ScriptedCreature.h" #include "trial_of_the_crusader.h" @@ -47,15 +33,7 @@ enum Yells SAY_INFERNAL_ERUPTION = 8, SAY_KILL_PLAYER = 9, SAY_DEATH = 10, - SAY_BERSERK = 11, -}; - -enum Equipment -{ - EQUIP_MAIN = 47266, - EQUIP_OFFHAND = 46996, - EQUIP_RANGED = 47267, - EQUIP_DONE = EQUIP_NO_CHANGE, + SAY_BERSERK = 11 }; enum Summons @@ -64,7 +42,7 @@ enum Summons NPC_INFERNAL_VOLCANO = 34813, NPC_FEL_INFERNAL = 34815, // immune to all CC on Heroic (stuns, banish, interrupt, etc) NPC_NETHER_PORTAL = 34825, - NPC_MISTRESS_OF_PAIN = 34826, + NPC_MISTRESS_OF_PAIN = 34826 }; enum BossSpells @@ -84,442 +62,530 @@ enum BossSpells SPELL_BERSERK = 64238, // unused // Mistress of Pain spells - SPELL_SHIVAN_SLASH = 67098, - SPELL_SPINNING_STRIKE = 66283, - SPELL_MISTRESS_KISS = 67077, - SPELL_FEL_INFERNO = 67047, - SPELL_FEL_STREAK = 66494, + SPELL_SHIVAN_SLASH = 67098, + SPELL_SPINNING_STRIKE = 66283, + SPELL_MISTRESS_KISS = 66336, + SPELL_FEL_INFERNO = 67047, + SPELL_FEL_STREAK = 66494, + SPELL_LORD_HITTIN = 66326, // special effect preventing more specific spells be cast on the same player within 10 seconds + SPELL_MISTRESS_KISS_DEBUFF = 66334, + SPELL_MISTRESS_KISS_DAMAGE_SILENCE = 66359 }; -/*###### -## boss_jaraxxus -######*/ +enum Events +{ + // Lord Jaraxxus + EVENT_FEL_FIREBALL = 1, + EVENT_FEL_LIGHTNING = 2, + EVENT_INCINERATE_FLESH = 3, + EVENT_NETHER_POWER = 4, + EVENT_LEGION_FLAME = 5, + EVENT_SUMMONO_NETHER_PORTAL = 6, + EVENT_SUMMON_INFERNAL_ERUPTION = 7, + + // Mistress of Pain + EVENT_SHIVAN_SLASH = 8, + EVENT_SPINNING_STRIKE = 9, + EVENT_MISTRESS_KISS = 10 +}; class boss_jaraxxus : public CreatureScript { -public: - boss_jaraxxus() : CreatureScript("boss_jaraxxus") { } - - CreatureAI* GetAI(Creature* creature) const - { - return new boss_jaraxxusAI(creature); - } - - struct boss_jaraxxusAI : public ScriptedAI - { - boss_jaraxxusAI(Creature* creature) : ScriptedAI(creature), Summons(me) - { - instance = creature->GetInstanceScript(); - Reset(); - } - - InstanceScript* instance; + public: + boss_jaraxxus() : CreatureScript("boss_jaraxxus") { } - SummonList Summons; - - uint32 m_uiFelFireballTimer; - uint32 m_uiFelLightningTimer; - uint32 m_uiIncinerateFleshTimer; - uint32 m_uiNetherPowerTimer; - uint32 m_uiLegionFlameTimer; - uint32 m_uiSummonNetherPortalTimer; - uint32 m_uiSummonInfernalEruptionTimer; - - void Reset() + struct boss_jaraxxusAI : public BossAI { - if (instance) - instance->SetData(TYPE_JARAXXUS, NOT_STARTED); - SetEquipmentSlots(false, EQUIP_MAIN, EQUIP_OFFHAND, EQUIP_RANGED); - m_uiFelFireballTimer = 5*IN_MILLISECONDS; - m_uiFelLightningTimer = urand(10*IN_MILLISECONDS, 15*IN_MILLISECONDS); - m_uiIncinerateFleshTimer = urand(20*IN_MILLISECONDS, 25*IN_MILLISECONDS); - m_uiNetherPowerTimer = 40*IN_MILLISECONDS; - m_uiLegionFlameTimer = 30*IN_MILLISECONDS; - m_uiSummonNetherPortalTimer = 1*MINUTE*IN_MILLISECONDS; - m_uiSummonInfernalEruptionTimer = 2*MINUTE*IN_MILLISECONDS; - Summons.DespawnAll(); - } + boss_jaraxxusAI(Creature* creature) : BossAI(creature, BOSS_JARAXXUS) + { + } - void JustReachedHome() - { - if (instance) - instance->SetData(TYPE_JARAXXUS, FAIL); - DoCast(me, SPELL_JARAXXUS_CHAINS); - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - me->SetReactState(REACT_PASSIVE); - } + void Reset() + { + _Reset(); + events.ScheduleEvent(EVENT_FEL_FIREBALL, 5*IN_MILLISECONDS); + events.ScheduleEvent(EVENT_FEL_LIGHTNING, urand(10*IN_MILLISECONDS, 15*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_INCINERATE_FLESH, urand(20*IN_MILLISECONDS, 25*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_NETHER_POWER, 40*IN_MILLISECONDS); + events.ScheduleEvent(EVENT_LEGION_FLAME, 30*IN_MILLISECONDS); + events.ScheduleEvent(EVENT_SUMMONO_NETHER_PORTAL, 20*IN_MILLISECONDS); + events.ScheduleEvent(EVENT_SUMMON_INFERNAL_ERUPTION, 80*IN_MILLISECONDS); + } - void KilledUnit(Unit* who) - { - if (who->GetTypeId() == TYPEID_PLAYER) + void JustReachedHome() { + _JustReachedHome(); if (instance) - instance->SetData(DATA_TRIBUTE_TO_IMMORTALITY_ELEGIBLE, 0); + instance->SetBossState(BOSS_JARAXXUS, FAIL); + DoCast(me, SPELL_JARAXXUS_CHAINS); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); } - } - void JustDied(Unit* /*killer*/) - { - Summons.DespawnAll(); - Talk(SAY_DEATH); - if (instance) - instance->SetData(TYPE_JARAXXUS, DONE); - } - - void JustSummoned(Creature* summoned) - { - Summons.Summon(summoned); - } - - void EnterCombat(Unit* /*who*/) - { - me->SetInCombatWithZone(); - if (instance) - instance->SetData(TYPE_JARAXXUS, IN_PROGRESS); - Talk(SAY_AGGRO); - } - - void UpdateAI(const uint32 uiDiff) - { - if (!UpdateVictim()) - return; - - if (m_uiSummonInfernalEruptionTimer <= uiDiff) + void KilledUnit(Unit* who) { - Talk(EMOTE_INFERNAL_ERUPTION); - Talk(SAY_INFERNAL_ERUPTION); - DoCast(SPELL_INFERNAL_ERUPTION); - m_uiSummonInfernalEruptionTimer = 2*MINUTE*IN_MILLISECONDS; - } else m_uiSummonInfernalEruptionTimer -= uiDiff; + if (who->GetTypeId() == TYPEID_PLAYER) + { + Talk(SAY_KILL_PLAYER); + if (instance) + instance->SetData(DATA_TRIBUTE_TO_IMMORTALITY_ELEGIBLE, 0); + } + } - if (m_uiSummonNetherPortalTimer <= uiDiff) + void JustDied(Unit* /*killer*/) { - Talk(EMOTE_NETHER_PORTAL); - Talk(SAY_MISTRESS_OF_PAIN); - DoCast(SPELL_NETHER_PORTAL); - m_uiSummonNetherPortalTimer = 2*MINUTE*IN_MILLISECONDS; - } else m_uiSummonNetherPortalTimer -= uiDiff; + _JustDied(); + Talk(SAY_DEATH); + } - if (m_uiFelFireballTimer <= uiDiff) + void JustSummoned(Creature* summoned) { - DoCastVictim(SPELL_FEL_FIREBALL); - m_uiFelFireballTimer = urand(10*IN_MILLISECONDS, 15*IN_MILLISECONDS); - } else m_uiFelFireballTimer -= uiDiff; + summons.Summon(summoned); + } - if (m_uiFelLightningTimer <= uiDiff) + void EnterCombat(Unit* /*who*/) { - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM)) - DoCast(target, SPELL_FEL_LIGHTING); - m_uiFelLightningTimer = urand(10*IN_MILLISECONDS, 15*IN_MILLISECONDS); - } else m_uiFelLightningTimer -= uiDiff; + _EnterCombat(); + Talk(SAY_AGGRO); + } - if (m_uiIncinerateFleshTimer <= uiDiff) + void UpdateAI(const uint32 diff) { - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 0, true)) - { - Talk(EMOTE_INCINERATE, target->GetGUID()); - Talk(SAY_INCINERATE); - DoCast(target, SPELL_INCINERATE_FLESH); - } - m_uiIncinerateFleshTimer = urand(20*IN_MILLISECONDS, 25*IN_MILLISECONDS); - } else m_uiIncinerateFleshTimer -= uiDiff; + if (!UpdateVictim()) + return; - if (m_uiNetherPowerTimer <= uiDiff) - { - me->CastCustomSpell(SPELL_NETHER_POWER, SPELLVALUE_AURA_STACK, RAID_MODE<uint32>(5, 10, 5,10), me, true); - m_uiNetherPowerTimer = 40*IN_MILLISECONDS; - } else m_uiNetherPowerTimer -= uiDiff; + events.Update(diff); - if (m_uiLegionFlameTimer <= uiDiff) - { - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 0, true)) + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) { - Talk(EMOTE_LEGION_FLAME, target->GetGUID()); - DoCast(target, SPELL_LEGION_FLAME); + switch (eventId) + { + case EVENT_FEL_FIREBALL: + DoCastVictim(SPELL_FEL_FIREBALL); + events.ScheduleEvent(EVENT_FEL_FIREBALL, urand(10*IN_MILLISECONDS, 15*IN_MILLISECONDS)); + return; + case EVENT_FEL_LIGHTNING: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true, -SPELL_LORD_HITTIN)) + DoCast(target, SPELL_FEL_LIGHTING); + events.ScheduleEvent(EVENT_FEL_LIGHTNING, urand(10*IN_MILLISECONDS, 15*IN_MILLISECONDS)); + return; + case EVENT_INCINERATE_FLESH: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 0.0f, true, -SPELL_LORD_HITTIN)) + { + Talk(EMOTE_INCINERATE, target->GetGUID()); + Talk(SAY_INCINERATE); + DoCast(target, SPELL_INCINERATE_FLESH); + } + events.ScheduleEvent(EVENT_INCINERATE_FLESH, urand(20*IN_MILLISECONDS, 25*IN_MILLISECONDS)); + return; + case EVENT_NETHER_POWER: + me->CastCustomSpell(SPELL_NETHER_POWER, SPELLVALUE_AURA_STACK, RAID_MODE<uint32>(5, 10, 5,10), me, true); + events.ScheduleEvent(EVENT_NETHER_POWER, 40*IN_MILLISECONDS); + return; + case EVENT_LEGION_FLAME: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 0.0f, true, -SPELL_LORD_HITTIN)) + { + Talk(EMOTE_LEGION_FLAME, target->GetGUID()); + DoCast(target, SPELL_LEGION_FLAME); + } + events.ScheduleEvent(EVENT_LEGION_FLAME, 30*IN_MILLISECONDS); + return; + case EVENT_SUMMONO_NETHER_PORTAL: + Talk(EMOTE_NETHER_PORTAL); + Talk(SAY_MISTRESS_OF_PAIN); + DoCast(SPELL_NETHER_PORTAL); + events.ScheduleEvent(EVENT_SUMMONO_NETHER_PORTAL, 2*MINUTE*IN_MILLISECONDS); + return; + case EVENT_SUMMON_INFERNAL_ERUPTION: + Talk(EMOTE_INFERNAL_ERUPTION); + Talk(SAY_INFERNAL_ERUPTION); + DoCast(SPELL_INFERNAL_ERUPTION); + events.ScheduleEvent(EVENT_SUMMON_INFERNAL_ERUPTION, 2*MINUTE*IN_MILLISECONDS); + return; + } } - m_uiLegionFlameTimer = 30*IN_MILLISECONDS; - } else m_uiLegionFlameTimer -= uiDiff; - DoMeleeAttackIfReady(); - } - }; + DoMeleeAttackIfReady(); + } + }; + CreatureAI* GetAI(Creature* creature) const + { + return new boss_jaraxxusAI(creature); + } }; class mob_legion_flame : public CreatureScript { -public: - mob_legion_flame() : CreatureScript("mob_legion_flame") { } - - CreatureAI* GetAI(Creature* creature) const - { - return new mob_legion_flameAI(creature); - } + public: + mob_legion_flame() : CreatureScript("mob_legion_flame") { } - struct mob_legion_flameAI : public Scripted_NoMovementAI - { - mob_legion_flameAI(Creature* creature) : Scripted_NoMovementAI(creature) + struct mob_legion_flameAI : public Scripted_NoMovementAI { - Reset(); - } + mob_legion_flameAI(Creature* creature) : Scripted_NoMovementAI(creature) + { + _instance = creature->GetInstanceScript(); + } - void Reset() - { - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); - me->SetInCombatWithZone(); - DoCast(SPELL_LEGION_FLAME_EFFECT); - } + void Reset() + { + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); + me->SetInCombatWithZone(); + DoCast(SPELL_LEGION_FLAME_EFFECT); + } + + void UpdateAI(const uint32 /*diff*/) + { + UpdateVictim(); + if (_instance && _instance->GetBossState(BOSS_JARAXXUS) != IN_PROGRESS) + me->DespawnOrUnsummon(); + } + private: + InstanceScript* _instance; + }; - void UpdateAI(const uint32 /*uiDiff*/) + CreatureAI* GetAI(Creature* creature) const { - UpdateVictim(); + return new mob_legion_flameAI(creature); } - }; - }; class mob_infernal_volcano : public CreatureScript { -public: - mob_infernal_volcano() : CreatureScript("mob_infernal_volcano") { } - - CreatureAI* GetAI(Creature* creature) const - { - return new mob_infernal_volcanoAI(creature); - } + public: + mob_infernal_volcano() : CreatureScript("mob_infernal_volcano") { } - struct mob_infernal_volcanoAI : public Scripted_NoMovementAI - { - mob_infernal_volcanoAI(Creature* creature) : Scripted_NoMovementAI(creature), Summons(me) + struct mob_infernal_volcanoAI : public Scripted_NoMovementAI { - instance = creature->GetInstanceScript(); - Reset(); - } + mob_infernal_volcanoAI(Creature* creature) : Scripted_NoMovementAI(creature), _summons(me) + { + } - InstanceScript* instance; + void Reset() + { + me->SetReactState(REACT_PASSIVE); - SummonList Summons; + if (!IsHeroic()) + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_PACIFIED); + else + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_PACIFIED); - void Reset() - { - me->SetReactState(REACT_PASSIVE); + _summons.DespawnAll(); + } - if (!IsHeroic()) - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_PACIFIED); - else - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_PACIFIED); + void IsSummonedBy(Unit* /*summoner*/) + { + DoCast(SPELL_INFERNAL_ERUPTION_EFFECT); + } - Summons.DespawnAll(); - } + void JustSummoned(Creature* summoned) + { + _summons.Summon(summoned); + // makes immediate corpse despawn of summoned Felflame Infernals + summoned->SetCorpseDelay(0); + } - void IsSummonedBy(Unit* /*summoner*/) - { - DoCast(SPELL_INFERNAL_ERUPTION_EFFECT); - } + void JustDied(Unit* /*killer*/) + { + // used to despawn corpse immediately + me->DespawnOrUnsummon(); + } - void JustSummoned(Creature* summoned) - { - Summons.Summon(summoned); - // makes immediate corpse despawn of summoned Felflame Infernals - summoned->SetCorpseDelay(0); - } + void UpdateAI(uint32 const /*diff*/) {} + + private: + SummonList _summons; + }; - void JustDied(Unit* /*killer*/) + CreatureAI* GetAI(Creature* creature) const { - // used to despawn corpse immediately - me->DespawnOrUnsummon(); + return new mob_infernal_volcanoAI(creature); } - - void UpdateAI(uint32 const /*diff*/) {} - }; - }; class mob_fel_infernal : public CreatureScript { -public: - mob_fel_infernal() : CreatureScript("mob_fel_infernal") { } + public: + mob_fel_infernal() : CreatureScript("mob_fel_infernal") { } - CreatureAI* GetAI(Creature* creature) const - { - return new mob_fel_infernalAI(creature); - } - - struct mob_fel_infernalAI : public ScriptedAI - { - mob_fel_infernalAI(Creature* creature) : ScriptedAI(creature) + struct mob_fel_infernalAI : public ScriptedAI { - instance = creature->GetInstanceScript(); - Reset(); - } - - InstanceScript* instance; - uint32 m_uiFelStreakTimer; + mob_fel_infernalAI(Creature* creature) : ScriptedAI(creature) + { + _instance = creature->GetInstanceScript(); + } - void Reset() - { - m_uiFelStreakTimer = 30*IN_MILLISECONDS; - me->SetInCombatWithZone(); - } + void Reset() + { + _felStreakTimer = 30*IN_MILLISECONDS; + me->SetInCombatWithZone(); + } - /*void SpellHitTarget(Unit* target, const SpellInfo* pSpell) - { - if (pSpell->Id == SPELL_FEL_STREAK) - DoCastAOE(SPELL_FEL_INFERNO); //66517 - }*/ + void UpdateAI(const uint32 diff) + { + if (_instance && _instance->GetBossState(BOSS_JARAXXUS) != IN_PROGRESS) + { + me->DespawnOrUnsummon(); + return; + } - void UpdateAI(const uint32 uiDiff) - { - if (!UpdateVictim()) - return; + if (!UpdateVictim()) + return; - if (instance && instance->GetData(TYPE_JARAXXUS) != IN_PROGRESS) - me->DespawnOrUnsummon(); + if (_felStreakTimer <= diff) + { + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true)) + DoCast(target, SPELL_FEL_STREAK); + _felStreakTimer = 30*IN_MILLISECONDS; + } + else + _felStreakTimer -= diff; - if (m_uiFelStreakTimer <= uiDiff) - { - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) - DoCast(target, SPELL_FEL_STREAK); - m_uiFelStreakTimer = 30*IN_MILLISECONDS; - } else m_uiFelStreakTimer -= uiDiff; + DoMeleeAttackIfReady(); + } + private: + uint32 _felStreakTimer; + InstanceScript* _instance; + }; - DoMeleeAttackIfReady(); + CreatureAI* GetAI(Creature* creature) const + { + return new mob_fel_infernalAI(creature); } - }; - }; class mob_nether_portal : public CreatureScript { -public: - mob_nether_portal() : CreatureScript("mob_nether_portal") { } - - CreatureAI* GetAI(Creature* creature) const - { - return new mob_nether_portalAI(creature); - } + public: + mob_nether_portal() : CreatureScript("mob_nether_portal") { } - struct mob_nether_portalAI : public ScriptedAI - { - mob_nether_portalAI(Creature* creature) : ScriptedAI(creature), Summons(me) + struct mob_nether_portalAI : public ScriptedAI { - instance = creature->GetInstanceScript(); - Reset(); - } + mob_nether_portalAI(Creature* creature) : ScriptedAI(creature), _summons(me) + { + } - InstanceScript* instance; + void Reset() + { + me->SetReactState(REACT_PASSIVE); - SummonList Summons; + if (!IsHeroic()) + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_PACIFIED); + else + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_PACIFIED); - void Reset() - { - me->SetReactState(REACT_PASSIVE); + _summons.DespawnAll(); + } - if (!IsHeroic()) - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_PACIFIED); - else - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_PACIFIED); + void IsSummonedBy(Unit* /*summoner*/) + { + DoCast(SPELL_NETHER_PORTAL_EFFECT); + } - Summons.DespawnAll(); - } + void JustSummoned(Creature* summoned) + { + _summons.Summon(summoned); + // makes immediate corpse despawn of summoned Mistress of Pain + summoned->SetCorpseDelay(0); + } - void IsSummonedBy(Unit* /*summoner*/) - { - DoCast(SPELL_NETHER_PORTAL_EFFECT); - } + void JustDied(Unit* /*killer*/) + { + // used to despawn corpse immediately + me->DespawnOrUnsummon(); + } - void JustSummoned(Creature* summoned) - { - Summons.Summon(summoned); - // makes immediate corpse despawn of summoned Mistress of Pain - summoned->SetCorpseDelay(0); - } + void UpdateAI(uint32 const /*diff*/) {} + + private: + SummonList _summons; + }; - void JustDied(Unit* /*killer*/) + CreatureAI* GetAI(Creature* creature) const { - // used to despawn corpse immediately - me->DespawnOrUnsummon(); + return new mob_nether_portalAI(creature); } - - void UpdateAI(uint32 const /*diff*/) {} - }; - }; class mob_mistress_of_pain : public CreatureScript { -public: - mob_mistress_of_pain() : CreatureScript("mob_mistress_of_pain") { } + public: + mob_mistress_of_pain() : CreatureScript("mob_mistress_of_pain") { } - CreatureAI* GetAI(Creature* creature) const - { - return new mob_mistress_of_painAI(creature); - } + struct mob_mistress_of_painAI : public ScriptedAI + { + mob_mistress_of_painAI(Creature* creature) : ScriptedAI(creature) + { + _instance = creature->GetInstanceScript(); + if (_instance) + _instance->SetData(DATA_MISTRESS_OF_PAIN_COUNT, INCREASE); + } + + void Reset() + { + _events.ScheduleEvent(EVENT_SHIVAN_SLASH, 30*IN_MILLISECONDS); + _events.ScheduleEvent(EVENT_SPINNING_STRIKE, 30*IN_MILLISECONDS); + if (IsHeroic()) + _events.ScheduleEvent(EVENT_MISTRESS_KISS, 15*IN_MILLISECONDS); + me->SetInCombatWithZone(); + } - struct mob_mistress_of_painAI : public ScriptedAI - { - mob_mistress_of_painAI(Creature* creature) : ScriptedAI(creature) + void JustDied(Unit* /*killer*/) + { + if (_instance) + _instance->SetData(DATA_MISTRESS_OF_PAIN_COUNT, DECREASE); + } + + void UpdateAI(const uint32 diff) + { + if (_instance && _instance->GetBossState(BOSS_JARAXXUS) != IN_PROGRESS) + { + me->DespawnOrUnsummon(); + return; + } + + if (!UpdateVictim()) + return; + + _events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_SHIVAN_SLASH: + DoCastVictim(SPELL_SHIVAN_SLASH); + _events.ScheduleEvent(EVENT_SHIVAN_SLASH, 30*IN_MILLISECONDS); + return; + case EVENT_SPINNING_STRIKE: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true)) + DoCast(target, SPELL_SPINNING_STRIKE); + _events.ScheduleEvent(EVENT_SPINNING_STRIKE, 30*IN_MILLISECONDS); + return; + case EVENT_MISTRESS_KISS: + DoCast(me, SPELL_MISTRESS_KISS); + _events.ScheduleEvent(EVENT_MISTRESS_KISS, 30*IN_MILLISECONDS); + return; + default: + break; + } + } + + DoMeleeAttackIfReady(); + } + private: + InstanceScript* _instance; + EventMap _events; + }; + + CreatureAI* GetAI(Creature* creature) const { - instance = creature->GetInstanceScript(); - if (instance) - instance->SetData(DATA_MISTRESS_OF_PAIN_COUNT, INCREASE); - Reset(); + return new mob_mistress_of_painAI(creature); } +}; - InstanceScript* instance; - uint32 m_uiShivanSlashTimer; - uint32 m_uiSpinningStrikeTimer; - uint32 m_uiMistressKissTimer; +class spell_mistress_kiss : public SpellScriptLoader +{ + public: + spell_mistress_kiss() : SpellScriptLoader("spell_mistress_kiss") { } - void Reset() + class spell_mistress_kiss_AuraScript : public AuraScript { - m_uiShivanSlashTimer = 30*IN_MILLISECONDS; - m_uiSpinningStrikeTimer = 30*IN_MILLISECONDS; - m_uiMistressKissTimer = 15*IN_MILLISECONDS; - me->SetInCombatWithZone(); - } + PrepareAuraScript(spell_mistress_kiss_AuraScript); - void JustDied(Unit* /*killer*/) + bool Load() + { + if (GetCaster()) + if (sSpellMgr->GetSpellIdForDifficulty(SPELL_MISTRESS_KISS_DAMAGE_SILENCE, GetCaster())) + return true; + return false; + } + + void HandleDummyTick(AuraEffect const* /*aurEff*/) + { + Unit* caster = GetCaster(); + Unit* target = GetTarget(); + if (caster && target) + { + if (target->HasUnitState(UNIT_STATE_CASTING)) + { + caster->CastSpell(target, SPELL_MISTRESS_KISS_DAMAGE_SILENCE, true); + target->RemoveAurasDueToSpell(GetSpellInfo()->Id); + } + } + } + + void Register() + { + OnEffectPeriodic += AuraEffectPeriodicFn(spell_mistress_kiss_AuraScript::HandleDummyTick, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY); + } + }; + + AuraScript* GetAuraScript() const { - if (instance) - instance->SetData(DATA_MISTRESS_OF_PAIN_COUNT, DECREASE); + return new spell_mistress_kiss_AuraScript(); } +}; - void UpdateAI(const uint32 uiDiff) +class spell_mistress_kiss_area : public SpellScriptLoader +{ + public: + spell_mistress_kiss_area() : SpellScriptLoader("spell_mistress_kiss_area") {} + + class spell_mistress_kiss_area_SpellScript : public SpellScript { - if (instance && instance->GetData(TYPE_JARAXXUS) != IN_PROGRESS) + PrepareSpellScript(spell_mistress_kiss_area_SpellScript) + + bool Load() { - me->DespawnOrUnsummon(); - return; + if (GetCaster()) + if (sSpellMgr->GetSpellIdForDifficulty(SPELL_MISTRESS_KISS_DEBUFF, GetCaster())) + return true; + return false; } - if (!UpdateVictim()) - return; - - if (m_uiShivanSlashTimer <= uiDiff) + void HandleScript(SpellEffIndex /*effIndex*/) { - DoCastVictim(SPELL_SHIVAN_SLASH); - m_uiShivanSlashTimer = 30*IN_MILLISECONDS; - } else m_uiShivanSlashTimer -= uiDiff; + Unit* caster = GetCaster(); + Unit* target = GetHitUnit(); + if (caster && target) + caster->CastSpell(target, SPELL_MISTRESS_KISS_DEBUFF, true); + } - if (m_uiSpinningStrikeTimer <= uiDiff) + void FilterTargets(std::list<WorldObject*>& targets) { - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0, true)) - DoCast(target, SPELL_SPINNING_STRIKE); - m_uiSpinningStrikeTimer = 30*IN_MILLISECONDS; - } else m_uiSpinningStrikeTimer -= uiDiff; + // get a list of players with mana + std::list<WorldObject*> _targets; + for (std::list<WorldObject*>::iterator itr = targets.begin(); itr != targets.end(); ++itr) + if ((*itr)->ToUnit()->getPowerType() == POWER_MANA) + _targets.push_back(*itr); + + // pick a random target and kiss him + if (WorldObject* _target = Trinity::Containers::SelectRandomContainerElement(_targets)) + { + // correctly fill "targets" for the visual effect + targets.clear(); + targets.push_back(_target); + if (Unit* caster = GetCaster()) + caster->CastSpell(_target->ToUnit(), SPELL_MISTRESS_KISS_DEBUFF, true); + } + } - if (IsHeroic() && m_uiMistressKissTimer <= uiDiff) + void Register() { - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0, true)) - DoCast(target, SPELL_MISTRESS_KISS); - m_uiMistressKissTimer = 30*IN_MILLISECONDS; - } else m_uiMistressKissTimer -= uiDiff; + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_mistress_kiss_area_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + } + }; - DoMeleeAttackIfReady(); + SpellScript* GetSpellScript() const + { + return new spell_mistress_kiss_area_SpellScript(); } - }; - }; void AddSC_boss_jaraxxus() @@ -530,4 +596,7 @@ void AddSC_boss_jaraxxus() new mob_fel_infernal(); new mob_nether_portal(); new mob_mistress_of_pain(); + + new spell_mistress_kiss(); + new spell_mistress_kiss_area(); } diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_northrend_beasts.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_northrend_beasts.cpp index e55cd550a95..2cb0854b3c4 100755 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_northrend_beasts.cpp +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_northrend_beasts.cpp @@ -15,24 +15,14 @@ * You should have received a copy of the GNU General Public License along * with this program. If not, see <http://www.gnu.org/licenses/>. */ -/* ScriptData -SDName: northrend_beasts -SD%Complete: 90% -SDComment: based on /dev/rsa -SDCategory: -EndScriptData */ // Known bugs: -// Gormok - Not implemented as a vehicle -// - Snobold Firebomb -// - Snobolled (creature at back) -// Snakes - miss the 1-hitkill from emerging -// - visual changes between mobile and stationary models seems not to work sometimes +// Gormok - Snobolled (creature at back) #include "ScriptMgr.h" #include "ScriptedCreature.h" #include "trial_of_the_crusader.h" -#include "Player.h" +#include "Vehicle.h" enum Yells { @@ -45,7 +35,7 @@ enum Yells // Icehowl EMOTE_TRAMPLE_START = 0, EMOTE_TRAMPLE_CRASH = 1, - EMOTE_TRAMPLE_FAIL = 2, + EMOTE_TRAMPLE_FAIL = 2 }; enum Equipment @@ -53,7 +43,7 @@ enum Equipment EQUIP_MAIN = 50760, EQUIP_OFFHAND = 48040, EQUIP_RANGED = 47267, - EQUIP_DONE = EQUIP_NO_CHANGE, + EQUIP_DONE = EQUIP_NO_CHANGE }; enum Model @@ -61,13 +51,15 @@ enum Model MODEL_ACIDMAW_STATIONARY = 29815, MODEL_ACIDMAW_MOBILE = 29816, MODEL_DREADSCALE_STATIONARY = 26935, - MODEL_DREADSCALE_MOBILE = 24564, + MODEL_DREADSCALE_MOBILE = 24564 }; -enum Summons +enum BeastSummons { NPC_SNOBOLD_VASSAL = 34800, + NPC_FIRE_BOMB = 34854, NPC_SLIME_POOL = 35176, + MAX_SNOBOLDS = 4 }; enum BossSpells @@ -108,332 +100,446 @@ enum BossSpells SPELL_ARCTIC_BREATH = 66689, SPELL_TRAMPLE = 66734, SPELL_FROTHING_RAGE = 66759, - SPELL_STAGGERED_DAZE = 66758, + SPELL_STAGGERED_DAZE = 66758 }; -class boss_gormok : public CreatureScript +enum MyActions { -public: - boss_gormok() : CreatureScript("boss_gormok") { } - - CreatureAI* GetAI(Creature* creature) const - { - return new boss_gormokAI(creature); - } + ACTION_ENABLE_FIRE_BOMB = 1, + ACTION_DISABLE_FIRE_BOMB = 2 +}; - struct boss_gormokAI : public ScriptedAI - { - boss_gormokAI(Creature* creature) : ScriptedAI(creature), Summons(me) - { - instance = creature->GetInstanceScript(); - } +enum Events +{ + // Gormok + EVENT_IMPALE = 1, + EVENT_STAGGERING_STOMP = 2, + EVENT_THROW = 3, - InstanceScript* instance; + // Snobold + EVENT_FIRE_BOMB = 4, + EVENT_BATTER = 5, + EVENT_HEAD_CRACK = 6, - uint32 m_uiImpaleTimer; - uint32 m_uiStaggeringStompTimer; - SummonList Summons; - uint32 m_uiSummonTimer; - uint32 m_uiSummonCount; + // Acidmaw & Dreadscale + EVENT_BITE = 7, + EVENT_SPEW = 8, + EVENT_SLIME_POOL = 9, + EVENT_SPIT = 10, + EVENT_SPRAY = 11, + EVENT_SWEEP = 12, + EVENT_SUBMERGE = 13, + EVENT_EMERGE = 14, + EVENT_SUMMON_ACIDMAW = 15, - void Reset() - { - m_uiImpaleTimer = urand(8*IN_MILLISECONDS, 10*IN_MILLISECONDS); - m_uiStaggeringStompTimer = 15*IN_MILLISECONDS; - m_uiSummonTimer = urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS);; + // Icehowl + EVENT_FEROCIOUS_BUTT = 16, + EVENT_MASSIVE_CRASH = 17, + EVENT_WHIRL = 18, + EVENT_ARCTIC_BREATH = 19, + EVENT_TRAMPLE = 20 +}; - if (GetDifficulty() == RAID_DIFFICULTY_25MAN_NORMAL || - GetDifficulty() == RAID_DIFFICULTY_25MAN_HEROIC) - m_uiSummonCount = 5; - else - m_uiSummonCount = 4; +enum Phases +{ + PHASE_MOBILE = 1, + PHASE_STATIONARY = 2, + PHASE_SUBMERGED = 3, - Summons.DespawnAll(); - } + PHASE_MASK_MOBILE = 1 << PHASE_MOBILE, + PHASE_MASK_STATIONARY = 1 << PHASE_STATIONARY +}; - void EnterEvadeMode() - { - instance->DoUseDoorOrButton(instance->GetData64(GO_MAIN_GATE_DOOR)); - ScriptedAI::EnterEvadeMode(); - } +class boss_gormok : public CreatureScript +{ + public: + boss_gormok() : CreatureScript("boss_gormok") { } - void MovementInform(uint32 type, uint32 pointId) + struct boss_gormokAI : public BossAI { - if (type != POINT_MOTION_TYPE) - return; - - switch (pointId) + boss_gormokAI(Creature* creature) : BossAI(creature, BOSS_BEASTS) { - case 0: - instance->DoUseDoorOrButton(instance->GetData64(GO_MAIN_GATE_DOOR)); - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); - me->SetReactState(REACT_AGGRESSIVE); - me->SetInCombatWithZone(); - break; } - } - void JustDied(Unit* /*killer*/) - { - if (instance) - instance->SetData(TYPE_NORTHREND_BEASTS, GORMOK_DONE); - } + void Reset() + { + events.ScheduleEvent(EVENT_IMPALE, urand(8*IN_MILLISECONDS, 10*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_STAGGERING_STOMP, 15*IN_MILLISECONDS); + events.ScheduleEvent(EVENT_THROW, urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS)); - void JustReachedHome() - { - if (instance) + summons.DespawnAll(); + } + + void EnterEvadeMode() { instance->DoUseDoorOrButton(instance->GetData64(GO_MAIN_GATE_DOOR)); - instance->SetData(TYPE_NORTHREND_BEASTS, FAIL); + ScriptedAI::EnterEvadeMode(); } - me->DespawnOrUnsummon(); - } - void EnterCombat(Unit* /*who*/) - { - me->SetInCombatWithZone(); - instance->SetData(TYPE_NORTHREND_BEASTS, GORMOK_IN_PROGRESS); - } - - void JustSummoned(Creature* summon) - { - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 0.0f, true)) + void MovementInform(uint32 type, uint32 pointId) { - if (summon->GetEntry() == NPC_SNOBOLD_VASSAL) + if (type != POINT_MOTION_TYPE) + return; + + switch (pointId) { - summon->GetMotionMaster()->MoveJump(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 10.0f, 20.0f); - DoCast(me, SPELL_RISING_ANGER); - --m_uiSummonCount; + case 0: + instance->DoUseDoorOrButton(instance->GetData64(GO_MAIN_GATE_DOOR)); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); + me->SetReactState(REACT_AGGRESSIVE); + me->SetInCombatWithZone(); + break; + default: + break; } - summon->AI()->AttackStart(target); } - Summons.Summon(summon); - } - void SummonedCreatureDespawn(Creature* summon) - { - if (summon->GetEntry() == NPC_SNOBOLD_VASSAL) - if (summon->isAlive()) - ++m_uiSummonCount; - Summons.Despawn(summon); - } + void JustDied(Unit* /*killer*/) + { + if (instance) + instance->SetData(TYPE_NORTHREND_BEASTS, GORMOK_DONE); + } - void UpdateAI(uint32 const diff) - { - if (!UpdateVictim()) - return; + void JustReachedHome() + { + if (instance) + { + instance->DoUseDoorOrButton(instance->GetData64(GO_MAIN_GATE_DOOR)); + instance->SetData(TYPE_NORTHREND_BEASTS, FAIL); + } + me->DespawnOrUnsummon(); + } - if (m_uiImpaleTimer <= diff) + void EnterCombat(Unit* /*who*/) { - DoCastVictim(SPELL_IMPALE); - m_uiImpaleTimer = urand(8*IN_MILLISECONDS, 10*IN_MILLISECONDS); - } else m_uiImpaleTimer -= diff; + _EnterCombat(); + me->SetInCombatWithZone(); + instance->SetData(TYPE_NORTHREND_BEASTS, GORMOK_IN_PROGRESS); - if (m_uiStaggeringStompTimer <= diff) + for (uint8 i = 0; i < MAX_SNOBOLDS; i++) + { + if (Creature* pSnobold = DoSpawnCreature(NPC_SNOBOLD_VASSAL, 0, 0, 0, 0, TEMPSUMMON_CORPSE_DESPAWN, 0)) + { + pSnobold->EnterVehicle(me, i); + pSnobold->SetInCombatWithZone(); + pSnobold->AI()->DoAction(ACTION_ENABLE_FIRE_BOMB); + } + } + } + + void DamageTaken(Unit* /*who*/, uint32& damage) { - DoCastVictim(SPELL_STAGGERING_STOMP); - m_uiStaggeringStompTimer = urand(20*IN_MILLISECONDS, 25*IN_MILLISECONDS); - } else m_uiStaggeringStompTimer -= diff; + // despawn the remaining passengers on death + if (damage >= me->GetHealth()) + for (uint8 i = 0; i < MAX_SNOBOLDS; ++i) + if (Unit* pSnobold = me->GetVehicleKit()->GetPassenger(i)) + pSnobold->ToCreature()->DespawnOrUnsummon(); + } - if (m_uiSummonTimer <= diff) + void UpdateAI(uint32 const diff) { - if (m_uiSummonCount > 0) + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) { - me->SummonCreature(NPC_SNOBOLD_VASSAL, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), 0, TEMPSUMMON_CORPSE_DESPAWN); - Talk(EMOTE_SNOBOLLED); + switch (eventId) + { + case EVENT_IMPALE: + DoCastVictim(SPELL_IMPALE); + events.ScheduleEvent(EVENT_IMPALE, urand(8*IN_MILLISECONDS, 10*IN_MILLISECONDS)); + return; + case EVENT_STAGGERING_STOMP: + DoCastVictim(SPELL_STAGGERING_STOMP); + events.ScheduleEvent(EVENT_STAGGERING_STOMP, 15*IN_MILLISECONDS); + return; + case EVENT_THROW: + for (uint8 i = 0; i < MAX_SNOBOLDS; ++i) + { + if (Unit* pSnobold = me->GetVehicleKit()->GetPassenger(i)) + { + pSnobold->ExitVehicle(); + pSnobold->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); + pSnobold->ToCreature()->SetReactState(REACT_AGGRESSIVE); + pSnobold->ToCreature()->AI()->DoAction(ACTION_DISABLE_FIRE_BOMB); + pSnobold->CastSpell(me, SPELL_RISING_ANGER, true); + Talk(EMOTE_SNOBOLLED); + break; + } + } + events.ScheduleEvent(EVENT_THROW, urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS)); + return; + default: + return; + } } - m_uiSummonTimer = urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS); - } else m_uiSummonTimer -= diff; - DoMeleeAttackIfReady(); - } - }; + DoMeleeAttackIfReady(); + } + }; + CreatureAI* GetAI(Creature* creature) const + { + return new boss_gormokAI(creature); + } }; class mob_snobold_vassal : public CreatureScript { -public: - mob_snobold_vassal() : CreatureScript("mob_snobold_vassal") { } - - CreatureAI* GetAI(Creature* creature) const - { - return new mob_snobold_vassalAI(creature); - } + public: + mob_snobold_vassal() : CreatureScript("mob_snobold_vassal") { } - struct mob_snobold_vassalAI : public ScriptedAI - { - mob_snobold_vassalAI(Creature* creature) : ScriptedAI(creature) + struct mob_snobold_vassalAI : public ScriptedAI { - instance = creature->GetInstanceScript(); - if (instance) - instance->SetData(DATA_SNOBOLD_COUNT, INCREASE); - } + mob_snobold_vassalAI(Creature* creature) : ScriptedAI(creature) + { + _instance = creature->GetInstanceScript(); + if (_instance) + _instance->SetData(DATA_SNOBOLD_COUNT, INCREASE); + } - InstanceScript* instance; - uint32 m_uiFireBombTimer; - uint32 m_uiBatterTimer; - uint32 m_uiHeadCrackTimer; - uint64 m_uiBossGUID; - uint64 m_uiTargetGUID; - bool m_bTargetDied; + void Reset() + { + _events.ScheduleEvent(EVENT_BATTER, 5*IN_MILLISECONDS); + _events.ScheduleEvent(EVENT_HEAD_CRACK, 25*IN_MILLISECONDS); - void Reset() - { - m_uiFireBombTimer = 15000; - m_uiBatterTimer = 5000; - m_uiHeadCrackTimer = 25000; + _targetGUID = 0; + _targetDied = false; - m_uiTargetGUID = 0; - m_bTargetDied = false; - if (instance) - m_uiBossGUID = instance->GetData64(NPC_GORMOK); - //Workaround for Snobold - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); - } - - void EnterEvadeMode() - { - instance->DoUseDoorOrButton(instance->GetData64(GO_MAIN_GATE_DOOR)); - ScriptedAI::EnterEvadeMode(); - } + if (_instance) + _bossGUID = _instance->GetData64(NPC_GORMOK); + //Workaround for Snobold + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); + } - void EnterCombat(Unit* who) - { - m_uiTargetGUID = who->GetGUID(); - me->TauntApply(who); - DoCast(who, SPELL_SNOBOLLED); - } + void EnterEvadeMode() + { + ScriptedAI::EnterEvadeMode(); + } - void DamageTaken(Unit* pDoneBy, uint32 &uiDamage) - { - if (pDoneBy->GetGUID()==m_uiTargetGUID) - uiDamage = 0; - } + void EnterCombat(Unit* who) + { + _targetGUID = who->GetGUID(); + me->TauntApply(who); + DoCast(who, SPELL_SNOBOLLED); + } - void MovementInform(uint32 type, uint32 pointId) - { - if (type != POINT_MOTION_TYPE) - return; + void DamageTaken(Unit* pDoneBy, uint32 &uiDamage) + { + if (pDoneBy->GetGUID() == _targetGUID) + uiDamage = 0; + } - switch (pointId) + void MovementInform(uint32 type, uint32 pointId) { - case 0: - if (m_bTargetDied) - me->DespawnOrUnsummon(); - break; + if (type != POINT_MOTION_TYPE) + return; + + switch (pointId) + { + case 0: + if (_targetDied) + me->DespawnOrUnsummon(); + break; + default: + break; + } } - } - void JustDied(Unit* /*killer*/) - { - if (Unit* target = Unit::GetPlayer(*me, m_uiTargetGUID)) - if (target->isAlive()) - target->RemoveAurasDueToSpell(SPELL_SNOBOLLED); - if (instance) - instance->SetData(DATA_SNOBOLD_COUNT, DECREASE); - } + void JustDied(Unit* /*killer*/) + { + if (Unit* target = Unit::GetPlayer(*me, _targetGUID)) + if (target->isAlive()) + target->RemoveAurasDueToSpell(SPELL_SNOBOLLED); + if (_instance) + _instance->SetData(DATA_SNOBOLD_COUNT, DECREASE); + } - void UpdateAI(uint32 const diff) - { - if (m_bTargetDied || !UpdateVictim()) - return; + void DoAction(int32 const action) + { + switch (action) + { + case ACTION_ENABLE_FIRE_BOMB: + _events.ScheduleEvent(EVENT_FIRE_BOMB, urand(5*IN_MILLISECONDS, 30*IN_MILLISECONDS)); + break; + case ACTION_DISABLE_FIRE_BOMB: + _events.CancelEvent(EVENT_FIRE_BOMB); + break; + default: + break; + } + } - if (Unit* target = Unit::GetPlayer(*me, m_uiTargetGUID)) + void UpdateAI(uint32 const diff) { - if (!target->isAlive()) + if (!UpdateVictim() || _targetDied) + return; + + if (Unit* target = Unit::GetPlayer(*me, _targetGUID)) { - if (instance) + if (!target->isAlive()) { - Unit* gormok = ObjectAccessor::GetCreature(*me, instance->GetData64(NPC_GORMOK)); - if (gormok && gormok->isAlive()) + if (_instance) { - SetCombatMovement(false); - m_bTargetDied = true; - me->GetMotionMaster()->MoveJump(gormok->GetPositionX(), gormok->GetPositionY(), gormok->GetPositionZ(), 15.0f, 15.0f); - } - else if (Unit* target2 = SelectTarget(SELECT_TARGET_RANDOM, 0)) - { - m_uiTargetGUID = target2->GetGUID(); - me->GetMotionMaster()->MoveJump(target2->GetPositionX(), target2->GetPositionY(), target2->GetPositionZ(), 15.0f, 15.0f); + Unit* gormok = ObjectAccessor::GetCreature(*me, _instance->GetData64(NPC_GORMOK)); + if (gormok && gormok->isAlive()) + { + SetCombatMovement(false); + _targetDied = true; + + // looping through Gormoks seats + for (uint8 i = 0; i < MAX_SNOBOLDS; i++) + { + if (!gormok->GetVehicleKit()->GetPassenger(i)) + { + me->EnterVehicle(gormok, i); + DoAction(ACTION_ENABLE_FIRE_BOMB); + break; + } + } + } + else if (Unit* target2 = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true)) + { + _targetGUID = target2->GetGUID(); + me->GetMotionMaster()->MoveJump(target2->GetPositionX(), target2->GetPositionY(), target2->GetPositionZ(), 15.0f, 15.0f); + } } } } + + _events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_FIRE_BOMB: + if (me->GetVehicleBase()) + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, -me->GetVehicleBase()->GetCombatReach(), true)) + me->CastSpell(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), SPELL_FIRE_BOMB, true); + _events.ScheduleEvent(EVENT_FIRE_BOMB, 20*IN_MILLISECONDS); + return; + case EVENT_HEAD_CRACK: + // commented out while SPELL_SNOBOLLED gets fixed + //if (Unit* target = Unit::GetPlayer(*me, m_uiTargetGUID)) + DoCastVictim(SPELL_HEAD_CRACK); + _events.ScheduleEvent(EVENT_HEAD_CRACK, 30*IN_MILLISECONDS); + return; + case EVENT_BATTER: + // commented out while SPELL_SNOBOLLED gets fixed + //if (Unit* target = Unit::GetPlayer(*me, m_uiTargetGUID)) + DoCastVictim(SPELL_BATTER); + _events.ScheduleEvent(EVENT_BATTER, 10*IN_MILLISECONDS); + return; + default: + return; + } + } + + // do melee attack only when not on Gormoks back + if (!me->GetVehicleBase()) + DoMeleeAttackIfReady(); } + private: + EventMap _events; + InstanceScript* _instance; + uint64 _bossGUID; + uint64 _targetGUID; + bool _targetDied; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new mob_snobold_vassalAI(creature); + } +}; + +class npc_firebomb : public CreatureScript +{ + public: + npc_firebomb() : CreatureScript("npc_firebomb") { } - if (m_uiFireBombTimer < diff) + struct npc_firebombAI : public ScriptedAI + { + npc_firebombAI(Creature* creature) : ScriptedAI(creature) { - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) - DoCast(target, SPELL_FIRE_BOMB); - m_uiFireBombTimer = 20000; + _instance = creature->GetInstanceScript(); } - else m_uiFireBombTimer -= diff; - if (m_uiBatterTimer < diff) + void Reset() { - if (Unit* target = Unit::GetPlayer(*me, m_uiTargetGUID)) - DoCast(target, SPELL_BATTER); - m_uiBatterTimer = 10000; + DoCast(me, SPELL_FIRE_BOMB_DOT, true); + SetCombatMovement(false); + me->SetReactState(REACT_PASSIVE); + me->SetDisplayId(me->GetCreatureTemplate()->Modelid2); } - else m_uiBatterTimer -= diff; - if (m_uiHeadCrackTimer < diff) + void UpdateAI(uint32 const /*diff*/) { - if (Unit* target = Unit::GetPlayer(*me, m_uiTargetGUID)) - DoCast(target, SPELL_HEAD_CRACK); - m_uiHeadCrackTimer = 35000; + if (_instance->GetData(TYPE_NORTHREND_BEASTS) != GORMOK_IN_PROGRESS) + me->DespawnOrUnsummon(); } - else m_uiHeadCrackTimer -= diff; - DoMeleeAttackIfReady(); - } - }; + private: + InstanceScript* _instance; + }; + CreatureAI* GetAI(Creature* creature) const + { + return new npc_firebombAI(creature); + } }; -struct boss_jormungarAI : public ScriptedAI +struct boss_jormungarAI : public BossAI { - boss_jormungarAI(Creature* creature) : ScriptedAI(creature) + boss_jormungarAI(Creature* creature) : BossAI(creature, BOSS_BEASTS) { - instanceScript = creature->GetInstanceScript(); } void Reset() { - enraged = false; - biteTimer = urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS); - spewTimer = urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS); - slimePoolTimer = 15*IN_MILLISECONDS; - spitTimer = urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS); - sprayTimer = urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS); - sweepTimer = urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS); + Enraged = false; + + events.ScheduleEvent(EVENT_SPIT, urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS), 0, PHASE_STATIONARY); + events.ScheduleEvent(EVENT_SPRAY, urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS), 0, PHASE_STATIONARY); + events.ScheduleEvent(EVENT_SWEEP, urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS), 0, PHASE_STATIONARY); + events.ScheduleEvent(EVENT_BITE, urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS), 0, PHASE_MOBILE); + events.ScheduleEvent(EVENT_SPEW, urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS), 0, PHASE_MOBILE); + events.ScheduleEvent(EVENT_SLIME_POOL, 15*IN_MILLISECONDS, 0, PHASE_MOBILE); } void JustDied(Unit* /*killer*/) { - if (instanceScript) + if (instance) { - if (Creature* otherWorm = Unit::GetCreature(*me, instanceScript->GetData64(otherWormEntry))) + if (Creature* otherWorm = Unit::GetCreature(*me, instance->GetData64(OtherWormEntry))) { if (!otherWorm->isAlive()) { - instanceScript->SetData(TYPE_NORTHREND_BEASTS, SNAKES_DONE); + instance->SetData(TYPE_NORTHREND_BEASTS, SNAKES_DONE); me->DespawnOrUnsummon(); otherWorm->DespawnOrUnsummon(); } else - instanceScript->SetData(TYPE_NORTHREND_BEASTS, SNAKES_SPECIAL); + instance->SetData(TYPE_NORTHREND_BEASTS, SNAKES_SPECIAL); } } } void JustReachedHome() { - if (instanceScript && instanceScript->GetData(TYPE_NORTHREND_BEASTS) != FAIL) - { - instanceScript->SetData(TYPE_NORTHREND_BEASTS, FAIL); - } + // prevent losing 2 attempts at once on heroics + if (instance && instance->GetData(TYPE_NORTHREND_BEASTS) != FAIL) + instance->SetData(TYPE_NORTHREND_BEASTS, FAIL); me->DespawnOrUnsummon(); } @@ -441,17 +547,16 @@ struct boss_jormungarAI : public ScriptedAI void KilledUnit(Unit* who) { if (who->GetTypeId() == TYPEID_PLAYER) - { - if (instanceScript) - instanceScript->SetData(DATA_TRIBUTE_TO_IMMORTALITY_ELEGIBLE, 0); - } + if (instance) + instance->SetData(DATA_TRIBUTE_TO_IMMORTALITY_ELEGIBLE, 0); } void EnterCombat(Unit* /*who*/) { + _EnterCombat(); me->SetInCombatWithZone(); - if (instanceScript) - instanceScript->SetData(TYPE_NORTHREND_BEASTS, SNAKES_IN_PROGRESS); + if (instance) + instance->SetData(TYPE_NORTHREND_BEASTS, SNAKES_IN_PROGRESS); } void UpdateAI(uint32 const diff) @@ -459,563 +564,597 @@ struct boss_jormungarAI : public ScriptedAI if (!UpdateVictim()) return; - if (instanceScript && instanceScript->GetData(TYPE_NORTHREND_BEASTS) == SNAKES_SPECIAL && !enraged) + if (!Enraged && instance && instance->GetData(TYPE_NORTHREND_BEASTS) == SNAKES_SPECIAL) { me->RemoveAurasDueToSpell(SPELL_SUBMERGE_0); me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); DoCast(SPELL_ENRAGE); - enraged = true; + Enraged = true; Talk(EMOTE_ENRAGE); - switch (stage) - { - case 0: - break; - case 4: - stage = 5; - submergeTimer = 5*IN_MILLISECONDS; - break; - default: - stage = 7; - } } - switch (stage) - { - case 0: // Mobile - if (biteTimer <= diff) - { - DoCastVictim(biteSpell); - biteTimer = urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS); - } else biteTimer -= diff; + events.Update(diff); - if (spewTimer <= diff) - { - DoCastAOE(spewSpell); - spewTimer = urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS); - } else spewTimer -= diff; + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; - if (slimePoolTimer <= diff) - { - /* Spell summon has only 30s duration */ + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_EMERGE: + Emerge(); + return; + case EVENT_SUBMERGE: + Submerge(); + return; + case EVENT_BITE: + DoCastVictim(BiteSpell); + events.ScheduleEvent(EVENT_BITE, urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS), 0, PHASE_MOBILE); + return; + case EVENT_SPEW: + DoCastAOE(SpewSpell); + events.ScheduleEvent(EVENT_SPEW, urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS), 0, PHASE_MOBILE); + return; + case EVENT_SLIME_POOL: DoCast(me, SUMMON_SLIME_POOL); - slimePoolTimer = 30*IN_MILLISECONDS; - } else slimePoolTimer -= diff; - - if (submergeTimer <= diff && !enraged) - { - stage = 1; - submergeTimer = 5*IN_MILLISECONDS; - } else submergeTimer -= diff; - - DoMeleeAttackIfReady(); - break; - case 1: // Submerge - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); - DoCast(me, SPELL_SUBMERGE_0); - me->GetMotionMaster()->MovePoint(0, ToCCommonLoc[1].GetPositionX()+ frand(-40.0f, 40.0f), ToCCommonLoc[1].GetPositionY() + frand(-40.0f, 40.0f), ToCCommonLoc[1].GetPositionZ()); - stage = 2; - case 2: // Wait til emerge - if (submergeTimer <= diff) - { - stage = 3; - submergeTimer = 50*IN_MILLISECONDS; - } else submergeTimer -= diff; - break; - case 3: // Emerge - me->SetDisplayId(modelStationary); - me->RemoveAurasDueToSpell(SPELL_SUBMERGE_0); - DoCast(me, SPELL_EMERGE_0); - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE); - SetCombatMovement(false); - me->GetMotionMaster()->MoveIdle(); - stage = 4; - break; - case 4: // Stationary - if (sprayTimer <= diff) - { - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) - DoCast(target, spraySpell); - sprayTimer = urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS); - } else sprayTimer -= diff; - - if (sweepTimer <= diff) - { + events.ScheduleEvent(EVENT_SLIME_POOL, 30*IN_MILLISECONDS, 0, PHASE_MOBILE); + return; + case EVENT_SUMMON_ACIDMAW: + if (Creature* acidmaw = me->SummonCreature(NPC_ACIDMAW, ToCCommonLoc[9].GetPositionX(), ToCCommonLoc[9].GetPositionY(), ToCCommonLoc[9].GetPositionZ(), 5, TEMPSUMMON_MANUAL_DESPAWN)) + { + acidmaw->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); + acidmaw->SetReactState(REACT_AGGRESSIVE); + acidmaw->SetInCombatWithZone(); + acidmaw->CastSpell(acidmaw, SPELL_EMERGE_0); + } + return; + case EVENT_SPRAY: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true)) + DoCast(target, SpraySpell); + events.ScheduleEvent(EVENT_SPRAY, urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS), 0, PHASE_STATIONARY); + return; + case EVENT_SWEEP: DoCastAOE(SPELL_SWEEP_0); - sweepTimer = urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS); - } else sweepTimer -= diff; - - if (submergeTimer <= diff) - { - stage = 5; - submergeTimer = 10*IN_MILLISECONDS; - } else submergeTimer -= diff; - - DoSpellAttackIfReady(spitSpell); - break; - case 5: // Submerge - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); - DoCast(me, SPELL_SUBMERGE_0); - me->GetMotionMaster()->MovePoint(0, ToCCommonLoc[1].GetPositionX() + frand(-40.0f, 40.0f), ToCCommonLoc[1].GetPositionY() + frand(-40.0f, 40.0f), ToCCommonLoc[1].GetPositionZ()); - stage = 6; - case 6: // Wait til emerge - if (submergeTimer <= diff) - { - stage = 7; - submergeTimer = 45*IN_MILLISECONDS; - } else submergeTimer -= diff; - break; - case 7: // Emerge - me->SetDisplayId(modelMobile); - me->RemoveAurasDueToSpell(SPELL_SUBMERGE_0); - DoCast(me, SPELL_EMERGE_0); - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE); - SetCombatMovement(true); - me->GetMotionMaster()->MoveChase(me->getVictim()); - stage = 0; - break; + events.ScheduleEvent(EVENT_SWEEP, urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS), 0, PHASE_STATIONARY); + return; + default: + return; + } } + if (events.GetPhaseMask() & PHASE_MASK_MOBILE) + DoMeleeAttackIfReady(); + if (events.GetPhaseMask() & PHASE_MASK_STATIONARY) + DoSpellAttackIfReady(SpitSpell); } - InstanceScript* instanceScript; + void Submerge() + { + DoCast(me, SPELL_SUBMERGE_0); + me->RemoveAurasDueToSpell(SPELL_EMERGE_0); + me->SetInCombatWithZone(); + events.SetPhase(PHASE_SUBMERGED); + events.ScheduleEvent(EVENT_EMERGE, 5*IN_MILLISECONDS, 0, PHASE_SUBMERGED); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); + me->GetMotionMaster()->MovePoint(0, ToCCommonLoc[1].GetPositionX()+ frand(-40.0f, 40.0f), ToCCommonLoc[1].GetPositionY() + frand(-40.0f, 40.0f), ToCCommonLoc[1].GetPositionZ()); + WasMobile = !WasMobile; + } - uint32 otherWormEntry; + void Emerge() + { + DoCast(me, SPELL_EMERGE_0); + me->SetDisplayId(ModelMobile); + me->RemoveAurasDueToSpell(SPELL_SUBMERGE_0); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); + me->GetMotionMaster()->Clear(); + + // if the worm was mobile before submerging, make him stationary now + if (WasMobile) + { + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE); + SetCombatMovement(false); + me->SetDisplayId(ModelStationary); + events.SetPhase(PHASE_STATIONARY); + events.ScheduleEvent(EVENT_SUBMERGE, 45*IN_MILLISECONDS, 0, PHASE_STATIONARY); + events.ScheduleEvent(EVENT_SPIT, urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS), 0, PHASE_STATIONARY); + events.ScheduleEvent(EVENT_SPRAY, urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS), 0, PHASE_STATIONARY); + events.ScheduleEvent(EVENT_SWEEP, urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS), 0, PHASE_STATIONARY); + } + else + { + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE); + SetCombatMovement(true); + me->GetMotionMaster()->MoveChase(me->getVictim()); + me->SetDisplayId(ModelMobile); + events.SetPhase(PHASE_MOBILE); + events.ScheduleEvent(EVENT_SUBMERGE, 45*IN_MILLISECONDS, 0, PHASE_MOBILE); + events.ScheduleEvent(EVENT_BITE, urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS), 0, PHASE_MOBILE); + events.ScheduleEvent(EVENT_SPEW, urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS), 0, PHASE_MOBILE); + events.ScheduleEvent(EVENT_SLIME_POOL, 15*IN_MILLISECONDS, 0, PHASE_MOBILE); + } + } - uint32 modelStationary; - uint32 modelMobile; + protected: + uint32 OtherWormEntry; + uint32 ModelStationary; + uint32 ModelMobile; - uint32 biteSpell; - uint32 spewSpell; - uint32 spitSpell; - uint32 spraySpell; + uint32 BiteSpell; + uint32 SpewSpell; + uint32 SpitSpell; + uint32 SpraySpell; - uint32 biteTimer; - uint32 spewTimer; - uint32 slimePoolTimer; - uint32 spitTimer; - uint32 sprayTimer; - uint32 sweepTimer; - uint32 submergeTimer; - uint8 stage; - bool enraged; + Phases Phase; + bool Enraged; + bool WasMobile; }; class boss_acidmaw : public CreatureScript { public: - boss_acidmaw() : CreatureScript("boss_acidmaw") { } + boss_acidmaw() : CreatureScript("boss_acidmaw") { } - struct boss_acidmawAI : public boss_jormungarAI - { - boss_acidmawAI(Creature* creature) : boss_jormungarAI(creature) { } + struct boss_acidmawAI : public boss_jormungarAI + { + boss_acidmawAI(Creature* creature) : boss_jormungarAI(creature) { } - void Reset() + void Reset() + { + boss_jormungarAI::Reset(); + BiteSpell = SPELL_PARALYTIC_BITE; + SpewSpell = SPELL_ACID_SPEW; + SpitSpell = SPELL_ACID_SPIT; + SpraySpell = SPELL_PARALYTIC_SPRAY; + ModelStationary = MODEL_ACIDMAW_STATIONARY; + ModelMobile = MODEL_ACIDMAW_MOBILE; + OtherWormEntry = NPC_DREADSCALE; + + WasMobile = true; + Emerge(); + } + }; + + CreatureAI* GetAI(Creature* creature) const { - boss_jormungarAI::Reset(); - biteSpell = SPELL_PARALYTIC_BITE; - spewSpell = SPELL_ACID_SPEW; - spitSpell = SPELL_ACID_SPIT; - spraySpell = SPELL_PARALYTIC_SPRAY; - modelStationary = MODEL_ACIDMAW_STATIONARY; - modelMobile = MODEL_ACIDMAW_MOBILE; - otherWormEntry = NPC_DREADSCALE; - - submergeTimer = 500; - DoCast(me, SPELL_SUBMERGE_0); - stage = 2; + return new boss_acidmawAI(creature); } - }; - - CreatureAI* GetAI(Creature* creature) const - { - return new boss_acidmawAI(creature); - } }; class boss_dreadscale : public CreatureScript { -public: - boss_dreadscale() : CreatureScript("boss_dreadscale") { } + public: + boss_dreadscale() : CreatureScript("boss_dreadscale") { } - struct boss_dreadscaleAI : public boss_jormungarAI - { - boss_dreadscaleAI(Creature* creature) : boss_jormungarAI(creature) + struct boss_dreadscaleAI : public boss_jormungarAI { - instanceScript = creature->GetInstanceScript(); - } + boss_dreadscaleAI(Creature* creature) : boss_jormungarAI(creature) + { + } - InstanceScript* instanceScript; + void Reset() + { + boss_jormungarAI::Reset(); + BiteSpell = SPELL_BURNING_BITE; + SpewSpell = SPELL_MOLTEN_SPEW; + SpitSpell = SPELL_FIRE_SPIT; + SpraySpell = SPELL_BURNING_SPRAY; + ModelStationary = MODEL_DREADSCALE_STATIONARY; + ModelMobile = MODEL_DREADSCALE_MOBILE; + OtherWormEntry = NPC_ACIDMAW; + + events.SetPhase(PHASE_MOBILE); + events.ScheduleEvent(EVENT_SUMMON_ACIDMAW, 3*IN_MILLISECONDS); + events.ScheduleEvent(EVENT_SUBMERGE, 45*IN_MILLISECONDS, 0, PHASE_MOBILE); + WasMobile = false; + } - void Reset() - { - boss_jormungarAI::Reset(); - biteSpell = SPELL_BURNING_BITE; - spewSpell = SPELL_MOLTEN_SPEW; - spitSpell = SPELL_FIRE_SPIT; - spraySpell = SPELL_BURNING_SPRAY; - modelStationary = MODEL_DREADSCALE_STATIONARY; - modelMobile = MODEL_DREADSCALE_MOBILE; - otherWormEntry = NPC_ACIDMAW; - - submergeTimer = 45 * IN_MILLISECONDS; - stage = 0; - } + void MovementInform(uint32 type, uint32 pointId) + { + if (type != POINT_MOTION_TYPE) + return; - void MovementInform(uint32 type, uint32 pointId) - { - if (type != POINT_MOTION_TYPE) - return; + switch (pointId) + { + case 0: + instance->DoUseDoorOrButton(instance->GetData64(GO_MAIN_GATE_DOOR)); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); + me->SetReactState(REACT_AGGRESSIVE); + me->SetInCombatWithZone(); + break; + default: + break; + } + } - switch (pointId) + void EnterEvadeMode() { - case 0: - instanceScript->DoUseDoorOrButton(instanceScript->GetData64(GO_MAIN_GATE_DOOR)); - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); - me->SetReactState(REACT_AGGRESSIVE); - me->SetInCombatWithZone(); - if (Creature* otherWorm = Unit::GetCreature(*me, instanceScript->GetData64(otherWormEntry))) - { - otherWorm->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); - otherWorm->SetReactState(REACT_AGGRESSIVE); - otherWorm->SetVisible(true); - otherWorm->SetInCombatWithZone(); - } - break; + instance->DoUseDoorOrButton(instance->GetData64(GO_MAIN_GATE_DOOR)); + boss_jormungarAI::EnterEvadeMode(); } - } - void EnterEvadeMode() - { - instanceScript->DoUseDoorOrButton(instanceScript->GetData64(GO_MAIN_GATE_DOOR)); - boss_jormungarAI::EnterEvadeMode(); - } + void JustReachedHome() + { + if (instance) + instance->DoUseDoorOrButton(instance->GetData64(GO_MAIN_GATE_DOOR)); - void JustReachedHome() - { - if (instanceScript) - instanceScript->DoUseDoorOrButton(instanceScript->GetData64(GO_MAIN_GATE_DOOR)); + boss_jormungarAI::JustReachedHome(); + } + }; - boss_jormungarAI::JustReachedHome(); + CreatureAI* GetAI(Creature* creature) const + { + return new boss_dreadscaleAI(creature); } - }; - - CreatureAI* GetAI(Creature* creature) const - { - return new boss_dreadscaleAI(creature); - } }; class mob_slime_pool : public CreatureScript { -public: - mob_slime_pool() : CreatureScript("mob_slime_pool") { } - - CreatureAI* GetAI(Creature* creature) const - { - return new mob_slime_poolAI(creature); - } - - struct mob_slime_poolAI : public ScriptedAI - { - mob_slime_poolAI(Creature* creature) : ScriptedAI(creature) - { - } + public: + mob_slime_pool() : CreatureScript("mob_slime_pool") { } - bool casted; - void Reset() + struct mob_slime_poolAI : public ScriptedAI { - casted = false; - me->SetReactState(REACT_PASSIVE); - } + mob_slime_poolAI(Creature* creature) : ScriptedAI(creature) + { + _instance = creature->GetInstanceScript(); + } - void UpdateAI(uint32 const /*diff*/) - { - if (!casted) + void Reset() { - casted = true; - DoCast(me, SPELL_SLIME_POOL_EFFECT); + _cast = false; + me->SetReactState(REACT_PASSIVE); } - } - }; -}; + void UpdateAI(uint32 const /*diff*/) + { + if (!_cast) + { + _cast = true; + DoCast(me, SPELL_SLIME_POOL_EFFECT); + } -class boss_icehowl : public CreatureScript -{ -public: - boss_icehowl() : CreatureScript("boss_icehowl") { } + if (_instance->GetData(TYPE_NORTHREND_BEASTS) != SNAKES_IN_PROGRESS && _instance->GetData(TYPE_NORTHREND_BEASTS) != SNAKES_SPECIAL) + me->DespawnOrUnsummon(); + } + private: + InstanceScript* _instance; + bool _cast; - CreatureAI* GetAI(Creature* creature) const - { - return new boss_icehowlAI(creature); - } + }; - struct boss_icehowlAI : public ScriptedAI - { - boss_icehowlAI(Creature* creature) : ScriptedAI(creature) + CreatureAI* GetAI(Creature* creature) const { - instance = creature->GetInstanceScript(); + return new mob_slime_poolAI(creature); } +}; - InstanceScript* instance; - - uint32 m_uiFerociousButtTimer; - uint32 m_uiArticBreathTimer; - uint32 m_uiWhirlTimer; - uint32 m_uiMassiveCrashTimer; - uint32 m_uiTrampleTimer; - float m_fTrampleTargetX, m_fTrampleTargetY, m_fTrampleTargetZ; - uint64 m_uiTrampleTargetGUID; - bool m_bMovementStarted; - bool m_bMovementFinish; - bool m_bTrampleCasted; - uint8 m_uiStage; - Unit* target; - - void Reset() +class spell_gormok_fire_bomb : public SpellScriptLoader +{ + public: + spell_gormok_fire_bomb() : SpellScriptLoader("spell_gormok_fire_bomb") {} + + class spell_gormok_fire_bomb_SpellScript : public SpellScript { - m_uiFerociousButtTimer = urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS); - m_uiArticBreathTimer = urand(25*IN_MILLISECONDS, 40*IN_MILLISECONDS); - m_uiWhirlTimer = urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS); - m_uiMassiveCrashTimer = 30*IN_MILLISECONDS; - m_uiTrampleTimer = IN_MILLISECONDS; - m_bMovementStarted = false; - m_bMovementFinish = false; - m_bTrampleCasted = false; - m_uiTrampleTargetGUID = 0; - m_fTrampleTargetX = 0; - m_fTrampleTargetY = 0; - m_fTrampleTargetZ = 0; - m_uiStage = 0; - } + PrepareSpellScript(spell_gormok_fire_bomb_SpellScript); + + void TriggerFireBomb(SpellEffIndex /*effIndex*/) + { + if (const WorldLocation* pos = GetExplTargetDest()) + { + if (Unit* caster = GetCaster()) + caster->SummonCreature(NPC_FIRE_BOMB, pos->GetPositionX(), pos->GetPositionY(), pos->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 30*IN_MILLISECONDS); + } + } + + void Register() + { + OnEffectHit += SpellEffectFn(spell_gormok_fire_bomb_SpellScript::TriggerFireBomb, EFFECT_0, SPELL_EFFECT_TRIGGER_MISSILE); + } + }; - void JustDied(Unit* /*killer*/) + SpellScript* GetSpellScript() const { - if (instance) - instance->SetData(TYPE_NORTHREND_BEASTS, ICEHOWL_DONE); + return new spell_gormok_fire_bomb_SpellScript(); } +}; + +class boss_icehowl : public CreatureScript +{ + public: + boss_icehowl() : CreatureScript("boss_icehowl") { } - void MovementInform(uint32 type, uint32 pointId) + struct boss_icehowlAI : public BossAI { - if (type != POINT_MOTION_TYPE && type != EFFECT_MOTION_TYPE) - return; + boss_icehowlAI(Creature* creature) : BossAI(creature, BOSS_BEASTS) + { + } - switch (pointId) + void Reset() { - case 0: - if (me->GetDistance2d(ToCCommonLoc[1].GetPositionX(), ToCCommonLoc[1].GetPositionY()) < 6.0f) - { - // Middle of the room - m_uiStage = 1; - } - else - { - // Landed from Hop backwards (start trample) - if (Unit::GetPlayer(*me, m_uiTrampleTargetGUID)) + events.ScheduleEvent(EVENT_FEROCIOUS_BUTT, urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_ARCTIC_BREATH, urand(15*IN_MILLISECONDS, 25*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_WHIRL, urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_MASSIVE_CRASH, 30*IN_MILLISECONDS); + _movementStarted = false; + _movementFinish = false; + _trampleCasted = false; + _trampleTargetGUID = 0; + _trampleTargetX = 0; + _trampleTargetY = 0; + _trampleTargetZ = 0; + _stage = 0; + } + + void JustDied(Unit* /*killer*/) + { + _JustDied(); + if (instance) + instance->SetData(TYPE_NORTHREND_BEASTS, ICEHOWL_DONE); + } + + void MovementInform(uint32 type, uint32 pointId) + { + if (type != POINT_MOTION_TYPE && type != EFFECT_MOTION_TYPE) + return; + + switch (pointId) + { + case 0: + if (_stage != 0) { - m_uiStage = 4; + if (me->GetDistance2d(ToCCommonLoc[1].GetPositionX(), ToCCommonLoc[1].GetPositionY()) < 6.0f) + // Middle of the room + _stage = 1; + else + { + // Landed from Hop backwards (start trample) + if (Unit::GetPlayer(*me, _trampleTargetGUID)) + _stage = 4; + else + _stage = 6; + } } - else - m_uiStage = 6; - } - break; - case 1: // Finish trample - m_bMovementFinish = true; - break; - case 2: - instance->DoUseDoorOrButton(instance->GetData64(GO_MAIN_GATE_DOOR)); - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); - me->SetReactState(REACT_AGGRESSIVE); - me->SetInCombatWithZone(); - break; + break; + case 1: // Finish trample + _movementFinish = true; + break; + case 2: + instance->DoUseDoorOrButton(instance->GetData64(GO_MAIN_GATE_DOOR)); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); + me->SetReactState(REACT_AGGRESSIVE); + me->SetInCombatWithZone(); + break; + default: + break; + } } - } - void EnterEvadeMode() - { - instance->DoUseDoorOrButton(instance->GetData64(GO_MAIN_GATE_DOOR)); - ScriptedAI::EnterEvadeMode(); - } - - void JustReachedHome() - { - if (instance) + void EnterEvadeMode() { instance->DoUseDoorOrButton(instance->GetData64(GO_MAIN_GATE_DOOR)); - instance->SetData(TYPE_NORTHREND_BEASTS, FAIL); + ScriptedAI::EnterEvadeMode(); } - me->DespawnOrUnsummon(); - } - void KilledUnit(Unit* who) - { - if (who->GetTypeId() == TYPEID_PLAYER) + void JustReachedHome() { if (instance) - instance->SetData(DATA_TRIBUTE_TO_IMMORTALITY_ELEGIBLE, 0); + { + instance->DoUseDoorOrButton(instance->GetData64(GO_MAIN_GATE_DOOR)); + instance->SetData(TYPE_NORTHREND_BEASTS, FAIL); + } + me->DespawnOrUnsummon(); } - } - - void EnterCombat(Unit* /*who*/) - { - if (instance) - instance->SetData(TYPE_NORTHREND_BEASTS, ICEHOWL_IN_PROGRESS); - me->SetInCombatWithZone(); - } - void SpellHitTarget(Unit* target, SpellInfo const* spell) - { - if (spell->Id == SPELL_TRAMPLE && target->GetTypeId() == TYPEID_PLAYER) + void KilledUnit(Unit* who) { - if (!m_bTrampleCasted) + if (who->GetTypeId() == TYPEID_PLAYER) { - DoCast(me, SPELL_FROTHING_RAGE, true); - m_bTrampleCasted = true; + if (instance) + instance->SetData(DATA_TRIBUTE_TO_IMMORTALITY_ELEGIBLE, 0); } } - } - void UpdateAI(uint32 const diff) - { - if (!UpdateVictim()) - return; + void EnterCombat(Unit* /*who*/) + { + _EnterCombat(); + if (instance) + instance->SetData(TYPE_NORTHREND_BEASTS, ICEHOWL_IN_PROGRESS); + } - switch (m_uiStage) + void SpellHitTarget(Unit* target, SpellInfo const* spell) { - case 0: - if (m_uiFerociousButtTimer <= diff) + if (spell->Id == SPELL_TRAMPLE && target->GetTypeId() == TYPEID_PLAYER) + { + if (!_trampleCasted) { - DoCastVictim(SPELL_FEROCIOUS_BUTT); - m_uiFerociousButtTimer = urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS); - } else m_uiFerociousButtTimer -= diff; + DoCast(me, SPELL_FROTHING_RAGE, true); + _trampleCasted = true; + } + } + } - if (m_uiArticBreathTimer <= diff) - { - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) - DoCast(target, SPELL_ARCTIC_BREATH); - m_uiArticBreathTimer = urand(25*IN_MILLISECONDS, 40*IN_MILLISECONDS); - } else m_uiArticBreathTimer -= diff; + void UpdateAI(uint32 const diff) + { + if (!UpdateVictim()) + return; - if (m_uiWhirlTimer <= diff) - { - DoCastAOE(SPELL_WHIRL); - m_uiWhirlTimer = urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS); - } else m_uiWhirlTimer -= diff; + events.Update(diff); - if (m_uiMassiveCrashTimer <= diff) - { - me->GetMotionMaster()->MoveJump(ToCCommonLoc[1].GetPositionX(), ToCCommonLoc[1].GetPositionY(), ToCCommonLoc[1].GetPositionZ(), 10.0f, 20.0f); // 1: Middle of the room - SetCombatMovement(false); - me->AttackStop(); - m_uiStage = 7; //Invalid (Do nothing more than move) - m_uiMassiveCrashTimer = 30*IN_MILLISECONDS; - } else m_uiMassiveCrashTimer -= diff; + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; - DoMeleeAttackIfReady(); - break; - case 1: - DoCastAOE(SPELL_MASSIVE_CRASH); - me->StopMoving(); - me->AttackStop(); - m_uiStage = 2; - break; - case 2: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0, true)) + switch (_stage) + { + case 0: { + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_FEROCIOUS_BUTT: + DoCastVictim(SPELL_FEROCIOUS_BUTT); + events.ScheduleEvent(EVENT_FEROCIOUS_BUTT, urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS)); + return; + case EVENT_ARCTIC_BREATH: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true)) + DoCast(target, SPELL_ARCTIC_BREATH); + return; + case EVENT_WHIRL: + DoCastAOE(SPELL_WHIRL); + events.ScheduleEvent(EVENT_WHIRL, urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS)); + return; + case EVENT_MASSIVE_CRASH: + me->GetMotionMaster()->MoveJump(ToCCommonLoc[1].GetPositionX(), ToCCommonLoc[1].GetPositionY(), ToCCommonLoc[1].GetPositionZ(), 20.0f, 20.0f); // 1: Middle of the room + SetCombatMovement(false); + me->AttackStop(); + _stage = 7; //Invalid (Do nothing more than move) + return; + default: + break; + } + } + DoMeleeAttackIfReady(); + break; + } + case 1: + DoCastAOE(SPELL_MASSIVE_CRASH); me->StopMoving(); me->AttackStop(); - m_uiTrampleTargetGUID = target->GetGUID(); - me->SetTarget(m_uiTrampleTargetGUID); - m_bTrampleCasted = false; - //SetCombatMovement(false); - //me->GetMotionMaster()->MoveIdle(); - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - m_uiTrampleTimer = 4*IN_MILLISECONDS; - m_uiStage = 3; - } else m_uiStage = 6; - break; - case 3: - me->StopMoving(); - me->AttackStop(); - if (m_uiTrampleTimer <= diff) - { - if (Unit* target = Unit::GetPlayer(*me, m_uiTrampleTargetGUID)) + _stage = 2; + break; + case 2: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true)) { - m_bTrampleCasted = false; - m_bMovementStarted = true; - m_fTrampleTargetX = target->GetPositionX(); - m_fTrampleTargetY = target->GetPositionY(); - m_fTrampleTargetZ = target->GetPositionZ(); - me->GetMotionMaster()->MoveJump(2*me->GetPositionX()-m_fTrampleTargetX, - 2*me->GetPositionY()-m_fTrampleTargetY, - me->GetPositionZ(), - 20.0f, 30.0f); // 2: Hop Backwards - m_uiStage = 7; //Invalid (Do nothing more than move) - } else m_uiStage = 6; - } else m_uiTrampleTimer -= diff; - break; - case 4: - me->StopMoving(); - me->AttackStop(); - Talk(EMOTE_TRAMPLE_START, m_uiTrampleTargetGUID); - me->GetMotionMaster()->MoveCharge(m_fTrampleTargetX, m_fTrampleTargetY, m_fTrampleTargetZ+2, 42, 1); - me->SetTarget(0); - m_uiStage = 5; - break; - case 5: - if (m_bMovementFinish) - { - if (m_uiTrampleTimer <= diff) DoCastAOE(SPELL_TRAMPLE); - m_bMovementFinish = false; - m_uiStage = 6; - return; - } - if (m_uiTrampleTimer <= diff) - { - Map::PlayerList const &lPlayers = me->GetMap()->GetPlayers(); - for (Map::PlayerList::const_iterator itr = lPlayers.begin(); itr != lPlayers.end(); ++itr) + me->StopMoving(); + me->AttackStop(); + _trampleTargetGUID = target->GetGUID(); + me->SetTarget(_trampleTargetGUID); + _trampleCasted = false; + SetCombatMovement(false); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_DISABLE_MOVE); + me->GetMotionMaster()->Clear(); + me->GetMotionMaster()->MoveIdle(); + events.ScheduleEvent(EVENT_TRAMPLE, 4*IN_MILLISECONDS); + _stage = 3; + } + else + _stage = 6; + break; + case 3: + while (uint32 eventId = events.ExecuteEvent()) { - if (Unit* player = itr->getSource()) - if (player->isAlive() && player->IsWithinDistInMap(me, 6.0f)) + switch (eventId) + { + case EVENT_TRAMPLE: { - DoCastAOE(SPELL_TRAMPLE); - m_uiTrampleTimer = IN_MILLISECONDS; + if (Unit* target = Unit::GetPlayer(*me, _trampleTargetGUID)) + { + me->StopMoving(); + me->AttackStop(); + _trampleCasted = false; + _movementStarted = true; + _trampleTargetX = target->GetPositionX(); + _trampleTargetY = target->GetPositionY(); + _trampleTargetZ = target->GetPositionZ(); + // 2: Hop Backwards + me->GetMotionMaster()->MoveJump(2*me->GetPositionX() - _trampleTargetX, 2*me->GetPositionY() - _trampleTargetY, me->GetPositionZ(), 30.0f, 20.0f); + _stage = 7; //Invalid (Do nothing more than move) + } + else + _stage = 6; break; } + default: + break; + } } - } else m_uiTrampleTimer -= diff; - break; - case 6: - if (!m_bTrampleCasted) - { - DoCast(me, SPELL_STAGGERED_DAZE); - Talk(EMOTE_TRAMPLE_CRASH); - } - else - { - DoCast(me, SPELL_FROTHING_RAGE, true); - Talk(EMOTE_TRAMPLE_FAIL); - } - m_bMovementStarted = false; - me->GetMotionMaster()->MovementExpired(); - me->GetMotionMaster()->MoveChase(me->getVictim()); - SetCombatMovement(true); - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - m_uiStage = 0; - break; + break; + case 4: + me->StopMoving(); + me->AttackStop(); + Talk(EMOTE_TRAMPLE_START, _trampleTargetGUID); + me->GetMotionMaster()->MoveCharge(_trampleTargetX, _trampleTargetY, _trampleTargetZ, 42, 1); + me->SetTarget(0); + _stage = 5; + break; + case 5: + if (_movementFinish) + { + DoCastAOE(SPELL_TRAMPLE); + _movementFinish = false; + _stage = 6; + return; + } + if (events.ExecuteEvent() == EVENT_TRAMPLE) + { + Map::PlayerList const &lPlayers = me->GetMap()->GetPlayers(); + for (Map::PlayerList::const_iterator itr = lPlayers.begin(); itr != lPlayers.end(); ++itr) + { + if (Unit* player = itr->getSource()) + { + if (player->isAlive() && player->IsWithinDistInMap(me, 6.0f)) + { + DoCastAOE(SPELL_TRAMPLE); + events.ScheduleEvent(EVENT_TRAMPLE, 4*IN_MILLISECONDS); + break; + } + } + } + } + break; + case 6: + if (!_trampleCasted) + { + DoCast(me, SPELL_STAGGERED_DAZE); + Talk(EMOTE_TRAMPLE_CRASH); + } + else + { + DoCast(me, SPELL_FROTHING_RAGE, true); + Talk(EMOTE_TRAMPLE_FAIL); + } + _movementStarted = false; + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_DISABLE_MOVE); + SetCombatMovement(true); + me->GetMotionMaster()->MovementExpired(); + me->GetMotionMaster()->Clear(); + me->GetMotionMaster()->MoveChase(me->getVictim()); + AttackStart(me->getVictim()); + events.ScheduleEvent(EVENT_MASSIVE_CRASH, 40*IN_MILLISECONDS); + events.ScheduleEvent(EVENT_ARCTIC_BREATH, urand(15*IN_MILLISECONDS, 25*IN_MILLISECONDS)); + _stage = 0; + break; + default: + break; + } } - } - }; + private: + float _trampleTargetX, _trampleTargetY, _trampleTargetZ; + uint64 _trampleTargetGUID; + bool _movementStarted; + bool _movementFinish; + bool _trampleCasted; + uint8 _stage; + Unit* _target; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new boss_icehowlAI(creature); + } }; void AddSC_boss_northrend_beasts() { new boss_gormok(); new mob_snobold_vassal(); + new npc_firebomb(); + new spell_gormok_fire_bomb(); + new boss_acidmaw(); new boss_dreadscale(); new mob_slime_pool(); + new boss_icehowl(); } diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_twin_valkyr.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_twin_valkyr.cpp index a65eaebbc0c..4d99429bcb8 100755 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_twin_valkyr.cpp +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_twin_valkyr.cpp @@ -16,13 +16,6 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -/* ScriptData -SDName: trial_of_the_crusader -SD%Complete: ??% -SDComment: based on /dev/rsa -SDCategory: Crusader Coliseum -EndScriptData */ - // Known bugs: // - They should be floating but they aren't respecting the floor =( // - Hardcoded bullets spawner @@ -48,13 +41,13 @@ enum Yells SAY_TWINK_PACT = 5, SAY_KILL_PLAYER = 6, SAY_BERSERK = 7, - SAY_DEATH = 8, + SAY_DEATH = 8 }; enum Equipment { EQUIP_MAIN_1 = 9423, - EQUIP_MAIN_2 = 37377, + EQUIP_MAIN_2 = 37377 }; enum Summons @@ -62,7 +55,7 @@ enum Summons NPC_BULLET_CONTROLLER = 34743, NPC_BULLET_DARK = 34628, - NPC_BULLET_LIGHT = 34630, + NPC_BULLET_LIGHT = 34630 }; enum BossSpells @@ -72,6 +65,7 @@ enum BossSpells SPELL_LIGHT_SHIELD = 65858, SPELL_LIGHT_TWIN_PACT = 65876, SPELL_LIGHT_VORTEX = 66046, + SPELL_LIGHT_VORTEX_DAMAGE = 66048, SPELL_LIGHT_TOUCH = 67297, SPELL_LIGHT_ESSENCE = 65686, SPELL_EMPOWERED_LIGHT = 65748, @@ -83,17 +77,18 @@ enum BossSpells SPELL_DARK_SHIELD = 65874, SPELL_DARK_TWIN_PACT = 65875, SPELL_DARK_VORTEX = 66058, + SPELL_DARK_VORTEX_DAMAGE = 66059, SPELL_DARK_TOUCH = 67282, SPELL_DARK_ESSENCE = 65684, SPELL_EMPOWERED_DARK = 65724, SPELL_TWIN_EMPATHY_DARK = 66132, SPELL_UNLEASHED_DARK = 65808, - SPELL_CONTROLLER_PERIODIC = 66149, + SPELL_CONTROLLER_PERIODIC = 66149, SPELL_POWER_TWINS = 65879, SPELL_BERSERK = 64238, SPELL_POWERING_UP = 67590, - SPELL_SURGE_OF_SPEED = 65828, + SPELL_SURGE_OF_SPEED = 65828 }; #define SPELL_DARK_ESSENCE_HELPER RAID_MODE<uint32>(65684, 67176, 67177, 67178) @@ -106,13 +101,12 @@ enum BossSpells enum Actions { - ACTION_VORTEX, - ACTION_PACT + ACTION_VORTEX = 0, + ACTION_PACT = 1 }; -/*###### -## boss_twin_base -######*/ +#define ESSENCE_REMOVE 0 +#define ESSENCE_APPLY 1 class OrbsDespawner : public BasicEvent { @@ -145,61 +139,36 @@ class OrbsDespawner : public BasicEvent Creature* _creature; }; -struct boss_twin_baseAI : public ScriptedAI +struct boss_twin_baseAI : public BossAI { - boss_twin_baseAI(Creature* creature) : ScriptedAI(creature), Summons(me) + boss_twin_baseAI(Creature* creature) : BossAI(creature, BOSS_VALKIRIES) { - instance = creature->GetInstanceScript(); } - InstanceScript* instance; - SummonList Summons; - - AuraStateType m_uiAuraState; - - uint8 m_uiStage; - bool m_bIsBerserk; - uint32 m_uiWeapon; - uint32 m_uiSpecialAbilityTimer; - uint32 m_uiSpikeTimer; - uint32 m_uiTouchTimer; - uint32 m_uiBerserkTimer; - - int32 m_uiVortexEmote; - uint32 m_uiSisterNpcId; - uint32 m_uiMyEmphatySpellId; - uint32 m_uiOtherEssenceSpellId; - uint32 m_uiSurgeSpellId; - uint32 m_uiVortexSpellId; - uint32 m_uiShieldSpellId; - uint32 m_uiTwinPactSpellId; - uint32 m_uiSpikeSpellId; - uint32 m_uiTouchSpellId; - void Reset() { - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_NOT_SELECTABLE); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); me->SetReactState(REACT_PASSIVE); - me->ModifyAuraState(m_uiAuraState, true); - /* Uncomment this once that they are flying above the ground + me->ModifyAuraState(AuraState, true); + /* Uncomment this once that they are floating above the ground me->SetLevitate(true); me->SetFlying(true); */ - m_bIsBerserk = false; + IsBerserk = false; - m_uiSpecialAbilityTimer = MINUTE*IN_MILLISECONDS; - m_uiSpikeTimer = 20*IN_MILLISECONDS; - m_uiTouchTimer = urand(10, 15)*IN_MILLISECONDS; - m_uiBerserkTimer = IsHeroic() ? 6*MINUTE*IN_MILLISECONDS : 10*MINUTE*IN_MILLISECONDS; + SpecialAbilityTimer = 1*MINUTE*IN_MILLISECONDS; + SpikeTimer = 20*IN_MILLISECONDS; + TouchTimer = urand(10*IN_MILLISECONDS, 15*IN_MILLISECONDS); + BerserkTimer = IsHeroic() ? 6*MINUTE*IN_MILLISECONDS : 10*MINUTE*IN_MILLISECONDS; - Summons.DespawnAll(); + summons.DespawnAll(); } void JustReachedHome() { if (instance) - instance->SetData(TYPE_VALKIRIES, FAIL); + instance->SetBossState(BOSS_VALKIRIES, FAIL); - Summons.DespawnAll(); + summons.DespawnAll(); me->DespawnOrUnsummon(); } @@ -211,10 +180,11 @@ struct boss_twin_baseAI : public ScriptedAI switch (uiId) { case 1: - instance->DoUseDoorOrButton(instance->GetData64(GO_MAIN_GATE_DOOR)); me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_NOT_SELECTABLE); me->SetReactState(REACT_AGGRESSIVE); break; + default: + break; } } @@ -230,7 +200,7 @@ struct boss_twin_baseAI : public ScriptedAI void JustSummoned(Creature* summoned) { - Summons.Summon(summoned); + summons.Summon(summoned); } void SummonedCreatureDespawn(Creature* summoned) @@ -248,8 +218,10 @@ struct boss_twin_baseAI : public ScriptedAI case NPC_BULLET_CONTROLLER: me->m_Events.AddEvent(new OrbsDespawner(me), me->m_Events.CalculateTime(100)); break; + default: + break; } - Summons.Despawn(summoned); + summons.Despawn(summoned); } void JustDied(Unit* /*killer*/) @@ -263,24 +235,22 @@ struct boss_twin_baseAI : public ScriptedAI { me->SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); pSister->SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); - - instance->SetData(TYPE_VALKIRIES, DONE); - Summons.DespawnAll(); + _JustDied(); } else { me->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); - instance->SetData(TYPE_VALKIRIES, SPECIAL); + instance->SetBossState(BOSS_VALKIRIES, SPECIAL); } } } - Summons.DespawnAll(); + summons.DespawnAll(); } // Called when sister pointer needed Creature* GetSister() { - return Unit::GetCreature((*me), instance->GetData64(m_uiSisterNpcId)); + return Unit::GetCreature((*me), instance->GetData64(SisterNpcId)); } void EnterCombat(Unit* /*who*/) @@ -290,14 +260,14 @@ struct boss_twin_baseAI : public ScriptedAI { if (Creature* pSister = GetSister()) { - me->AddAura(m_uiMyEmphatySpellId, pSister); + me->AddAura(MyEmphatySpellId, pSister); pSister->SetInCombatWithZone(); } - instance->SetData(TYPE_VALKIRIES, IN_PROGRESS); + instance->SetBossState(BOSS_VALKIRIES, IN_PROGRESS); } Talk(SAY_AGGRO); - DoCast(me, m_uiSurgeSpellId); + DoCast(me, SurgeSpellId); } void DoAction(const int32 action) @@ -305,45 +275,50 @@ struct boss_twin_baseAI : public ScriptedAI switch (action) { case ACTION_VORTEX: - m_uiStage = me->GetEntry() == NPC_LIGHTBANE ? 2 : 1; + Stage = me->GetEntry() == NPC_LIGHTBANE ? 2 : 1; break; case ACTION_PACT: - m_uiStage = me->GetEntry() == NPC_LIGHTBANE ? 1 : 2; + Stage = me->GetEntry() == NPC_LIGHTBANE ? 1 : 2; + break; + default: break; } } void EnableDualWield(bool mode = true) { - SetEquipmentSlots(false, m_uiWeapon, mode ? m_uiWeapon : int32(EQUIP_UNEQUIP), EQUIP_UNEQUIP); + SetEquipmentSlots(false, Weapon, mode ? Weapon : int32(EQUIP_UNEQUIP), EQUIP_UNEQUIP); me->SetCanDualWield(mode); me->UpdateDamagePhysical(mode ? OFF_ATTACK : BASE_ATTACK); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 diff) { if (!instance || !UpdateVictim()) return; - switch (m_uiStage) + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + switch (Stage) { case 0: break; case 1: // Vortex - if (m_uiSpecialAbilityTimer <= uiDiff) + if (SpecialAbilityTimer <= diff) { if (Creature* pSister = GetSister()) pSister->AI()->DoAction(ACTION_VORTEX); - Talk(m_uiVortexEmote); - DoCastAOE(m_uiVortexSpellId); - m_uiStage = 0; - m_uiSpecialAbilityTimer = MINUTE*IN_MILLISECONDS; + Talk(VortexEmote); + DoCastAOE(VortexSpellId); + Stage = 0; + SpecialAbilityTimer = 1*MINUTE*IN_MILLISECONDS; } else - m_uiSpecialAbilityTimer -= uiDiff; + SpecialAbilityTimer -= diff; break; - case 2: // Shield+Pact - if (m_uiSpecialAbilityTimer <= uiDiff) + case 2: // Shield + Pact + if (SpecialAbilityTimer <= diff) { Talk(EMOTE_TWINK_PACT); Talk(SAY_TWINK_PACT); @@ -352,164 +327,169 @@ struct boss_twin_baseAI : public ScriptedAI pSister->AI()->DoAction(ACTION_PACT); pSister->CastSpell(pSister, SPELL_POWER_TWINS, false); } - DoCast(me, m_uiShieldSpellId); - DoCast(me, m_uiTwinPactSpellId); - m_uiStage = 0; - m_uiSpecialAbilityTimer = MINUTE*IN_MILLISECONDS; + DoCast(me, ShieldSpellId); + DoCast(me, TwinPactSpellId); + Stage = 0; + SpecialAbilityTimer = 1*MINUTE*IN_MILLISECONDS; } else - m_uiSpecialAbilityTimer -= uiDiff; + SpecialAbilityTimer -= diff; break; default: break; } - if (m_uiSpikeTimer <= uiDiff) + if (SpikeTimer <= diff) { - DoCastVictim(m_uiSpikeSpellId); - m_uiSpikeTimer = 20*IN_MILLISECONDS; + DoCastVictim(SpikeSpellId); + SpikeTimer = 20*IN_MILLISECONDS; } else - m_uiSpikeTimer -= uiDiff; + SpikeTimer -= diff; - if (IsHeroic() && m_uiTouchTimer <= uiDiff) + if (IsHeroic() && TouchTimer <= diff) { - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 200, true, m_uiOtherEssenceSpellId)) - me->CastCustomSpell(m_uiTouchSpellId, SPELLVALUE_MAX_TARGETS, 1, target, false); - m_uiTouchTimer = urand(10, 15)*IN_MILLISECONDS; + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 200.0f, true, OtherEssenceSpellId)) + me->CastCustomSpell(TouchSpellId, SPELLVALUE_MAX_TARGETS, 1, target, false); + TouchTimer = urand(10*IN_MILLISECONDS, 15*IN_MILLISECONDS); } else - m_uiTouchTimer -= uiDiff; + TouchTimer -= diff; - if (!m_bIsBerserk && m_uiBerserkTimer <= uiDiff) + if (!IsBerserk && BerserkTimer <= diff) { DoCast(me, SPELL_BERSERK); Talk(SAY_BERSERK); - m_bIsBerserk = true; + IsBerserk = true; } else - m_uiBerserkTimer -= uiDiff; + BerserkTimer -= diff; DoMeleeAttackIfReady(); } -}; -/*###### -## boss_fjola -######*/ + protected: + AuraStateType AuraState; + + uint8 Stage; + bool IsBerserk; + + uint32 Weapon; + uint32 SpecialAbilityTimer; + uint32 SpikeTimer; + uint32 TouchTimer; + uint32 BerserkTimer; + + int32 VortexEmote; + uint32 SisterNpcId; + uint32 MyEmphatySpellId; + uint32 OtherEssenceSpellId; + uint32 SurgeSpellId; + uint32 VortexSpellId; + uint32 ShieldSpellId; + uint32 TwinPactSpellId; + uint32 SpikeSpellId; + uint32 TouchSpellId; +}; class boss_fjola : public CreatureScript { -public: - boss_fjola() : CreatureScript("boss_fjola") { } - - CreatureAI* GetAI(Creature* creature) const - { - return new boss_fjolaAI(creature); - } + public: + boss_fjola() : CreatureScript("boss_fjola") { } - struct boss_fjolaAI : public boss_twin_baseAI - { - boss_fjolaAI(Creature* creature) : boss_twin_baseAI(creature) + struct boss_fjolaAI : public boss_twin_baseAI { - instance = creature->GetInstanceScript(); - } + boss_fjolaAI(Creature* creature) : boss_twin_baseAI(creature) + { + } - InstanceScript* instance; - - void Reset() { - boss_twin_baseAI::Reset(); - SetEquipmentSlots(false, EQUIP_MAIN_1, EQUIP_UNEQUIP, EQUIP_NO_CHANGE); - m_uiStage = 0; - m_uiWeapon = EQUIP_MAIN_1; - m_uiAuraState = AURA_STATE_UNKNOWN22; - m_uiVortexEmote = EMOTE_VORTEX; - m_uiSisterNpcId = NPC_DARKBANE; - m_uiMyEmphatySpellId = SPELL_TWIN_EMPATHY_DARK; - m_uiOtherEssenceSpellId = SPELL_DARK_ESSENCE_HELPER; - m_uiSurgeSpellId = SPELL_LIGHT_SURGE; - m_uiVortexSpellId = SPELL_LIGHT_VORTEX; - m_uiShieldSpellId = SPELL_LIGHT_SHIELD; - m_uiTwinPactSpellId = SPELL_LIGHT_TWIN_PACT; - m_uiTouchSpellId = SPELL_LIGHT_TOUCH; - m_uiSpikeSpellId = SPELL_LIGHT_TWIN_SPIKE; + void Reset() + { + SetEquipmentSlots(false, EQUIP_MAIN_1, EQUIP_UNEQUIP, EQUIP_NO_CHANGE); + Stage = 0; + Weapon = EQUIP_MAIN_1; + AuraState = AURA_STATE_UNKNOWN22; + VortexEmote = EMOTE_VORTEX; + SisterNpcId = NPC_DARKBANE; + MyEmphatySpellId = SPELL_TWIN_EMPATHY_DARK; + OtherEssenceSpellId = SPELL_DARK_ESSENCE_HELPER; + SurgeSpellId = SPELL_LIGHT_SURGE; + VortexSpellId = SPELL_LIGHT_VORTEX; + ShieldSpellId = SPELL_LIGHT_SHIELD; + TwinPactSpellId = SPELL_LIGHT_TWIN_PACT; + TouchSpellId = SPELL_LIGHT_TOUCH; + SpikeSpellId = SPELL_LIGHT_TWIN_SPIKE; + + if (instance) + instance->DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, EVENT_START_TWINS_FIGHT); + boss_twin_baseAI::Reset(); + } - if (instance) + void EnterCombat(Unit* who) { - instance->DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, EVENT_START_TWINS_FIGHT); + if (instance) + instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, EVENT_START_TWINS_FIGHT); + + me->SummonCreature(NPC_BULLET_CONTROLLER, ToCCommonLoc[1].GetPositionX(), ToCCommonLoc[1].GetPositionY(), ToCCommonLoc[1].GetPositionZ(), 0.0f, TEMPSUMMON_MANUAL_DESPAWN); + boss_twin_baseAI::EnterCombat(who); } - } - void EnterCombat(Unit* who) - { - if (instance) + void EnterEvadeMode() { - instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, EVENT_START_TWINS_FIGHT); + instance->DoUseDoorOrButton(instance->GetData64(GO_MAIN_GATE_DOOR)); + boss_twin_baseAI::EnterEvadeMode(); } - me->SummonCreature(NPC_BULLET_CONTROLLER, ToCCommonLoc[1].GetPositionX(), ToCCommonLoc[1].GetPositionY(), ToCCommonLoc[1].GetPositionZ(), 0.0f, TEMPSUMMON_MANUAL_DESPAWN); - boss_twin_baseAI::EnterCombat(who); - } + void JustReachedHome() + { + if (instance) + instance->DoUseDoorOrButton(instance->GetData64(GO_MAIN_GATE_DOOR)); - void EnterEvadeMode() - { - instance->DoUseDoorOrButton(instance->GetData64(GO_MAIN_GATE_DOOR)); - boss_twin_baseAI::EnterEvadeMode(); - } + boss_twin_baseAI::JustReachedHome(); + } + }; - void JustReachedHome() + CreatureAI* GetAI(Creature* creature) const { - if (instance) - instance->DoUseDoorOrButton(instance->GetData64(GO_MAIN_GATE_DOOR)); - - boss_twin_baseAI::JustReachedHome(); + return new boss_fjolaAI(creature); } - }; - }; -/*###### -## boss_eydis -######*/ - class boss_eydis : public CreatureScript { -public: - boss_eydis() : CreatureScript("boss_eydis") { } + public: + boss_eydis() : CreatureScript("boss_eydis") { } - CreatureAI* GetAI(Creature* creature) const - { - return new boss_eydisAI(creature); - } + struct boss_eydisAI : public boss_twin_baseAI + { + boss_eydisAI(Creature* creature) : boss_twin_baseAI(creature) {} - struct boss_eydisAI : public boss_twin_baseAI - { - boss_eydisAI(Creature* creature) : boss_twin_baseAI(creature) {} - - void Reset() { - boss_twin_baseAI::Reset(); - SetEquipmentSlots(false, EQUIP_MAIN_2, EQUIP_UNEQUIP, EQUIP_NO_CHANGE); - m_uiStage = 1; - m_uiWeapon = EQUIP_MAIN_2; - m_uiAuraState = AURA_STATE_UNKNOWN19; - m_uiVortexEmote = EMOTE_VORTEX; - m_uiSisterNpcId = NPC_LIGHTBANE; - m_uiMyEmphatySpellId = SPELL_TWIN_EMPATHY_LIGHT; - m_uiOtherEssenceSpellId = SPELL_LIGHT_ESSENCE_HELPER; - m_uiSurgeSpellId = SPELL_DARK_SURGE; - m_uiVortexSpellId = SPELL_DARK_VORTEX; - m_uiShieldSpellId = SPELL_DARK_SHIELD; - m_uiTwinPactSpellId = SPELL_DARK_TWIN_PACT; - m_uiTouchSpellId = SPELL_DARK_TOUCH; - m_uiSpikeSpellId = SPELL_DARK_TWIN_SPIKE; - } - }; + void Reset() + { + SetEquipmentSlots(false, EQUIP_MAIN_2, EQUIP_UNEQUIP, EQUIP_NO_CHANGE); + Stage = 1; + Weapon = EQUIP_MAIN_2; + AuraState = AURA_STATE_UNKNOWN19; + VortexEmote = EMOTE_VORTEX; + SisterNpcId = NPC_LIGHTBANE; + MyEmphatySpellId = SPELL_TWIN_EMPATHY_LIGHT; + OtherEssenceSpellId = SPELL_LIGHT_ESSENCE_HELPER; + SurgeSpellId = SPELL_DARK_SURGE; + VortexSpellId = SPELL_DARK_VORTEX; + ShieldSpellId = SPELL_DARK_SHIELD; + TwinPactSpellId = SPELL_DARK_TWIN_PACT; + TouchSpellId = SPELL_DARK_TOUCH; + SpikeSpellId = SPELL_DARK_TWIN_SPIKE; + boss_twin_baseAI::Reset(); + } + }; + CreatureAI* GetAI(Creature* creature) const + { + return new boss_eydisAI(creature); + } }; -#define ESSENCE_REMOVE 0 -#define ESSENCE_APPLY 1 - class mob_essence_of_twin : public CreatureScript { public: @@ -525,10 +505,10 @@ class mob_essence_of_twin : public CreatureScript switch (me->GetEntry()) { case NPC_LIGHT_ESSENCE: - spellReturned = data == ESSENCE_REMOVE? SPELL_DARK_ESSENCE_HELPER : SPELL_LIGHT_ESSENCE_HELPER; + spellReturned = (data == ESSENCE_REMOVE) ? SPELL_DARK_ESSENCE_HELPER : SPELL_LIGHT_ESSENCE_HELPER; break; case NPC_DARK_ESSENCE: - spellReturned = data == ESSENCE_REMOVE? SPELL_LIGHT_ESSENCE_HELPER : SPELL_DARK_ESSENCE_HELPER; + spellReturned = (data == ESSENCE_REMOVE) ? SPELL_LIGHT_ESSENCE_HELPER : SPELL_DARK_ESSENCE_HELPER; break; default: break; @@ -556,12 +536,8 @@ struct mob_unleashed_ballAI : public ScriptedAI { mob_unleashed_ballAI(Creature* creature) : ScriptedAI(creature) { - instance = creature->GetInstanceScript(); } - InstanceScript* instance; - uint32 m_uiRangeCheckTimer; - void MoveToNextPoint() { float x0 = ToCCommonLoc[1].GetPositionX(), y0 = ToCCommonLoc[1].GetPositionY(), r = 47.0f; @@ -578,13 +554,13 @@ struct mob_unleashed_ballAI : public ScriptedAI void Reset() { - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_NOT_SELECTABLE); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); me->SetReactState(REACT_PASSIVE); me->SetDisableGravity(true); me->SetCanFly(true); SetCombatMovement(false); MoveToNextPoint(); - m_uiRangeCheckTimer = IN_MILLISECONDS; + RangeCheckTimer = 0.5*IN_MILLISECONDS; } void MovementInform(uint32 uiType, uint32 uiId) @@ -600,160 +576,112 @@ struct mob_unleashed_ballAI : public ScriptedAI else me->DisappearAndDie(); break; + default: + break; } } + + protected: + uint32 RangeCheckTimer; }; class mob_unleashed_dark : public CreatureScript { -public: - mob_unleashed_dark() : CreatureScript("mob_unleashed_dark") { } - - CreatureAI* GetAI(Creature* creature) const - { - return new mob_unleashed_darkAI(creature); - } - - struct mob_unleashed_darkAI : public mob_unleashed_ballAI - { - mob_unleashed_darkAI(Creature* creature) : mob_unleashed_ballAI(creature) {} + public: + mob_unleashed_dark() : CreatureScript("mob_unleashed_dark") { } - void UpdateAI(const uint32 uiDiff) + struct mob_unleashed_darkAI : public mob_unleashed_ballAI { - if (m_uiRangeCheckTimer < uiDiff) + mob_unleashed_darkAI(Creature* creature) : mob_unleashed_ballAI(creature) {} + + void UpdateAI(const uint32 diff) { - if (me->SelectNearestPlayer(2.0f)) + if (RangeCheckTimer < diff) + { + if (me->SelectNearestPlayer(3.0f)) { - DoCastAOE(SPELL_UNLEASHED_DARK); + DoCastAOE(SPELL_UNLEASHED_DARK_HELPER); me->GetMotionMaster()->MoveIdle(); - me->DespawnOrUnsummon(500); + me->DespawnOrUnsummon(1*IN_MILLISECONDS); } - m_uiRangeCheckTimer = IN_MILLISECONDS; + RangeCheckTimer = 0.5*IN_MILLISECONDS; + } + else + RangeCheckTimer -= diff; } - else m_uiRangeCheckTimer -= uiDiff; - } + }; - void SpellHitTarget(Unit* who, SpellInfo const* spell) + CreatureAI* GetAI(Creature* creature) const { - if (spell->Id == SPELL_UNLEASHED_DARK_HELPER) - { - if (who->HasAura(SPELL_DARK_ESSENCE_HELPER)) - who->CastSpell(who, SPELL_POWERING_UP, true); - } + return new mob_unleashed_darkAI(creature); } - }; - }; class mob_unleashed_light : public CreatureScript { -public: - mob_unleashed_light() : CreatureScript("mob_unleashed_light") { } - - CreatureAI* GetAI(Creature* creature) const - { - return new mob_unleashed_lightAI(creature); - } - - struct mob_unleashed_lightAI : public mob_unleashed_ballAI - { - mob_unleashed_lightAI(Creature* creature) : mob_unleashed_ballAI(creature) {} + public: + mob_unleashed_light() : CreatureScript("mob_unleashed_light") { } - void UpdateAI(const uint32 uiDiff) + struct mob_unleashed_lightAI : public mob_unleashed_ballAI { - if (m_uiRangeCheckTimer < uiDiff) + mob_unleashed_lightAI(Creature* creature) : mob_unleashed_ballAI(creature) {} + + void UpdateAI(const uint32 diff) { - if (me->SelectNearestPlayer(2.0f)) + if (RangeCheckTimer < diff) + { + if (me->SelectNearestPlayer(3.0f)) { - DoCastAOE(SPELL_UNLEASHED_LIGHT); + DoCastAOE(SPELL_UNLEASHED_LIGHT_HELPER); me->GetMotionMaster()->MoveIdle(); - me->DespawnOrUnsummon(500); + me->DespawnOrUnsummon(1*IN_MILLISECONDS); } - m_uiRangeCheckTimer = IN_MILLISECONDS; + RangeCheckTimer = 0.5*IN_MILLISECONDS; + } + else + RangeCheckTimer -= diff; } - else m_uiRangeCheckTimer -= uiDiff; - } + }; - void SpellHitTarget(Unit* who, SpellInfo const* spell) + CreatureAI* GetAI(Creature* creature) const { - if (spell->Id == SPELL_UNLEASHED_LIGHT_HELPER) - { - if (who->HasAura(SPELL_LIGHT_ESSENCE_HELPER)) - who->CastSpell(who, SPELL_POWERING_UP, true); - } + return new mob_unleashed_lightAI(creature); } - }; - }; class mob_bullet_controller : public CreatureScript { -public: - mob_bullet_controller() : CreatureScript("mob_bullet_controller") { } - - CreatureAI* GetAI(Creature* creature) const - { - return new mob_bullet_controllerAI(creature); - } - - struct mob_bullet_controllerAI : public Scripted_NoMovementAI - { - mob_bullet_controllerAI(Creature* creature) : Scripted_NoMovementAI(creature) - { - Reset(); - } - - void Reset() - { - DoCastAOE(SPELL_CONTROLLER_PERIODIC); - } - - void UpdateAI(const uint32 /*uiDiff*/) - { - UpdateVictim(); - } - }; -}; - -class spell_powering_up : public SpellScriptLoader -{ public: - spell_powering_up() : SpellScriptLoader("spell_powering_up") { } + mob_bullet_controller() : CreatureScript("mob_bullet_controller") { } - class spell_powering_up_AuraScript : public AuraScript + struct mob_bullet_controllerAI : public Scripted_NoMovementAI { - PrepareAuraScript(spell_powering_up_AuraScript); - - void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + mob_bullet_controllerAI(Creature* creature) : Scripted_NoMovementAI(creature) { - if (Unit* target = GetTarget()) - { - if (Aura* pAura = target->GetAura(GetId())) - { - if (pAura->GetStackAmount() == 100) - { - if (target->GetDummyAuraEffect(SPELLFAMILY_GENERIC, 2206, EFFECT_1)) - target->CastSpell(target, SPELL_EMPOWERED_DARK, true); - - if (target->GetDummyAuraEffect(SPELLFAMILY_GENERIC, 2845, EFFECT_1)) - target->CastSpell(target, SPELL_EMPOWERED_LIGHT, true); + Reset(); + } - target->RemoveAurasDueToSpell(GetId()); - } - } - } + void Reset() + { + DoCastAOE(SPELL_CONTROLLER_PERIODIC); } - void Register() + void UpdateAI(const uint32 /*diff*/) { - OnEffectApply += AuraEffectApplyFn(spell_powering_up_AuraScript::OnApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); + UpdateVictim(); } }; - AuraScript* GetAuraScript() const + CreatureAI* GetAI(Creature* creature) const { - return new spell_powering_up_AuraScript(); + return new mob_bullet_controllerAI(creature); } +}; + +class spell_powering_up : public SpellScriptLoader +{ + public: + spell_powering_up() : SpellScriptLoader("spell_powering_up") { } class spell_powering_up_SpellScript : public SpellScript { @@ -761,20 +689,39 @@ class spell_powering_up : public SpellScriptLoader PrepareSpellScript(spell_powering_up_SpellScript) uint32 spellId; + uint32 poweringUp; bool Load() { spellId = sSpellMgr->GetSpellIdForDifficulty(SPELL_SURGE_OF_SPEED, GetCaster()); if (!sSpellMgr->GetSpellInfo(spellId)) return false; + + poweringUp = sSpellMgr->GetSpellIdForDifficulty(SPELL_POWERING_UP, GetCaster()); + if (!sSpellMgr->GetSpellInfo(poweringUp)) + return false; + return true; } void HandleScriptEffect(SpellEffIndex /*effIndex*/) { - if (Unit* target = GetExplTargetUnit()) - if (urand(0, 99) < 15) - target->CastSpell(target, spellId, true); + if (Unit* target = GetHitUnit()) + { + if (Aura* pAura = target->GetAura(poweringUp)) + { + if (pAura->GetStackAmount() >= 100) + { + if (target->GetDummyAuraEffect(SPELLFAMILY_GENERIC, 2206, EFFECT_1)) + target->CastSpell(target, SPELL_EMPOWERED_DARK, true); + + if (target->GetDummyAuraEffect(SPELLFAMILY_GENERIC, 2845, EFFECT_1)) + target->CastSpell(target, SPELL_EMPOWERED_LIGHT, true); + + target->RemoveAurasDueToSpell(poweringUp); + } + } + } } void Register() @@ -808,10 +755,68 @@ class spell_valkyr_essences : public SpellScriptLoader return true; } - void Absorb(AuraEffect* /*aurEff*/, DamageInfo & /*dmgInfo*/, uint32 & /*absorbAmount*/) + void Absorb(AuraEffect* /*aurEff*/, DamageInfo & dmgInfo, uint32 & /*absorbAmount*/) { - if (urand(0, 99) < 5) - GetTarget()->CastSpell(GetTarget(), spellId, true); + if (Unit* owner = GetUnitOwner()) + { + if (dmgInfo.GetSpellInfo()) + { + if (uint32 poweringUp = sSpellMgr->GetSpellIdForDifficulty(SPELL_POWERING_UP, owner)) + { + if (urand(0, 99) < 5) + GetTarget()->CastSpell(GetTarget(), spellId, true); + + // Twin Vortex part + uint32 lightVortex = sSpellMgr->GetSpellIdForDifficulty(SPELL_LIGHT_VORTEX_DAMAGE, owner); + uint32 darkVortex = sSpellMgr->GetSpellIdForDifficulty(SPELL_DARK_VORTEX_DAMAGE, owner); + int32 stacksCount = int32(dmgInfo.GetSpellInfo()->Effects[EFFECT_0].CalcValue()) * 0.001 - 1; + + if (lightVortex && darkVortex && stacksCount) + { + if (dmgInfo.GetSpellInfo()->Id == darkVortex || dmgInfo.GetSpellInfo()->Id == lightVortex) + { + Aura* pAura = owner->GetAura(poweringUp); + if (pAura) + { + pAura->ModStackAmount(stacksCount); + owner->CastSpell(owner, poweringUp, true); + } + else + { + owner->CastSpell(owner, poweringUp, true); + if (Aura* pTemp = owner->GetAura(poweringUp)) + pTemp->ModStackAmount(stacksCount); + } + } + } + + // Picking floating balls + uint32 unleashedDark = sSpellMgr->GetSpellIdForDifficulty(SPELL_UNLEASHED_DARK, owner); + uint32 unleashedLight = sSpellMgr->GetSpellIdForDifficulty(SPELL_UNLEASHED_LIGHT, owner); + + if (unleashedDark && unleashedLight) + { + if (dmgInfo.GetSpellInfo()->Id == unleashedDark || dmgInfo.GetSpellInfo()->Id == unleashedLight) + { + // need to do the things in this order, else players might have 100 charges of Powering Up without anything happening + Aura* pAura = owner->GetAura(poweringUp); + if (pAura) + { + // 2 lines together add the correct amount of buff stacks + pAura->ModStackAmount(stacksCount); + owner->CastSpell(owner, poweringUp, true); + } + else + { + owner->CastSpell(owner, poweringUp, true); + if (Aura* pTemp = owner->GetAura(poweringUp)) + pTemp->ModStackAmount(stacksCount); + } + } + } + } + } + } } void Register() @@ -880,6 +885,7 @@ void AddSC_boss_twin_valkyr() new mob_unleashed_dark(); new mob_essence_of_twin(); new mob_bullet_controller(); + new spell_powering_up(); new spell_valkyr_essences(); new spell_power_of_the_twins(); diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/instance_trial_of_the_crusader.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/instance_trial_of_the_crusader.cpp index 98c1cf24f2b..7b0cd31bc67 100755 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/instance_trial_of_the_crusader.cpp +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/instance_trial_of_the_crusader.cpp @@ -16,13 +16,6 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -/* ScriptData -SDName: instance_trial_of_the_crusader -SD%Complete: 80% -SDComment: by /dev/rsa -SDCategory: Trial of the Crusader -EndScriptData */ - #include "ScriptMgr.h" #include "InstanceScript.h" #include "trial_of_the_crusader.h" @@ -37,82 +30,55 @@ class instance_trial_of_the_crusader : public InstanceMapScript { instance_trial_of_the_crusader_InstanceMapScript(Map* map) : InstanceScript(map) {} - uint32 EncounterStatus[MAX_ENCOUNTERS]; - uint32 TrialCounter; - uint32 EventStage; - uint32 EventTimer; - uint32 EventNPCId; - uint32 NorthrendBeasts; - std::string SaveDataBuffer; - bool NeedSave; - - uint64 BarrentGUID; - uint64 TirionGUID; - uint64 TirionFordringGUID; - uint64 FizzlebangGUID; - uint64 GarroshGUID; - uint64 VarianGUID; - - uint64 GormokGUID; - uint64 AcidmawGUID; - uint64 DreadscaleGUID; - uint64 IcehowlGUID; - uint64 JaraxxusGUID; - uint64 ChampionsControllerGUID; - uint64 DarkbaneGUID; - uint64 LightbaneGUID; - uint64 AnubarakGUID; - - uint64 CrusadersCacheGUID; - uint64 FloorGUID; - - uint64 TributeChestGUID; - - uint64 MainGateDoorGUID; - uint64 EastPortcullisGUID; - uint64 WebDoorGUID; - - // Achievement stuff - uint32 NotOneButTwoJormungarsTimer; - uint32 ResilienceWillFixItTimer; - uint8 SnoboldCount; - uint8 MistressOfPainCount; - bool TributeToImmortalityElegible; - void Initialize() { - for (uint8 i = 0; i < MAX_ENCOUNTERS; ++i) - EncounterStatus[i] = NOT_STARTED; - + SetBossNumber(MAX_ENCOUNTERS); TrialCounter = 50; EventStage = 0; - - TirionFordringGUID = 0; - - TributeChestGUID = 0; - - MainGateDoorGUID = 0; - EastPortcullisGUID = 0; - WebDoorGUID = 0; - NorthrendBeasts = NOT_STARTED; - EventTimer = 1000; - NotOneButTwoJormungarsTimer = 0; ResilienceWillFixItTimer = 0; SnoboldCount = 0; MistressOfPainCount = 0; TributeToImmortalityElegible = true; - NeedSave = false; + EventNPCId = 0; + + TirionFordringGUID = 0; + BarrentGUID = 0; + TirionGUID = 0; + FizzlebangGUID = 0; + GarroshGUID = 0; + VarianGUID = 0; + GormokGUID = 0; + AcidmawGUID = 0; + DreadscaleGUID = 0; + IcehowlGUID = 0; + JaraxxusGUID = 0; + ChampionsControllerGUID = 0; + DarkbaneGUID = 0; + LightbaneGUID = 0; + AnubarakGUID = 0; + + TributeChestGUID = 0; + MainGateDoorGUID = 0; + EastPortcullisGUID = 0; + WebDoorGUID = 0; + CrusadersCacheGUID = 0; + FloorGUID = 0; } bool IsEncounterInProgress() const { for (uint8 i = 0; i < MAX_ENCOUNTERS; ++i) - if (EncounterStatus[i] == IN_PROGRESS) + if (GetBossState(i) == IN_PROGRESS) return true; + + // Special state is set at Faction Champions after first champ dead, encounter is still in combat + if (GetBossState(BOSS_CRUSADERS) == SPECIAL) + return true; + return false; } @@ -123,12 +89,26 @@ class instance_trial_of_the_crusader : public InstanceMapScript player->SendUpdateWorldState(UPDATE_STATE_UI_SHOW, 1); player->SendUpdateWorldState(UPDATE_STATE_UI_COUNT, GetData(TYPE_COUNTER)); } + else + player->SendUpdateWorldState(UPDATE_STATE_UI_SHOW, 0); + + // make sure Anub'arak isnt missing and floor is destroyed after a crash + if (GetBossState(BOSS_LICH_KING) == DONE && TrialCounter && GetBossState(BOSS_ANUBARAK) != DONE) + { + Creature* anubArak = Unit::GetCreature(*player, GetData64(NPC_ANUBARAK)); + if (!anubArak) + anubArak = player->SummonCreature(NPC_ANUBARAK, AnubarakLoc[0].GetPositionX(), AnubarakLoc[0].GetPositionY(), AnubarakLoc[0].GetPositionZ(), 3, TEMPSUMMON_CORPSE_TIMED_DESPAWN, DESPAWN_TIME); + + if (GameObject* floor = GameObject::GetGameObject(*player, GetData64(GO_ARGENT_COLISEUM_FLOOR))) + floor->SetDestructibleState(GO_DESTRUCTIBLE_DAMAGED); + } } void OpenDoor(uint64 guid) { if (!guid) return; + if (GameObject* go = instance->GetGameObject(guid)) go->SetGoState(GO_STATE_ACTIVE_ALTERNATIVE); } @@ -137,6 +117,7 @@ class instance_trial_of_the_crusader : public InstanceMapScript { if (!guid) return; + if (GameObject* go = instance->GetGameObject(guid)) go->SetGoState(GO_STATE_READY); } @@ -147,6 +128,8 @@ class instance_trial_of_the_crusader : public InstanceMapScript { case NPC_BARRENT: BarrentGUID = creature->GetGUID(); + if (!TrialCounter) + creature->DespawnOrUnsummon(); break; case NPC_TIRION: TirionGUID = creature->GetGUID(); @@ -191,6 +174,8 @@ class instance_trial_of_the_crusader : public InstanceMapScript case NPC_ANUBARAK: AnubarakGUID = creature->GetGUID(); break; + default: + break; } } @@ -237,34 +222,41 @@ class instance_trial_of_the_crusader : public InstanceMapScript case GO_TRIBUTE_CHEST_25H_99: TributeChestGUID = go->GetGUID(); break; + default: + break; } } - void SetData(uint32 type, uint32 data) + bool SetBossState(uint32 type, EncounterState state) { + if (!InstanceScript::SetBossState(type, state)) + return false; + switch (type) { - case TYPE_JARAXXUS: + case BOSS_BEASTS: + break; + case BOSS_JARAXXUS: // Cleanup Icehowl if (Creature* icehowl = instance->GetCreature(IcehowlGUID)) icehowl->DespawnOrUnsummon(); - if (data == DONE) + if (state == DONE) EventStage = 2000; break; - case TYPE_CRUSADERS: + case BOSS_CRUSADERS: // Cleanup Jaraxxus if (Creature* jaraxxus = instance->GetCreature(JaraxxusGUID)) jaraxxus->DespawnOrUnsummon(); if (Creature* fizzlebang = instance->GetCreature(FizzlebangGUID)) fizzlebang->DespawnOrUnsummon(); - switch (data) + switch (state) { case IN_PROGRESS: ResilienceWillFixItTimer = 0; break; case SPECIAL: //Means the first blood ResilienceWillFixItTimer = 60*IN_MILLISECONDS; - data = IN_PROGRESS; + state = IN_PROGRESS; break; case DONE: DoUpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET, SPELL_DEFEAT_FACTION_CHAMPIONS); @@ -273,21 +265,23 @@ class instance_trial_of_the_crusader : public InstanceMapScript DoRespawnGameObject(CrusadersCacheGUID, 7*DAY); EventStage = 3100; break; + default: + break; } break; - case TYPE_VALKIRIES: + case BOSS_VALKIRIES: // Cleanup chest if (GameObject* cache = instance->GetGameObject(CrusadersCacheGUID)) cache->Delete(); - switch (data) + switch (state) { case FAIL: - if (EncounterStatus[TYPE_VALKIRIES] == NOT_STARTED) - data = NOT_STARTED; + if (GetBossState(BOSS_VALKIRIES) == NOT_STARTED) + state = NOT_STARTED; break; case SPECIAL: - if (EncounterStatus[TYPE_VALKIRIES] == SPECIAL) - data = DONE; + if (GetBossState(BOSS_VALKIRIES) == SPECIAL) + state = DONE; break; case DONE: if (instance->GetPlayers().getFirst()->getSource()->GetTeam() == ALLIANCE) @@ -295,50 +289,122 @@ class instance_trial_of_the_crusader : public InstanceMapScript else EventStage = 4030; break; + default: + break; } break; - case TYPE_ANUBARAK: - switch (data) + case BOSS_LICH_KING: + break; + case BOSS_ANUBARAK: + switch (state) { case DONE: + { EventStage = 6000; - break; - case SPECIAL: uint32 tributeChest = 0; if (instance->GetSpawnMode() == RAID_DIFFICULTY_10MAN_HEROIC) { if (TrialCounter >= 50) tributeChest = GO_TRIBUTE_CHEST_10H_99; else + { if (TrialCounter >= 45) tributeChest = GO_TRIBUTE_CHEST_10H_50; else + { if (TrialCounter >= 25) tributeChest = GO_TRIBUTE_CHEST_10H_45; else tributeChest = GO_TRIBUTE_CHEST_10H_25; + } + } } else if (instance->GetSpawnMode() == RAID_DIFFICULTY_25MAN_HEROIC) { if (TrialCounter >= 50) tributeChest = GO_TRIBUTE_CHEST_25H_99; else + { if (TrialCounter >= 45) tributeChest = GO_TRIBUTE_CHEST_25H_50; else + { if (TrialCounter >= 25) tributeChest = GO_TRIBUTE_CHEST_25H_45; else tributeChest = GO_TRIBUTE_CHEST_25H_25; + } + } } + if (tributeChest) if (Creature* tirion = instance->GetCreature(TirionGUID)) - // need proper location.this one is guessed based on videos - if (GameObject* chest = tirion->SummonGameObject(tributeChest, 643.814f, 136.027f, 141.295f, 0, 0, 0, 0, 0, 90000000)) + if (GameObject* chest = tirion->SummonGameObject(tributeChest, 805.62f, 134.87f, 142.16f, 3.27f, 0, 0, 0, 0, WEEK)) chest->SetRespawnTime(chest->GetRespawnDelay()); break; + } + default: + break; } break; + default: + break; + } + + if (IsEncounterInProgress()) + { + CloseDoor(GetData64(GO_EAST_PORTCULLIS)); + CloseDoor(GetData64(GO_WEB_DOOR)); + } + else + { + OpenDoor(GetData64(GO_EAST_PORTCULLIS)); + OpenDoor(GetData64(GO_WEB_DOOR)); + } + + if (type < MAX_ENCOUNTERS) + { + sLog->outInfo(LOG_FILTER_TSCR, "[ToCr] BossState(type %u) %u = state %u;", type, GetBossState(type), state); + if (state == FAIL) + { + if (instance->IsHeroic()) + { + --TrialCounter; + // decrease attempt counter at wipe + Map::PlayerList const &PlayerList = instance->GetPlayers(); + for (Map::PlayerList::const_iterator itr = PlayerList.begin(); itr != PlayerList.end(); ++itr) + if (Player* player = itr->getSource()) + player->SendUpdateWorldState(UPDATE_STATE_UI_COUNT, TrialCounter); + + // if theres no more attemps allowed + if (!TrialCounter) + { + if (Unit* announcer = instance->GetCreature(GetData64(NPC_BARRENT))) + announcer->ToCreature()->DespawnOrUnsummon(); + + if (Creature* anubArak = instance->GetCreature(GetData64(NPC_ANUBARAK))) + anubArak->DespawnOrUnsummon(); + } + } + NeedSave = true; + EventStage = (type == BOSS_BEASTS ? 666 : 0); + state = NOT_STARTED; + } + + if (state == DONE || NeedSave) + { + if (Unit* announcer = instance->GetCreature(GetData64(NPC_BARRENT))) + announcer->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + Save(); + } + } + return true; + } + + void SetData(uint32 type, uint32 data) + { + switch (type) + { case TYPE_COUNTER: TrialCounter = data; data = DONE; @@ -358,7 +424,6 @@ class instance_trial_of_the_crusader : public InstanceMapScript case GORMOK_DONE: EventStage = 200; SetData(TYPE_NORTHREND_BEASTS, IN_PROGRESS); - SetData(TYPE_BEASTS, IN_PROGRESS); break; case SNAKES_IN_PROGRESS: NotOneButTwoJormungarsTimer = 0; @@ -371,15 +436,16 @@ class instance_trial_of_the_crusader : public InstanceMapScript DoUpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET, SPELL_WORMS_KILLED_IN_10_SECONDS); EventStage = 300; SetData(TYPE_NORTHREND_BEASTS, IN_PROGRESS); - SetData(TYPE_BEASTS, IN_PROGRESS); break; case ICEHOWL_DONE: EventStage = 400; SetData(TYPE_NORTHREND_BEASTS, DONE); - SetData(TYPE_BEASTS, DONE); + SetBossState(BOSS_BEASTS, DONE); break; case FAIL: - SetData(TYPE_BEASTS, FAIL); + SetBossState(BOSS_BEASTS, FAIL); + break; + default: break; } break; @@ -399,37 +465,8 @@ class instance_trial_of_the_crusader : public InstanceMapScript case DATA_TRIBUTE_TO_IMMORTALITY_ELEGIBLE: TributeToImmortalityElegible = false; break; - } - if (IsEncounterInProgress()) - { - CloseDoor(GetData64(GO_EAST_PORTCULLIS)); - CloseDoor(GetData64(GO_WEB_DOOR)); - } - else - { - OpenDoor(GetData64(GO_EAST_PORTCULLIS)); - OpenDoor(GetData64(GO_WEB_DOOR)); - } - - if (type < MAX_ENCOUNTERS) - { - sLog->outInfo(LOG_FILTER_TSCR, "[ToCr] EncounterStatus[type %u] %u = data %u;", type, EncounterStatus[type], data); - if (data == FAIL) - { - --TrialCounter; - NeedSave = true; - EventStage = (type == TYPE_BEASTS ? 666 : 0); - data = NOT_STARTED; - } - - EncounterStatus[type] = data; - - if (data == DONE || NeedSave == true) - { - if (Unit* announcer = instance->GetCreature(GetData64(NPC_BARRENT))) - announcer->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); - Save(); - } + default: + break; } } @@ -488,18 +525,6 @@ class instance_trial_of_the_crusader : public InstanceMapScript { switch (type) { - case TYPE_BEASTS: - return EncounterStatus[TYPE_BEASTS]; - case TYPE_JARAXXUS: - return EncounterStatus[TYPE_JARAXXUS]; - case TYPE_CRUSADERS: - return EncounterStatus[TYPE_CRUSADERS]; - case TYPE_VALKIRIES: - return EncounterStatus[TYPE_VALKIRIES]; - case TYPE_LICH_KING: - return EncounterStatus[TYPE_LICH_KING]; - case TYPE_ANUBARAK: - return EncounterStatus[TYPE_ANUBARAK]; case TYPE_COUNTER: return TrialCounter; case TYPE_EVENT: @@ -613,7 +638,7 @@ class instance_trial_of_the_crusader : public InstanceMapScript NotOneButTwoJormungarsTimer -= diff; } - if (GetData(TYPE_CRUSADERS) == IN_PROGRESS && ResilienceWillFixItTimer) + if (GetBossState(BOSS_CRUSADERS) == SPECIAL && ResilienceWillFixItTimer) { if (ResilienceWillFixItTimer <= diff) ResilienceWillFixItTimer = 0; @@ -629,7 +654,7 @@ class instance_trial_of_the_crusader : public InstanceMapScript std::ostringstream saveStream; for (uint8 i = 0; i < MAX_ENCOUNTERS; ++i) - saveStream << EncounterStatus[i] << ' '; + saveStream << GetBossState(i) << ' '; saveStream << TrialCounter; SaveDataBuffer = saveStream.str(); @@ -658,10 +683,11 @@ class instance_trial_of_the_crusader : public InstanceMapScript for (uint8 i = 0; i < MAX_ENCOUNTERS; ++i) { - loadStream >> EncounterStatus[i]; - - if (EncounterStatus[i] == IN_PROGRESS) - EncounterStatus[i] = NOT_STARTED; + uint32 tmpState; + loadStream >> tmpState; + if (tmpState == IN_PROGRESS || tmpState > SPECIAL) + tmpState = NOT_STARTED; + SetBossState(i, EncounterState(tmpState)); } loadStream >> TrialCounter; @@ -700,10 +726,52 @@ class instance_trial_of_the_crusader : public InstanceMapScript return TrialCounter == 50 && TributeToImmortalityElegible; case A_TRIBUTE_TO_DEDICATED_INSANITY: return false/*uiGrandCrusaderAttemptsLeft == 50 && !bHasAtAnyStagePlayerEquippedTooGoodItem*/; + default: + break; } return false; } + + protected: + uint32 TrialCounter; + uint32 EventStage; + uint32 EventTimer; + uint32 EventNPCId; + uint32 NorthrendBeasts; + bool NeedSave; + std::string SaveDataBuffer; + + uint64 BarrentGUID; + uint64 TirionGUID; + uint64 TirionFordringGUID; + uint64 FizzlebangGUID; + uint64 GarroshGUID; + uint64 VarianGUID; + + uint64 GormokGUID; + uint64 AcidmawGUID; + uint64 DreadscaleGUID; + uint64 IcehowlGUID; + uint64 JaraxxusGUID; + uint64 ChampionsControllerGUID; + uint64 DarkbaneGUID; + uint64 LightbaneGUID; + uint64 AnubarakGUID; + + uint64 CrusadersCacheGUID; + uint64 FloorGUID; + uint64 TributeChestGUID; + uint64 MainGateDoorGUID; + uint64 EastPortcullisGUID; + uint64 WebDoorGUID; + + // Achievement stuff + uint32 NotOneButTwoJormungarsTimer; + uint32 ResilienceWillFixItTimer; + uint8 SnoboldCount; + uint8 MistressOfPainCount; + bool TributeToImmortalityElegible; }; InstanceScript* GetInstanceScript(InstanceMap* map) const diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/trial_of_the_crusader.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/trial_of_the_crusader.cpp index 2494fec87a9..b4d35afa8fb 100755 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/trial_of_the_crusader.cpp +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/trial_of_the_crusader.cpp @@ -16,13 +16,6 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -/* ScriptData -SDName: Trial Of the crusader -SD%Complete: ??% -SDComment: event script based on /dev/rsa -SDCategory: trial_of_the_crusader -EndScriptData */ - //Known Bugs: // - Need better implementation of Gossip and correct gossip text and option @@ -85,7 +78,7 @@ enum eYells // Highlord Tirion Fordring - 36095 SAY_STAGE_4_06 = 0, - SAY_STAGE_4_07 = 1, + SAY_STAGE_4_07 = 1 }; struct _Messages @@ -98,23 +91,22 @@ struct _Messages static _Messages _GossipMessage[]= { - {MSG_BEASTS, GOSSIP_ACTION_INFO_DEF+1, false, TYPE_BEASTS}, - {MSG_JARAXXUS, GOSSIP_ACTION_INFO_DEF+2, false, TYPE_JARAXXUS}, - {MSG_CRUSADERS, GOSSIP_ACTION_INFO_DEF+3, false, TYPE_CRUSADERS}, - {MSG_VALKIRIES, GOSSIP_ACTION_INFO_DEF+4, false, TYPE_VALKIRIES}, - {MSG_LICH_KING, GOSSIP_ACTION_INFO_DEF+5, false, TYPE_ANUBARAK}, - {MSG_ANUBARAK, GOSSIP_ACTION_INFO_DEF+6, true, TYPE_ANUBARAK} + {MSG_BEASTS, GOSSIP_ACTION_INFO_DEF + 1, false, BOSS_BEASTS}, + {MSG_JARAXXUS, GOSSIP_ACTION_INFO_DEF + 2, false, BOSS_JARAXXUS}, + {MSG_CRUSADERS, GOSSIP_ACTION_INFO_DEF + 3, false, BOSS_CRUSADERS}, + {MSG_VALKIRIES, GOSSIP_ACTION_INFO_DEF + 4, false, BOSS_VALKIRIES}, + {MSG_LICH_KING, GOSSIP_ACTION_INFO_DEF + 5, false, BOSS_ANUBARAK}, + {MSG_ANUBARAK, GOSSIP_ACTION_INFO_DEF + 6, true, BOSS_ANUBARAK} }; enum { - NUM_MESSAGES = 6, + NUM_MESSAGES = 6 }; class npc_announcer_toc10 : public CreatureScript { public: - npc_announcer_toc10() : CreatureScript("npc_announcer_toc10") { } struct npc_announcer_toc10AI : public ScriptedAI @@ -137,20 +129,20 @@ class npc_announcer_toc10 : public CreatureScript bool OnGossipHello(Player* player, Creature* creature) { - InstanceScript* instanceScript = creature->GetInstanceScript(); - if (!instanceScript) + InstanceScript* instance = creature->GetInstanceScript(); + if (!instance) return true; char const* _message = "We are ready!"; - if (player->isInCombat() || instanceScript->IsEncounterInProgress() || instanceScript->GetData(TYPE_EVENT)) + if (player->isInCombat() || instance->IsEncounterInProgress() || instance->GetData(TYPE_EVENT)) return true; uint8 i = 0; for (; i < NUM_MESSAGES; ++i) { - if ((!_GossipMessage[i].state && instanceScript->GetData(_GossipMessage[i].encounter) != DONE) - || (_GossipMessage[i].state && instanceScript->GetData(_GossipMessage[i].encounter) == DONE)) + if ((!_GossipMessage[i].state && instance->GetBossState(_GossipMessage[i].encounter) != DONE) + || (_GossipMessage[i].state && instance->GetBossState(_GossipMessage[i].encounter) == DONE)) { player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, _message, GOSSIP_SENDER_MAIN, _GossipMessage[i].id); break; @@ -161,75 +153,65 @@ class npc_announcer_toc10 : public CreatureScript return true; } - bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) + bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 /*action*/) { player->PlayerTalkClass->ClearMenus(); player->CLOSE_GOSSIP_MENU(); - InstanceScript* instanceScript = creature->GetInstanceScript(); - if (!instanceScript) + InstanceScript* instance = creature->GetInstanceScript(); + if (!instance) return true; - switch (action) + if (instance->GetBossState(BOSS_BEASTS) != DONE) { - case GOSSIP_ACTION_INFO_DEF+1: - if (instanceScript->GetData(TYPE_BEASTS) != DONE) - { - instanceScript->SetData(TYPE_EVENT, 110); - instanceScript->SetData(TYPE_NORTHREND_BEASTS, NOT_STARTED); - instanceScript->SetData(TYPE_BEASTS, NOT_STARTED); - } - break; - case GOSSIP_ACTION_INFO_DEF+2: - if (Creature* jaraxxus = Unit::GetCreature(*player, instanceScript->GetData64(NPC_JARAXXUS))) - { - jaraxxus->RemoveAurasDueToSpell(SPELL_JARAXXUS_CHAINS); - jaraxxus->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - jaraxxus->SetReactState(REACT_AGGRESSIVE); - jaraxxus->SetInCombatWithZone(); - } - else if (instanceScript->GetData(TYPE_JARAXXUS) != DONE) - { - instanceScript->SetData(TYPE_EVENT, 1010); - instanceScript->SetData(TYPE_JARAXXUS, NOT_STARTED); - } - break; - case GOSSIP_ACTION_INFO_DEF+3: - if (instanceScript->GetData(TYPE_CRUSADERS) != DONE) - { - if (player->GetTeam() == ALLIANCE) - instanceScript->SetData(TYPE_EVENT, 3000); - else - instanceScript->SetData(TYPE_EVENT, 3001); - instanceScript->SetData(TYPE_CRUSADERS, NOT_STARTED); - } - break; - case GOSSIP_ACTION_INFO_DEF+4: - if (instanceScript->GetData(TYPE_VALKIRIES) != DONE) - { - instanceScript->SetData(TYPE_EVENT, 4000); - instanceScript->SetData(TYPE_VALKIRIES, NOT_STARTED); - } - break; - case GOSSIP_ACTION_INFO_DEF+5: + instance->SetData(TYPE_EVENT, 110); + instance->SetData(TYPE_NORTHREND_BEASTS, NOT_STARTED); + instance->SetBossState(BOSS_BEASTS, NOT_STARTED); + } + else if (instance->GetBossState(BOSS_JARAXXUS) != DONE) + { + // if Jaraxxus is spawned, but the raid wiped + if (Creature* jaraxxus = Unit::GetCreature(*player, instance->GetData64(NPC_JARAXXUS))) { - if (instanceScript->GetData(TYPE_LICH_KING) != DONE && !player->isGameMaster()) - return true; - - if (GameObject* floor = GameObject::GetGameObject(*player, instanceScript->GetData64(GO_ARGENT_COLISEUM_FLOOR))) - floor->SetDestructibleState(GO_DESTRUCTIBLE_DAMAGED); + jaraxxus->RemoveAurasDueToSpell(SPELL_JARAXXUS_CHAINS); + jaraxxus->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + jaraxxus->SetReactState(REACT_DEFENSIVE); + jaraxxus->SetInCombatWithZone(); + } + else + { + instance->SetData(TYPE_EVENT, 1010); + instance->SetBossState(BOSS_JARAXXUS, NOT_STARTED); + } + } + else if (instance->GetBossState(BOSS_CRUSADERS) != DONE) + { + if (player->GetTeam() == ALLIANCE) + instance->SetData(TYPE_EVENT, 3000); + else + instance->SetData(TYPE_EVENT, 3001); + instance->SetBossState(BOSS_CRUSADERS, NOT_STARTED); + } + else if (instance->GetBossState(BOSS_VALKIRIES) != DONE) + { + instance->SetData(TYPE_EVENT, 4000); + instance->SetBossState(BOSS_VALKIRIES, NOT_STARTED); + } + else if (instance->GetBossState(BOSS_LICH_KING) != DONE) + { + if (GameObject* floor = GameObject::GetGameObject(*player, instance->GetData64(GO_ARGENT_COLISEUM_FLOOR))) + floor->SetDestructibleState(GO_DESTRUCTIBLE_DAMAGED); - creature->CastSpell(creature, 69016, false); + creature->CastSpell(creature, SPELL_CORPSE_TELEPORT, false); + creature->CastSpell(creature, SPELL_DESTROY_FLOOR_KNOCKUP, false); - Creature* anubArak = Unit::GetCreature(*creature, instanceScript->GetData64(NPC_ANUBARAK)); - if (!anubArak || !anubArak->isAlive()) - anubArak = creature->SummonCreature(NPC_ANUBARAK, AnubarakLoc[0].GetPositionX(), AnubarakLoc[0].GetPositionY(), AnubarakLoc[0].GetPositionZ(), 3, TEMPSUMMON_CORPSE_TIMED_DESPAWN, DESPAWN_TIME); + Creature* anubArak = Unit::GetCreature(*creature, instance->GetData64(NPC_ANUBARAK)); + if (!anubArak || !anubArak->isAlive()) + anubArak = creature->SummonCreature(NPC_ANUBARAK, AnubarakLoc[0].GetPositionX(), AnubarakLoc[0].GetPositionY(), AnubarakLoc[0].GetPositionZ(), 3, TEMPSUMMON_CORPSE_TIMED_DESPAWN, DESPAWN_TIME); - instanceScript->SetData(TYPE_ANUBARAK, NOT_STARTED); + instance->SetBossState(BOSS_ANUBARAK, NOT_STARTED); - if (creature->IsVisible()) - creature->SetVisible(false); - break; - } + if (creature->IsVisible()) + creature->SetVisible(false); } creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); return true; @@ -244,112 +226,130 @@ class npc_announcer_toc10 : public CreatureScript class boss_lich_king_toc : public CreatureScript { public: - boss_lich_king_toc() : CreatureScript("boss_lich_king_toc") { } struct boss_lich_king_tocAI : public ScriptedAI { boss_lich_king_tocAI(Creature* creature) : ScriptedAI(creature) { - instance = creature->GetInstanceScript(); + _instance = creature->GetInstanceScript(); } - InstanceScript* instance; - uint32 m_uiUpdateTimer; - void Reset() { - m_uiUpdateTimer = 0; + _updateTimer = 0; me->SetReactState(REACT_PASSIVE); - if (Creature* summoned = me->SummonCreature(NPC_TRIGGER, ToCCommonLoc[2].GetPositionX(), ToCCommonLoc[2].GetPositionY(), ToCCommonLoc[2].GetPositionZ(), 5, TEMPSUMMON_TIMED_DESPAWN, 60000)) + if (Creature* summoned = me->SummonCreature(NPC_TRIGGER, ToCCommonLoc[2].GetPositionX(), ToCCommonLoc[2].GetPositionY(), ToCCommonLoc[2].GetPositionZ(), 5, TEMPSUMMON_TIMED_DESPAWN, 1*MINUTE*IN_MILLISECONDS)) { summoned->CastSpell(summoned, 51807, false); - summoned->SetDisplayId(11686); + summoned->SetDisplayId(summoned->GetCreatureTemplate()->Modelid2); } - if (instance) instance->SetData(TYPE_LICH_KING, IN_PROGRESS); + if (_instance) + _instance->SetBossState(BOSS_LICH_KING, IN_PROGRESS); me->SetWalk(true); } void MovementInform(uint32 uiType, uint32 uiId) { - if (uiType != POINT_MOTION_TYPE || !instance) + if (uiType != POINT_MOTION_TYPE || !_instance) return; + switch (uiId) { case 0: - instance->SetData(TYPE_EVENT, 5030); + _instance->SetData(TYPE_EVENT, 5030); break; case 1: - instance->SetData(TYPE_EVENT, 5050); + _instance->SetData(TYPE_EVENT, 5050); + break; + default: break; } } void UpdateAI(const uint32 uiDiff) { - if (!instance) + if (!_instance) return; - if (instance->GetData(TYPE_EVENT_NPC) != NPC_LICH_KING_1) + if (_instance->GetData(TYPE_EVENT_NPC) != NPC_LICH_KING_1) return; - m_uiUpdateTimer = instance->GetData(TYPE_EVENT_TIMER); - if (m_uiUpdateTimer <= uiDiff) + _updateTimer = _instance->GetData(TYPE_EVENT_TIMER); + if (_updateTimer <= uiDiff) { - switch (instance->GetData(TYPE_EVENT)) + switch (_instance->GetData(TYPE_EVENT)) { case 5010: Talk(SAY_STAGE_4_02); - m_uiUpdateTimer = 3000; + _updateTimer = 3*IN_MILLISECONDS; me->GetMotionMaster()->MovePoint(0, LichKingLoc[0]); - instance->SetData(TYPE_EVENT, 5020); + _instance->SetData(TYPE_EVENT, 5020); break; case 5030: Talk(SAY_STAGE_4_04); me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_TALK); - m_uiUpdateTimer = 10000; - instance->SetData(TYPE_EVENT, 5040); + _updateTimer = 10*IN_MILLISECONDS; + _instance->SetData(TYPE_EVENT, 5040); break; case 5040: me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE); me->GetMotionMaster()->MovePoint(1, LichKingLoc[1]); - m_uiUpdateTimer = 1000; - instance->SetData(TYPE_EVENT, 0); + _updateTimer = 1*IN_MILLISECONDS; + _instance->SetData(TYPE_EVENT, 0); break; case 5050: me->HandleEmoteCommand(EMOTE_ONESHOT_EXCLAMATION); - m_uiUpdateTimer = 3000; - instance->SetData(TYPE_EVENT, 5060); + _updateTimer = 3*IN_MILLISECONDS; + _instance->SetData(TYPE_EVENT, 5060); break; case 5060: Talk(SAY_STAGE_4_05); me->HandleEmoteCommand(EMOTE_ONESHOT_KNEEL); - m_uiUpdateTimer = 2500; - instance->SetData(TYPE_EVENT, 5070); + _updateTimer = 2.5*IN_MILLISECONDS; + _instance->SetData(TYPE_EVENT, 5070); break; case 5070: me->CastSpell(me, 68198, false); - m_uiUpdateTimer = 1500; - instance->SetData(TYPE_EVENT, 5080); + _updateTimer = 1.5*IN_MILLISECONDS; + _instance->SetData(TYPE_EVENT, 5080); break; case 5080: - if (GameObject* go = instance->instance->GetGameObject(instance->GetData64(GO_ARGENT_COLISEUM_FLOOR))) - go->SetDestructibleState(GO_DESTRUCTIBLE_DAMAGED); - me->CastSpell(me, 69016, false); - instance->SetData(TYPE_LICH_KING, DONE); - Creature* temp = Unit::GetCreature(*me, instance->GetData64(NPC_ANUBARAK)); - if (!temp || !temp->isAlive()) - temp = me->SummonCreature(NPC_ANUBARAK, AnubarakLoc[0].GetPositionX(), AnubarakLoc[0].GetPositionY(), AnubarakLoc[0].GetPositionZ(), 3, TEMPSUMMON_CORPSE_TIMED_DESPAWN, DESPAWN_TIME); - - instance->SetData(TYPE_EVENT, 0); + if (GameObject* go = _instance->instance->GetGameObject(_instance->GetData64(GO_ARGENT_COLISEUM_FLOOR))) + { + go->SetDisplayId(DISPLAYID_DESTROYED_FLOOR); + go->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_DAMAGED | GO_FLAG_NODESPAWN); + go->SetGoState(GO_STATE_ACTIVE); + } + + me->CastSpell(me, SPELL_CORPSE_TELEPORT, false); + me->CastSpell(me, SPELL_DESTROY_FLOOR_KNOCKUP, false); + + if (_instance) + { + _instance->SetBossState(BOSS_LICH_KING, DONE); + Creature* temp = Unit::GetCreature(*me, _instance->GetData64(NPC_ANUBARAK)); + if (!temp || !temp->isAlive()) + temp = me->SummonCreature(NPC_ANUBARAK, AnubarakLoc[0].GetPositionX(), AnubarakLoc[0].GetPositionY(), AnubarakLoc[0].GetPositionZ(), 3, TEMPSUMMON_CORPSE_TIMED_DESPAWN, DESPAWN_TIME); + + _instance->SetData(TYPE_EVENT, 0); + } me->DespawnOrUnsummon(); - m_uiUpdateTimer = 20000; + _updateTimer = 20*IN_MILLISECONDS; + break; + default: break; } - } else m_uiUpdateTimer -= uiDiff; + } + else + _updateTimer -= uiDiff; - instance->SetData(TYPE_EVENT_TIMER, m_uiUpdateTimer); + _instance->SetData(TYPE_EVENT_TIMER, _updateTimer); } + + private: + InstanceScript* _instance; + uint32 _updateTimer; }; CreatureAI* GetAI(Creature* creature) const @@ -361,27 +361,20 @@ class boss_lich_king_toc : public CreatureScript class npc_fizzlebang_toc : public CreatureScript { public: - npc_fizzlebang_toc() : CreatureScript("npc_fizzlebang_toc") { } struct npc_fizzlebang_tocAI : public ScriptedAI { - npc_fizzlebang_tocAI(Creature* creature) : ScriptedAI(creature), Summons(me) + npc_fizzlebang_tocAI(Creature* creature) : ScriptedAI(creature), _summons(me) { - instance = me->GetInstanceScript(); + _instance = me->GetInstanceScript(); } - InstanceScript* instance; - SummonList Summons; - uint32 m_uiUpdateTimer; - uint64 m_uiPortalGUID; - uint64 m_uiTriggerGUID; - void JustDied(Unit* killer) { Talk(SAY_STAGE_1_06, killer->GetGUID()); - instance->SetData(TYPE_EVENT, 1180); - if (Creature* temp = Unit::GetCreature(*me, instance->GetData64(NPC_JARAXXUS))) + _instance->SetData(TYPE_EVENT, 1180); + if (Creature* temp = Unit::GetCreature(*me, _instance->GetData64(NPC_JARAXXUS))) { temp->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); temp->SetReactState(REACT_AGGRESSIVE); @@ -392,7 +385,7 @@ class npc_fizzlebang_toc : public CreatureScript void Reset() { me->SetWalk(true); - m_uiPortalGUID = 0; + _portalGUID = 0; me->GetMotionMaster()->MovePoint(1, ToCCommonLoc[10].GetPositionX(), ToCCommonLoc[10].GetPositionY()-60, ToCCommonLoc[10].GetPositionZ()); } @@ -405,42 +398,44 @@ class npc_fizzlebang_toc : public CreatureScript { case 1: me->SetWalk(false); - if (instance) + if (_instance) { - instance->DoUseDoorOrButton(instance->GetData64(GO_MAIN_GATE_DOOR)); - instance->SetData(TYPE_EVENT, 1120); - instance->SetData(TYPE_EVENT_TIMER, 1000); + _instance->DoUseDoorOrButton(_instance->GetData64(GO_MAIN_GATE_DOOR)); + _instance->SetData(TYPE_EVENT, 1120); + _instance->SetData(TYPE_EVENT_TIMER, 1*IN_MILLISECONDS); } break; + default: + break; } } void JustSummoned(Creature* summoned) { - Summons.Summon(summoned); + _summons.Summon(summoned); } void UpdateAI(const uint32 uiDiff) { - if (!instance) + if (!_instance) return; - if (instance->GetData(TYPE_EVENT_NPC) != NPC_FIZZLEBANG) + if (_instance->GetData(TYPE_EVENT_NPC) != NPC_FIZZLEBANG) return; - m_uiUpdateTimer = instance->GetData(TYPE_EVENT_TIMER); - if (m_uiUpdateTimer <= uiDiff) + _updateTimer = _instance->GetData(TYPE_EVENT_TIMER); + if (_updateTimer <= uiDiff) { - switch (instance->GetData(TYPE_EVENT)) + switch (_instance->GetData(TYPE_EVENT)) { case 1110: - instance->SetData(TYPE_EVENT, 1120); - m_uiUpdateTimer = 4000; + _instance->SetData(TYPE_EVENT, 1120); + _updateTimer = 4*IN_MILLISECONDS; break; case 1120: Talk(SAY_STAGE_1_02); - instance->SetData(TYPE_EVENT, 1130); - m_uiUpdateTimer = 12000; + _instance->SetData(TYPE_EVENT, 1130); + _updateTimer = 12*IN_MILLISECONDS; break; case 1130: me->GetMotionMaster()->MovementExpired(); @@ -448,18 +443,18 @@ class npc_fizzlebang_toc : public CreatureScript me->HandleEmoteCommand(EMOTE_ONESHOT_SPELL_CAST_OMNI); if (Unit* pTrigger = me->SummonCreature(NPC_TRIGGER, ToCCommonLoc[1].GetPositionX(), ToCCommonLoc[1].GetPositionY(), ToCCommonLoc[1].GetPositionZ(), 4.69494f, TEMPSUMMON_MANUAL_DESPAWN)) { - m_uiTriggerGUID = pTrigger->GetGUID(); + _triggerGUID = pTrigger->GetGUID(); pTrigger->SetObjectScale(2.0f); - pTrigger->SetDisplayId(22862); + pTrigger->SetDisplayId(pTrigger->ToCreature()->GetCreatureTemplate()->Modelid1); pTrigger->CastSpell(pTrigger, SPELL_WILFRED_PORTAL, false); } - instance->SetData(TYPE_EVENT, 1132); - m_uiUpdateTimer = 4000; + _instance->SetData(TYPE_EVENT, 1132); + _updateTimer = 4*IN_MILLISECONDS; break; case 1132: me->GetMotionMaster()->MovementExpired(); - instance->SetData(TYPE_EVENT, 1134); - m_uiUpdateTimer = 4000; + _instance->SetData(TYPE_EVENT, 1134); + _updateTimer = 4*IN_MILLISECONDS; break; case 1134: me->HandleEmoteCommand(EMOTE_ONESHOT_SPELL_CAST_OMNI); @@ -468,14 +463,14 @@ class npc_fizzlebang_toc : public CreatureScript pPortal->SetReactState(REACT_PASSIVE); pPortal->SetObjectScale(2.0f); pPortal->CastSpell(pPortal, SPELL_WILFRED_PORTAL, false); - m_uiPortalGUID = pPortal->GetGUID(); + _portalGUID = pPortal->GetGUID(); } - m_uiUpdateTimer = 4000; - instance->SetData(TYPE_EVENT, 1135); + _updateTimer = 4*IN_MILLISECONDS; + _instance->SetData(TYPE_EVENT, 1135); break; case 1135: - instance->SetData(TYPE_EVENT, 1140); - m_uiUpdateTimer = 3000; + _instance->SetData(TYPE_EVENT, 1140); + _updateTimer = 3*IN_MILLISECONDS; break; case 1140: Talk(SAY_STAGE_1_04); @@ -485,27 +480,27 @@ class npc_fizzlebang_toc : public CreatureScript temp->SetReactState(REACT_PASSIVE); temp->GetMotionMaster()->MovePoint(0, ToCCommonLoc[1].GetPositionX(), ToCCommonLoc[1].GetPositionY()-10, ToCCommonLoc[1].GetPositionZ()); } - instance->SetData(TYPE_EVENT, 1142); - m_uiUpdateTimer = 5000; + _instance->SetData(TYPE_EVENT, 1142); + _updateTimer = 5*IN_MILLISECONDS; break; case 1142: - if (Creature* temp = Unit::GetCreature(*me, instance->GetData64(NPC_JARAXXUS))) + if (Creature* temp = Unit::GetCreature(*me, _instance->GetData64(NPC_JARAXXUS))) temp->SetTarget(me->GetGUID()); - if (Creature* pTrigger = Unit::GetCreature(*me, m_uiTriggerGUID)) + if (Creature* pTrigger = Unit::GetCreature(*me, _triggerGUID)) pTrigger->DespawnOrUnsummon(); - if (Creature* pPortal = Unit::GetCreature(*me, m_uiPortalGUID)) + if (Creature* pPortal = Unit::GetCreature(*me, _portalGUID)) pPortal->DespawnOrUnsummon(); - instance->SetData(TYPE_EVENT, 1144); - m_uiUpdateTimer = 10000; + _instance->SetData(TYPE_EVENT, 1144); + _updateTimer = 10*IN_MILLISECONDS; break; case 1144: - if (Creature* temp = Unit::GetCreature(*me, instance->GetData64(NPC_JARAXXUS))) + if (Creature* temp = Unit::GetCreature(*me, _instance->GetData64(NPC_JARAXXUS))) temp->AI()->Talk(SAY_STAGE_1_05); - instance->SetData(TYPE_EVENT, 1150); - m_uiUpdateTimer = 5000; + _instance->SetData(TYPE_EVENT, 1150); + _updateTimer = 5*IN_MILLISECONDS; break; case 1150: - if (Creature* temp = Unit::GetCreature(*me, instance->GetData64(NPC_JARAXXUS))) + if (Creature* temp = Unit::GetCreature(*me, _instance->GetData64(NPC_JARAXXUS))) { //1-shot Fizzlebang temp->CastSpell(me, 67888, false); @@ -513,13 +508,22 @@ class npc_fizzlebang_toc : public CreatureScript temp->AddThreat(me, 1000.0f); temp->AI()->AttackStart(me); } - instance->SetData(TYPE_EVENT, 1160); - m_uiUpdateTimer = 3000; + _instance->SetData(TYPE_EVENT, 1160); + _updateTimer = 3*IN_MILLISECONDS; break; } - } else m_uiUpdateTimer -= uiDiff; - instance->SetData(TYPE_EVENT_TIMER, m_uiUpdateTimer); + } + else + _updateTimer -= uiDiff; + _instance->SetData(TYPE_EVENT_TIMER, _updateTimer); } + + private: + InstanceScript* _instance; + SummonList _summons; + uint32 _updateTimer; + uint64 _portalGUID; + uint64 _triggerGUID; }; CreatureAI* GetAI(Creature* creature) const @@ -531,53 +535,49 @@ class npc_fizzlebang_toc : public CreatureScript class npc_tirion_toc : public CreatureScript { public: - npc_tirion_toc() : CreatureScript("npc_tirion_toc") { } struct npc_tirion_tocAI : public ScriptedAI { npc_tirion_tocAI(Creature* creature) : ScriptedAI(creature) { - instance = me->GetInstanceScript(); + _instance = me->GetInstanceScript(); } - InstanceScript* instance; - uint32 m_uiUpdateTimer; - void Reset() {} void AttackStart(Unit* /*who*/) {} void UpdateAI(const uint32 uiDiff) { - if (!instance) + if (!_instance) return; - if (instance->GetData(TYPE_EVENT_NPC) != NPC_TIRION) + if (_instance->GetData(TYPE_EVENT_NPC) != NPC_TIRION) return; - m_uiUpdateTimer = instance->GetData(TYPE_EVENT_TIMER); - if (m_uiUpdateTimer <= uiDiff) + _updateTimer = _instance->GetData(TYPE_EVENT_TIMER); + if (_updateTimer <= uiDiff) { - switch (instance->GetData(TYPE_EVENT)) + switch (_instance->GetData(TYPE_EVENT)) { case 110: me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_TALK); Talk(SAY_STAGE_0_01); - m_uiUpdateTimer = 22000; - instance->SetData(TYPE_EVENT, 120); + _updateTimer = 22*IN_MILLISECONDS; + _instance->SetData(TYPE_EVENT, 120); break; case 140: me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_TALK); Talk(SAY_STAGE_0_02); - m_uiUpdateTimer = 5000; - instance->SetData(TYPE_EVENT, 150); + _updateTimer = 5*IN_MILLISECONDS; + _instance->SetData(TYPE_EVENT, 150); break; case 150: me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_NONE); - if (instance->GetData(TYPE_BEASTS) != DONE) + if (_instance->GetBossState(BOSS_BEASTS) != DONE) { - instance->DoUseDoorOrButton(instance->GetData64(GO_MAIN_GATE_DOOR)); + _instance->DoUseDoorOrButton(_instance->GetData64(GO_MAIN_GATE_DOOR)); if (Creature* temp = me->SummonCreature(NPC_GORMOK, ToCSpawnLoc[0].GetPositionX(), ToCSpawnLoc[0].GetPositionY(), ToCSpawnLoc[0].GetPositionZ(), 5, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 30*IN_MILLISECONDS)) { @@ -586,154 +586,133 @@ class npc_tirion_toc : public CreatureScript temp->SetReactState(REACT_PASSIVE); } } - m_uiUpdateTimer = 3000; - instance->SetData(TYPE_EVENT, 155); + _updateTimer = 3*IN_MILLISECONDS; + _instance->SetData(TYPE_EVENT, 155); break; case 155: - instance->SetData(TYPE_BEASTS, IN_PROGRESS); - m_uiUpdateTimer = 5000; - instance->SetData(TYPE_EVENT, 160); + // keep the raid in combat for the whole encounter, pauses included + me->SetInCombatWithZone(); + _updateTimer = 5*IN_MILLISECONDS; + _instance->SetData(TYPE_EVENT, 160); break; case 200: Talk(SAY_STAGE_0_04); - m_uiUpdateTimer = 8000; - instance->SetData(TYPE_EVENT, 205); - break; - case 205: - m_uiUpdateTimer = 3000; - instance->SetData(TYPE_EVENT, 210); - break; - case 210: - if (instance->GetData(TYPE_BEASTS) != DONE) + if (_instance->GetBossState(BOSS_BEASTS) != DONE) { - instance->DoUseDoorOrButton(instance->GetData64(GO_MAIN_GATE_DOOR)); + _instance->DoUseDoorOrButton(_instance->GetData64(GO_MAIN_GATE_DOOR)); if (Creature* temp = me->SummonCreature(NPC_DREADSCALE, ToCSpawnLoc[1].GetPositionX(), ToCSpawnLoc[1].GetPositionY(), ToCSpawnLoc[1].GetPositionZ(), 5, TEMPSUMMON_MANUAL_DESPAWN)) { - temp->GetMotionMaster()->MovePoint(0, ToCCommonLoc[8].GetPositionX(), ToCCommonLoc[8].GetPositionY(), ToCCommonLoc[8].GetPositionZ()); - temp->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); - temp->SetReactState(REACT_PASSIVE); - } - if (Creature* temp = me->SummonCreature(NPC_ACIDMAW, ToCCommonLoc[9].GetPositionX(), ToCCommonLoc[9].GetPositionY(), ToCCommonLoc[9].GetPositionZ(), 5, TEMPSUMMON_MANUAL_DESPAWN)) - { - temp->SetVisible(true); + temp->GetMotionMaster()->MovePoint(0, ToCCommonLoc[5].GetPositionX(), ToCCommonLoc[5].GetPositionY(), ToCCommonLoc[5].GetPositionZ()); temp->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); temp->SetReactState(REACT_PASSIVE); } } - m_uiUpdateTimer = 5000; - instance->SetData(TYPE_EVENT, 220); + _updateTimer = 5*IN_MILLISECONDS; + _instance->SetData(TYPE_EVENT, 220); break; case 220: - instance->SetData(TYPE_EVENT, 230); + _instance->SetData(TYPE_EVENT, 230); break; case 300: Talk(SAY_STAGE_0_05); - m_uiUpdateTimer = 8000; - instance->SetData(TYPE_EVENT, 305); - break; - case 305: - m_uiUpdateTimer = 3000; - instance->SetData(TYPE_EVENT, 310); - break; - case 310: - if (instance->GetData(TYPE_BEASTS) != DONE) + if (_instance->GetBossState(BOSS_BEASTS) != DONE) { - instance->DoUseDoorOrButton(instance->GetData64(GO_MAIN_GATE_DOOR)); + _instance->DoUseDoorOrButton(_instance->GetData64(GO_MAIN_GATE_DOOR)); if (Creature* temp = me->SummonCreature(NPC_ICEHOWL, ToCSpawnLoc[0].GetPositionX(), ToCSpawnLoc[0].GetPositionY(), ToCSpawnLoc[0].GetPositionZ(), 5, TEMPSUMMON_DEAD_DESPAWN)) { temp->GetMotionMaster()->MovePoint(2, ToCCommonLoc[5].GetPositionX(), ToCCommonLoc[5].GetPositionY(), ToCCommonLoc[5].GetPositionZ()); me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); me->SetReactState(REACT_PASSIVE); - } } - m_uiUpdateTimer = 5000; - instance->SetData(TYPE_EVENT, 315); + _updateTimer = 5*IN_MILLISECONDS; + _instance->SetData(TYPE_EVENT, 315); break; case 315: - instance->SetData(TYPE_EVENT, 320); + _instance->SetData(TYPE_EVENT, 320); break; case 400: Talk(SAY_STAGE_0_06); - m_uiUpdateTimer = 5000; - instance->SetData(TYPE_EVENT, 0); + me->getThreatManager().clearReferences(); + _updateTimer = 5*IN_MILLISECONDS; + _instance->SetData(TYPE_EVENT, 0); break; case 666: Talk(SAY_STAGE_0_WIPE); - m_uiUpdateTimer = 5000; - instance->SetData(TYPE_EVENT, 0); + _updateTimer = 5*IN_MILLISECONDS; + _instance->SetData(TYPE_EVENT, 0); break; case 1010: Talk(SAY_STAGE_1_01); - m_uiUpdateTimer = 7000; - instance->DoUseDoorOrButton(instance->GetData64(GO_MAIN_GATE_DOOR)); + _updateTimer = 7*IN_MILLISECONDS; + _instance->DoUseDoorOrButton(_instance->GetData64(GO_MAIN_GATE_DOOR)); me->SummonCreature(NPC_FIZZLEBANG, ToCSpawnLoc[0].GetPositionX(), ToCSpawnLoc[0].GetPositionY(), ToCSpawnLoc[0].GetPositionZ(), 2, TEMPSUMMON_CORPSE_TIMED_DESPAWN, DESPAWN_TIME); - instance->SetData(TYPE_EVENT, 0); + _instance->SetData(TYPE_EVENT, 0); break; case 1180: Talk(SAY_STAGE_1_07); - m_uiUpdateTimer = 3000; - instance->SetData(TYPE_EVENT, 0); + _updateTimer = 3*IN_MILLISECONDS; + _instance->SetData(TYPE_EVENT, 0); break; case 2000: Talk(SAY_STAGE_1_08); - m_uiUpdateTimer = 18000; - instance->SetData(TYPE_EVENT, 2010); + _updateTimer = 18*IN_MILLISECONDS; + _instance->SetData(TYPE_EVENT, 2010); break; case 2030: Talk(SAY_STAGE_1_11); - m_uiUpdateTimer = 5000; - instance->SetData(TYPE_EVENT, 0); + _updateTimer = 5*IN_MILLISECONDS; + _instance->SetData(TYPE_EVENT, 0); break; case 3000: Talk(SAY_STAGE_2_01); - m_uiUpdateTimer = 12000; - instance->SetData(TYPE_EVENT, 3050); + _updateTimer = 12*IN_MILLISECONDS; + _instance->SetData(TYPE_EVENT, 3050); break; case 3001: Talk(SAY_STAGE_2_01); - m_uiUpdateTimer = 12000; - instance->SetData(TYPE_EVENT, 3051); + _updateTimer = 10*IN_MILLISECONDS; + _instance->SetData(TYPE_EVENT, 3051); break; case 3060: Talk(SAY_STAGE_2_03); - m_uiUpdateTimer = 5000; - instance->SetData(TYPE_EVENT, 3070); + _updateTimer = 5*IN_MILLISECONDS; + _instance->SetData(TYPE_EVENT, 3070); break; case 3061: Talk(SAY_STAGE_2_03); - m_uiUpdateTimer = 5000; - instance->SetData(TYPE_EVENT, 3071); + _updateTimer = 5*IN_MILLISECONDS; + _instance->SetData(TYPE_EVENT, 3071); break; //Summoning crusaders case 3091: if (Creature* pChampionController = me->SummonCreature(NPC_CHAMPIONS_CONTROLLER, ToCCommonLoc[1])) pChampionController->AI()->SetData(0, HORDE); - m_uiUpdateTimer = 3000; - instance->SetData(TYPE_EVENT, 3092); + _updateTimer = 3*IN_MILLISECONDS; + _instance->SetData(TYPE_EVENT, 3092); break; //Summoning crusaders case 3090: if (Creature* pChampionController = me->SummonCreature(NPC_CHAMPIONS_CONTROLLER, ToCCommonLoc[1])) pChampionController->AI()->SetData(0, ALLIANCE); - m_uiUpdateTimer = 3000; - instance->SetData(TYPE_EVENT, 3092); + _updateTimer = 3*IN_MILLISECONDS; + _instance->SetData(TYPE_EVENT, 3092); break; case 3092: - if (Creature* pChampionController = Unit::GetCreature((*me), instance->GetData64(NPC_CHAMPIONS_CONTROLLER))) + if (Creature* pChampionController = Unit::GetCreature((*me), _instance->GetData64(NPC_CHAMPIONS_CONTROLLER))) pChampionController->AI()->SetData(1, NOT_STARTED); - instance->SetData(TYPE_EVENT, 3095); + _instance->SetData(TYPE_EVENT, 3095); break; //Crusaders battle end case 3100: Talk(SAY_STAGE_2_06); - m_uiUpdateTimer = 5000; - instance->SetData(TYPE_EVENT, 0); + _updateTimer = 5*IN_MILLISECONDS; + _instance->SetData(TYPE_EVENT, 0); break; case 4000: Talk(SAY_STAGE_3_01); - m_uiUpdateTimer = 13000; - instance->SetData(TYPE_EVENT, 4010); + _updateTimer = 13*IN_MILLISECONDS; + _instance->SetData(TYPE_EVENT, 4010); break; case 4010: Talk(SAY_STAGE_3_02); @@ -751,78 +730,88 @@ class npc_tirion_toc : public CreatureScript temp->SummonCreature(NPC_DARK_ESSENCE, TwinValkyrsLoc[2].GetPositionX(), TwinValkyrsLoc[2].GetPositionY(), TwinValkyrsLoc[2].GetPositionZ()); temp->SummonCreature(NPC_DARK_ESSENCE, TwinValkyrsLoc[3].GetPositionX(), TwinValkyrsLoc[3].GetPositionY(), TwinValkyrsLoc[3].GetPositionZ()); } - m_uiUpdateTimer = 3000; - instance->SetData(TYPE_EVENT, 4015); + _updateTimer = 3*IN_MILLISECONDS; + _instance->SetData(TYPE_EVENT, 4015); break; case 4015: - instance->DoUseDoorOrButton(instance->GetData64(GO_MAIN_GATE_DOOR)); - if (Creature* temp = Unit::GetCreature((*me), instance->GetData64(NPC_LIGHTBANE))) + _instance->DoUseDoorOrButton(_instance->GetData64(GO_MAIN_GATE_DOOR)); + if (Creature* temp = Unit::GetCreature((*me), _instance->GetData64(NPC_LIGHTBANE))) { temp->GetMotionMaster()->MovePoint(1, ToCCommonLoc[8].GetPositionX(), ToCCommonLoc[8].GetPositionY(), ToCCommonLoc[8].GetPositionZ()); temp->SetVisible(true); } - if (Creature* temp = Unit::GetCreature((*me), instance->GetData64(NPC_DARKBANE))) + if (Creature* temp = Unit::GetCreature((*me), _instance->GetData64(NPC_DARKBANE))) { temp->GetMotionMaster()->MovePoint(1, ToCCommonLoc[9].GetPositionX(), ToCCommonLoc[9].GetPositionY(), ToCCommonLoc[9].GetPositionZ()); temp->SetVisible(true); } - m_uiUpdateTimer = 5000; - instance->SetData(TYPE_EVENT, 4016); + _updateTimer = 10*IN_MILLISECONDS; + _instance->SetData(TYPE_EVENT, 4016); break; case 4016: - instance->SetData(TYPE_EVENT, 4017); + _instance->DoUseDoorOrButton(_instance->GetData64(GO_MAIN_GATE_DOOR)); + _instance->SetData(TYPE_EVENT, 4017); break; case 4040: - m_uiUpdateTimer = 60000; - instance->SetData(TYPE_EVENT, 5000); + _updateTimer = 1*MINUTE*IN_MILLISECONDS; + _instance->SetData(TYPE_EVENT, 5000); break; case 5000: Talk(SAY_STAGE_4_01); - m_uiUpdateTimer = 10000; - instance->SetData(TYPE_EVENT, 5005); + _updateTimer = 10*IN_MILLISECONDS; + _instance->SetData(TYPE_EVENT, 5005); break; case 5005: - m_uiUpdateTimer = 8000; - instance->SetData(TYPE_EVENT, 5010); + _updateTimer = 8*IN_MILLISECONDS; + _instance->SetData(TYPE_EVENT, 5010); me->SummonCreature(NPC_LICH_KING_1, ToCCommonLoc[2].GetPositionX(), ToCCommonLoc[2].GetPositionY(), ToCCommonLoc[2].GetPositionZ(), 5); break; case 5020: Talk(SAY_STAGE_4_03); - m_uiUpdateTimer = 1000; - instance->SetData(TYPE_EVENT, 0); + _updateTimer = 1*IN_MILLISECONDS; + _instance->SetData(TYPE_EVENT, 0); break; case 6000: me->SummonCreature(NPC_TIRION_FORDRING, EndSpawnLoc[0].GetPositionX(), EndSpawnLoc[0].GetPositionY(), EndSpawnLoc[0].GetPositionZ()); me->SummonCreature(NPC_ARGENT_MAGE, EndSpawnLoc[1].GetPositionX(), EndSpawnLoc[1].GetPositionY(), EndSpawnLoc[1].GetPositionZ()); me->SummonGameObject(GO_PORTAL_TO_DALARAN, EndSpawnLoc[2].GetPositionX(), EndSpawnLoc[2].GetPositionY(), EndSpawnLoc[2].GetPositionZ(), 5, 0, 0, 0, 0, 0); - m_uiUpdateTimer = 20000; - instance->SetData(TYPE_EVENT, 6005); + _updateTimer = 20*IN_MILLISECONDS; + _instance->SetData(TYPE_EVENT, 6005); break; case 6005: - if (Creature* tirionFordring = Unit::GetCreature((*me), instance->GetData64(NPC_TIRION_FORDRING))) + if (Creature* tirionFordring = Unit::GetCreature((*me), _instance->GetData64(NPC_TIRION_FORDRING))) tirionFordring->AI()->Talk(SAY_STAGE_4_06); - m_uiUpdateTimer = 20000; - instance->SetData(TYPE_EVENT, 6010); + _updateTimer = 20*IN_MILLISECONDS; + _instance->SetData(TYPE_EVENT, 6010); break; case 6010: if (IsHeroic()) { - if (Creature* tirionFordring = Unit::GetCreature((*me), instance->GetData64(NPC_TIRION_FORDRING))) + if (Creature* tirionFordring = Unit::GetCreature((*me), _instance->GetData64(NPC_TIRION_FORDRING))) tirionFordring->AI()->Talk(SAY_STAGE_4_07); - m_uiUpdateTimer = 60000; - instance->SetData(TYPE_ANUBARAK, SPECIAL); - instance->SetData(TYPE_EVENT, 6020); - } else instance->SetData(TYPE_EVENT, 6030); + _updateTimer = 1*MINUTE*IN_MILLISECONDS; + _instance->SetBossState(BOSS_ANUBARAK, SPECIAL); + _instance->SetData(TYPE_EVENT, 6020); + } + else + _instance->SetData(TYPE_EVENT, 6030); break; case 6020: me->DespawnOrUnsummon(); - m_uiUpdateTimer = 5000; - instance->SetData(TYPE_EVENT, 6030); + _updateTimer = 5*IN_MILLISECONDS; + _instance->SetData(TYPE_EVENT, 6030); + break; + default: break; } - } else m_uiUpdateTimer -= uiDiff; - instance->SetData(TYPE_EVENT_TIMER, m_uiUpdateTimer); + } + else + _updateTimer -= uiDiff; + _instance->SetData(TYPE_EVENT_TIMER, _updateTimer); } + private: + InstanceScript* _instance; + uint32 _updateTimer; }; CreatureAI* GetAI(Creature* creature) const @@ -834,76 +823,79 @@ class npc_tirion_toc : public CreatureScript class npc_garrosh_toc : public CreatureScript { public: - npc_garrosh_toc() : CreatureScript("npc_garrosh_toc") { } struct npc_garrosh_tocAI : public ScriptedAI { npc_garrosh_tocAI(Creature* creature) : ScriptedAI(creature) { - instance = me->GetInstanceScript(); + _instance = me->GetInstanceScript(); } - InstanceScript* instance; - uint32 m_uiUpdateTimer; - void Reset() {} void AttackStart(Unit* /*who*/) {} void UpdateAI(const uint32 uiDiff) { - if (!instance) + if (!_instance) return; - if (instance->GetData(TYPE_EVENT_NPC) != NPC_GARROSH) + if (_instance->GetData(TYPE_EVENT_NPC) != NPC_GARROSH) return; - m_uiUpdateTimer = instance->GetData(TYPE_EVENT_TIMER); - if (m_uiUpdateTimer <= uiDiff) + _updateTimer = _instance->GetData(TYPE_EVENT_TIMER); + if (_updateTimer <= uiDiff) { - switch (instance->GetData(TYPE_EVENT)) + switch (_instance->GetData(TYPE_EVENT)) { case 130: me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_TALK); Talk(SAY_STAGE_0_03h); - m_uiUpdateTimer = 3000; - instance->SetData(TYPE_EVENT, 132); + _updateTimer = 3*IN_MILLISECONDS; + _instance->SetData(TYPE_EVENT, 132); break; case 132: me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_NONE); - m_uiUpdateTimer = 5000; - instance->SetData(TYPE_EVENT, 140); + _updateTimer = 5*IN_MILLISECONDS; + _instance->SetData(TYPE_EVENT, 140); break; case 2010: Talk(SAY_STAGE_1_09); - m_uiUpdateTimer = 9000; - instance->SetData(TYPE_EVENT, 2020); + _updateTimer = 9*IN_MILLISECONDS; + _instance->SetData(TYPE_EVENT, 2020); break; case 3050: Talk(SAY_STAGE_2_02h); - m_uiUpdateTimer = 15000; - instance->SetData(TYPE_EVENT, 3060); + _updateTimer = 15*IN_MILLISECONDS; + _instance->SetData(TYPE_EVENT, 3060); break; case 3070: Talk(SAY_STAGE_2_04h); - m_uiUpdateTimer = 6000; - instance->SetData(TYPE_EVENT, 3080); + _updateTimer = 6*IN_MILLISECONDS; + _instance->SetData(TYPE_EVENT, 3080); break; case 3081: Talk(SAY_STAGE_2_05h); - m_uiUpdateTimer = 3000; - instance->SetData(TYPE_EVENT, 3091); + _updateTimer = 3*IN_MILLISECONDS; + _instance->SetData(TYPE_EVENT, 3091); break; case 4030: Talk(SAY_STAGE_3_03h); - m_uiUpdateTimer = 5000; - instance->SetData(TYPE_EVENT, 4040); + _updateTimer = 5*IN_MILLISECONDS; + _instance->SetData(TYPE_EVENT, 4040); + break; + default: break; } - } else m_uiUpdateTimer -= uiDiff; - instance->SetData(TYPE_EVENT_TIMER, m_uiUpdateTimer); + } + else + _updateTimer -= uiDiff; + _instance->SetData(TYPE_EVENT_TIMER, _updateTimer); } + private: + InstanceScript* _instance; + uint32 _updateTimer; }; CreatureAI* GetAI(Creature* creature) const @@ -915,76 +907,79 @@ class npc_garrosh_toc : public CreatureScript class npc_varian_toc : public CreatureScript { public: - npc_varian_toc() : CreatureScript("npc_varian_toc") { } struct npc_varian_tocAI : public ScriptedAI { npc_varian_tocAI(Creature* creature) : ScriptedAI(creature) { - instance = me->GetInstanceScript(); + _instance = me->GetInstanceScript(); } - InstanceScript* instance; - uint32 m_uiUpdateTimer; - void Reset() {} void AttackStart(Unit* /*who*/) {} void UpdateAI(const uint32 uiDiff) { - if (!instance) + if (!_instance) return; - if (instance->GetData(TYPE_EVENT_NPC) != NPC_VARIAN) + if (_instance->GetData(TYPE_EVENT_NPC) != NPC_VARIAN) return; - m_uiUpdateTimer = instance->GetData(TYPE_EVENT_TIMER); - if (m_uiUpdateTimer <= uiDiff) + _updateTimer = _instance->GetData(TYPE_EVENT_TIMER); + if (_updateTimer <= uiDiff) { - switch (instance->GetData(TYPE_EVENT)) + switch (_instance->GetData(TYPE_EVENT)) { case 120: me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_TALK); Talk(SAY_STAGE_0_03a); - m_uiUpdateTimer = 2000; - instance->SetData(TYPE_EVENT, 122); + _updateTimer = 2*IN_MILLISECONDS; + _instance->SetData(TYPE_EVENT, 122); break; case 122: me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_NONE); - m_uiUpdateTimer = 3000; - instance->SetData(TYPE_EVENT, 130); + _updateTimer = 3*IN_MILLISECONDS; + _instance->SetData(TYPE_EVENT, 130); break; case 2020: Talk(SAY_STAGE_1_10); - m_uiUpdateTimer = 5000; - instance->SetData(TYPE_EVENT, 2030); + _updateTimer = 5*IN_MILLISECONDS; + _instance->SetData(TYPE_EVENT, 2030); break; case 3051: Talk(SAY_STAGE_2_02a); - m_uiUpdateTimer = 10000; - instance->SetData(TYPE_EVENT, 3061); + _updateTimer = 17*IN_MILLISECONDS; + _instance->SetData(TYPE_EVENT, 3061); break; case 3071: Talk(SAY_STAGE_2_04a); - m_uiUpdateTimer = 5000; - instance->SetData(TYPE_EVENT, 3081); + _updateTimer = 5*IN_MILLISECONDS; + _instance->SetData(TYPE_EVENT, 3081); break; case 3080: Talk(SAY_STAGE_2_05a); - m_uiUpdateTimer = 3000; - instance->SetData(TYPE_EVENT, 3090); + _updateTimer = 3*IN_MILLISECONDS; + _instance->SetData(TYPE_EVENT, 3090); break; case 4020: Talk(SAY_STAGE_3_03a); - m_uiUpdateTimer = 5000; - instance->SetData(TYPE_EVENT, 4040); + _updateTimer = 5*IN_MILLISECONDS; + _instance->SetData(TYPE_EVENT, 4040); + break; + default: break; } - } else m_uiUpdateTimer -= uiDiff; - instance->SetData(TYPE_EVENT_TIMER, m_uiUpdateTimer); + } + else + _updateTimer -= uiDiff; + _instance->SetData(TYPE_EVENT_TIMER, _updateTimer); } + private: + InstanceScript* _instance; + uint32 _updateTimer; }; CreatureAI* GetAI(Creature* creature) const @@ -995,8 +990,8 @@ class npc_varian_toc : public CreatureScript void AddSC_trial_of_the_crusader() { - new npc_announcer_toc10(); new boss_lich_king_toc(); + new npc_announcer_toc10(); new npc_fizzlebang_toc(); new npc_tirion_toc(); new npc_garrosh_toc(); diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/trial_of_the_crusader.h b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/trial_of_the_crusader.h index 58cbd727963..fa38b6b46c1 100644 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/trial_of_the_crusader.h +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/trial_of_the_crusader.h @@ -7,12 +7,12 @@ enum { - TYPE_BEASTS = 0, - TYPE_JARAXXUS = 1, - TYPE_CRUSADERS = 2, - TYPE_VALKIRIES = 3, - TYPE_LICH_KING = 4, - TYPE_ANUBARAK = 5, + BOSS_BEASTS = 0, + BOSS_JARAXXUS = 1, + BOSS_CRUSADERS = 2, + BOSS_VALKIRIES = 3, + BOSS_LICH_KING = 4, // not really a boss but oh well + BOSS_ANUBARAK = 5, MAX_ENCOUNTERS = 6, TYPE_COUNTER = 8, @@ -31,15 +31,19 @@ enum SPELL_WILFRED_PORTAL = 68424, SPELL_JARAXXUS_CHAINS = 67924, + SPELL_CORPSE_TELEPORT = 69016, + SPELL_DESTROY_FLOOR_KNOCKUP = 68193, DESPAWN_TIME = 300000, + + DISPLAYID_DESTROYED_FLOOR = 9060 }; const Position ToCSpawnLoc[]= { {563.912f, 261.625f, 394.73f, 4.70437f}, // 0 Center {575.451f, 261.496f, 394.73f, 4.6541f}, // 1 Left - {549.951f, 261.55f, 394.73f, 4.74835f}, // 2 Right + {549.951f, 261.55f, 394.73f, 4.74835f} // 2 Right }; const Position ToCCommonLoc[]= @@ -68,7 +72,7 @@ const Position ToCCommonLoc[]= {558.811610f, 195.985779f, 394.671661f, 0}, // 13 {567.641724f, 195.351501f, 394.659943f, 0}, // 14 {560.633972f, 195.391708f, 395.137543f, 0}, // 15 - {565.816956f, 195.477921f, 395.136810f, 0}, // 16 + {565.816956f, 195.477921f, 395.136810f, 0} // 16 }; const Position JaraxxusLoc[]= @@ -76,7 +80,7 @@ const Position JaraxxusLoc[]= {508.104767f, 138.247345f, 395.128052f, 0}, // 0 - Fizzlebang start location {548.610596f, 139.807800f, 394.321838f, 0}, // 1 - fizzlebang end {581.854187f, 138.0f, 394.319f, 0}, // 2 - Portal Right - {550.558838f, 138.0f, 394.319f, 0}, // 3 - Portal Left + {550.558838f, 138.0f, 394.319f, 0} // 3 - Portal Left }; const Position FactionChampionLoc[]= @@ -102,21 +106,21 @@ const Position FactionChampionLoc[]= {528.958f, 131.47f, 394.73f, 0}, // 16 - Horde Final Pos 6 {526.309f, 116.667f, 394.833f, 0}, // 17 - Horde Final Pos 7 {524.238f, 122.411f, 394.819f, 0}, // 18 - Horde Final Pos 8 - {521.901f, 128.488f, 394.832f, 0}, // 19 - Horde Final Pos 9 + {521.901f, 128.488f, 394.832f, 0} // 19 - Horde Final Pos 9 }; const Position TwinValkyrsLoc[]= { - {586.060242f, 117.514809f, 394.314026f, 0}, // 0 - Dark essence 1 - {541.602112f, 161.879837f, 394.587952f, 0}, // 1 - Dark essence 2 - {541.021118f, 117.262932f, 395.314819f, 0}, // 2 - Light essence 1 - {586.200562f, 162.145523f, 394.626129f, 0}, // 3 - Light essence 2 + {586.060242f, 117.514809f, 394.41f, 0}, // 0 - Dark essence 1 + {541.602112f, 161.879837f, 394.41f, 0}, // 1 - Dark essence 2 + {541.021118f, 117.262932f, 394.41f, 0}, // 2 - Light essence 1 + {586.200562f, 162.145523f, 394.41f, 0} // 3 - Light essence 2 }; const Position LichKingLoc[]= { {563.549f, 152.474f, 394.393f, 0}, // 0 - Lich king start - {563.547f, 141.613f, 393.908f, 0}, // 1 - Lich king end + {563.547f, 141.613f, 393.908f, 0} // 1 - Lich king end }; const Position AnubarakLoc[]= @@ -126,20 +130,20 @@ const Position AnubarakLoc[]= {694.886353f, 102.484665f, 142.119614f, 0}, // 3 - Nerub Spawn {694.500671f, 185.363968f, 142.117905f, 0}, // 5 - Nerub Spawn {731.987244f, 83.3824690f, 142.119614f, 0}, // 2 - Nerub Spawn - {740.184509f, 193.443390f, 142.117584f, 0}, // 4 - Nerub Spawn + {740.184509f, 193.443390f, 142.117584f, 0} // 4 - Nerub Spawn }; const Position EndSpawnLoc[]= { {648.9167f, 131.0208f, 141.6161f, 0}, // 0 - Highlord Tirion Fordring {649.1614f, 142.0399f, 141.3057f ,0}, // 1 - Argent Mage - {644.6250f, 149.2743f, 140.6015f ,0}, // 2 - Portal to Dalaran + {644.6250f, 149.2743f, 140.6015f ,0} // 2 - Portal to Dalaran }; enum euiWorldStates { UPDATE_STATE_UI_SHOW = 4390, - UPDATE_STATE_UI_COUNT = 4389, + UPDATE_STATE_UI_COUNT = 4389 }; enum eNorthrendBeasts @@ -152,7 +156,7 @@ enum eNorthrendBeasts SNAKES_SPECIAL = 2003, SNAKES_DONE = 2004, ICEHOWL_IN_PROGRESS = 3000, - ICEHOWL_DONE = 3001, + ICEHOWL_DONE = 3001 }; enum eAnnouncerMessages @@ -162,7 +166,7 @@ enum eAnnouncerMessages MSG_CRUSADERS = 724003, MSG_VALKIRIES = 724004, MSG_LICH_KING = 724005, - MSG_ANUBARAK = 724006, + MSG_ANUBARAK = 724006 }; enum eCreature @@ -227,7 +231,7 @@ enum eCreature NPC_DARK_ESSENCE = 34567, NPC_LIGHT_ESSENCE = 34568, - NPC_ANUBARAK = 34564, + NPC_ANUBARAK = 34564 }; enum eGameObject @@ -253,7 +257,7 @@ enum eGameObject GO_MAIN_GATE_DOOR = 195647, GO_EAST_PORTCULLIS = 195648, GO_WEB_DOOR = 195485, - GO_PORTAL_TO_DALARAN = 195682, + GO_PORTAL_TO_DALARAN = 195682 }; enum eAchievementData |