fix(Script/HoL): Volkhan timings and Molten Golem timers and abilities (#23433)

This commit is contained in:
blinkysc
2025-10-30 21:53:37 -05:00
committed by GitHub
parent a1c8e0f221
commit 43552868b8
@@ -30,6 +30,7 @@ enum VolkahnSpells
//Molten Golem //Molten Golem
SPELL_BLAST_WAVE = 23113, SPELL_BLAST_WAVE = 23113,
SPELL_COOL_DOWN = 52443,
SPELL_IMMOLATION_STRIKE = 52433, SPELL_IMMOLATION_STRIKE = 52433,
SPELL_SHATTER = 52429, SPELL_SHATTER = 52429,
}; };
@@ -59,8 +60,8 @@ enum VolkhanEvents
EVENT_MOVE_TO_ANVIL = 5, EVENT_MOVE_TO_ANVIL = 5,
// Molten Golem // Molten Golem
EVENT_BLAST = 11, EVENT_IMMOLATION_STRIKE = 12,
EVENT_IMMOLATION = 12, EVENT_CHANGE_TARGET = 13,
}; };
enum Yells enum Yells
@@ -82,7 +83,7 @@ struct boss_volkhan : public BossAI
{ {
_Reset(); _Reset();
x = y = z = PointID = ShatteredCount = 0; x = y = z = PointID = ShatteredCount = 0;
HealthCheck = 100; shatteredStompCast = false;
me->SetSpeed(MOVE_RUN, 1.2f, true); me->SetSpeed(MOVE_RUN, 1.2f, true);
me->SetReactState(REACT_AGGRESSIVE); me->SetReactState(REACT_AGGRESSIVE);
instance->SetData(DATA_VOLKHAN_ACHIEVEMENT, true); instance->SetData(DATA_VOLKHAN_ACHIEVEMENT, true);
@@ -93,7 +94,10 @@ struct boss_volkhan : public BossAI
_JustEngagedWith(); _JustEngagedWith();
me->SetInCombatWithZone(); me->SetInCombatWithZone();
Talk(SAY_AGGRO); Talk(SAY_AGGRO);
ScheduleEvents(false); events.ScheduleEvent(EVENT_MOVE_TO_ANVIL, randtime(9s, 14s));
events.ScheduleEvent(EVENT_HEAT, randtime(18s, 38s));
events.ScheduleEvent(EVENT_CHECK_HEALTH, 1s);
events.ScheduleEvent(EVENT_POSITION, 4s);
} }
void JustDied(Unit*) override void JustDied(Unit*) override
@@ -151,15 +155,6 @@ struct boss_volkhan : public BossAI
Talk(SAY_SLAY); Talk(SAY_SLAY);
} }
void ScheduleEvents(bool anvil)
{
events.SetPhase(1);
events.RescheduleEvent(EVENT_HEAT, 8s, 0, 1);
events.RescheduleEvent(EVENT_SHATTER, 10s, 0, 1);
events.RescheduleEvent(EVENT_CHECK_HEALTH, anvil ? 1s : 6s, 0, 1);
events.RescheduleEvent(EVENT_POSITION, 4s, 0, 1);
}
void JustSummoned(Creature* summon) override void JustSummoned(Creature* summon) override
{ {
summons.Summon(summon); summons.Summon(summon);
@@ -182,6 +177,19 @@ struct boss_volkhan : public BossAI
} }
} }
bool HasActiveGolem()
{
for (ObjectGuid const& guid : summons)
{
if (Creature* golem = ObjectAccessor::GetCreature(*me, guid))
{
if (golem->GetEntry() == NPC_MOLTEN_GOLEM && golem->IsAlive())
return true;
}
}
return false;
}
void MovementInform(uint32 type, uint32 id) override void MovementInform(uint32 type, uint32 id) override
{ {
if (type != POINT_MOTION_TYPE) if (type != POINT_MOTION_TYPE)
@@ -190,10 +198,8 @@ struct boss_volkhan : public BossAI
if (id == POINT_ANVIL) if (id == POINT_ANVIL)
{ {
me->SetSpeed(MOVE_RUN, 1.2f, true); me->SetSpeed(MOVE_RUN, 1.2f, true);
me->SetReactState(REACT_AGGRESSIVE); DoCastSelf(SPELL_TEMPER);
me->CastSpell(me, SPELL_TEMPER, false);
PointID = 0; PointID = 0;
ScheduleEvents(true);
// update orientation at server // update orientation at server
me->SetOrientation(2.19f); me->SetOrientation(2.19f);
@@ -205,24 +211,26 @@ struct boss_volkhan : public BossAI
me->SetControlled(true, UNIT_STATE_ROOT); me->SetControlled(true, UNIT_STATE_ROOT);
} }
else else
events.ScheduleEvent(EVENT_MOVE_TO_ANVIL, 0ms, 0, 2); me->GetMotionMaster()->MovePoint(PointID, x, y, z);
} }
void SpellHitTarget(Unit* /*who*/, SpellInfo const* spellInfo) override void SpellHitTarget(Unit* /*who*/, SpellInfo const* spellInfo) override
{ {
if (spellInfo->Id == SPELL_TEMPER) if (spellInfo->Id == SPELL_TEMPER)
{ {
me->CastSpell(me, SPELL_SUMMON_MOLTEN_GOLEM, true); DoCastSelf(SPELL_SUMMON_MOLTEN_GOLEM, true);
me->CastSpell(me, SPELL_SUMMON_MOLTEN_GOLEM, true); DoCastSelf(SPELL_SUMMON_MOLTEN_GOLEM, true);
me->GetMotionMaster()->MoveChase(me->GetVictim());
me->SetControlled(false, UNIT_STATE_ROOT); me->SetControlled(false, UNIT_STATE_ROOT);
me->SetReactState(REACT_AGGRESSIVE);
if (me->GetVictim())
me->GetMotionMaster()->MoveChase(me->GetVictim());
events.RescheduleEvent(EVENT_HEAT, randtime(9s, 24s));
} }
} }
void GoToAnvil() void GoToAnvil()
{ {
events.SetPhase(2);
HealthCheck -= 20;
me->SetSpeed(MOVE_RUN, 4.0f, true); me->SetSpeed(MOVE_RUN, 4.0f, true);
me->SetReactState(REACT_PASSIVE); me->SetReactState(REACT_PASSIVE);
@@ -231,12 +239,12 @@ struct boss_volkhan : public BossAI
if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == CHASE_MOTION_TYPE) if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == CHASE_MOTION_TYPE)
me->GetMotionMaster()->MovementExpired(); me->GetMotionMaster()->MovementExpired();
events.ScheduleEvent(EVENT_MOVE_TO_ANVIL, 0ms, 0, 2); GetNextPos();
me->GetMotionMaster()->MovePoint(PointID, x, y, z);
} }
void UpdateAI(uint32 diff) override void UpdateAI(uint32 diff) override
{ {
//Return since we have no target
if (!UpdateVictim()) if (!UpdateVictim())
return; return;
@@ -248,31 +256,31 @@ struct boss_volkhan : public BossAI
switch (events.ExecuteEvent()) switch (events.ExecuteEvent())
{ {
case EVENT_HEAT: case EVENT_HEAT:
me->CastSpell(me, SPELL_HEAT, true); if (HasActiveGolem())
events.Repeat(8s); {
DoCastSelf(SPELL_HEAT);
events.Repeat(randtime(9s, 24s));
}
break; break;
case EVENT_CHECK_HEALTH: case EVENT_CHECK_HEALTH:
if (HealthBelowPct(HealthCheck)) if (!shatteredStompCast && HealthBelowPct(25))
GoToAnvil(); {
shatteredStompCast = true;
DoCastAOE(SPELL_SHATTERING_STOMP);
Talk(SAY_STOMP);
summons.DoAction(ACTION_SHATTER);
}
events.Repeat(1s); events.Repeat(1s);
return; return;
case EVENT_SHATTER:
{
events.Repeat(10s);
summons.DoAction(ACTION_SHATTER);
break;
}
case EVENT_MOVE_TO_ANVIL: case EVENT_MOVE_TO_ANVIL:
GetNextPos(); GoToAnvil();
me->GetMotionMaster()->MovePoint(PointID, x, y, z); events.Repeat(randtime(30s, 36s));
return; return;
case EVENT_POSITION: case EVENT_POSITION:
if (me->GetDistance(1331.9f, -106, 56) > 95) if (me->GetDistance(1331.9f, -106, 56) > 95)
EnterEvadeMode(); EnterEvadeMode();
else else
events.Repeat(4s); events.Repeat(4s);
return; return;
} }
@@ -282,10 +290,10 @@ struct boss_volkhan : public BossAI
private: private:
EventMap events; EventMap events;
SummonList summons; SummonList summons;
uint8 HealthCheck;
float x, y, z; float x, y, z;
uint8 PointID; uint8 PointID;
uint8 ShatteredCount; uint8 ShatteredCount;
bool shatteredStompCast;
}; };
struct npc_molten_golem : public ScriptedAI struct npc_molten_golem : public ScriptedAI
@@ -298,8 +306,9 @@ struct npc_molten_golem : public ScriptedAI
void Reset() override void Reset() override
{ {
events.Reset(); events.Reset();
events.ScheduleEvent(EVENT_BLAST, 7s); events.ScheduleEvent(EVENT_IMMOLATION_STRIKE, 3s);
events.ScheduleEvent(EVENT_IMMOLATION, 3s); events.ScheduleEvent(EVENT_CHANGE_TARGET, 5s);
DoCastSelf(SPELL_COOL_DOWN, true);
} }
void DamageTaken(Unit*, uint32& uiDamage, DamageEffectType, SpellSchoolMask) override void DamageTaken(Unit*, uint32& uiDamage, DamageEffectType, SpellSchoolMask) override
@@ -312,6 +321,9 @@ struct npc_molten_golem : public ScriptedAI
if (uiDamage >= me->GetHealth()) if (uiDamage >= me->GetHealth())
{ {
if (me->GetMap()->IsHeroic())
DoCastSelf(SPELL_BLAST_WAVE, true);
me->UpdateEntry(NPC_BRITTLE_GOLEM, 0, false); me->UpdateEntry(NPC_BRITTLE_GOLEM, 0, false);
me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_DISABLE_MOVE); me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_DISABLE_MOVE);
me->SetHealth(me->GetMaxHealth()); me->SetHealth(me->GetMaxHealth());
@@ -351,14 +363,19 @@ struct npc_molten_golem : public ScriptedAI
switch (events.ExecuteEvent()) switch (events.ExecuteEvent())
{ {
case EVENT_BLAST: case EVENT_IMMOLATION_STRIKE:
me->CastSpell(me, SPELL_BLAST_WAVE, false); if (SelectTarget(SelectTargetMethod::MaxThreat, 0, 0.0f, true, true, -SPELL_IMMOLATION_STRIKE))
events.Repeat(14s); DoCastVictim(SPELL_IMMOLATION_STRIKE);
break;
case EVENT_IMMOLATION:
me->CastSpell(me->GetVictim(), SPELL_IMMOLATION_STRIKE, false);
events.Repeat(5s); events.Repeat(5s);
break; break;
case EVENT_CHANGE_TARGET:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true))
{
me->GetThreatMgr().ResetAllThreat();
me->AddThreat(target, 30000.0f);
AttackStart(target);
}
break;
} }
DoMeleeAttackIfReady(); DoMeleeAttackIfReady();