fix(Scripts/Ulduar): sync Mimiron's Rocket Strike marker and detonation with the missile (#26844)

This commit is contained in:
Andrew
2026-07-28 14:18:46 -03:00
committed by GitHub
parent 0398c6baf8
commit b06fc4b858
2 changed files with 111 additions and 10 deletions

View File

@@ -22,6 +22,7 @@
#include "GameTime.h"
#include "GridNotifiers.h"
#include "MapMgr.h"
#include "ObjectAccessor.h"
#include "PassiveAI.h"
#include "Player.h"
#include "ScriptedCreature.h"
@@ -60,6 +61,7 @@ enum SpellData
SPELL_ROCKET_STRIKE_BOTH = 65034, // VX-001 fires both mounted rockets
SPELL_ROCKET_STRIKE_TARGET = 63681, // Cast by a fired rocket; picks the impact target (prefers ranged)
SPELL_SUMMON_ROCKET_STRIKE = 63036, // Summons the ground strike at the chosen target
SPELL_ROCKET_STRIKE_DAMAGE = 63041,
NPC_ROCKET_VISUAL = 34050,
NPC_ROCKET_STRIKE_N = 34047,
@@ -219,6 +221,9 @@ enum EVENTS
EVENT_SUMMON_EMERGENCY_FIRE_BOTS = 68,
EVENT_EMERGENCY_BOT_CHECK = 69,
EVENT_EMERGENCY_BOT_ATTACK = 70,
// Rocket (Mimiron Visual):
EVENT_ROCKET_FIRE = 71,
};
enum Actions
@@ -1877,9 +1882,14 @@ class spell_mimiron_rocket_strike_target_select : public SpellScript
void HandleScript(SpellEffIndex /*effIndex*/)
{
ObjectGuid originalCaster = GetOriginalCaster() ? GetOriginalCaster()->GetGUID() : GetCaster()->GetGUID();
GetCaster()->CastSpell(GetHitUnit(), SPELL_SUMMON_ROCKET_STRIKE, TRIGGERED_FULL_MASK, nullptr, nullptr, originalCaster);
GetCaster()->SetDisplayId(11686); // hide the spent rocket until it is reloaded
// Spawn the strike trigger now, so its warning visual and 5s fuse run while the missile is still to come.
// The rocket fires the missile later, timed to land as the fuse expires (see npc_ulduar_mimiron_rocket).
if (Creature* rocket = GetCaster()->ToCreature())
if (Creature* trigger = rocket->SummonCreature(NPC_ROCKET_STRIKE_N, *GetHitUnit(), TEMPSUMMON_TIMED_DESPAWN, 6000))
{
rocket->AI()->SetGUID(trigger->GetGUID(), 0);
rocket->AI()->SetGUID(GetHitUnit()->GetGUID(), 1);
}
}
void Register() override
@@ -1906,19 +1916,70 @@ struct npc_ulduar_mimiron_rocket : public NullCreatureAI
me->AddUnitState(UNIT_STATE_NO_ENVIRONMENT_UPD);
}
void SetData(uint32 /*id*/, uint32 /*value*/) override
void SetGUID(ObjectGuid const& guid, int32 id) override
{
me->GetMotionMaster()->MovePoint(0, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ() + 100.0f, FORCED_MOVEMENT_NONE, 0.f, false, true);
if (id == 0)
{
_strikeTrigger = guid;
// Delay the shot so the 63036 missile (7 yd/s client-side) lands as the strike trigger's 5s fuse expires.
_travelMs = 0;
if (Creature* trigger = ObjectAccessor::GetCreature(*me, guid))
_travelMs = uint32(me->GetExactDist(trigger) / 7.0f * 1000.0f);
_events.RescheduleEvent(EVENT_ROCKET_FIRE, Milliseconds(_travelMs < 5000 ? 5000 - _travelMs : 0));
}
else
_strikeVictim = guid;
}
void UpdateAI(uint32 /*diff*/) override
ObjectGuid GetGUID(int32 /*id*/) const override
{
if (!me->GetVehicle())
return _strikeTrigger;
}
void UpdateAI(uint32 diff) override
{
_events.Update(diff);
if (_events.ExecuteEvent() == EVENT_ROCKET_FIRE)
{
me->SetSpeed(MOVE_RUN, me->GetSpeedRate(MOVE_RUN) + 0.4f, false);
me->SetSpeed(MOVE_FLIGHT, me->GetSpeedRate(MOVE_RUN), false);
if (Unit* victim = ObjectAccessor::GetUnit(*me, _strikeVictim))
me->CastSpell(victim, SPELL_SUMMON_ROCKET_STRIKE, true);
if (Creature* trigger = ObjectAccessor::GetCreature(*me, _strikeTrigger))
trigger->AI()->SetData(0, _travelMs);
me->SetDisplayId(11686); // hide the spent rocket until it is reloaded
}
}
private:
EventMap _events;
ObjectGuid _strikeTrigger;
ObjectGuid _strikeVictim;
uint32 _travelMs = 0;
};
// 63036 - Summon Rocket Strike
class spell_mimiron_summon_rocket_strike : public SpellScript
{
PrepareSpellScript(spell_mimiron_summon_rocket_strike);
void SetDest(SpellDestination& dest)
{
// Land on the pre-spawned strike trigger, not on the target's current position.
if (Creature* rocket = GetCaster()->ToCreature())
if (Creature* trigger = ObjectAccessor::GetCreature(*rocket, rocket->AI()->GetGUID()))
dest.Relocate(*trigger);
}
void PreventSummon(SpellEffIndex effIndex)
{
// The strike trigger is pre-spawned on target selection; this cast only provides the missile visual.
PreventHitDefaultEffect(effIndex);
}
void Register() override
{
OnDestinationTargetSelect += SpellDestinationTargetSelectFn(spell_mimiron_summon_rocket_strike::SetDest, EFFECT_0, TARGET_DEST_TARGET_ENEMY);
OnEffectHit += SpellEffectFn(spell_mimiron_summon_rocket_strike::PreventSummon, EFFECT_0, SPELL_EFFECT_SUMMON);
}
};
struct npc_ulduar_bot_summon_trigger : public NullCreatureAI
@@ -2338,11 +2399,24 @@ struct npc_ulduar_rocket_strike_trigger : public NullCreatureAI
me->DespawnOrUnsummon(6s);
}
void SetData(uint32 /*id*/, uint32 value) override
{
// Detonate in sync with the incoming missile; the 64064 tick is suppressed (spell_mimiron_rocket_strike_aura).
_events.ScheduleEvent(1, Milliseconds(value));
}
void UpdateAI(uint32 diff) override
{
_events.Update(diff);
if (_events.ExecuteEvent() == 1)
me->CastSpell(me, SPELL_ROCKET_STRIKE_DAMAGE, true);
}
void SpellHitTarget(Unit* target, SpellInfo const* spell) override
{
if (!target || !spell)
return;
if (spell->Id == 63041)
if (spell->Id == SPELL_ROCKET_STRIKE_DAMAGE)
{
if (target->GetEntry() == NPC_ASSAULT_BOT)
me->CastSpell(me, 65040, true); // achievement Not-So-Friendly Fire
@@ -2352,6 +2426,26 @@ struct npc_ulduar_rocket_strike_trigger : public NullCreatureAI
c->AI()->SetData(0, 13);
}
}
private:
EventMap _events;
};
// 64064 - Rocket Strike
class spell_mimiron_rocket_strike_aura : public AuraScript
{
PrepareAuraScript(spell_mimiron_rocket_strike_aura);
void HandlePeriodic(AuraEffect const* /*aurEff*/)
{
// No fuse tick: the strike trigger detonates in sync with the missile impact (npc_ulduar_rocket_strike_trigger).
PreventDefaultAction();
}
void Register() override
{
OnEffectPeriodic += AuraEffectPeriodicFn(spell_mimiron_rocket_strike_aura::HandlePeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL);
}
};
class achievement_mimiron_firefighter : public AchievementCriteriaScript
@@ -2415,6 +2509,8 @@ void AddSC_boss_mimiron()
RegisterSpellScript(spell_ulduar_mimiron_mine_explosion);
RegisterSpellScript(spell_mimiron_rocket_strike);
RegisterSpellScript(spell_mimiron_rocket_strike_target_select);
RegisterSpellScript(spell_mimiron_summon_rocket_strike);
RegisterSpellScript(spell_mimiron_rocket_strike_aura);
new go_ulduar_do_not_push_this_button();
RegisterUlduarCreatureAI(npc_ulduar_flames_initial);
RegisterUlduarCreatureAI(npc_ulduar_flames_spread);