King rest core scripts

This commit is contained in:
luis
2026-09-10 22:16:52 -03:00
parent 56d6639fb2
commit cb66441cae
5 changed files with 1270 additions and 4 deletions
@@ -0,0 +1,458 @@
/*
* This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "CreatureAI.h"
#include "CreatureAIImpl.h"
#include "InstanceScript.h"
#include "Map.h"
#include "ObjectAccessor.h"
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "TemporarySummon.h"
#include "kings_rest.h"
// Sniff-derived (Map 1762, build 12.1.0.69587)
enum KingDazarSpells
{
// King Dazar
SPELL_AERIAL_SMASH = 1303101, // leap at a player, 4s
SPELL_AERIAL_SMASH_DUMMY = 1303105,
SPELL_AERIAL_SMASH_IMPACT = 1303115, // landing shockwaves
SPELL_BLADE_COMBO_1 = 269503, // telegraph on a player
SPELL_BLADE_COMBO_2 = 268586, // 1.5s channel
SPELL_BLADE_COMBO_3 = 268587,
SPELL_BLADE_COMBO_4 = 268589,
SPELL_BLADE_COMBO_5 = 268590,
SPELL_BLADE_COMBO_6 = 268591,
SPELL_GILDED_DESTRUCTION = 1303267, // 6s, floods the arena via Gold Pool Stalkers
SPELL_GILDED_DESTRUCTION_DOT = 1303288,
SPELL_ETERNAL_BOND = 1303523, // empower T'zala
SPELL_COPY_THREAT_TO_VEHICLE = 173531,
SPELL_IMPALING_SPEAR = 1302944, // Dazar ground spears
SPELL_IMPALING_SPEAR_B = 1302945,
// Reban (raptor)
SPELL_RAPTOR_SPAWN_SPLASH = 269023, // summons raptor adds
SPELL_HUNTING_LEAP = 269231,
SPELL_HUNTING_LEAP_THROW = 269232,
SPELL_HUNTING_LEAP_TELEGRAPH = 1303039, // ground telegraph
SPELL_HUNTING_LEAP_LAND = 1310473, // landing impact
SPELL_DEATHLY_ROAR = 269369, // 4s fear howl
// T'zala (vehicle)
SPELL_QUAKING_LEAP = 1303323, // 3s, roots the raid
SPELL_QUAKING_LEAP_SMALL = 1303324,
SPELL_QUAKING_LEAP_IMPACT = 1303326, // landing damage
SPELL_QUAKING_LEAP_IMPACT_2 = 1303327,
SPELL_QUAKING_LEAP_IMPACT_3 = 1303328,
SPELL_AERIAL_SMASH_TZALA = 1303120,
SPELL_SAVAGE_MAUL = 1303481,
SPELL_SAVAGE_MAUL_HEAVY = 1303488,
SPELL_SAVAGE_MAUL_CAST = 1303490,
SPELL_ETERNAL_BOND_TZALA = 1303519
};
enum KingDazarEvents
{
EVENT_AERIAL_SMASH = 1,
EVENT_BLADE_COMBO,
EVENT_BLADE_COMBO_NEXT,
EVENT_GILDED_DESTRUCTION,
EVENT_ETERNAL_BOND,
EVENT_IMPALING_SPEARS,
EVENT_TZALA_EMPOWER,
EVENT_LEAP,
EVENT_ROAR,
EVENT_RAPTOR_SPLASH,
EVENT_QUAKE,
EVENT_MAUL,
EVENT_SMASH_TZALA,
EVENT_POOL_DOT
};
enum KingDazarTexts
{
SAY_DAZAR_AGGRO = 0, // You will pay for desecrating my temple!
SAY_DAZAR_BOND = 1, // Even death cannot break de bond between us, my pets. Now feast, T'zala... FEAST!
SAY_DAZAR_GILDED = 2, // Dis is why I am king... and you are nothing.
SAY_DAZAR_HUNT = 3, // Come... come, my dear Reban. It is feeding time!
SAY_DAZAR_SLASH = 4, // None can withstand my blade!
SAY_DAZAR_ROAR_MELEE = 5, // I will shred your flesh!
SAY_DAZAR_KILL = 6, // Run! Send word to de Zandalari! ... Run!
SAY_DAZAR_DEATH = 7 // I... surrender... to de sands of time...
};
// 136160 - King Dazar
struct boss_king_dazar : public BossAI
{
boss_king_dazar(Creature* creature) : BossAI(creature, DATA_KING_DAZAR), _comboChain(0) { }
void JustEngagedWith(Unit* who) override
{
BossAI::JustEngagedWith(who);
Talk(SAY_DAZAR_AGGRO);
// The raptor and its mount join the fray alongside the king
for (Creature* pet : GetPets())
if (pet)
{
instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, pet, 2);
pet->AI()->DoZoneInCombat();
}
events.ScheduleEvent(EVENT_AERIAL_SMASH, 15s);
events.ScheduleEvent(EVENT_BLADE_COMBO, 23s);
events.ScheduleEvent(EVENT_GILDED_DESTRUCTION, 30s);
events.ScheduleEvent(EVENT_ETERNAL_BOND, 40s);
events.ScheduleEvent(EVENT_IMPALING_SPEARS, 46s);
}
void JustDied(Unit* /*killer*/) override
{
Talk(SAY_DAZAR_DEATH);
for (Creature* pet : GetPets())
if (pet)
{
instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, pet, 2);
pet->DespawnOrUnsummon(3s);
}
summons.DespawnAll();
_JustDied();
}
void KilledUnit(Unit* victim) override
{
if (victim->IsPlayer())
Talk(SAY_DAZAR_KILL);
}
void DoAerialSmash()
{
Talk(SAY_DAZAR_SLASH);
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 80.0f, true))
DoCast(target, SPELL_AERIAL_SMASH);
events.ScheduleEvent(EVENT_AERIAL_SMASH, 28s);
}
void DoBladeCombo()
{
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 80.0f, true))
{
DoCast(target, SPELL_BLADE_COMBO_1);
DoCast(target, SPELL_BLADE_COMBO_2);
}
_comboChain = 0;
events.ScheduleEvent(EVENT_BLADE_COMBO_NEXT, 1s);
}
void DoBladeComboNext()
{
static uint32 const chain[] = { SPELL_BLADE_COMBO_3, SPELL_BLADE_COMBO_4, SPELL_BLADE_COMBO_5, SPELL_BLADE_COMBO_6 };
Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 80.0f, true);
if (!target)
{
_comboChain = 0;
return;
}
DoCast(target, chain[_comboChain]);
if (++_comboChain < 4)
events.ScheduleEvent(EVENT_BLADE_COMBO_NEXT, 800ms);
else
{
_comboChain = 0;
events.ScheduleEvent(EVENT_BLADE_COMBO, 42s);
}
}
void DoGildedDestruction()
{
Talk(SAY_DAZAR_GILDED);
DoCastSelf(SPELL_GILDED_DESTRUCTION);
events.ScheduleEvent(EVENT_GILDED_DESTRUCTION, 55s);
}
void DoEternalBond()
{
Talk(SAY_DAZAR_BOND);
DoCastSelf(SPELL_ETERNAL_BOND);
if (Creature* tzala = me->FindNearestCreature(NPC_TZALA, 150.0f, true))
tzala->AI()->SetData(DATA_KING_DAZAR, 0);
events.ScheduleEvent(EVENT_ETERNAL_BOND, 80s);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_AERIAL_SMASH:
DoAerialSmash();
break;
case EVENT_BLADE_COMBO:
DoBladeCombo();
break;
case EVENT_BLADE_COMBO_NEXT:
DoBladeComboNext();
break;
case EVENT_GILDED_DESTRUCTION:
DoGildedDestruction();
break;
case EVENT_ETERNAL_BOND:
DoEternalBond();
break;
case EVENT_IMPALING_SPEARS:
DoCastSelf(SPELL_IMPALING_SPEAR);
events.ScheduleEvent(EVENT_IMPALING_SPEARS, 45s);
break;
default:
break;
}
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
}
}
private:
std::vector<Creature*> GetPets() const
{
std::vector<Creature*> pets;
pets.reserve(2);
if (Creature* tzala = me->FindNearestCreature(NPC_TZALA, 150.0f, true))
pets.push_back(tzala);
if (Creature* reban = me->FindNearestCreature(NPC_REBAN, 150.0f, true))
pets.push_back(reban);
return pets;
}
uint8 _comboChain;
};
// 136984 - Reban (King Dazar's raptor)
struct npc_kings_rest_reban : public ScriptedAI
{
npc_kings_rest_reban(Creature* creature) : ScriptedAI(creature) { }
void JustEngagedWith(Unit* /*who*/) override
{
if (InstanceScript* instance = me->GetInstanceScript())
instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, me, 2);
_events.ScheduleEvent(EVENT_RAPTOR_SPLASH, 5s);
_events.ScheduleEvent(EVENT_LEAP, 8s);
_events.ScheduleEvent(EVENT_ROAR, 14s);
}
void Reset() override
{
_events.Reset();
}
void DoHuntingLeap()
{
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 80.0f, true))
{
DoCast(target, SPELL_HUNTING_LEAP);
DoCast(target, SPELL_HUNTING_LEAP_TELEGRAPH);
}
_events.ScheduleEvent(EVENT_LEAP, 10s);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
_events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
while (uint32 eventId = _events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_RAPTOR_SPLASH:
DoCastSelf(SPELL_RAPTOR_SPAWN_SPLASH);
_events.ScheduleEvent(EVENT_RAPTOR_SPLASH, 33s);
break;
case EVENT_LEAP:
DoHuntingLeap();
break;
case EVENT_ROAR:
DoCastSelf(SPELL_DEATHLY_ROAR);
_events.ScheduleEvent(EVENT_ROAR, 10s);
break;
default:
break;
}
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
}
}
private:
EventMap _events;
};
// 136976 - T'zala (the raptor mount)
struct npc_kings_rest_tzala : public ScriptedAI
{
npc_kings_rest_tzala(Creature* creature) : ScriptedAI(creature) { }
void JustEngagedWith(Unit* /*who*/) override
{
if (InstanceScript* instance = me->GetInstanceScript())
instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, me, 2);
// Emulates the retail mount moment ~37s into the fight
_events.ScheduleEvent(EVENT_TZALA_EMPOWER, 37s);
_events.ScheduleEvent(EVENT_SMASH_TZALA, 54s);
_events.ScheduleEvent(EVENT_QUAKE, 49s);
_events.ScheduleEvent(EVENT_MAUL, 76s);
}
void Reset() override
{
_events.Reset();
}
void SetData(uint32 /*type*/, uint32 /*value*/) override
{
// Eternal Bond from the boss empowers the mount
DoCastSelf(SPELL_ETERNAL_BOND_TZALA);
DoCastSelf(SPELL_COPY_THREAT_TO_VEHICLE);
me->SetHealth(me->GetMaxHealth());
}
void DoQuakingLeap()
{
for (MapReference const& ref : me->GetMap()->GetPlayers())
{
Player* player = ref.GetSource();
if (!player || !player->IsAlive() || !me->IsWithinDistInMap(player, 100.0f))
continue;
DoCast(player, SPELL_QUAKING_LEAP);
}
DoCastSelf(SPELL_QUAKING_LEAP_IMPACT);
_events.ScheduleEvent(EVENT_QUAKE, 22s);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
_events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
while (uint32 eventId = _events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_TZALA_EMPOWER:
SetData(0, 0);
break;
case EVENT_SMASH_TZALA:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 80.0f, true))
DoCast(target, SPELL_AERIAL_SMASH_TZALA);
_events.ScheduleEvent(EVENT_SMASH_TZALA, 28s);
break;
case EVENT_QUAKE:
DoQuakingLeap();
break;
case EVENT_MAUL:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 40.0f, true))
DoCast(target, SPELL_SAVAGE_MAUL);
_events.ScheduleEvent(EVENT_MAUL, 12s);
break;
default:
break;
}
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
}
}
private:
EventMap _events;
};
// 269148 - Gold Pool Stalker
struct npc_kings_rest_gold_pool_stalker : public ScriptedAI
{
npc_kings_rest_gold_pool_stalker(Creature* creature) : ScriptedAI(creature) { }
void JustAppeared() override
{
DoZoneInCombat();
_events.ScheduleEvent(EVENT_POOL_DOT, 1s);
}
void UpdateAI(uint32 diff) override
{
_events.Update(diff);
while (uint32 eventId = _events.ExecuteEvent())
{
if (eventId == EVENT_POOL_DOT)
{
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100.0f, true))
DoCast(target, SPELL_GILDED_DESTRUCTION_DOT);
_events.ScheduleEvent(EVENT_POOL_DOT, 3s + 500ms);
}
}
}
private:
EventMap _events;
};
void AddSC_boss_king_dazar()
{
RegisterKingsRestCreatureAI(boss_king_dazar);
RegisterKingsRestCreatureAI(npc_kings_rest_reban);
RegisterKingsRestCreatureAI(npc_kings_rest_tzala);
RegisterKingsRestCreatureAI(npc_kings_rest_gold_pool_stalker);
}
@@ -0,0 +1,323 @@
/*
* This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "CreatureAI.h"
#include "CreatureAIImpl.h"
#include "InstanceScript.h"
#include "Map.h"
#include "ObjectAccessor.h"
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "SpellAuras.h"
#include "SpellScript.h"
#include "TemporarySummon.h"
#include "kings_rest.h"
// Sniff-derived (Map 1762, build 12.1.0.69587)
enum MchimbaSpells
{
SPELL_COMMAND_CONSTRUCTS = 1312911, // engage, summons Interment Construct
SPELL_DRAIN_FLUIDS = 267618, // pull players, 2s cast
SPELL_EXPLOSIVE_ACIDS = 1312143, // floor pools during Drain Fluids
SPELL_BURN_CORRUPTION = 267639, // dot on random player, 4s
SPELL_BURN_CORRUPTION_DUMMY = 1311956,
SPELL_AWAKENING_SLAM = 1312146, // frontal, 3s
SPELL_BURNING_GROUND = 267874, // floor fire at random player
SPELL_ENTOMB = 267702, // lock player into a coffin, 3s
SPELL_OPEN_COFFIN = 271290, // finish the entombed player, 6s
SPELL_EMBALM = 1312569, // Interment Construct dot
SPELL_WRETCHED_DISCHARGE = 267763, // mummy floor pools, 4s
SPELL_SUMMON_HALF_MUMMY = 1312147, // coffin -> Half-Finished Mummy
SPELL_STRUGGLE = 267764, // entombed player tries to break free
SPELL_CHECK_FOR_BADDIES = 267844,
SPELL_MARK_AS_BAD = 1316988,
SPELL_CANCEL_BAD_MARKINGS = 272532
};
enum MchimbaEvents
{
EVENT_MCHIMBA_SLAM = 1,
EVENT_MCHIMBA_BURN,
EVENT_MCHIMBA_DRAIN,
EVENT_MCHIMBA_ACIDS,
EVENT_MCHIMBA_BURNING_GROUND,
EVENT_MCHIMBA_ENTOMB,
EVENT_MCHIMBA_OPEN_COFFIN,
EVENT_MCHIMBA_CONSTRUCT_THROW
};
enum MchimbaTexts
{
SAY_MCHIMBA_AGGRO = 0, // Your bodies bear de infection!
SAY_MCHIMBA_BURN = 1, // De blood curse must be purged!
SAY_MCHIMBA_SLAM = 2, // Prevent infection! Remove de brain!
SAY_MCHIMBA_ENTOMB = 3, // Prepare de body!
SAY_MCHIMBA_KILL = 4, // You have disturbed de dead!
SAY_MCHIMBA_DEATH = 5 // De dead... must be... preserved...
};
// 134993 - Mchimba the Embalmer
struct boss_mchimba_the_embalmer : public BossAI
{
boss_mchimba_the_embalmer(Creature* creature) : BossAI(creature, DATA_MCHIMBA_THE_EMBALMER), _acidPulses(0) { }
void JustEngagedWith(Unit* who) override
{
BossAI::JustEngagedWith(who);
Talk(SAY_MCHIMBA_AGGRO);
DoCastSelf(SPELL_COMMAND_CONSTRUCTS);
events.ScheduleEvent(EVENT_MCHIMBA_DRAIN, 6s);
events.ScheduleEvent(EVENT_MCHIMBA_BURN, 20s);
events.ScheduleEvent(EVENT_MCHIMBA_SLAM, 30s);
events.ScheduleEvent(EVENT_MCHIMBA_BURNING_GROUND, 55s);
events.ScheduleEvent(EVENT_MCHIMBA_ENTOMB, 60s);
}
void JustDied(Unit* /*killer*/) override
{
Talk(SAY_MCHIMBA_DEATH);
DoCastSelf(SPELL_CANCEL_BAD_MARKINGS);
summons.DespawnAll();
_JustDied();
}
void KilledUnit(Unit* victim) override
{
if (victim->IsPlayer())
Talk(SAY_MCHIMBA_KILL);
}
void DoSlam()
{
Talk(SAY_MCHIMBA_SLAM);
DoCastSelf(SPELL_AWAKENING_SLAM);
events.ScheduleEvent(EVENT_MCHIMBA_SLAM, 90s);
}
void DoBurn()
{
Talk(SAY_MCHIMBA_BURN);
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 1, 150.0f, true))
DoCast(target, SPELL_BURN_CORRUPTION);
events.ScheduleEvent(EVENT_MCHIMBA_BURN, 30s);
}
void DoDrain()
{
DoCastSelf(SPELL_DRAIN_FLUIDS);
_acidPulses = 0;
events.ScheduleEvent(EVENT_MCHIMBA_ACIDS, 5s);
events.ScheduleEvent(EVENT_MCHIMBA_DRAIN, 33s);
}
void DoAcidsPulse()
{
// The whole raid is showered by Explosive Acids while the pool erupts
for (MapReference const& ref : me->GetMap()->GetPlayers())
if (Player* player = ref.GetSource())
if (player->IsAlive() && me->IsWithinDistInMap(player, 150.0f))
DoCast(player, SPELL_EXPLOSIVE_ACIDS);
if (++_acidPulses < 5)
events.ScheduleEvent(EVENT_MCHIMBA_ACIDS, 2s);
}
void DoEntomb()
{
Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 150.0f, true);
if (!target)
{
events.ScheduleEvent(EVENT_MCHIMBA_ENTOMB, 2s);
return;
}
// Lock onto the most embalmed player if any
Unit* best = nullptr;
int32 bestStacks = 0;
for (MapReference const& ref : me->GetMap()->GetPlayers())
{
Player* player = ref.GetSource();
if (!player || !player->IsAlive() || !me->IsWithinDistInMap(player, 150.0f))
continue;
int32 stacks = player->GetAuraCount(SPELL_EMBALM);
if (stacks > bestStacks)
{
bestStacks = stacks;
best = player;
}
}
if (best)
target = best;
Talk(SAY_MCHIMBA_ENTOMB, target);
DoCast(target, SPELL_ENTOMB);
_entombTargetGUID = target->GetGUID();
events.ScheduleEvent(EVENT_MCHIMBA_OPEN_COFFIN, 8s);
events.ScheduleEvent(EVENT_MCHIMBA_ENTOMB, 30s);
}
void DoOpenCoffin()
{
if (Unit* entombed = ObjectAccessor::GetUnit(*me, _entombTargetGUID))
if (entombed->IsAlive() && entombed->HasAura(SPELL_ENTOMB))
DoCast(entombed, SPELL_OPEN_COFFIN);
_entombTargetGUID.Clear();
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_MCHIMBA_SLAM:
DoSlam();
break;
case EVENT_MCHIMBA_BURN:
DoBurn();
break;
case EVENT_MCHIMBA_DRAIN:
DoDrain();
break;
case EVENT_MCHIMBA_ACIDS:
DoAcidsPulse();
break;
case EVENT_MCHIMBA_BURNING_GROUND:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100.0f, true))
DoCast(target, SPELL_BURNING_GROUND);
events.ScheduleEvent(EVENT_MCHIMBA_BURNING_GROUND, 70s);
break;
case EVENT_MCHIMBA_ENTOMB:
DoEntomb();
break;
case EVENT_MCHIMBA_OPEN_COFFIN:
DoOpenCoffin();
break;
default:
break;
}
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
}
}
private:
ObjectGuid _entombTargetGUID;
uint8 _acidPulses;
};
enum MummyEvents
{
EVENT_MUMMY_EMBALM = 1,
EVENT_MUMMY_DISCHARGE
};
// 137969 - Interment Construct
struct npc_kings_rest_interment_construct : public ScriptedAI
{
npc_kings_rest_interment_construct(Creature* creature) : ScriptedAI(creature) { }
void JustAppeared() override
{
DoZoneInCombat();
_events.ScheduleEvent(EVENT_MUMMY_EMBALM, 1s);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
_events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
while (uint32 eventId = _events.ExecuteEvent())
{
if (eventId == EVENT_MUMMY_EMBALM)
{
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 150.0f, true))
DoCast(target, SPELL_EMBALM);
_events.ScheduleEvent(EVENT_MUMMY_EMBALM, 7s);
}
}
}
private:
EventMap _events;
};
// 273050 / 136264 - Half-Finished Mummy / Finished Mummy
struct npc_kings_rest_wretched_mummy : public ScriptedAI
{
npc_kings_rest_wretched_mummy(Creature* creature) : ScriptedAI(creature) { }
void JustAppeared() override
{
DoZoneInCombat();
_events.ScheduleEvent(EVENT_MUMMY_DISCHARGE, 4s);
}
void Reset() override
{
_events.Reset();
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
_events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
while (uint32 eventId = _events.ExecuteEvent())
{
if (eventId == EVENT_MUMMY_DISCHARGE)
{
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100.0f, true))
DoCast(target, SPELL_WRETCHED_DISCHARGE);
_events.ScheduleEvent(EVENT_MUMMY_DISCHARGE, 9s);
}
}
}
private:
EventMap _events;
};
void AddSC_boss_mchimba_the_embalmer()
{
RegisterKingsRestCreatureAI(boss_mchimba_the_embalmer);
RegisterKingsRestCreatureAI(npc_kings_rest_interment_construct);
RegisterKingsRestCreatureAI(npc_kings_rest_wretched_mummy);
}
@@ -0,0 +1,461 @@
/*
* This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "CreatureAI.h"
#include "CreatureAIImpl.h"
#include "InstanceScript.h"
#include "Map.h"
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "TemporarySummon.h"
#include "kings_rest.h"
// Sniff-derived (Map 1762, build 12.1.0.69587)
enum CouncilSpells
{
// Zanazal the Wise
SPELL_ASSIST_CALL = 1305716, // buffs all allies
SPELL_ARC_LIGHTNING = 1305810, // chain lightning channel, ~1s
SPELL_POISON_NOVA = 267273, // 4s wind-up nova
SPELL_CALL_OF_THE_ELEMENTS = 267060, // 2.5s, summons the 3 totems
// Kula the Butcher
SPELL_WHIRLING_AXE = 266191, // toss axe at a player
// Aka'ali the Conqueror
SPELL_BERSERKER_ASSIST_TELEPORT = 1305707, // reposition near an ally
SPELL_BARREL_THROUGH = 266951, // 6s telegraph charge
// Totems
SPELL_REINFORCED = 1309499,
SPELL_TORRENT = 267096, // Torrent Totem
SPELL_DISRUPTION = 267257, // Thundering Totem
SPELL_EXPLODE = 267077 // Explosive Totem, 9s
};
enum CouncilEvents
{
// Zanazal
EVENT_Z_ASSIST = 1,
EVENT_Z_ARC_LIGHTNING,
EVENT_Z_POISON_NOVA,
EVENT_Z_CALL_ELEMENTS,
// Kula
EVENT_K_WHIRLING_AXE,
// Aka'ali
EVENT_A_ASSIST_TELEPORT,
EVENT_A_BARREL_THROUGH,
// Totems
EVENT_TOTEM_TORRENT,
EVENT_TOTEM_DISRUPTION,
EVENT_TOTEM_EXPLODE
};
enum CouncilTexts
{
SAY_KULA_AGGRO = 0, // Time to get de axe!
SAY_KULA_WHIRLING_AXE = 1, // Somebody is losing a head!
SAY_ZANAZAL_POISON = 0, // Dere is no antidote for dis poison!
SAY_ZANAZAL_ELEMENTS = 1, // De elements answer my call!
SAY_AKAALI_BARREL = 0, // Here comes de pain!
SAY_AKAALI_DEATH = 1, // My rage... be... undying...
SAY_KULA_DEATH = 2, // My head... will make... a fine trophy...
SAY_ZANAZAL_DEATH = 2 // Please... bury me... far from dese... imbeciles...
};
// Base AI shared by the three council members: manages the shared encounter state,
// the boss frame, chaining the arena into combat and encounter completion.
class boss_council_tribes_member : public ScriptedAI
{
public:
boss_council_tribes_member(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) { }
void JustEngagedWith(Unit* who) override
{
ScriptedAI::JustEngagedWith(who);
// The whole council chamber answers the pull
for (Creature* member : GetMembers())
if (member)
member->AI()->DoZoneInCombat();
if (_instance && _instance->GetBossState(DATA_COUNCIL_OF_TRIBES) != IN_PROGRESS)
{
_instance->SetBossState(DATA_COUNCIL_OF_TRIBES, IN_PROGRESS);
for (Creature* member : GetMembers())
if (member)
_instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, member);
}
}
void EnterEvadeMode(EvadeReason why) override
{
ScriptedAI::EnterEvadeMode(why);
if (!_instance || _instance->GetBossState(DATA_COUNCIL_OF_TRIBES) == DONE)
return;
bool anyInCombat = false;
for (Creature* member : GetMembers())
if (member && member->IsInCombat())
anyInCombat = true;
if (!anyInCombat && _instance->GetBossState(DATA_COUNCIL_OF_TRIBES) == IN_PROGRESS)
{
for (Creature* member : GetMembers())
if (member)
_instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, member);
_instance->SetBossState(DATA_COUNCIL_OF_TRIBES, FAIL);
}
}
void JustDied(Unit* /*killer*/) override
{
Talk(GetDeathText());
if (!_instance)
return;
bool allDead = true;
for (Creature* member : GetMembers())
if (member && member->IsAlive())
allDead = false;
if (allDead && _instance->GetBossState(DATA_COUNCIL_OF_TRIBES) == IN_PROGRESS)
{
for (Creature* member : GetMembers())
if (member)
_instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, member);
_instance->SetBossState(DATA_COUNCIL_OF_TRIBES, DONE);
// summoned totems despawn themselves once the encounter leaves IN_PROGRESS
}
}
protected:
InstanceScript* _instance;
std::vector<Creature*> GetMembers() const
{
std::vector<Creature*> members;
members.reserve(3);
if (!_instance)
return members;
if (Creature* member = _instance->GetCreature(DATA_AKAALI_THE_CONQUEROR))
members.push_back(member);
if (Creature* member = _instance->GetCreature(DATA_ZANAZAL_THE_WISE))
members.push_back(member);
if (Creature* member = _instance->GetCreature(DATA_KULA_THE_BUTCHER))
members.push_back(member);
return members;
}
virtual uint8 GetDeathText() const = 0;
};
// 269810 - Zanazal the Wise
struct boss_zanazal_the_wise : public boss_council_tribes_member
{
boss_zanazal_the_wise(Creature* creature) : boss_council_tribes_member(creature) { }
void JustEngagedWith(Unit* who) override
{
boss_council_tribes_member::JustEngagedWith(who);
events.ScheduleEvent(EVENT_Z_ASSIST, 2s);
events.ScheduleEvent(EVENT_Z_ARC_LIGHTNING, 2s);
events.ScheduleEvent(EVENT_Z_POISON_NOVA, 10s + 500ms);
events.ScheduleEvent(EVENT_Z_CALL_ELEMENTS, 20s);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_Z_ASSIST:
DoCastSelf(SPELL_ASSIST_CALL);
events.ScheduleEvent(EVENT_Z_ASSIST, 90s);
break;
case EVENT_Z_ARC_LIGHTNING:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100.0f, true))
DoCast(target, SPELL_ARC_LIGHTNING);
events.ScheduleEvent(EVENT_Z_ARC_LIGHTNING, 8s + 500ms);
break;
case EVENT_Z_POISON_NOVA:
Talk(SAY_ZANAZAL_POISON);
DoCastSelf(SPELL_POISON_NOVA);
events.ScheduleEvent(EVENT_Z_POISON_NOVA, 18s);
break;
case EVENT_Z_CALL_ELEMENTS:
Talk(SAY_ZANAZAL_ELEMENTS);
DoCastSelf(SPELL_CALL_OF_THE_ELEMENTS);
events.ScheduleEvent(EVENT_Z_CALL_ELEMENTS, 30s);
break;
default:
break;
}
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
}
}
protected:
uint8 GetDeathText() const override
{
return SAY_ZANAZAL_DEATH;
}
};
// 269811 - Kula the Butcher
struct boss_kula_the_butcher : public boss_council_tribes_member
{
boss_kula_the_butcher(Creature* creature) : boss_council_tribes_member(creature) { }
void JustEngagedWith(Unit* who) override
{
boss_council_tribes_member::JustEngagedWith(who);
Talk(SAY_KULA_AGGRO);
events.ScheduleEvent(EVENT_K_WHIRLING_AXE, 24s);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
while (uint32 eventId = events.ExecuteEvent())
{
if (eventId == EVENT_K_WHIRLING_AXE)
{
Talk(SAY_KULA_WHIRLING_AXE);
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 1, 100.0f, true))
DoCast(target, SPELL_WHIRLING_AXE);
events.ScheduleEvent(EVENT_K_WHIRLING_AXE, 20s);
}
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
}
}
protected:
uint8 GetDeathText() const override
{
return SAY_KULA_DEATH;
}
};
// 269808 - Aka'ali the Conqueror
struct boss_akaali_the_conqueror : public boss_council_tribes_member
{
boss_akaali_the_conqueror(Creature* creature) : boss_council_tribes_member(creature) { }
void JustEngagedWith(Unit* who) override
{
boss_council_tribes_member::JustEngagedWith(who);
events.ScheduleEvent(EVENT_A_ASSIST_TELEPORT, 22s);
events.ScheduleEvent(EVENT_A_BARREL_THROUGH, 27s);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_A_ASSIST_TELEPORT:
DoCastSelf(SPELL_BERSERKER_ASSIST_TELEPORT);
events.ScheduleEvent(EVENT_A_ASSIST_TELEPORT, 30s);
break;
case EVENT_A_BARREL_THROUGH:
Talk(SAY_AKAALI_BARREL);
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 1, 100.0f, true))
DoCast(target, SPELL_BARREL_THROUGH);
events.ScheduleEvent(EVENT_A_BARREL_THROUGH, 24s);
break;
default:
break;
}
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
}
}
protected:
uint8 GetDeathText() const override
{
return SAY_AKAALI_DEATH;
}
};
// 135765 - Torrent Totem
struct npc_kings_rest_torrent_totem : public ScriptedAI
{
npc_kings_rest_torrent_totem(Creature* creature) : ScriptedAI(creature) { }
void JustAppeared() override
{
DoCastSelf(SPELL_REINFORCED);
DoZoneInCombat();
_events.ScheduleEvent(EVENT_TOTEM_TORRENT, 1s);
}
void UpdateAI(uint32 diff) override
{
if (DespawnIfEncounterEnded())
return;
_events.Update(diff);
while (uint32 eventId = _events.ExecuteEvent())
{
if (eventId == EVENT_TOTEM_TORRENT)
{
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100.0f, true))
DoCast(target, SPELL_TORRENT);
_events.ScheduleEvent(EVENT_TOTEM_TORRENT, 6s);
}
}
}
private:
EventMap _events;
bool DespawnIfEncounterEnded()
{
if (InstanceScript* instance = me->GetInstanceScript())
if (instance->GetBossState(DATA_COUNCIL_OF_TRIBES) == IN_PROGRESS)
return false;
me->DespawnOrUnsummon(1s);
return true;
}
};
// 135761 - Thundering Totem
struct npc_kings_rest_thundering_totem : public ScriptedAI
{
npc_kings_rest_thundering_totem(Creature* creature) : ScriptedAI(creature) { }
void JustAppeared() override
{
DoCastSelf(SPELL_REINFORCED);
DoZoneInCombat();
_events.ScheduleEvent(EVENT_TOTEM_DISRUPTION, 1s);
}
void UpdateAI(uint32 diff) override
{
if (InstanceScript* instance = me->GetInstanceScript())
if (instance->GetBossState(DATA_COUNCIL_OF_TRIBES) != IN_PROGRESS)
{
me->DespawnOrUnsummon(1s);
return;
}
_events.Update(diff);
while (uint32 eventId = _events.ExecuteEvent())
{
if (eventId == EVENT_TOTEM_DISRUPTION)
{
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100.0f, true))
DoCast(target, SPELL_DISRUPTION);
_events.ScheduleEvent(EVENT_TOTEM_DISRUPTION, 8s);
}
}
}
private:
EventMap _events;
};
// 135764 - Explosive Totem
struct npc_kings_rest_explosive_totem : public ScriptedAI
{
npc_kings_rest_explosive_totem(Creature* creature) : ScriptedAI(creature) { }
void JustAppeared() override
{
DoCastSelf(SPELL_REINFORCED);
DoZoneInCombat();
_events.ScheduleEvent(EVENT_TOTEM_EXPLODE, 9s);
}
void UpdateAI(uint32 diff) override
{
if (InstanceScript* instance = me->GetInstanceScript())
if (instance->GetBossState(DATA_COUNCIL_OF_TRIBES) != IN_PROGRESS)
{
me->DespawnOrUnsummon(1s);
return;
}
_events.Update(diff);
while (uint32 eventId = _events.ExecuteEvent())
{
if (eventId == EVENT_TOTEM_EXPLODE)
{
DoCastSelf(SPELL_EXPLODE);
me->DespawnOrUnsummon(1s);
}
}
}
private:
EventMap _events;
};
void AddSC_boss_the_council_of_tribes()
{
RegisterKingsRestCreatureAI(boss_zanazal_the_wise);
RegisterKingsRestCreatureAI(boss_kula_the_butcher);
RegisterKingsRestCreatureAI(boss_akaali_the_conqueror);
RegisterKingsRestCreatureAI(npc_kings_rest_torrent_totem);
RegisterKingsRestCreatureAI(npc_kings_rest_thundering_totem);
RegisterKingsRestCreatureAI(npc_kings_rest_explosive_totem);
}
@@ -47,11 +47,29 @@ enum KingsRestCreatureIds
{
// Bosses
BOSS_GOLDEN_SERPENT = 135322,
BOSS_AKAALI_THE_CONQUEROR = 135470,
BOSS_ZANAZAL_THE_WISE = 135472,
BOSS_KULA_THE_BUTCHER = 135475,
BOSS_AKAALI_THE_CONQUEROR = 269808,
BOSS_ZANAZAL_THE_WISE = 269810,
BOSS_KULA_THE_BUTCHER = 269811,
BOSS_MCHIMBA_THE_EMBALMER = 134993,
BOSS_KING_DAZAR = 136160
BOSS_KING_DAZAR = 136160,
// Mchimba the Embalmer
NPC_INTERMENT_CONSTRUCT = 137969,
NPC_FINISHED_MUMMY = 136264,
NPC_HALF_FINISHED_MUMMY = 273050,
NPC_EMBALMING_COFFIN = 136256,
NPC_HUNTING_LEAP = 270502,
// Council of Tribes
NPC_TORRENT_TOTEM = 135765,
NPC_EXPLOSIVE_TOTEM = 135764,
NPC_THUNDERING_TOTEM = 135761,
// King Dazar
NPC_TZALA = 136976,
NPC_REBAN = 136984,
NPC_GOLD_POOL_STALKER = 269148,
NPC_WAYSTONE = 247012,
};
enum KingsRestGameObjectIds
@@ -33,6 +33,9 @@ void AddSC_boss_sporecaller_zancha();
void AddSC_instance_kings_rest();
void AddSC_kings_rest();
void AddSC_boss_golden_serpent();
void AddSC_boss_mchimba_the_embalmer();
void AddSC_boss_the_council_of_tribes();
void AddSC_boss_king_dazar();
// The name of this function should match:
// void Add${NameOfDirectory}Scripts()
@@ -54,4 +57,7 @@ void AddZandalarScripts()
AddSC_instance_kings_rest();
AddSC_kings_rest();
AddSC_boss_golden_serpent();
AddSC_boss_mchimba_the_embalmer();
AddSC_boss_the_council_of_tribes();
AddSC_boss_king_dazar();
}