diff options
author | Keader <keader.android@gmail.com> | 2017-12-23 22:03:57 -0300 |
---|---|---|
committer | funjoker <funjoker109@gmail.com> | 2021-04-15 05:53:27 +0200 |
commit | a5635526ed4fd7d32be7b250a0da7eb45720629e (patch) | |
tree | 284b2d8056ec150326c5dc042b593dd51a2bc420 /src | |
parent | c6d6ece1c7a450145598d5ac3c83b399cc731ee9 (diff) |
Scripts/Trial of Crusader: Northrend Beasts Rework (#21031)
* Rewritten Gormok encounter
* Rewritten Snobold Vassal Script
* Rewritten Jormungars encounter
* Rewritten Icehowl encounter
* Added missing texts
* Added missing spells
* Implemented berserk mechanic on heroic diffs.
* Implemented Achievement requirement to make heroic diffs.
* Rewritten Barrett Ramsay scripts
* Added Barrett gossips and ported everything to DB.
* Added right Barrett in each encounter
* Removed a lot of hacks
* Rewritten Tirion Fordring script
* Rewritten Varian Wrynn script
* Rewritten Garrosh script
* Rewritten Wilfred event
* Rewritten Lich King event
* Updated codestyle
* Added missing spawns
* Fixed combat behavior before Gormok
* Fixed some visual stuff
(cherry picked from commit 2362e9c79410c689afc10266b94f7e78c88bbddc)
Diffstat (limited to 'src')
8 files changed, 2099 insertions, 2223 deletions
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 c5dc4db2e50..a3da5f57881 100644 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_faction_champions.cpp +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_faction_champions.cpp @@ -28,11 +28,6 @@ #include "TemporarySummon.h" #include "trial_of_the_crusader.h" -enum Yells -{ - SAY_KILL_PLAYER = 6 -}; - enum AIs { AI_MELEE = 0, @@ -209,7 +204,7 @@ enum Events EVENT_REGROWTH = 3, EVENT_REJUVENATION = 4, EVENT_TRANQUILITY = 5, - EVENT_HEAL_BARKSKIN = 6, + EVENT_HEAL_BARKSKIN = 6, EVENT_THORNS = 7, EVENT_NATURE_GRASP = 8, @@ -551,9 +546,7 @@ class boss_toc_champion_controller : public CreatureScript case DONE: { _championsKilled++; - if (_championsKilled == 1) - instance->SetBossState(DATA_FACTION_CRUSADERS, SPECIAL); - else if (_championsKilled >= summons.size()) + if (_championsKilled >= summons.size()) { instance->SetBossState(DATA_FACTION_CRUSADERS, DONE); summons.DespawnAll(); @@ -584,7 +577,7 @@ class boss_toc_champion_controller : public CreatureScript struct boss_faction_championsAI : public BossAI { - boss_faction_championsAI(Creature* creature, uint32 aitype) : BossAI(creature, DATA_FACTION_CHAMPIONS) + boss_faction_championsAI(Creature* creature, uint32 aitype) : BossAI(creature, DATA_FACTION_CHAMPIONS), _teamInstance(0) { _aiType = aitype; SetBoundary(instance->GetBossBoundary(DATA_FACTION_CRUSADERS)); @@ -592,6 +585,7 @@ struct boss_faction_championsAI : public BossAI void Reset() override { + _teamInstance = instance->GetData(DATA_TEAM); _events.ScheduleEvent(EVENT_THREAT, 5*IN_MILLISECONDS); if (IsHeroic() && (_aiType != AI_PET)) _events.ScheduleEvent(EVENT_REMOVE_CC, 5*IN_MILLISECONDS); @@ -656,22 +650,13 @@ struct boss_faction_championsAI : public BossAI { if (who->GetTypeId() == TYPEID_PLAYER) { - Map::PlayerList const& players = me->GetMap()->GetPlayers(); - uint32 TeamInInstance = 0; - - if (!players.isEmpty()) - if (Player* player = players.begin()->GetSource()) - TeamInInstance = player->GetTeam(); - - if (TeamInInstance == ALLIANCE) + if (_teamInstance == ALLIANCE) { if (Creature* varian = instance->GetCreature(DATA_VARIAN)) - varian->AI()->Talk(SAY_KILL_PLAYER); + varian->AI()->DoAction(ACTION_SAY_KILLED_PLAYER); } - else - if (Creature* garrosh = instance->GetCreature(DATA_GARROSH)) - garrosh->AI()->Talk(SAY_KILL_PLAYER); - + else if (Creature* garrosh = instance->GetCreature(DATA_GARROSH)) + garrosh->AI()->DoAction(ACTION_SAY_KILLED_PLAYER); } } @@ -757,6 +742,7 @@ struct boss_faction_championsAI : public BossAI private: uint32 _aiType; + uint32 _teamInstance; // make sure that every bosses separate events dont mix with these _events EventMap _events; }; 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 9382f74ef1b..dcb939e57f8 100644 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_lord_jaraxxus.cpp +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_lord_jaraxxus.cpp @@ -17,6 +17,8 @@ #include "ScriptMgr.h" #include "InstanceScript.h" +#include "MotionMaster.h" +#include "Player.h" #include "ScriptedCreature.h" #include "SpellInfo.h" #include "SpellScript.h" @@ -49,19 +51,21 @@ enum Summons enum BossSpells { - SPELL_LEGION_FLAME = 66197, // player should run away from raid because he triggers Legion Flame - SPELL_LEGION_FLAME_EFFECT = 66201, // used by trigger npc - SPELL_NETHER_POWER = 66228, // +20% of spell damage per stack, stackable up to 5/10 times, must be dispelled/stealed - SPELL_FEL_LIGHTING = 66528, // jumps to nearby targets - SPELL_FEL_FIREBALL = 66532, // does heavy damage to the tank, interruptable - SPELL_INCINERATE_FLESH = 66237, // target must be healed or will trigger Burning Inferno - SPELL_BURNING_INFERNO = 66242, // triggered by Incinerate Flesh - SPELL_INFERNAL_ERUPTION = 66258, // summons Infernal Volcano - SPELL_INFERNAL_ERUPTION_EFFECT = 66252, // summons Felflame Infernal (3 at Normal and inifinity at Heroic) - SPELL_NETHER_PORTAL = 66269, // summons Nether Portal - SPELL_NETHER_PORTAL_EFFECT = 66263, // summons Mistress of Pain (1 at Normal and infinity at Heroic) - - SPELL_BERSERK = 64238, // unused + SPELL_LEGION_FLAME = 66197, // player should run away from raid because he triggers Legion Flame + SPELL_LEGION_FLAME_EFFECT = 66201, // used by trigger npc + SPELL_NETHER_POWER = 66228, // +20% of spell damage per stack, stackable up to 5/10 times, must be dispelled/stealed + SPELL_FEL_LIGHTING = 66528, // jumps to nearby targets + SPELL_FEL_FIREBALL = 66532, // does heavy damage to the tank, interruptable + SPELL_INCINERATE_FLESH = 66237, // target must be healed or will trigger Burning Inferno + SPELL_BURNING_INFERNO = 66242, // triggered by Incinerate Flesh + SPELL_INFERNAL_ERUPTION = 66258, // summons Infernal Volcano + SPELL_INFERNAL_ERUPTION_EFFECT = 66252, // summons Felflame Infernal (3 at Normal and inifinity at Heroic) + SPELL_NETHER_PORTAL = 66269, // summons Nether Portal + SPELL_NETHER_PORTAL_EFFECT = 66263, // summons Mistress of Pain (1 at Normal and infinity at Heroic) + SPELL_LORD_JARAXXUS_HITTIN_YA = 66327, + SPELL_FEL_LIGHTNING = 67888, + + SPELL_BERSERK = 64238, // unused // Mistress of Pain spells SPELL_SHIVAN_SLASH = 67098, @@ -78,18 +82,31 @@ enum BossSpells 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, + EVENT_INTRO = 1, + EVENT_FEL_FIREBALL, + EVENT_FEL_LIGHTNING, + EVENT_INCINERATE_FLESH, + EVENT_NETHER_POWER, + EVENT_LEGION_FLAME, + EVENT_SUMMONO_NETHER_PORTAL, + EVENT_SUMMON_INFERNAL_ERUPTION, + EVENT_TAUNT_GNOME, + EVENT_KILL_GNOME, + EVENT_CHANGE_ORIENTATION, + EVENT_START_COMBAT, // Mistress of Pain - EVENT_SHIVAN_SLASH = 8, - EVENT_SPINNING_STRIKE = 9, - EVENT_MISTRESS_KISS = 10 + EVENT_SHIVAN_SLASH, + EVENT_SPINNING_STRIKE, + EVENT_MISTRESS_KISS +}; + +enum Misc +{ + PHASE_INTRO = 1, + PHASE_COMBAT = 2, + SPLINE_INITIAL_MOVEMENT = 1, + POINT_SUMMONED = 1 }; class boss_jaraxxus : public CreatureScript @@ -104,22 +121,44 @@ class boss_jaraxxus : public CreatureScript void Reset() override { _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); + if (instance->GetBossState(DATA_JARAXXUS) == NOT_STARTED) + DoAction(ACTION_JARAXXUS_INTRO); } void JustReachedHome() override { _JustReachedHome(); instance->SetBossState(DATA_JARAXXUS, FAIL); - DoCast(me, SPELL_JARAXXUS_CHAINS); - me->AddUnitFlag(UNIT_FLAG_NON_ATTACKABLE); + DoCastSelf(SPELL_JARAXXUS_CHAINS); me->SetImmuneToPC(true); + me->SetReactState(REACT_PASSIVE); + } + + void DoAction(int32 action) override + { + if (action == ACTION_JARAXXUS_INTRO) + { + me->SetReactState(REACT_PASSIVE); + events.SetPhase(PHASE_INTRO); + events.ScheduleEvent(EVENT_INTRO, 1s); + } + else if (action == ACTION_JARAXXUS_ENGAGE) + { + me->RemoveAurasDueToSpell(SPELL_JARAXXUS_CHAINS); + me->SetImmuneToPC(false); + me->SetReactState(REACT_AGGRESSIVE); + DoZoneInCombat(); + } + } + + void MovementInform(uint32 type, uint32 pointId) override + { + if (type == SPLINE_CHAIN_MOTION_TYPE && pointId == POINT_SUMMONED) + if (Creature* wilfred = instance->GetCreature(DATA_FIZZLEBANG)) + { + me->SetFacingToObject(wilfred); + events.ScheduleEvent(EVENT_TAUNT_GNOME, 9s); + } } void KilledUnit(Unit* who) override @@ -138,11 +177,18 @@ class boss_jaraxxus : public CreatureScript { _EnterCombat(); Talk(SAY_AGGRO); + 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 UpdateAI(uint32 diff) override { - if (!UpdateVictim()) + if (!UpdateVictim() && !events.IsInPhase(PHASE_INTRO)) return; events.Update(diff); @@ -157,12 +203,12 @@ class boss_jaraxxus : public CreatureScript case EVENT_FEL_FIREBALL: DoCastVictim(SPELL_FEL_FIREBALL); events.ScheduleEvent(EVENT_FEL_FIREBALL, urand(10*IN_MILLISECONDS, 15*IN_MILLISECONDS)); - return; + break; case EVENT_FEL_LIGHTNING: if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true, true, -SPELL_LORD_HITTIN)) DoCast(target, SPELL_FEL_LIGHTING); events.ScheduleEvent(EVENT_FEL_LIGHTNING, urand(10*IN_MILLISECONDS, 15*IN_MILLISECONDS)); - return; + break; case EVENT_INCINERATE_FLESH: if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 0.0f, true, true, -SPELL_LORD_HITTIN)) { @@ -171,11 +217,11 @@ class boss_jaraxxus : public CreatureScript DoCast(target, SPELL_INCINERATE_FLESH); } events.ScheduleEvent(EVENT_INCINERATE_FLESH, urand(20*IN_MILLISECONDS, 25*IN_MILLISECONDS)); - return; + break; 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; + break; case EVENT_LEGION_FLAME: if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 0.0f, true, true, -SPELL_LORD_HITTIN)) { @@ -183,19 +229,42 @@ class boss_jaraxxus : public CreatureScript DoCast(target, SPELL_LEGION_FLAME); } events.ScheduleEvent(EVENT_LEGION_FLAME, 30*IN_MILLISECONDS); - return; + break; 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; + break; 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; + break; + case EVENT_INTRO: + DoCastSelf(SPELL_LORD_JARAXXUS_HITTIN_YA, true); + me->GetMotionMaster()->MoveAlongSplineChain(POINT_SUMMONED, SPLINE_INITIAL_MOVEMENT, true); + break; + case EVENT_TAUNT_GNOME: + Talk(SAY_INTRO); + events.ScheduleEvent(EVENT_KILL_GNOME, 9s); + break; + case EVENT_KILL_GNOME: + DoCastSelf(SPELL_FEL_LIGHTNING); + events.ScheduleEvent(EVENT_CHANGE_ORIENTATION, 3s); + break; + case EVENT_CHANGE_ORIENTATION: + me->SetFacingTo(4.729842f); + events.ScheduleEvent(EVENT_START_COMBAT, 7s); + break; + case EVENT_START_COMBAT: + me->SetImmuneToPC(false); + me->SetReactState(REACT_AGGRESSIVE); + DoZoneInCombat(); + break; + default: + break; } if (me->HasUnitState(UNIT_STATE_CASTING)) 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 aab0cd46128..de6ba1849e5 100644 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_northrend_beasts.cpp +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_northrend_beasts.cpp @@ -38,17 +38,9 @@ enum Yells SAY_SPECIAL = 1, // Icehowl - EMOTE_TRAMPLE_START = 0, - EMOTE_TRAMPLE_CRASH = 1, - EMOTE_TRAMPLE_FAIL = 2 -}; - -enum Equipment -{ - EQUIP_MAIN = 50760, - EQUIP_OFFHAND = 48040, - EQUIP_RANGED = 47267, - EQUIP_DONE = EQUIP_NO_CHANGE + EMOTE_TRAMPLE_ROAR = 0, + EMOTE_TRAMPLE_FAIL = 1, + EMOTE_TRAMPLE_ENRAGE = 2 }; enum Model @@ -59,75 +51,81 @@ enum Model MODEL_DREADSCALE_MOBILE = 24564 }; -enum BeastSummons -{ - NPC_SNOBOLD_VASSAL = 34800, - NPC_FIRE_BOMB = 34854, - NPC_SLIME_POOL = 35176, - MAX_SNOBOLDS = 4 -}; - enum BossSpells { - //Gormok - SPELL_IMPALE = 66331, - SPELL_STAGGERING_STOMP = 67648, - //Snobold - SPELL_RISING_ANGER = 66636, - SPELL_SNOBOLLED = 66406, - SPELL_BATTER = 66408, - SPELL_FIRE_BOMB = 66313, - SPELL_FIRE_BOMB_1 = 66317, - SPELL_FIRE_BOMB_DOT = 66318, - SPELL_HEAD_CRACK = 66407, - SPELL_JUMP_TO_HAND = 66342, - SPELL_RIDE_PLAYER = 66245, - - //Acidmaw & Dreadscale Generic - SPELL_SWEEP = 66794, - SUMMON_SLIME_POOL = 66883, - SPELL_EMERGE = 66947, - SPELL_SUBMERGE = 66948, - SPELL_ENRAGE = 68335, - SPELL_SLIME_POOL_EFFECT = 66882, //In 60s it diameter grows from 10y to 40y (r=r+0.25 per second) - SPELL_GROUND_VISUAL_0 = 66969, - SPELL_GROUND_VISUAL_1 = 68302, - SPELL_HATE_TO_ZERO = 63984, - //Acidmaw - SPELL_ACID_SPIT = 66880, - SPELL_PARALYTIC_SPRAY = 66901, - SPELL_PARALYTIC_BITE = 66824, //Paralytic Toxin - SPELL_ACID_SPEW = 66818, - SPELL_PARALYSIS = 66830, - SPELL_PARALYTIC_TOXIN = 66823, - //Dreadscale - SPELL_BURNING_BITE = 66879, // Burning Bile - SPELL_MOLTEN_SPEW = 66821, - SPELL_FIRE_SPIT = 66796, - SPELL_BURNING_SPRAY = 66902, - SPELL_BURNING_BILE = 66869, - - //Icehowl - SPELL_FEROCIOUS_BUTT = 66770, - SPELL_MASSIVE_CRASH = 66683, - SPELL_WHIRL = 67345, - SPELL_ARCTIC_BREATH = 66689, - SPELL_TRAMPLE = 66734, - SPELL_FROTHING_RAGE = 66759, - SPELL_STAGGERED_DAZE = 66758 + // Gormok + SPELL_IMPALE = 66331, + SPELL_STAGGERING_STOMP = 66330, + SPELL_TANKING_GORMOK = 66415, // No idea what it does (SERVERSIDE spell) + + // Snobold + SPELL_RISING_ANGER = 66636, + SPELL_SNOBOLLED = 66406, + SPELL_BATTER = 66408, + SPELL_FIRE_BOMB = 66313, + SPELL_HEAD_CRACK = 66407, + SPELL_JUMP_TO_HAND = 66342, + SPELL_RIDE_PLAYER = 66245, + + // Acidmaw & Dreadscale Generic + SPELL_SWEEP = 66794, + SUMMON_SLIME_POOL = 66883, + SPELL_EMERGE = 66947, + SPELL_SUBMERGE = 66948, + SPELL_SUBMERGE_2 = 66936, + SPELL_ENRAGE = 68335, + SPELL_GROUND_VISUAL_0 = 66969, + SPELL_GROUND_VISUAL_1 = 68302, + SPELL_HATE_TO_ZERO = 63984, + // Acidmaw + SPELL_ACID_SPIT = 66880, + SPELL_PARALYTIC_SPRAY = 66901, + SPELL_PARALYTIC_BITE = 66824, + SPELL_ACID_SPEW = 66818, + SPELL_PARALYSIS = 66830, + SPELL_PARALYTIC_TOXIN = 66823, + // Dreadscale + SPELL_BURNING_BITE = 66879, + SPELL_MOLTEN_SPEW = 66821, + SPELL_FIRE_SPIT = 66796, + SPELL_BURNING_SPRAY = 66902, + SPELL_BURNING_BILE = 66869, + + // Slime Pool + SPELL_SLIME_POOL_EFFECT = 66882, + SPELL_PACIFY_SELF = 19951, + + // Icehowl + SPELL_FEROCIOUS_BUTT = 66770, + SPELL_MASSIVE_CRASH = 66683, + SPELL_WHIRL = 67345, + SPELL_ARCTIC_BREATH = 66688, + SPELL_TRAMPLE = 66734, + SPELL_FROTHING_RAGE = 66759, + SPELL_STAGGERED_DAZE = 66758, + SPELL_FURIOUS_CHARGE_SUMMON = 66729, + SPELL_ROAR = 66736, + SPELL_JUMP_BACK = 66733, + SPELL_SURGE_OF_ADRENALINE = 68667, + SPELL_BERSERK = 26662 }; enum MyActions { - ACTION_ENABLE_FIRE_BOMB = 1, - ACTION_DISABLE_FIRE_BOMB = 2, - ACTION_ACTIVE_SNOBOLD = 3 + ACTION_ENABLE_FIRE_BOMB = 1, + ACTION_DISABLE_FIRE_BOMB, + ACTION_ACTIVE_SNOBOLD, + ACTION_ENRAGE, + ACTION_TRAMPLE_FAIL, + ACTION_GORMOK_DEAD, + ACTION_JORMUNGARS_DEAD }; enum Events { // Gormok - EVENT_IMPALE = 1, + EVENT_ENGAGE = 1, + EVENT_IMPALE, EVENT_STAGGERING_STOMP, EVENT_THROW, @@ -138,11 +136,15 @@ enum Events EVENT_SNOBOLLED, EVENT_CHECK_MOUNT, + // Beasts Combat Stalker + EVENT_BERSERK, + EVENT_START_ICEHOWL, + EVENT_START_JORGMUNGARS, + // Acidmaw & Dreadscale EVENT_BITE, EVENT_SPEW, EVENT_SLIME_POOL, - EVENT_SPIT, EVENT_SPRAY, EVENT_SWEEP, EVENT_SUBMERGE, @@ -154,395 +156,513 @@ enum Events EVENT_MASSIVE_CRASH, EVENT_WHIRL, EVENT_ARCTIC_BREATH, + EVENT_SELECT_CHARGE_TARGET, + EVENT_ROAR_EMOTE, + EVENT_ICEHOWL_ROAR, + EVENT_JUMP_BACK, EVENT_TRAMPLE }; enum Phases { - PHASE_MOBILE = 1, - PHASE_STATIONARY = 2, - PHASE_SUBMERGED = 3 + PHASE_EVENT = 1, + PHASE_COMBAT, + PHASE_MOBILE, + PHASE_STATIONARY, + PHASE_SUBMERGED, + PHASE_CHARGE }; -enum GormokMisc +enum NorthrendBeastsPoint { - DATA_NEW_TARGET = 1, - GORMOK_HAND_SEAT = 4, - PLAYER_VEHICLE_ID = 444, + POINT_INITIAL_MOVEMENT = 1, + POINT_MIDDLE, + POINT_ICEHOWL_CHARGE }; -class boss_gormok : public CreatureScript +enum Misc { - public: - boss_gormok() : CreatureScript("boss_gormok") { } + DATA_NEW_TARGET = 1, + GORMOK_HAND_SEAT = 4, + MAX_SNOBOLDS = 4, + SPLINE_INITIAL_MOVEMENT = 1 +}; - struct boss_gormokAI : public BossAI - { - boss_gormokAI(Creature* creature) : BossAI(creature, DATA_GORMOK_THE_IMPALER) - { - SetBoundary(instance->GetBossBoundary(DATA_NORTHREND_BEASTS)); - } +Position const CombatStalkerPosition = { 563.8941f, 137.3333f, 405.8467f }; - void Reset() override - { - events.ScheduleEvent(EVENT_IMPALE, Seconds(8), Seconds(10)); - events.ScheduleEvent(EVENT_STAGGERING_STOMP, Seconds(15)); - events.ScheduleEvent(EVENT_THROW, Seconds(15), Seconds(30)); +class SnobolledTargetSelector +{ +public: + SnobolledTargetSelector() { } - summons.DespawnAll(); - } + bool operator()(Unit* unit) const + { + return unit->GetTypeId() == TYPEID_PLAYER && !unit->HasAura(SPELL_RIDE_PLAYER) && !unit->HasAura(SPELL_SNOBOLLED); + } +}; - void EnterEvadeMode(EvadeReason why) override - { - instance->DoUseDoorOrButton(instance->GetGuidData(DATA_MAIN_GATE)); - ScriptedAI::EnterEvadeMode(why); - } +struct boss_northrend_beastsAI : public BossAI +{ + boss_northrend_beastsAI(Creature* creature, uint32 bossId) : BossAI(creature, bossId) + { + SetBoundary(instance->GetBossBoundary(DATA_NORTHREND_BEASTS)); + Initialize(); + } - void MovementInform(uint32 type, uint32 pointId) override - { - if (type != POINT_MOTION_TYPE) - return; + void Reset() override + { + events.Reset(); + events.SetPhase(PHASE_EVENT); + summons.DespawnAll(); + me->SetReactState(REACT_PASSIVE); + me->SetCombatPulseDelay(0); + Initialize(); + HandleInitialMovement(); + } - switch (pointId) - { - case 0: - instance->DoUseDoorOrButton(instance->GetGuidData(DATA_MAIN_GATE)); - me->RemoveUnitFlag(UnitFlags(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE)); - me->SetImmuneToPC(false); - me->SetReactState(REACT_AGGRESSIVE); - me->SetInCombatWithZone(); - break; - default: - break; - } - } + void HandleInitialMovement() + { + switch (me->GetEntry()) + { + case NPC_GORMOK: + case NPC_DREADSCALE: + me->GetMotionMaster()->MoveAlongSplineChain(POINT_INITIAL_MOVEMENT, SPLINE_INITIAL_MOVEMENT, false); + break; + case NPC_ICEHOWL: + me->GetMotionMaster()->MoveAlongSplineChain(POINT_INITIAL_MOVEMENT, SPLINE_INITIAL_MOVEMENT, true); + break; + default: + break; + } + } - void JustDied(Unit* /*killer*/) override - { - instance->SetData(TYPE_NORTHREND_BEASTS, GORMOK_DONE); - } + void HandleWithHeroicEvents() + { + if (Creature* combatStalker = instance->GetCreature(DATA_BEASTS_COMBAT_STALKER)) + { + if (me->GetEntry() == NPC_GORMOK) + combatStalker->AI()->DoAction(ACTION_START_JORMUNGARS); + else if (me->GetEntry() == NPC_DREADSCALE) + combatStalker->AI()->DoAction(ACTION_START_ICEHOWL); + } + } - void JustReachedHome() override - { - instance->DoUseDoorOrButton(instance->GetGuidData(DATA_MAIN_GATE)); - instance->SetData(TYPE_NORTHREND_BEASTS, FAIL); + virtual void Initialize() { } - me->DespawnOrUnsummon(); - } + void EnterCombat(Unit* /*who*/) override + { + me->SetCombatPulseDelay(5); + me->setActive(true); + ScheduleTasks(); + HandleInstanceProgress(); + instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, me); + if (IsHeroic()) + HandleWithHeroicEvents(); + } - void EnterCombat(Unit* /*who*/) override - { - me->SetCombatPulseDelay(5); - me->setActive(true); - //DoZoneInCombat(); + void HandleInstanceProgress() + { + switch (me->GetEntry()) + { + case NPC_GORMOK: instance->SetData(TYPE_NORTHREND_BEASTS, GORMOK_IN_PROGRESS); - instance->SetBossState(DATA_NORTHREND_BEASTS, IN_PROGRESS); - } + break; + case NPC_ACIDMAW: + case NPC_DREADSCALE: + if (instance->GetData(TYPE_NORTHREND_BEASTS) != SNAKES_IN_PROGRESS) + instance->SetData(TYPE_NORTHREND_BEASTS, SNAKES_IN_PROGRESS); + break; + case NPC_ICEHOWL: + instance->SetData(TYPE_NORTHREND_BEASTS, ICEHOWL_IN_PROGRESS); + break; + default: + break; + } + } - void DamageTaken(Unit* /*who*/, uint32& damage) override - { - // despawn the remaining passengers on death - if (damage >= me->GetHealth()) - for (uint8 i = 0; i < MAX_SNOBOLDS; ++i) - if (Unit* snobold = me->GetVehicleKit()->GetPassenger(i)) - snobold->ToCreature()->DespawnOrUnsummon(); - } + void EnterEvadeMode(EvadeReason why) override + { + ScriptedAI::EnterEvadeMode(why); + instance->SetData(DATA_DESPAWN_SNOBOLDS, 0); + instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me); + // prevent losing 2 attempts at once on heroics + if (instance->GetData(TYPE_NORTHREND_BEASTS) != FAIL) + instance->SetData(TYPE_NORTHREND_BEASTS, FAIL); + if (Creature* combatStalker = instance->GetCreature(DATA_BEASTS_COMBAT_STALKER)) + combatStalker->DespawnOrUnsummon(); + summons.DespawnAll(); + me->DespawnOrUnsummon(); + } - void PassengerBoarded(Unit* who, int8 seatId, bool apply) override - { - if (apply && seatId == GORMOK_HAND_SEAT) - who->CastSpell(me, SPELL_RISING_ANGER, true); - } + void JustDied(Unit* /*killer*/) override + { + instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me); + if (me->GetEntry() == NPC_GORMOK) + { + instance->SetData(TYPE_NORTHREND_BEASTS, GORMOK_DONE); + if (Creature* combatStalker = instance->GetCreature(DATA_BEASTS_COMBAT_STALKER)) + combatStalker->AI()->DoAction(ACTION_GORMOK_DEAD); + } + else + instance->SetData(TYPE_NORTHREND_BEASTS, ICEHOWL_DONE); + } - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim() && !events.IsInPhase(PHASE_EVENT)) + return; + + events.Update(diff); - events.Update(diff); + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; + while (uint32 eventId = events.ExecuteEvent()) + { + ExecuteEvent(eventId); + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + } - while (uint32 eventId = events.ExecuteEvent()) + DoMeleeAttackIfReady(); + } +}; + +struct boss_gormok : public boss_northrend_beastsAI +{ + boss_gormok(Creature* creature) : boss_northrend_beastsAI(creature, DATA_GORMOK_THE_IMPALER) { } + + void ScheduleTasks() override + { + events.ScheduleEvent(EVENT_IMPALE, 10s); + events.ScheduleEvent(EVENT_STAGGERING_STOMP, 15s); + events.ScheduleEvent(EVENT_THROW, 20s); + } + + void PassengerBoarded(Unit* who, int8 seatId, bool apply) override + { + if (apply && seatId == GORMOK_HAND_SEAT) + who->CastSpell(who, SPELL_RISING_ANGER, true); + } + + void MovementInform(uint32 type, uint32 pointId) override + { + if (type == SPLINE_CHAIN_MOTION_TYPE && pointId == POINT_INITIAL_MOVEMENT) + events.ScheduleEvent(EVENT_ENGAGE, 7s); + } + + void ExecuteEvent(uint32 eventId) override + { + switch (eventId) + { + case EVENT_ENGAGE: + instance->DoUseDoorOrButton(instance->GetGuidData(DATA_MAIN_GATE)); + me->SetImmuneToPC(false); + me->SetReactState(REACT_AGGRESSIVE); + // Npc that should keep raid in combat while boss change + if (Creature* combatStalker = me->SummonCreature(NPC_BEASTS_COMBAT_STALKER, CombatStalkerPosition)) { - switch (eventId) + combatStalker->SetInCombatWithZone(); + combatStalker->SetCombatPulseDelay(5); + } + DoZoneInCombat(); + events.SetPhase(PHASE_COMBAT); + DoCastSelf(SPELL_TANKING_GORMOK, true); + break; + case EVENT_IMPALE: + DoCastVictim(SPELL_IMPALE); + events.Repeat(10s); + break; + case EVENT_STAGGERING_STOMP: + DoCastVictim(SPELL_STAGGERING_STOMP); + events.Repeat(22s); + break; + case EVENT_THROW: + for (uint8 i = 0; i < MAX_SNOBOLDS; ++i) + { + if (Unit* snobold = me->GetVehicleKit()->GetPassenger(i)) { - case EVENT_IMPALE: - DoCastVictim(SPELL_IMPALE); - events.Repeat(Seconds(8), Seconds(10)); - break; - case EVENT_STAGGERING_STOMP: - DoCastVictim(SPELL_STAGGERING_STOMP); - events.Repeat(Seconds(15)); - break; - case EVENT_THROW: - for (uint8 i = 0; i < MAX_SNOBOLDS; ++i) - { - if (Unit* snobold = me->GetVehicleKit()->GetPassenger(i)) - { - snobold->ExitVehicle(); - snobold->RemoveUnitFlag(UnitFlags(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE)); - snobold->GetAI()->DoAction(ACTION_DISABLE_FIRE_BOMB); - snobold->CastSpell(me, SPELL_JUMP_TO_HAND, true); - break; - } - } - events.Repeat(Seconds(15), Seconds(30)); - break; - default: - break; + snobold->ExitVehicle(); + snobold->RemoveUnitFlag(UnitFlags(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE)); + snobold->GetAI()->DoAction(ACTION_DISABLE_FIRE_BOMB); + snobold->CastSpell(me, SPELL_JUMP_TO_HAND, true); + break; } } - - DoMeleeAttackIfReady(); - } - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetTrialOfTheCrusaderAI<boss_gormokAI>(creature); + events.Repeat(20s); + break; + default: + break; } + } }; -class SnobolledTargetSelector : public std::unary_function<Unit*, bool> +struct npc_snobold_vassal : public ScriptedAI { -public: - SnobolledTargetSelector(Unit const* /*unit*/) { } + npc_snobold_vassal(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()), _mountedOnPlayer(false) + { + _instance->SetData(DATA_SNOBOLD_COUNT, INCREASE); + SetCombatMovement(false); + } - bool operator()(Unit* unit) const + bool CanAIAttack(Unit const* who) const override { - if (unit->GetTypeId() != TYPEID_PLAYER) + if (_mountedOnPlayer && who->GetGUID() != _targetGUID) return false; - if (unit->HasAura(SPELL_RIDE_PLAYER) || unit->HasAura(SPELL_SNOBOLLED)) - return false; + return ScriptedAI::CanAIAttack(who); + } - return true; + void AttackStart(Unit* victim) override + { + Creature* gormok = _instance->GetCreature(DATA_GORMOK_THE_IMPALER); + if (!_mountedOnPlayer && (!gormok || !gormok->IsAlive())) + AttackStartCaster(victim, 30.0f); + else + ScriptedAI::AttackStart(victim); } -}; -class npc_snobold_vassal : public CreatureScript -{ - public: - npc_snobold_vassal() : CreatureScript("npc_snobold_vassal") { } + void EnterCombat(Unit* /*who*/) override + { + _events.ScheduleEvent(EVENT_CHECK_MOUNT, 3s); + _events.ScheduleEvent(EVENT_FIRE_BOMB, 12s, 25s); + } - struct npc_snobold_vassalAI : public ScriptedAI + void JustDied(Unit* /*killer*/) override + { + _instance->SetData(DATA_SNOBOLD_COUNT, DECREASE); + } + + void DoAction(int32 action) override + { + switch (action) { - npc_snobold_vassalAI(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()), _isActive(false) - { - _instance->SetData(DATA_SNOBOLD_COUNT, INCREASE); - SetCombatMovement(false); - } + case ACTION_ENABLE_FIRE_BOMB: + _events.ScheduleEvent(EVENT_FIRE_BOMB, 12s, 25s); + break; + case ACTION_DISABLE_FIRE_BOMB: + _events.CancelEvent(EVENT_FIRE_BOMB); + break; + case ACTION_ACTIVE_SNOBOLD: + _mountedOnPlayer = true; + break; + default: + break; + } + } - void Reset() override + void SetGUID(ObjectGuid guid, int32 id) override + { + if (id == DATA_NEW_TARGET) + if (Unit* target = ObjectAccessor::GetPlayer(*me, guid)) { - me->AddUnitFlag(UnitFlags(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE)); - me->SetInCombatWithZone(); - _events.ScheduleEvent(EVENT_CHECK_MOUNT, Seconds(1)); - _events.ScheduleEvent(EVENT_FIRE_BOMB, Seconds(5), Seconds(30)); + _targetGUID = guid; + AttackStart(target); + _events.ScheduleEvent(EVENT_BATTER, 5s); + _events.ScheduleEvent(EVENT_SNOBOLLED, 1s); + _events.ScheduleEvent(EVENT_HEAD_CRACK, 1s); } + } - void JustDied(Unit* /*killer*/) override - { - if (Unit* target = ObjectAccessor::GetPlayer(*me, _targetGUID)) - target->RemoveAurasDueToSpell(SPELL_SNOBOLLED); - _instance->SetData(DATA_SNOBOLD_COUNT, DECREASE); - } + void MountOnBoss() + { + Unit* gormok = _instance->GetCreature(DATA_GORMOK_THE_IMPALER); + if (gormok && gormok->IsAlive()) + { + me->AttackStop(); + _targetGUID.Clear(); + _mountedOnPlayer = false; + _events.CancelEvent(EVENT_BATTER); + _events.CancelEvent(EVENT_HEAD_CRACK); - void DoAction(int32 action) override + for (uint8 i = 0; i < MAX_SNOBOLDS; i++) { - switch (action) + if (!gormok->GetVehicleKit()->GetPassenger(i)) { - case ACTION_ENABLE_FIRE_BOMB: - _events.ScheduleEvent(EVENT_FIRE_BOMB, Seconds(5), Seconds(30)); - break; - case ACTION_DISABLE_FIRE_BOMB: - _events.CancelEvent(EVENT_FIRE_BOMB); - break; - case ACTION_ACTIVE_SNOBOLD: - _isActive = true; - break; - default: - break; + me->EnterVehicle(gormok, i); + DoAction(ACTION_ENABLE_FIRE_BOMB); + break; } } + } + else + { + me->RemoveUnitFlag(UnitFlags(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE)); + _events.CancelEvent(EVENT_CHECK_MOUNT); + me->AttackStop(); + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true)) + AttackStart(target); + SetCombatMovement(true); + } + } - void SetGUID(ObjectGuid guid, int32 id) override - { - if (id == DATA_NEW_TARGET) - if (Unit* target = ObjectAccessor::GetPlayer(*me, guid)) - { - _targetGUID = guid; - AttackStart(target); - _events.ScheduleEvent(EVENT_BATTER, Seconds(5)); - _events.ScheduleEvent(EVENT_HEAD_CRACK, Seconds(25)); - _events.ScheduleEvent(EVENT_SNOBOLLED, Milliseconds(500)); - } - } + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; - void AttackStart(Unit* who) override - { - //Snobold only melee attack players that is your vehicle - if (!_isActive || who->GetGUID() != _targetGUID) - return; + _events.Update(diff); - ScriptedAI::AttackStart(who); - } + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; - void MountOnBoss() + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) { - Unit* gormok = _instance->GetCreature(DATA_GORMOK_THE_IMPALER); - if (gormok && gormok->IsAlive()) - { - me->AttackStop(); - _targetGUID.Clear(); - _isActive = false; - _events.CancelEvent(EVENT_BATTER); - _events.CancelEvent(EVENT_HEAD_CRACK); - - for (uint8 i = 0; i < MAX_SNOBOLDS; i++) - { - if (!gormok->GetVehicleKit()->GetPassenger(i)) - { - me->EnterVehicle(gormok, i); - DoAction(ACTION_ENABLE_FIRE_BOMB); - break; - } - } - } - //Without Boss, snobolds should jump in another players - else if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, SnobolledTargetSelector(me))) - me->CastSpell(target, SPELL_RIDE_PLAYER, true); + case EVENT_FIRE_BOMB: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true)) + me->CastSpell(target, SPELL_FIRE_BOMB); + _events.Repeat(20s, 30s); + break; + case EVENT_HEAD_CRACK: + if (Unit* target = me->GetVehicleBase()) + DoCast(target, SPELL_HEAD_CRACK); + _events.Repeat(30s); + break; + case EVENT_BATTER: + if (Unit* target = me->GetVehicleBase()) + DoCast(target, SPELL_BATTER); + _events.Repeat(10s, 15s); + break; + case EVENT_SNOBOLLED: + DoCastSelf(SPELL_SNOBOLLED); + break; + case EVENT_CHECK_MOUNT: + if (!me->GetVehicleBase()) + MountOnBoss(); + _events.Repeat(3s); + break; + default: + break; } - void UpdateAI(uint32 diff) override - { - _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, SPELL_FIRE_BOMB); - _events.Repeat(Seconds(20)); - break; - case EVENT_HEAD_CRACK: - DoCast(me->GetVehicleBase(), SPELL_HEAD_CRACK); - _events.Repeat(Seconds(30)); - break; - case EVENT_BATTER: - DoCast(me->GetVehicleBase(), SPELL_BATTER); - _events.Repeat(Seconds(10)); - break; - case EVENT_SNOBOLLED: - DoCastAOE(SPELL_SNOBOLLED); - break; - case EVENT_CHECK_MOUNT: - if (!me->GetVehicleBase()) - MountOnBoss(); - _events.Repeat(Seconds(1)); - break; - default: - break; - } + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + } - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - } + // do melee attack only if is in player back. + if (_mountedOnPlayer) + DoMeleeAttackIfReady(); + } - if (!UpdateVictim()) - return; +private: + EventMap _events; + InstanceScript* _instance; + ObjectGuid _targetGUID; + bool _mountedOnPlayer; +}; - // do melee attack only if is in player back. - if (_isActive) - DoMeleeAttackIfReady(); - } +struct npc_beasts_combat_stalker : public ScriptedAI +{ + npc_beasts_combat_stalker(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) { } - private: - EventMap _events; - InstanceScript* _instance; - ObjectGuid _targetGUID; - bool _isActive; - }; + void Reset() override + { + me->SetReactState(REACT_PASSIVE); + _events.ScheduleEvent(EVENT_BERSERK, IsHeroic() ? 9min : 15min); + } - CreatureAI* GetAI(Creature* creature) const override + void DoAction(int32 action) override + { + switch (action) { - return GetTrialOfTheCrusaderAI<npc_snobold_vassalAI>(creature); + case ACTION_START_JORMUNGARS: + _events.ScheduleEvent(EVENT_START_JORGMUNGARS, 2min + 30s); + break; + case ACTION_GORMOK_DEAD: + _events.CancelEvent(EVENT_START_JORGMUNGARS); + break; + case ACTION_START_ICEHOWL: + _events.ScheduleEvent(EVENT_START_ICEHOWL, 2min + 30s); + break; + case ACTION_JORMUNGARS_DEAD: + _events.CancelEvent(EVENT_START_ICEHOWL); + break; + default: + break; } -}; + } -class npc_firebomb : public CreatureScript -{ - public: - npc_firebomb() : CreatureScript("npc_firebomb") { } + void UpdateAI(uint32 diff) override + { + _events.Update(diff); - struct npc_firebombAI : public ScriptedAI + while (uint32 eventId = _events.ExecuteEvent()) { - npc_firebombAI(Creature* creature) : ScriptedAI(creature) - { - _instance = creature->GetInstanceScript(); - } - - void Reset() override - { - DoCast(me, SPELL_FIRE_BOMB_DOT, true); - SetCombatMovement(false); - me->SetReactState(REACT_PASSIVE); - me->SetDisplayFromModel(1); - } - - void UpdateAI(uint32 /*diff*/) override + switch (eventId) { - if (_instance->GetData(TYPE_NORTHREND_BEASTS) != GORMOK_IN_PROGRESS) - me->DespawnOrUnsummon(); + case EVENT_BERSERK: + if (Creature* gormok = _instance->GetCreature(DATA_GORMOK_THE_IMPALER)) + gormok->CastSpell(gormok, SPELL_BERSERK, true); + + if (Creature* dreadscale = _instance->GetCreature(DATA_DREADSCALE)) + dreadscale->CastSpell(dreadscale, SPELL_BERSERK, true); + + if (Creature* acidmaw = _instance->GetCreature(DATA_ACIDMAW)) + acidmaw->CastSpell(acidmaw, SPELL_BERSERK, true); + + if (Creature* icehowl = _instance->GetCreature(DATA_ICEHOWL)) + icehowl->CastSpell(icehowl, SPELL_BERSERK, true); + break; + case EVENT_START_JORGMUNGARS: + if (Creature* tirion = _instance->GetCreature(DATA_FORDRING)) + tirion->AI()->DoAction(ACTION_START_JORMUNGARS); + break; + case EVENT_START_ICEHOWL: + if (Creature* tirion = _instance->GetCreature(DATA_FORDRING)) + tirion->AI()->DoAction(ACTION_START_ICEHOWL); + break; + default: + break; } - - private: - InstanceScript* _instance; - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetTrialOfTheCrusaderAI<npc_firebombAI>(creature); } + } + +private: + EventMap _events; + InstanceScript* _instance; }; -struct boss_jormungarAI : public BossAI +struct boss_jormungarAI : public boss_northrend_beastsAI { - boss_jormungarAI(Creature* creature, uint32 bossId) : BossAI(creature, bossId) - { - OtherWormEntry = 0; - ModelStationary = 0; - ModelMobile = 0; + boss_jormungarAI(Creature* creature, uint32 bossId) : boss_northrend_beastsAI(creature, bossId) { } - BiteSpell = 0; - SpewSpell = 0; - SpitSpell = 0; - SpraySpell = 0; + void Initialize() override + { + otherWormEntry = 0; + modelStationary = 0; + modelMobile = 0; + biteSpell = 0; + spewSpell = 0; + spitSpell = 0; + spraySpell = 0; + wasMobile = false; + } - Phase = PHASE_MOBILE; - Enraged = false; - WasMobile = false; - SetBoundary(instance->GetBossBoundary(DATA_NORTHREND_BEASTS)); + void JustSummoned(Creature* summoned) override + { + if (summoned->GetEntry() == NPC_ACIDMAW) + BossAI::JustSummoned(summoned); + else + summons.Summon(summoned); } - void Reset() override + void ScheduleTasks() override { - Enraged = false; + if (events.IsInPhase(PHASE_STATIONARY)) + { + events.ScheduleEvent(EVENT_SPRAY, me->GetEntry() == NPC_DREADSCALE ? 17s : 9s, 0, PHASE_STATIONARY); + events.ScheduleEvent(EVENT_SWEEP, 16s, 0, PHASE_STATIONARY); + } + else + { + events.ScheduleEvent(EVENT_BITE, 5s, 0, PHASE_MOBILE); + events.ScheduleEvent(EVENT_SPEW, 10s, 0, PHASE_MOBILE); + events.ScheduleEvent(EVENT_SLIME_POOL, 14s, 0, PHASE_MOBILE); + } - 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); + events.ScheduleEvent(EVENT_SUBMERGE, 45s); } uint32 GetOtherWormData(uint32 wormEntry) @@ -552,825 +672,508 @@ struct boss_jormungarAI : public BossAI void JustDied(Unit* /*killer*/) override { - if (Creature* otherWorm = instance->GetCreature(GetOtherWormData(OtherWormEntry))) + if (Creature* otherWorm = instance->GetCreature(GetOtherWormData(otherWormEntry))) { if (!otherWorm->IsAlive()) { instance->SetData(TYPE_NORTHREND_BEASTS, SNAKES_DONE); - me->DespawnOrUnsummon(); otherWorm->DespawnOrUnsummon(); + if (Creature* combatStalker = instance->GetCreature(DATA_BEASTS_COMBAT_STALKER)) + combatStalker->AI()->DoAction(ACTION_JORMUNGARS_DEAD); } else + { instance->SetData(TYPE_NORTHREND_BEASTS, SNAKES_SPECIAL); + otherWorm->AI()->DoAction(ACTION_ENRAGE); + } } + instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me); } - void JustReachedHome() override - { - // prevent losing 2 attempts at once on heroics - if (instance->GetData(TYPE_NORTHREND_BEASTS) != FAIL) - instance->SetData(TYPE_NORTHREND_BEASTS, FAIL); - - me->DespawnOrUnsummon(); - } - - void EnterCombat(Unit* /*who*/) override + void DoAction(int32 action) override { - _EnterCombat(); - me->SetInCombatWithZone(); - instance->SetData(TYPE_NORTHREND_BEASTS, SNAKES_IN_PROGRESS); + if (action == ACTION_ENRAGE) + { + DoCastSelf(SPELL_ENRAGE, true); + Talk(EMOTE_ENRAGE); + if (events.IsInPhase(PHASE_SUBMERGED)) + events.RescheduleEvent(EVENT_EMERGE, 1ms); + } } - void UpdateAI(uint32 diff) override + void Submerge() { - if (!UpdateVictim()) - return; + me->SetReactState(REACT_PASSIVE); + me->AttackStop(); - if (!Enraged && instance->GetData(TYPE_NORTHREND_BEASTS) == SNAKES_SPECIAL) + if (wasMobile) { - me->RemoveAurasDueToSpell(SPELL_SUBMERGE); - me->RemoveUnitFlag(UnitFlags(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE)); - DoCast(SPELL_ENRAGE); - Enraged = true; - Talk(EMOTE_ENRAGE); + me->HandleEmoteCommand(EMOTE_ONESHOT_SUBMERGE); + DoCastSelf(SPELL_SUBMERGE); + me->SetSpeedRate(MOVE_RUN, 8.0f); + DoCastSelf(SPELL_GROUND_VISUAL_0, true); + events.SetPhase(PHASE_SUBMERGED); + events.ScheduleEvent(EVENT_EMERGE, 5s, 0, PHASE_SUBMERGED); + me->AddUnitFlag(UnitFlags(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE)); } - - events.Update(diff); - - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - while (uint32 eventId = events.ExecuteEvent()) + else { - 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); - 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->RemoveUnitFlag(UnitFlags(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE)); - acidmaw->SetImmuneToPC(false); - acidmaw->SetReactState(REACT_AGGRESSIVE); - acidmaw->SetInCombatWithZone(); - acidmaw->CastSpell(acidmaw, SPELL_EMERGE); - acidmaw->CastSpell(acidmaw, SPELL_GROUND_VISUAL_1, true); - } - 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); - events.ScheduleEvent(EVENT_SWEEP, urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS), 0, PHASE_STATIONARY); - return; - default: - return; - } + me->HandleEmoteCommand(EMOTE_ONESHOT_SUBMERGE); + DoCastSelf(SPELL_SUBMERGE_2); + me->RemoveAurasDueToSpell(SPELL_GROUND_VISUAL_1); + me->SetSpeedRate(MOVE_RUN, 1.1111f); + DoCastSelf(SPELL_GROUND_VISUAL_0, true); + events.SetPhase(PHASE_SUBMERGED); + me->SetControlled(false, UNIT_STATE_ROOT); + events.ScheduleEvent(EVENT_EMERGE, 6s, 0, PHASE_SUBMERGED); + me->AddUnitFlag(UnitFlags(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE)); } - if (events.IsInPhase(PHASE_MOBILE)) - DoMeleeAttackIfReady(); - if (events.IsInPhase(PHASE_STATIONARY)) - DoCastVictim(SpitSpell); - } - - void Submerge() - { - DoCast(me, SPELL_SUBMERGE); - DoCast(me, SPELL_GROUND_VISUAL_0, true); - me->RemoveAurasDueToSpell(SPELL_EMERGE); - me->SetInCombatWithZone(); - events.SetPhase(PHASE_SUBMERGED); - events.ScheduleEvent(EVENT_EMERGE, 5*IN_MILLISECONDS, 0, PHASE_SUBMERGED); - me->AddUnitFlag(UnitFlags(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() + me->GetMidsectionHeight()); - WasMobile = !WasMobile; } void Emerge() { - DoCast(me, SPELL_EMERGE); - DoCastAOE(SPELL_HATE_TO_ZERO, true); - me->SetDisplayId(ModelMobile); - me->RemoveAurasDueToSpell(SPELL_SUBMERGE); + me->UpdateSpeed(MOVE_RUN); + uint32 submergeSpell = wasMobile ? SPELL_SUBMERGE : SPELL_SUBMERGE_2; + me->RemoveAurasDueToSpell(submergeSpell); me->RemoveAurasDueToSpell(SPELL_GROUND_VISUAL_0); + DoCastSelf(SPELL_EMERGE); + DoCastAOE(SPELL_HATE_TO_ZERO, true); me->RemoveUnitFlag(UnitFlags(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE)); + me->SetReactState(REACT_AGGRESSIVE); + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) + AttackStart(target); // if the worm was mobile before submerging, make him stationary now - if (WasMobile) + if (wasMobile) { me->SetControlled(true, UNIT_STATE_ROOT); - SetCombatMovement(false); - me->SetDisplayId(ModelStationary); - me->CastSpell(me, SPELL_GROUND_VISUAL_1, true); + me->SetDisplayId(modelStationary); + DoCastSelf(SPELL_GROUND_VISUAL_1, true); 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->SetControlled(false, UNIT_STATE_ROOT); - SetCombatMovement(true); - me->GetMotionMaster()->MoveChase(me->GetVictim()); - me->SetDisplayId(ModelMobile); - me->RemoveAurasDueToSpell(SPELL_GROUND_VISUAL_1); + if (Unit* target = me->GetVictim()) + me->GetMotionMaster()->MoveChase(target); + 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); } + wasMobile = !wasMobile; + ScheduleTasks(); } - protected: - uint32 OtherWormEntry; - uint32 ModelStationary; - uint32 ModelMobile; - - uint32 BiteSpell; - uint32 SpewSpell; - uint32 SpitSpell; - uint32 SpraySpell; - - Phases Phase; - bool Enraged; - bool WasMobile; -}; - -class boss_acidmaw : public CreatureScript -{ - public: - boss_acidmaw() : CreatureScript("boss_acidmaw") { } - - struct boss_acidmawAI : public boss_jormungarAI - { - boss_acidmawAI(Creature* creature) : boss_jormungarAI(creature, DATA_ACIDMAW) { } - - void Reset() override - { - 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 override - { - return GetTrialOfTheCrusaderAI<boss_acidmawAI>(creature); - } -}; - -class boss_dreadscale : public CreatureScript -{ - public: - boss_dreadscale() : CreatureScript("boss_dreadscale") { } - - struct boss_dreadscaleAI : public boss_jormungarAI + void ExecuteEvent(uint32 eventId) override + { + switch (eventId) { - boss_dreadscaleAI(Creature* creature) : boss_jormungarAI(creature, DATA_DREADSCALE) { } - - void Reset() override - { - 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 MovementInform(uint32 type, uint32 pointId) override - { - if (type != POINT_MOTION_TYPE) - return; - - switch (pointId) + case EVENT_ENGAGE: + if (me->GetEntry() == NPC_DREADSCALE) { - case 0: - instance->DoCloseDoorOrButton(instance->GetGuidData(DATA_MAIN_GATE)); - me->RemoveUnitFlag(UnitFlags(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE)); - me->SetImmuneToPC(false); - me->SetReactState(REACT_AGGRESSIVE); - me->SetInCombatWithZone(); - break; - default: - break; + instance->DoCloseDoorOrButton(instance->GetGuidData(DATA_MAIN_GATE)); + me->SetImmuneToPC(false); + events.SetPhase(PHASE_MOBILE); + me->SetReactState(REACT_AGGRESSIVE); + DoZoneInCombat(); + events.ScheduleEvent(EVENT_SUMMON_ACIDMAW, 1ms); } - } + else + { + me->SetReactState(REACT_AGGRESSIVE); + DoZoneInCombat(); + } + break; + case EVENT_EMERGE: + Emerge(); + break; + case EVENT_SUBMERGE: + Submerge(); + break; + case EVENT_BITE: + DoCastVictim(biteSpell); + events.Repeat(15s); + break; + case EVENT_SPEW: + DoCastAOE(spewSpell); + events.Repeat(21s); + break; + case EVENT_SLIME_POOL: + DoCastSelf(SUMMON_SLIME_POOL); + events.Repeat(12s); + break; + case EVENT_SUMMON_ACIDMAW: + me->SummonCreature(NPC_ACIDMAW, ToCCommonLoc[9]); + break; + case EVENT_SPRAY: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 0.0f, true)) + DoCast(target, spraySpell); + events.Repeat(21s); + break; + case EVENT_SWEEP: + DoCastAOE(SPELL_SWEEP); + events.Repeat(17s); + break; + default: + break; + } + } - void EnterEvadeMode(EvadeReason why) override - { - instance->DoUseDoorOrButton(instance->GetGuidData(DATA_MAIN_GATE)); - boss_jormungarAI::EnterEvadeMode(why); - } + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim() && !events.IsInPhase(PHASE_EVENT)) + return; - void JustReachedHome() override - { - instance->DoUseDoorOrButton(instance->GetGuidData(DATA_MAIN_GATE)); + events.Update(diff); - boss_jormungarAI::JustReachedHome(); - } - }; + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; - CreatureAI* GetAI(Creature* creature) const override + while (uint32 eventId = events.ExecuteEvent()) { - return GetTrialOfTheCrusaderAI<boss_dreadscaleAI>(creature); + ExecuteEvent(eventId); + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; } -}; - -class npc_slime_pool : public CreatureScript -{ - public: - npc_slime_pool() : CreatureScript("npc_slime_pool") { } - struct npc_slime_poolAI : public ScriptedAI - { - npc_slime_poolAI(Creature* creature) : ScriptedAI(creature) - { - Initialize(); - _instance = creature->GetInstanceScript(); - } - - void Initialize() - { - _cast = false; - } - - void Reset() override - { - Initialize(); - me->SetReactState(REACT_PASSIVE); - } - - void UpdateAI(uint32 /*diff*/) override - { - if (!_cast) - { - _cast = true; - DoCast(me, SPELL_SLIME_POOL_EFFECT); - } - - if (_instance->GetData(TYPE_NORTHREND_BEASTS) != SNAKES_IN_PROGRESS && _instance->GetData(TYPE_NORTHREND_BEASTS) != SNAKES_SPECIAL) - me->DespawnOrUnsummon(); - } - private: - InstanceScript* _instance; - bool _cast; - - }; + if (events.IsInPhase(PHASE_MOBILE)) + DoMeleeAttackIfReady(); + else + DoCastVictim(spitSpell); + } - CreatureAI* GetAI(Creature* creature) const override - { - return GetTrialOfTheCrusaderAI<npc_slime_poolAI>(creature); - } + protected: + uint32 otherWormEntry; + uint32 modelStationary; + uint32 modelMobile; + uint32 biteSpell; + uint32 spewSpell; + uint32 spitSpell; + uint32 spraySpell; + bool wasMobile; }; -class spell_gormok_fire_bomb : public SpellScriptLoader +struct boss_dreadscale : public boss_jormungarAI { - public: - spell_gormok_fire_bomb() : SpellScriptLoader("spell_gormok_fire_bomb") { } + boss_dreadscale(Creature* creature) : boss_jormungarAI(creature, DATA_DREADSCALE) { } - class spell_gormok_fire_bomb_SpellScript : public SpellScript - { - PrepareSpellScript(spell_gormok_fire_bomb_SpellScript); - - void TriggerFireBomb(SpellEffIndex /*effIndex*/) - { - if (WorldLocation const* 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() override - { - OnEffectHit += SpellEffectFn(spell_gormok_fire_bomb_SpellScript::TriggerFireBomb, EFFECT_0, SPELL_EFFECT_TRIGGER_MISSILE); - } - }; + void Reset() override + { + boss_northrend_beastsAI::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; + wasMobile = true; + } - SpellScript* GetSpellScript() const override - { - return new spell_gormok_fire_bomb_SpellScript(); - } + void MovementInform(uint32 type, uint32 pointId) override + { + if (type == SPLINE_CHAIN_MOTION_TYPE && pointId == POINT_INITIAL_MOVEMENT) + events.ScheduleEvent(EVENT_ENGAGE, Seconds(3)); + } }; -class boss_icehowl : public CreatureScript +struct boss_acidmaw : public boss_jormungarAI { - public: - boss_icehowl() : CreatureScript("boss_icehowl") { } - - struct boss_icehowlAI : public BossAI - { - boss_icehowlAI(Creature* creature) : BossAI(creature, DATA_ICEHOWL) - { - Initialize(); - SetBoundary(instance->GetBossBoundary(DATA_NORTHREND_BEASTS)); - } - - void Initialize() - { - _movementStarted = false; - _movementFinish = false; - _trampleCast = false; - _trampleTargetGUID.Clear(); - _trampleTargetX = 0; - _trampleTargetY = 0; - _trampleTargetZ = 0; - _stage = 0; - } + boss_acidmaw(Creature* creature) : boss_jormungarAI(creature, DATA_ACIDMAW) { } - void Reset() override - { - 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); - Initialize(); - } - - void JustDied(Unit* /*killer*/) override - { - _JustDied(); - instance->SetData(TYPE_NORTHREND_BEASTS, ICEHOWL_DONE); - } - - void MovementInform(uint32 type, uint32 pointId) override - { - if (type != POINT_MOTION_TYPE && type != EFFECT_MOTION_TYPE) - return; - - switch (pointId) - { - case 0: - if (_stage != 0) - { - 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 (ObjectAccessor::GetPlayer(*me, _trampleTargetGUID)) - _stage = 4; - else - _stage = 6; - } - } - break; - case 1: // Finish trample - _movementFinish = true; - break; - case 2: - instance->DoUseDoorOrButton(instance->GetGuidData(DATA_MAIN_GATE)); - me->RemoveUnitFlag(UnitFlags(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE)); - me->SetImmuneToPC(false); - me->SetReactState(REACT_AGGRESSIVE); - me->SetInCombatWithZone(); - break; - default: - break; - } - } - - void EnterEvadeMode(EvadeReason why) override - { - instance->DoUseDoorOrButton(instance->GetGuidData(DATA_MAIN_GATE)); - ScriptedAI::EnterEvadeMode(why); - } - - void JustReachedHome() override - { - instance->DoUseDoorOrButton(instance->GetGuidData(DATA_MAIN_GATE)); - instance->SetData(TYPE_NORTHREND_BEASTS, FAIL); - me->DespawnOrUnsummon(); - } - - void EnterCombat(Unit* /*who*/) override - { - _EnterCombat(); - instance->SetData(TYPE_NORTHREND_BEASTS, ICEHOWL_IN_PROGRESS); - } + void Reset() override + { + boss_northrend_beastsAI::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; + events.SetPhase(PHASE_STATIONARY); + wasMobile = false; + me->SetControlled(true, UNIT_STATE_ROOT); + DoCastSelf(SPELL_GROUND_VISUAL_1, true); + events.ScheduleEvent(EVENT_ENGAGE, Seconds(3)); + } +}; - void SpellHitTarget(Unit* target, SpellInfo const* spell) override - { - if (spell->Id == SPELL_TRAMPLE && target->GetTypeId() == TYPEID_PLAYER) - { - if (!_trampleCast) - { - DoCast(me, SPELL_FROTHING_RAGE, true); - _trampleCast = true; - } - } - } +struct npc_jormungars_slime_pool : public ScriptedAI +{ + npc_jormungars_slime_pool(Creature* creature) : ScriptedAI(creature) { } - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; + void Reset() override + { + DoCastSelf(SPELL_SLIME_POOL_EFFECT, true); + DoCastSelf(SPELL_PACIFY_SELF, true); + } +}; - events.Update(diff); +struct boss_icehowl : public boss_northrend_beastsAI +{ + boss_icehowl(Creature* creature) : boss_northrend_beastsAI(creature, DATA_ICEHOWL) { } - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; + void ScheduleTasks() override + { + events.ScheduleEvent(EVENT_FEROCIOUS_BUTT, 8s, 0, PHASE_COMBAT); + events.ScheduleEvent(EVENT_ARCTIC_BREATH, 20s, 0, PHASE_COMBAT); + events.ScheduleEvent(EVENT_WHIRL, 15s, 0, PHASE_COMBAT); + events.ScheduleEvent(EVENT_MASSIVE_CRASH, 35s, 0, PHASE_COMBAT); + } - 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], 20.0f, 20.0f, 0); // 1: Middle of the room - SetCombatMovement(false); - me->AttackStop(); - _stage = 7; //Invalid (Do nothing more than move) - return; - default: - break; - } - - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - } - DoMeleeAttackIfReady(); - break; - } - case 1: - DoCastAOE(SPELL_MASSIVE_CRASH); - me->StopMoving(); - me->AttackStop(); - _stage = 2; - break; - case 2: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true)) - { - me->StopMoving(); - me->AttackStop(); - _trampleTargetGUID = target->GetGUID(); - me->SetTarget(_trampleTargetGUID); - _trampleCast = false; - SetCombatMovement(false); - me->AddUnitFlag(UNIT_FLAG_NON_ATTACKABLE); - me->SetControlled(true, UNIT_STATE_ROOT); - 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()) - { - switch (eventId) - { - case EVENT_TRAMPLE: - { - if (Unit* target = ObjectAccessor::GetPlayer(*me, _trampleTargetGUID)) - { - me->StopMoving(); - me->AttackStop(); - _trampleCast = 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(), me->GetOrientation(), 30.0f, 20.0f, 0); - me->SetControlled(false, UNIT_STATE_ROOT); - _stage = 7; //Invalid (Do nothing more than move) - } - else - _stage = 6; - break; - } - default: - break; - } - - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - } - break; - case 4: - me->StopMoving(); - me->AttackStop(); - if (Player* target = ObjectAccessor::GetPlayer(*me, _trampleTargetGUID)) - Talk(EMOTE_TRAMPLE_START, target); - me->GetMotionMaster()->MoveCharge(_trampleTargetX, _trampleTargetY, _trampleTargetZ, 42, 1); - me->SetTarget(ObjectGuid::Empty); - _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 (!_trampleCast) - { - DoCast(me, SPELL_STAGGERED_DAZE); - Talk(EMOTE_TRAMPLE_CRASH); - } - else - { - DoCast(me, SPELL_FROTHING_RAGE, true); - Talk(EMOTE_TRAMPLE_FAIL); - } - _movementStarted = false; - me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE); - 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; - } - } + void RescheduleTasks() + { + events.ScheduleEvent(EVENT_FEROCIOUS_BUTT, 8s, 0, PHASE_COMBAT); + events.ScheduleEvent(EVENT_ARCTIC_BREATH, 20s, 0, PHASE_COMBAT); + events.ScheduleEvent(EVENT_WHIRL, 15s, 0, PHASE_COMBAT); + events.ScheduleEvent(EVENT_MASSIVE_CRASH, 45s, 0, PHASE_COMBAT); + } - private: - float _trampleTargetX, _trampleTargetY, _trampleTargetZ; - ObjectGuid _trampleTargetGUID; - bool _movementStarted; - bool _movementFinish; - bool _trampleCast; - uint8 _stage; - }; + void MovementInform(uint32 type, uint32 pointId) override + { + if (type != POINT_MOTION_TYPE && type != EFFECT_MOTION_TYPE && type != SPLINE_CHAIN_MOTION_TYPE) + return; - CreatureAI* GetAI(Creature* creature) const override + switch (pointId) { - return GetTrialOfTheCrusaderAI<boss_icehowlAI>(creature); + case POINT_INITIAL_MOVEMENT: + events.ScheduleEvent(EVENT_ENGAGE, 3s); + break; + case POINT_MIDDLE: + DoCastSelf(SPELL_MASSIVE_CRASH); + events.ScheduleEvent(EVENT_SELECT_CHARGE_TARGET, 4s); + break; + case POINT_ICEHOWL_CHARGE: + events.Reset(); + events.SetPhase(PHASE_COMBAT); + RescheduleTasks(); + me->SetReactState(REACT_AGGRESSIVE); + DoCastSelf(SPELL_TRAMPLE); + break; + default: + break; } -}; - -class spell_gormok_jump_to_hand : public SpellScriptLoader -{ -public: - spell_gormok_jump_to_hand() : SpellScriptLoader("spell_gormok_jump_to_hand") { } + } - class spell_gormok_jump_to_hand_AuraScript : public AuraScript + void DoAction(int32 action) override { - PrepareAuraScript(spell_gormok_jump_to_hand_AuraScript); - - bool Validate(SpellInfo const* /*spellInfo*/) override + if (action == ACTION_ENRAGE) { - return ValidateSpellInfo({ SPELL_RIDE_PLAYER }); + DoCastSelf(SPELL_FROTHING_RAGE, true); + Talk(EMOTE_TRAMPLE_ENRAGE); } - - bool Load() override + else if (action == ACTION_TRAMPLE_FAIL) { - if (GetCaster() && GetCaster()->GetEntry() == NPC_SNOBOLD_VASSAL) - return true; - return false; + DoCastSelf(SPELL_STAGGERED_DAZE, true); + Talk(EMOTE_TRAMPLE_FAIL); + events.DelayEvents(15s); } + } - void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + void ExecuteEvent(uint32 eventId) override + { + switch (eventId) { - if (Unit* caster = GetCaster()) - { - if (CreatureAI* gormokAI = GetTarget()->ToCreature()->AI()) + case EVENT_ENGAGE: + instance->DoCloseDoorOrButton(instance->GetGuidData(DATA_MAIN_GATE)); + me->SetImmuneToPC(false); + events.SetPhase(PHASE_COMBAT); + me->SetReactState(REACT_AGGRESSIVE); + DoZoneInCombat(); + break; + case EVENT_MASSIVE_CRASH: + me->SetReactState(REACT_PASSIVE); + me->AttackStop(); + events.SetPhase(PHASE_CHARGE); + me->GetMotionMaster()->MoveJump(ToCCommonLoc[1], 20.0f, 20.0f, POINT_MIDDLE); + break; + case EVENT_SELECT_CHARGE_TARGET: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true)) { - if (Unit* target = gormokAI->SelectTarget(SELECT_TARGET_RANDOM, 0, SnobolledTargetSelector(GetTarget()))) - { - gormokAI->Talk(EMOTE_SNOBOLLED); - caster->GetAI()->DoAction(ACTION_ACTIVE_SNOBOLD); - caster->CastSpell(target, SPELL_RIDE_PLAYER, true); - } + DoCast(target, SPELL_FURIOUS_CHARGE_SUMMON, true); + me->SetTarget(target->GetGUID()); + Talk(EMOTE_TRAMPLE_ROAR, target); + events.ScheduleEvent(EVENT_ICEHOWL_ROAR, 1s); } - } - } - - void Register() override - { - AfterEffectRemove += AuraEffectRemoveFn(spell_gormok_jump_to_hand_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_CONTROL_VEHICLE, AURA_EFFECT_HANDLE_REAL); + break; + case EVENT_ICEHOWL_ROAR: + if (Creature* stalker = instance->GetCreature(DATA_FURIOUS_CHARGE)) + DoCast(stalker, SPELL_ROAR); + events.ScheduleEvent(EVENT_JUMP_BACK, 3s, 0, PHASE_CHARGE); + break; + case EVENT_JUMP_BACK: + if (Creature* stalker = instance->GetCreature(DATA_FURIOUS_CHARGE)) + DoCast(stalker, SPELL_JUMP_BACK); + events.ScheduleEvent(EVENT_TRAMPLE, 2s, 0, PHASE_CHARGE); + break; + case EVENT_TRAMPLE: + if (Creature* stalker = instance->GetCreature(DATA_FURIOUS_CHARGE)) + me->GetMotionMaster()->MoveCharge(stalker->GetPositionX(), stalker->GetPositionY(), stalker->GetPositionZ(), 42.0f, POINT_ICEHOWL_CHARGE); + me->SetTarget(ObjectGuid::Empty); + break; + case EVENT_FEROCIOUS_BUTT: + DoCastVictim(SPELL_FEROCIOUS_BUTT); + events.Repeat(20s); + break; + case EVENT_ARCTIC_BREATH: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true)) + DoCast(target, SPELL_ARCTIC_BREATH); + events.Repeat(24s); + break; + case EVENT_WHIRL: + DoCastSelf(SPELL_WHIRL); + events.Repeat(16s); + break; + default: + break; } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_gormok_jump_to_hand_AuraScript(); } }; -class spell_gormok_ride_player : public SpellScriptLoader +// 66342 - Jump to Hand +class spell_gormok_jump_to_hand : public AuraScript { -public: - spell_gormok_ride_player() : SpellScriptLoader("spell_gormok_ride_player") { } + PrepareAuraScript(spell_gormok_jump_to_hand); - class spell_gormok_ride_player_AuraScript : public AuraScript + bool Validate(SpellInfo const* /*spell*/) override { - PrepareAuraScript(spell_gormok_ride_player_AuraScript); + return ValidateSpellInfo({ SPELL_RIDE_PLAYER }); + } - bool Load() override - { - if (GetCaster() && GetCaster()->GetEntry() == NPC_SNOBOLD_VASSAL) - return true; - return false; - } + void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + Unit* caster = GetCaster(); + if (!caster || caster->GetEntry() != NPC_SNOBOLD_VASSAL) + return; - void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) - { - Unit* target = GetTarget(); - if (target->GetTypeId() != TYPEID_PLAYER || !target->IsInWorld()) - return; + if (Creature* gormok = GetTarget()->ToCreature()) + if (Unit* target = gormok->AI()->SelectTarget(SELECT_TARGET_RANDOM, 0, SnobolledTargetSelector())) + { + gormok->AI()->Talk(EMOTE_SNOBOLLED); + caster->GetAI()->DoAction(ACTION_ACTIVE_SNOBOLD); + caster->CastSpell(target, SPELL_RIDE_PLAYER, true); + } + } - if (!target->CreateVehicleKit(PLAYER_VEHICLE_ID, 0)) - return; + void Register() override + { + AfterEffectRemove += AuraEffectRemoveFn(spell_gormok_jump_to_hand::OnRemove, EFFECT_0, SPELL_AURA_CONTROL_VEHICLE, AURA_EFFECT_HANDLE_REAL); + } +}; - if (Unit *caster = GetCaster()) - caster->GetAI()->SetGUID(target->GetGUID(), DATA_NEW_TARGET); - } +// 66245 - Ride Vehicle +class spell_gormok_ride_player : public AuraScript +{ + PrepareAuraScript(spell_gormok_ride_player); - void AfterRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) - { - GetTarget()->RemoveVehicleKit(); - } + void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + Unit* target = GetTarget(); + if (target->GetTypeId() != TYPEID_PLAYER || !target->IsInWorld()) + return; - void Register() override - { - OnEffectApply += AuraEffectApplyFn(spell_gormok_ride_player_AuraScript::OnApply, EFFECT_0, SPELL_AURA_CONTROL_VEHICLE, AURA_EFFECT_HANDLE_REAL); - AfterEffectRemove += AuraEffectRemoveFn(spell_gormok_ride_player_AuraScript::AfterRemove, EFFECT_0, SPELL_AURA_CONTROL_VEHICLE, AURA_EFFECT_HANDLE_REAL); - } - }; + if (Unit *caster = GetCaster()) + if (caster->IsAIEnabled) + caster->GetAI()->SetGUID(target->GetGUID(), DATA_NEW_TARGET); + } - AuraScript* GetAuraScript() const override + void Register() override { - return new spell_gormok_ride_player_AuraScript(); + OnEffectApply += AuraEffectApplyFn(spell_gormok_ride_player::OnApply, EFFECT_0, SPELL_AURA_CONTROL_VEHICLE, AURA_EFFECT_HANDLE_REAL); } }; -class spell_gormok_snobolled : public SpellScriptLoader +// 66406 - Snobolled! +class spell_gormok_snobolled : public AuraScript { -public: - spell_gormok_snobolled() : SpellScriptLoader("spell_gormok_snobolled") { } + PrepareAuraScript(spell_gormok_snobolled); - class spell_gormok_snobolled_AuraScript : public AuraScript + bool Validate(SpellInfo const* /*spell*/) override { - PrepareAuraScript(spell_gormok_snobolled_AuraScript); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_RIDE_PLAYER }); - } - - void OnPeriodic(AuraEffect const* /*aurEff*/) - { - if (!GetTarget()->HasAura(SPELL_RIDE_PLAYER)) - Remove(); - } + return ValidateSpellInfo({ SPELL_RIDE_PLAYER }); + } - void Register() override - { - OnEffectPeriodic += AuraEffectPeriodicFn(spell_gormok_snobolled_AuraScript::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY); - } - }; + void OnPeriodic(AuraEffect const* /*aurEff*/) + { + if (!GetTarget()->HasAura(SPELL_RIDE_PLAYER)) + Remove(); + } - AuraScript* GetAuraScript() const override + void Register() override { - return new spell_gormok_snobolled_AuraScript(); + OnEffectPeriodic += AuraEffectPeriodicFn(spell_gormok_snobolled::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY); } }; -class spell_jormungars_paralytic_toxin : public SpellScriptLoader +// 66823 - Paralytic Toxin +class spell_jormungars_paralytic_toxin : public AuraScript { -public: - spell_jormungars_paralytic_toxin() : SpellScriptLoader("spell_jormungars_paralytic_toxin") { } + PrepareAuraScript(spell_jormungars_paralytic_toxin); - class spell_jormungars_paralytic_toxin_AuraScript : public AuraScript + bool Validate(SpellInfo const* /*spell*/) override { - PrepareAuraScript(spell_jormungars_paralytic_toxin_AuraScript); + return ValidateSpellInfo({ SPELL_PARALYSIS }); + } - bool Validate(SpellInfo const* /*spell*/) override - { - return ValidateSpellInfo({ SPELL_PARALYSIS }); - } + void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + Unit* caster = GetCaster(); + if (caster && caster->GetEntry() == NPC_ACIDMAW) + if (Creature* acidmaw = caster->ToCreature()) + acidmaw->AI()->Talk(SAY_SPECIAL, GetTarget()); + } - void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) - { - Unit* caster = GetCaster(); - if (caster && caster->GetEntry() == NPC_ACIDMAW) - { - if (Creature* acidMaw = caster->ToCreature()) - acidMaw->AI()->Talk(SAY_SPECIAL, GetTarget()); - } - } + void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + GetTarget()->RemoveAurasDueToSpell(SPELL_PARALYSIS); + } - void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) - { - GetTarget()->RemoveAurasDueToSpell(SPELL_PARALYSIS); - } + void CalculateAmount(AuraEffect const* aurEff, int32& amount, bool& canBeRecalculated) + { + if (!canBeRecalculated) + amount = aurEff->GetAmount(); + + canBeRecalculated = false; + } - void CalculateAmount(AuraEffect const* aurEff, int32& amount, bool& canBeRecalculated) + void HandleDummy(AuraEffect const* /*aurEff*/) + { + if (AuraEffect* slowEff = GetEffect(EFFECT_0)) { - if (!canBeRecalculated) - amount = aurEff->GetAmount(); + int32 newAmount = slowEff->GetAmount() - 10; + if (newAmount < -100) + newAmount = -100; + slowEff->ChangeAmount(newAmount); - canBeRecalculated = false; + if (newAmount == -100 && !GetTarget()->HasAura(SPELL_PARALYSIS)) + GetTarget()->CastSpell(GetTarget(), SPELL_PARALYSIS, true, nullptr, slowEff, GetCasterGUID()); } + } - void HandleDummy(AuraEffect const* /*aurEff*/) - { - if (AuraEffect* slowEff = GetEffect(EFFECT_0)) - { - int32 newAmount = slowEff->GetAmount() - 10; - if (newAmount < -100) - newAmount = -100; - slowEff->ChangeAmount(newAmount); + void Register() override + { + AfterEffectApply += AuraEffectApplyFn(spell_jormungars_paralytic_toxin::OnApply, EFFECT_0, SPELL_AURA_MOD_DECREASE_SPEED, AURA_EFFECT_HANDLE_REAL); + AfterEffectRemove += AuraEffectRemoveFn(spell_jormungars_paralytic_toxin::OnRemove, EFFECT_0, SPELL_AURA_MOD_DECREASE_SPEED, AURA_EFFECT_HANDLE_REAL); + DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_jormungars_paralytic_toxin::CalculateAmount, EFFECT_0, SPELL_AURA_MOD_DECREASE_SPEED); + OnEffectPeriodic += AuraEffectPeriodicFn(spell_jormungars_paralytic_toxin::HandleDummy, EFFECT_2, SPELL_AURA_PERIODIC_DUMMY); + } +}; - if (newAmount <= -100 && !GetTarget()->HasAura(SPELL_PARALYSIS)) - GetTarget()->CastSpell(GetTarget(), SPELL_PARALYSIS, true, nullptr, slowEff, GetCasterGUID()); - } - } +// 66870 - Burning Bile +class spell_jormungars_burning_bile : public SpellScript +{ + PrepareSpellScript(spell_jormungars_burning_bile); - void Register() override - { - AfterEffectApply += AuraEffectApplyFn(spell_jormungars_paralytic_toxin_AuraScript::OnApply, EFFECT_0, SPELL_AURA_MOD_DECREASE_SPEED, AURA_EFFECT_HANDLE_REAL); - AfterEffectRemove += AuraEffectRemoveFn(spell_jormungars_paralytic_toxin_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_MOD_DECREASE_SPEED, AURA_EFFECT_HANDLE_REAL); - DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_jormungars_paralytic_toxin_AuraScript::CalculateAmount, EFFECT_0, SPELL_AURA_MOD_DECREASE_SPEED); - OnEffectPeriodic += AuraEffectPeriodicFn(spell_jormungars_paralytic_toxin_AuraScript::HandleDummy, EFFECT_2, SPELL_AURA_PERIODIC_DUMMY); - } - }; + void HandleScriptEffect(SpellEffIndex effIndex) + { + PreventHitDefaultEffect(effIndex); + GetHitUnit()->RemoveAurasByType(SPELL_AURA_MOD_DECREASE_SPEED); + } - AuraScript* GetAuraScript() const override + void Register() override { - return new spell_jormungars_paralytic_toxin_AuraScript(); + OnEffectHitTarget += SpellEffectFn(spell_jormungars_burning_bile::HandleScriptEffect, EFFECT_1, SPELL_EFFECT_SCRIPT_EFFECT); } }; @@ -1398,6 +1201,8 @@ class spell_jormungars_slime_pool : public AuraScript } }; +/* 66869 - Burning Bile + 66823 - Paralytic Toxin */ class spell_jormungars_snakes_spray : public SpellScriptLoader { public: @@ -1418,15 +1223,13 @@ public: void HandleScript(SpellEffIndex /*effIndex*/) { - if (Player* target = GetHitPlayer()) - GetCaster()->CastSpell(target, _spellId, true); + GetCaster()->CastSpell(GetHitUnit(), _spellId, true); } void Register() override { OnEffectHitTarget += SpellEffectFn(spell_jormungars_snakes_spray_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCHOOL_DAMAGE); } - uint32 _spellId; }; @@ -1439,55 +1242,115 @@ private: uint32 _spellId; }; -class spell_jormungars_paralysis : public SpellScriptLoader +// 66830 - Paralysis +class spell_jormungars_paralysis : public AuraScript { -public: - spell_jormungars_paralysis() : SpellScriptLoader("spell_jormungars_paralysis") { } + PrepareAuraScript(spell_jormungars_paralysis); - class spell_jormungars_paralysis_AuraScript : public AuraScript + void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) { - PrepareAuraScript(spell_jormungars_paralysis_AuraScript); + if (Unit* caster = GetCaster()) + if (InstanceScript* instance = caster->GetInstanceScript()) + if (instance->GetBossState(DATA_NORTHREND_BEASTS) == IN_PROGRESS) + return; - void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) - { - if (Unit* caster = GetCaster()) - if (InstanceScript* instance = caster->GetInstanceScript()) - if (instance->GetData(TYPE_NORTHREND_BEASTS) == SNAKES_IN_PROGRESS || instance->GetData(TYPE_NORTHREND_BEASTS) == SNAKES_SPECIAL) - return; + Remove(); + } - Remove(); - } + void Register() override + { + AfterEffectApply += AuraEffectApplyFn(spell_jormungars_paralysis::OnApply, EFFECT_0, SPELL_AURA_MOD_STUN, AURA_EFFECT_HANDLE_REAL); + } +}; - void Register() override - { - AfterEffectApply += AuraEffectApplyFn(spell_jormungars_paralysis_AuraScript::OnApply, EFFECT_0, SPELL_AURA_MOD_STUN, AURA_EFFECT_HANDLE_REAL); - } - }; +// 66688 - Arctic Breath +class spell_icehowl_arctic_breath : public SpellScript +{ + PrepareSpellScript(spell_icehowl_arctic_breath); + + bool Validate(SpellInfo const* spellInfo) override + { + return ValidateSpellInfo({ static_cast<uint32>(spellInfo->GetEffect(EFFECT_0)->CalcValue()) }); + } + + void HandleScriptEffect(SpellEffIndex effIndex) + { + uint32 spellId = GetSpellInfo()->GetEffect(effIndex)->CalcValue(); + GetCaster()->CastSpell(GetHitUnit(), spellId, true); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_icehowl_arctic_breath::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } +}; + +// 66734 - Trample +class spell_icehowl_trample : public SpellScript +{ + PrepareSpellScript(spell_icehowl_trample); + + void CheckTargets(std::list<WorldObject*>& targets) + { + Creature* caster = GetCaster()->ToCreature(); + if (!caster || !caster->IsAIEnabled) + return; - AuraScript* GetAuraScript() const override + if (targets.empty()) + caster->AI()->DoAction(ACTION_TRAMPLE_FAIL); + else + caster->AI()->DoAction(ACTION_ENRAGE); + } + + void Register() override { - return new spell_jormungars_paralysis_AuraScript(); + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_icehowl_trample::CheckTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + } +}; + +// 66683 - Massive Crash +class spell_icehowl_massive_crash : public AuraScript +{ + PrepareAuraScript(spell_icehowl_massive_crash); + + bool Validate(SpellInfo const* /*spell*/) override + { + return ValidateSpellInfo({ SPELL_SURGE_OF_ADRENALINE }); + } + + void HandleSpeed(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (Player* target = GetTarget()->ToPlayer()) + if (target->GetMap()->IsHeroic()) + target->CastSpell(target, SPELL_SURGE_OF_ADRENALINE, true); + } + + void Register() override + { + AfterEffectRemove += AuraEffectRemoveFn(spell_icehowl_massive_crash::HandleSpeed, EFFECT_2, SPELL_AURA_MOD_STUN, AURA_EFFECT_HANDLE_REAL); } }; void AddSC_boss_northrend_beasts() { - new boss_gormok(); - new npc_snobold_vassal(); - new npc_firebomb(); - new spell_gormok_fire_bomb(); - new spell_gormok_jump_to_hand(); - new spell_gormok_ride_player(); - new spell_gormok_snobolled(); - - new boss_acidmaw(); - new boss_dreadscale(); - new npc_slime_pool(); - new spell_jormungars_paralytic_toxin(); + RegisterTrialOfTheCrusaderCreatureAI(boss_gormok); + RegisterTrialOfTheCrusaderCreatureAI(npc_snobold_vassal); + RegisterTrialOfTheCrusaderCreatureAI(npc_beasts_combat_stalker); + RegisterTrialOfTheCrusaderCreatureAI(boss_acidmaw); + RegisterTrialOfTheCrusaderCreatureAI(boss_dreadscale); + RegisterTrialOfTheCrusaderCreatureAI(npc_jormungars_slime_pool); + RegisterTrialOfTheCrusaderCreatureAI(boss_icehowl); + + RegisterAuraScript(spell_gormok_jump_to_hand); + RegisterAuraScript(spell_gormok_ride_player); + RegisterAuraScript(spell_gormok_snobolled); + RegisterAuraScript(spell_jormungars_paralytic_toxin); + RegisterSpellScript(spell_jormungars_burning_bile); RegisterAuraScript(spell_jormungars_slime_pool); new spell_jormungars_snakes_spray("spell_jormungars_burning_spray", SPELL_BURNING_BILE); new spell_jormungars_snakes_spray("spell_jormungars_paralytic_spray", SPELL_PARALYTIC_TOXIN); - new spell_jormungars_paralysis(); - - new boss_icehowl(); + RegisterAuraScript(spell_jormungars_paralysis); + RegisterSpellScript(spell_icehowl_arctic_breath); + RegisterSpellScript(spell_icehowl_trample); + RegisterAuraScript(spell_icehowl_massive_crash); } 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 350482157e1..232c2bf8139 100644 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_twin_valkyr.cpp +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_twin_valkyr.cpp @@ -44,10 +44,14 @@ enum Texts SAY_DEATH = 8 }; -enum Equipment +enum Misc { - EQUIP_MAIN_1 = 9423, - EQUIP_MAIN_2 = 37377 + EQUIP_MAIN_1 = 9423, + EQUIP_MAIN_2 = 37377, + POINT_INITIAL_MOVEMENT = 1, + SPLINE_INITIAL_MOVEMENT = 1, + PHASE_EVENT = 1, + PHASE_COMBAT = 2 }; enum Summons @@ -100,7 +104,8 @@ enum Events EVENT_TWIN_SPIKE = 1, EVENT_TOUCH = 2, EVENT_SPECIAL_ABILITY = 3, - EVENT_BERSERK = 4 + EVENT_BERSERK = 4, + EVENT_START_MOVE = 5 }; enum Stages @@ -124,9 +129,7 @@ enum Actions class OrbsDespawner : public BasicEvent { public: - explicit OrbsDespawner(Creature* creature) : _creature(creature) - { - } + explicit OrbsDespawner(Creature* creature) : _creature(creature) { } bool Execute(uint64 /*currTime*/, uint32 /*diff*/) override { @@ -177,7 +180,6 @@ struct boss_twin_baseAI : public BossAI void Reset() override { - me->AddUnitFlag(UnitFlags(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE)); me->SetReactState(REACT_PASSIVE); me->ModifyAuraState(AuraState, true); /* Uncomment this once that they are floating above the ground @@ -185,30 +187,26 @@ struct boss_twin_baseAI : public BossAI me->SetFlying(true); */ summons.DespawnAll(); + events.SetPhase(PHASE_EVENT); + events.ScheduleEvent(EVENT_START_MOVE, 4s); } void JustReachedHome() override { instance->SetBossState(DATA_TWIN_VALKIRIES, FAIL); - + HandleRemoveAuras(); summons.DespawnAll(); me->DespawnOrUnsummon(); } - void MovementInform(uint32 uiType, uint32 uiId) override + void MovementInform(uint32 type, uint32 pointId) override { - if (uiType != POINT_MOTION_TYPE) - return; - - switch (uiId) + if (type == SPLINE_CHAIN_MOTION_TYPE && pointId == POINT_INITIAL_MOVEMENT) { - case 1: - me->RemoveUnitFlag(UnitFlags(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE)); - me->SetImmuneToPC(false); - me->SetReactState(REACT_AGGRESSIVE); - break; - default: - break; + me->SetImmuneToPC(false); + me->SetReactState(REACT_AGGRESSIVE); + if (me->GetEntry() == NPC_FJOLA_LIGHTBANE) // avoid call twice + instance->DoCloseDoorOrButton(instance->GetGuidData(DATA_MAIN_GATE)); } } @@ -218,25 +216,13 @@ struct boss_twin_baseAI : public BossAI Talk(SAY_KILL_PLAYER); } - void SummonedCreatureDespawn(Creature* summoned) override + void HandleRemoveAuras() { - switch (summoned->GetEntry()) - { - case NPC_LIGHT_ESSENCE: - instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_LIGHT_ESSENCE); - instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_POWERING_UP); - break; - case NPC_DARK_ESSENCE: - instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_DARK_ESSENCE); - instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_POWERING_UP); - break; - case NPC_BULLET_CONTROLLER: - me->m_Events.AddEvent(new OrbsDespawner(me), me->m_Events.CalculateTime(100)); - break; - default: - break; - } - summons.Despawn(summoned); + instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_LIGHT_ESSENCE); + instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_POWERING_UP); + instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_DARK_ESSENCE); + instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_POWERING_UP); + me->m_Events.AddEventAtOffset(new OrbsDespawner(me), 100ms); } void JustDied(Unit* /*killer*/) override @@ -250,6 +236,7 @@ struct boss_twin_baseAI : public BossAI pSister->AddDynamicFlag(UNIT_DYNFLAG_LOOTABLE); events.Reset(); summons.DespawnAll(); + HandleRemoveAuras(); instance->SetBossState(DATA_TWIN_VALKIRIES, DONE); } else @@ -332,11 +319,35 @@ struct boss_twin_baseAI : public BossAI DoCast(me, SPELL_BERSERK); Talk(SAY_BERSERK); break; + case EVENT_START_MOVE: + events.SetPhase(PHASE_COMBAT); + me->GetMotionMaster()->MoveAlongSplineChain(POINT_INITIAL_MOVEMENT, SPLINE_INITIAL_MOVEMENT, false); + break; default: break; } } + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim() && !events.IsInPhase(PHASE_EVENT)) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) + { + ExecuteEvent(eventId); + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + } + + DoMeleeAttackIfReady(); + } + protected: AuraStateType AuraState; uint32 Weapon; 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 b347a7ab6df..4784ec6a3aa 100644 --- 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 @@ -22,10 +22,13 @@ #include "Log.h" #include "Map.h" #include "Player.h" +#include "ScriptedCreature.h" #include "TemporarySummon.h" #include "trial_of_the_crusader.h" #include <sstream> + // ToDo: Remove magic numbers of events + BossBoundaryData const boundaries = { { DATA_NORTHREND_BEASTS, new CircleBoundary(Position(563.26f, 139.6f), 75.0) }, @@ -37,23 +40,25 @@ BossBoundaryData const boundaries = ObjectData const creatureData[] = { - { NPC_GORMOK, DATA_GORMOK_THE_IMPALER }, - { NPC_ACIDMAW, DATA_ACIDMAW }, - { NPC_DREADSCALE, DATA_DREADSCALE }, - { NPC_ICEHOWL, DATA_ICEHOWL }, - { NPC_JARAXXUS, DATA_JARAXXUS }, - { NPC_CHAMPIONS_CONTROLLER, DATA_FACTION_CRUSADERS }, - { NPC_FJOLA_LIGHTBANE, DATA_FJOLA_LIGHTBANE }, - { NPC_EYDIS_DARKBANE, DATA_EYDIS_DARKBANE }, - { NPC_LICH_KING, DATA_LICH_KING }, - { NPC_ANUBARAK, DATA_ANUBARAK }, - { NPC_BARRET_RAMSEY, DATA_BARRET_RAMSEY }, - { NPC_TIRION_FORDRING, DATA_FORDRING }, - { NPC_TIRION_FORDRING_ANUBARAK, DATA_FORDRING_ANUBARAK }, - { NPC_VARIAN, DATA_VARIAN }, - { NPC_GARROSH, DATA_GARROSH }, - { NPC_FIZZLEBANG, DATA_FIZZLEBANG }, - { 0, 0 } // END + { NPC_GORMOK, DATA_GORMOK_THE_IMPALER }, + { NPC_ACIDMAW, DATA_ACIDMAW }, + { NPC_DREADSCALE, DATA_DREADSCALE }, + { NPC_ICEHOWL, DATA_ICEHOWL }, + { NPC_BEASTS_COMBAT_STALKER, DATA_BEASTS_COMBAT_STALKER }, + { NPC_FURIOUS_CHARGE_STALKER, DATA_FURIOUS_CHARGE }, + { NPC_JARAXXUS, DATA_JARAXXUS }, + { NPC_CHAMPIONS_CONTROLLER, DATA_FACTION_CRUSADERS }, + { NPC_FJOLA_LIGHTBANE, DATA_FJOLA_LIGHTBANE }, + { NPC_EYDIS_DARKBANE, DATA_EYDIS_DARKBANE }, + { NPC_LICH_KING, DATA_LICH_KING }, + { NPC_ANUBARAK, DATA_ANUBARAK }, + { NPC_TIRION_FORDRING, DATA_FORDRING }, + { NPC_TIRION_FORDRING_ANUBARAK, DATA_FORDRING_ANUBARAK }, + { NPC_VARIAN, DATA_VARIAN }, + { NPC_GARROSH, DATA_GARROSH }, + { NPC_FIZZLEBANG, DATA_FIZZLEBANG }, + { NPC_LICH_KING_VOICE, DATA_LICH_KING_VOICE }, + { 0, 0 } // END }; ObjectData const gameObjectData[] = @@ -77,6 +82,17 @@ ObjectData const gameObjectData[] = { 0, 0 } // END }; +DoorData const doorData[] = +{ + { GO_EAST_PORTCULLIS, DATA_NORTHREND_BEASTS, DOOR_TYPE_ROOM }, + { GO_EAST_PORTCULLIS, DATA_JARAXXUS, DOOR_TYPE_ROOM }, + { GO_EAST_PORTCULLIS, DATA_FACTION_CRUSADERS, DOOR_TYPE_ROOM }, + { GO_EAST_PORTCULLIS, DATA_TWIN_VALKIRIES, DOOR_TYPE_ROOM }, + { GO_EAST_PORTCULLIS, DATA_LICH_KING, DOOR_TYPE_ROOM }, + { GO_WEB_DOOR, DATA_ANUBARAK, DOOR_TYPE_ROOM }, + { 0, 0, DOOR_TYPE_ROOM } // END +}; + class instance_trial_of_the_crusader : public InstanceMapScript { public: @@ -90,9 +106,12 @@ class instance_trial_of_the_crusader : public InstanceMapScript SetBossNumber(EncounterCount); LoadBossBoundaries(boundaries); LoadObjectData(creatureData, gameObjectData); + LoadDoorData(doorData); TrialCounter = 50; EventStage = 0; NorthrendBeasts = NOT_STARTED; + NorthrendBeastsCount = 4; + Team = TEAM_OTHER; EventTimer = 1000; NotOneButTwoJormungarsTimer = 0; ResilienceWillFixItTimer = 0; @@ -102,19 +121,6 @@ class instance_trial_of_the_crusader : public InstanceMapScript NeedSave = false; } - bool IsEncounterInProgress() const override - { - for (uint8 i = 0; i < EncounterCount; ++i) - 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(DATA_FACTION_CRUSADERS) == SPECIAL) - return true; - - return false; - } - void OnPlayerEnter(Player* player) override { if (instance->IsHeroic()) @@ -125,36 +131,27 @@ class instance_trial_of_the_crusader : public InstanceMapScript else player->SendUpdateWorldState(UPDATE_STATE_UI_SHOW, 0); - // make sure Anub'arak isnt missing - if (GetBossState(DATA_LICH_KING) == DONE && TrialCounter && GetBossState(DATA_ANUBARAK) != DONE) - if (!GetCreature(DATA_ANUBARAK)) - player->SummonCreature(NPC_ANUBARAK, AnubarakLoc[0], TEMPSUMMON_CORPSE_TIMED_DESPAWN, DESPAWN_TIME); - } + if (Team == TEAM_OTHER) + Team = player->GetTeam(); - void OpenDoor(ObjectGuid guid) - { - if (!guid) - return; - - if (GameObject* go = instance->GetGameObject(guid)) - go->SetGoState(GO_STATE_ACTIVE_ALTERNATIVE); + if (NorthrendBeasts == GORMOK_IN_PROGRESS) + player->CreateVehicleKit(PLAYER_VEHICLE_ID, 0); } - void CloseDoor(ObjectGuid guid) + void OnCreatureCreate(Creature* creature) override { - if (!guid) - return; - - if (GameObject* go = instance->GetGameObject(guid)) - go->SetGoState(GO_STATE_READY); + InstanceScript::OnCreatureCreate(creature); + if (creature->GetEntry() == NPC_SNOBOLD_VASSAL) + snoboldGUIDS.push_back(creature->GetGUID()); } - void OnCreatureCreate(Creature* creature) override + // Summon prevention to heroic modes + uint32 GetCreatureEntry(ObjectGuid::LowType /*guidLow*/, CreatureData const* data) override { - InstanceScript::OnCreatureCreate(creature); - if (creature->GetEntry() == NPC_BARRET_RAMSEY) - if (!TrialCounter) - creature->DespawnOrUnsummon(); + if (!TrialCounter) + return 0; + + return data->id; } void OnGameObjectCreate(GameObject* go) override @@ -182,23 +179,28 @@ class instance_trial_of_the_crusader : public InstanceMapScript case DATA_NORTHREND_BEASTS: break; case DATA_JARAXXUS: - // Cleanup Icehowl - if (Creature* icehowl = GetCreature(DATA_ICEHOWL)) - icehowl->DespawnOrUnsummon(); - if (state == DONE) + if (state == FAIL) + { + if (Creature* fordring = GetCreature(DATA_FORDRING)) + fordring->AI()->DoAction(ACTION_JARAXXUS_WIPE); + } + else if (state == DONE) + { + if (Creature* fordring = GetCreature(DATA_FORDRING)) + fordring->AI()->DoAction(ACTION_JARAXXUS_DEFEATED); EventStage = 2000; + } break; case DATA_FACTION_CRUSADERS: - // Cleanup Jaraxxus - if (Creature* jaraxxus = GetCreature(DATA_JARAXXUS)) - jaraxxus->DespawnOrUnsummon(); - if (Creature* fizzlebang = GetCreature(DATA_FIZZLEBANG)) - fizzlebang->DespawnOrUnsummon(); switch (state) { case IN_PROGRESS: ResilienceWillFixItTimer = 0; break; + case FAIL: + if (Creature* fordring = GetCreature(DATA_FORDRING)) + fordring->AI()->DoAction(ACTION_FACTION_WIPE); + break; case SPECIAL: //Means the first blood ResilienceWillFixItTimer = 60*IN_MILLISECONDS; state = IN_PROGRESS; @@ -210,6 +212,8 @@ class instance_trial_of_the_crusader : public InstanceMapScript DoRespawnGameObject(GetGuidData(DATA_CRUSADERS_CHEST), 7 * DAY); if (GameObject* cache = GetGameObject(DATA_CRUSADERS_CHEST)) cache->RemoveFlag(GO_FLAG_NOT_SELECTABLE); + if (Creature* fordring = GetCreature(DATA_FORDRING)) + fordring->AI()->DoAction(ACTION_CHAMPIONS_DEFEATED); EventStage = 3100; break; default: @@ -223,12 +227,12 @@ class instance_trial_of_the_crusader : public InstanceMapScript switch (state) { case FAIL: - if (GetBossState(DATA_TWIN_VALKIRIES) == NOT_STARTED) - state = NOT_STARTED; + if (Creature* fordring = GetCreature(DATA_FORDRING)) + fordring->AI()->DoAction(ACTION_VALKYR_WIPE); break; - case SPECIAL: - if (GetBossState(DATA_TWIN_VALKIRIES) == SPECIAL) - state = DONE; + case DONE: + if (Creature* fordring = GetCreature(DATA_FORDRING)) + fordring->AI()->DoAction(ACTION_VALKYR_DEFEATED); break; default: break; @@ -292,17 +296,6 @@ class instance_trial_of_the_crusader : public InstanceMapScript break; } - if (IsEncounterInProgress()) - { - CloseDoor(GetGuidData(DATA_EAST_PORTCULLIS)); - CloseDoor(GetGuidData(DATA_WEB_DOOR)); - } - else - { - OpenDoor(GetGuidData(DATA_EAST_PORTCULLIS)); - OpenDoor(GetGuidData(DATA_WEB_DOOR)); - } - if (type < EncounterCount) { TC_LOG_DEBUG("scripts", "[ToCr] BossState(type %u) %u = state %u;", type, GetBossState(type), state); @@ -320,9 +313,6 @@ class instance_trial_of_the_crusader : public InstanceMapScript // if theres no more attemps allowed if (!TrialCounter) { - if (Unit* announcer = GetCreature(DATA_BARRET_RAMSEY)) - announcer->ToCreature()->DespawnOrUnsummon(); - if (Creature* anubarak = GetCreature(DATA_ANUBARAK)) anubarak->DespawnOrUnsummon(); } @@ -333,15 +323,41 @@ class instance_trial_of_the_crusader : public InstanceMapScript } if (state == DONE || NeedSave) - { - if (Unit* announcer = GetCreature(DATA_BARRET_RAMSEY)) - announcer->AddNpcFlag(UNIT_NPC_FLAG_GOSSIP); Save(); - } } return true; } + void HandleNorthrendBeastsDone() + { + --NorthrendBeastsCount; + if (!NorthrendBeastsCount) + { + SetData(TYPE_NORTHREND_BEASTS, DONE); + SetBossState(DATA_NORTHREND_BEASTS, DONE); + SetData(DATA_DESPAWN_SNOBOLDS, 0); + EventStage = 400; + if (Creature* combatStalker = GetCreature(DATA_BEASTS_COMBAT_STALKER)) + combatStalker->DespawnOrUnsummon(); + HandlePlayerVehicle(false); + if (Creature* fordring = GetCreature(DATA_FORDRING)) + fordring->AI()->DoAction(ACTION_NORTHREND_BEASTS_DEFEATED); + } + } + + void HandlePlayerVehicle(bool apply) + { + Map::PlayerList const &players = instance->GetPlayers(); + for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) + if (Player* player = itr->GetSource()) + { + if (apply) + player->CreateVehicleKit(PLAYER_VEHICLE_ID, 0); + else + player->RemoveVehicleKit(); + } + } + void SetData(uint32 type, uint32 data) override { switch (type) @@ -362,34 +378,49 @@ class instance_trial_of_the_crusader : public InstanceMapScript NorthrendBeasts = data; switch (data) { + case GORMOK_IN_PROGRESS: + SetBossState(DATA_NORTHREND_BEASTS, IN_PROGRESS); + NorthrendBeastsCount = 4; + HandlePlayerVehicle(true); + break; case GORMOK_DONE: - EventStage = 200; - SetData(TYPE_NORTHREND_BEASTS, IN_PROGRESS); + if (Creature* tirion = GetCreature(DATA_FORDRING)) + tirion->AI()->DoAction(ACTION_START_JORMUNGARS); + HandleNorthrendBeastsDone(); break; case SNAKES_IN_PROGRESS: NotOneButTwoJormungarsTimer = 0; break; case SNAKES_SPECIAL: NotOneButTwoJormungarsTimer = 10*IN_MILLISECONDS; + HandleNorthrendBeastsDone(); break; case SNAKES_DONE: if (NotOneButTwoJormungarsTimer > 0) DoUpdateCriteria(CRITERIA_TYPE_BE_SPELL_TARGET, SPELL_WORMS_KILLED_IN_10_SECONDS); - EventStage = 300; - SetData(TYPE_NORTHREND_BEASTS, IN_PROGRESS); + if (Creature* tirion = GetCreature(DATA_FORDRING)) + tirion->AI()->DoAction(ACTION_START_ICEHOWL); + HandleNorthrendBeastsDone(); break; case ICEHOWL_DONE: - EventStage = 400; - SetData(TYPE_NORTHREND_BEASTS, DONE); - SetBossState(DATA_NORTHREND_BEASTS, DONE); + HandleNorthrendBeastsDone(); break; case FAIL: + HandlePlayerVehicle(false); SetBossState(DATA_NORTHREND_BEASTS, FAIL); + if (Creature* tirion = GetCreature(DATA_FORDRING)) + tirion->AI()->DoAction(ACTION_NORTHREND_BEASTS_WIPE); break; default: break; } break; + case DATA_DESPAWN_SNOBOLDS: + for (ObjectGuid const guid : snoboldGUIDS) + if (Creature* snobold = instance->GetCreature(guid)) + snobold->DespawnOrUnsummon(); + snoboldGUIDS.clear(); + break; //Achievements case DATA_SNOBOLD_COUNT: if (data == INCREASE) @@ -412,6 +443,8 @@ class instance_trial_of_the_crusader : public InstanceMapScript { switch (type) { + case DATA_TEAM: + return Team; case TYPE_COUNTER: return TrialCounter; case TYPE_EVENT: @@ -524,7 +557,7 @@ class instance_trial_of_the_crusader : public InstanceMapScript NotOneButTwoJormungarsTimer -= diff; } - if (GetBossState(DATA_FACTION_CRUSADERS) == SPECIAL && ResilienceWillFixItTimer) + if (GetBossState(DATA_FACTION_CRUSADERS) == IN_PROGRESS && ResilienceWillFixItTimer) { if (ResilienceWillFixItTimer <= diff) ResilienceWillFixItTimer = 0; @@ -624,15 +657,18 @@ class instance_trial_of_the_crusader : public InstanceMapScript uint32 EventStage; uint32 EventTimer; uint32 NorthrendBeasts; - bool NeedSave; + uint32 Team; + bool NeedSave; std::string SaveDataBuffer; + GuidVector snoboldGUIDS; // Achievement stuff uint32 NotOneButTwoJormungarsTimer; uint32 ResilienceWillFixItTimer; - uint8 SnoboldCount; - uint8 MistressOfPainCount; - bool TributeToImmortalityEligible; + uint8 SnoboldCount; + uint8 MistressOfPainCount; + uint8 NorthrendBeastsCount; + bool TributeToImmortalityEligible; }; InstanceScript* GetInstanceScript(InstanceMap* map) const override 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 1a134bbf191..7d57afe379b 100644 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/trial_of_the_crusader.cpp +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/trial_of_the_crusader.cpp @@ -15,9 +15,6 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -//Known Bugs: -// - Need better implementation of Gossip and correct gossip text and option - #include "ScriptMgr.h" #include "GameObject.h" #include "InstanceScript.h" @@ -27,113 +24,143 @@ #include "Player.h" #include "ScriptedCreature.h" #include "ScriptedGossip.h" +#include "SpellInfo.h" +#include "SpellScript.h" #include "TemporarySummon.h" #include "trial_of_the_crusader.h" +#include "Weather.h" enum Yells { - // Highlord Tirion Fordring - 34996 - SAY_STAGE_0_01 = 0, - SAY_STAGE_0_02 = 1, - SAY_STAGE_0_04 = 2, - SAY_STAGE_0_05 = 3, - SAY_STAGE_0_06 = 4, - SAY_STAGE_0_WIPE = 5, - SAY_STAGE_1_01 = 6, - SAY_STAGE_1_07 = 7, - SAY_STAGE_1_08 = 8, - SAY_STAGE_1_11 = 9, - SAY_STAGE_2_01 = 10, - SAY_STAGE_2_03 = 11, - SAY_STAGE_2_06 = 12, - SAY_STAGE_3_01 = 13, - SAY_STAGE_3_02 = 14, - SAY_STAGE_4_01 = 15, - SAY_STAGE_4_03 = 16, + // Highlord Tirion Fordring + TIRION_SAY_WELCOME = 0, + TIRION_SAY_GORMOK = 1, + TIRION_SAY_JORMUNGARS = 2, + TIRION_SAY_ICEHOWL = 3, + TIRION_SAY_BEASTS_DONE = 4, + TIRION_SAY_BEASTS_WIPE = 5, + TIRION_SAY_WILFRED = 6, + TIRION_SAY_KILL_JARAXXUS = 7, + TIRION_SAY_LAMENT = 8, + TIRION_SAY_CALM_DOWN = 9, + TIRION_SAY_CHAMPIONS = 10, + TIRION_SAY_ALLOW_COMBAT = 11, + TIRION_SAY_TRAGIC_VICTORY = 12, + TIRION_SAY_WORK_TOGETHER = 13, + TIRION_SAY_GAME_BEGIN = 14, + TIRION_SAY_UNITED = 15, + TIRION_SAY_ARTHAS = 16, // Varian Wrynn - SAY_STAGE_0_03a = 0, - SAY_STAGE_1_10 = 1, - SAY_STAGE_2_02a = 2, - SAY_STAGE_2_04a = 3, - SAY_STAGE_2_05a = 4, - SAY_STAGE_3_03a = 5, + VARIAN_SAY_BEASTS = 0, + VARIAN_SAY_COME_PIGS = 1, + VARIAN_SAY_DEMAND_JUSTICE = 2, + VARIAN_SAY_FIGHT_GLORY = 3, + VARIAN_SAY_FACTION_DEAD = 4, + VARIAN_SAY_VALKYR_DEAD = 5, + VARIAN_SAY_KILLED = 6, // Garrosh - SAY_STAGE_0_03h = 0, - SAY_STAGE_1_09 = 1, - SAY_STAGE_2_02h = 2, - SAY_STAGE_2_04h = 3, - SAY_STAGE_2_05h = 4, - SAY_STAGE_3_03h = 5, + GARROSH_SAY_BEASTS = 0, + GARROSH_SAY_ALLIANCE_DOGS = 1, + GARROSH_SAY_DEMAND_JUSTICE = 2, + GARROSH_SAY_NO_MERCY = 3, + GARROSH_SAY_FACTION_DEAD = 4, + GARROSH_SAY_VALKYR_DEAD = 5, + GARROSH_SAY_KILLED = 6, // Wilfred Fizzlebang - SAY_STAGE_1_02 = 0, - SAY_STAGE_1_03 = 1, - SAY_STAGE_1_04 = 2, - SAY_STAGE_1_06 = 3, + WILFRED_SAY_INTRO = 0, + WILFRED_SAY_OBLIVION = 1, + WILFRED_SAY_MASTER = 2, + WILFRED_SAY_DEAD = 3, - // Lord Jaraxxus - SAY_STAGE_1_05 = 0, + // The Lich King Voice + LK_VOICE_SAY_CHALLENGE = 4, + LK_VOICE_SAY_SOULS_WILL_BE_MINE = 5, // The Lich King - SAY_STAGE_4_02 = 0, - SAY_STAGE_4_05 = 1, - SAY_STAGE_4_04 = 2, + LK_SAY_EMPIRE = 0, - // Highlord Tirion Fordring - 36095 - SAY_STAGE_4_06 = 0, - SAY_STAGE_4_07 = 1 + // Highlord Tirion Fordring (Anu'barak) + SAY_STAGE_4_06 = 0, + SAY_STAGE_4_07 = 1 }; -Position const ToCSpawnLoc[] = +enum TrialMisc { - { 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 + SPLINE_INITIAL_MOVEMENT = 1, + POINT_SUMMON = 1, + POINT_MIDDLE = 2, + GROUP_VALKYR = 1, + GOSSIPID_FAIL = 1, + POINT_BARRETT_DESPAWN = 1, + AREA_TRIAL_OF_THE_CRUSADER = 4722 }; -Position const ToCCommonLoc[] = +enum TrialEvents { - { 559.257996f, 90.266197f, 395.122986f, 0 }, // 0 Barrent - - { 563.672974f, 139.571f, 393.837006f, 0 }, // 1 Center - { 563.833008f, 187.244995f, 394.5f, 0 }, // 2 Backdoor - { 577.347839f, 195.338888f, 395.14f, 0 }, // 3 - Right - { 550.955933f, 195.338888f, 395.14f, 0 }, // 4 - Left - { 563.833008f, 195.244995f, 394.585561f, 0 }, // 5 - Center - { 573.5f, 180.5f, 395.14f, 0 }, // 6 Move 0 Right - { 553.5f, 180.5f, 395.14f, 0 }, // 7 Move 0 Left - { 573.0f, 170.0f, 395.14f, 0 }, // 8 Move 1 Right - { 555.5f, 170.0f, 395.14f, 0 }, // 9 Move 1 Left - { 563.8f, 216.1f, 395.1f, 0 }, // 10 Behind the door - - { 575.042358f, 195.260727f, 395.137146f, 0 }, // 5 - { 552.248901f, 195.331955f, 395.132658f, 0 }, // 6 - { 573.342285f, 195.515823f, 395.135956f, 0 }, // 7 - { 554.239929f, 195.825577f, 395.137909f, 0 }, // 8 - { 571.042358f, 195.260727f, 395.137146f, 0 }, // 9 - { 556.720581f, 195.015472f, 395.132658f, 0 }, // 10 - { 569.534119f, 195.214478f, 395.139526f, 0 }, // 11 - { 569.231201f, 195.941071f, 395.139526f, 0 }, // 12 - { 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 + EVENT_GORMOK_INTRO = 1, + EVENT_GORMOK_EXCLAMATION, + EVENT_SPAWM_GORMOK, + EVENT_EXCLAMATION, + EVENT_SUMMON_BARRET, + EVENT_START_CALL_WILFRED, + EVENT_KILL_JARAXXUS, + EVENT_EMOTE_SHEATHE, + EVENT_TIRION_LAMENT, + EVENT_TIRION_CALM_DOWN, + EVENT_ALLOW_COMBAT, + EVENT_TRAGIC_VICTORY, + EVENT_SUMMON_WILFRED, + EVENT_START_MOVE, + EVENT_OBLIVION, + EVENT_SUMMON_JARAXXUS, + EVENT_SET_TARGET, + EVENT_LAST_TALK, + EVENT_SUMMON_VALKYR, + EVENT_OPEN_GATE, + EVENT_SAY_ARTHAS, + EVENT_ALLIANCE_DOGS, + EVENT_COME_PIGS, + EVENT_DEMAND_JUSTICE, + EVENT_NO_MERCY, + EVENT_VALKYR_DEAD, + EVENT_LICH_KING_SAY_CHALLENGE, + EVENT_LICH_KING_SAY_SOULS, + EVENT_SUMMON_LICH_KING, + EVENT_BREAK_PLATFORM, + EVENT_EMOTE_TALK, + EVENT_REMOVE_EMOTE_TALK, + EVENT_EMOTE_EXCLAMATION, + EVENT_EMOTE_KNEEL, + EVENT_SUMMON_CHAMPIONS, + EVENT_START_CHAMPIONS, + EVENT_START_TALK }; -Position const TwinValkyrsLoc[] = +enum TocMenuIds { - { 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 + MENUID_NORTHREND_BEASTS = 10600, + MENUID_JARAXXUS = 10610, + MENUID_FACTION_CHAMPIONS = 10687, + MENUID_VALKYR = 10688, + MENUID_LK = 10693 }; -Position const LichKingLoc[] = +Position const BarretSpawnPosition = { 559.1528f, 90.55729f, 395.2734f, 5.078908f }; +Position const WilfredSpawnPosition = { 563.6007f, 208.5278f, 395.2696f, 4.729842f }; +Position const JaraxxusSpawnPosition = { 563.8264f, 140.6563f, 393.9861f, 4.694936f }; +Position const PortalTargetSpawnPosition = { 563.6597f, 139.7569f, 399.2507f, 4.712389f }; +Position const PurpleGroundSpawnPosition = { 563.6858f, 139.4323f, 393.9862f, 4.694936f }; +Position const ArthasPortalSpawnPosition = { 563.6996f, 175.9826f, 394.5042f, 4.694936f }; +Position const LichKingSpawnPosition = { 563.5712f, 174.8351f, 394.4954f, 4.712389f }; +Position const CorpseTeleportPosition = { 631.9390f, 136.5040f, 142.5540f, 0.803332f }; + +Position const NorthrendBeastsSpawnPositions[] = { - { 563.549f, 152.474f, 394.393f, 0 }, // 0 - Lich king start - { 563.547f, 141.613f, 393.908f, 0 } // 1 - Lich king end + { 563.9358f, 229.8299f, 394.8061f, 4.694936f }, // Gormok \ Icehowl + { 564.2802f, 233.1322f, 394.7897f, 1.621917f }, // Dreadscale }; Position const AnubarakLoc[] = @@ -153,895 +180,728 @@ Position const EndSpawnLoc[] = { 644.6250f, 149.2743f, 140.6015f, 5.f } // 2 - Portal to Dalaran }; -struct _Messages +// ToDo: Remove it in nexts rewrites +Position const ToCCommonLoc[] = { - AnnouncerMessages msgnum; - uint32 id; - bool state; - uint32 encounter; -}; + { 559.257996f, 90.266197f, 395.122986f, 0.0f }, // 0 Barrent + { 563.672974f, 139.57100f, 393.837006f, 0.0f }, // 1 Center + { 563.833008f, 187.244995f, 394.50000f, 0.0f }, // 2 Backdoor + { 577.347839f, 195.338888f, 395.14000f, 0.0f }, // 3 - Right + { 550.955933f, 195.338888f, 395.14000f, 0.0f }, // 4 - Left + { 563.833008f, 195.244995f, 394.585561f, 0.0f }, // 5 - Center + { 573.500000f, 180.500000f, 395.14f, 0.0f }, // 6 Move 0 Right + { 553.5f, 180.5f, 395.14f, 0 }, // 7 Move 0 Left + { 573.0f, 170.0f, 395.14f, 0 }, // 8 Move 1 Right + { 549.5139f, 170.1389f, 394.7965f, 5.009095f }, // 9 Move 1 Left + { 563.8f, 216.1f, 395.1f, 0 }, // 10 Behind the door -static _Messages _GossipMessage[]= -{ - {MSG_BEASTS, GOSSIP_ACTION_INFO_DEF + 1, false, DATA_NORTHREND_BEASTS}, - {MSG_JARAXXUS, GOSSIP_ACTION_INFO_DEF + 2, false, DATA_JARAXXUS}, - {MSG_CRUSADERS, GOSSIP_ACTION_INFO_DEF + 3, false, DATA_FACTION_CRUSADERS}, - {MSG_VALKIRIES, GOSSIP_ACTION_INFO_DEF + 4, false, DATA_TWIN_VALKIRIES}, - {MSG_LICH_KING, GOSSIP_ACTION_INFO_DEF + 5, false, DATA_ANUBARAK}, - {MSG_ANUBARAK, GOSSIP_ACTION_INFO_DEF + 6, true, DATA_ANUBARAK} + { 575.042358f, 195.260727f, 395.137146f, 0 }, // 5 + { 552.248901f, 195.331955f, 395.132658f, 0 }, // 6 + { 573.342285f, 195.515823f, 395.135956f, 0 }, // 7 + { 554.239929f, 195.825577f, 395.137909f, 0 }, // 8 + { 571.042358f, 195.260727f, 395.137146f, 0 }, // 9 + { 556.720581f, 195.015472f, 395.132658f, 0 }, // 10 + { 569.534119f, 195.214478f, 395.139526f, 0 }, // 11 + { 569.231201f, 195.941071f, 395.139526f, 0 }, // 12 + { 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 }; -enum Messages +class ArthasPortalEvent : public BasicEvent { - NUM_MESSAGES = 6 +public: + ArthasPortalEvent(Unit* owner) : BasicEvent(), _owner(owner) { } + + bool Execute(uint64 /*eventTime*/, uint32 /*diff*/) override + { + _owner->CastSpell(_owner, SPELL_ARTHAS_PORTAL, true); + _owner->GetMap()->SetZoneWeather(AREA_TRIAL_OF_THE_CRUSADER, WEATHER_STATE_MEDIUM_SNOW, 0.75f); + return true; + } + +private: + Unit* _owner; }; -class npc_announcer_toc10 : public CreatureScript +struct npc_barrett_toc : public ScriptedAI { - public: - npc_announcer_toc10() : CreatureScript("npc_announcer_toc10") { } - - struct npc_announcer_toc10AI : public ScriptedAI + npc_barrett_toc(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) { } + + void SendActionToTirion(uint32 action) + { + if (Creature* fordring = _instance->GetCreature(DATA_FORDRING)) + fordring->AI()->DoAction(action); + me->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP); + me->GetMotionMaster()->MoveAlongSplineChain(POINT_BARRETT_DESPAWN, SPLINE_INITIAL_MOVEMENT, false); + } + + bool GossipSelect(Player* player, uint32 menuId, uint32 gossipListId) override + { + switch (menuId) { - npc_announcer_toc10AI(Creature* creature) : ScriptedAI(creature), instance(creature->GetInstanceScript()) { } - - InstanceScript* instance; - - void Reset() override - { - me->AddUnitFlag(UNIT_FLAG_NON_ATTACKABLE); - if (Creature* pAlly = GetClosestCreatureWithEntry(me, NPC_THRALL, 300.0f)) - pAlly->AddUnitFlag(UNIT_FLAG_NON_ATTACKABLE); - if (Creature* pAlly = GetClosestCreatureWithEntry(me, NPC_PROUDMOORE, 300.0f)) - pAlly->AddUnitFlag(UNIT_FLAG_NON_ATTACKABLE); - } - - void AttackStart(Unit* /*who*/) override { } - - bool GossipHello(Player* player) override - { - char const* _message = "We are ready!"; - - if (player->IsInCombat() || instance->IsEncounterInProgress()) - return true; - - uint8 i = 0; - for (; i < NUM_MESSAGES; ++i) + case MENUID_NORTHREND_BEASTS: + if (gossipListId == GOSSIPID_FAIL) + SendActionToTirion(ACTION_START_GORMOK_FAIL); + else + SendActionToTirion(ACTION_START_GORMOK); + break; + case MENUID_JARAXXUS: + if (gossipListId == GOSSIPID_FAIL) { - if ((!_GossipMessage[i].state && instance->GetBossState(_GossipMessage[i].encounter) != DONE) - || (_GossipMessage[i].state && instance->GetBossState(_GossipMessage[i].encounter) == DONE)) - { - AddGossipItemFor(player, GOSSIP_ICON_CHAT, _message, GOSSIP_SENDER_MAIN, _GossipMessage[i].id); - break; - } + if (Creature* jaraxxus = _instance->GetCreature(DATA_JARAXXUS)) + jaraxxus->AI()->DoAction(ACTION_JARAXXUS_ENGAGE); + me->GetMotionMaster()->MoveAlongSplineChain(POINT_BARRETT_DESPAWN, SPLINE_INITIAL_MOVEMENT, false); + CloseGossipMenuFor(player); + return true; } + else + SendActionToTirion(ACTION_START_JARAXXUS_EVENT); + break; + case MENUID_FACTION_CHAMPIONS: + if (gossipListId == GOSSIPID_FAIL) + SendActionToTirion(ACTION_START_CHAMPIONS_ENGAGE); + else + SendActionToTirion(ACTION_START_CHAMPIONS); + break; + case MENUID_VALKYR: + if (gossipListId == GOSSIPID_FAIL) + SendActionToTirion(ACTION_START_VALKYR_ENGAGE); + else + SendActionToTirion(ACTION_START_VALKYR); + break; + case MENUID_LK: + SendActionToTirion(ACTION_START_LK_EVENT); + break; + default: + return false; + } - if (i >= NUM_MESSAGES) - return false; + CloseGossipMenuFor(player); + return true; + } - SendGossipMenuFor(player, _GossipMessage[i].msgnum, me->GetGUID()); - return true; - } + void MovementInform(uint32 type, uint32 pointId) override + { + if (type != SPLINE_CHAIN_MOTION_TYPE) + return; - bool GossipSelect(Player* player, uint32 /*menuId*/, uint32 /*gossipListId*/) override - { - ClearGossipMenuFor(player); - CloseGossipMenuFor(player); + if (pointId == POINT_BARRETT_DESPAWN) + me->DespawnOrUnsummon(); + } - if (instance->GetBossState(DATA_NORTHREND_BEASTS) != DONE) - { - instance->SetData(TYPE_EVENT, 110); - instance->SetData(TYPE_NORTHREND_BEASTS, NOT_STARTED); - instance->SetBossState(DATA_NORTHREND_BEASTS, NOT_STARTED); - } - else if (instance->GetBossState(DATA_JARAXXUS) != DONE) - { - // if Jaraxxus is spawned, but the raid wiped - if (Creature* jaraxxus = instance->GetCreature(DATA_JARAXXUS)) - { - jaraxxus->RemoveAurasDueToSpell(SPELL_JARAXXUS_CHAINS); - jaraxxus->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE); - jaraxxus->SetImmuneToPC(false); - jaraxxus->SetReactState(REACT_DEFENSIVE); - jaraxxus->SetInCombatWithZone(); - } - else - { - instance->SetData(TYPE_EVENT, 1010); - instance->SetBossState(DATA_JARAXXUS, NOT_STARTED); - } - } - else if (instance->GetBossState(DATA_FACTION_CRUSADERS) != DONE) - { - if (player->GetTeam() == ALLIANCE) - instance->SetData(TYPE_EVENT, 3000); - else - instance->SetData(TYPE_EVENT, 3001); - instance->SetBossState(DATA_FACTION_CRUSADERS, NOT_STARTED); - } - else if (instance->GetBossState(DATA_TWIN_VALKIRIES) != DONE) - { - instance->SetData(TYPE_EVENT, 4000); - instance->SetBossState(DATA_TWIN_VALKIRIES, NOT_STARTED); - } - else if (instance->GetBossState(DATA_LICH_KING) != DONE) - { - if (me->GetMap()->GetPlayers().getFirst()->GetSource()->GetTeam() == ALLIANCE) - instance->SetData(TYPE_EVENT, 4020); - else - instance->SetData(TYPE_EVENT, 4030); - instance->SetBossState(DATA_LICH_KING, NOT_STARTED); - } - me->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP); - return true; - } - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetTrialOfTheCrusaderAI<npc_announcer_toc10AI>(creature); - } +private: + InstanceScript* _instance; }; -class boss_lich_king_toc : public CreatureScript +struct boss_lich_king_toc : public ScriptedAI { - public: - boss_lich_king_toc() : CreatureScript("boss_lich_king_toc") { } + boss_lich_king_toc(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) { } - struct boss_lich_king_tocAI : public ScriptedAI - { - boss_lich_king_tocAI(Creature* creature) : ScriptedAI(creature) - { - _instance = creature->GetInstanceScript(); - } + void Reset() override + { + me->SetReactState(REACT_PASSIVE); + _instance->SetBossState(DATA_LICH_KING, IN_PROGRESS); + _events.ScheduleEvent(EVENT_START_MOVE, 1s); + } - void Reset() override - { - me->SetReactState(REACT_PASSIVE); - 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->SetDisplayFromModel(1); - } + void MovementInform(uint32 type, uint32 pointId) override + { + if (type != SPLINE_CHAIN_MOTION_TYPE) + return; - _instance->SetBossState(DATA_LICH_KING, IN_PROGRESS); - me->SetWalk(true); - } + if (pointId == POINT_MIDDLE) + _events.ScheduleEvent(EVENT_START_TALK, 4s); + } - void MovementInform(uint32 uiType, uint32 uiId) override - { - if (uiType != POINT_MOTION_TYPE || !_instance) - return; - - switch (uiId) - { - case 0: - _instance->SetData(TYPE_EVENT, 5030); - break; - case 1: - _instance->SetData(TYPE_EVENT, 5050); - break; - default: - break; - } - } + void UpdateAI(uint32 diff) override + { + _events.Update(diff); - void UpdateAI(uint32 uiDiff) override + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) { - if (!_instance) - return; - - if (_instance->GetData(TYPE_EVENT_NPC) != NPC_LICH_KING) - return; - - uint32 _updateTimer = _instance->GetData(TYPE_EVENT_TIMER); - if (_updateTimer <= uiDiff) - { - switch (_instance->GetData(TYPE_EVENT)) - { - case 5010: - Talk(SAY_STAGE_4_02); - _updateTimer = 3*IN_MILLISECONDS; - me->GetMotionMaster()->MovePoint(0, LichKingLoc[0]); - _instance->SetData(TYPE_EVENT, 5020); - break; - case 5030: - Talk(SAY_STAGE_4_04); - me->SetEmoteState(EMOTE_STATE_TALK); - _updateTimer = 10*IN_MILLISECONDS; - _instance->SetData(TYPE_EVENT, 5040); - break; - case 5040: - me->SetEmoteState(EMOTE_ONESHOT_NONE); - me->GetMotionMaster()->MovePoint(1, LichKingLoc[1]); - _updateTimer = 1*IN_MILLISECONDS; - _instance->SetData(TYPE_EVENT, 0); - break; - case 5050: - me->HandleEmoteCommand(EMOTE_ONESHOT_EXCLAMATION); - _updateTimer = 3*IN_MILLISECONDS; - _instance->SetData(TYPE_EVENT, 5060); - break; - case 5060: - Talk(SAY_STAGE_4_05); - me->HandleEmoteCommand(EMOTE_ONESHOT_KNEEL); - _updateTimer = 2.5*IN_MILLISECONDS; - _instance->SetData(TYPE_EVENT, 5070); - break; - case 5070: - me->CastSpell(me, 68198, false); - _updateTimer = 1.5*IN_MILLISECONDS; - _instance->SetData(TYPE_EVENT, 5080); - break; - case 5080: - { - if (GameObject* go = _instance->GetGameObject(DATA_COLISEUM_FLOOR)) - go->SetDestructibleState(GO_DESTRUCTIBLE_DAMAGED); - - me->CastSpell(me, SPELL_CORPSE_TELEPORT, false); - me->CastSpell(me, SPELL_DESTROY_FLOOR_KNOCKUP, false); - - _instance->SetBossState(DATA_LICH_KING, DONE); - - if (!_instance->GetCreature(DATA_ANUBARAK)) - me->SummonCreature(NPC_ANUBARAK, AnubarakLoc[0], TEMPSUMMON_CORPSE_TIMED_DESPAWN, DESPAWN_TIME); - - _instance->SetData(TYPE_EVENT, 0); - - me->DespawnOrUnsummon(); - _updateTimer = 20*IN_MILLISECONDS; - break; - } - default: - break; - } - } - else - _updateTimer -= uiDiff; - - _instance->SetData(TYPE_EVENT_TIMER, _updateTimer); + case EVENT_START_MOVE: + me->GetMotionMaster()->MoveAlongSplineChain(POINT_MIDDLE, SPLINE_INITIAL_MOVEMENT, true); + break; + case EVENT_BREAK_PLATFORM: + DoCastSelf(SPELL_LK_FROST_NOVA, true); + DoCastSelf(SPELL_CORPSE_TELEPORT, true); + DoCastSelf(SPELL_DESTROY_FLOOR_KNOCKUP, true); + if (Creature* fordring = _instance->GetCreature(DATA_FORDRING)) + fordring->AI()->DoAction(ACTION_LK_EVENT_FINISHED); + if (GameObject* floor = _instance->GetGameObject(DATA_COLISEUM_FLOOR)) + floor->SetDestructibleState(GO_DESTRUCTIBLE_DAMAGED); + _instance->SetBossState(DATA_LICH_KING, DONE); + break; + case EVENT_EMOTE_TALK: + me->SetEmoteState(EMOTE_STATE_TALK); + me->GetMap()->SetZoneWeather(AREA_TRIAL_OF_THE_CRUSADER, WEATHER_STATE_FOG, 0.0f); + _events.ScheduleEvent(EVENT_EMOTE_EXCLAMATION, 10s); + break; + case EVENT_EMOTE_EXCLAMATION: + me->HandleEmoteCommand(EMOTE_ONESHOT_EXCLAMATION); + _events.ScheduleEvent(EVENT_EMOTE_KNEEL, 3s); + break; + case EVENT_EMOTE_KNEEL: + me->HandleEmoteCommand(EMOTE_ONESHOT_KNEEL); + break; + case EVENT_START_TALK: + Talk(LK_SAY_EMPIRE); + _events.ScheduleEvent(EVENT_EMOTE_TALK, 4s); + _events.ScheduleEvent(EVENT_BREAK_PLATFORM, 18s); + break; + default: + break; } - - private: - InstanceScript* _instance; - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetTrialOfTheCrusaderAI<boss_lich_king_tocAI>(creature); } + } + +private: + InstanceScript* _instance; + EventMap _events; }; -class npc_fizzlebang_toc : public CreatureScript +struct npc_tirion_toc : public ScriptedAI { - public: - npc_fizzlebang_toc() : CreatureScript("npc_fizzlebang_toc") { } - - struct npc_fizzlebang_tocAI : public ScriptedAI + npc_tirion_toc(Creature* creature) : ScriptedAI(creature), _instance (creature->GetInstanceScript()), _factionLeaderData(0), _summons(me), + _jormungarsSummoned(false), _icehowlSummoned(false) { } + + void Reset() override + { + _events.Reset(); + _factionLeaderData = _instance->GetData(DATA_TEAM) == ALLIANCE ? DATA_VARIAN : DATA_GARROSH; + _jormungarsSummoned = false; + _icehowlSummoned = false; + HandleBarrettSummon(); + } + + void JustSummoned(Creature* summoned) override + { + _summons.Summon(summoned); + } + + void HandleBarrettSummon() + { + if (IsHeroic() && _instance->GetBossState(DATA_NORTHREND_BEASTS) != DONE) + me->SummonCreature(NPC_BARRETT_BEASTS_HC, BarretSpawnPosition); + else if (_instance->GetBossState(DATA_NORTHREND_BEASTS) != DONE) + me->SummonCreature(NPC_BARRETT_BEASTS, BarretSpawnPosition); + else if (_instance->GetBossState(DATA_JARAXXUS) != DONE) + me->SummonCreature(NPC_BARRETT_JARAXXUS, BarretSpawnPosition); + else if (_instance->GetBossState(DATA_FACTION_CRUSADERS) != DONE) + me->SummonCreature(NPC_BARRETT_FACTION, BarretSpawnPosition); + else if (_instance->GetBossState(DATA_TWIN_VALKIRIES) != DONE) + me->SummonCreature(NPC_BARRETT_VALKYR, BarretSpawnPosition); + else if (_instance->GetBossState(DATA_LICH_KING) != DONE) + me->SummonCreature(NPC_BARRETT_LK, BarretSpawnPosition); + } + + void DoAction(int32 action) override + { + switch (action) { - npc_fizzlebang_tocAI(Creature* creature) : ScriptedAI(creature), _summons(me) + case ACTION_START_GORMOK: + Talk(TIRION_SAY_WELCOME); + _events.ScheduleEvent(EVENT_GORMOK_INTRO, 24s); + break; + case ACTION_START_GORMOK_FAIL: + _events.ScheduleEvent(EVENT_GORMOK_INTRO, 1ms); + break; + case ACTION_START_JORMUNGARS: + if (_jormungarsSummoned) + return; + _jormungarsSummoned = true; + Talk(TIRION_SAY_JORMUNGARS); + _instance->DoUseDoorOrButton(_instance->GetGuidData(DATA_MAIN_GATE)); + me->SummonCreature(NPC_DREADSCALE, NorthrendBeastsSpawnPositions[1]); + _events.ScheduleEvent(EVENT_EXCLAMATION, 7s); + break; + case ACTION_START_ICEHOWL: + if (_icehowlSummoned) + return; + _icehowlSummoned = true; + Talk(TIRION_SAY_ICEHOWL); + _instance->DoUseDoorOrButton(_instance->GetGuidData(DATA_MAIN_GATE)); + me->SummonCreature(NPC_ICEHOWL, NorthrendBeastsSpawnPositions[0], TEMPSUMMON_DEAD_DESPAWN); + _events.ScheduleEvent(EVENT_EXCLAMATION, 6s); + break; + case ACTION_NORTHREND_BEASTS_WIPE: + _jormungarsSummoned = false; + _icehowlSummoned = false; + Talk(TIRION_SAY_BEASTS_WIPE); + _events.ScheduleEvent(EVENT_SUMMON_BARRET, 13s); + break; + case ACTION_NORTHREND_BEASTS_DEFEATED: + Talk(TIRION_SAY_BEASTS_DONE); + _events.ScheduleEvent(EVENT_EXCLAMATION, 2s); + _events.ScheduleEvent(EVENT_SUMMON_BARRET, 6s); + break; + case ACTION_START_JARAXXUS_EVENT: + _events.ScheduleEvent(EVENT_START_CALL_WILFRED, 1s); + break; + case ACTION_JARAXXUS_DEFEATED: + _events.ScheduleEvent(EVENT_TIRION_LAMENT, 7s); + break; + case ACTION_JARAXXUS_WIPE: + _events.ScheduleEvent(EVENT_SUMMON_BARRET, 30s); + break; + case ACTION_START_CHAMPIONS: { - _instance = me->GetInstanceScript(); + Talk(TIRION_SAY_CHAMPIONS); + uint32 data = _instance->GetData(DATA_TEAM) == ALLIANCE ? DATA_GARROSH : DATA_VARIAN; + if (Creature* otherFactionLeader = _instance->GetCreature(data)) + otherFactionLeader->AI()->DoAction(ACTION_START_CHAMPIONS); + _events.ScheduleEvent(EVENT_ALLOW_COMBAT, 26s); + break; } - - void JustDied(Unit* killer) override + case ACTION_FACTION_WIPE: + _events.ScheduleEvent(EVENT_SUMMON_BARRET, 4s); + break; + case ACTION_START_CHAMPIONS_ENGAGE: { - Talk(SAY_STAGE_1_06, killer); - _instance->SetData(TYPE_EVENT, 1180); - if (Creature* jaraxxus = _instance->GetCreature(DATA_JARAXXUS)) - { - jaraxxus->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE); - jaraxxus->SetImmuneToPC(false); - jaraxxus->SetReactState(REACT_AGGRESSIVE); - jaraxxus->SetInCombatWithZone(); - } + uint32 data = _instance->GetData(DATA_TEAM) == ALLIANCE ? DATA_GARROSH : DATA_VARIAN; + if (Creature* otherFactionLeader = _instance->GetCreature(data)) + otherFactionLeader->AI()->DoAction(ACTION_START_CHAMPIONS_ENGAGE); + _events.ScheduleEvent(EVENT_SUMMON_CHAMPIONS, 3s); + break; } + case ACTION_CHAMPIONS_DEFEATED: + _events.ScheduleEvent(EVENT_TRAGIC_VICTORY, 7s); + break; + case ACTION_SUMMON_JARAXXUS: + me->SummonCreature(NPC_JARAXXUS, JaraxxusSpawnPosition); + break; + case ACTION_KILL_JARAXXUS: + _events.ScheduleEvent(EVENT_KILL_JARAXXUS, 6s); + break; + case ACTION_START_VALKYR: + Talk(TIRION_SAY_WORK_TOGETHER); + _events.ScheduleEvent(EVENT_SUMMON_VALKYR, 17s); + break; + case ACTION_VALKYR_WIPE: + _events.ScheduleEvent(EVENT_SUMMON_BARRET, 6s); + _summons.DespawnEntry(NPC_LIGHT_ESSENCE); + _summons.DespawnEntry(NPC_DARK_ESSENCE); + break; + case ACTION_VALKYR_DEFEATED: + _events.ScheduleEvent(EVENT_SUMMON_BARRET, 4s); + if (Creature* factionLeader = _instance->GetCreature(_factionLeaderData)) + factionLeader->AI()->DoAction(ACTION_VALKYR_DEFEATED); + _summons.DespawnEntry(NPC_LIGHT_ESSENCE); + _summons.DespawnEntry(NPC_DARK_ESSENCE); + break; + case ACTION_START_VALKYR_ENGAGE: + Talk(TIRION_SAY_GAME_BEGIN); + _events.ScheduleEvent(EVENT_SUMMON_VALKYR, 5s); + break; + case ACTION_START_LK_EVENT: + Talk(TIRION_SAY_UNITED); + me->GetMap()->SetZoneWeather(AREA_TRIAL_OF_THE_CRUSADER, WEATHER_STATE_LIGHT_SNOW, 0.5f); + _events.ScheduleEvent(EVENT_LICH_KING_SAY_CHALLENGE, 19s); + _events.ScheduleEvent(EVENT_SAY_ARTHAS, 26s); + break; + case ACTION_LK_EVENT_FINISHED: + _events.ScheduleEvent(EVENT_LICH_KING_SAY_SOULS, 2s); + break; + default: + break; + } + } - void Reset() override - { - _portalGUID.Clear(); - me->SetWalk(true); - me->GetMotionMaster()->MovePoint(1, ToCCommonLoc[10].GetPositionX(), ToCCommonLoc[10].GetPositionY()-60, ToCCommonLoc[10].GetPositionZ()); - } + void EnterEvadeMode(EvadeReason /*why*/) override + { + // Needed when using hotswap + _summons.DespawnAll(); + } - void MovementInform(uint32 uiType, uint32 uiId) override - { - if (uiType != POINT_MOTION_TYPE) - return; + void UpdateAI(uint32 diff) override + { + _events.Update(diff); - switch (uiId) - { - case 1: - me->SetWalk(false); - _instance->DoUseDoorOrButton(_instance->GetGuidData(DATA_MAIN_GATE)); - _instance->SetData(TYPE_EVENT, 1120); - _instance->SetData(TYPE_EVENT_TIMER, 1*IN_MILLISECONDS); - break; - default: - break; - } - } - - void JustSummoned(Creature* summoned) override + while (uint32 eventId = _events.ExecuteEvent()) + { + switch(eventId) { - _summons.Summon(summoned); + case EVENT_GORMOK_INTRO: + Talk(TIRION_SAY_GORMOK); + if (Creature* factionLeader = _instance->GetCreature(_factionLeaderData)) + factionLeader->AI()->DoAction(ACTION_START_GORMOK); + _events.ScheduleEvent(EVENT_GORMOK_EXCLAMATION, 6s); + break; + case EVENT_GORMOK_EXCLAMATION: + me->HandleEmoteCommand(EMOTE_ONESHOT_EXCLAMATION); + _events.ScheduleEvent(EVENT_SPAWM_GORMOK, 6s); + break; + case EVENT_SPAWM_GORMOK: + _instance->DoUseDoorOrButton(_instance->GetGuidData(DATA_MAIN_GATE)); + me->SummonCreature(NPC_GORMOK, NorthrendBeastsSpawnPositions[0], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 12s); + break; + case EVENT_EXCLAMATION: + me->HandleEmoteCommand(EMOTE_ONESHOT_EXCLAMATION); + break; + case EVENT_SUMMON_BARRET: + HandleBarrettSummon(); + break; + case EVENT_START_CALL_WILFRED: + Talk(TIRION_SAY_WILFRED); + _events.ScheduleEvent(EVENT_SUMMON_WILFRED, 7s); + break; + case EVENT_SUMMON_WILFRED: + _instance->DoUseDoorOrButton(_instance->GetGuidData(DATA_MAIN_GATE)); + me->SummonCreature(NPC_FIZZLEBANG, WilfredSpawnPosition, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 16s); + break; + case EVENT_KILL_JARAXXUS: + Talk(TIRION_SAY_KILL_JARAXXUS); + _events.ScheduleEvent(EVENT_EMOTE_SHEATHE, 2s); + break; + case EVENT_EMOTE_SHEATHE: + me->HandleEmoteCommand(EMOTE_ONESHOT_TALK_NO_SHEATHE); + break; + case EVENT_TIRION_LAMENT: + Talk(TIRION_SAY_LAMENT); + if (Creature* varian = _instance->GetCreature(DATA_VARIAN)) + varian->AI()->DoAction(ACTION_JARAXXUS_DEFEATED); + if (Creature* garrosh = _instance->GetCreature(DATA_GARROSH)) + garrosh->AI()->DoAction(ACTION_JARAXXUS_DEFEATED); + _events.ScheduleEvent(EVENT_TIRION_CALM_DOWN, 33s); + break; + case EVENT_TIRION_CALM_DOWN: + Talk(TIRION_SAY_CALM_DOWN); + _events.ScheduleEvent(EVENT_SUMMON_BARRET, 20s); + break; + case EVENT_ALLOW_COMBAT: + Talk(TIRION_SAY_ALLOW_COMBAT); + _events.ScheduleEvent(EVENT_SUMMON_CHAMPIONS, 7s); + break; + case EVENT_TRAGIC_VICTORY: + Talk(TIRION_SAY_TRAGIC_VICTORY); + _events.ScheduleEvent(EVENT_SUMMON_BARRET, 24s); + break; + case EVENT_SUMMON_VALKYR: + me->SummonCreatureGroup(GROUP_VALKYR); + _events.ScheduleEvent(EVENT_OPEN_GATE, 3s); + break; + case EVENT_OPEN_GATE: + _instance->DoUseDoorOrButton(_instance->GetGuidData(DATA_MAIN_GATE)); + break; + case EVENT_SAY_ARTHAS: + Talk(TIRION_SAY_ARTHAS); + break; + case EVENT_LICH_KING_SAY_CHALLENGE: + if (Creature* lkVoice = _instance->GetCreature(DATA_LICH_KING_VOICE)) + lkVoice->AI()->Talk(LK_VOICE_SAY_CHALLENGE); + if (Creature* arthasPortal = me->SummonCreature(NPC_ARTHAS_PORTAL, ArthasPortalSpawnPosition, TEMPSUMMON_TIMED_DESPAWN, Seconds(34))) + arthasPortal->m_Events.AddEventAtOffset(new ArthasPortalEvent(arthasPortal), 3s); + _events.ScheduleEvent(EVENT_SUMMON_LICH_KING, 5s); + break; + case EVENT_LICH_KING_SAY_SOULS: + if (Creature* lkVoice = _instance->GetCreature(DATA_LICH_KING_VOICE)) + lkVoice->AI()->Talk(LK_VOICE_SAY_SOULS_WILL_BE_MINE); + break; + case EVENT_SUMMON_LICH_KING: + me->SummonCreature(NPC_LICH_KING, LichKingSpawnPosition, TEMPSUMMON_TIMED_DESPAWN, 30s); + break; + case EVENT_SUMMON_CHAMPIONS: + if (Creature* factitonController = me->SummonCreature(NPC_CHAMPIONS_CONTROLLER, ToCCommonLoc[1])) + factitonController->AI()->SetData(0, _instance->GetData(DATA_TEAM)); // will be changed to DoAction soon + _events.ScheduleEvent(EVENT_START_CHAMPIONS, 3s); + break; + case EVENT_START_CHAMPIONS: + if (Creature* factitonController = _instance->GetCreature(DATA_FACTION_CRUSADERS)) + factitonController->AI()->SetData(1, NOT_STARTED); // will be changed to DoAction soon + break; + default: + break; } + } + } + +private: + InstanceScript* _instance; + EventMap _events; + uint32 _factionLeaderData; + SummonList _summons; + bool _jormungarsSummoned; + bool _icehowlSummoned; +}; - void UpdateAI(uint32 uiDiff) override +struct npc_open_portal_target_toc : public ScriptedAI +{ + npc_open_portal_target_toc(Creature* creature) : ScriptedAI(creature) { } + + void Reset() override + { + me->SetReactState(REACT_PASSIVE); + _scheduler.CancelAll(); + me->SetDisableGravity(true); + } + + void SpellHit(Unit* /*caster*/, SpellInfo const* spellInfo) override + { + if (spellInfo->Id == SPELL_OPEN_PORTAL) + { + _scheduler.Schedule(2s, [this](TaskContext /*wilfredPortal*/) { - if (!_instance) - return; - - if (_instance->GetData(TYPE_EVENT_NPC) != NPC_FIZZLEBANG) - return; + DoCastSelf(SPELL_WILFRED_PORTAL); + me->DespawnOrUnsummon(9s); + }); + } + } - uint32 _updateTimer = _instance->GetData(TYPE_EVENT_TIMER); - if (_updateTimer <= uiDiff) - { - switch (_instance->GetData(TYPE_EVENT)) - { - case 1110: - _instance->SetData(TYPE_EVENT, 1120); - _updateTimer = 4*IN_MILLISECONDS; - break; - case 1120: - Talk(SAY_STAGE_1_02); - _instance->SetData(TYPE_EVENT, 1130); - _updateTimer = 12*IN_MILLISECONDS; - break; - case 1130: - me->GetMotionMaster()->MovementExpired(); - Talk(SAY_STAGE_1_03); - me->HandleEmoteCommand(EMOTE_ONESHOT_SPELL_CAST_OMNI); - if (Creature* pTrigger = me->SummonCreature(NPC_TRIGGER, ToCCommonLoc[1].GetPositionX(), ToCCommonLoc[1].GetPositionY(), ToCCommonLoc[1].GetPositionZ(), 4.69494f, TEMPSUMMON_MANUAL_DESPAWN)) - { - _triggerGUID = pTrigger->GetGUID(); - pTrigger->SetObjectScale(2.0f); - pTrigger->SetDisplayFromModel(0); - pTrigger->CastSpell(pTrigger, SPELL_WILFRED_PORTAL, false); - } - _instance->SetData(TYPE_EVENT, 1132); - _updateTimer = 4*IN_MILLISECONDS; - break; - case 1132: - me->GetMotionMaster()->MovementExpired(); - _instance->SetData(TYPE_EVENT, 1134); - _updateTimer = 4*IN_MILLISECONDS; - break; - case 1134: - me->HandleEmoteCommand(EMOTE_ONESHOT_SPELL_CAST_OMNI); - if (Creature* pPortal = me->SummonCreature(NPC_WILFRED_PORTAL, ToCCommonLoc[1].GetPositionX(), ToCCommonLoc[1].GetPositionY(), ToCCommonLoc[1].GetPositionZ(), 4.71239f, TEMPSUMMON_MANUAL_DESPAWN)) - { - pPortal->SetReactState(REACT_PASSIVE); - pPortal->SetObjectScale(2.0f); - pPortal->CastSpell(pPortal, SPELL_WILFRED_PORTAL, false); - _portalGUID = pPortal->GetGUID(); - } - _updateTimer = 4*IN_MILLISECONDS; - _instance->SetData(TYPE_EVENT, 1135); - break; - case 1135: - _instance->SetData(TYPE_EVENT, 1140); - _updateTimer = 3*IN_MILLISECONDS; - break; - case 1140: - Talk(SAY_STAGE_1_04); - if (Creature* jaraxxus = me->SummonCreature(NPC_JARAXXUS, ToCCommonLoc[1].GetPositionX(), ToCCommonLoc[1].GetPositionY(), ToCCommonLoc[1].GetPositionZ(), 5.0f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, DESPAWN_TIME)) - { - jaraxxus->AddUnitFlag(UNIT_FLAG_NON_ATTACKABLE); - jaraxxus->SetImmuneToPC(true); - jaraxxus->SetReactState(REACT_PASSIVE); - jaraxxus->GetMotionMaster()->MovePoint(0, ToCCommonLoc[1].GetPositionX(), ToCCommonLoc[1].GetPositionY()-10, ToCCommonLoc[1].GetPositionZ()); - } - _instance->SetData(TYPE_EVENT, 1142); - _updateTimer = 5*IN_MILLISECONDS; - break; - case 1142: - if (Creature* jaraxxus = _instance->GetCreature(DATA_JARAXXUS)) - jaraxxus->SetTarget(me->GetGUID()); - if (Creature* pTrigger = ObjectAccessor::GetCreature(*me, _triggerGUID)) - pTrigger->DespawnOrUnsummon(); - if (Creature* pPortal = ObjectAccessor::GetCreature(*me, _portalGUID)) - pPortal->DespawnOrUnsummon(); - _instance->SetData(TYPE_EVENT, 1144); - _updateTimer = 10*IN_MILLISECONDS; - break; - case 1144: - if (Creature* jaraxxus = _instance->GetCreature(DATA_JARAXXUS)) - jaraxxus->AI()->Talk(SAY_STAGE_1_05); - _instance->SetData(TYPE_EVENT, 1150); - _updateTimer = 5*IN_MILLISECONDS; - break; - case 1150: - if (Creature* jaraxxus = _instance->GetCreature(DATA_JARAXXUS)) - { - //1-shot Fizzlebang - jaraxxus->CastSpell(me, 67888, false); // 67888 - Fel Lightning - AddThreat(me, 1000.0f, jaraxxus); - jaraxxus->AI()->AttackStart(me); - } - _instance->SetData(TYPE_EVENT, 1160); - _updateTimer = 3*IN_MILLISECONDS; - break; - } - } - else - _updateTimer -= uiDiff; - _instance->SetData(TYPE_EVENT_TIMER, _updateTimer); - } + void UpdateAI(uint32 diff) override + { + _scheduler.Update(diff); + } - private: - InstanceScript* _instance; - SummonList _summons; - ObjectGuid _portalGUID; - ObjectGuid _triggerGUID; - }; +private: + TaskScheduler _scheduler; +}; - CreatureAI* GetAI(Creature* creature) const override +struct npc_fizzlebang_toc : public ScriptedAI +{ + npc_fizzlebang_toc(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) { } + + void Reset() override + { + me->SetReactState(REACT_PASSIVE); + _events.Reset(); + _events.ScheduleEvent(EVENT_START_MOVE, Seconds(1)); + } + + void MovementInform(uint32 type, uint32 pointId) override + { + if (type == SPLINE_CHAIN_MOTION_TYPE && pointId == POINT_SUMMON) { - return GetTrialOfTheCrusaderAI<npc_fizzlebang_tocAI>(creature); + _instance->DoUseDoorOrButton(_instance->GetGuidData(DATA_MAIN_GATE)); + Talk(WILFRED_SAY_INTRO); + _events.ScheduleEvent(EVENT_EMOTE_TALK, 2s); + _events.ScheduleEvent(EVENT_REMOVE_EMOTE_TALK, 9s); + _events.ScheduleEvent(EVENT_OBLIVION, 11s); } -}; + } -class npc_tirion_toc : public CreatureScript -{ - public: - npc_tirion_toc() : CreatureScript("npc_tirion_toc") { } + void UpdateAI(uint32 diff) override + { + _events.Update(diff); - struct npc_tirion_tocAI : public ScriptedAI + while (uint32 eventId = _events.ExecuteEvent()) { - npc_tirion_tocAI(Creature* creature) : ScriptedAI(creature) + switch (eventId) { - _instance = me->GetInstanceScript(); + case EVENT_START_MOVE: + me->GetMotionMaster()->MoveAlongSplineChain(POINT_SUMMON, SPLINE_INITIAL_MOVEMENT, true); + break; + case EVENT_OBLIVION: + me->SummonCreature(NPC_WILFRED_PORTAL, PortalTargetSpawnPosition); + me->SummonCreature(NPC_PURPLE_GROUND, PurpleGroundSpawnPosition, TEMPSUMMON_TIMED_DESPAWN, 16s); + Talk(WILFRED_SAY_OBLIVION); + DoCastSelf(SPELL_OPEN_PORTAL); + _events.ScheduleEvent(EVENT_SUMMON_JARAXXUS, 11s); + break; + case EVENT_SUMMON_JARAXXUS: + if (Creature* fordring = _instance->GetCreature(DATA_FORDRING)) + fordring->AI()->DoAction(ACTION_SUMMON_JARAXXUS); + Talk(WILFRED_SAY_MASTER); + _events.ScheduleEvent(EVENT_EMOTE_TALK, 2s); + _events.ScheduleEvent(EVENT_REMOVE_EMOTE_TALK, 7s); + _events.ScheduleEvent(EVENT_SET_TARGET, 4s); + break; + case EVENT_SET_TARGET: + if (Creature* jaraxxus = _instance->GetCreature(DATA_JARAXXUS)) + me->SetTarget(jaraxxus->GetGUID()); + _events.ScheduleEvent(EVENT_EMOTE_SHEATHE, 6s); + break; + case EVENT_EMOTE_SHEATHE: + me->HandleEmoteCommand(EMOTE_ONESHOT_TALK_NO_SHEATHE); + _events.ScheduleEvent(EVENT_LAST_TALK, 9s); + break; + case EVENT_LAST_TALK: + Talk(WILFRED_SAY_DEAD); + if (Creature* fordring = _instance->GetCreature(DATA_FORDRING)) + fordring->AI()->DoAction(ACTION_KILL_JARAXXUS); + break; + case EVENT_EMOTE_TALK: + me->SetEmoteState(EMOTE_STATE_TALK); + break; + case EVENT_REMOVE_EMOTE_TALK: + me->SetEmoteState(EMOTE_ONESHOT_NONE); + break; + default: + break; } + } + } - void Reset() override { } - - void AttackStart(Unit* /*who*/) override { } - - void UpdateAI(uint32 uiDiff) override - { - if (!_instance) - return; - - if (_instance->GetData(TYPE_EVENT_NPC) != NPC_TIRION_FORDRING) - return; +private: + InstanceScript* _instance; + EventMap _events; +}; - uint32 _updateTimer = _instance->GetData(TYPE_EVENT_TIMER); - if (_updateTimer <= uiDiff) - { - switch (_instance->GetData(TYPE_EVENT)) - { - case 110: - me->SetEmoteState(EMOTE_ONESHOT_TALK); - Talk(SAY_STAGE_0_01); - _updateTimer = 22*IN_MILLISECONDS; - _instance->SetData(TYPE_EVENT, 120); - break; - case 140: - me->SetEmoteState(EMOTE_ONESHOT_TALK); - Talk(SAY_STAGE_0_02); - _updateTimer = 5*IN_MILLISECONDS; - _instance->SetData(TYPE_EVENT, 150); - break; - case 150: - me->SetEmoteState(EMOTE_STATE_NONE); - if (_instance->GetBossState(DATA_NORTHREND_BEASTS) != DONE) - { - _instance->DoUseDoorOrButton(_instance->GetGuidData(DATA_MAIN_GATE)); - - if (Creature* gormok = me->SummonCreature(NPC_GORMOK, ToCSpawnLoc[0].GetPositionX(), ToCSpawnLoc[0].GetPositionY(), ToCSpawnLoc[0].GetPositionZ(), 5, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 30*IN_MILLISECONDS)) - { - gormok->GetMotionMaster()->MovePoint(0, ToCCommonLoc[5].GetPositionX(), ToCCommonLoc[5].GetPositionY(), ToCCommonLoc[5].GetPositionZ()); - gormok->AddUnitFlag(UnitFlags(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE)); - gormok->SetReactState(REACT_PASSIVE); - } - } - _updateTimer = 3*IN_MILLISECONDS; - _instance->SetData(TYPE_EVENT, 155); - break; - case 155: - // 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); - if (_instance->GetBossState(DATA_NORTHREND_BEASTS) != DONE) - { - _instance->DoUseDoorOrButton(_instance->GetGuidData(DATA_MAIN_GATE)); - if (Creature* dreadscale = me->SummonCreature(NPC_DREADSCALE, ToCSpawnLoc[1].GetPositionX(), ToCSpawnLoc[1].GetPositionY(), ToCSpawnLoc[1].GetPositionZ(), 5, TEMPSUMMON_MANUAL_DESPAWN)) - { - dreadscale->GetMotionMaster()->MovePoint(0, ToCCommonLoc[5].GetPositionX(), ToCCommonLoc[5].GetPositionY(), ToCCommonLoc[5].GetPositionZ()); - dreadscale->AddUnitFlag(UnitFlags(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE)); - dreadscale->SetReactState(REACT_PASSIVE); - } - } - _updateTimer = 5*IN_MILLISECONDS; - _instance->SetData(TYPE_EVENT, 220); - break; - case 220: - _instance->SetData(TYPE_EVENT, 230); - break; - case 300: - Talk(SAY_STAGE_0_05); - if (_instance->GetBossState(DATA_NORTHREND_BEASTS) != DONE) - { - _instance->DoUseDoorOrButton(_instance->GetGuidData(DATA_MAIN_GATE)); - if (Creature* icehowl = me->SummonCreature(NPC_ICEHOWL, ToCSpawnLoc[0].GetPositionX(), ToCSpawnLoc[0].GetPositionY(), ToCSpawnLoc[0].GetPositionZ(), 5, TEMPSUMMON_DEAD_DESPAWN)) - { - icehowl->GetMotionMaster()->MovePoint(2, ToCCommonLoc[5].GetPositionX(), ToCCommonLoc[5].GetPositionY(), ToCCommonLoc[5].GetPositionZ()); - me->AddUnitFlag(UnitFlags(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE)); - me->SetReactState(REACT_PASSIVE); - } - } - _updateTimer = 5*IN_MILLISECONDS; - _instance->SetData(TYPE_EVENT, 315); - break; - case 315: - _instance->SetData(TYPE_EVENT, 320); - break; - case 400: - Talk(SAY_STAGE_0_06); - me->GetThreatManager().ClearAllThreat(); - _updateTimer = 5*IN_MILLISECONDS; - _instance->SetData(TYPE_EVENT, 0); - break; - case 666: - Talk(SAY_STAGE_0_WIPE); - _updateTimer = 5*IN_MILLISECONDS; - _instance->SetData(TYPE_EVENT, 0); - break; - case 1010: - Talk(SAY_STAGE_1_01); - _updateTimer = 7*IN_MILLISECONDS; - _instance->DoUseDoorOrButton(_instance->GetGuidData(DATA_MAIN_GATE)); - 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); - break; - case 1180: - Talk(SAY_STAGE_1_07); - _updateTimer = 3*IN_MILLISECONDS; - _instance->SetData(TYPE_EVENT, 0); - break; - case 2000: - Talk(SAY_STAGE_1_08); - _updateTimer = 18*IN_MILLISECONDS; - _instance->SetData(TYPE_EVENT, 2010); - break; - case 2030: - Talk(SAY_STAGE_1_11); - _updateTimer = 5*IN_MILLISECONDS; - _instance->SetData(TYPE_EVENT, 0); - break; - case 3000: - Talk(SAY_STAGE_2_01); - _updateTimer = 12*IN_MILLISECONDS; - _instance->SetData(TYPE_EVENT, 3050); - break; - case 3001: - Talk(SAY_STAGE_2_01); - _updateTimer = 10*IN_MILLISECONDS; - _instance->SetData(TYPE_EVENT, 3051); - break; - case 3060: - Talk(SAY_STAGE_2_03); - _updateTimer = 5*IN_MILLISECONDS; - _instance->SetData(TYPE_EVENT, 3070); - break; - case 3061: - Talk(SAY_STAGE_2_03); - _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); - _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); - _updateTimer = 3*IN_MILLISECONDS; - _instance->SetData(TYPE_EVENT, 3092); - break; - case 3092: - if (Creature* pChampionController = _instance->GetCreature(DATA_FACTION_CRUSADERS)) - pChampionController->AI()->SetData(1, NOT_STARTED); - _instance->SetData(TYPE_EVENT, 3095); - break; - //Crusaders battle end - case 3100: - Talk(SAY_STAGE_2_06); - _updateTimer = 5*IN_MILLISECONDS; - _instance->SetData(TYPE_EVENT, 0); - break; - case 4000: - Talk(SAY_STAGE_3_01); - _updateTimer = 13*IN_MILLISECONDS; - _instance->SetData(TYPE_EVENT, 4010); - break; - case 4010: - Talk(SAY_STAGE_3_02); - if (Creature* lightbane = me->SummonCreature(NPC_FJOLA_LIGHTBANE, ToCSpawnLoc[1].GetPositionX(), ToCSpawnLoc[1].GetPositionY(), ToCSpawnLoc[1].GetPositionZ(), 5, TEMPSUMMON_CORPSE_TIMED_DESPAWN, DESPAWN_TIME)) - { - lightbane->SetVisible(false); - lightbane->SetReactState(REACT_PASSIVE); - lightbane->SummonCreature(NPC_LIGHT_ESSENCE, TwinValkyrsLoc[0].GetPositionX(), TwinValkyrsLoc[0].GetPositionY(), TwinValkyrsLoc[0].GetPositionZ()); - lightbane->SummonCreature(NPC_LIGHT_ESSENCE, TwinValkyrsLoc[1].GetPositionX(), TwinValkyrsLoc[1].GetPositionY(), TwinValkyrsLoc[1].GetPositionZ()); - } - if (Creature* darkbane = me->SummonCreature(NPC_EYDIS_DARKBANE, ToCSpawnLoc[2].GetPositionX(), ToCSpawnLoc[2].GetPositionY(), ToCSpawnLoc[2].GetPositionZ(), 5, TEMPSUMMON_CORPSE_TIMED_DESPAWN, DESPAWN_TIME)) - { - darkbane->SetVisible(false); - darkbane->SetReactState(REACT_PASSIVE); - darkbane->SummonCreature(NPC_DARK_ESSENCE, TwinValkyrsLoc[2].GetPositionX(), TwinValkyrsLoc[2].GetPositionY(), TwinValkyrsLoc[2].GetPositionZ()); - darkbane->SummonCreature(NPC_DARK_ESSENCE, TwinValkyrsLoc[3].GetPositionX(), TwinValkyrsLoc[3].GetPositionY(), TwinValkyrsLoc[3].GetPositionZ()); - } - _updateTimer = 3*IN_MILLISECONDS; - _instance->SetData(TYPE_EVENT, 4015); - break; - case 4015: - _instance->DoUseDoorOrButton(_instance->GetGuidData(DATA_MAIN_GATE)); - if (Creature* lightbane = _instance->GetCreature(DATA_FJOLA_LIGHTBANE)) - { - lightbane->GetMotionMaster()->MovePoint(1, ToCCommonLoc[8].GetPositionX(), ToCCommonLoc[8].GetPositionY(), ToCCommonLoc[8].GetPositionZ()); - lightbane->SetVisible(true); - } - if (Creature* darkbane = _instance->GetCreature(DATA_EYDIS_DARKBANE)) - { - darkbane->GetMotionMaster()->MovePoint(1, ToCCommonLoc[9].GetPositionX(), ToCCommonLoc[9].GetPositionY(), ToCCommonLoc[9].GetPositionZ()); - darkbane->SetVisible(true); - } - _updateTimer = 10*IN_MILLISECONDS; - _instance->SetData(TYPE_EVENT, 4016); - break; - case 4016: - _instance->DoUseDoorOrButton(_instance->GetGuidData(DATA_MAIN_GATE)); - _instance->SetData(TYPE_EVENT, 4017); - break; - case 4040: - _updateTimer = 1*MINUTE*IN_MILLISECONDS; - _instance->SetData(TYPE_EVENT, 5000); - break; - case 5000: - Talk(SAY_STAGE_4_01); - _updateTimer = 10*IN_MILLISECONDS; - _instance->SetData(TYPE_EVENT, 5005); - break; - case 5005: - _updateTimer = 8*IN_MILLISECONDS; - _instance->SetData(TYPE_EVENT, 5010); - me->SummonCreature(NPC_LICH_KING, ToCCommonLoc[2].GetPositionX(), ToCCommonLoc[2].GetPositionY(), ToCCommonLoc[2].GetPositionZ(), 5); - break; - case 5020: - Talk(SAY_STAGE_4_03); - _updateTimer = 1*IN_MILLISECONDS; - _instance->SetData(TYPE_EVENT, 0); - break; - case 6000: - me->SummonCreature(NPC_TIRION_FORDRING_ANUBARAK, EndSpawnLoc[0]); - me->SummonCreature(NPC_ARGENT_MAGE, EndSpawnLoc[1]); - me->SummonGameObject(GO_PORTAL_TO_DALARAN, EndSpawnLoc[2], QuaternionData::fromEulerAnglesZYX(EndSpawnLoc[2].GetOrientation(), 0.0f, 0.0f), 0); - _updateTimer = 20*IN_MILLISECONDS; - _instance->SetData(TYPE_EVENT, 6005); - break; - case 6005: - if (Creature* tirionFordring = _instance->GetCreature(DATA_FORDRING_ANUBARAK)) - tirionFordring->AI()->Talk(SAY_STAGE_4_06); - _updateTimer = 20*IN_MILLISECONDS; - _instance->SetData(TYPE_EVENT, 6010); - break; - case 6010: - if (IsHeroic()) - { - if (Creature* tirionFordring = _instance->GetCreature(DATA_FORDRING_ANUBARAK)) - tirionFordring->AI()->Talk(SAY_STAGE_4_07); - _updateTimer = 1*MINUTE*IN_MILLISECONDS; - _instance->SetBossState(DATA_ANUBARAK, SPECIAL); - _instance->SetData(TYPE_EVENT, 6020); - } - else - _instance->SetData(TYPE_EVENT, 6030); - break; - case 6020: - me->DespawnOrUnsummon(); - _updateTimer = 5*IN_MILLISECONDS; - _instance->SetData(TYPE_EVENT, 6030); - break; - default: - break; - } - } - else - _updateTimer -= uiDiff; - _instance->SetData(TYPE_EVENT_TIMER, _updateTimer); - } - private: - InstanceScript* _instance; - }; +struct npc_garrosh_toc : public ScriptedAI +{ + npc_garrosh_toc(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) { } - CreatureAI* GetAI(Creature* creature) const override + void DoAction(int32 action) override + { + switch (action) { - return GetTrialOfTheCrusaderAI<npc_tirion_tocAI>(creature); + case ACTION_START_GORMOK: + _events.ScheduleEvent(EVENT_GORMOK_INTRO, 12s); + break; + case ACTION_JARAXXUS_DEFEATED: + _events.ScheduleEvent(EVENT_ALLIANCE_DOGS, 14s); + break; + case ACTION_START_CHAMPIONS: + _events.ScheduleEvent(EVENT_DEMAND_JUSTICE, 8s); + break; + case ACTION_SAY_KILLED_PLAYER: + Talk(GARROSH_SAY_KILLED); + break; + case ACTION_CHAMPIONS_DEFEATED: + Talk(GARROSH_SAY_FACTION_DEAD); + break; + case ACTION_VALKYR_DEFEATED: + _events.ScheduleEvent(EVENT_VALKYR_DEAD, 5s); + break; + case ACTION_START_CHAMPIONS_ENGAGE: + _events.ScheduleEvent(EVENT_NO_MERCY, 6s); + break; + default: + break; } -}; + } -class npc_garrosh_toc : public CreatureScript -{ - public: - npc_garrosh_toc() : CreatureScript("npc_garrosh_toc") { } + void UpdateAI(uint32 diff) override + { + _events.Update(diff); - struct npc_garrosh_tocAI : public ScriptedAI + while (uint32 eventId = _events.ExecuteEvent()) { - npc_garrosh_tocAI(Creature* creature) : ScriptedAI(creature) + switch (eventId) { - _instance = me->GetInstanceScript(); + case EVENT_GORMOK_INTRO: + Talk(GARROSH_SAY_BEASTS); + break; + case EVENT_ALLIANCE_DOGS: + Talk(GARROSH_SAY_ALLIANCE_DOGS); + break; + case EVENT_DEMAND_JUSTICE: + Talk(GARROSH_SAY_DEMAND_JUSTICE); + _events.ScheduleEvent(EVENT_NO_MERCY, 21s); + break; + case EVENT_NO_MERCY: + Talk(GARROSH_SAY_NO_MERCY); + break; + case EVENT_VALKYR_DEAD: + Talk(GARROSH_SAY_VALKYR_DEAD); + break; + default: + break; } + } + } - void Reset() override { } - - void AttackStart(Unit* /*who*/) override { } - - void UpdateAI(uint32 uiDiff) override - { - if (!_instance) - return; - - if (_instance->GetData(TYPE_EVENT_NPC) != NPC_GARROSH) - return; +private: + InstanceScript* _instance; + EventMap _events; +}; - uint32 _updateTimer = _instance->GetData(TYPE_EVENT_TIMER); - if (_updateTimer <= uiDiff) - { - switch (_instance->GetData(TYPE_EVENT)) - { - case 130: - me->SetEmoteState(EMOTE_ONESHOT_TALK); - Talk(SAY_STAGE_0_03h); - _updateTimer = 3*IN_MILLISECONDS; - _instance->SetData(TYPE_EVENT, 132); - break; - case 132: - me->SetEmoteState(EMOTE_STATE_NONE); - _updateTimer = 5*IN_MILLISECONDS; - _instance->SetData(TYPE_EVENT, 140); - break; - case 2010: - Talk(SAY_STAGE_1_09); - _updateTimer = 9*IN_MILLISECONDS; - _instance->SetData(TYPE_EVENT, 2020); - break; - case 3050: - Talk(SAY_STAGE_2_02h); - _updateTimer = 15*IN_MILLISECONDS; - _instance->SetData(TYPE_EVENT, 3060); - break; - case 3070: - Talk(SAY_STAGE_2_04h); - _updateTimer = 6*IN_MILLISECONDS; - _instance->SetData(TYPE_EVENT, 3080); - break; - case 3081: - Talk(SAY_STAGE_2_05h); - _updateTimer = 3*IN_MILLISECONDS; - _instance->SetData(TYPE_EVENT, 3091); - break; - case 4030: - Talk(SAY_STAGE_3_03h); - _updateTimer = 5*IN_MILLISECONDS; - _instance->SetData(TYPE_EVENT, 4040); - break; - default: - break; - } - } - else - _updateTimer -= uiDiff; - _instance->SetData(TYPE_EVENT_TIMER, _updateTimer); - } - private: - InstanceScript* _instance; - }; +struct npc_varian_toc : public ScriptedAI +{ + npc_varian_toc(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) { } - CreatureAI* GetAI(Creature* creature) const override + void DoAction(int32 action) override + { + switch (action) { - return GetTrialOfTheCrusaderAI<npc_garrosh_tocAI>(creature); + case ACTION_START_GORMOK: + _events.ScheduleEvent(EVENT_GORMOK_INTRO, 11s); + break; + case ACTION_JARAXXUS_DEFEATED: + _events.ScheduleEvent(EVENT_COME_PIGS, 24s); + break; + case ACTION_START_CHAMPIONS: + _events.ScheduleEvent(EVENT_DEMAND_JUSTICE, 9s); + break; + case ACTION_SAY_KILLED_PLAYER: + Talk(VARIAN_SAY_KILLED); + break; + case ACTION_CHAMPIONS_DEFEATED: + Talk(VARIAN_SAY_FACTION_DEAD); + break; + case ACTION_VALKYR_DEFEATED: + _events.ScheduleEvent(EVENT_VALKYR_DEAD, 6s); + break; + case ACTION_START_CHAMPIONS_ENGAGE: + _events.ScheduleEvent(EVENT_NO_MERCY, 6s); + break; + default: + break; } -}; + } -class npc_varian_toc : public CreatureScript -{ - public: - npc_varian_toc() : CreatureScript("npc_varian_toc") { } + void UpdateAI(uint32 diff) override + { + _events.Update(diff); - struct npc_varian_tocAI : public ScriptedAI + while (uint32 eventId = _events.ExecuteEvent()) { - npc_varian_tocAI(Creature* creature) : ScriptedAI(creature) + switch (eventId) { - _instance = me->GetInstanceScript(); + case EVENT_GORMOK_INTRO: + Talk(VARIAN_SAY_BEASTS); + break; + case EVENT_COME_PIGS: + Talk(VARIAN_SAY_COME_PIGS); + break; + case EVENT_DEMAND_JUSTICE: + Talk(VARIAN_SAY_DEMAND_JUSTICE); + _events.ScheduleEvent(EVENT_NO_MERCY, 20s); + break; + case EVENT_NO_MERCY: + Talk(VARIAN_SAY_FIGHT_GLORY); + break; + case EVENT_VALKYR_DEAD: + Talk(VARIAN_SAY_VALKYR_DEAD); + break; + default: + break; } + } + } - void Reset() override { } - - void AttackStart(Unit* /*who*/) override { } - - void UpdateAI(uint32 uiDiff) override - { - if (!_instance) - return; +private: + InstanceScript* _instance; + EventMap _events; +}; - if (_instance->GetData(TYPE_EVENT_NPC) != NPC_VARIAN) - return; +// 69016 - Corpse Teleport +class spell_lich_king_teleport_corpse : public SpellScript +{ + PrepareSpellScript(spell_lich_king_teleport_corpse); - uint32 _updateTimer = _instance->GetData(TYPE_EVENT_TIMER); - if (_updateTimer <= uiDiff) - { - switch (_instance->GetData(TYPE_EVENT)) - { - case 120: - me->SetEmoteState(EMOTE_ONESHOT_TALK); - Talk(SAY_STAGE_0_03a); - _updateTimer = 2*IN_MILLISECONDS; - _instance->SetData(TYPE_EVENT, 122); - break; - case 122: - me->SetEmoteState(EMOTE_STATE_NONE); - _updateTimer = 3*IN_MILLISECONDS; - _instance->SetData(TYPE_EVENT, 130); - break; - case 2020: - Talk(SAY_STAGE_1_10); - _updateTimer = 5*IN_MILLISECONDS; - _instance->SetData(TYPE_EVENT, 2030); - break; - case 3051: - Talk(SAY_STAGE_2_02a); - _updateTimer = 17*IN_MILLISECONDS; - _instance->SetData(TYPE_EVENT, 3061); - break; - case 3071: - Talk(SAY_STAGE_2_04a); - _updateTimer = 5*IN_MILLISECONDS; - _instance->SetData(TYPE_EVENT, 3081); - break; - case 3080: - Talk(SAY_STAGE_2_05a); - _updateTimer = 3*IN_MILLISECONDS; - _instance->SetData(TYPE_EVENT, 3090); - break; - case 4020: - Talk(SAY_STAGE_3_03a); - _updateTimer = 5*IN_MILLISECONDS; - _instance->SetData(TYPE_EVENT, 4040); - break; - default: - break; - } - } - else - _updateTimer -= uiDiff; - _instance->SetData(TYPE_EVENT_TIMER, _updateTimer); - } - private: - InstanceScript* _instance; - }; + void HandleTeleport(SpellEffIndex /*effIndex*/) + { + GetHitUnit()->NearTeleportTo(CorpseTeleportPosition); + } - CreatureAI* GetAI(Creature* creature) const override - { - return GetTrialOfTheCrusaderAI<npc_varian_tocAI>(creature); - } + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_lich_king_teleport_corpse::HandleTeleport, EFFECT_0, SPELL_EFFECT_DUMMY); + } }; void AddSC_trial_of_the_crusader() { - new boss_lich_king_toc(); - new npc_announcer_toc10(); - new npc_fizzlebang_toc(); - new npc_tirion_toc(); - new npc_garrosh_toc(); - new npc_varian_toc(); + RegisterTrialOfTheCrusaderCreatureAI(npc_barrett_toc); + RegisterTrialOfTheCrusaderCreatureAI(boss_lich_king_toc); + RegisterTrialOfTheCrusaderCreatureAI(npc_tirion_toc); + RegisterTrialOfTheCrusaderCreatureAI(npc_open_portal_target_toc); + RegisterTrialOfTheCrusaderCreatureAI(npc_fizzlebang_toc); + RegisterTrialOfTheCrusaderCreatureAI(npc_garrosh_toc); + RegisterTrialOfTheCrusaderCreatureAI(npc_varian_toc); + RegisterSpellScript(spell_lich_king_teleport_corpse); } 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 76451d9b865..e740dba7ee3 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 @@ -37,13 +37,12 @@ enum TCRDataTypes DATA_ANUBARAK = 5, // Additional Data - DATA_GORMOK_THE_IMPALER = 5, - DATA_ACIDMAW = 6, - DATA_DREADSCALE = 7, - DATA_ICEHOWL = 8, - DATA_FJOLA_LIGHTBANE = 9, - DATA_EYDIS_DARKBANE = 10, - DATA_BARRET_RAMSEY = 11, + DATA_GORMOK_THE_IMPALER = 6, + DATA_ACIDMAW = 7, + DATA_DREADSCALE = 8, + DATA_ICEHOWL = 9, + DATA_FJOLA_LIGHTBANE = 10, + DATA_EYDIS_DARKBANE = 11, DATA_FORDRING = 12, DATA_FORDRING_ANUBARAK = 13, DATA_VARIAN = 14, @@ -57,9 +56,14 @@ enum TCRDataTypes DATA_EAST_PORTCULLIS = 21, DATA_WEB_DOOR = 22, DATA_TRIBUTE_CHEST = 23, + DATA_BEASTS_COMBAT_STALKER = 24, + DATA_FURIOUS_CHARGE = 25, + DATA_DESPAWN_SNOBOLDS = 26, + DATA_TEAM = 27, + DATA_LICH_KING_VOICE = 28, - TYPE_COUNTER = 24, - TYPE_EVENT = 25, + TYPE_COUNTER = 29, + TYPE_EVENT = 30, TYPE_EVENT_TIMER = 101, TYPE_EVENT_NPC = 102, @@ -69,20 +73,54 @@ enum TCRDataTypes DATA_MISTRESS_OF_PAIN_COUNT = 302, INCREASE = 501, - DECREASE = 502, + DECREASE = 502 }; enum TCRSpellIds { SPELL_WILFRED_PORTAL = 68424, + SPELL_OPEN_PORTAL = 67864, SPELL_JARAXXUS_CHAINS = 67924, - SPELL_CORPSE_TELEPORT = 69016, SPELL_DESTROY_FLOOR_KNOCKUP = 68193, + SPELL_ARTHAS_PORTAL = 51807, + SPELL_LK_FROST_NOVA = 68198, + SPELL_CORPSE_TELEPORT = 69016 }; -enum TCRMiscData +enum TCRMisc { - DESPAWN_TIME = 1200000 + DESPAWN_TIME = 1200000, + PLAYER_VEHICLE_ID = 444 +}; + +enum TCRActions +{ + ACTION_START_GORMOK = 1, + ACTION_START_GORMOK_FAIL, + ACTION_START_JORMUNGARS, + ACTION_START_ICEHOWL, + ACTION_NORTHREND_BEASTS_WIPE, + ACTION_NORTHREND_BEASTS_DEFEATED, + ACTION_START_JARAXXUS_EVENT, + ACTION_KILL_JARAXXUS, + ACTION_JARAXXUS_DEFEATED, + ACTION_START_CHAMPIONS, + ACTION_SUMMON_CHAMPIONS, + ACTION_TIRION_ALLOW, + ACTION_CHAMPIONS_DEFEATED, + ACTION_SUMMON_JARAXXUS, + ACTION_JARAXXUS_INTRO, + ACTION_START_VALKYR, + ACTION_START_LK_EVENT, + ACTION_SAY_KILLED_PLAYER, + ACTION_VALKYR_DEFEATED, + ACTION_LK_EVENT_FINISHED, + ACTION_JARAXXUS_ENGAGE, + ACTION_START_CHAMPIONS_ENGAGE, + ACTION_START_VALKYR_ENGAGE, + ACTION_JARAXXUS_WIPE, + ACTION_FACTION_WIPE, + ACTION_VALKYR_WIPE }; extern Position const ToCCommonLoc[]; @@ -119,7 +157,12 @@ enum AnnouncerMessages enum TCRCreatureIds { - NPC_BARRET_RAMSEY = 34816, + NPC_BARRETT_BEASTS = 34816, + NPC_BARRETT_BEASTS_HC = 35909, + NPC_BARRETT_JARAXXUS = 35035, + NPC_BARRETT_FACTION = 35766, + NPC_BARRETT_VALKYR = 35770, + NPC_BARRETT_LK = 35771, NPC_TIRION_FORDRING = 34996, NPC_TIRION_FORDRING_ANUBARAK = 36095, NPC_ARGENT_MAGE = 36097, @@ -131,17 +174,19 @@ enum TCRCreatureIds NPC_THRALL = 34994, NPC_PROUDMOORE = 34992, NPC_WILFRED_PORTAL = 17965, - NPC_TRIGGER = 35651, + NPC_PURPLE_GROUND = 35651, NPC_ICEHOWL = 34797, NPC_GORMOK = 34796, NPC_DREADSCALE = 34799, NPC_ACIDMAW = 35144, + NPC_BEASTS_COMBAT_STALKER = 36549, + NPC_FURIOUS_CHARGE_STALKER = 35062, + NPC_SNOBOLD_VASSAL = 34800, NPC_JARAXXUS = 34780, NPC_CHAMPIONS_CONTROLLER = 34781, - NPC_ALLIANCE_DEATH_KNIGHT = 34461, NPC_ALLIANCE_DRUID_BALANCE = 34460, NPC_ALLIANCE_DRUID_RESTORATION = 34469, @@ -178,6 +223,9 @@ enum TCRCreatureIds NPC_DARK_ESSENCE = 34567, NPC_LIGHT_ESSENCE = 34568, + NPC_LICH_KING_VOICE = 16980, + NPC_ARTHAS_PORTAL = 22517, + NPC_ANUBARAK = 34564 }; @@ -247,4 +295,6 @@ inline AI* GetTrialOfTheCrusaderAI(T* obj) return GetInstanceAI<AI>(obj, ToCrScriptName); } +#define RegisterTrialOfTheCrusaderCreatureAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetTrialOfTheCrusaderAI) + #endif diff --git a/src/server/scripts/Spells/spell_generic.cpp b/src/server/scripts/Spells/spell_generic.cpp index c45451c869a..6c9e8cd80ac 100644 --- a/src/server/scripts/Spells/spell_generic.cpp +++ b/src/server/scripts/Spells/spell_generic.cpp @@ -2701,7 +2701,8 @@ class spell_gen_spectator_cheer_trigger : public SpellScript void HandleDummy(SpellEffIndex /*effIndex*/) { - GetCaster()->HandleEmoteCommand(EmoteArray[urand(0, 2)]); + if (roll_chance_i(40)) + GetCaster()->HandleEmoteCommand(EmoteArray[urand(0, 2)]); } void Register() override |