mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2025-11-29 17:38:24 +08:00
refactor(Scripts/MagisterTerrace): Clean up Vexallus instance script … (#21303)
This commit is contained in:
@@ -0,0 +1,2 @@
|
|||||||
|
--
|
||||||
|
UPDATE `creature_template` SET `ScriptName` = '' WHERE (`entry` = 24745);
|
||||||
@@ -41,72 +41,61 @@ enum Spells
|
|||||||
SPELL_SUMMON_PURE_ENERGY_H2 = 46159 // Heroic mode summon 2
|
SPELL_SUMMON_PURE_ENERGY_H2 = 46159 // Heroic mode summon 2
|
||||||
};
|
};
|
||||||
|
|
||||||
struct npc_pure_energy : public ScriptedAI
|
|
||||||
{
|
|
||||||
explicit npc_pure_energy(Creature* creature) : ScriptedAI(creature) {}
|
|
||||||
|
|
||||||
// Initialize on summon
|
|
||||||
void IsSummonedBy(WorldObject* summoner) override
|
|
||||||
{
|
|
||||||
if (!summoner)
|
|
||||||
return;
|
|
||||||
if (Creature* vexallus = summoner ? summoner->ToCreature() : nullptr)
|
|
||||||
{
|
|
||||||
if (Unit* target = vexallus->AI()->SelectTarget(SelectTargetMethod::Random, 0))
|
|
||||||
me->CastSpell(target, SPELL_ENERGY_FEEDBACK_CHANNEL, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void DamageTaken(Unit* attacker, uint32& damage, DamageEffectType, SpellSchoolMask) override
|
|
||||||
{
|
|
||||||
if (!attacker || !attacker->IsPlayer() || attacker->GetVictim() != me)
|
|
||||||
damage = 0; // Only take damage from players targeting this add
|
|
||||||
}
|
|
||||||
|
|
||||||
void UpdateAI(uint32 /*diff*/) override
|
|
||||||
{
|
|
||||||
if (!UpdateVictim())
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AttackStart(Unit* victim) override
|
|
||||||
{
|
|
||||||
if (victim)
|
|
||||||
{
|
|
||||||
me->Attack(victim, false);
|
|
||||||
me->GetMotionMaster()->MoveChase(victim, 0.0f, 0.0f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct boss_vexallus : public BossAI
|
struct boss_vexallus : public BossAI
|
||||||
{
|
{
|
||||||
// Configuration constants
|
boss_vexallus(Creature* creature) : BossAI(creature, DATA_VEXALLUS), _energyCooldown(false), _energyCount(0) { }
|
||||||
static constexpr std::array<uint8_t, 5> HEALTH_THRESHOLDS = {85, 70, 55, 40, 25}; // HP % for energy spawns
|
|
||||||
static constexpr Seconds ENERGY_COOLDOWN = 5s; // Time between energy spawns
|
|
||||||
static constexpr Seconds ABILITY_TIMER = 8s; // Basic ability cooldown
|
|
||||||
static constexpr uint8 INITIAL_PURE_ENERGY = 5; // Starting energy count
|
|
||||||
|
|
||||||
explicit boss_vexallus(Creature* creature)
|
|
||||||
: BossAI(creature, DATA_VEXALLUS)
|
|
||||||
, _energyCooldown(false)
|
|
||||||
, _overloaded(false)
|
|
||||||
, _energyQueue(0)
|
|
||||||
, _pureEnergy(INITIAL_PURE_ENERGY)
|
|
||||||
, _thresholdsPassed({})
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void Reset() override
|
void Reset() override
|
||||||
{
|
{
|
||||||
_Reset();
|
_Reset();
|
||||||
_energyCooldown = false;
|
_energyCooldown = false;
|
||||||
_energyQueue = 0;
|
_energyCount = 0;
|
||||||
_overloaded = false;
|
|
||||||
_pureEnergy = INITIAL_PURE_ENERGY;
|
|
||||||
std::fill(_thresholdsPassed.begin(), _thresholdsPassed.end(), false);
|
|
||||||
|
|
||||||
ScheduleEnergyCheck();
|
ScheduleHealthCheckEvent({ 85, 70, 55, 40, 25 }, [&]
|
||||||
|
{
|
||||||
|
scheduler.Schedule(1s, [this](TaskContext context)
|
||||||
|
{
|
||||||
|
if (!_energyCooldown)
|
||||||
|
{
|
||||||
|
Talk(SAY_ENERGY);
|
||||||
|
Talk(EMOTE_DISCHARGE_ENERGY);
|
||||||
|
if (IsHeroic())
|
||||||
|
{
|
||||||
|
DoCastSelf(SPELL_SUMMON_PURE_ENERGY_H1);
|
||||||
|
DoCastSelf(SPELL_SUMMON_PURE_ENERGY_H2);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
DoCastSelf(SPELL_SUMMON_PURE_ENERGY_N);
|
||||||
|
|
||||||
|
_energyCooldown = true;
|
||||||
|
++_energyCount;
|
||||||
|
|
||||||
|
me->m_Events.AddEventAtOffset([&]
|
||||||
|
{
|
||||||
|
_energyCooldown = false;
|
||||||
|
}, 5s);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
context.Repeat(5s);
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
ScheduleHealthCheckEvent(20, [&]
|
||||||
|
{
|
||||||
|
scheduler.Schedule(1s, [this](TaskContext context)
|
||||||
|
{
|
||||||
|
if (_energyCount == 5 && !_energyCooldown)
|
||||||
|
{
|
||||||
|
scheduler.CancelAll();
|
||||||
|
Talk(SAY_OVERLOAD);
|
||||||
|
Talk(EMOTE_OVERLOAD);
|
||||||
|
DoCastSelf(SPELL_OVERLOAD, true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
context.Repeat(5s);
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void JustDied(Unit*) override
|
void JustDied(Unit*) override
|
||||||
@@ -125,7 +114,28 @@ struct boss_vexallus : public BossAI
|
|||||||
{
|
{
|
||||||
_JustEngagedWith();
|
_JustEngagedWith();
|
||||||
Talk(SAY_AGGRO);
|
Talk(SAY_AGGRO);
|
||||||
ScheduleCombatAbilities();
|
|
||||||
|
ScheduleTimedEvent(5s, [&]
|
||||||
|
{
|
||||||
|
DoCastRandomTarget(SPELL_CHAIN_LIGHTNING);
|
||||||
|
}, 8s);
|
||||||
|
|
||||||
|
ScheduleTimedEvent(5s, [&]
|
||||||
|
{
|
||||||
|
DoCastRandomTarget(SPELL_ARCANE_SHOCK);
|
||||||
|
}, 5s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void JustSummoned(Creature* summon) override
|
||||||
|
{
|
||||||
|
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
|
||||||
|
{
|
||||||
|
summon->SetReactState(REACT_PASSIVE);
|
||||||
|
summon->GetMotionMaster()->MoveFollow(target, 0.0f, 0.0f);
|
||||||
|
summon->CastSpell(target, SPELL_ENERGY_FEEDBACK_CHANNEL, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
summons.Summon(summon);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SummonedCreatureDies(Creature* summon, Unit* killer) override
|
void SummonedCreatureDies(Creature* summon, Unit* killer) override
|
||||||
@@ -136,112 +146,12 @@ struct boss_vexallus : public BossAI
|
|||||||
killer->CastSpell(killer, SPELL_ENERGY_FEEDBACK, true, 0, 0, summon->GetGUID());
|
killer->CastSpell(killer, SPELL_ENERGY_FEEDBACK, true, 0, 0, summon->GetGUID());
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdateAI(uint32 diff) override
|
|
||||||
{
|
|
||||||
if (!UpdateVictim())
|
|
||||||
return;
|
|
||||||
DoMeleeAttackIfReady();
|
|
||||||
CheckOverload();
|
|
||||||
CheckHealthThresholds();
|
|
||||||
|
|
||||||
events.Update(diff);
|
|
||||||
scheduler.Update(diff);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Schedule periodic energy spawn checks
|
bool _energyCooldown;
|
||||||
void ScheduleEnergyCheck()
|
uint8 _energyCount;
|
||||||
{
|
|
||||||
scheduler.Schedule(1s, [this](TaskContext context)
|
|
||||||
{
|
|
||||||
ProcessEnergyQueue();
|
|
||||||
context.Repeat(1s);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle energy spawn logic
|
|
||||||
void ProcessEnergyQueue()
|
|
||||||
{
|
|
||||||
if (!_energyCooldown && _energyQueue > 0)
|
|
||||||
{
|
|
||||||
Talk(SAY_ENERGY);
|
|
||||||
Talk(EMOTE_DISCHARGE_ENERGY);
|
|
||||||
|
|
||||||
if (IsHeroic())
|
|
||||||
{
|
|
||||||
DoCastSelf(SPELL_SUMMON_PURE_ENERGY_H1);
|
|
||||||
DoCastSelf(SPELL_SUMMON_PURE_ENERGY_H2);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
DoCastSelf(SPELL_SUMMON_PURE_ENERGY_N);
|
|
||||||
}
|
|
||||||
|
|
||||||
_energyQueue--;
|
|
||||||
_pureEnergy--;
|
|
||||||
SetEnergyCooldown();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start energy spawn cooldown
|
|
||||||
void SetEnergyCooldown()
|
|
||||||
{
|
|
||||||
_energyCooldown = true;
|
|
||||||
scheduler.Schedule(ENERGY_COOLDOWN, [this](TaskContext)
|
|
||||||
{
|
|
||||||
_energyCooldown = false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Schedule basic combat abilities
|
|
||||||
void ScheduleCombatAbilities()
|
|
||||||
{
|
|
||||||
ScheduleTimedEvent(ABILITY_TIMER, [&]
|
|
||||||
{
|
|
||||||
DoCastRandomTarget(SPELL_CHAIN_LIGHTNING);
|
|
||||||
}, ABILITY_TIMER, ABILITY_TIMER);
|
|
||||||
|
|
||||||
ScheduleTimedEvent(5s, [&]
|
|
||||||
{
|
|
||||||
DoCastRandomTarget(SPELL_ARCANE_SHOCK);
|
|
||||||
}, ABILITY_TIMER, ABILITY_TIMER);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for final phase transition
|
|
||||||
void CheckOverload()
|
|
||||||
{
|
|
||||||
if (!_overloaded && _pureEnergy == 0 && !_energyCooldown && HealthBelowPct(20))
|
|
||||||
{
|
|
||||||
Talk(SAY_OVERLOAD);
|
|
||||||
Talk(EMOTE_OVERLOAD);
|
|
||||||
DoCastSelf(SPELL_OVERLOAD, true);
|
|
||||||
_overloaded = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check health-based energy spawn triggers
|
|
||||||
void CheckHealthThresholds()
|
|
||||||
{
|
|
||||||
for (size_t i = 0; i < HEALTH_THRESHOLDS.size(); ++i)
|
|
||||||
{
|
|
||||||
if (!_thresholdsPassed[i] && HealthBelowPct(HEALTH_THRESHOLDS[i]))
|
|
||||||
{
|
|
||||||
_energyQueue++;
|
|
||||||
_thresholdsPassed[i] = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// State tracking
|
|
||||||
bool _energyCooldown; // Energy spawn on cooldown
|
|
||||||
bool _overloaded; // Final phase active
|
|
||||||
uint8 _energyQueue; // Pending energy spawns
|
|
||||||
uint8 _pureEnergy; // Remaining energy count
|
|
||||||
std::array<bool, 5> _thresholdsPassed; // Health threshold tracking
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void AddSC_boss_vexallus()
|
void AddSC_boss_vexallus()
|
||||||
{
|
{
|
||||||
RegisterMagistersTerraceCreatureAI(npc_pure_energy);
|
|
||||||
RegisterMagistersTerraceCreatureAI(boss_vexallus);
|
RegisterMagistersTerraceCreatureAI(boss_vexallus);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user