From b06fc4b8581db91500b8acdd910458aa49d94a2b Mon Sep 17 00:00:00 2001 From: Andrew <47818697+Nyeriah@users.noreply.github.com> Date: Tue, 28 Jul 2026 14:18:46 -0300 Subject: [PATCH] fix(Scripts/Ulduar): sync Mimiron's Rocket Strike marker and detonation with the missile (#26844) --- .../rev_1785202717966359900.sql | 5 + .../Northrend/Ulduar/Ulduar/boss_mimiron.cpp | 116 ++++++++++++++++-- 2 files changed, 111 insertions(+), 10 deletions(-) create mode 100644 data/sql/updates/pending_db_world/rev_1785202717966359900.sql diff --git a/data/sql/updates/pending_db_world/rev_1785202717966359900.sql b/data/sql/updates/pending_db_world/rev_1785202717966359900.sql new file mode 100644 index 000000000..64553fc57 --- /dev/null +++ b/data/sql/updates/pending_db_world/rev_1785202717966359900.sql @@ -0,0 +1,5 @@ +-- +DELETE FROM `spell_script_names` WHERE `spell_id` IN (63036, 64064) AND `ScriptName` IN ('spell_mimiron_summon_rocket_strike', 'spell_mimiron_rocket_strike_aura'); +INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES +(63036, 'spell_mimiron_summon_rocket_strike'), +(64064, 'spell_mimiron_rocket_strike_aura'); diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp index 92581a93e..2037f393f 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp @@ -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);