From 44f89c7dae7f399d7c8437087c8e9e35c62b848b Mon Sep 17 00:00:00 2001 From: Ovahlord Date: Thu, 10 Sep 2020 21:15:07 +0200 Subject: [PATCH] Scripts/BWD: store Magmaw's body parts via guids instead of smelly pointers and validate the body parts on engage --- .../BlackwingDescent/boss_magmaw.cpp | 155 ++++++++++++------ 1 file changed, 101 insertions(+), 54 deletions(-) diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingDescent/boss_magmaw.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingDescent/boss_magmaw.cpp index 2e5aa0f93c..83cca1db70 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingDescent/boss_magmaw.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingDescent/boss_magmaw.cpp @@ -194,6 +194,15 @@ enum EncounterFramePriorities FRAME_PRIORITY_EXPOSED_HEAD_OF_MAGMAW = 2 }; +enum BodyParts : uint8 +{ + BODY_PART_EXPOSED_HEAD_1 = 0, + BODY_PART_EXPOSED_HEAD_2, + BODY_PART_PINCER_1, + BODY_PART_PINCER_2, + MAX_BODY_PARTS +}; + Position const ExposedHeadOfMagmawPos = { -299.0f, -28.9861f, 191.0293f, 4.118977f }; Position const NefarianIntroSummonPos = { -390.1042f, 40.88411f, 207.8586f, 0.196609f }; @@ -203,8 +212,7 @@ Position const NefarianIntroSummonPos = { -390.1042f, 40.88411f, 207.8586f, 0 struct boss_magmaw : public BossAI { boss_magmaw(Creature* creature) : BossAI(creature, DATA_MAGMAW), - _exposedHead1(nullptr), _exposedHead2(nullptr), _pincer1(nullptr), _pincer2(nullptr), _magmaProjectileCount(0), - _achievementEnligible(true), _headEngaged(false), _heroicPhaseTwoActive(!IsHeroic()) + _magmaProjectileCount(0), _achievementEnligible(true), _headEngaged(false), _heroicPhaseTwoActive(!IsHeroic()) { me->SetReactState(REACT_PASSIVE); } @@ -217,6 +225,16 @@ struct boss_magmaw : public BossAI void JustEngagedWith(Unit* who) override { + // Sanity checks if the body has been successfully set up + for (uint8 i = BODY_PART_EXPOSED_HEAD_1; i < MAX_BODY_PARTS; ++i) + { + if (!GetBodyPart(BodyParts(i))) + { + EnterEvadeMode(EVADE_REASON_OTHER); + break; + } + } + BossAI::JustEngagedWith(who); instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, me, FRAME_PRIORITY_MAGMAW); me->SetReactState(REACT_AGGRESSIVE); @@ -254,17 +272,21 @@ struct boss_magmaw : public BossAI { _EnterEvadeMode(); instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me); - if (_headEngaged) - instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, _exposedHead1); + + Creature* head = GetBodyPart(BODY_PART_EXPOSED_HEAD_1); + if (_headEngaged && head) + instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, head); DoCastSelf(SPELL_EJECT_PASSENGER_3, true); - _pincer1->CastSpell(_pincer1, SPELL_EJECT_PASSENGER_1, true); - _pincer2->CastSpell(_pincer2, SPELL_EJECT_PASSENGER_1, true); + for (BodyParts part : { BODY_PART_PINCER_1, BODY_PART_PINCER_2 }) + if (Creature* pincer = GetBodyPart(part)) + pincer->CastSpell(pincer, 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(); + if (head) + head->DespawnOrUnsummon(); summons.DespawnAll(); if (Creature* nefarian = instance->GetCreature(DATA_NEFARIAN_MAGMAW)) @@ -274,8 +296,9 @@ struct boss_magmaw : public BossAI void JustDied(Unit* /*killer*/) override { - if (_headEngaged) - instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, _exposedHead1); + if (Creature* head = GetBodyPart(BODY_PART_EXPOSED_HEAD_1)) + if (_headEngaged) + instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, head); instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_PARASITIC_INFECTION_VOMIT); instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_PARASITIC_INFECTION_PERIODIC_DAMAGE); @@ -320,10 +343,10 @@ struct boss_magmaw : public BossAI 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(); + for (BodyParts part : { BODY_PART_PINCER_1, BODY_PART_PINCER_2 }) + if (Creature* pincer = GetBodyPart(part)) + if (pincer->GetVehicleKit() && pincer->GetVehicleKit()->GetAvailableSeatCount()) + return pincer->GetGUID(); break; default: return ObjectGuid::Empty; @@ -345,8 +368,10 @@ struct boss_magmaw : public BossAI { // 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); + + for (BodyParts part : { BODY_PART_PINCER_1, BODY_PART_PINCER_2 }) + if (Creature* pincer = GetBodyPart(part)) + pincer->CastSpell(pincer, SPELL_EJECT_PASSENGER_1, true); } } @@ -371,9 +396,13 @@ struct boss_magmaw : public BossAI case ACTION_ENABLE_MOUNTING: 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); + + if (Creature* head = GetBodyPart(BODY_PART_EXPOSED_HEAD_1)) + head->CastSpell(head, SPELL_RIDE_VEHICLE_HEAD, true); + + for (BodyParts part : { BODY_PART_PINCER_1, BODY_PART_PINCER_2 }) + if (Creature* pincer = GetBodyPart(part)) + pincer->CastSpell(pincer, SPELL_EJECT_PASSENGER_1, true); events.ScheduleEvent(EVENT_ANNOUNCE_PINCERS_EXPOSED, 1s, 0, PHASE_COMBAT); break; case ACTION_DISABLE_MOUNTING: @@ -396,8 +425,12 @@ struct boss_magmaw : public BossAI case ACTION_COVER_HEAD: events.SetPhase(PHASE_COMBAT); events.ScheduleEvent(EVENT_FINISH_IMPALE_SELF, 3s, 0, PHASE_COMBAT); - _exposedHead1->CastSpell(_exposedHead1, SPELL_RIDE_VEHICLE_EXPOSED_HEAD, true); - _exposedHead1->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + + if (Creature* head = GetBodyPart(BODY_PART_EXPOSED_HEAD_1)) + { + head->CastSpell(head, SPELL_RIDE_VEHICLE_EXPOSED_HEAD, true); + head->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + } break; case ACTION_FAIL_ACHIEVEMT: _achievementEnligible = false; @@ -469,8 +502,9 @@ struct boss_magmaw : public BossAI 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); + for (BodyParts part : { BODY_PART_PINCER_1, BODY_PART_PINCER_2 }) + if (Creature* pincer = GetBodyPart(part)) + pincer->CastSpell(pincer, SPELL_EJECT_PASSENGER_1, true); break; case EVENT_ANNOUNCE_PINCERS_EXPOSED: Talk(SAY_ANNOUNCE_EXPOSE_PINCERS); @@ -480,13 +514,16 @@ struct boss_magmaw : public BossAI events.ScheduleEvent(EVENT_SHOW_HEAD, 5s, 0, PHASE_IMPALED); break; case EVENT_SHOW_HEAD: - if (!_headEngaged) + if (Creature* head = GetBodyPart(BODY_PART_EXPOSED_HEAD_1)) { - instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, _exposedHead1, FRAME_PRIORITY_EXPOSED_HEAD_OF_MAGMAW); - _headEngaged = true; + if (!_headEngaged) + { + instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, head, FRAME_PRIORITY_EXPOSED_HEAD_OF_MAGMAW); + _headEngaged = true; + } + head->CastSpell(head, SPELL_RIDE_VEHICLE_HEAD, true); + head->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); } - _exposedHead1->CastSpell(_exposedHead1, SPELL_RIDE_VEHICLE_HEAD, true); - _exposedHead1->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); break; case EVENT_FINISH_IMPALE_SELF: me->SetReactState(REACT_AGGRESSIVE); @@ -504,47 +541,55 @@ struct boss_magmaw : public BossAI private: void SetupBody() { - _pincer1 = DoSummon(NPC_MAGMAWS_PINCER_1, me->GetPosition()); - if (_pincer1) + Creature* pincer1 = DoSummon(NPC_MAGMAWS_PINCER_1, me->GetPosition()); + if (pincer1) { - _pincer1->EnterVehicle(me, SEAT_MAGMAWS_PINCER_1); - _pincer1->SetDisplayId(_pincer1->GetCreatureTemplate()->Modelid3); + pincer1->EnterVehicle(me, SEAT_MAGMAWS_PINCER_1); + pincer1->SetDisplayId(pincer1->GetCreatureTemplate()->Modelid3); + _bodyPartGUIDs[BODY_PART_PINCER_1] = pincer1->GetGUID(); } - _pincer2 = DoSummon(NPC_MAGMAWS_PINCER_2, me->GetPosition()); - if (_pincer2) + Creature* pincer2 = DoSummon(NPC_MAGMAWS_PINCER_2, me->GetPosition()); + if (pincer2) { - _pincer2->EnterVehicle(me, SEAT_MAGMAWS_PINCER_2); - _pincer2->SetDisplayId(_pincer2->GetCreatureTemplate()->Modelid3); + pincer2->EnterVehicle(me, SEAT_MAGMAWS_PINCER_2); + pincer2->SetDisplayId(pincer2->GetCreatureTemplate()->Modelid3); + _bodyPartGUIDs[BODY_PART_PINCER_2] = pincer2->GetGUID(); } - _exposedHead1 = DoSummon(NPC_EXPOSED_HEAD_OF_MAGMAW, ExposedHeadOfMagmawPos); - _exposedHead2 = DoSummon(NPC_EXPOSED_HEAD_OF_MAGMAW_2, me->GetPosition()); + Creature* exposedHead1 = DoSummon(NPC_EXPOSED_HEAD_OF_MAGMAW, ExposedHeadOfMagmawPos); + Creature* exposedHead2 = DoSummon(NPC_EXPOSED_HEAD_OF_MAGMAW_2, me->GetPosition()); - if (!_exposedHead1 || !_exposedHead2) + if (!exposedHead1 || !exposedHead2) + { + summons.DespawnAll(); return; + } - _exposedHead1->SetReactState(REACT_PASSIVE); - _exposedHead2->SetReactState(REACT_PASSIVE); + _bodyPartGUIDs[BODY_PART_EXPOSED_HEAD_1] = exposedHead1->GetGUID(); + _bodyPartGUIDs[BODY_PART_EXPOSED_HEAD_2] = exposedHead2->GetGUID(); - _exposedHead2->EnterVehicle(me, SEAT_EXPOSED_HEAD_OF_MAGMAW_2); + 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); + 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); + 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); + DoCast(exposedHead2, SPELL_POINT_OF_VULNERABILITY_SHARE_DAMAGE); + DoCast(exposedHead1, SPELL_POINT_OF_VULNERABILITY_SHARE_DAMAGE); - _exposedHead2->CastSpell(_exposedHead2, SPELL_QUEST_INVIS_5); + exposedHead2->CastSpell(exposedHead2, SPELL_QUEST_INVIS_5); ObjectGuid guid = me->GetGUID(); - Unit* head = _exposedHead1; + Unit* head = exposedHead1; head->m_Events.AddEventAtOffset([head, guid]() { if (Unit* target = ObjectAccessor::GetUnit(*head, guid)) @@ -552,10 +597,12 @@ private: }, 1s + 200ms); } - Creature* _exposedHead1; - Creature* _exposedHead2; - Creature* _pincer1; - Creature* _pincer2; + Creature* GetBodyPart(BodyParts part) const + { + return ObjectAccessor::GetCreature(*me, _bodyPartGUIDs[part]); + } + + std::array _bodyPartGUIDs; uint8 _magmaProjectileCount; bool _achievementEnligible; bool _headEngaged;