refactor(Scripts/Pet): Death Knight use creature register macros (#22399)

This commit is contained in:
Jelle Meeus
2025-06-30 17:55:18 +02:00
committed by GitHub
parent fd262c3ab1
commit dbb995cace

View File

@@ -49,292 +49,228 @@ enum DeathKnightSpells
SPELL_GHOUL_FRENZY = 62218,
};
class npc_pet_dk_ebon_gargoyle : public CreatureScript
struct npc_pet_dk_ebon_gargoyle : ScriptedAI
{
public:
npc_pet_dk_ebon_gargoyle() : CreatureScript("npc_pet_dk_ebon_gargoyle") { }
struct npc_pet_dk_ebon_gargoyleAI : ScriptedAI
npc_pet_dk_ebon_gargoyle(Creature* creature) : ScriptedAI(creature)
{
npc_pet_dk_ebon_gargoyleAI(Creature* creature) : ScriptedAI(creature)
{
_despawnTimer = 36000; // 30 secs + 4 fly out + 2 initial attack timer
_despawning = false;
_initialSelection = true;
_targetGUID.Clear();
}
_despawnTimer = 36000; // 30 secs + 4 fly out + 2 initial attack timer
_despawning = false;
_initialSelection = true;
_targetGUID.Clear();
}
void MovementInform(uint32 type, uint32 point) override
void MovementInform(uint32 type, uint32 point) override
{
if (type == POINT_MOTION_TYPE && point == 1)
{
if (type == POINT_MOTION_TYPE && point == 1)
me->SetCanFly(false);
me->SetDisableGravity(false);
}
}
void InitializeAI() override
{
ScriptedAI::InitializeAI();
Unit* owner = me->GetOwner();
if (!owner)
return;
// Xinef: Night of the Dead avoidance
if (Aura* aur = me->GetAura(SPELL_DK_NIGHT_OF_THE_DEAD))
if (AuraEffect* aurEff = owner->GetAuraEffect(SPELL_AURA_ADD_FLAT_MODIFIER, SPELLFAMILY_DEATHKNIGHT, 2718, 0))
if (aur->GetEffect(0))
aur->GetEffect(0)->SetAmount(-aurEff->GetSpellInfo()->Effects[EFFECT_2].CalcValue());
me->SetCanFly(true);
me->SetDisableGravity(true);
float tz = me->GetMapHeight(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), true, MAX_FALL_DISTANCE);
me->GetMotionMaster()->MoveCharge(me->GetPositionX(), me->GetPositionY(), tz, 7.0f, 1);
me->AddUnitState(UNIT_STATE_NO_ENVIRONMENT_UPD);
_selectionTimer = 2000;
_initialCastTimer = 0;
}
void MySelectNextTarget()
{
Unit* owner = me->GetOwner();
if (owner && owner->IsPlayer() && (!me->GetVictim() || me->GetVictim()->IsImmunedToSpell(sSpellMgr->GetSpellInfo(51963)) || !me->IsValidAttackTarget(me->GetVictim()) || !owner->CanSeeOrDetect(me->GetVictim())))
{
Unit* selection = owner->ToPlayer()->GetSelectedUnit();
if (selection && selection != me->GetVictim() && me->IsValidAttackTarget(selection))
{
me->SetCanFly(false);
me->SetDisableGravity(false);
me->GetMotionMaster()->Clear(false);
SetGazeOn(selection);
}
else if (!me->GetVictim() || !owner->CanSeeOrDetect(me->GetVictim()))
{
me->CombatStop(true);
me->GetMotionMaster()->Clear(false);
me->GetMotionMaster()->MoveFollow(owner, PET_FOLLOW_DIST, 0.0f);
RemoveTargetAura();
}
}
}
void InitializeAI() override
void AttackStart(Unit* who) override
{
RemoveTargetAura();
_targetGUID = who->GetGUID();
me->AddAura(SPELL_DK_SUMMON_GARGOYLE_1, who);
ScriptedAI::AttackStart(who);
}
void RemoveTargetAura()
{
if (Unit* target = ObjectAccessor::GetUnit(*me, _targetGUID))
target->RemoveAura(SPELL_DK_SUMMON_GARGOYLE_1, me->GetGUID());
}
void Reset() override
{
_selectionTimer = 0;
me->SetReactState(REACT_PASSIVE);
MySelectNextTarget();
}
// Fly away when dismissed
void FlyAway()
{
RemoveTargetAura();
// Stop Fighting
me->CombatStop(true);
me->ApplyModFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE, true);
// Sanctuary
me->CastSpell(me, SPELL_DK_SANCTUARY, true);
me->SetReactState(REACT_PASSIVE);
me->SetSpeed(MOVE_FLIGHT, 1.0f, true);
me->SetSpeed(MOVE_RUN, 1.0f, true);
float x = me->GetPositionX() + 20 * cos(me->GetOrientation());
float y = me->GetPositionY() + 20 * std::sin(me->GetOrientation());
float z = me->GetPositionZ() + 40;
me->DisableSpline();
me->GetMotionMaster()->Clear(false);
me->GetMotionMaster()->MoveCharge(x, y, z, 7.0f, 1);
me->SetCanFly(true);
me->SetDisableGravity(true);
_despawning = true;
}
void UpdateAI(uint32 diff) override
{
if (_initialSelection)
{
ScriptedAI::InitializeAI();
Unit* owner = me->GetOwner();
if (!owner)
_initialSelection = false;
// Find victim of Summon Gargoyle spell
std::list<Unit*> targets;
Acore::AnyUnfriendlyUnitInObjectRangeCheck u_check(me, me, 50.0f);
Acore::UnitListSearcher<Acore::AnyUnfriendlyUnitInObjectRangeCheck> searcher(me, targets, u_check);
Cell::VisitAllObjects(me, searcher, 50.0f);
for (auto const& target : targets)
if (target->GetAura(SPELL_DK_SUMMON_GARGOYLE_1, me->GetOwnerGUID()))
{
target->RemoveAura(SPELL_DK_SUMMON_GARGOYLE_1, me->GetOwnerGUID());
SetGazeOn(target);
_targetGUID = target->GetGUID();
break;
}
}
if (_despawnTimer > 4000)
{
_despawnTimer -= diff;
if (!UpdateVictimWithGaze())
{
MySelectNextTarget();
return;
// Xinef: Night of the Dead avoidance
if (Aura* aur = me->GetAura(SPELL_DK_NIGHT_OF_THE_DEAD))
if (AuraEffect* aurEff = owner->GetAuraEffect(SPELL_AURA_ADD_FLAT_MODIFIER, SPELLFAMILY_DEATHKNIGHT, 2718, 0))
{
if (aur->GetEffect(0))
{
aur->GetEffect(0)->SetAmount(-aurEff->GetSpellInfo()->Effects[EFFECT_2].CalcValue());
}
}
me->SetCanFly(true);
me->SetDisableGravity(true);
float tz = me->GetMapHeight(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), true, MAX_FALL_DISTANCE);
me->GetMotionMaster()->MoveCharge(me->GetPositionX(), me->GetPositionY(), tz, 7.0f, 1);
me->AddUnitState(UNIT_STATE_NO_ENVIRONMENT_UPD);
_selectionTimer = 2000;
_initialCastTimer = 0;
}
void MySelectNextTarget()
{
Unit* owner = me->GetOwner();
if (owner && owner->IsPlayer() && (!me->GetVictim() || me->GetVictim()->IsImmunedToSpell(sSpellMgr->GetSpellInfo(51963)) || !me->IsValidAttackTarget(me->GetVictim()) || !owner->CanSeeOrDetect(me->GetVictim())))
{
Unit* selection = owner->ToPlayer()->GetSelectedUnit();
if (selection && selection != me->GetVictim() && me->IsValidAttackTarget(selection))
{
me->GetMotionMaster()->Clear(false);
SetGazeOn(selection);
}
else if (!me->GetVictim() || !owner->CanSeeOrDetect(me->GetVictim()))
{
me->CombatStop(true);
me->GetMotionMaster()->Clear(false);
me->GetMotionMaster()->MoveFollow(owner, PET_FOLLOW_DIST, 0.0f);
RemoveTargetAura();
}
}
}
void AttackStart(Unit* who) override
{
RemoveTargetAura();
_targetGUID = who->GetGUID();
me->AddAura(SPELL_DK_SUMMON_GARGOYLE_1, who);
ScriptedAI::AttackStart(who);
}
void RemoveTargetAura()
{
if (Unit* target = ObjectAccessor::GetUnit(*me, _targetGUID))
target->RemoveAura(SPELL_DK_SUMMON_GARGOYLE_1, me->GetGUID());
}
void Reset() override
{
_selectionTimer = 0;
me->SetReactState(REACT_PASSIVE);
MySelectNextTarget();
}
// Fly away when dismissed
void FlyAway()
{
RemoveTargetAura();
// Stop Fighting
me->CombatStop(true);
me->ApplyModFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE, true);
// Sanctuary
me->CastSpell(me, SPELL_DK_SANCTUARY, true);
me->SetReactState(REACT_PASSIVE);
me->SetSpeed(MOVE_FLIGHT, 1.0f, true);
me->SetSpeed(MOVE_RUN, 1.0f, true);
float x = me->GetPositionX() + 20 * cos(me->GetOrientation());
float y = me->GetPositionY() + 20 * std::sin(me->GetOrientation());
float z = me->GetPositionZ() + 40;
me->DisableSpline();
me->GetMotionMaster()->Clear(false);
me->GetMotionMaster()->MoveCharge(x, y, z, 7.0f, 1);
me->SetCanFly(true);
me->SetDisableGravity(true);
_despawning = true;
}
void UpdateAI(uint32 diff) override
{
if (_initialSelection)
_initialCastTimer += diff;
_selectionTimer += diff;
if (_selectionTimer >= 1000)
{
_initialSelection = false;
// Find victim of Summon Gargoyle spell
std::list<Unit*> targets;
Acore::AnyUnfriendlyUnitInObjectRangeCheck u_check(me, me, 50.0f);
Acore::UnitListSearcher<Acore::AnyUnfriendlyUnitInObjectRangeCheck> searcher(me, targets, u_check);
Cell::VisitAllObjects(me, searcher, 50.0f);
for (std::list<Unit*>::const_iterator iter = targets.begin(); iter != targets.end(); ++iter)
if ((*iter)->GetAura(SPELL_DK_SUMMON_GARGOYLE_1, me->GetOwnerGUID()))
{
(*iter)->RemoveAura(SPELL_DK_SUMMON_GARGOYLE_1, me->GetOwnerGUID());
SetGazeOn(*iter);
_targetGUID = (*iter)->GetGUID();
break;
}
MySelectNextTarget();
_selectionTimer = 0;
}
if (_despawnTimer > 4000)
{
if (_initialCastTimer >= 2000 && !me->HasUnitState(UNIT_STATE_CASTING | UNIT_STATE_LOST_CONTROL) && me->GetMotionMaster()->GetMotionSlotType(MOTION_SLOT_CONTROLLED) == NULL_MOTION_TYPE)
me->CastSpell(me->GetVictim(), 51963, false);
}
else
{
if (!_despawning)
FlyAway();
if (_despawnTimer > diff)
_despawnTimer -= diff;
if (!UpdateVictimWithGaze())
{
MySelectNextTarget();
return;
}
_initialCastTimer += diff;
_selectionTimer += diff;
if (_selectionTimer >= 1000)
{
MySelectNextTarget();
_selectionTimer = 0;
}
if (_initialCastTimer >= 2000 && !me->HasUnitState(UNIT_STATE_CASTING | UNIT_STATE_LOST_CONTROL) && me->GetMotionMaster()->GetMotionSlotType(MOTION_SLOT_CONTROLLED) == NULL_MOTION_TYPE)
me->CastSpell(me->GetVictim(), 51963, false);
}
else
{
if (!_despawning)
FlyAway();
if (_despawnTimer > diff)
_despawnTimer -= diff;
else
me->DespawnOrUnsummon();
}
me->DespawnOrUnsummon();
}
}
private:
ObjectGuid _targetGUID;
uint32 _despawnTimer;
uint32 _selectionTimer;
uint32 _initialCastTimer;
bool _despawning;
bool _initialSelection;
};
private:
ObjectGuid _targetGUID;
uint32 _despawnTimer;
uint32 _selectionTimer;
uint32 _initialCastTimer;
bool _despawning;
bool _initialSelection;
};
CreatureAI* GetAI(Creature* creature) const override
struct npc_pet_dk_ghoul : public CombatAI
{
npc_pet_dk_ghoul(Creature* c) : CombatAI(c) { }
void JustDied(Unit* /*who*/) override
{
return new npc_pet_dk_ebon_gargoyleAI(creature);
if (me->IsGuardian() || me->IsSummon())
me->ToTempSummon()->UnSummon();
}
};
class npc_pet_dk_ghoul : public CreatureScript
struct npc_pet_dk_risen_ally : public PossessedAI
{
public:
npc_pet_dk_ghoul() : CreatureScript("npc_pet_dk_ghoul") { }
npc_pet_dk_risen_ally(Creature* c) : PossessedAI(c) { }
struct npc_pet_dk_ghoulAI : public CombatAI
void OnCharmed(bool apply) override
{
npc_pet_dk_ghoulAI(Creature* c) : CombatAI(c) { }
void JustDied(Unit* /*who*/) override
{
if (me->IsGuardian() || me->IsSummon())
me->ToTempSummon()->UnSummon();
}
};
CreatureAI* GetAI(Creature* pCreature) const override
{
return new npc_pet_dk_ghoulAI (pCreature);
}
};
class npc_pet_dk_risen_ally : public CreatureScript
{
public:
npc_pet_dk_risen_ally() : CreatureScript("npc_pet_dk_risen_ally") { }
struct npc_pet_dk_risen_allyAI : public PossessedAI
{
npc_pet_dk_risen_allyAI(Creature* c) : PossessedAI(c) { }
void OnCharmed(bool apply) override
{
if (!apply)
{
if (Unit* owner = me->GetCharmerOrOwner())
if (!apply)
if (Unit* owner = me->GetCharmerOrOwner())
if (Player* player = owner->ToPlayer())
{
if (Player* player = owner->ToPlayer())
{
player->RemoveAurasDueToSpell(SPELL_DK_RAISE_ALLY); // Remove Raise Ally aura
player->RemoveAurasDueToSpell(SPELL_GHOUL_FRENZY); // Remove Frenzy aura
//player->ClearResurrectRequestData();
}
player->RemoveAurasDueToSpell(SPELL_DK_RAISE_ALLY); // Remove Raise Ally aura
player->RemoveAurasDueToSpell(SPELL_GHOUL_FRENZY); // Remove Frenzy aura
//player->ClearResurrectRequestData();
}
}
}
};
CreatureAI* GetAI(Creature* pCreature) const override
{
return new npc_pet_dk_risen_allyAI (pCreature);
}
};
class npc_pet_dk_army_of_the_dead : public CreatureScript
struct npc_pet_dk_army_of_the_dead : public CombatAI
{
public:
npc_pet_dk_army_of_the_dead() : CreatureScript("npc_pet_dk_army_of_the_dead") { }
npc_pet_dk_army_of_the_dead(Creature* creature) : CombatAI(creature) { }
struct npc_pet_dk_army_of_the_deadAI : public CombatAI
void InitializeAI() override
{
npc_pet_dk_army_of_the_deadAI(Creature* creature) : CombatAI(creature) { }
void InitializeAI() override
{
CombatAI::InitializeAI();
((Minion*)me)->SetFollowAngle(rand_norm() * 2 * M_PI);
}
};
CreatureAI* GetAI(Creature* creature) const override
{
return new npc_pet_dk_army_of_the_deadAI (creature);
CombatAI::InitializeAI();
((Minion*)me)->SetFollowAngle(rand_norm() * 2 * M_PI);
}
};
class npc_pet_dk_dancing_rune_weapon : public CreatureScript
struct npc_pet_dk_dancing_rune_weapon : public NullCreatureAI
{
public:
npc_pet_dk_dancing_rune_weapon() : CreatureScript("npc_pet_dk_dancing_rune_weapon") { }
npc_pet_dk_dancing_rune_weapon(Creature* creature) : NullCreatureAI(creature) { }
struct npc_pet_dk_dancing_rune_weaponAI : public NullCreatureAI
void InitializeAI() override
{
npc_pet_dk_dancing_rune_weaponAI(Creature* creature) : NullCreatureAI(creature) { }
me->AddAura(SPELL_HUNTER_PET_SCALING_04, me);
if (Unit* owner = me->GetOwner())
me->GetMotionMaster()->MoveFollow(owner, 0.01f, me->GetFollowAngle(), MOTION_SLOT_CONTROLLED);
void InitializeAI() override
{
// Xinef: Hit / Expertise scaling
me->AddAura(61017, me);
if (Unit* owner = me->GetOwner())
me->GetMotionMaster()->MoveFollow(owner, 0.01f, me->GetFollowAngle(), MOTION_SLOT_CONTROLLED);
NullCreatureAI::InitializeAI();
}
};
CreatureAI* GetAI(Creature* creature) const override
{
return new npc_pet_dk_dancing_rune_weaponAI (creature);
NullCreatureAI::InitializeAI();
}
};
@@ -346,12 +282,8 @@ class spell_pet_dk_gargoyle_strike : public SpellScript
{
int32 damage = 60;
if (Unit* caster = GetCaster())
{
if (caster->GetLevel() >= 60)
{
damage += (caster->GetLevel() - 60) * 4;
}
}
SetEffectValue(damage);
}
@@ -364,10 +296,10 @@ class spell_pet_dk_gargoyle_strike : public SpellScript
void AddSC_deathknight_pet_scripts()
{
new npc_pet_dk_ebon_gargoyle();
new npc_pet_dk_ghoul();
new npc_pet_dk_risen_ally();
new npc_pet_dk_army_of_the_dead();
new npc_pet_dk_dancing_rune_weapon();
RegisterCreatureAI(npc_pet_dk_ebon_gargoyle);
RegisterCreatureAI(npc_pet_dk_ghoul);
RegisterCreatureAI(npc_pet_dk_risen_ally);
RegisterCreatureAI(npc_pet_dk_army_of_the_dead);
RegisterCreatureAI(npc_pet_dk_dancing_rune_weapon);
RegisterSpellScript(spell_pet_dk_gargoyle_strike);
}