From bcba6a82fabec3a9d50d84edab34e3091b10d8a0 Mon Sep 17 00:00:00 2001 From: Ovahlord Date: Sat, 5 Oct 2019 09:12:08 +0200 Subject: [PATCH] Scripts/Deadmines: reworked Glubtok encounter * update script to new model * use sniffed spline points and velocity for Glubtok's firewall platter * corrected several timers * re-order death sequence to reflect sniff data perfectly * optimized several condition handlings * increased Glubtok's melee damage * added missing instance bind flag to Glubtok --- .../custom/custom_2019_10_05_01_world.sql | 1 + .../Deadmines/boss_glubtok.cpp | 533 +++++++++--------- .../EasternKingdoms/Deadmines/deadmines.h | 3 + 3 files changed, 256 insertions(+), 281 deletions(-) create mode 100644 sql/updates/world/custom/custom_2019_10_05_01_world.sql diff --git a/sql/updates/world/custom/custom_2019_10_05_01_world.sql b/sql/updates/world/custom/custom_2019_10_05_01_world.sql new file mode 100644 index 00000000000..6bd836037b1 --- /dev/null +++ b/sql/updates/world/custom/custom_2019_10_05_01_world.sql @@ -0,0 +1 @@ +UPDATE `creature_template` SET `DamageModifier`= 120, `flags_extra`= `flags_extra` | 1 WHERE `entry`= 48936; diff --git a/src/server/scripts/EasternKingdoms/Deadmines/boss_glubtok.cpp b/src/server/scripts/EasternKingdoms/Deadmines/boss_glubtok.cpp index 2c1a57f404e..34ec5a51096 100644 --- a/src/server/scripts/EasternKingdoms/Deadmines/boss_glubtok.cpp +++ b/src/server/scripts/EasternKingdoms/Deadmines/boss_glubtok.cpp @@ -20,6 +20,7 @@ #include "ScriptedCreature.h" #include "SpellScript.h" #include "SpellAuraEffects.h" +#include "MoveSplineInit.h" #include "Player.h" #include "Vehicle.h" #include "deadmines.h" @@ -64,7 +65,7 @@ enum Events EVENT_ANNOUNCE_FIRE_WALL, EVENT_FIRE_WALL, EVENT_BLOSSOM_TARGETING, - EVENT_ARCANE_OVERLOAD, + EVENT_KILL_SELF }; enum Phases @@ -97,122 +98,185 @@ enum Data }; Position const leftSideDistanceCheck = { -210.840f, -443.449f, 61.179f }; +Position const FirewallPlatterSummonPos = { -193.4054f, -441.5011f, 54.57029f, 1.833041f }; -class boss_glubtok : public CreatureScript +static constexpr uint32 const FirewallPlatterCyclicPathSize = 9; +Position const FirewallPlatterCyclicPath[FirewallPlatterCyclicPathSize] = { -public: - boss_glubtok() : CreatureScript("boss_glubtok") { } + { -193.2778f, -442.0017f, 53.70924f }, + { -193.4514f, -441.0169f, 55.70924f }, + { -192.7042f, -441.1826f, 55.70924f }, + { -192.293f, -441.8281f, 55.70924f }, + { -192.4586f, -442.5753f, 55.70924f }, + { -193.1041f, -442.9865f, 55.70924f }, + { -193.8514f, -442.8209f, 55.70924f }, + { -194.2626f, -442.1754f, 55.70924f }, + { -194.0969f, -441.4282f, 55.70924f } +}; - struct boss_glubtokAI : public BossAI +struct boss_glubtok : public BossAI +{ + boss_glubtok(Creature* creature) : BossAI(creature, DATA_GLUBTOK), + _defeated(false), _nextBlossomBunny(NPC_FIRE_BLOSSOM_BUNNY), _lastFists(FISTS_OF_FLAME) { } + + void Reset() override { - boss_glubtokAI(Creature* creature) : BossAI(creature, DATA_GLUBTOK) - { - Initialize(); - } + _Reset(); + me->SetCanDualWield(true); + } - void Initialize() + void JustAppeared() override + { + if (Creature* platter = DoSummon(NPC_GLUBTOK_FIREWALL_PLATTER, FirewallPlatterSummonPos, 0, TEMPSUMMON_MANUAL_DESPAWN)) { - _killed = false; - _allowKill = false; - _nextBlossomBunny = NPC_FIRE_BLOSSOM_BUNNY; - _lastFists = FISTS_OF_FLAME; - - } - - void Reset() override - { - _Reset(); - Initialize(); - me->SetCanDualWield(true); - } - - void JustAppeared() override - { - DoSummon(NPC_GLUBTOK_FIREWALL_PLATTER, { me->GetPositionX(), me->GetPositionY(), 54.57029f, me->GetOrientation() }, 0, TEMPSUMMON_MANUAL_DESPAWN); - } - - void JustEngagedWith(Unit* /*who*/) override - { - _JustEngagedWith(); - Talk(SAY_AGGRO); - instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, me); - events.SetPhase(PHASE_1); - events.ScheduleEvent(EVENT_BLINK, Seconds(18), 0, PHASE_1); - } - - void JustDied(Unit* /*killer*/) override - { - _JustDied(); - instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me); - } - - void EnterEvadeMode(EvadeReason /*why*/) override - { - _EnterEvadeMode(); - summons.DespawnAll(); - instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me); - _DespawnAtEvade(); - } - - void JustSummoned(Creature* summon) override - { - switch (summon->GetEntry()) + platter->m_Events.AddEventAtOffset([platter]() { - case NPC_GLUBTOK_FIREWALL_PLATTER: - summon->SetSpeed(MOVE_RUN, 0.5f); - summon->m_Events.AddEventAtOffset([summon]() - { - summon->GetMotionMaster()->MoveCirclePath(summon->GetPositionX(), summon->GetPositionY(), 55.70924f, 3.0f, true, 10); - }, 1s); - break; - case NPC_FIREWALL_PLATTER_1A: - case NPC_FIREWALL_PLATTER_1B: - case NPC_FIREWALL_PLATTER_1C: - case NPC_FIREWALL_PLATTER_2A: - case NPC_FIREWALL_PLATTER_2B: - case NPC_FIREWALL_PLATTER_2C: - _firewallDummyGUIDs.push_back(summon->GetGUID()); - break; - default: - break; - } - summons.Summon(summon); + platter->GetMotionMaster()->MoveCyclicPath(FirewallPlatterCyclicPath, FirewallPlatterCyclicPathSize, false, true, 0.25f); + }, 1s); + } + } + + void JustEngagedWith(Unit* /*who*/) override + { + _JustEngagedWith(); + Talk(SAY_AGGRO); + instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, me); + events.SetPhase(PHASE_1); + events.ScheduleEvent(EVENT_BLINK, 16s, 18s, 0, PHASE_1); + } + + void JustDied(Unit* /*killer*/) override + { + _JustDied(); + instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me); + } + + void EnterEvadeMode(EvadeReason /*why*/) override + { + _EnterEvadeMode(); + summons.DespawnAll(); + instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me); + _DespawnAtEvade(); + } + + void JustSummoned(Creature* summon) override + { + switch (summon->GetEntry()) + { + case NPC_FIREWALL_PLATTER_2A: + case NPC_FIREWALL_PLATTER_2B: + case NPC_FIREWALL_PLATTER_2C: + _firewallDummyGUIDs.push_back(summon->GetGUID()); + break; + default: + break; + } + summons.Summon(summon); + } + + void DamageTaken(Unit* /*attacker*/, uint32& damage) override + { + if (me->HealthBelowPctDamaged(50, damage) && !events.IsInPhase(PHASE_2) && !_defeated) + { + events.SetPhase(PHASE_2); + me->SetReactState(REACT_PASSIVE); + me->AttackStop(); + me->InterruptNonMeleeSpells(true); + DoCastSelf(SPELL_TELEPORT, true); + me->StopMoving(); + me->NearTeleportTo(me->GetHomePosition()); + events.ScheduleEvent(EVENT_PHASE_TWO_INTRO_1, 3s + 800ms, 0, PHASE_2); } - void SpellHitTarget(Unit* target, SpellInfo const* spell) override + if (damage >= me->GetHealth()) { - if (spell->Id == SPELL_BLOSSOM_TARGETING) + damage = me->GetHealth() - 1; + if (!_defeated) { - DoCast(target, target->GetEntry() == NPC_FIRE_BLOSSOM_BUNNY ? SPELL_FIRE_BLOSSOM : SPELL_FROST_BLOSSOM, true); - target->CastSpell(target, target->GetEntry() == NPC_FIRE_BLOSSOM_BUNNY ? SPELL_FIRE_BLOSSOM_VISUAL : SPELL_FROST_BLOSSOM_VISUAL, true); - } - } + _defeated = true; + Talk(SAY_DEATH); + events.Reset(); + DoCastSelf(SPELL_ARCANE_OVERLOAD); + events.ScheduleEvent(EVENT_KILL_SELF, 4s + 800ms); - void DamageTaken(Unit* /*attacker*/, uint32& damage) override - { - if (me->HealthBelowPctDamaged(50, damage) && !events.IsInPhase(PHASE_2)) - { - events.SetPhase(PHASE_2); - me->SetReactState(REACT_PASSIVE); - me->AttackStop(); - me->CastStop(); - DoCastSelf(SPELL_TELEPORT, true); - me->StopMoving(); - me->NearTeleportTo(me->GetHomePosition()); - events.ScheduleEvent(EVENT_PHASE_TWO_INTRO_1, Seconds(3) + Milliseconds(600)); - } - - if (damage >= me->GetHealth() && !_allowKill) - { - damage = me->GetHealth() - 1; - if (!_killed) + // We really need this here because there are more of those triggers in the instance... + std::list units; + GetCreatureListWithEntryInGrid(units, me, NPC_GENERAL_PURPOSE_BUNNY_L2, 30.0f); + if (!units.empty()) { - _killed = true; - Talk(SAY_DEATH); - events.CancelEvent(EVENT_BLOSSOM_TARGETING); - DoCastSelf(SPELL_ARCANE_OVERLOAD, true); - events.ScheduleEvent(EVENT_ARCANE_OVERLOAD, Seconds(6)); - // We really need this here because there are more of those triggers in the instance... + for (auto itr = units.begin(); itr != units.end(); ++itr) + { + if ((*itr)->GetHomePosition().GetExactDist(leftSideDistanceCheck) <= 20.0f) + (*itr)->CastSpell((*itr), SPELL_ARCANE_FROST_BEAM); + else + (*itr)->CastSpell((*itr), SPELL_ARCANE_FIRE_BEAM); + } + } + } + } + } + + uint32 GetData(uint32 type) const override + { + if (type == DATA_CURRENT_BLOSSOM) + return _nextBlossomBunny; + return 0; + } + + 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_BLINK: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 50.0f, true, 0)) + { + DoCast(target, SPELL_BLINK); + if (IsHeroic()) + me->getThreatManager().resetAllAggro(); + + events.ScheduleEvent(EVENT_ELEMENTAL_FISTS, 800ms, 0, PHASE_1); + events.Repeat(13s, 14s); + } + break; + case EVENT_ELEMENTAL_FISTS: + Talk(_lastFists == FISTS_OF_FLAME ? SAY_FISTS_OF_FROST : SAY_FISTS_OF_FLAME); + DoCastSelf(_lastFists == FISTS_OF_FLAME ? SPELL_FISTS_OF_FROST : SPELL_FISTS_OF_FLAME); + _lastFists = _lastFists == FISTS_OF_FLAME ? FISTS_OF_FROST : SPELL_FISTS_OF_FLAME; + break; + case EVENT_PHASE_TWO_INTRO_1: + Talk(SAY_PHASE_TWO_INTRO_1); + DoCastSelf(SPELL_EMOTE_TALK, true); + events.ScheduleEvent(EVENT_PHASE_TWO_INTRO_2, 2s + 400ms, 0, PHASE_2); + break; + case EVENT_PHASE_TWO_INTRO_2: + Talk(SAY_PHASE_TWO_INTRO_2); + DoCastSelf(SPELL_EMOTE_ROAR, true); + events.ScheduleEvent(EVENT_ARCANE_POWER, 2s + 400ms, 0, PHASE_2); + break; + case EVENT_ARCANE_POWER: + { + Talk(SAY_ARCANE_POWER); + DoCastSelf(SPELL_ARCANE_POWER); + me->SetDisableGravity(true); + me->SendSetPlayHoverAnim(true); + + Movement::MoveSplineInit init(me); + init.MoveTo(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ() + 2.0f, false); + init.SetWalk(true); + init.SetVelocity(0.8f); + init.Launch(); + + // We really need this here because there are more of those triggers in other rooms... std::list units; GetCreatureListWithEntryInGrid(units, me, NPC_GENERAL_PURPOSE_BUNNY_L2, 30.0f); if (!units.empty()) @@ -225,199 +289,106 @@ public: (*itr)->CastSpell((*itr), SPELL_ARCANE_FIRE_BEAM); } } + events.ScheduleEvent(EVENT_STUN_SELF, 2s + 200ms, 0, PHASE_2); + events.ScheduleEvent(EVENT_BLOSSOM_TARGETING, 6s, 0, PHASE_2); + break; } - } - } - - uint32 GetData(uint32 type) const override - { - if (type == DATA_CURRENT_BLOSSOM) - return _nextBlossomBunny; - return 0; - } - - 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_BLINK: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 50.0f, true, 0)) - { - DoCast(target, SPELL_BLINK); - if (IsHeroic()) - me->getThreatManager().resetAllAggro(); - - events.ScheduleEvent(EVENT_ELEMENTAL_FISTS, Milliseconds(800), 0, PHASE_1); - events.Repeat(Seconds(13) + Milliseconds(300)); - } - break; - case EVENT_ELEMENTAL_FISTS: - switch (_lastFists) - { - case FISTS_OF_FLAME: - Talk(SAY_FISTS_OF_FROST); - DoCastSelf(SPELL_FISTS_OF_FROST); - _lastFists = FISTS_OF_FROST; - break; - case FISTS_OF_FROST: - Talk(SAY_FISTS_OF_FLAME); - DoCastSelf(SPELL_FISTS_OF_FLAME); - _lastFists = FISTS_OF_FLAME; - break; - default: - break; - } - break; - case EVENT_PHASE_TWO_INTRO_1: - Talk(SAY_PHASE_TWO_INTRO_1); - DoCastSelf(SPELL_EMOTE_TALK, true); - events.ScheduleEvent(EVENT_PHASE_TWO_INTRO_2, Seconds(2) + Milliseconds(400)); - break; - case EVENT_PHASE_TWO_INTRO_2: - Talk(SAY_PHASE_TWO_INTRO_2); - DoCastSelf(SPELL_EMOTE_ROAR, true); - events.ScheduleEvent(EVENT_ARCANE_POWER, Seconds(2) + Milliseconds(400)); - break; - case EVENT_ARCANE_POWER: + case EVENT_STUN_SELF: + DoCastSelf(SPELL_STUN_SELF); + if (IsHeroic()) + events.ScheduleEvent(EVENT_ANNOUNCE_FIRE_WALL, 1s + 500ms, 0, PHASE_2); + break; + case EVENT_ANNOUNCE_FIRE_WALL: + Talk(SAY_ANNOUNCE_FIRE_WALL); + events.ScheduleEvent(EVENT_FIRE_WALL, 1s + 400ms, 0, PHASE_2); + break; + case EVENT_FIRE_WALL: + for (ObjectGuid guid : _firewallDummyGUIDs) { - Talk(SAY_ARCANE_POWER); - DoCastSelf(SPELL_ARCANE_POWER); - me->SetHover(true); - - // We really need this here because there are more of those triggers in other rooms... - std::list units; - GetCreatureListWithEntryInGrid(units, me, NPC_GENERAL_PURPOSE_BUNNY_L2, 30.0f); - if (!units.empty()) - { - for (auto itr = units.begin(); itr != units.end(); ++itr) - { - if ((*itr)->GetHomePosition().GetExactDist(leftSideDistanceCheck) <= 20.0f) - (*itr)->CastSpell((*itr), SPELL_ARCANE_FROST_BEAM); - else - (*itr)->CastSpell((*itr), SPELL_ARCANE_FIRE_BEAM); - } - } - events.ScheduleEvent(EVENT_STUN_SELF, Seconds(2) + Milliseconds(500)); - events.ScheduleEvent(EVENT_BLOSSOM_TARGETING, Seconds(6)); - break; + if (Creature* firewallDummy = ObjectAccessor::GetCreature(*me, guid)) + firewallDummy->CastSpell(firewallDummy, SPELL_FIRE_WALL); } - case EVENT_STUN_SELF: - DoCastSelf(SPELL_STUN_SELF, true); - if (IsHeroic()) - events.ScheduleEvent(EVENT_ANNOUNCE_FIRE_WALL, Seconds(1) + Milliseconds(500)); - break; - case EVENT_ANNOUNCE_FIRE_WALL: - Talk(SAY_ANNOUNCE_FIRE_WALL); - events.ScheduleEvent(EVENT_FIRE_WALL, Seconds(1) + Milliseconds(400)); - break; - case EVENT_FIRE_WALL: - for (ObjectGuid guid : _firewallDummyGUIDs) - if (Creature* firewallDummy = ObjectAccessor::GetCreature(*me, guid)) - if (firewallDummy->GetEntry() != NPC_FIREWALL_PLATTER_1A - && firewallDummy->GetEntry() != NPC_FIREWALL_PLATTER_1B - && firewallDummy->GetEntry() != NPC_FIREWALL_PLATTER_1C) - firewallDummy->CastSpell(firewallDummy, SPELL_FIRE_WALL); - break; - case EVENT_ARCANE_OVERLOAD: - me->SetHover(false); - _allowKill = true; - DoCastSelf(SPELL_TRANSITION_INVISIBILITY, true); - DoCastSelf(SPELL_ARCANE_OVERLOAD_INSTAKILL, true); - if (Creature* bunny = me->FindNearestCreature(NPC_GENERAL_PURPOSE_DUMMY_JMF, 5.0f, true)) + break; + case EVENT_BLOSSOM_TARGETING: + _nextBlossomBunny == NPC_FIRE_BLOSSOM_BUNNY ? NPC_FROST_BLOSSOM_BUNNY : NPC_FIRE_BLOSSOM_BUNNY; + DoCastAOE(SPELL_BLOSSOM_TARGETING, true); + events.Repeat(2s + 400ms); + break; + case EVENT_KILL_SELF: + { + me->KillSelf(); + Creature* creature = me; + me->m_Events.AddEventAtOffset([creature]() + { + creature->CastSpell(creature, SPELL_TRANSITION_INVISIBILITY); + creature->CastSpell(creature, SPELL_ARCANE_OVERLOAD_INSTAKILL); + if (Creature* bunny = creature->FindNearestCreature(NPC_GENERAL_PURPOSE_DUMMY_JMF, 5.0f, true)) bunny->CastSpell(bunny, SPELL_ARCANE_OVERLOAD_EXPLOSION); - break; - case EVENT_BLOSSOM_TARGETING: - if (_nextBlossomBunny == NPC_FIRE_BLOSSOM_BUNNY) - _nextBlossomBunny = NPC_FROST_BLOSSOM_BUNNY; - else - _nextBlossomBunny = NPC_FIRE_BLOSSOM_BUNNY; + }, 1s + 600ms); + break; + } + default: + break; + } + } + DoMeleeAttackIfReady(); + } +private: + bool _defeated; + uint8 _lastFists; + uint32 _nextBlossomBunny; + GuidVector _firewallDummyGUIDs; +}; - DoCastAOE(SPELL_BLOSSOM_TARGETING, true); - events.Repeat(Seconds(2) + Milliseconds(400)); - break; - default: - break; +class spell_glubtok_blossom_targeting : public SpellScript +{ + PrepareSpellScript(spell_glubtok_blossom_targeting); + + void FilterTargets(std::list& targets) + { + if (targets.empty()) + return; + + if (Unit* caster = GetCaster()) + { + if (Creature* creature = caster->ToCreature()) + { + if (creature->IsAIEnabled) + { + uint32 currentBlossomEntry = creature->AI()->GetData(DATA_CURRENT_BLOSSOM); + targets.remove_if([currentBlossomEntry](WorldObject const* obj)->bool + { + return obj->GetTypeId() != TYPEID_UNIT || obj->GetEntry() != currentBlossomEntry; + }); } } - - DoMeleeAttackIfReady(); } - private: - bool _killed; - bool _allowKill; - uint8 _lastFists; - uint32 _nextBlossomBunny; - GuidVector _firewallDummyGUIDs; - }; - CreatureAI* GetAI(Creature *creature) const override - { - return GetDeadminesAI(creature); + if (targets.empty()) + return; + + Trinity::Containers::RandomResize(targets, 1); } -}; -class CreatureEntryCheck -{ - public: - CreatureEntryCheck(uint32 entry) : _entry(entry) { } - - bool operator()(WorldObject* object) + void HandleBlossomEffect(SpellEffIndex /*effIndex*/) + { + Unit* target = GetHitUnit(); + if (Unit* caster = GetCaster()) { - return (object->GetEntry() != _entry); + caster->CastSpell(target, target->GetEntry() == NPC_FIRE_BLOSSOM_BUNNY ? SPELL_FIRE_BLOSSOM : SPELL_FROST_BLOSSOM, true); + target->CastSpell(target, target->GetEntry() == NPC_FIRE_BLOSSOM_BUNNY ? SPELL_FIRE_BLOSSOM_VISUAL : SPELL_FROST_BLOSSOM_VISUAL, true); } - private: - uint32 _entry; -}; + } -class spell_glubtok_blossom_targeting : public SpellScriptLoader -{ - public: - spell_glubtok_blossom_targeting() : SpellScriptLoader("spell_glubtok_blossom_targeting") { } - - class spell_glubtok_blossom_targeting_SpellScript : public SpellScript - { - PrepareSpellScript(spell_glubtok_blossom_targeting_SpellScript); - - void FilterTargets(std::list& targets) - { - if (targets.empty()) - return; - - if (Unit* caster = GetCaster()) - if (Creature* creature = caster->ToCreature()) - if (creature->IsAIEnabled) - targets.remove_if(CreatureEntryCheck(creature->GetAI()->GetData(DATA_CURRENT_BLOSSOM))); - - if (targets.empty()) - return; - - Trinity::Containers::RandomResize(targets, 1); - } - - void Register() override - { - OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_glubtok_blossom_targeting_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENTRY); - } - }; - - SpellScript* GetSpellScript() const override - { - return new spell_glubtok_blossom_targeting_SpellScript(); - } + void Register() override + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_glubtok_blossom_targeting::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENTRY); + OnEffectHitTarget += SpellEffectFn(spell_glubtok_blossom_targeting::HandleBlossomEffect, EFFECT_0, SPELL_EFFECT_APPLY_AURA); + } }; void AddSC_boss_glubtok() { - new boss_glubtok(); - new spell_glubtok_blossom_targeting(); + RegisterDeadminesCreatureAI(boss_glubtok); + RegisterSpellScript(spell_glubtok_blossom_targeting); } diff --git a/src/server/scripts/EasternKingdoms/Deadmines/deadmines.h b/src/server/scripts/EasternKingdoms/Deadmines/deadmines.h index 76f74d168ad..0525e881bdb 100644 --- a/src/server/scripts/EasternKingdoms/Deadmines/deadmines.h +++ b/src/server/scripts/EasternKingdoms/Deadmines/deadmines.h @@ -546,4 +546,7 @@ AI* GetDeadminesAI(GameObject* go) return GetInstanceAI(go, DMScriptName); } +#define RegisterDeadminesCreatureAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetDeadminesAI) + +// DEADMINES_H_ #endif