From f336d6032b6d154ef74e649f5d090fdbc0ab3727 Mon Sep 17 00:00:00 2001 From: Ovahlord Date: Tue, 28 Jan 2020 08:17:06 +0100 Subject: [PATCH] Scripts/Spells: moved Magmaw's involved eject passenger spells to generic spell script and use vehicle exit position script hook --- .../custom/custom_2020_01_28_00_world.sql | 10 + .../BlackwingDescent/boss_magmaw.cpp | 751 +++++++++--------- src/server/scripts/Spells/spell_generic.cpp | 32 +- 3 files changed, 414 insertions(+), 379 deletions(-) create mode 100644 sql/updates/world/custom/custom_2020_01_28_00_world.sql diff --git a/sql/updates/world/custom/custom_2020_01_28_00_world.sql b/sql/updates/world/custom/custom_2020_01_28_00_world.sql new file mode 100644 index 00000000000..1f01e6eaf6b --- /dev/null +++ b/sql/updates/world/custom/custom_2020_01_28_00_world.sql @@ -0,0 +1,10 @@ +DELETE FROM `spell_script_names` WHERE `ScriptName` IN +('spell_magmaw_eject_passenger_1', +'spell_magmaw_eject_passenger_3', +'spell_gen_eject_passenger') AND `spell_id` IN (95204, 77946); + +INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES +(95204, 'spell_gen_eject_passenger'), +(77946, 'spell_gen_eject_passenger'); + +UPDATE `creature_template` SET `ScriptName`= '' WHERE `entry` IN (41620, 41789); diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingDescent/boss_magmaw.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingDescent/boss_magmaw.cpp index 65b99f15e69..c87ebc6adfe 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingDescent/boss_magmaw.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingDescent/boss_magmaw.cpp @@ -174,387 +174,421 @@ Position const NefarianIntroSummonPos = { -390.1042f, 40.88411f, 207.8586f, 0 #define SPELL_PARASITIC_INFECTION_PERIODIC_DAMAGE RAID_MODE(78941, 91913, 94678, 94679) -struct boss_magmaw : public BossAI +class boss_magmaw : public CreatureScript, public UnitScript { - boss_magmaw(Creature* creature) : BossAI(creature, DATA_MAGMAW) +public: + boss_magmaw() : CreatureScript("boss_magmaw"), UnitScript("boss_magmaw_vehicle") { } + + void ModifyVehiclePassengerExitPos(Unit* /*passenger*/, Vehicle* vehicle, Position& pos) override { - Initialize(); + if (vehicle->GetBase()->GetEntry() != BOSS_MAGMAW) + return; + + pos.Relocate(MagmawVehicleExitPos); } - void Initialize() + struct boss_magmawAI : public BossAI { - _magmaProjectileCount = 0; - _exposedHead1 = nullptr; - _exposedHead2 = nullptr; - _pincer1 = nullptr; - _pincer2 = nullptr; - _hasExposedHead = false; - _headEngaged = false; - _achievementEnligible = true; - _heroicPhaseTwoActive = !IsHeroic(); - me->SetReactState(REACT_PASSIVE); - } - - void Reset() override - { - _Reset(); - Initialize(); - } - - void JustAppeared() override - { - SetupBody(); - } - - void JustEngagedWith(Unit* /*who*/) override - { - _JustEngagedWith(); - instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, me); - me->SetReactState(REACT_AGGRESSIVE); - events.ScheduleEvent(EVENT_MAGMA_PROJECTILE, 6s); - events.ScheduleEvent(EVENT_LAVA_SPEW, 19s); - events.ScheduleEvent(EVENT_MANGLE, 1min + 30s); - - _exposedHead1->SetInCombatWithZone(); - _exposedHead2->SetInCombatWithZone(); - - if (IsHeroic()) - DoSummon(NPC_NEFARIAN_MAGMAW, NefarianIntroSummonPos, 0, TEMPSUMMON_MANUAL_DESPAWN); - } - - void EnterEvadeMode(EvadeReason /*why*/) override - { - _EnterEvadeMode(); - instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me); - if (_headEngaged) - instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, _exposedHead1); - - DoCastSelf(SPELL_EJECT_PASSENGER_3, true); - _pincer1->CastSpell(_pincer1, SPELL_EJECT_PASSENGER_1, true); - _pincer2->CastSpell(_pincer2, SPELL_EJECT_PASSENGER_1, true); - - instance->SetBossState(DATA_MAGMAW, FAIL); - instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_PARASITIC_INFECTION_VOMIT); - instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_PARASITIC_INFECTION_PERIODIC_DAMAGE); - _exposedHead1->DespawnOrUnsummon(); - summons.DespawnAll(); - - if (Creature* nefarian = instance->GetCreature(DATA_NEFARIAN_MAGMAW)) - nefarian->DespawnOrUnsummon(); - _DespawnAtEvade(); - } - - void JustDied(Unit* /*killer*/) override - { - if (_headEngaged) - instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, _exposedHead1); - - instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_PARASITIC_INFECTION_VOMIT); - instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_PARASITIC_INFECTION_PERIODIC_DAMAGE); - instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me); - - if (Creature* nefarian = instance->GetCreature(DATA_NEFARIAN_MAGMAW)) - nefarian->AI()->DoAction(ACTION_MAGMAW_DEAD); - - me->StopMoving(); // Tempfix to prevent Magmaw from falling into the lava - _JustDied(); - } - - void JustSummoned(Creature* summon) override - { - switch (summon->GetEntry()) + boss_magmawAI(Creature* creature) : BossAI(creature, DATA_MAGMAW) { - case NPC_PILLAR_OF_FLAME: - summon->CastSpell(summon, SPELL_PILLAR_OF_FLAME_DUMMY); - summon->SetDisplayId(summon->GetCreatureTemplate()->Modelid1); - summon->DespawnOrUnsummon(7s); - Talk(SAY_ANNOUNCE_LAVA_PARASITES); - summons.Summon(summon); - break; - case NPC_NEFARIAN_MAGMAW: - case NPC_EXPOSED_HEAD_OF_MAGMAW: - break; - default: - summons.Summon(summon); - break; - } - } - - void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override - { - switch (spell->Id) - { - case SPELL_MASSIVE_CRASH: - { - me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK); - me->SetFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_ALLOW_ENEMY_INTERACT); - _exposedHead1->CastSpell(_exposedHead1, SPELL_RIDE_VEHICLE_HEAD, true); - _pincer1->CastSpell(_pincer1, SPELL_EJECT_PASSENGER_1, true); - _pincer2->CastSpell(_pincer2, SPELL_EJECT_PASSENGER_1, true); - - events.ScheduleEvent(EVENT_ANNOUNCE_PINCERS_EXPOSED, 1s); - events.ScheduleEvent(EVENT_FINISH_MASSIVE_CRASH, 7s); - - Unit* head = _exposedHead1; - head->m_Events.AddEventAtOffset([head]() - { - head->CastSpell(head, SPELL_RIDE_VEHICLE_EXPOSED_HEAD, true); - }, 6s); - - break; - } - case SPELL_IMPALE_SELF: - DoCastSelf(SPELL_EJECT_PASSENGER_3, true); - Talk(SAY_ANNOUNCE_EXPOSED_HEAD); - me->RemoveAurasDueToSpell(SPELL_CHAIN_VISUAL_1); - me->RemoveAurasDueToSpell(SPELL_CHAIN_VISUAL_2); - events.ScheduleEvent(EVENT_HIDE_HEAD, 29s); - events.ScheduleEvent(EVENT_FINISH_IMPALE_SELF, 33s); - break; - default: - break; - } - } - - uint32 GetData(uint32 type) const override - { - if (type == DATA_ACHIEVEMENT_STATE) - return _achievementEnligible; - - return 0; - } - - ObjectGuid GetGUID(int32 type) const override - { - switch (type) - { - case DATA_FREE_PINCER: - if (_pincer1->GetVehicleKit() && _pincer1->GetVehicleKit()->GetAvailableSeatCount()) - return _pincer1->GetGUID(); - else if (_pincer2->GetVehicleKit() && _pincer2->GetVehicleKit()->GetAvailableSeatCount()) - return _pincer2->GetGUID(); - default: - return ObjectGuid::Empty; + Initialize(); } - return ObjectGuid::Empty; - } - - void DamageTaken(Unit* /*attacker*/, uint32& damage) override - { - if (me->HealthBelowPctDamaged(30, damage) && !_heroicPhaseTwoActive) + void Initialize() { - if (Creature* nefarian = instance->GetCreature(DATA_NEFARIAN_MAGMAW)) - nefarian->AI()->DoAction(ACTION_SCHEDULE_SHADOW_BREATH); - _heroicPhaseTwoActive = true; + _magmaProjectileCount = 0; + _exposedHead1 = nullptr; + _exposedHead2 = nullptr; + _pincer1 = nullptr; + _pincer2 = nullptr; + _hasExposedHead = false; + _headEngaged = false; + _achievementEnligible = true; + _heroicPhaseTwoActive = !IsHeroic(); + me->SetReactState(REACT_PASSIVE); } - if (damage >= me->GetHealth()) + void Reset() override { - // Make sure we eject all passengers nicely before we die so they wont end up in the lava + _Reset(); + Initialize(); + } + + void JustAppeared() override + { + SetupBody(); + } + + void JustEngagedWith(Unit* /*who*/) override + { + _JustEngagedWith(); + instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, me); + me->SetReactState(REACT_AGGRESSIVE); + events.ScheduleEvent(EVENT_MAGMA_PROJECTILE, 6s); + events.ScheduleEvent(EVENT_LAVA_SPEW, 19s); + events.ScheduleEvent(EVENT_MANGLE, 1min + 30s); + + _exposedHead1->SetInCombatWithZone(); + _exposedHead2->SetInCombatWithZone(); + + if (IsHeroic()) + DoSummon(NPC_NEFARIAN_MAGMAW, NefarianIntroSummonPos, 0, TEMPSUMMON_MANUAL_DESPAWN); + } + + void EnterEvadeMode(EvadeReason /*why*/) override + { + _EnterEvadeMode(); + instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me); + if (_headEngaged) + instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, _exposedHead1); + DoCastSelf(SPELL_EJECT_PASSENGER_3, true); _pincer1->CastSpell(_pincer1, SPELL_EJECT_PASSENGER_1, true); _pincer2->CastSpell(_pincer2, SPELL_EJECT_PASSENGER_1, true); + + instance->SetBossState(DATA_MAGMAW, FAIL); + instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_PARASITIC_INFECTION_VOMIT); + instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_PARASITIC_INFECTION_PERIODIC_DAMAGE); + _exposedHead1->DespawnOrUnsummon(); + summons.DespawnAll(); + + if (Creature* nefarian = instance->GetCreature(DATA_NEFARIAN_MAGMAW)) + nefarian->DespawnOrUnsummon(); + _DespawnAtEvade(); } - } - void DoAction(int32 action) override - { - switch (action) + void JustDied(Unit* /*killer*/) override { - case ACTION_IMPALE_MAGMAW: - events.CancelEvent(EVENT_MAGMA_PROJECTILE); - events.CancelEvent(EVENT_LAVA_SPEW); - me->AttackStop(); - me->SetReactState(REACT_PASSIVE); - me->CastStop(); - me->RemoveAurasDueToSpell(SPELL_MASSIVE_CRASH); - me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK); - me->RemoveFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_ALLOW_ENEMY_INTERACT); - me->RemoveAurasDueToSpell(SPELL_PILLAR_OF_FLAME_MISSILE_PERIODIC); + if (_headEngaged) + instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, _exposedHead1); - if (Creature* spikeStalker = me->FindNearestCreature(NPC_MAGMAW_SPIKE_STALKER, 60.0f)) - me->SetFacingToObject(spikeStalker); + instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_PARASITIC_INFECTION_VOMIT); + instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_PARASITIC_INFECTION_PERIODIC_DAMAGE); + instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me); - events.ScheduleEvent(EVENT_IMPALE_SELF, 1s); - events.ScheduleEvent(EVENT_EXPOSE_HEAD, 4s + 700ms); - _hasExposedHead = true; - break; - case ACTION_FAIL_ACHIEVEMT: - _achievementEnligible = false; - break; - default: - break; + if (Creature* nefarian = instance->GetCreature(DATA_NEFARIAN_MAGMAW)) + nefarian->AI()->DoAction(ACTION_MAGMAW_DEAD); + + me->StopMoving(); // Tempfix to prevent Magmaw from falling into the lava + _JustDied(); } - } - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - events.Update(diff); - - if (me->HasUnitState(UNIT_STATE_CASTING) && !_hasExposedHead) - return; - - while (uint32 eventId = events.ExecuteEvent()) + void JustSummoned(Creature* summon) override { - switch (eventId) + switch (summon->GetEntry()) { - case EVENT_MAGMA_PROJECTILE: - if (_magmaProjectileCount < 4) - { - DoCastAOE(SPELL_MAGMA_SPIT_TARGETING); - _magmaProjectileCount++; - events.Repeat(6s); - } - else - { - DoCastAOE(SPELL_PILLAR_OF_FLAME); - DoCastAOE(SPELL_PILLAR_OF_FLAME_SET_VEHICLE_ID); - _magmaProjectileCount = 0; - events.Repeat(8s); - } + case NPC_PILLAR_OF_FLAME: + summon->CastSpell(summon, SPELL_PILLAR_OF_FLAME_DUMMY); + summon->SetDisplayId(summon->GetCreatureTemplate()->Modelid1); + summon->DespawnOrUnsummon(7s); + Talk(SAY_ANNOUNCE_LAVA_PARASITES); + summons.Summon(summon); break; - case EVENT_LAVA_SPEW: - DoCastAOE(SPELL_LAVA_SPEW); - events.Repeat(27s, 28s); + case NPC_NEFARIAN_MAGMAW: + case NPC_EXPOSED_HEAD_OF_MAGMAW: break; - case EVENT_MANGLE: - if (SelectTarget(SELECT_TARGET_RANDOM, 0, NonTankTargetSelector(me))) - DoCastAOE(SPELL_MANGLE_TARGETING); + default: + summons.Summon(summon); + break; + } + } - events.CancelEvent(EVENT_MAGMA_PROJECTILE); - events.CancelEvent(EVENT_LAVA_SPEW); - events.ScheduleEvent(EVENT_PREPARE_MASSIVE_CRASH, 3s + 500ms); - events.Repeat(1min + 35s); - break; - case EVENT_PREPARE_MASSIVE_CRASH: - if (ObjectGuid guid = instance->GetGuidData(DATA_PREPARE_MASSIVE_CRASH_AND_GET_TARGET_GUID)) - { - if (Creature* stalker = ObjectAccessor::GetCreature(*me, guid)) - { - me->AttackStop(); - me->SetReactState(REACT_PASSIVE); - me->ReleaseSpellFocus(nullptr, false); - me->SetFacingToObject(stalker, true); - events.ScheduleEvent(EVENT_MASSIVE_CRASH, 5s); - } - } - break; - case EVENT_MASSIVE_CRASH: - DoCast(SPELL_MASSIVE_CRASH); + void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override + { + switch (spell->Id) + { + case SPELL_MASSIVE_CRASH: + { + me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK); + me->SetFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_ALLOW_ENEMY_INTERACT); + _exposedHead1->CastSpell(_exposedHead1, SPELL_RIDE_VEHICLE_HEAD, true); _pincer1->CastSpell(_pincer1, SPELL_EJECT_PASSENGER_1, true); _pincer2->CastSpell(_pincer2, SPELL_EJECT_PASSENGER_1, true); + + events.ScheduleEvent(EVENT_ANNOUNCE_PINCERS_EXPOSED, 1s); + events.ScheduleEvent(EVENT_FINISH_MASSIVE_CRASH, 7s); + + Unit* head = _exposedHead1; + head->m_Events.AddEventAtOffset([head]() + { + head->CastSpell(head, SPELL_RIDE_VEHICLE_EXPOSED_HEAD, true); + }, 6s); + break; - case EVENT_ANNOUNCE_PINCERS_EXPOSED: - Talk(SAY_ANNOUNCE_EXPOSE_PINCERS); - break; - case EVENT_FINISH_MASSIVE_CRASH: - me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK); - me->RemoveFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_ALLOW_ENEMY_INTERACT); - me->SetReactState(REACT_AGGRESSIVE); - events.ScheduleEvent(EVENT_LAVA_SPEW, 1ms); - events.ScheduleEvent(EVENT_MAGMA_PROJECTILE, 8s); - break; - case EVENT_IMPALE_SELF: - DoCastSelf(SPELL_IMPALE_SELF); - break; - case EVENT_EXPOSE_HEAD: - if (!_headEngaged) - { - instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, _exposedHead1, 2); - instance->SendEncounterUnit(ENCOUNTER_FRAME_UPDATE_PRIORITY, me); - _headEngaged = true; - } - _exposedHead1->CastSpell(_exposedHead1, SPELL_RIDE_VEHICLE_HEAD, true); - _exposedHead1->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - break; - case EVENT_HIDE_HEAD: - _exposedHead1->CastSpell(_exposedHead1, SPELL_RIDE_VEHICLE_EXPOSED_HEAD, true); - _exposedHead1->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - break; - case EVENT_FINISH_IMPALE_SELF: - _hasExposedHead = false; - me->SetReactState(REACT_AGGRESSIVE); - events.ScheduleEvent(EVENT_LAVA_SPEW, 1ms); - events.ScheduleEvent(EVENT_MAGMA_PROJECTILE, 4s); + } + case SPELL_IMPALE_SELF: + DoCastSelf(SPELL_EJECT_PASSENGER_3, true); + Talk(SAY_ANNOUNCE_EXPOSED_HEAD); + me->RemoveAurasDueToSpell(SPELL_CHAIN_VISUAL_1); + me->RemoveAurasDueToSpell(SPELL_CHAIN_VISUAL_2); + events.ScheduleEvent(EVENT_HIDE_HEAD, 29s); + events.ScheduleEvent(EVENT_FINISH_IMPALE_SELF, 33s); break; default: break; } } - if (Unit* victim = me->GetVictim()) + uint32 GetData(uint32 type) const override { - if (me->IsWithinMeleeRange(victim)) - DoMeleeAttackIfReady(); - else - DoSpellAttackIfReady(SPELL_MAGMA_SPIT_MOLTEN_TANTRUM); - } - } + if (type == DATA_ACHIEVEMENT_STATE) + return _achievementEnligible; -private: - void SetupBody() + return 0; + } + + ObjectGuid GetGUID(int32 type) const override + { + switch (type) + { + case DATA_FREE_PINCER: + if (_pincer1->GetVehicleKit() && _pincer1->GetVehicleKit()->GetAvailableSeatCount()) + return _pincer1->GetGUID(); + else if (_pincer2->GetVehicleKit() && _pincer2->GetVehicleKit()->GetAvailableSeatCount()) + return _pincer2->GetGUID(); + default: + return ObjectGuid::Empty; + } + + return ObjectGuid::Empty; + } + + void DamageTaken(Unit* /*attacker*/, uint32& damage) override + { + if (me->HealthBelowPctDamaged(30, damage) && !_heroicPhaseTwoActive) + { + if (Creature* nefarian = instance->GetCreature(DATA_NEFARIAN_MAGMAW)) + nefarian->AI()->DoAction(ACTION_SCHEDULE_SHADOW_BREATH); + _heroicPhaseTwoActive = true; + } + + if (damage >= me->GetHealth()) + { + // Make sure we eject all passengers nicely before we die so they wont end up in the lava + DoCastSelf(SPELL_EJECT_PASSENGER_3, true); + _pincer1->CastSpell(_pincer1, SPELL_EJECT_PASSENGER_1, true); + _pincer2->CastSpell(_pincer2, SPELL_EJECT_PASSENGER_1, true); + } + } + + void DoAction(int32 action) override + { + switch (action) + { + case ACTION_IMPALE_MAGMAW: + events.CancelEvent(EVENT_MAGMA_PROJECTILE); + events.CancelEvent(EVENT_LAVA_SPEW); + me->AttackStop(); + me->SetReactState(REACT_PASSIVE); + me->CastStop(); + me->RemoveAurasDueToSpell(SPELL_MASSIVE_CRASH); + me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK); + me->RemoveFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_ALLOW_ENEMY_INTERACT); + me->RemoveAurasDueToSpell(SPELL_PILLAR_OF_FLAME_MISSILE_PERIODIC); + + if (Creature* spikeStalker = me->FindNearestCreature(NPC_MAGMAW_SPIKE_STALKER, 60.0f)) + me->SetFacingToObject(spikeStalker); + + events.ScheduleEvent(EVENT_IMPALE_SELF, 1s); + events.ScheduleEvent(EVENT_EXPOSE_HEAD, 4s + 700ms); + _hasExposedHead = true; + break; + case ACTION_FAIL_ACHIEVEMT: + _achievementEnligible = false; + break; + default: + break; + } + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING) && !_hasExposedHead) + return; + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_MAGMA_PROJECTILE: + if (_magmaProjectileCount < 4) + { + DoCastAOE(SPELL_MAGMA_SPIT_TARGETING); + _magmaProjectileCount++; + events.Repeat(6s); + } + else + { + DoCastAOE(SPELL_PILLAR_OF_FLAME); + DoCastAOE(SPELL_PILLAR_OF_FLAME_SET_VEHICLE_ID); + _magmaProjectileCount = 0; + events.Repeat(8s); + } + break; + case EVENT_LAVA_SPEW: + DoCastAOE(SPELL_LAVA_SPEW); + events.Repeat(27s, 28s); + break; + case EVENT_MANGLE: + if (SelectTarget(SELECT_TARGET_RANDOM, 0, NonTankTargetSelector(me))) + DoCastAOE(SPELL_MANGLE_TARGETING); + + events.CancelEvent(EVENT_MAGMA_PROJECTILE); + events.CancelEvent(EVENT_LAVA_SPEW); + events.ScheduleEvent(EVENT_PREPARE_MASSIVE_CRASH, 3s + 500ms); + events.Repeat(1min + 35s); + break; + case EVENT_PREPARE_MASSIVE_CRASH: + if (ObjectGuid guid = instance->GetGuidData(DATA_PREPARE_MASSIVE_CRASH_AND_GET_TARGET_GUID)) + { + if (Creature* stalker = ObjectAccessor::GetCreature(*me, guid)) + { + me->AttackStop(); + me->SetReactState(REACT_PASSIVE); + me->ReleaseSpellFocus(nullptr, false); + me->SetFacingToObject(stalker, true); + events.ScheduleEvent(EVENT_MASSIVE_CRASH, 5s); + } + } + break; + case EVENT_MASSIVE_CRASH: + DoCast(SPELL_MASSIVE_CRASH); + _pincer1->CastSpell(_pincer1, SPELL_EJECT_PASSENGER_1, true); + _pincer2->CastSpell(_pincer2, SPELL_EJECT_PASSENGER_1, true); + break; + case EVENT_ANNOUNCE_PINCERS_EXPOSED: + Talk(SAY_ANNOUNCE_EXPOSE_PINCERS); + break; + case EVENT_FINISH_MASSIVE_CRASH: + me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK); + me->RemoveFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_ALLOW_ENEMY_INTERACT); + me->SetReactState(REACT_AGGRESSIVE); + events.ScheduleEvent(EVENT_LAVA_SPEW, 1ms); + events.ScheduleEvent(EVENT_MAGMA_PROJECTILE, 8s); + break; + case EVENT_IMPALE_SELF: + DoCastSelf(SPELL_IMPALE_SELF); + break; + case EVENT_EXPOSE_HEAD: + if (!_headEngaged) + { + instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, _exposedHead1, 2); + instance->SendEncounterUnit(ENCOUNTER_FRAME_UPDATE_PRIORITY, me); + _headEngaged = true; + } + _exposedHead1->CastSpell(_exposedHead1, SPELL_RIDE_VEHICLE_HEAD, true); + _exposedHead1->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + break; + case EVENT_HIDE_HEAD: + _exposedHead1->CastSpell(_exposedHead1, SPELL_RIDE_VEHICLE_EXPOSED_HEAD, true); + _exposedHead1->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + break; + case EVENT_FINISH_IMPALE_SELF: + _hasExposedHead = false; + me->SetReactState(REACT_AGGRESSIVE); + events.ScheduleEvent(EVENT_LAVA_SPEW, 1ms); + events.ScheduleEvent(EVENT_MAGMA_PROJECTILE, 4s); + break; + default: + break; + } + } + + if (Unit* victim = me->GetVictim()) + { + if (me->IsWithinMeleeRange(victim)) + DoMeleeAttackIfReady(); + else + DoSpellAttackIfReady(SPELL_MAGMA_SPIT_MOLTEN_TANTRUM); + } + } + + private: + void SetupBody() + { + _pincer1 = DoSummon(NPC_MAGMAWS_PINCER_1, me->GetPosition()); + if (_pincer1) + { + _pincer1->EnterVehicle(me, SEAT_MAGMAWS_PINCER_1); + _pincer1->SetDisplayId(_pincer1->GetCreatureTemplate()->Modelid3); + } + + _pincer2 = DoSummon(NPC_MAGMAWS_PINCER_2, me->GetPosition()); + if (_pincer2) + { + _pincer2->EnterVehicle(me, SEAT_MAGMAWS_PINCER_2); + _pincer2->SetDisplayId(_pincer2->GetCreatureTemplate()->Modelid3); + } + + _exposedHead1 = DoSummon(NPC_EXPOSED_HEAD_OF_MAGMAW, ExposedHeadOfMagmawPos); + _exposedHead2 = DoSummon(NPC_EXPOSED_HEAD_OF_MAGMAW_2, me->GetPosition()); + + if (!_exposedHead1 || !_exposedHead2) + return; + + _exposedHead1->SetReactState(REACT_PASSIVE); + _exposedHead2->SetReactState(REACT_PASSIVE); + + _exposedHead2->EnterVehicle(me, SEAT_EXPOSED_HEAD_OF_MAGMAW_2); + DoCastSelf(SPELL_BIRTH); + + // First we link the real exposed head + _exposedHead1->CastSpell(me, SPELL_POINT_OF_VULNERABILITY_SHARE_DAMAGE); + _exposedHead1->CastSpell(_exposedHead1, SPELL_POINT_OF_VULNERABILITY); + _exposedHead1->CastSpell(_exposedHead2, SPELL_POINT_OF_VULNERABILITY_SHARE_DAMAGE); + // ... now the dummy exposed head + _exposedHead2->CastSpell(me, SPELL_POINT_OF_VULNERABILITY_SHARE_DAMAGE); + _exposedHead2->CastSpell(_exposedHead2, SPELL_POINT_OF_VULNERABILITY); + // ... and now Magmaw + DoCast(_exposedHead2, SPELL_POINT_OF_VULNERABILITY_SHARE_DAMAGE); + DoCast(_exposedHead1, SPELL_POINT_OF_VULNERABILITY_SHARE_DAMAGE); + + _exposedHead2->CastSpell(_exposedHead2, SPELL_QUEST_INVIS_5); + + ObjectGuid guid = me->GetGUID(); + Unit* head = _exposedHead1; + head->m_Events.AddEventAtOffset([head, guid]() + { + if (Unit* target = ObjectAccessor::GetUnit(*head, guid)) + head->CastSpell(target, SPELL_RIDE_VEHICLE_EXPOSED_HEAD, true); + }, 1s + 200ms); + } + + Creature* _exposedHead1; + Creature* _exposedHead2; + Creature* _pincer1; + Creature* _pincer2; + uint8 _magmaProjectileCount; + bool _achievementEnligible; + bool _hasExposedHead; + bool _headEngaged; + bool _heroicPhaseTwoActive; + }; + + CreatureAI* GetAI(Creature* creature) const override { - _pincer1 = DoSummon(NPC_MAGMAWS_PINCER_1, me->GetPosition()); - if (_pincer1) - { - _pincer1->EnterVehicle(me, SEAT_MAGMAWS_PINCER_1); - _pincer1->SetDisplayId(_pincer1->GetCreatureTemplate()->Modelid3); - } + return GetBlackwingDescentAI(creature); + } +}; - _pincer2 = DoSummon(NPC_MAGMAWS_PINCER_2, me->GetPosition()); - if (_pincer2) - { - _pincer2->EnterVehicle(me, SEAT_MAGMAWS_PINCER_2); - _pincer2->SetDisplayId(_pincer2->GetCreatureTemplate()->Modelid3); - } +class npc_magmaw_magmaws_pincer : public UnitScript +{ +public: + npc_magmaw_magmaws_pincer() : UnitScript("npc_magmaw_magmaws_pincer") { } - _exposedHead1 = DoSummon(NPC_EXPOSED_HEAD_OF_MAGMAW, ExposedHeadOfMagmawPos); - _exposedHead2 = DoSummon(NPC_EXPOSED_HEAD_OF_MAGMAW_2, me->GetPosition()); - - if (!_exposedHead1 || !_exposedHead2) + void ModifyVehiclePassengerExitPos(Unit* /*passenger*/, Vehicle* vehicle, Position& pos) + { + Unit* base = vehicle->GetBase(); + if (base->GetEntry() != NPC_MAGMAWS_PINCER_1 && base->GetEntry() != NPC_MAGMAWS_PINCER_2) return; - _exposedHead1->SetReactState(REACT_PASSIVE); - _exposedHead2->SetReactState(REACT_PASSIVE); - - _exposedHead2->EnterVehicle(me, SEAT_EXPOSED_HEAD_OF_MAGMAW_2); - DoCastSelf(SPELL_BIRTH); - - // First we link the real exposed head - _exposedHead1->CastSpell(me, SPELL_POINT_OF_VULNERABILITY_SHARE_DAMAGE); - _exposedHead1->CastSpell(_exposedHead1, SPELL_POINT_OF_VULNERABILITY); - _exposedHead1->CastSpell(_exposedHead2, SPELL_POINT_OF_VULNERABILITY_SHARE_DAMAGE); - // ... now the dummy exposed head - _exposedHead2->CastSpell(me, SPELL_POINT_OF_VULNERABILITY_SHARE_DAMAGE); - _exposedHead2->CastSpell(_exposedHead2, SPELL_POINT_OF_VULNERABILITY); - // ... and now Magmaw - DoCast(_exposedHead2, SPELL_POINT_OF_VULNERABILITY_SHARE_DAMAGE); - DoCast(_exposedHead1, SPELL_POINT_OF_VULNERABILITY_SHARE_DAMAGE); - - _exposedHead2->CastSpell(_exposedHead2, SPELL_QUEST_INVIS_5); - - ObjectGuid guid = me->GetGUID(); - Unit* head = _exposedHead1; - head->m_Events.AddEventAtOffset([head, guid]() - { - if (Unit* target = ObjectAccessor::GetUnit(*head, guid)) - head->CastSpell(target, SPELL_RIDE_VEHICLE_EXPOSED_HEAD, true); - }, 1s + 200ms); + pos.Relocate(MagmawVehicleExitPos); } - - Creature* _exposedHead1; - Creature* _exposedHead2; - Creature* _pincer1; - Creature* _pincer2; - uint8 _magmaProjectileCount; - bool _achievementEnligible; - bool _hasExposedHead; - bool _headEngaged; - bool _heroicPhaseTwoActive; }; struct npc_magmaw_nefarian : public ScriptedAI @@ -1044,44 +1078,6 @@ class spell_magmaw_eject_passenger : public SpellScript } }; -class spell_magmaw_eject_passenger_1 : public SpellScript -{ - PrepareSpellScript(spell_magmaw_eject_passenger_1); - - void EjectPassenger(SpellEffIndex /*effIndex*/) - { - if (Vehicle* vehicle = GetHitUnit()->GetVehicleKit()) - { - if (Unit* passenger = vehicle->GetPassenger(SEAT_PINCER)) - passenger->_ExitVehicle(&MagmawVehicleExitPos); - } - } - - void Register() override - { - OnEffectHitTarget += SpellEffectFn(spell_magmaw_eject_passenger_1::EjectPassenger, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); - } -}; - -class spell_magmaw_eject_passenger_3 : public SpellScript -{ - PrepareSpellScript(spell_magmaw_eject_passenger_3); - - void EjectPassenger(SpellEffIndex /*effIndex*/) - { - if (Vehicle* vehicle = GetHitUnit()->GetVehicleKit()) - { - if (Unit* passenger = vehicle->GetPassenger(SEAT_MANGLE)) - passenger->_ExitVehicle(&MagmawVehicleExitPos); - } - } - - void Register() override - { - OnEffectHitTarget += SpellEffectFn(spell_magmaw_eject_passenger_3::EjectPassenger, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); - } -}; - class spell_magmaw_lava_parasite : public AuraScript { PrepareAuraScript(spell_magmaw_lava_parasite); @@ -1237,7 +1233,8 @@ class achievement_parasite_evening : public AchievementCriteriaScript void AddSC_boss_magmaw() { - RegisterBlackwingDescentCreatureAI(boss_magmaw); + new boss_magmaw(); + new npc_magmaw_magmaws_pincer(); RegisterBlackwingDescentCreatureAI(npc_magmaw_nefarian); RegisterBlackwingDescentCreatureAI(npc_magmaw_lava_parasite); RegisterBlackwingDescentCreatureAI(npc_magmaw_blazing_bone_construct); @@ -1248,8 +1245,6 @@ void AddSC_boss_magmaw() RegisterSpellScript(spell_magmaw_ride_vehicle); RegisterAuraScript(spell_magmaw_launch_hook); RegisterSpellScript(spell_magmaw_eject_passenger); - RegisterSpellScript(spell_magmaw_eject_passenger_1); - RegisterSpellScript(spell_magmaw_eject_passenger_3); RegisterAuraScript(spell_magmaw_lava_parasite); RegisterSpellScript(spell_magmaw_lava_parasite_summon); RegisterSpellScript(spell_magmaw_blazing_inferno_targeting); diff --git a/src/server/scripts/Spells/spell_generic.cpp b/src/server/scripts/Spells/spell_generic.cpp index a1976ed2fbc..9ec00ee06bc 100644 --- a/src/server/scripts/Spells/spell_generic.cpp +++ b/src/server/scripts/Spells/spell_generic.cpp @@ -3830,6 +3830,12 @@ class spell_gen_eject_all_passengers : public SpellScriptLoader } }; +enum EjectPassenger +{ + SPELL_GEN_EJECT_PASSENGER_1 = 77946, + SPELL_GEN_EJECT_PASSENGER_3 = 95204 +}; + class spell_gen_eject_passenger : public SpellScriptLoader { public: @@ -3842,7 +3848,17 @@ class spell_gen_eject_passenger : public SpellScriptLoader bool Validate(SpellInfo const* spellInfo) override { if (spellInfo->Effects[EFFECT_0].CalcValue() < 1) + { + switch (spellInfo->Id) + { + case SPELL_GEN_EJECT_PASSENGER_1: + case SPELL_GEN_EJECT_PASSENGER_3: + return ValidateSpellInfo({ spellInfo->Id }); + default: + return false; + } return false; + } return true; } @@ -3850,7 +3866,21 @@ class spell_gen_eject_passenger : public SpellScriptLoader { if (Vehicle* vehicle = GetHitUnit()->GetVehicleKit()) { - if (Unit* passenger = vehicle->GetPassenger(GetEffectValue() - 1)) + uint8 seatId = 0; + switch (GetSpellInfo()->Id) + { + case SPELL_GEN_EJECT_PASSENGER_1: + seatId = 0; + break; + case SPELL_GEN_EJECT_PASSENGER_3: + seatId = 2; + break; + default: + seatId = GetEffectValue() - 1; + break; + } + + if (Unit* passenger = vehicle->GetPassenger(seatId)) passenger->ExitVehicle(); } }