Core/Vehicles: expand vehicle seat addon table implementation to support passenger exit options
This commit is contained in:
1 parent
f336d6032b
commit
dfaa49c87b
8 files changed
+455
-412
No files matched your search
@@ -0,0 +1,26 @@
|
||||
DROP TABLE IF EXISTS `vehicle_seat_addon`;
|
||||
CREATE TABLE `vehicle_seat_addon` (
|
||||
`SeatEntry` INT(4) UNSIGNED NOT NULL COMMENT 'VehicleSeatEntry.dbc identifier',
|
||||
`SeatOrientation` FLOAT(6) DEFAULT 0 COMMENT 'Seat Orientation override value',
|
||||
`ExitParamX` FLOAT(10) DEFAULT 0,
|
||||
`ExitParamY` FLOAT(10) DEFAULT 0,
|
||||
`ExitParamZ` FLOAT(10) DEFAULT 0,
|
||||
`ExitParamO` FLOAT(10) DEFAULT 0,
|
||||
`ExitParamValue` TINYINT(1) DEFAULT 0,
|
||||
PRIMARY KEY (`SeatEntry`)
|
||||
);
|
||||
|
||||
INSERT INTO `vehicle_seat_addon` (`SeatEntry`, `SeatOrientation`, `ExitParamX`, `ExitParamY`, `ExitParamZ`, `ExitParamO`, `ExitParamValue`) VALUES
|
||||
(8372, 3.141592, 0, 0, 0, 0, 0), -- Ozumat
|
||||
(8426, 3.141592, 0, 0, 0, 0, 0), -- Ozumat
|
||||
(8450, 3.141592, 0, 0, 0, 0, 0), -- Ozumat
|
||||
(8451, 3.141592, 0, 0, 0, 0, 0), -- Ozumat
|
||||
(8453, 3.141592, 0, 0, 0, 0, 0), -- Ozumat
|
||||
(8030, 0, -9618.6875, -1030.1104, 41.684166, 4.847490787, 2), -- Stormwind Charger Seat 1
|
||||
(7936, 0, -311.4653, -48.59722, 212.8065, 1.064651, 2), -- Magmaw Seat 3
|
||||
(8104, 0, -311.4653, -48.59722, 212.8065, 1.064651, 2), -- Magmaw' Pincer Seat 1
|
||||
(7909, 0, -311.4653, -48.59722, 212.8065, 1.064651, 2), -- Magmaw' Pincer Seat 1
|
||||
(2764, 0, -2, 2, 0, 0, 1), -- Traveler's Tundra Mammoth Seat 2
|
||||
(2765, 0, -2, -2, 0, 0, 1), -- Traveler's Tundra Mammoth Seat 3
|
||||
(2767, 0, -2, 2, 0, 0, 1), -- Traveler's Tundra Mammoth Seat 2
|
||||
(2768, 0, -2, -2, 0, 0, 1); -- Traveler's Tundra Mammoth Seat 3
|
||||
@@ -13465,8 +13465,8 @@ void Unit::_ExitVehicle(Position const* exitPosition)
|
||||
return;
|
||||
|
||||
// This should be done before dismiss, because there may be some aura removal
|
||||
VehicleSeatAddon const seatAddon = m_vehicle->GetSeatAddonForSeatOfPassenger(this);
|
||||
Vehicle* vehicle = m_vehicle->RemovePassenger(this);
|
||||
|
||||
Player* player = ToPlayer();
|
||||
|
||||
// If the player is on mounted duel and exits the mount, he should immediatly lose the duel
|
||||
@@ -13489,7 +13489,12 @@ void Unit::_ExitVehicle(Position const* exitPosition)
|
||||
// Set exit position to vehicle position and use the current orientation
|
||||
pos = vehicle->GetBase()->GetPosition();
|
||||
pos.SetOrientation(GetOrientation());
|
||||
sScriptMgr->ModifyVehiclePassengerExitPos(this, vehicle, pos);
|
||||
|
||||
// Change exit position based on seat entry
|
||||
if (seatAddon.ExitParameter == VehicleExitParameters::VehicleExitParamOffset)
|
||||
pos.RelocateOffset({ seatAddon.ExitParameterX, seatAddon.ExitParameterY, seatAddon.ExitParameterZ, seatAddon.ExitParameterO });
|
||||
else if (seatAddon.ExitParameter == VehicleExitParameters::VehicleExitParamDest)
|
||||
pos.Relocate({ seatAddon.ExitParameterX, seatAddon.ExitParameterY, seatAddon.ExitParameterZ, seatAddon.ExitParameterO });
|
||||
}
|
||||
|
||||
float height = pos.GetPositionZ() + vehicle->GetBase()->GetCollisionHeight();
|
||||
|
||||
@@ -41,7 +41,8 @@ UsableSeatNum(0), _me(unit), _vehicleInfo(vehInfo), _creatureEntry(creatureEntry
|
||||
if (uint32 seatId = _vehicleInfo->SeatID[i])
|
||||
if (VehicleSeatEntry const* veSeat = sVehicleSeatStore.LookupEntry(seatId))
|
||||
{
|
||||
Seats.insert(std::make_pair(i, VehicleSeat(veSeat)));
|
||||
VehicleSeatAddon addon = sObjectMgr->GetVehicleSeatAddon(seatId);
|
||||
Seats.insert(std::make_pair(i, VehicleSeat(veSeat, addon)));
|
||||
if (veSeat->CanEnterOrExit())
|
||||
++UsableSeatNum;
|
||||
}
|
||||
@@ -395,6 +396,17 @@ SeatMap::const_iterator Vehicle::GetNextEmptySeat(int8 seatId, bool next) const
|
||||
return seat;
|
||||
}
|
||||
|
||||
VehicleSeatAddon const Vehicle::GetSeatAddonForSeatOfPassenger(Unit const* passenger) const
|
||||
{
|
||||
for (SeatMap::const_iterator itr = Seats.begin(); itr != Seats.end(); itr++)
|
||||
{
|
||||
if (!itr->second.IsEmpty() && itr->second.Passenger.Guid == passenger->GetGUID())
|
||||
return itr->second.SeatAddon;
|
||||
}
|
||||
|
||||
return VehicleSeatAddon();
|
||||
}
|
||||
|
||||
/**
|
||||
* @fn void Vehicle::InstallAccessory(uint32 entry, int8 seatId, bool minion, uint8 type,
|
||||
* uint32 summonTime)
|
||||
@@ -861,6 +873,7 @@ bool VehicleJoinEvent::Execute(uint64, uint32)
|
||||
Passenger->RemoveAurasByType(SPELL_AURA_MOUNTED);
|
||||
|
||||
VehicleSeatEntry const* veSeat = Seat->second.SeatInfo;
|
||||
VehicleSeatAddon const veSeatAddon = Seat->second.SeatAddon;
|
||||
|
||||
Player* player = Passenger->ToPlayer();
|
||||
if (player)
|
||||
@@ -882,8 +895,7 @@ bool VehicleJoinEvent::Execute(uint64, uint32)
|
||||
if (veSeat->HasFlag(VEHICLE_SEAT_FLAG_PASSENGER_NOT_SELECTABLE))
|
||||
Passenger->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
|
||||
|
||||
float o = sObjectMgr->GetVehicleSeatOrientationOffset(veSeat->ID);
|
||||
|
||||
float o = veSeatAddon.SeatOrientationOffset;
|
||||
float x = veSeat->AttachmentOffset.X;
|
||||
float y = veSeat->AttachmentOffset.Y;
|
||||
float z = veSeat->AttachmentOffset.Z;
|
||||
|
||||
@@ -52,10 +52,10 @@ class TC_GAME_API Vehicle : public TransportBase
|
||||
bool HasEmptySeat(int8 seatId) const;
|
||||
Unit* GetPassenger(int8 seatId) const;
|
||||
SeatMap::const_iterator GetNextEmptySeat(int8 seatId, bool next) const;
|
||||
VehicleSeatAddon const GetSeatAddonForSeatOfPassenger(Unit const* passenger) const;
|
||||
uint8 GetAvailableSeatCount() const;
|
||||
|
||||
bool AddPassenger(Unit* passenger, int8 seatId = -1);
|
||||
void EjectPassenger(Unit* passenger, Unit* controller);
|
||||
Vehicle* RemovePassenger(Unit* passenger);
|
||||
void RelocatePassengers();
|
||||
void RemoveAllPassengers();
|
||||
|
||||
@@ -75,6 +75,14 @@ enum VehicleSpells
|
||||
VEHICLE_SPELL_PARACHUTE = 45472
|
||||
};
|
||||
|
||||
enum class VehicleExitParameters
|
||||
{
|
||||
VehicleExitParamNone, // provided parameters will be ignored
|
||||
VehicleExitParamOffset, // provided parameters will be used as offset values
|
||||
VehicleExitParamDest, // provided parameters will be used as absolute destination
|
||||
VehicleExitParamMax
|
||||
};
|
||||
|
||||
struct PassengerInfo
|
||||
{
|
||||
PassengerInfo() : IsUnselectable(false) { }
|
||||
@@ -89,9 +97,24 @@ struct PassengerInfo
|
||||
}
|
||||
};
|
||||
|
||||
struct VehicleSeatAddon
|
||||
{
|
||||
VehicleSeatAddon() { }
|
||||
VehicleSeatAddon(float orientatonOffset, float exitX, float exitY, float exitZ, float exitO, uint8 param) :
|
||||
SeatOrientationOffset(orientatonOffset), ExitParameterX(exitX), ExitParameterY(exitY), ExitParameterZ(exitZ),
|
||||
ExitParameterO(exitO), ExitParameter(VehicleExitParameters(param)) { }
|
||||
|
||||
float SeatOrientationOffset = 0.f;
|
||||
float ExitParameterX = 0.f;
|
||||
float ExitParameterY = 0.f;
|
||||
float ExitParameterZ = 0.f;
|
||||
float ExitParameterO = 0.f;
|
||||
VehicleExitParameters ExitParameter = VehicleExitParameters::VehicleExitParamNone;
|
||||
};
|
||||
|
||||
struct VehicleSeat
|
||||
{
|
||||
explicit VehicleSeat(VehicleSeatEntry const* seatInfo) : SeatInfo(seatInfo)
|
||||
explicit VehicleSeat(VehicleSeatEntry const* seatInfo, VehicleSeatAddon const seatAddon) : SeatInfo(seatInfo), SeatAddon(seatAddon)
|
||||
{
|
||||
Passenger.Reset();
|
||||
}
|
||||
@@ -99,6 +122,7 @@ struct VehicleSeat
|
||||
bool IsEmpty() const { return Passenger.Guid.IsEmpty(); }
|
||||
|
||||
VehicleSeatEntry const* SeatInfo;
|
||||
VehicleSeatAddon const SeatAddon;
|
||||
PassengerInfo Passenger;
|
||||
};
|
||||
|
||||
|
||||
@@ -3347,8 +3347,8 @@ void ObjectMgr::LoadVehicleSeatAddon()
|
||||
|
||||
uint32 count = 0;
|
||||
|
||||
// 0 1
|
||||
QueryResult result = WorldDatabase.Query("SELECT `SeatID`, `Angle` FROM `vehicle_seat_addon`");
|
||||
// 0 1
|
||||
QueryResult result = WorldDatabase.Query("SELECT `SeatEntry`, `SeatOrientation`, `ExitParamX`, `ExitParamY`, `ExitParamZ`, `ExitParamO`, `ExitParamValue` FROM `vehicle_seat_addon`");
|
||||
|
||||
if (!result)
|
||||
{
|
||||
@@ -3361,7 +3361,12 @@ void ObjectMgr::LoadVehicleSeatAddon()
|
||||
Field* fields = result->Fetch();
|
||||
|
||||
uint32 seatID = fields[0].GetUInt32();
|
||||
float orientation = fields[1].GetFloat() * float(M_PI) / 180;
|
||||
float orientation = fields[1].GetFloat();
|
||||
float exitX = fields[2].GetFloat();
|
||||
float exitY = fields[3].GetFloat();
|
||||
float exitZ = fields[4].GetFloat();
|
||||
float exitO = fields[5].GetFloat();
|
||||
uint8 exitParam = fields[6].GetUInt8();
|
||||
|
||||
if (!sVehicleSeatStore.LookupEntry(seatID))
|
||||
{
|
||||
@@ -3372,12 +3377,18 @@ void ObjectMgr::LoadVehicleSeatAddon()
|
||||
// Sanitizing values
|
||||
if (orientation > float(M_PI * 2))
|
||||
{
|
||||
TC_LOG_ERROR("sql.sql", "Table `vehicle_seat_addon`: SeatID: %u is using invalid angle offset value (%f). Setting to 0.", seatID, fields[1].GetFloat());
|
||||
TC_LOG_ERROR("sql.sql", "Table `vehicle_seat_addon`: SeatID: %u is using invalid angle offset value (%f). Setting to 0.", seatID, orientation);
|
||||
orientation = 0.0f;
|
||||
continue;
|
||||
}
|
||||
|
||||
_vehicleSeatAddonStore.emplace(seatID, orientation);
|
||||
if (exitParam >= AsUnderlyingType(VehicleExitParameters::VehicleExitParamMax))
|
||||
{
|
||||
TC_LOG_ERROR("sql.sql", "Table `vehicle_seat_addon`: SeatID: %u is using invalid exit parameter value (%u). Setting to 0 (none).", seatID, exitParam);
|
||||
continue;
|
||||
}
|
||||
|
||||
_vehicleSeatAddonStore[seatID] = VehicleSeatAddon(orientation, exitX, exitY, exitZ, exitO, exitParam);
|
||||
|
||||
++count;
|
||||
}
|
||||
|
||||
@@ -560,7 +560,7 @@ typedef std::unordered_map<uint32, QuestLocale> QuestLocaleContainer;
|
||||
typedef std::unordered_map<uint32, NpcTextLocale> NpcTextLocaleContainer;
|
||||
typedef std::unordered_map<uint32, PageTextLocale> PageTextLocaleContainer;
|
||||
typedef std::unordered_map<uint32, uint8> TaxiNodeLevelDataContainer;
|
||||
typedef std::unordered_map<uint32, float> VehicleSeatAddonContainer;
|
||||
typedef std::unordered_map<uint32, VehicleSeatAddon> VehicleSeatAddonContainer;
|
||||
|
||||
struct GossipMenuItemsLocale
|
||||
{
|
||||
@@ -1557,13 +1557,13 @@ class TC_GAME_API ObjectMgr
|
||||
|
||||
uint32 GetGameObjectTypeByEntry(uint32 entry) const;
|
||||
|
||||
float GetVehicleSeatOrientationOffset(uint32 seatId) const
|
||||
VehicleSeatAddon const GetVehicleSeatAddon(uint32 seatId) const
|
||||
{
|
||||
VehicleSeatAddonContainer::const_iterator itr = _vehicleSeatAddonStore.find(seatId);
|
||||
if (itr != _vehicleSeatAddonStore.end())
|
||||
return itr->second;
|
||||
if (itr == _vehicleSeatAddonStore.end())
|
||||
return VehicleSeatAddon();
|
||||
|
||||
return 0.0f;
|
||||
return itr->second;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
+360
-395
@@ -174,421 +174,387 @@ Position const NefarianIntroSummonPos = { -390.1042f, 40.88411f, 207.8586f, 0
|
||||
|
||||
#define SPELL_PARASITIC_INFECTION_PERIODIC_DAMAGE RAID_MODE<uint32>(78941, 91913, 94678, 94679)
|
||||
|
||||
class boss_magmaw : public CreatureScript, public UnitScript
|
||||
struct boss_magmaw : public BossAI
|
||||
{
|
||||
public:
|
||||
boss_magmaw() : CreatureScript("boss_magmaw"), UnitScript("boss_magmaw_vehicle") { }
|
||||
|
||||
void ModifyVehiclePassengerExitPos(Unit* /*passenger*/, Vehicle* vehicle, Position& pos) override
|
||||
boss_magmaw(Creature* creature) : BossAI(creature, DATA_MAGMAW)
|
||||
{
|
||||
if (vehicle->GetBase()->GetEntry() != BOSS_MAGMAW)
|
||||
return;
|
||||
|
||||
pos.Relocate(MagmawVehicleExitPos);
|
||||
Initialize();
|
||||
}
|
||||
|
||||
struct boss_magmawAI : public BossAI
|
||||
void Initialize()
|
||||
{
|
||||
boss_magmawAI(Creature* creature) : BossAI(creature, DATA_MAGMAW)
|
||||
_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())
|
||||
{
|
||||
Initialize();
|
||||
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;
|
||||
}
|
||||
|
||||
void Initialize()
|
||||
return ObjectGuid::Empty;
|
||||
}
|
||||
|
||||
void DamageTaken(Unit* /*attacker*/, uint32& damage) override
|
||||
{
|
||||
if (me->HealthBelowPctDamaged(30, damage) && !_heroicPhaseTwoActive)
|
||||
{
|
||||
_magmaProjectileCount = 0;
|
||||
_exposedHead1 = nullptr;
|
||||
_exposedHead2 = nullptr;
|
||||
_pincer1 = nullptr;
|
||||
_pincer2 = nullptr;
|
||||
_hasExposedHead = false;
|
||||
_headEngaged = false;
|
||||
_achievementEnligible = true;
|
||||
_heroicPhaseTwoActive = !IsHeroic();
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
if (Creature* nefarian = instance->GetCreature(DATA_NEFARIAN_MAGMAW))
|
||||
nefarian->AI()->DoAction(ACTION_SCHEDULE_SHADOW_BREATH);
|
||||
_heroicPhaseTwoActive = true;
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
if (damage >= me->GetHealth())
|
||||
{
|
||||
_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);
|
||||
|
||||
// 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);
|
||||
|
||||
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())
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
return GetBlackwingDescentAI<boss_magmawAI>(creature);
|
||||
}
|
||||
};
|
||||
|
||||
class npc_magmaw_magmaws_pincer : public UnitScript
|
||||
{
|
||||
public:
|
||||
npc_magmaw_magmaws_pincer() : UnitScript("npc_magmaw_magmaws_pincer") { }
|
||||
|
||||
void ModifyVehiclePassengerExitPos(Unit* /*passenger*/, Vehicle* vehicle, Position& pos)
|
||||
void DoAction(int32 action) override
|
||||
{
|
||||
Unit* base = vehicle->GetBase();
|
||||
if (base->GetEntry() != NPC_MAGMAWS_PINCER_1 && base->GetEntry() != NPC_MAGMAWS_PINCER_2)
|
||||
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;
|
||||
|
||||
pos.Relocate(MagmawVehicleExitPos);
|
||||
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;
|
||||
};
|
||||
|
||||
struct npc_magmaw_nefarian : public ScriptedAI
|
||||
@@ -1233,8 +1199,7 @@ class achievement_parasite_evening : public AchievementCriteriaScript
|
||||
|
||||
void AddSC_boss_magmaw()
|
||||
{
|
||||
new boss_magmaw();
|
||||
new npc_magmaw_magmaws_pincer();
|
||||
RegisterBlackwingDescentCreatureAI(boss_magmaw);
|
||||
RegisterBlackwingDescentCreatureAI(npc_magmaw_nefarian);
|
||||
RegisterBlackwingDescentCreatureAI(npc_magmaw_lava_parasite);
|
||||
RegisterBlackwingDescentCreatureAI(npc_magmaw_blazing_bone_construct);
|
||||
|
||||
Reference in new issue
Block a user