diff --git a/data/sql/updates/pending_db_world/rev_1711048056647652400.sql b/data/sql/updates/pending_db_world/rev_1711048056647652400.sql new file mode 100644 index 000000000..391553a3a --- /dev/null +++ b/data/sql/updates/pending_db_world/rev_1711048056647652400.sql @@ -0,0 +1,46 @@ +-- +UPDATE `creature_template` SET `AIName` = '', `ScriptName` = 'npc_ashtongue_channeler', `faction` = 1692 WHERE (`entry` = 23421); +UPDATE `creature_template` SET `AIName` = '', `ScriptName` = 'npc_ashtongue_sorcerer' WHERE (`entry` = 23215); +DELETE FROM `smart_scripts` WHERE (`entryorguid` = 23215) AND (`source_type` = 0); +UPDATE `creature_template_addon` SET `auras` = '39833' WHERE (`entry` = 22841); +UPDATE `creature_template` SET `faction` = 1847 WHERE (`entry` = 23210); +UPDATE `creature_template` SET `faction` = 1813 WHERE (`entry` = 23319); + +DELETE FROM `creature_text` WHERE `CreatureID` = 23191; +INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES +(23191, 0, 0, 'Broken of the Ashtongue tribe, your leader speaks!', 14, 0, 100, 15, 0, 0, 21342, 0, 'Akama SAY_BROKEN_FREE_0'), +(23191, 1, 0, 'The Betrayer no longer holds sway over us. His dark magic over the Ashtongue soul has been destroyed!', 14, 0, 100, 1, 0, 0, 21343, 0, 'Akama SAY_BROKEN_FREE_1'), +(23191, 2, 0, 'Come out from the shadows! I\'ve returned to lead you against our true enemy! Shed your chains and raise your weapons against your Illidari masters!', 14, 0, 100, 397, 0, 0, 21344, 0, 'Akama SAY_BROKEN_FREE_2'), +(23191, 3, 0, 'I will not last much longer!', 14, 0, 100, 0, 0, 11385, 21784, 0, 'Akama SAY_LOW_HEALTH'), +(23191, 4, 0, 'No! Not yet!', 14, 0, 100, 0, 0, 11386, 21785, 0, 'Akama SAY_DEAD'); + +UPDATE `creature` SET `spawntimesecs` = 300 WHERE `id1` = 23191 AND `map` = 564; + +DELETE FROM `creature_formations` WHERE `leaderGUID` = 148236; +INSERT INTO `creature_formations` (`memberGUID`, `leaderGUID`, `groupAI`) VALUES +(148236, 148236, 24), +(148237, 148236, 24), +(148238, 148236, 24), +(148239, 148236, 24), +(148240, 148236, 24), +(148241, 148236, 24), +(148242, 148236, 24); + +-- Delete leftover gobs +DELETE FROM `gameobject` WHERE `guid` IN (20523,20558,20559,20561,20563,20567) AND `map` = 564; + +DELETE FROM `creature_text` WHERE `CreatureID` = 23089 AND `GroupID` IN (9, 10); +INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES +(23089, 9, 0, 'Those who\'ve defiled this temple have all been defeated. All but one!', 12, 0, 100, 1, 0, 0, 21518, 0, 'SAY_AKAMA_COUNCIL_1'), +(23089, 10, 0, 'Let us finish what we\'ve started. I will lead you to Illidan\'s abode once you\'ve recovered your strength.', 12, 0, 100, 1, 0, 0, 21520, 0, 'SAY_AKAMA_COUNCIL_2'); + +DELETE FROM `waypoint_data` WHERE `id` = 230891; +INSERT INTO `waypoint_data` (`id`, `point`, `position_x`, `position_y`, `position_z`, `move_type`) VALUES +(230891, 1, 642.5905, 305.6287, 271.6885, 1), +(230891, 2, 660.76465, 305.76627, 271.70413, 1); + +UPDATE `creature` SET `phaseMask` = 3 WHERE `guid` = 148734; +UPDATE `creature` SET `phaseMask` = 5 WHERE `guid` = 148733; + +DELETE FROM `smart_scripts` WHERE `source_type` = 2 AND `entryorguid` = 4665; +INSERT INTO `smart_scripts` VALUES (4665, 2, 0, 0, 46, 0, 100, 1, 0, 0, 0, 0, 0, 0, 45, 0, 1, 0, 0, 0, 0, 10, 148358, 22871, 0, 0, 0, 0, 0, 0, 'Area Trigger - On Trigger - Teron Gorefiend Talk'); diff --git a/src/server/scripts/Outland/BlackTemple/black_temple.h b/src/server/scripts/Outland/BlackTemple/black_temple.h index 4944e0b7e..491125714 100644 --- a/src/server/scripts/Outland/BlackTemple/black_temple.h +++ b/src/server/scripts/Outland/BlackTemple/black_temple.h @@ -40,17 +40,27 @@ enum DataTypes DATA_RELIQUARY_OF_SOULS = 5, DATA_MOTHER_SHAHRAZ = 6, DATA_ILLIDARI_COUNCIL = 7, - DATA_AKAMA_FINISHED = 8, + DATA_AKAMA_ILLIDAN = 8, DATA_ILLIDAN_STORMRAGE = 9, - MAX_ENCOUNTERS = 10 + MAX_ENCOUNTERS = 10, + + DATA_AKAMA_SHADE = 11, + DATA_GATHIOS_THE_SHATTERER = 12, + DATA_HIGH_NETHERMANCER_ZEREVOR = 13, + DATA_LADY_MALANDE = 14, + DATA_VERAS_DARKSHADOW = 15 }; enum CreatureIds { + NPC_HIGH_WARLORD_NAJENTUS = 22887, + NPC_SUPREMUS = 22898, NPC_SHADE_OF_AKAMA = 22841, NPC_AKAMA_SHADE = 23191, - NPC_STORM_FURY = 22848, + NPC_ASHTONGUE_CHANNELER = 23421, + NPC_CREATURE_GENERATOR_AKAMA = 23210, NPC_TERON_GOREFIEND = 22871, + NPC_GURTOGG_BLOODBOIL = 22948, NPC_VENGEFUL_SPIRIT = 23109, NPC_SHADOWY_CONSTRUCT = 23111, NPC_ANGERED_SOUL_FRAGMENT = 23398, @@ -58,17 +68,26 @@ enum CreatureIds NPC_SUFFERING_SOUL_FRAGMENT = 23399, NPC_RELIQUARY_OF_THE_LOST = 22856, NPC_ENSLAVED_SOUL = 23469, + NPC_MOTHER_SHAHRAZ = 22947, NPC_GATHIOS_THE_SHATTERER = 22949, NPC_HIGH_NETHERMANCER_ZEREVOR = 22950, NPC_LADY_MALANDE = 22951, NPC_VERAS_DARKSHADOW = 22952, NPC_ILLIDARI_COUNCIL = 23426, - NPC_AKAMA = 23089, + NPC_AKAMA_ILLIDAN = 23089, NPC_ILLIDAN_STORMRAGE = 22917, NPC_PARASITIC_SHADOWFIEND = 23498, NPC_BLADE_OF_AZZINOTH = 22996, NPC_FLAME_OF_AZZINOTH = 22997, + NPC_ASHTONGUE_BATTLELORD = 22844, + NPC_ASHTONGUE_MYSTIC = 22845, + NPC_ASHTONGUE_STORMCALLER = 22846, + NPC_ASHTONGUE_PRIMALIST = 22847, + NPC_ASHTONGUE_FERAL_SPIRIT = 22849, + NPC_ASHTONGUE_STALKER = 23374, + NPC_STORM_FURY = 22848, + NPC_DRAGON_TURTLE = 22885 }; diff --git a/src/server/scripts/Outland/BlackTemple/boss_illidan.cpp b/src/server/scripts/Outland/BlackTemple/boss_illidan.cpp index c860ef94d..698375624 100644 --- a/src/server/scripts/Outland/BlackTemple/boss_illidan.cpp +++ b/src/server/scripts/Outland/BlackTemple/boss_illidan.cpp @@ -48,6 +48,8 @@ enum Says SAY_AKAMA_ILLIDAN1 = 4, SAY_AKAMA_ILLIDAN2 = 5, SAY_AKAMA_ILLIDAN3 = 6, + SAY_AKAMA_COUNCIL_1 = 9, + SAY_AKAMA_COUNCIL_2 = 10, SAY_MAIEV_SHADOWSONG_TAUNT = 0, SAY_MAIEV_SHADOWSONG_ILLIDAN1 = 1, @@ -117,6 +119,7 @@ enum Spells enum Misc { + ACTION_ILLIDARI_COUNCIL_DONE = 0, ACTION_FIGHT_MINIONS = 1, ACTION_RETURN_BLADE = 2, ACTION_ILLIDAN_CAGED = 3, @@ -133,7 +136,9 @@ enum Misc NPC_ILLIDAN_DB_TARGET = 23070, NPC_MAIEV_SHADOWSONG = 23197, - GO_CAGE_TRAP = 185916 + GO_CAGE_TRAP = 185916, + + PATH_AKAMA_ILLIDARI_COUNCIL_1 = 230891 }; enum Events @@ -237,13 +242,13 @@ public: { BossAI::EnterEvadeMode(why); - if (Creature* akama = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_AKAMA))) + if (Creature* akama = instance->GetCreature(NPC_AKAMA_ILLIDAN)) akama->AI()->EnterEvadeMode(why); } bool CanAIAttack(Unit const* target) const override { - return target->GetEntry() != NPC_AKAMA && target->GetEntry() != NPC_MAIEV_SHADOWSONG; + return target->GetEntry() != NPC_AKAMA_ILLIDAN && target->GetEntry() != NPC_MAIEV_SHADOWSONG; } void DoAction(int32 param) override @@ -408,7 +413,7 @@ public: switch (events2.ExecuteEvent()) { case EVENT_SUMMON_MINIONS2: - if (Creature* akama = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_AKAMA))) + if (Creature* akama = instance->GetCreature(NPC_AKAMA_ILLIDAN)) akama->AI()->DoAction(ACTION_FIGHT_MINIONS); break; case EVENT_PHASE_2_EYE_BEAM_START: @@ -445,7 +450,7 @@ public: maiev->AI()->Talk(SAY_MAIEV_SHADOWSONG_ILLIDAN3); } - if (Creature* akama = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_AKAMA))) + if (Creature* akama = instance->GetCreature(NPC_AKAMA_ILLIDAN)) { akama->AI()->DoAction(ACTION_ILLIDAN_DEAD); akama->SetTarget(me->GetGUID()); @@ -754,6 +759,8 @@ enum Akama EVENT_AKAMA_HEALTH = 102 }; +Position AkamaTeleport = { 609.772f, 308.456f, 271.826f, 6.1972566f }; + class npc_akama_illidan : public CreatureScript { public: @@ -764,7 +771,7 @@ public: npc_akama_illidanAI(Creature* creature) : npc_escortAI(creature), summons(me) { instance = creature->GetInstanceScript(); - if (instance->GetBossState(DATA_AKAMA_FINISHED) == DONE) + if (instance->GetBossState(DATA_AKAMA_ILLIDAN) == DONE) { me->GetMap()->LoadGrid(751.664f, 238.933f); me->SetHomePosition(751.664f, 238.933f, 353.106f, 2.18f); @@ -789,6 +796,12 @@ public: summons.DespawnAll(); me->CombatStop(true); } + else if (param == ACTION_ILLIDARI_COUNCIL_DONE) + { + me->NearTeleportTo(AkamaTeleport); + me->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP); + me->GetMotionMaster()->MovePath(PATH_AKAMA_ILLIDARI_COUNCIL_1, false); + } } void Reset() override @@ -796,7 +809,6 @@ public: me->SetReactState(REACT_AGGRESSIVE); me->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP); me->setActive(false); - me->SetVisible(instance->GetBossState(DATA_ILLIDARI_COUNCIL) == DONE && instance->GetBossState(DATA_ILLIDAN_STORMRAGE) != DONE); events.Reset(); summons.DespawnAll(); } @@ -807,7 +819,7 @@ public: me->ReplaceAllNpcFlags(UNIT_NPC_FLAG_NONE); me->setActive(true); - if (instance->GetBossState(DATA_AKAMA_FINISHED) != DONE) + if (instance->GetBossState(DATA_AKAMA_ILLIDAN) != DONE) { me->SetReactState(REACT_PASSIVE); Start(false, true); @@ -830,6 +842,22 @@ public: } } + void PathEndReached(uint32 pathId) override + { + if (pathId == PATH_AKAMA_ILLIDARI_COUNCIL_1) + { + ScheduleUniqueTimedEvent(200ms, [&] + { + Talk(SAY_AKAMA_COUNCIL_1); + }, 1); + ScheduleUniqueTimedEvent(7800ms, [&] + { + Talk(SAY_AKAMA_COUNCIL_2); + me->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP); + }, 2); + } + } + void JustSummoned(Creature* summon) override { summons.Summon(summon); @@ -878,6 +906,7 @@ public: void UpdateEscortAI(uint32 diff) override { + scheduler.Update(diff); events.Update(diff); switch (events.ExecuteEvent()) { @@ -913,8 +942,8 @@ public: udalo->CastSpell(udalo, SPELL_AKAMA_DOOR_OPEN, false); break; case EVENT_AKAMA_SCENE_9: - instance->SetBossState(DATA_AKAMA_FINISHED, NOT_STARTED); - instance->SetBossState(DATA_AKAMA_FINISHED, DONE); + instance->SetBossState(DATA_AKAMA_ILLIDAN, NOT_STARTED); + instance->SetBossState(DATA_AKAMA_ILLIDAN, DONE); break; case EVENT_AKAMA_SCENE_10: Talk(SAY_AKAMA_BEWARE); @@ -923,40 +952,40 @@ public: SetEscortPaused(false); break; case EVENT_AKAMA_SCENE_20: - if (Creature* illidan = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_ILLIDAN_STORMRAGE))) + if (Creature* illidan = instance->GetCreature(DATA_ILLIDAN_STORMRAGE)) illidan->SetStandState(UNIT_STAND_STATE_STAND); break; case EVENT_AKAMA_SCENE_21: me->SetFacingTo(M_PI); break; case EVENT_AKAMA_SCENE_22: - if (Creature* illidan = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_ILLIDAN_STORMRAGE))) + if (Creature* illidan = instance->GetCreature(DATA_ILLIDAN_STORMRAGE)) illidan->AI()->Talk(SAY_ILLIDAN_AKAMA1); break; case EVENT_AKAMA_SCENE_23: Talk(SAY_AKAMA_ILLIDAN1); break; case EVENT_AKAMA_SCENE_24: - if (Creature* illidan = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_ILLIDAN_STORMRAGE))) + if (Creature* illidan = instance->GetCreature(DATA_ILLIDAN_STORMRAGE)) illidan->AI()->Talk(SAY_ILLIDAN_AKAMA2); break; case EVENT_AKAMA_SCENE_25: Talk(SAY_AKAMA_ILLIDAN2); break; case EVENT_AKAMA_SCENE_26: - if (Creature* illidan = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_ILLIDAN_STORMRAGE))) + if (Creature* illidan = instance->GetCreature(DATA_ILLIDAN_STORMRAGE)) illidan->AI()->Talk(SAY_ILLIDAN_AKAMA3); break; case EVENT_AKAMA_SCENE_27: - if (Creature* illidan = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_ILLIDAN_STORMRAGE))) + if (Creature* illidan = instance->GetCreature(DATA_ILLIDAN_STORMRAGE)) illidan->LoadEquipment(1, true); break; case EVENT_AKAMA_SCENE_28: - if (Creature* illidan = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_ILLIDAN_STORMRAGE))) + if (Creature* illidan = instance->GetCreature(DATA_ILLIDAN_STORMRAGE)) illidan->HandleEmoteCommand(EMOTE_ONESHOT_TALK_NO_SHEATHE); break; case EVENT_AKAMA_SCENE_29: - if (Creature* illidan = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_ILLIDAN_STORMRAGE))) + if (Creature* illidan = instance->GetCreature(DATA_ILLIDAN_STORMRAGE)) { illidan->SetImmuneToAll(false); illidan->SetInCombatWithZone(); diff --git a/src/server/scripts/Outland/BlackTemple/boss_shade_of_akama.cpp b/src/server/scripts/Outland/BlackTemple/boss_shade_of_akama.cpp index 691c345e0..d55c9169f 100644 --- a/src/server/scripts/Outland/BlackTemple/boss_shade_of_akama.cpp +++ b/src/server/scripts/Outland/BlackTemple/boss_shade_of_akama.cpp @@ -25,30 +25,43 @@ enum Says SAY_BROKEN_FREE_0 = 0, SAY_BROKEN_FREE_1 = 1, SAY_BROKEN_FREE_2 = 2, + SAY_LOW_HEALTH = 3, + SAY_DEATH = 4, + SAY_BROKEN_S1 = 0, SAY_BROKEN_S2 = 1 }; enum Spells { + // Akama SPELL_STEALTH = 34189, - SPELL_AKAMA_SOUL_CHANNEL = 40447, - SPELL_SHADE_SOUL_CHANNEL = 40401, - SPELL_CHAIN_LIGHTNING = 39945, SPELL_DESTRUCTIVE_POISON = 40874, - SPELL_SHADE_OF_AKAMA_TRIGGER = 40955, - SPELL_AKAMA_SOUL_RETRIEVE = 40902, + SPELL_CHAIN_LIGHTNING = 39945, + SPELL_AKAMA_SOUL_CHANNEL = 40447, + SPELL_FIXATE = 40607, + SPELL_AKAMA_SOUL_RETRIEVE = 40902, // epilogue + SPELL_AKAMA_SOUL_EXPEL_CHANNEL = 40927, // epilogue - SPELL_ASHTONGUE_WAVE_B = 42035, - SPELL_SUMMON_ASHTONGUE_SORCERER = 40476, - SPELL_SUMMON_ASHTONGUE_DEFENDER = 40474 + // Shade & Channelers + SPELL_SHADE_SOUL_CHANNEL = 40401, + SPELL_THREAT = 41602, + SPELL_SHADE_OF_AKAMA_TRIGGER = 40955, + + // Summons + SPELL_ASHTONGUE_WAVE_A = 42073, // unused + SPELL_ASHTONGUE_WAVE_B = 42035, + SPELL_SUMMON_ASHTONGUE_SORCERER = 40476, + SPELL_SUMMON_ASHTONGUE_DEFENDER = 40474 }; enum Creatures { - NPC_ASHTONGUE_CHANNELER = 23421, - NPC_CREATURE_GENERATOR_AKAMA = 23210, NPC_ASHTONGUE_SORCERER = 23215, + NPC_ASHTONGUE_DEFENDER = 23216, + NPC_ASHTONGUE_ELEMENTAL = 23523, + NPC_ASHTONGUE_ROGUE = 23318, + NPC_ASHTONGUE_SPIRITBIND = 23524, NPC_ASHTONGUE_BROKEN = 23319 }; @@ -56,220 +69,137 @@ enum Misc { SUMMON_GROUP_BROKENS = 1, - POINT_START = 0, - POINT_CHANNEL_SOUL = 1, + POINT_ENGAGE = 0, + POINT_OUTRO = 1, - ACTION_AKAMA_DIED = 1, - ACTION_START_ENCOUNTER = 2, - ACTION_STOP_SPAWNING = 3, - ACTION_DESPAWN_ALL = 4, - ACTION_CHANNELERS_START_CHANNEL = 5, - ACTION_KILL_CHANNELERS = 6, - ACTION_NO_SORCERERS = 7, - ACTION_SHADE_DIED = 8, + ACTION_GENERATOR_START = 1, + ACTION_GENERATOR_STOP = 2, + ACTION_GENERATOR_DESPAWN_ALL = 3, - EVENT_AKAMA_START_ENCOUNTER = 1, - EVENT_AKAMA_START_CHANNEL = 2, - EVENT_SPELL_CHAIN_LIGHTNING = 4, - EVENT_SPELL_DESTRUCTIVE_POISON = 5, + COUNTER_SPAWNS_MAX = 20, // Max number of spawns for each generator, number chosen at random - EVENT_SHADE_CHECK_DISTANCE = 10, - EVENT_SHADE_RESET_ENCOUNTER = 11, - EVENT_SHADE_GATHER_NPCS = 12, + ACTION_AKAMA_START_OUTRO = 1, - EVENT_SUMMON_WAVE_B = 20, - EVENT_SUMMON_ASHTONGUE_SORCERER = 21, - EVENT_SUMMON_ASHTONGUE_DEFENDER = 22, - - EVENT_AKAMA_SCENE0 = 29, - EVENT_AKAMA_SCENE1 = 30, - EVENT_AKAMA_SCENE2 = 31, - EVENT_AKAMA_SCENE3 = 32, - EVENT_AKAMA_SCENE4 = 33, - EVENT_AKAMA_SCENE5 = 34, - EVENT_AKAMA_SCENE6 = 35, - EVENT_AKAMA_SCENE7 = 36 + FACTION_DEFAULT = 1820, + FACTION_ENGAGE = 1868 }; +Position AkamaEngage = { 517.4877f, 400.79926f, 112.77704f }; +Position AkamaOutro = { 469.0867f, 401.0793f, 118.52704f, 0.087266460061073303f }; +Position ShadeEngage = { 512.48773f, 400.8283f, 112.77704f }; + struct boss_shade_of_akama : public BossAI { - boss_shade_of_akama(Creature* creature) : BossAI(creature, DATA_SHADE_OF_AKAMA), summonsChanneler(me), summonsGenerator(me) - { - events2.ScheduleEvent(EVENT_SHADE_GATHER_NPCS, 1000); - } + boss_shade_of_akama(Creature* creature) : BossAI(creature, DATA_SHADE_OF_AKAMA) { } - SummonList summonsChanneler; - SummonList summonsGenerator; - EventMap events2; - - void ChannelersAction(int32 action) - { - for (SummonList::const_iterator i = summonsChanneler.begin(); i != summonsChanneler.end(); ++i) - if (Creature* summon = ObjectAccessor::GetCreature(*me, *i)) - { - if (action == ACTION_CHANNELERS_START_CHANNEL) - { - summon->CastSpell(me, SPELL_SHADE_SOUL_CHANNEL, true); - summon->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - } - else if (action == ACTION_START_ENCOUNTER) - { - summon->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - } - else if (action == ACTION_KILL_CHANNELERS) - { - Unit::Kill(me, summon); - } - } - } + std::list channelers; + std::list generators; void Reset() override { - BossAI::Reset(); - me->SetReactState(REACT_PASSIVE); + channelers.clear(); + generators.clear(); + me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - me->SetImmuneToAll(true); me->SetWalk(true); + me->SetReactState(REACT_DEFENSIVE); + BossAI::Reset(); } void EnterEvadeMode(EvadeReason why) override { + for (Creature* generator : generators) + generator->AI()->DoAction(ACTION_GENERATOR_DESPAWN_ALL); + + for (Creature* channeler : channelers) + channeler->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + BossAI::EnterEvadeMode(why); - summonsGenerator.DoAction(ACTION_DESPAWN_ALL); - events2.ScheduleEvent(EVENT_SHADE_RESET_ENCOUNTER, 20000); - me->SetVisible(false); - ChannelersAction(ACTION_KILL_CHANNELERS); } void JustDied(Unit* killer) override { BossAI::JustDied(killer); - summonsGenerator.DoAction(ACTION_DESPAWN_ALL); - summonsChanneler.DespawnAll(); me->CastSpell(me, SPELL_SHADE_OF_AKAMA_TRIGGER, true); - if (Creature* akama = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_AKAMA_SHADE))) + + for (Creature* generator : generators) + generator->AI()->DoAction(ACTION_GENERATOR_DESPAWN_ALL); + + if (Creature* akama = instance->GetCreature(DATA_AKAMA_SHADE)) + akama->AI()->DoAction(ACTION_AKAMA_START_OUTRO); + } + + void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override + { + if (spell->Id == SPELL_AKAMA_SOUL_CHANNEL) { - akama->SetHomePosition(*akama); - akama->AI()->DoAction(ACTION_SHADE_DIED); + instance->SetBossState(DATA_SHADE_OF_AKAMA, IN_PROGRESS); + + me->GetCreatureListWithEntryInGrid(channelers, NPC_ASHTONGUE_CHANNELER, 40.0f); + me->GetCreatureListWithEntryInGrid(generators, NPC_CREATURE_GENERATOR_AKAMA, 100.0f); + + for (Creature* channeler : channelers) + channeler->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + + for (Creature* generator : generators) + generator->AI()->DoAction(ACTION_GENERATOR_START); + + ScheduleTimedEvent(1200ms, [&] + { + if (me->GetSpeed(MOVE_WALK) > 0.01f) + { + me->GetMotionMaster()->Clear(); + me->GetMotionMaster()->MovePoint(POINT_ENGAGE, ShadeEngage); + } + }, 1200ms); } } - void DoAction(int32 param) override + void MovementInform(uint32 type, uint32 point) override { - if (param == ACTION_START_ENCOUNTER) + if (type == POINT_MOTION_TYPE && point == POINT_ENGAGE) { - summonsGenerator.DoAction(ACTION_START_ENCOUNTER); - ChannelersAction(ACTION_START_ENCOUNTER); - events.ScheduleEvent(EVENT_SHADE_CHECK_DISTANCE, 1000); - } - else if (param == ACTION_AKAMA_DIED) - { - EnterEvadeMode(EVADE_REASON_OTHER); + me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + me->RemoveAurasDueToSpell(SPELL_AKAMA_SOUL_CHANNEL); + scheduler.CancelAll(); + + for (Creature* generator : generators) + generator->AI()->DoAction(ACTION_GENERATOR_STOP); + + if (Creature* akama = instance->GetCreature(DATA_AKAMA_SHADE)) + { + akama->SetReactState(REACT_AGGRESSIVE); + akama->InterruptSpell(CURRENT_CHANNELED_SPELL); + DoCast(akama, SPELL_THREAT, true); + me->AddThreat(akama, 900000.0f); + akama->AI()->DoCast(me, SPELL_FIXATE, true); + AttackStart(akama); + } + + ScheduleTimedEvent(3500ms, [&] + { + if (Creature* akama = instance->GetCreature(DATA_AKAMA_SHADE)) + me->AddThreat(akama, 900000.0f); + }, 3500ms); } } void UpdateAI(uint32 diff) override { - events2.Update(diff); - switch (events2.ExecuteEvent()) - { - case EVENT_SHADE_GATHER_NPCS: - { - std::list ChannelerList; - me->GetCreaturesWithEntryInRange(ChannelerList, 100.0f, NPC_ASHTONGUE_CHANNELER); - for (std::list::const_iterator itr = ChannelerList.begin(); itr != ChannelerList.end(); ++itr) - summonsChanneler.Summon(*itr); - - std::list SpawnerList; - me->GetCreaturesWithEntryInRange(SpawnerList, 100.0f, NPC_CREATURE_GENERATOR_AKAMA); - for (std::list::const_iterator itr = SpawnerList.begin(); itr != SpawnerList.end(); ++itr) - summonsGenerator.Summon(*itr); - - summonsChanneler.Respawn(); - summonsGenerator.Respawn(); - ChannelersAction(ACTION_CHANNELERS_START_CHANNEL); - - if (Creature* akama = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_AKAMA_SHADE))) - akama->Respawn(true); - break; - } - case EVENT_SHADE_RESET_ENCOUNTER: - me->SetVisible(true); - summonsGenerator.Respawn(); - summonsChanneler.Respawn(); - ChannelersAction(ACTION_CHANNELERS_START_CHANNEL); - - if (Creature* akama = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_AKAMA_SHADE))) - akama->Respawn(true); - break; - } - - if (!UpdateVictim()) - return; - - events.Update(diff); - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - switch (events.ExecuteEvent()) - { - case EVENT_SHADE_CHECK_DISTANCE: - if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() != POINT_MOTION_TYPE) - { - int32 slow = me->GetMaxNegativeAuraModifier(SPELL_AURA_MOD_DECREASE_SPEED); - if (slow > -100) - { - me->SetWalk(true); - me->GetMotionMaster()->MovePoint(POINT_START, 510.0f, 400.7993f, 112.7837f); - } - } - else - { - int32 slow = me->GetMaxNegativeAuraModifier(SPELL_AURA_MOD_DECREASE_SPEED); - if (slow < -100) - me->GetMotionMaster()->Clear(); - else if (slow == 0) - { - summonsGenerator.DoAction(ACTION_NO_SORCERERS); - me->SetWalk(false); - } - } - - if (me->IsWithinMeleeRange(me->GetVictim())) - { - me->SetReactState(REACT_AGGRESSIVE); - DoResetThreatList(); - me->GetVictim()->InterruptNonMeleeSpells(false); - me->AddThreat(me->GetVictim(), 1000000.0f); - me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - me->SetImmuneToAll(false); - summonsGenerator.DoAction(ACTION_STOP_SPAWNING); - break; - } - events.ScheduleEvent(EVENT_SHADE_CHECK_DISTANCE, 1000); - break; - } + scheduler.Update(diff); DoMeleeAttackIfReady(); } - - bool CheckEvadeIfOutOfCombatArea() const override - { - return !SelectTargetFromPlayerList(120.0f); - } }; struct npc_akama_shade : public ScriptedAI { - npc_akama_shade(Creature* creature) : ScriptedAI(creature), summons(me) + npc_akama_shade(Creature* creature) : ScriptedAI(creature) { instance = creature->GetInstanceScript(); } InstanceScript* instance; - EventMap events; - EventMap events2; - SummonList summons; void Reset() override { @@ -279,244 +209,262 @@ struct npc_akama_shade : public ScriptedAI return; } + me->SetFaction(FACTION_DEFAULT); me->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP); - me->CastSpell(me, SPELL_STEALTH, true); - events.Reset(); - events2.Reset(); + DoCastSelf(SPELL_STEALTH, true); + me->SetWalk(true); + scheduler.CancelAll(); } void MovementInform(uint32 type, uint32 point) override { - if (type != POINT_MOTION_TYPE || point != POINT_CHANNEL_SOUL) - return; + if (type == POINT_MOTION_TYPE) + { + switch (point) + { + case POINT_ENGAGE: + me->SetHomePosition(me->GetPosition()); + me->SetFaction(FACTION_ENGAGE); + DoCast(me, SPELL_AKAMA_SOUL_CHANNEL, true); + break; + case POINT_OUTRO: + DoCastSelf(SPELL_AKAMA_SOUL_RETRIEVE, true); + ScheduleUniqueTimedEvent(15600ms, [&] + { + Talk(SAY_BROKEN_FREE_0); + me->SummonCreatureGroup(SUMMON_GROUP_BROKENS); + }, 1); + ScheduleUniqueTimedEvent(26550ms, [&] + { + Talk(SAY_BROKEN_FREE_1); + }, 2); + ScheduleUniqueTimedEvent(37500ms, [&] + { + Talk(SAY_BROKEN_FREE_2); + }, 3); + ScheduleUniqueTimedEvent(52000ms, [&] + { + std::list brokens; + me->GetCreatureListWithEntryInGrid(brokens, NPC_ASHTONGUE_BROKEN, 40.0f); + if (Creature* broken = GetClosestCreatureWithEntry(me, NPC_ASHTONGUE_BROKEN, 40.0f)) + broken->AI()->Talk(SAY_BROKEN_S1); - me->SetFacingTo(0.0f); - events2.ScheduleEvent(EVENT_AKAMA_SCENE1, 1000); - events2.ScheduleEvent(EVENT_AKAMA_SCENE2, 16500); - events2.ScheduleEvent(EVENT_AKAMA_SCENE3, 17500); - events2.ScheduleEvent(EVENT_AKAMA_SCENE4, 27000); - events2.ScheduleEvent(EVENT_AKAMA_SCENE5, 37000); - events2.ScheduleEvent(EVENT_AKAMA_SCENE6, 51000); - events2.ScheduleEvent(EVENT_AKAMA_SCENE7, 56000); + for (Creature* broken : brokens) + { + broken->SetStandState(UNIT_STAND_STATE_KNEEL); + broken->SetFaction(FACTION_DEFAULT); + broken->AI()->Talk(SAY_BROKEN_S2, 4800ms); + } + }, 4); + break; + } + } } void DoAction(int32 param) override { - if (param == ACTION_SHADE_DIED) - events2.ScheduleEvent(EVENT_AKAMA_SCENE0, 1000); + if (param == ACTION_AKAMA_START_OUTRO) + { + me->SetWalk(false); + me->GetMotionMaster()->MovePoint(POINT_OUTRO, AkamaOutro); + } } + void JustSummoned(Creature* summon) override + { + // In Retail they seem to me like they should move in formations of 3 to set points, this is simpler for now + ScriptedAI::JustSummoned(summon); + float x, y, z; + me->GetNearPoint(summon, x, y, z, 25.f, 0, me->GetAngle(summon)); + summon->SetWalk(true); + summon->GetMotionMaster()->MovePoint(POINT_OUTRO, x, y, z); + } + + void EnterEvadeMode(EvadeReason /*why*/) override { } + void JustDied(Unit* /*killer*/) override { - if (Creature* shade = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_SHADE_OF_AKAMA))) - shade->AI()->DoAction(ACTION_AKAMA_DIED); + if (Creature* shade = instance->GetCreature(DATA_SHADE_OF_AKAMA)) + { + shade->SetHomePosition(shade->GetHomePosition()); + shade->AI()->EnterEvadeMode(); + } + + me->DespawnOrUnsummon(); } void JustEngagedWith(Unit* /*who*/) override { - events.ScheduleEvent(EVENT_SPELL_CHAIN_LIGHTNING, 2000); - events.ScheduleEvent(EVENT_SPELL_DESTRUCTIVE_POISON, 5000); + ScheduleTimedEvent(2s, [&] + { + DoCastVictim(SPELL_CHAIN_LIGHTNING); + }, 10s, 15s); + ScheduleTimedEvent(5s, [&] + { + DoCastVictim(SPELL_DESTRUCTIVE_POISON); + }, 4s, 15s); } - void JustSummoned(Creature* summon) override + void sGossipSelect(Player* player, uint32 /*sender*/, uint32 /*action*/) override { - float dist = frand(30.0f, 32.0f); - summon->SetWalk(true); - summon->GetMotionMaster()->MovePoint(POINT_START, summon->GetPositionX() + dist * cos(summon->GetOrientation()), summon->GetPositionY() + dist * std::sin(summon->GetOrientation()), summon->GetPositionZ(), false); - summons.Summon(summon); + CloseGossipMenuFor(player); + me->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP); + me->RemoveAurasDueToSpell(SPELL_STEALTH); + me->GetMotionMaster()->MovePoint(POINT_ENGAGE, AkamaEngage); } void UpdateAI(uint32 diff) override { - events2.Update(diff); - switch (events2.ExecuteEvent()) - { - case EVENT_AKAMA_START_ENCOUNTER: - me->RemoveAura(SPELL_STEALTH); - me->SetWalk(true); - me->GetMotionMaster()->MovePoint(POINT_START, 517.4877f, 400.7993f, 112.7837f, false); - events2.ScheduleEvent(EVENT_AKAMA_START_CHANNEL, 11000); - break; - case EVENT_AKAMA_START_CHANNEL: - me->CastSpell(me, SPELL_AKAMA_SOUL_CHANNEL, false); - if (Creature* shade = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_SHADE_OF_AKAMA))) - { - shade->AI()->AttackStart(me); - shade->GetMotionMaster()->Clear(); - shade->AI()->DoAction(ACTION_START_ENCOUNTER); - } - break; - case EVENT_AKAMA_SCENE0: - me->SetWalk(true); - me->GetMotionMaster()->MovePoint(POINT_CHANNEL_SOUL, 467.0f, 400.7993f, 118.537f); - break; - case EVENT_AKAMA_SCENE1: - me->CastSpell(me, SPELL_AKAMA_SOUL_RETRIEVE, true); - break; - case EVENT_AKAMA_SCENE2: - Talk(SAY_BROKEN_FREE_0); - break; - case EVENT_AKAMA_SCENE3: - me->SummonCreatureGroup(SUMMON_GROUP_BROKENS); - break; - case EVENT_AKAMA_SCENE4: - Talk(SAY_BROKEN_FREE_1); - break; - case EVENT_AKAMA_SCENE5: - for (SummonList::const_iterator itr = summons.begin(); itr != summons.end(); ++itr) - if (Creature* broken = ObjectAccessor::GetCreature(*me, *itr)) - broken->SetStandState(UNIT_STAND_STATE_KNEEL); - Talk(SAY_BROKEN_FREE_2); - break; - case EVENT_AKAMA_SCENE6: - if (Creature* broken = summons.GetCreatureWithEntry(NPC_ASHTONGUE_BROKEN)) - broken->AI()->Talk(SAY_BROKEN_S1); - break; - case EVENT_AKAMA_SCENE7: - for (SummonList::const_iterator itr = summons.begin(); itr != summons.end(); ++itr) - if (Creature* broken = ObjectAccessor::GetCreature(*me, *itr)) - broken->AI()->Talk(SAY_BROKEN_S2); - break; - } - - if (!UpdateVictim()) - return; - - events.Update(diff); - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - switch (events.ExecuteEvent()) - { - case EVENT_SPELL_CHAIN_LIGHTNING: - me->CastSpell(me->GetVictim(), SPELL_CHAIN_LIGHTNING, false); - events.ScheduleEvent(EVENT_SPELL_CHAIN_LIGHTNING, urand(10000, 15000)); - break; - case EVENT_SPELL_DESTRUCTIVE_POISON: - me->CastSpell(me, SPELL_DESTRUCTIVE_POISON, false); - events.ScheduleEvent(EVENT_SPELL_DESTRUCTIVE_POISON, urand(4000, 5000)); - break; - } - + scheduler.Update(diff); DoMeleeAttackIfReady(); } - - void sGossipSelect(Player* player, uint32 /*sender*/, uint32 action) override - { - if (action == 0) - { - CloseGossipMenuFor(player); - me->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP); - events2.ScheduleEvent(EVENT_AKAMA_START_ENCOUNTER, 0); - } - } }; -struct npc_creature_generator_akama : public NullCreatureAI +struct npc_creature_generator_akama : public ScriptedAI { - npc_creature_generator_akama(Creature* creature) : NullCreatureAI(creature), summons(me) + npc_creature_generator_akama(Creature* creature) : ScriptedAI(creature), summons(me) { instance = creature->GetInstanceScript(); } + uint8 spawnCounter = 0; + void Reset() override { - events.Reset(); summons.DespawnAll(); + scheduler.CancelAll(); } void JustSummoned(Creature* summon) override { - summons.Summon(summon); - if (summon->GetEntry() == NPC_ASHTONGUE_SORCERER) + spawnCounter++; + ScriptedAI::JustSummoned(summon); + + switch (summon->GetEntry()) { - std::list channelerList; - me->GetCreaturesWithEntryInRange(channelerList, 120.0f, NPC_ASHTONGUE_CHANNELER); - for (std::list::const_iterator itr = channelerList.begin(); itr != channelerList.end(); ++itr) + case NPC_ASHTONGUE_SORCERER: + if (Creature* shade = instance->GetCreature(DATA_SHADE_OF_AKAMA)) { - if ((*itr)->IsAlive() || (*itr)->HasUnitFlag(UNIT_FLAG_NOT_SELECTABLE)) - continue; - - summon->SetInCombatWithZone(); - summon->SetReactState(REACT_PASSIVE); - summon->GetMotionMaster()->MovePoint(POINT_START, **itr); - (*itr)->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - return; + float x, y, z; + shade->GetNearPoint(shade, x, y, z, 20.f, 0, shade->GetAngle(summon)); + summon->GetMotionMaster()->MovePoint(POINT_ENGAGE, x, y, z); } - } - - summon->SetInCombatWithZone(); - if (Unit* akama = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_AKAMA_SHADE))) - { - summon->AddThreat(akama, 500.0f); - summon->AI()->AttackStart(akama); + break; + default: + summon->SetInCombatWithZone(); + if (Creature* akama = instance->GetCreature(DATA_AKAMA_SHADE)) + summon->AI()->AttackStart(akama); + break; } } void SummonedCreatureDies(Creature* summon, Unit*) override { + spawnCounter--; summon->DespawnOrUnsummon(10000); summons.Despawn(summon); } void DoAction(int32 param) override { - if (param == ACTION_STOP_SPAWNING || param == ACTION_DESPAWN_ALL) + switch (param) { - events.Reset(); - for (SummonList::const_iterator itr = summons.begin(); itr != summons.end(); ++itr) + case ACTION_GENERATOR_STOP: + scheduler.CancelAll(); + break; + case ACTION_GENERATOR_START: + if (me->GetPositionY() > 400.0f) // Right Side { - if (Creature* summon = ObjectAccessor::GetCreature(*me, *itr)) + ScheduleTimedEvent(10s, [&] { - if (summon->GetEntry() != NPC_ASHTONGUE_SORCERER) - continue; - summon->InterruptNonMeleeSpells(false); - summon->GetMotionMaster()->Clear(); - summon->SetInCombatWithZone(); - } + if (spawnCounter <= COUNTER_SPAWNS_MAX) + DoCastSelf(SPELL_ASHTONGUE_WAVE_B); + }, 50s, 60s); + + ScheduleTimedEvent(2s, 5s, [&] + { + if (spawnCounter <= COUNTER_SPAWNS_MAX) + DoCastSelf(SPELL_SUMMON_ASHTONGUE_DEFENDER); + }, 30s, 40s); } - } - if (param == ACTION_DESPAWN_ALL) + + if (me->GetPositionY() < 400.0f) // Left Side + { + ScheduleTimedEvent(3s, [&] + { + if (spawnCounter <= COUNTER_SPAWNS_MAX) + DoCastSelf(SPELL_ASHTONGUE_WAVE_B); + }, 50s, 60s); + + ScheduleTimedEvent(2s, 5s, [&] + { + if (spawnCounter <= COUNTER_SPAWNS_MAX) + DoCastSelf(SPELL_SUMMON_ASHTONGUE_SORCERER); + }, 30s, 35s); + } + break; + case ACTION_GENERATOR_DESPAWN_ALL: summons.DespawnAll(); - else if (param == ACTION_NO_SORCERERS) - events.CancelEvent(EVENT_SUMMON_ASHTONGUE_SORCERER); - else if (param == ACTION_START_ENCOUNTER) - { - events.ScheduleEvent(EVENT_SUMMON_WAVE_B, 5000); - events.ScheduleEvent(EVENT_SUMMON_ASHTONGUE_DEFENDER, 20000); - events.ScheduleEvent(EVENT_SUMMON_ASHTONGUE_SORCERER, 35000); + scheduler.CancelAll(); + break; } } void UpdateAI(uint32 diff) override { - events.Update(diff); - - switch (events.ExecuteEvent()) - { - case EVENT_SUMMON_WAVE_B: - me->CastSpell(me, SPELL_ASHTONGUE_WAVE_B, true); - events.ScheduleEvent(EVENT_SUMMON_WAVE_B, 45000); - break; - case EVENT_SUMMON_ASHTONGUE_SORCERER: // left - me->CastSpell(me, SPELL_SUMMON_ASHTONGUE_SORCERER, true); - events.ScheduleEvent(EVENT_SUMMON_ASHTONGUE_SORCERER, 45000); - break; - case EVENT_SUMMON_ASHTONGUE_DEFENDER: // right - me->CastSpell(me, SPELL_SUMMON_ASHTONGUE_DEFENDER, true); - events.ScheduleEvent(EVENT_SUMMON_ASHTONGUE_DEFENDER, 45000); - break; - default: - break; - } + scheduler.Update(diff); } private: - EventMap events; SummonList summons; InstanceScript* instance; }; +struct npc_ashtongue_sorcerer : public NullCreatureAI +{ + npc_ashtongue_sorcerer(Creature* creature) : NullCreatureAI(creature) + { + instance = creature->GetInstanceScript(); + } + + void MovementInform(uint32 type, uint32 point) override + { + if (type == POINT_MOTION_TYPE && point == POINT_ENGAGE) + me->CastSpell(me, SPELL_SHADE_SOUL_CHANNEL, true); + } + +private: + InstanceScript* instance; +}; + +struct npc_ashtongue_channeler : public NullCreatureAI +{ + npc_ashtongue_channeler(Creature* creature) : NullCreatureAI(creature) + { + instance = creature->GetInstanceScript(); + } + + void Reset() override + { + scheduler.Schedule(3600ms, [this](TaskContext context) + { + if (!me->HasUnitState(UNIT_STATE_CASTING)) + me->CastSpell(me, SPELL_SHADE_SOUL_CHANNEL, true); + + context.Repeat(); + }); + } + + void UpdateAI(uint32 diff) override + { + scheduler.Update(diff); + } + +private: + InstanceScript* instance; + TaskScheduler scheduler; +}; + class spell_shade_of_akama_shade_soul_channel : public AuraScript { PrepareAuraScript(spell_shade_of_akama_shade_soul_channel); @@ -562,6 +510,8 @@ void AddSC_boss_shade_of_akama() RegisterBlackTempleCreatureAI(boss_shade_of_akama); RegisterBlackTempleCreatureAI(npc_akama_shade); RegisterBlackTempleCreatureAI(npc_creature_generator_akama); + RegisterBlackTempleCreatureAI(npc_ashtongue_channeler); + RegisterBlackTempleCreatureAI(npc_ashtongue_sorcerer); RegisterSpellScript(spell_shade_of_akama_shade_soul_channel); RegisterSpellScript(spell_shade_of_akama_akama_soul_expel); } diff --git a/src/server/scripts/Outland/BlackTemple/illidari_council.cpp b/src/server/scripts/Outland/BlackTemple/illidari_council.cpp index 247b61311..0fee4ec3b 100644 --- a/src/server/scripts/Outland/BlackTemple/illidari_council.cpp +++ b/src/server/scripts/Outland/BlackTemple/illidari_council.cpp @@ -152,15 +152,13 @@ public: { } - ObjectGuid councilGUIDs[4]; - - void Reset() override + void EnterEvadeMode(EvadeReason why) { - BossAI::Reset(); - Creature* member = nullptr; - for (uint8 i = 0; i < 4; ++i) - if ((member = ObjectAccessor::GetCreature(*me, councilGUIDs[i]))) + for (uint8 i = DATA_GATHIOS_THE_SHATTERER; i <= DATA_VERAS_DARKSHADOW; ++i) + if (Creature* member = instance->GetCreature(i)) member->AI()->EnterEvadeMode(); + + BossAI::EnterEvadeMode(why); } void AttackStart(Unit*) override { } @@ -171,15 +169,11 @@ public: if (!me->isActiveObject() && param == ACTION_START_ENCOUNTER) { me->setActive(true); - councilGUIDs[0] = instance->GetGuidData(NPC_GATHIOS_THE_SHATTERER); - councilGUIDs[1] = instance->GetGuidData(NPC_HIGH_NETHERMANCER_ZEREVOR); - councilGUIDs[2] = instance->GetGuidData(NPC_LADY_MALANDE); - councilGUIDs[3] = instance->GetGuidData(NPC_VERAS_DARKSHADOW); bool spoken = false; - for (uint8 i = 0; i < 4; ++i) + for (uint8 i = DATA_GATHIOS_THE_SHATTERER; i <= DATA_VERAS_DARKSHADOW; ++i) { - if (Creature* member = ObjectAccessor::GetCreature(*me, councilGUIDs[i])) + if (Creature* member = instance->GetCreature(i)) { if (!spoken && (roll_chance_i(33) || i == 3)) { @@ -193,17 +187,15 @@ public: } else if (param == ACTION_ENRAGE) { - Creature* member = nullptr; - for (uint8 i = 0; i < 4; ++i) - if ((member = ObjectAccessor::GetCreature(*me, councilGUIDs[i]))) + for (uint8 i = DATA_GATHIOS_THE_SHATTERER; i <= DATA_VERAS_DARKSHADOW; ++i) + if (Creature* member = instance->GetCreature(i)) member->AI()->DoAction(ACTION_ENRAGE); } else if (param == ACTION_END_ENCOUNTER) { me->setActive(false); - Creature* member = nullptr; - for (uint8 i = 0; i < 4; ++i) - if ((member = ObjectAccessor::GetCreature(*me, councilGUIDs[i]))) + for (uint8 i = DATA_GATHIOS_THE_SHATTERER; i <= DATA_VERAS_DARKSHADOW; ++i) + if (Creature* member = instance->GetCreature(i)) if (member->IsAlive()) Unit::Kill(me, member); me->KillSelf(); @@ -217,7 +209,7 @@ public: if (!SelectTargetFromPlayerList(115.0f)) { - EnterEvadeMode(); + EnterEvadeMode(EVADE_REASON_NO_HOSTILES); return; } @@ -268,13 +260,13 @@ struct boss_illidari_council_memberAI : public ScriptedAI void JustDied(Unit*) override { Talk(SAY_COUNCIL_DEATH); - if (Creature* council = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_ILLIDARI_COUNCIL))) + if (Creature* council = instance->GetCreature(DATA_ILLIDARI_COUNCIL)) council->GetAI()->DoAction(ACTION_END_ENCOUNTER); } void JustEngagedWith(Unit* /*who*/) override { - if (Creature* council = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_ILLIDARI_COUNCIL))) + if (Creature* council = instance->GetCreature(DATA_ILLIDARI_COUNCIL)) council->GetAI()->DoAction(ACTION_START_ENCOUNTER); } }; @@ -296,14 +288,14 @@ public: Creature* SelectCouncilMember() { if (roll_chance_i(50)) - return ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_LADY_MALANDE)); + return instance->GetCreature(DATA_LADY_MALANDE); if (roll_chance_i(20)) - if (Creature* veras = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_VERAS_DARKSHADOW))) + if (Creature* veras = instance->GetCreature(DATA_VERAS_DARKSHADOW)) if (!veras->HasAura(SPELL_VANISH)) return veras; - return ObjectAccessor::GetCreature(*me, instance->GetGuidData(RAND(NPC_GATHIOS_THE_SHATTERER, NPC_HIGH_NETHERMANCER_ZEREVOR))); + return instance->GetCreature(RAND(DATA_GATHIOS_THE_SHATTERER, DATA_HIGH_NETHERMANCER_ZEREVOR)); } void JustEngagedWith(Unit* who) override @@ -555,7 +547,7 @@ public: break; case EVENT_SPELL_ENRAGE: DoResetThreatList(); - if (Creature* council = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_ILLIDARI_COUNCIL))) + if (Creature* council = instance->GetCreature(DATA_ILLIDARI_COUNCIL)) council->GetAI()->DoAction(ACTION_ENRAGE); break; } diff --git a/src/server/scripts/Outland/BlackTemple/instance_black_temple.cpp b/src/server/scripts/Outland/BlackTemple/instance_black_temple.cpp index ab447cdcb..175437358 100644 --- a/src/server/scripts/Outland/BlackTemple/instance_black_temple.cpp +++ b/src/server/scripts/Outland/BlackTemple/instance_black_temple.cpp @@ -36,12 +36,37 @@ DoorData const doorData[] = { GO_MOTHER_SHAHRAZ_DOOR, DATA_MOTHER_SHAHRAZ, DOOR_TYPE_PASSAGE }, { GO_COUNCIL_DOOR_1, DATA_ILLIDARI_COUNCIL, DOOR_TYPE_ROOM }, { GO_COUNCIL_DOOR_2, DATA_ILLIDARI_COUNCIL, DOOR_TYPE_ROOM }, - { GO_ILLIDAN_GATE, DATA_AKAMA_FINISHED, DOOR_TYPE_PASSAGE }, + { GO_ILLIDAN_GATE, DATA_AKAMA_ILLIDAN, DOOR_TYPE_PASSAGE }, { GO_ILLIDAN_DOOR_L, DATA_ILLIDAN_STORMRAGE, DOOR_TYPE_ROOM }, { GO_ILLIDAN_DOOR_R, DATA_ILLIDAN_STORMRAGE, DOOR_TYPE_ROOM }, { 0, 0, DOOR_TYPE_ROOM } }; +ObjectData const creatureData[] = +{ + { NPC_HIGH_WARLORD_NAJENTUS, DATA_HIGH_WARLORD_NAJENTUS }, + { NPC_SUPREMUS, DATA_SUPREMUS }, + { NPC_SHADE_OF_AKAMA, DATA_SHADE_OF_AKAMA }, + { NPC_AKAMA_SHADE, DATA_AKAMA_SHADE }, + { NPC_TERON_GOREFIEND, DATA_TERON_GOREFIEND }, + { NPC_GURTOGG_BLOODBOIL, DATA_GURTOGG_BLOODBOIL }, + { NPC_RELIQUARY_OF_THE_LOST, DATA_RELIQUARY_OF_SOULS }, + { NPC_MOTHER_SHAHRAZ, DATA_MOTHER_SHAHRAZ }, + { NPC_ILLIDARI_COUNCIL, DATA_ILLIDARI_COUNCIL }, + { NPC_GATHIOS_THE_SHATTERER, DATA_GATHIOS_THE_SHATTERER }, + { NPC_HIGH_NETHERMANCER_ZEREVOR, DATA_HIGH_NETHERMANCER_ZEREVOR }, + { NPC_LADY_MALANDE, DATA_LADY_MALANDE }, + { NPC_VERAS_DARKSHADOW, DATA_VERAS_DARKSHADOW }, + { NPC_AKAMA_ILLIDAN, DATA_AKAMA_ILLIDAN }, + { NPC_ILLIDAN_STORMRAGE, DATA_ILLIDAN_STORMRAGE }, + { 0, 0 } +}; + +ObjectData const objectData[] = +{ + { 0, 0 } +}; + BossBoundaryData const boundaries = { { DATA_HIGH_WARLORD_NAJENTUS, new RectangleBoundary(394.0f, 479.4f, 707.8f, 859.1f) }, @@ -70,6 +95,7 @@ public: SetBossNumber(MAX_ENCOUNTERS); LoadDoorData(doorData); LoadBossBoundaries(boundaries); + LoadObjectData(creatureData, objectData); ashtongueGUIDs.clear(); } @@ -78,52 +104,19 @@ public: { switch (creature->GetEntry()) { - case NPC_SHADE_OF_AKAMA: - ShadeOfAkamaGUID = creature->GetGUID(); - break; - case NPC_AKAMA_SHADE: - AkamaShadeGUID = creature->GetGUID(); - break; - case NPC_TERON_GOREFIEND: - TeronGorefiendGUID = creature->GetGUID(); - break; - case NPC_RELIQUARY_OF_THE_LOST: - ReliquaryGUID = creature->GetGUID(); - break; - case NPC_GATHIOS_THE_SHATTERER: - GathiosTheShattererGUID = creature->GetGUID(); - break; - case NPC_HIGH_NETHERMANCER_ZEREVOR: - HighNethermancerZerevorGUID = creature->GetGUID(); - break; - case NPC_LADY_MALANDE: - LadyMalandeGUID = creature->GetGUID(); - break; - case NPC_VERAS_DARKSHADOW: - VerasDarkshadowGUID = creature->GetGUID(); - break; - case NPC_ILLIDARI_COUNCIL: - IllidariCouncilGUID = creature->GetGUID(); - break; - case NPC_AKAMA: - AkamaGUID = creature->GetGUID(); - break; - case NPC_ILLIDAN_STORMRAGE: - IllidanStormrageGUID = creature->GetGUID(); - break; case NPC_VENGEFUL_SPIRIT: case NPC_SHADOWY_CONSTRUCT: - if (Creature* teron = instance->GetCreature(TeronGorefiendGUID)) + if (Creature* teron = GetCreature(DATA_TERON_GOREFIEND)) teron->AI()->JustSummoned(creature); break; case NPC_ENSLAVED_SOUL: - if (Creature* reliquary = instance->GetCreature(ReliquaryGUID)) + if (Creature* reliquary = GetCreature(DATA_RELIQUARY_OF_SOULS)) reliquary->AI()->JustSummoned(creature); break; case NPC_PARASITIC_SHADOWFIEND: case NPC_BLADE_OF_AZZINOTH: case NPC_FLAME_OF_AZZINOTH: - if (Creature* illidan = instance->GetCreature(IllidanStormrageGUID)) + if (Creature* illidan = GetCreature(DATA_ILLIDAN_STORMRAGE)) illidan->AI()->JustSummoned(creature); break; case NPC_ANGERED_SOUL_FRAGMENT: @@ -131,85 +124,38 @@ public: case NPC_SUFFERING_SOUL_FRAGMENT: creature->SetCorpseDelay(5); break; + case NPC_ASHTONGUE_BATTLELORD: + case NPC_ASHTONGUE_MYSTIC: + case NPC_ASHTONGUE_STORMCALLER: + case NPC_ASHTONGUE_PRIMALIST: + case NPC_ASHTONGUE_FERAL_SPIRIT: + case NPC_ASHTONGUE_STALKER: + case NPC_STORM_FURY: + if (GetBossState(DATA_SHADE_OF_AKAMA) == DONE) + creature->SetFaction(FACTION_ASHTONGUE_DEATHSWORN); + else + ashtongueGUIDs.insert(creature->GetGUID()); + break; + default: + break; } - if (creature->GetName().find("Ashtongue") != std::string::npos || creature->GetEntry() == NPC_STORM_FURY) - { - ashtongueGUIDs.push_back(creature->GetGUID()); - if (GetBossState(DATA_SHADE_OF_AKAMA) == DONE) - creature->SetFaction(FACTION_ASHTONGUE_DEATHSWORN); - } + InstanceScript::OnCreatureCreate(creature); } void OnGameObjectCreate(GameObject* go) override { - switch (go->GetEntry()) + // If created after Illidari Council is done, then skip Akama's event. Used for crashes/reset + if (go->GetEntry() == GO_ILLIDAN_GATE) { - case GO_NAJENTUS_GATE: - case GO_SUPREMUS_GATE: - case GO_SHADE_OF_AKAMA_DOOR: - case GO_TERON_DOOR_1: - case GO_TERON_DOOR_2: - case GO_GURTOGG_DOOR: - case GO_TEMPLE_DOOR: - case GO_MOTHER_SHAHRAZ_DOOR: - case GO_COUNCIL_DOOR_1: - case GO_COUNCIL_DOOR_2: - case GO_ILLIDAN_GATE: - case GO_ILLIDAN_DOOR_R: - case GO_ILLIDAN_DOOR_L: - AddDoor(go); - break; - } - } - - void OnGameObjectRemove(GameObject* go) override - { - switch (go->GetEntry()) - { - case GO_NAJENTUS_GATE: - case GO_SUPREMUS_GATE: - case GO_SHADE_OF_AKAMA_DOOR: - case GO_TERON_DOOR_1: - case GO_TERON_DOOR_2: - case GO_GURTOGG_DOOR: - case GO_TEMPLE_DOOR: - case GO_MOTHER_SHAHRAZ_DOOR: - case GO_COUNCIL_DOOR_1: - case GO_COUNCIL_DOOR_2: - case GO_ILLIDAN_GATE: - case GO_ILLIDAN_DOOR_R: - case GO_ILLIDAN_DOOR_L: - RemoveDoor(go); - break; - } - } - - ObjectGuid GetGuidData(uint32 type) const override - { - switch (type) - { - case NPC_SHADE_OF_AKAMA: - return ShadeOfAkamaGUID; - case NPC_AKAMA_SHADE: - return AkamaShadeGUID; - case NPC_GATHIOS_THE_SHATTERER: - return GathiosTheShattererGUID; - case NPC_HIGH_NETHERMANCER_ZEREVOR: - return HighNethermancerZerevorGUID; - case NPC_LADY_MALANDE: - return LadyMalandeGUID; - case NPC_VERAS_DARKSHADOW: - return VerasDarkshadowGUID; - case NPC_ILLIDARI_COUNCIL: - return IllidariCouncilGUID; - case NPC_AKAMA: - return AkamaGUID; - case NPC_ILLIDAN_STORMRAGE: - return IllidanStormrageGUID; + if (GetBossState(DATA_ILLIDARI_COUNCIL) == DONE) + { + SetBossState(DATA_AKAMA_ILLIDAN, DONE); + HandleGameObject(ObjectGuid::Empty, true, go); + } } - return ObjectGuid::Empty; + InstanceScript::OnGameObjectCreate(go); } bool SetBossState(uint32 type, EncounterState state) override @@ -225,26 +171,15 @@ public: } else if (type == DATA_ILLIDARI_COUNCIL && state == DONE) { - if (Creature* akama = instance->GetCreature(AkamaGUID)) - akama->SetVisible(true); + if (Creature* akama = GetCreature(DATA_AKAMA_ILLIDAN)) + akama->AI()->DoAction(0); } return true; } protected: - ObjectGuid ShadeOfAkamaGUID; - ObjectGuid AkamaShadeGUID; - ObjectGuid TeronGorefiendGUID; - ObjectGuid ReliquaryGUID; - GuidList ashtongueGUIDs; - ObjectGuid GathiosTheShattererGUID; - ObjectGuid HighNethermancerZerevorGUID; - ObjectGuid LadyMalandeGUID; - ObjectGuid VerasDarkshadowGUID; - ObjectGuid IllidariCouncilGUID; - ObjectGuid AkamaGUID; - ObjectGuid IllidanStormrageGUID; + GuidSet ashtongueGUIDs; }; InstanceScript* GetInstanceScript(InstanceMap* map) const override