Scripts/BWD: store Magmaw's body parts via guids instead of smelly pointers and validate the body parts on engage

This commit is contained in:
Ovahlord committed 2020-09-10 21:15:07 +02:00
1 parent d78cfb2843
commit 44f89c7dae
1 file changed
+101 -54
@@ -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<ObjectGuid, MAX_BODY_PARTS> _bodyPartGUIDs;
uint8 _magmaProjectileCount;
bool _achievementEnligible;
bool _headEngaged;