feat(Scripts): Implement generic script loader and registry macros (#8976)
* cherry-pick commit (https://github.com/TrinityCore/TrinityCore/commit/fb87ac8e8da3d215d4988b8c2fa25d7a98cf9ee0) * cherry-pick commit (https://github.com/TrinityCore/TrinityCore/commit/7d4fbf706ae19481468901ccd65c497fcabe56bf#diff-ea1c86c26019127a4e99686cd9029f9ec3e8193f2761b262c2475668edc06764) * cherry-pick commit (https://github.com/TrinityCore/TrinityCore/commit/75a6a7a0ad48874e75dd71f766dad3707341bb32#diff-ea1c86c26019127a4e99686cd9029f9ec3e8193f2761b262c2475668edc06764) Co-Authored-By: Treeston <14020072+Treeston@users.noreply.github.com> Co-Authored-By: Shauren <shauren.trinity@gmail.com> Co-authored-by: Treeston <14020072+Treeston@users.noreply.github.com> Co-authored-by: Shauren <shauren.trinity@gmail.com>
This commit is contained in:
@@ -31,6 +31,8 @@
|
|||||||
#include "PetDefines.h"
|
#include "PetDefines.h"
|
||||||
#include "QuestDef.h"
|
#include "QuestDef.h"
|
||||||
#include "SharedDefines.h"
|
#include "SharedDefines.h"
|
||||||
|
#include "Tuples.h"
|
||||||
|
#include "Types.h"
|
||||||
#include "Weather.h"
|
#include "Weather.h"
|
||||||
#include "World.h"
|
#include "World.h"
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
@@ -1964,6 +1966,85 @@ private:
|
|||||||
ScriptLoaderCallbackType _script_loader_callback;
|
ScriptLoaderCallbackType _script_loader_callback;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
namespace Acore::SpellScripts
|
||||||
|
{
|
||||||
|
template<typename T>
|
||||||
|
using is_SpellScript = std::is_base_of<SpellScript, T>;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
using is_AuraScript = std::is_base_of<AuraScript, T>;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... Ts>
|
||||||
|
class GenericSpellAndAuraScriptLoader : public SpellScriptLoader
|
||||||
|
{
|
||||||
|
using SpellScriptType = typename Acore::find_type_if_t<Acore::SpellScripts::is_SpellScript, Ts...>;
|
||||||
|
using AuraScriptType = typename Acore::find_type_if_t<Acore::SpellScripts::is_AuraScript, Ts...>;
|
||||||
|
using ArgsType = typename Acore::find_type_if_t<Acore::is_tuple, Ts...>;
|
||||||
|
|
||||||
|
public:
|
||||||
|
GenericSpellAndAuraScriptLoader(char const* name, ArgsType&& args) : SpellScriptLoader(name), _args(std::move(args)) { }
|
||||||
|
|
||||||
|
private:
|
||||||
|
SpellScript* GetSpellScript() const override
|
||||||
|
{
|
||||||
|
if constexpr (!std::is_same_v<SpellScriptType, Acore::find_type_end>)
|
||||||
|
{
|
||||||
|
return Acore::new_from_tuple<SpellScriptType>(_args);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AuraScript* GetAuraScript() const override
|
||||||
|
{
|
||||||
|
if constexpr (!std::is_same_v<AuraScriptType, Acore::find_type_end>)
|
||||||
|
{
|
||||||
|
return Acore::new_from_tuple<AuraScriptType>(_args);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ArgsType _args;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define RegisterSpellScriptWithArgs(spell_script, script_name, ...) new GenericSpellAndAuraScriptLoader<spell_script, decltype(std::make_tuple(__VA_ARGS__))>(script_name, std::make_tuple(__VA_ARGS__))
|
||||||
|
#define RegisterSpellScript(spell_script) RegisterSpellScriptWithArgs(spell_script, #spell_script)
|
||||||
|
#define RegisterSpellAndAuraScriptPairWithArgs(script_1, script_2, script_name, ...) new GenericSpellAndAuraScriptLoader<script_1, script_2, decltype(std::make_tuple(__VA_ARGS__))>(script_name, std::make_tuple(__VA_ARGS__))
|
||||||
|
#define RegisterSpellAndAuraScriptPair(script_1, script_2) RegisterSpellAndAuraScriptPairWithArgs(script_1, script_2, #script_1)
|
||||||
|
|
||||||
|
template <class AI>
|
||||||
|
class GenericCreatureScript : public CreatureScript
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
GenericCreatureScript(char const* name) : CreatureScript(name) { }
|
||||||
|
CreatureAI* GetAI(Creature* me) const override { return new AI(me); }
|
||||||
|
};
|
||||||
|
#define RegisterCreatureAI(ai_name) new GenericCreatureScript<ai_name>(#ai_name)
|
||||||
|
|
||||||
|
template <class AI, AI*(*AIFactory)(Creature*)>
|
||||||
|
class FactoryCreatureScript : public CreatureScript
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
FactoryCreatureScript(char const* name) : CreatureScript(name) { }
|
||||||
|
CreatureAI* GetAI(Creature* me) const override { return AIFactory(me); }
|
||||||
|
};
|
||||||
|
#define RegisterCreatureAIWithFactory(ai_name, factory_fn) new FactoryCreatureScript<ai_name, &factory_fn>(#ai_name)
|
||||||
|
|
||||||
|
template <class AI>
|
||||||
|
class GenericGameObjectScript : public GameObjectScript
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
GenericGameObjectScript(char const* name) : GameObjectScript(name) { }
|
||||||
|
GameObjectAI* GetAI(GameObject* go) const override { return new AI(go); }
|
||||||
|
};
|
||||||
|
#define RegisterGameObjectAI(ai_name) new GenericGameObjectScript<ai_name>(#ai_name)
|
||||||
|
|
||||||
#define sScriptMgr ScriptMgr::instance()
|
#define sScriptMgr ScriptMgr::instance()
|
||||||
|
|
||||||
template<class TScript>
|
template<class TScript>
|
||||||
|
|||||||
@@ -96,222 +96,212 @@ private:
|
|||||||
Creature const* _source;
|
Creature const* _source;
|
||||||
};
|
};
|
||||||
|
|
||||||
class boss_lord_marrowgar : public CreatureScript
|
struct boss_lord_marrowgar : public BossAI
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
boss_lord_marrowgar() : CreatureScript("boss_lord_marrowgar") { }
|
boss_lord_marrowgar(Creature* creature) : BossAI(creature, DATA_LORD_MARROWGAR)
|
||||||
|
|
||||||
struct boss_lord_marrowgarAI : public BossAI
|
|
||||||
{
|
{
|
||||||
boss_lord_marrowgarAI(Creature* creature) : BossAI(creature, DATA_LORD_MARROWGAR)
|
_introDone = false;
|
||||||
|
_boneSlice = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _introDone;
|
||||||
|
bool _boneSlice;
|
||||||
|
ObjectGuid _lastBoneSliceTargets[3];
|
||||||
|
|
||||||
|
void Reset() override
|
||||||
|
{
|
||||||
|
me->SetReactState(REACT_AGGRESSIVE);
|
||||||
|
_Reset();
|
||||||
|
events.ScheduleEvent(EVENT_ENABLE_BONE_SLICE, 10000);
|
||||||
|
events.ScheduleEvent(EVENT_SPELL_BONE_SPIKE_GRAVEYARD, urand(10000, 15000));
|
||||||
|
events.ScheduleEvent(EVENT_SPELL_COLDFLAME, 5000);
|
||||||
|
events.ScheduleEvent(EVENT_WARN_BONE_STORM, urand(45000, 50000));
|
||||||
|
events.ScheduleEvent(EVENT_ENRAGE, 600000);
|
||||||
|
|
||||||
|
_boneSlice = false;
|
||||||
|
|
||||||
|
for (uint8 i = 0; i < 3; ++i)
|
||||||
|
_lastBoneSliceTargets[i].Clear();
|
||||||
|
|
||||||
|
instance->SetData(DATA_BONED_ACHIEVEMENT, uint32(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
void EnterCombat(Unit* /*who*/) override
|
||||||
|
{
|
||||||
|
Talk(SAY_AGGRO);
|
||||||
|
me->setActive(true);
|
||||||
|
DoZoneInCombat();
|
||||||
|
instance->SetBossState(DATA_LORD_MARROWGAR, IN_PROGRESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpellHitTarget(Unit* target, const SpellInfo* spell) override
|
||||||
|
{
|
||||||
|
if (target && (spell->Id == 69055 || spell->Id == 70814)) // Bone Slice (Saber Lash)
|
||||||
|
for (uint8 i = 0; i < 3; ++i)
|
||||||
|
if (!_lastBoneSliceTargets[i])
|
||||||
|
{
|
||||||
|
_lastBoneSliceTargets[i] = target->GetGUID();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjectGuid GetGUID(int32 id) const override
|
||||||
|
{
|
||||||
|
if (id >= 0 && id <= 2)
|
||||||
|
return _lastBoneSliceTargets[id];
|
||||||
|
|
||||||
|
return ObjectGuid::Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateAI(uint32 diff) override
|
||||||
|
{
|
||||||
|
if (!UpdateVictim() || !CheckInRoom())
|
||||||
|
return;
|
||||||
|
|
||||||
|
events.Update(diff);
|
||||||
|
|
||||||
|
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch (events.ExecuteEvent())
|
||||||
{
|
{
|
||||||
_introDone = false;
|
case 0:
|
||||||
_boneSlice = false;
|
break;
|
||||||
|
case EVENT_ENABLE_BONE_SLICE:
|
||||||
|
_boneSlice = true;
|
||||||
|
break;
|
||||||
|
case EVENT_SPELL_BONE_SPIKE_GRAVEYARD:
|
||||||
|
{
|
||||||
|
bool a = me->HasAura(SPELL_BONE_STORM);
|
||||||
|
if (IsHeroic() || !a)
|
||||||
|
me->CastSpell(me, SPELL_BONE_SPIKE_GRAVEYARD, a);
|
||||||
|
events.RepeatEvent(urand(15000, 20000));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case EVENT_SPELL_COLDFLAME:
|
||||||
|
if (!me->HasAura(SPELL_BONE_STORM))
|
||||||
|
me->CastSpell((Unit*)nullptr, SPELL_COLDFLAME_NORMAL, false);
|
||||||
|
events.RepeatEvent(5000);
|
||||||
|
break;
|
||||||
|
case EVENT_SPELL_COLDFLAME_BONE_STORM:
|
||||||
|
me->CastSpell(me, SPELL_COLDFLAME_BONE_STORM, false);
|
||||||
|
break;
|
||||||
|
case EVENT_WARN_BONE_STORM:
|
||||||
|
_boneSlice = false;
|
||||||
|
Talk(EMOTE_BONE_STORM);
|
||||||
|
Talk(SAY_BONE_STORM);
|
||||||
|
me->FinishSpell(CURRENT_MELEE_SPELL, false);
|
||||||
|
me->CastSpell(me, SPELL_BONE_STORM, false);
|
||||||
|
me->SetReactState(REACT_PASSIVE); // to prevent chasing another target on UpdateVictim()
|
||||||
|
me->GetMotionMaster()->MoveIdle();
|
||||||
|
me->GetMotionMaster()->MovementExpired();
|
||||||
|
events.RepeatEvent(urand(90000, 95000));
|
||||||
|
events.ScheduleEvent(EVENT_BEGIN_BONE_STORM, 3050);
|
||||||
|
break;
|
||||||
|
case EVENT_BEGIN_BONE_STORM:
|
||||||
|
{
|
||||||
|
uint32 _boneStormDuration = RAID_MODE<uint32>(20000, 30000, 20000, 30000);
|
||||||
|
if (Aura* pStorm = me->GetAura(SPELL_BONE_STORM))
|
||||||
|
pStorm->SetDuration(int32(_boneStormDuration));
|
||||||
|
events.ScheduleEvent(EVENT_BONE_STORM_MOVE, 0);
|
||||||
|
events.ScheduleEvent(EVENT_END_BONE_STORM, _boneStormDuration + 1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case EVENT_BONE_STORM_MOVE:
|
||||||
|
{
|
||||||
|
if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == POINT_MOTION_TYPE)
|
||||||
|
{
|
||||||
|
events.RepeatEvent(1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
events.RepeatEvent(5000);
|
||||||
|
Unit* unit = SelectTarget(SELECT_TARGET_RANDOM, 0, BoneStormMoveTargetSelector(me));
|
||||||
|
if (!unit)
|
||||||
|
{
|
||||||
|
if ((unit = SelectTarget(SELECT_TARGET_TOPAGGRO, 0, 175.0f, true)))
|
||||||
|
if (unit->GetPositionX() > -337.0f)
|
||||||
|
{
|
||||||
|
EnterEvadeMode();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (unit)
|
||||||
|
me->GetMotionMaster()->MoveCharge(unit->GetPositionX(), unit->GetPositionY(), unit->GetPositionZ(), 25.0f, 1337);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case EVENT_END_BONE_STORM:
|
||||||
|
me->StopMoving();
|
||||||
|
me->GetMotionMaster()->MovementExpired();
|
||||||
|
me->SetReactState(REACT_AGGRESSIVE);
|
||||||
|
DoStartMovement(me->GetVictim());
|
||||||
|
events.CancelEvent(EVENT_BONE_STORM_MOVE);
|
||||||
|
events.ScheduleEvent(EVENT_ENABLE_BONE_SLICE, 10000);
|
||||||
|
if (!IsHeroic())
|
||||||
|
events.RescheduleEvent(EVENT_SPELL_BONE_SPIKE_GRAVEYARD, urand(15000, 20000));
|
||||||
|
break;
|
||||||
|
case EVENT_ENRAGE:
|
||||||
|
me->CastSpell(me, SPELL_BERSERK, true);
|
||||||
|
Talk(SAY_BERSERK);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _introDone;
|
if (me->HasAura(SPELL_BONE_STORM))
|
||||||
bool _boneSlice;
|
return;
|
||||||
ObjectGuid _lastBoneSliceTargets[3];
|
|
||||||
|
|
||||||
void Reset() override
|
if (_boneSlice && !me->GetCurrentSpell(CURRENT_MELEE_SPELL))
|
||||||
|
DoCastVictim(SPELL_BONE_SLICE);
|
||||||
|
|
||||||
|
if (_boneSlice && me->isAttackReady() && me->GetVictim() && !me->HasUnitState(UNIT_STATE_CASTING) && me->IsWithinMeleeRange(me->GetVictim()))
|
||||||
{
|
{
|
||||||
me->SetReactState(REACT_AGGRESSIVE);
|
|
||||||
_Reset();
|
|
||||||
events.ScheduleEvent(EVENT_ENABLE_BONE_SLICE, 10000);
|
|
||||||
events.ScheduleEvent(EVENT_SPELL_BONE_SPIKE_GRAVEYARD, urand(10000, 15000));
|
|
||||||
events.ScheduleEvent(EVENT_SPELL_COLDFLAME, 5000);
|
|
||||||
events.ScheduleEvent(EVENT_WARN_BONE_STORM, urand(45000, 50000));
|
|
||||||
events.ScheduleEvent(EVENT_ENRAGE, 600000);
|
|
||||||
|
|
||||||
_boneSlice = false;
|
|
||||||
|
|
||||||
for (uint8 i = 0; i < 3; ++i)
|
for (uint8 i = 0; i < 3; ++i)
|
||||||
_lastBoneSliceTargets[i].Clear();
|
_lastBoneSliceTargets[i].Clear();
|
||||||
|
|
||||||
instance->SetData(DATA_BONED_ACHIEVEMENT, uint32(true));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EnterCombat(Unit* /*who*/) override
|
DoMeleeAttackIfReady();
|
||||||
{
|
}
|
||||||
Talk(SAY_AGGRO);
|
|
||||||
me->setActive(true);
|
|
||||||
DoZoneInCombat();
|
|
||||||
instance->SetBossState(DATA_LORD_MARROWGAR, IN_PROGRESS);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SpellHitTarget(Unit* target, const SpellInfo* spell) override
|
void MovementInform(uint32 type, uint32 id) override
|
||||||
{
|
|
||||||
if (target && (spell->Id == 69055 || spell->Id == 70814)) // Bone Slice (Saber Lash)
|
|
||||||
for (uint8 i = 0; i < 3; ++i)
|
|
||||||
if (!_lastBoneSliceTargets[i])
|
|
||||||
{
|
|
||||||
_lastBoneSliceTargets[i] = target->GetGUID();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ObjectGuid GetGUID(int32 id) const override
|
|
||||||
{
|
|
||||||
if (id >= 0 && id <= 2)
|
|
||||||
return _lastBoneSliceTargets[id];
|
|
||||||
|
|
||||||
return ObjectGuid::Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
void UpdateAI(uint32 diff) override
|
|
||||||
{
|
|
||||||
if (!UpdateVictim() || !CheckInRoom())
|
|
||||||
return;
|
|
||||||
|
|
||||||
events.Update(diff);
|
|
||||||
|
|
||||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
|
||||||
return;
|
|
||||||
|
|
||||||
switch (events.ExecuteEvent())
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
break;
|
|
||||||
case EVENT_ENABLE_BONE_SLICE:
|
|
||||||
_boneSlice = true;
|
|
||||||
break;
|
|
||||||
case EVENT_SPELL_BONE_SPIKE_GRAVEYARD:
|
|
||||||
{
|
|
||||||
bool a = me->HasAura(SPELL_BONE_STORM);
|
|
||||||
if (IsHeroic() || !a)
|
|
||||||
me->CastSpell(me, SPELL_BONE_SPIKE_GRAVEYARD, a);
|
|
||||||
events.RepeatEvent(urand(15000, 20000));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case EVENT_SPELL_COLDFLAME:
|
|
||||||
if (!me->HasAura(SPELL_BONE_STORM))
|
|
||||||
me->CastSpell((Unit*)nullptr, SPELL_COLDFLAME_NORMAL, false);
|
|
||||||
events.RepeatEvent(5000);
|
|
||||||
break;
|
|
||||||
case EVENT_SPELL_COLDFLAME_BONE_STORM:
|
|
||||||
me->CastSpell(me, SPELL_COLDFLAME_BONE_STORM, false);
|
|
||||||
break;
|
|
||||||
case EVENT_WARN_BONE_STORM:
|
|
||||||
_boneSlice = false;
|
|
||||||
Talk(EMOTE_BONE_STORM);
|
|
||||||
Talk(SAY_BONE_STORM);
|
|
||||||
me->FinishSpell(CURRENT_MELEE_SPELL, false);
|
|
||||||
me->CastSpell(me, SPELL_BONE_STORM, false);
|
|
||||||
me->SetReactState(REACT_PASSIVE); // to prevent chasing another target on UpdateVictim()
|
|
||||||
me->GetMotionMaster()->MoveIdle();
|
|
||||||
me->GetMotionMaster()->MovementExpired();
|
|
||||||
events.RepeatEvent(urand(90000, 95000));
|
|
||||||
events.ScheduleEvent(EVENT_BEGIN_BONE_STORM, 3050);
|
|
||||||
break;
|
|
||||||
case EVENT_BEGIN_BONE_STORM:
|
|
||||||
{
|
|
||||||
uint32 _boneStormDuration = RAID_MODE<uint32>(20000, 30000, 20000, 30000);
|
|
||||||
if (Aura* pStorm = me->GetAura(SPELL_BONE_STORM))
|
|
||||||
pStorm->SetDuration(int32(_boneStormDuration));
|
|
||||||
events.ScheduleEvent(EVENT_BONE_STORM_MOVE, 0);
|
|
||||||
events.ScheduleEvent(EVENT_END_BONE_STORM, _boneStormDuration + 1);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case EVENT_BONE_STORM_MOVE:
|
|
||||||
{
|
|
||||||
if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == POINT_MOTION_TYPE)
|
|
||||||
{
|
|
||||||
events.RepeatEvent(1);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
events.RepeatEvent(5000);
|
|
||||||
Unit* unit = SelectTarget(SELECT_TARGET_RANDOM, 0, BoneStormMoveTargetSelector(me));
|
|
||||||
if (!unit)
|
|
||||||
{
|
|
||||||
if ((unit = SelectTarget(SELECT_TARGET_TOPAGGRO, 0, 175.0f, true)))
|
|
||||||
if (unit->GetPositionX() > -337.0f)
|
|
||||||
{
|
|
||||||
EnterEvadeMode();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (unit)
|
|
||||||
me->GetMotionMaster()->MoveCharge(unit->GetPositionX(), unit->GetPositionY(), unit->GetPositionZ(), 25.0f, 1337);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case EVENT_END_BONE_STORM:
|
|
||||||
me->StopMoving();
|
|
||||||
me->GetMotionMaster()->MovementExpired();
|
|
||||||
me->SetReactState(REACT_AGGRESSIVE);
|
|
||||||
DoStartMovement(me->GetVictim());
|
|
||||||
events.CancelEvent(EVENT_BONE_STORM_MOVE);
|
|
||||||
events.ScheduleEvent(EVENT_ENABLE_BONE_SLICE, 10000);
|
|
||||||
if (!IsHeroic())
|
|
||||||
events.RescheduleEvent(EVENT_SPELL_BONE_SPIKE_GRAVEYARD, urand(15000, 20000));
|
|
||||||
break;
|
|
||||||
case EVENT_ENRAGE:
|
|
||||||
me->CastSpell(me, SPELL_BERSERK, true);
|
|
||||||
Talk(SAY_BERSERK);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (me->HasAura(SPELL_BONE_STORM))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (_boneSlice && !me->GetCurrentSpell(CURRENT_MELEE_SPELL))
|
|
||||||
DoCastVictim(SPELL_BONE_SLICE);
|
|
||||||
|
|
||||||
if (_boneSlice && me->isAttackReady() && me->GetVictim() && !me->HasUnitState(UNIT_STATE_CASTING) && me->IsWithinMeleeRange(me->GetVictim()))
|
|
||||||
{
|
|
||||||
for (uint8 i = 0; i < 3; ++i)
|
|
||||||
_lastBoneSliceTargets[i].Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
DoMeleeAttackIfReady();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MovementInform(uint32 type, uint32 id) override
|
|
||||||
{
|
|
||||||
if (type != POINT_MOTION_TYPE || id != 1337)
|
|
||||||
return;
|
|
||||||
|
|
||||||
events.ScheduleEvent(EVENT_SPELL_COLDFLAME_BONE_STORM, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void JustDied(Unit* /*killer*/) override
|
|
||||||
{
|
|
||||||
Talk(SAY_DEATH);
|
|
||||||
_JustDied();
|
|
||||||
}
|
|
||||||
|
|
||||||
void JustReachedHome() override
|
|
||||||
{
|
|
||||||
_JustReachedHome();
|
|
||||||
instance->SetBossState(DATA_LORD_MARROWGAR, FAIL);
|
|
||||||
}
|
|
||||||
|
|
||||||
void KilledUnit(Unit* victim) override
|
|
||||||
{
|
|
||||||
if (victim->GetTypeId() == TYPEID_PLAYER)
|
|
||||||
Talk(SAY_KILL);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MoveInLineOfSight(Unit* who) override
|
|
||||||
{
|
|
||||||
if (!_introDone && me->IsAlive() && who->GetTypeId() == TYPEID_PLAYER && me->GetExactDist2dSq(who) <= 10000.0f) // 100*100, moveinlineofsight limited to 60yd anyway
|
|
||||||
{
|
|
||||||
Talk(SAY_ENTER_ZONE);
|
|
||||||
_introDone = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
BossAI::MoveInLineOfSight(who);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CanAIAttack(Unit const* target) const override
|
|
||||||
{
|
|
||||||
return target->GetPositionX() < -337.0f; // main gate
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
CreatureAI* GetAI(Creature* creature) const override
|
|
||||||
{
|
{
|
||||||
return GetIcecrownCitadelAI<boss_lord_marrowgarAI>(creature);
|
if (type != POINT_MOTION_TYPE || id != 1337)
|
||||||
|
return;
|
||||||
|
|
||||||
|
events.ScheduleEvent(EVENT_SPELL_COLDFLAME_BONE_STORM, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void JustDied(Unit* /*killer*/) override
|
||||||
|
{
|
||||||
|
Talk(SAY_DEATH);
|
||||||
|
_JustDied();
|
||||||
|
}
|
||||||
|
|
||||||
|
void JustReachedHome() override
|
||||||
|
{
|
||||||
|
_JustReachedHome();
|
||||||
|
instance->SetBossState(DATA_LORD_MARROWGAR, FAIL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void KilledUnit(Unit* victim) override
|
||||||
|
{
|
||||||
|
if (victim->GetTypeId() == TYPEID_PLAYER)
|
||||||
|
Talk(SAY_KILL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MoveInLineOfSight(Unit* who) override
|
||||||
|
{
|
||||||
|
if (!_introDone && me->IsAlive() && who->GetTypeId() == TYPEID_PLAYER && me->GetExactDist2dSq(who) <= 10000.0f) // 100*100, moveinlineofsight limited to 60yd anyway
|
||||||
|
{
|
||||||
|
Talk(SAY_ENTER_ZONE);
|
||||||
|
_introDone = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
BossAI::MoveInLineOfSight(who);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CanAIAttack(Unit const* target) const override
|
||||||
|
{
|
||||||
|
return target->GetPositionX() < -337.0f; // main gate
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -704,7 +694,7 @@ public:
|
|||||||
|
|
||||||
void AddSC_boss_lord_marrowgar()
|
void AddSC_boss_lord_marrowgar()
|
||||||
{
|
{
|
||||||
new boss_lord_marrowgar();
|
RegisterIcecrownCitadelCreatureAI(boss_lord_marrowgar);
|
||||||
new npc_coldflame();
|
new npc_coldflame();
|
||||||
new npc_bone_spike();
|
new npc_bone_spike();
|
||||||
new spell_marrowgar_coldflame();
|
new spell_marrowgar_coldflame();
|
||||||
|
|||||||
@@ -626,4 +626,6 @@ inline AI* GetIcecrownCitadelAI(T* obj)
|
|||||||
return GetInstanceAI<AI>(obj, ICCScriptName);
|
return GetInstanceAI<AI>(obj, ICCScriptName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define RegisterIcecrownCitadelCreatureAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetIcecrownCitadelAI)
|
||||||
|
|
||||||
#endif // ICECROWN_CITADEL_H_
|
#endif // ICECROWN_CITADEL_H_
|
||||||
|
|||||||
Reference in New Issue
Block a user