Core/Battlegrounds: Moved AreaSpiritHealer resurrection handling to respective npc flags (#28508)

* UNIT_NPC_FLAG_AREA_SPIRIT_HEALER
* UNIT_NPC_FLAG_2_AREA_SPIRIT_HEALER_INDIVIDUAL
This commit is contained in:
Jeremy
2023-05-09 05:20:35 +02:00
committed by GitHub
parent dc28475096
commit 205aba1ff3
26 changed files with 312 additions and 415 deletions
@@ -0,0 +1,29 @@
UPDATE `creature_template_addon` SET `auras`='9036 9617' WHERE `entry`=13117; -- 13117 (Horde Spirit Guide) - Ghost, Ghost Visual
UPDATE `creature_template_addon` SET `auras`='9036 9617' WHERE `entry`=13116; -- 13116 (Alliance Spirit Guide) - Ghost, Ghost Visual
UPDATE `creature_template` SET `ScriptName`='', `AIName`='' WHERE `entry` IN (13116, 13117, 88238, 88239); -- BGs
-- allow the graveyard teleporters to see dead players
UPDATE `creature_template` SET `flags_extra` = `flags_extra`|0x00000400 WHERE `entry` IN (26350, 26351);
-- Graveyard Teleport
DELETE FROM `serverside_spell_effect` WHERE `SpellID` = 46893;
INSERT INTO `serverside_spell_effect` (`SpellID`, `EffectIndex`, `DifficultyID`, `Effect`, `EffectAura`, `EffectAmplitude`, `EffectAttributes`, `EffectAuraPeriod`, `EffectBonusCoefficient`, `EffectChainAmplitude`, `EffectChainTargets`, `EffectItemType`, `EffectMechanic`, `EffectPointsPerResource`, `EffectPosFacing`, `EffectRealPointsPerLevel`, `EffectTriggerSpell`, `BonusCoefficientFromAP`, `PvpMultiplier`, `Coefficient`, `Variance`, `ResourceCoefficient`, `GroupSizeBasePointsCoefficient`, `EffectBasePoints`, `EffectMiscValue1`, `EffectMiscValue2`, `EffectRadiusIndex1`, `EffectRadiusIndex2`, `EffectSpellClassMask1`, `EffectSpellClassMask2`, `EffectSpellClassMask3`, `EffectSpellClassMask4`, `ImplicitTarget1`, `ImplicitTarget2`) VALUES
(46893, 0, 0, 120, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 22, 30);
DELETE FROM `spell_script_names` WHERE `ScriptName` IN ('spell_gen_spirit_heal_aoe', 'spell_gen_spirit_heal_personal', 'spell_gen_spirit_heal_channel', 'spell_gen_waiting_to_resurrect');
INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES
(22012, 'spell_gen_spirit_heal_aoe'),
(156758, 'spell_gen_spirit_heal_personal'),
(22011, 'spell_gen_spirit_heal_channel'),
(2584, 'spell_gen_waiting_to_resurrect');
DELETE FROM `creature_template_addon` WHERE `entry` IN (26350, 26351);
INSERT INTO `creature_template_addon` (`entry`, `path_id`, `mount`, `StandState`, `AnimTier`, `VisFlags`, `SheathState`, `PvPFlags`, `emote`, `aiAnimKit`, `movementAnimKit`, `meleeAnimKit`, `visibilityDistanceType`, `auras`) VALUES
(26350, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, '8149'), -- 26350 (Alliance Graveyard Teleporter) - Super Invis
(26351, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, '8149'); -- 26351 (Horde Graveyard Teleporter) - Super Invis
UPDATE `creature_template` SET `ScriptName`='', `AIName`='SmartAI' WHERE `entry` IN(26350, 26351);
DELETE FROM `smart_scripts` WHERE `entryorguid` IN(26350, 26351) AND `source_type`=0;
INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param_string`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
(26350,0,0,0,11,0,100,0,0,0,0,0,0,'',11,46893,0,0,0,0,0,1,0,0,0,0,0,0,0,0,'Alliance Graveyard Teleporter - On spawn - Cast "Graveyard Teleport"'),
(26351,0,0,0,11,0,100,0,0,0,0,0,0,'',11,46893,0,0,0,0,0,1,0,0,0,0,0,0,0,0,'Horde Graveyard Teleporter - On spawn - Cast "Graveyard Teleport"');
+3 -120
View File
@@ -56,7 +56,6 @@ Battlefield::Battlefield(Map* map)
m_uiKickAfkPlayersTimer = 1000;
m_LastResurrectTimer = 30 * IN_MILLISECONDS;
m_StartGroupingTimer = 0;
m_StartGrouping = false;
}
@@ -122,7 +121,6 @@ void Battlefield::HandlePlayerLeaveZone(Player* player, uint32 /*zone*/)
m_PlayersWillBeKick[player->GetTeamId()].erase(player->GetGUID());
m_players[player->GetTeamId()].erase(player->GetGUID());
SendRemoveWorldStates(player);
RemovePlayerFromResurrectQueue(player->GetGUID());
OnPlayerLeaveZone(player);
}
@@ -183,16 +181,6 @@ bool Battlefield::Update(uint32 diff)
objective_changed = true;
}
if (m_LastResurrectTimer <= diff)
{
for (uint8 i = 0; i < m_GraveyardList.size(); i++)
if (GetGraveyardById(i))
m_GraveyardList[i]->Resurrect();
m_LastResurrectTimer = RESURRECTION_INTERVAL;
}
else
m_LastResurrectTimer -= diff;
return objective_changed;
}
@@ -596,44 +584,6 @@ WorldSafeLocsEntry const* Battlefield::GetClosestGraveyard(Player* player)
return nullptr;
}
void Battlefield::AddPlayerToResurrectQueue(ObjectGuid npcGuid, ObjectGuid playerGuid)
{
for (uint8 i = 0; i < m_GraveyardList.size(); i++)
{
if (!m_GraveyardList[i])
continue;
if (m_GraveyardList[i]->HasNpc(npcGuid))
{
m_GraveyardList[i]->AddPlayer(playerGuid);
break;
}
}
}
void Battlefield::RemovePlayerFromResurrectQueue(ObjectGuid playerGuid)
{
for (uint8 i = 0; i < m_GraveyardList.size(); i++)
{
if (!m_GraveyardList[i])
continue;
if (m_GraveyardList[i]->HasPlayer(playerGuid))
{
m_GraveyardList[i]->RemovePlayer(playerGuid);
break;
}
}
}
void Battlefield::SendAreaSpiritHealerQueryOpcode(Player* player, ObjectGuid const& guid)
{
WorldPackets::Battleground::AreaSpiritHealerTime areaSpiritHealerTime;
areaSpiritHealerTime.HealerGuid = guid;
areaSpiritHealerTime.TimeLeft = m_LastResurrectTimer;
player->SendDirectMessage(areaSpiritHealerTime.Write());
}
// ----------------------
// - BfGraveyard Method -
// ----------------------
@@ -668,54 +618,6 @@ float BfGraveyard::GetDistance(Player* player)
return player->GetDistance2d(safeLoc->Loc.GetPositionX(), safeLoc->Loc.GetPositionY());
}
void BfGraveyard::AddPlayer(ObjectGuid playerGuid)
{
if (!m_ResurrectQueue.count(playerGuid))
{
m_ResurrectQueue.insert(playerGuid);
if (Player* player = ObjectAccessor::FindPlayer(playerGuid))
player->CastSpell(player, SPELL_WAITING_FOR_RESURRECT, true);
}
}
void BfGraveyard::RemovePlayer(ObjectGuid playerGuid)
{
m_ResurrectQueue.erase(m_ResurrectQueue.find(playerGuid));
if (Player* player = ObjectAccessor::FindPlayer(playerGuid))
player->RemoveAurasDueToSpell(SPELL_WAITING_FOR_RESURRECT);
}
void BfGraveyard::Resurrect()
{
if (m_ResurrectQueue.empty())
return;
for (GuidSet::const_iterator itr = m_ResurrectQueue.begin(); itr != m_ResurrectQueue.end(); ++itr)
{
// Get player object from his guid
Player* player = ObjectAccessor::FindPlayer(*itr);
if (!player)
continue;
// Check if the player is in world and on the good graveyard
if (player->IsInWorld())
if (Creature* spirit = m_Bf->GetCreature(m_SpiritGuide[m_ControlTeam]))
spirit->CastSpell(spirit, SPELL_SPIRIT_HEAL, true);
// Resurrect player
player->CastSpell(player, SPELL_RESURRECTION_VISUAL, true);
player->ResurrectPlayer(1.0f);
player->CastSpell(player, 6962, true);
player->CastSpell(player, SPELL_SPIRIT_HEAL_MANA, true);
player->SpawnCorpseBones(false);
}
m_ResurrectQueue.clear();
}
// For changing graveyard control
void BfGraveyard::GiveControlTo(TeamId team)
{
@@ -726,29 +628,10 @@ void BfGraveyard::GiveControlTo(TeamId team)
if (m_SpiritGuide[team])
m_SpiritGuide[team]->SetVisible(true);*/
if (Creature* spiritHealer = m_Bf->GetCreature(m_SpiritGuide[team]))
spiritHealer->SummonGraveyardTeleporter();
m_ControlTeam = team;
// Teleport to other graveyard, player witch were on this graveyard
RelocateDeadPlayers();
}
void BfGraveyard::RelocateDeadPlayers()
{
WorldSafeLocsEntry const* closestGrave = nullptr;
for (GuidSet::const_iterator itr = m_ResurrectQueue.begin(); itr != m_ResurrectQueue.end(); ++itr)
{
Player* player = ObjectAccessor::FindPlayer(*itr);
if (!player)
continue;
if (closestGrave)
player->TeleportTo(closestGrave->Loc);
else
{
closestGrave = m_Bf->GetClosestGraveyard(player);
if (closestGrave)
player->TeleportTo(closestGrave->Loc);
}
}
}
bool BfGraveyard::HasNpc(ObjectGuid guid)
-21
View File
@@ -177,24 +177,9 @@ class TC_GAME_API BfGraveyard
// Set spirit service for the graveyard
void SetSpirit(Creature* spirit, TeamId team);
// Add a player to the graveyard
void AddPlayer(ObjectGuid player_guid);
// Remove a player from the graveyard
void RemovePlayer(ObjectGuid player_guid);
// Resurrect players
void Resurrect();
// Move players waiting to that graveyard on the nearest one
void RelocateDeadPlayers();
// Check if this graveyard has a spirit guide
bool HasNpc(ObjectGuid guid);
// Check if a player is in this graveyard's resurrect queue
bool HasPlayer(ObjectGuid guid) { return m_ResurrectQueue.find(guid) != m_ResurrectQueue.end(); }
// Get the graveyard's ID.
uint32 GetGraveyardId() const { return m_GraveyardId; }
@@ -202,7 +187,6 @@ class TC_GAME_API BfGraveyard
TeamId m_ControlTeam;
uint32 m_GraveyardId;
ObjectGuid m_SpiritGuide[PVP_TEAMS_COUNT];
GuidSet m_ResurrectQueue;
Battlefield* m_Bf;
};
@@ -304,8 +288,6 @@ class TC_GAME_API Battlefield : public ZoneScript
// Find which graveyard the player must be teleported to to be resurrected by spiritguide
WorldSafeLocsEntry const* GetClosestGraveyard(Player* player);
virtual void AddPlayerToResurrectQueue(ObjectGuid npc_guid, ObjectGuid player_guid);
void RemovePlayerFromResurrectQueue(ObjectGuid player_guid);
void SetGraveyardNumber(uint32 number) { m_GraveyardList.resize(number); }
BfGraveyard* GetGraveyardById(uint32 id) const;
@@ -346,8 +328,6 @@ class TC_GAME_API Battlefield : public ZoneScript
/// Return if we can use mount in battlefield
bool CanFlyIn() { return !m_isActive; }
void SendAreaSpiritHealerQueryOpcode(Player* player, ObjectGuid const& guid);
void StartBattle();
void EndBattle(bool endByTimer);
@@ -403,7 +383,6 @@ class TC_GAME_API Battlefield : public ZoneScript
// Graveyard variables
GraveyardVect m_GraveyardList; // Vector witch contain the different GY of the battle
uint32 m_LastResurrectTimer; // Timer for resurrect player every 30 sec
uint32 m_StartGroupingTimer; // Timer for invite players in area 15 minute before start battle
bool m_StartGrouping; // bool for know if all players in area has been invited
+2 -128
View File
@@ -64,7 +64,6 @@ Battleground::Battleground(BattlegroundTemplate const* battlegroundTemplate) : _
m_Status = STATUS_NONE;
m_ClientInstanceID = 0;
m_EndTime = 0;
m_LastResurrectTime = 0;
m_InvitedAlliance = 0;
m_InvitedHorde = 0;
m_ArenaType = 0;
@@ -195,7 +194,6 @@ void Battleground::Update(uint32 diff)
}
else
{
_ProcessResurrect(diff);
if (sBattlegroundMgr->GetPrematureFinishTime() && (GetPlayersCountByTeam(ALLIANCE) < GetMinPlayersPerTeam() || GetPlayersCountByTeam(HORDE) < GetMinPlayersPerTeam()))
_ProcessProgress(diff);
else if (m_PrematureCountDown)
@@ -290,65 +288,6 @@ inline void Battleground::_ProcessOfflineQueue()
}
}
inline void Battleground::_ProcessResurrect(uint32 diff)
{
// *********************************************************
// *** BATTLEGROUND RESURRECTION SYSTEM ***
// *********************************************************
// this should be handled by spell system
m_LastResurrectTime += diff;
if (m_LastResurrectTime >= RESURRECTION_INTERVAL)
{
if (GetReviveQueueSize())
{
for (std::map<ObjectGuid, GuidVector>::iterator itr = m_ReviveQueue.begin(); itr != m_ReviveQueue.end(); ++itr)
{
Creature* sh = nullptr;
for (GuidVector::const_iterator itr2 = (itr->second).begin(); itr2 != (itr->second).end(); ++itr2)
{
Player* player = ObjectAccessor::FindPlayer(*itr2);
if (!player)
continue;
if (!sh && player->IsInWorld())
{
sh = player->GetMap()->GetCreature(itr->first);
// only for visual effect
if (sh)
// Spirit Heal, effect 117
sh->CastSpell(sh, SPELL_SPIRIT_HEAL, true);
}
// Resurrection visual
player->CastSpell(player, SPELL_RESURRECTION_VISUAL, true);
m_ResurrectQueue.push_back(*itr2);
}
(itr->second).clear();
}
m_ReviveQueue.clear();
m_LastResurrectTime = 0;
}
else
// queue is clear and time passed, just update last resurrection time
m_LastResurrectTime = 0;
}
else if (m_LastResurrectTime > 500) // Resurrect players only half a second later, to see spirit heal effect on NPC
{
for (GuidVector::const_iterator itr = m_ResurrectQueue.begin(); itr != m_ResurrectQueue.end(); ++itr)
{
Player* player = ObjectAccessor::FindPlayer(*itr);
if (!player)
continue;
player->ResurrectPlayer(1.0f);
player->CastSpell(player, 6962, true);
player->CastSpell(player, SPELL_SPIRIT_HEAL_MANA, true);
player->SpawnCorpseBones(false);
}
m_ResurrectQueue.clear();
}
}
uint32 Battleground::GetPrematureWinner()
{
uint32 winner = 0;
@@ -894,8 +833,6 @@ void Battleground::RemovePlayerAtLeave(ObjectGuid guid, bool Transport, bool Sen
PlayerScores.erase(itr2);
}
RemovePlayerFromResurrectQueue(guid);
Player* player = ObjectAccessor::FindPlayer(guid);
if (player)
@@ -1004,7 +941,6 @@ void Battleground::Reset()
SetStatus(STATUS_WAIT_QUEUE);
SetElapsedTime(0);
SetRemainingTime(0);
SetLastResurrectTime(0);
m_Events = 0;
if (m_InvitedAlliance > 0 || m_InvitedHorde > 0)
@@ -1027,7 +963,6 @@ void Battleground::Reset()
void Battleground::StartBattleground()
{
SetElapsedTime(0);
SetLastResurrectTime(0);
// add BG to free slot queue
AddToBGFreeSlotQueue();
@@ -1374,57 +1309,6 @@ bool Battleground::UpdatePlayerScore(Player* player, uint32 type, uint32 value,
return true;
}
void Battleground::AddPlayerToResurrectQueue(ObjectGuid npc_guid, ObjectGuid player_guid)
{
m_ReviveQueue[npc_guid].push_back(player_guid);
Player* player = ObjectAccessor::FindPlayer(player_guid);
if (!player)
return;
player->CastSpell(player, SPELL_WAITING_FOR_RESURRECT, true);
}
void Battleground::RemovePlayerFromResurrectQueue(ObjectGuid player_guid)
{
for (std::map<ObjectGuid, GuidVector>::iterator itr = m_ReviveQueue.begin(); itr != m_ReviveQueue.end(); ++itr)
{
for (GuidVector::iterator itr2 = itr->second.begin(); itr2 != itr->second.end(); ++itr2)
{
if (*itr2 == player_guid)
{
itr->second.erase(itr2);
if (Player* player = ObjectAccessor::FindPlayer(player_guid))
player->RemoveAurasDueToSpell(SPELL_WAITING_FOR_RESURRECT);
return;
}
}
}
}
void Battleground::RelocateDeadPlayers(ObjectGuid guideGuid)
{
// Those who are waiting to resurrect at this node are taken to the closest own node's graveyard
GuidVector& ghostList = m_ReviveQueue[guideGuid];
if (!ghostList.empty())
{
WorldSafeLocsEntry const* closestGrave = nullptr;
for (GuidVector::const_iterator itr = ghostList.begin(); itr != ghostList.end(); ++itr)
{
Player* player = ObjectAccessor::FindPlayer(*itr);
if (!player)
continue;
if (!closestGrave)
closestGrave = GetClosestGraveyard(player);
if (closestGrave)
player->TeleportTo(closestGrave->Loc);
}
ghostList.clear();
}
}
bool Battleground::AddObject(uint32 type, uint32 entry, float x, float y, float z, float o, float rotation0, float rotation1, float rotation2, float rotation3, uint32 /*respawnTime*/, GOState goState)
{
// If the assert is called, means that BgObjects must be resized!
@@ -1698,19 +1582,9 @@ bool Battleground::AddSpiritGuide(uint32 type, float x, float y, float z, float
{
uint32 entry = (teamId == TEAM_ALLIANCE) ? BG_CREATURE_ENTRY_A_SPIRITGUIDE : BG_CREATURE_ENTRY_H_SPIRITGUIDE;
if (Creature* creature = AddCreature(entry, type, x, y, z, o, teamId))
{
creature->setDeathState(DEAD);
creature->AddChannelObject(creature->GetGUID());
// aura
/// @todo Fix display here
// creature->SetVisibleAura(0, SPELL_SPIRIT_HEAL_CHANNEL);
// casting visual effect
creature->SetChannelSpellId(SPELL_SPIRIT_HEAL_CHANNEL);
creature->SetChannelVisual({ VISUAL_SPIRIT_HEAL_CHANNEL, 0 });
//creature->CastSpell(creature, SPELL_SPIRIT_HEAL_CHANNEL, true);
if (AddCreature(entry, type, x, y, z, o, teamId))
return true;
}
TC_LOG_ERROR("bg.battleground", "Battleground::AddSpiritGuide: cannot create spirit guide (type: {}, entry: {}) for BG (map: {}, instance id: {})!",
type, entry, GetMapId(), m_InstanceID);
EndNow();
+4 -14
View File
@@ -96,8 +96,10 @@ enum BattlegroundCreatures
enum BattlegroundSpells
{
SPELL_SPIRIT_HEAL_CHANNEL_AOE = 22011, // used for AoE resurrections
SPELL_SPIRIT_HEAL_PLAYER_AURA = 156758, // individual player timers for resurrection
SPELL_SPIRIT_HEAL_CHANNEL_SELF = 305122, // channel visual for individual area spirit healers
SPELL_WAITING_FOR_RESURRECT = 2584, // Waiting to Resurrect
SPELL_SPIRIT_HEAL_CHANNEL = 22011, // Spirit Heal Channel
VISUAL_SPIRIT_HEAL_CHANNEL = 3060,
SPELL_SPIRIT_HEAL = 22012, // Spirit Heal
SPELL_RESURRECTION_VISUAL = 24171, // Resurrection Impact Visual
@@ -115,6 +117,7 @@ enum BattlegroundSpells
SPELL_MERCENARY_ALLIANCE_1 = 193863,
SPELL_MERCENARY_ALLIANCE_REACTIONS = 195843,
SPELL_MERCENARY_SHAPESHIFT = 193970,
SPELL_PET_SUMMONED = 6962 // used after resurrection
};
enum BattlegroundTimeIntervals
@@ -286,7 +289,6 @@ class TC_GAME_API Battleground : public ZoneScript
uint32 GetClientInstanceID() const { return m_ClientInstanceID; }
uint32 GetElapsedTime() const { return m_StartTime; }
uint32 GetRemainingTime() const { return m_EndTime; }
uint32 GetLastResurrectTime() const { return m_LastResurrectTime; }
uint32 GetMaxPlayers() const;
uint32 GetMinPlayers() const;
@@ -313,7 +315,6 @@ class TC_GAME_API Battleground : public ZoneScript
void SetClientInstanceID(uint32 InstanceID) { m_ClientInstanceID = InstanceID; }
void SetElapsedTime(uint32 Time) { m_StartTime = Time; }
void SetRemainingTime(uint32 Time) { m_EndTime = Time; }
void SetLastResurrectTime(uint32 Time) { m_LastResurrectTime = Time; }
void SetRated(bool state) { m_IsRated = state; }
void SetArenaType(uint8 type) { m_ArenaType = type; }
void SetWinner(PvPTeamId winnerTeamId) { _winnerTeamId = winnerTeamId; }
@@ -343,14 +344,6 @@ class TC_GAME_API Battleground : public ZoneScript
typedef std::map<ObjectGuid, BattlegroundScore*> BattlegroundScoreMap;
uint32 GetPlayerScoresSize() const { return uint32(PlayerScores.size()); }
uint32 GetReviveQueueSize() const { return uint32(m_ReviveQueue.size()); }
void AddPlayerToResurrectQueue(ObjectGuid npc_guid, ObjectGuid player_guid);
void RemovePlayerFromResurrectQueue(ObjectGuid player_guid);
/// Relocate all players in ReviveQueue to the closest graveyard
void RelocateDeadPlayers(ObjectGuid guideGuid);
void StartBattleground();
GameObject* GetBGObject(uint32 type, bool logError = true);
@@ -543,7 +536,6 @@ class TC_GAME_API Battleground : public ZoneScript
virtual void PostUpdateImpl(uint32 /* diff */) { }
void _ProcessOfflineQueue();
void _ProcessResurrect(uint32 diff);
void _ProcessProgress(uint32 diff);
void _ProcessLeave(uint32 diff);
void _ProcessJoin(uint32 diff);
@@ -584,7 +576,6 @@ class TC_GAME_API Battleground : public ZoneScript
uint32 m_ResetStatTimer;
uint32 m_ValidStartPositionTimer;
int32 m_EndTime; // it is set to 120000 when bg is ending and it decreases itself
uint32 m_LastResurrectTime;
uint8 m_ArenaType; // 2=2v2, 3=3v3, 5=5v5
bool m_InBGFreeSlotQueue; // used to make sure that BG is only once inserted into the BattlegroundMgr.BGFreeSlotQueue[bgTypeId] deque
bool m_SetDeleteThis; // used for safe deletion of the bg after end / all players leave
@@ -597,7 +588,6 @@ class TC_GAME_API Battleground : public ZoneScript
uint32 m_LastPlayerPositionBroadcast;
// Player lists
GuidVector m_ResurrectQueue; // Player GUID
std::deque<ObjectGuid> m_OfflineQueue; // Player GUID
// Invited counters are useful for player invitation to BG - do not allow, if BG is started to one faction to have 2 more players than another faction
@@ -579,18 +579,6 @@ void BattlegroundMgr::SendToBattleground(Player* player, uint32 instanceId, Batt
TC_LOG_ERROR("bg.battleground", "BattlegroundMgr::SendToBattleground: Instance {} (bgType {}) not found while trying to teleport player {}", instanceId, bgTypeId, player->GetName());
}
void BattlegroundMgr::SendAreaSpiritHealerQueryOpcode(Player* player, Battleground* bg, ObjectGuid const& guid)
{
uint32 time_ = 30000 - bg->GetLastResurrectTime(); // resurrect every 30 seconds
if (time_ == uint32(-1))
time_ = 0;
WorldPackets::Battleground::AreaSpiritHealerTime areaSpiritHealerTime;
areaSpiritHealerTime.HealerGuid = guid;
areaSpiritHealerTime.TimeLeft = time_;
player->SendDirectMessage(areaSpiritHealerTime.Write());
}
bool BattlegroundMgr::IsArenaType(BattlegroundTypeId bgTypeId)
{
return bgTypeId == BATTLEGROUND_AA
@@ -96,7 +96,6 @@ class TC_GAME_API BattlegroundMgr
void BuildBattlegroundStatusActive(WorldPackets::Battleground::BattlefieldStatusActive* battlefieldStatus, Battleground* bg, Player* player, uint32 ticketId, uint32 joinTime, uint32 arenaType);
void BuildBattlegroundStatusQueued(WorldPackets::Battleground::BattlefieldStatusQueued* battlefieldStatus, Battleground* bg, Player* player, uint32 ticketId, uint32 joinTime, BattlegroundQueueTypeId queueId, uint32 avgWaitTime, uint32 arenaType, bool asGroup);
void BuildBattlegroundStatusFailed(WorldPackets::Battleground::BattlefieldStatusFailed* battlefieldStatus, BattlegroundQueueTypeId queueId, Player* pPlayer, uint32 ticketId, GroupJoinBattlegroundResult result, ObjectGuid const* errorGuid = nullptr);
void SendAreaSpiritHealerQueryOpcode(Player* player, Battleground* bg, ObjectGuid const& guid);
/* Battlegrounds */
Battleground* GetBattleground(uint32 InstanceID, BattlegroundTypeId bgTypeId);
@@ -393,8 +393,6 @@ void BattlegroundAB::_NodeDeOccupied(uint8 node)
//remove bonus honor aura trigger creature when node is lost
DelCreature(node+7);//NULL checks are in DelCreature! 0-6 spirit guides
RelocateDeadPlayers(BgCreatures[node]);
DelCreature(node);
// buff object isn't despawned
@@ -1000,8 +1000,6 @@ void BattlegroundAV::EventPlayerAssaultsPoint(Player* player, uint32 object)
//spawning/despawning of aura
SpawnBGObject(BG_AV_OBJECT_AURA_N_FIRSTAID_STATION + 3 * node, RESPAWN_IMMEDIATELY); //neutral aura spawn
SpawnBGObject(BG_AV_OBJECT_AURA_A_FIRSTAID_STATION + uint32(GetTeamIndexByTeamId(owner)) + 3 * node, RESPAWN_ONE_DAY); //teeamaura despawn
RelocateDeadPlayers(BgCreatures[node]);
}
DePopulateNode(node);
}
@@ -427,8 +427,6 @@ void BattlegroundIC::EventPlayerClickedOnFlag(Player* player, GameObject* target
nodePoint[i].timer = BANNER_STATE_CHANGE_TIME; // 1 minute for last change (real faction banner)
nodePoint[i].needChange = true;
RelocateDeadPlayers(BgCreatures[BG_IC_NPC_SPIRIT_GUIDE_1 + uint32(nodePoint[i].nodeType) - 2]);
// if we are here means that the point has been lost, or it is the first capture
if (nodePoint[i].nodeType != NODE_TYPE_REFINERY && nodePoint[i].nodeType != NODE_TYPE_QUARRY)
@@ -694,6 +694,9 @@ void Creature::Update(uint32 diff)
{
if (IsAIEnabled() && m_triggerJustAppeared && m_deathState != DEAD)
{
if (IsAreaSpiritHealer() && !IsAreaSpiritHealerIndividual())
CastSpell(nullptr, SPELL_SPIRIT_HEAL_CHANNEL_AOE, false);
if (m_respawnCompatibilityMode && m_vehicleKit)
m_vehicleKit->Reset();
m_triggerJustAppeared = false;
@@ -3600,3 +3603,22 @@ void Creature::SetTrainerId(Optional<uint32> trainerId)
{
_trainerId = trainerId;
}
enum AreaSpiritHealerData
{
NPC_ALLIANCE_GRAVEYARD_TELEPORT = 26350,
NPC_HORDE_GRAVEYARD_TELEPORT = 26351
};
void Creature::SummonGraveyardTeleporter()
{
if (!IsAreaSpiritHealer())
return;
uint32 npcEntry = GetFaction() == FACTION_ALLIANCE_GENERIC ? NPC_ALLIANCE_GRAVEYARD_TELEPORT : NPC_HORDE_GRAVEYARD_TELEPORT;
// maybe NPC is summoned with these spells:
// ID - 24237 Summon Alliance Graveyard Teleporter (SERVERSIDE)
// ID - 46894 Summon Horde Graveyard Teleporter (SERVERSIDE)
SummonCreature(npcEntry, GetPosition(), TEMPSUMMON_TIMED_DESPAWN, 1s, 0, 0);
}
@@ -424,6 +424,8 @@ class TC_GAME_API Creature : public Unit, public GridObject<Creature>, public Ma
uint32 GetTrainerId() const;
void SetTrainerId(Optional<uint32> trainerId);
void SummonGraveyardTeleporter();
protected:
bool CreateFromProto(ObjectGuid::LowType guidlow, uint32 entry, CreatureData const* data = nullptr, uint32 vehId = 0);
bool InitEntry(uint32 entry, CreatureData const* data = nullptr);
@@ -4380,6 +4380,8 @@ void Player::BuildPlayerRepop()
void Player::ResurrectPlayer(float restore_percent, bool applySickness)
{
SetAreaSpiritHealer(nullptr);
WorldPackets::Misc::DeathReleaseLoc packet;
packet.MapID = -1;
SendDirectMessage(packet.Write());
@@ -29235,6 +29237,39 @@ std::string Player::GetDebugInfo() const
return sstr.str();
}
void Player::SetAreaSpiritHealer(Creature* creature)
{
if (!creature)
{
_areaSpiritHealerGUID = ObjectGuid::Empty;
RemoveAurasDueToSpell(SPELL_WAITING_FOR_RESURRECT);
return;
}
if (!creature->IsAreaSpiritHealer())
return;
_areaSpiritHealerGUID = creature->GetGUID();
CastSpell(nullptr, SPELL_WAITING_FOR_RESURRECT);
}
void Player::SendAreaSpiritHealerTime(Unit* spiritHealer) const
{
int32 timeLeft = 0;
if (Spell* spell = spiritHealer->GetCurrentSpell(CURRENT_CHANNELED_SPELL))
timeLeft = spell->GetTimer();
SendAreaSpiritHealerTime(spiritHealer->GetGUID(), timeLeft);
}
void Player::SendAreaSpiritHealerTime(ObjectGuid const& spiritHealerGUID, int32 timeLeft) const
{
WorldPackets::Battleground::AreaSpiritHealerTime areaSpiritHealerTime;
areaSpiritHealerTime.HealerGuid = spiritHealerGUID;
areaSpiritHealerTime.TimeLeft = timeLeft;
SendDirectMessage(areaSpiritHealerTime.Write());
}
void Player::SendDisplayToast(uint32 entry, DisplayToastType type, bool isBonusRoll, uint32 quantity, DisplayToastMethod method, uint32 questId, Item* item /*= nullptr*/) const
{
WorldPackets::Misc::DisplayToast displayToast;
+8
View File
@@ -1121,6 +1121,7 @@ private:
uint32 constexpr PLAYER_MAX_HONOR_LEVEL = 500;
uint8 constexpr PLAYER_LEVEL_MIN_HONOR = 10;
uint32 constexpr SPELL_PVP_RULES_ENABLED = 134735;
float constexpr MAX_AREA_SPIRIT_HEALER_RANGE = 20.0f;
enum class ZonePVPTypeOverride : uint32
{
@@ -2865,6 +2866,12 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
UF::UpdateField<UF::PlayerData, 0, TYPEID_PLAYER> m_playerData;
UF::UpdateField<UF::ActivePlayerData, 0, TYPEID_ACTIVE_PLAYER> m_activePlayerData;
void SetAreaSpiritHealer(Creature* creature);
ObjectGuid const& GetSpiritHealerGUID() const { return _areaSpiritHealerGUID; }
bool CanAcceptAreaSpiritHealFrom(Unit* spiritHealer) const { return spiritHealer->GetGUID() == _areaSpiritHealerGUID; }
void SendAreaSpiritHealerTime(Unit* spiritHealer) const;
void SendAreaSpiritHealerTime(ObjectGuid const& spiritHealerGUID, int32 timeLeft) const;
protected:
// Gamemaster whisper whitelist
GuidList WhisperList;
@@ -3217,6 +3224,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
std::unique_ptr<RestMgr> _restMgr;
bool _usePvpItemLevels;
ObjectGuid _areaSpiritHealerGUID;
};
TC_GAME_API void AddItemsSetItem(Player* player, Item const* item);
+6
View File
@@ -9414,6 +9414,12 @@ void Unit::RemoveFromWorld()
if (IsInWorld())
{
if (IsAreaSpiritHealer())
{
if (Creature* creature = ToCreature())
creature->SummonGraveyardTeleporter();
}
m_duringRemoveFromWorld = true;
if (UnitAI* ai = GetAI())
ai->OnDespawn();
+1
View File
@@ -1120,6 +1120,7 @@ class TC_GAME_API Unit : public WorldObject
bool IsWildBattlePet() const { return HasNpcFlag(UNIT_NPC_FLAG_WILD_BATTLE_PET); }
bool IsServiceProvider() const;
bool IsSpiritService() const { return HasNpcFlag(UNIT_NPC_FLAG_SPIRIT_HEALER | UNIT_NPC_FLAG_AREA_SPIRIT_HEALER); }
bool IsAreaSpiritHealerIndividual() const { return HasNpcFlag2(UNIT_NPC_FLAG_2_AREA_SPIRIT_HEALER_INDIVIDUAL); }
bool IsCritter() const { return GetCreatureType() == CREATURE_TYPE_CRITTER; }
bool IsInFlight() const { return HasUnitState(UNIT_STATE_IN_FLIGHT); }
@@ -35,6 +35,9 @@
#include "Object.h"
#include "ObjectAccessor.h"
#include "Player.h"
#include "SpellAuras.h"
#include "SpellMgr.h"
#include "SpellInfo.h"
#include "World.h"
void WorldSession::HandleBattlemasterHelloOpcode(WorldPackets::NPC::Hello& hello)
@@ -651,34 +654,47 @@ void WorldSession::HandleRequestPvpReward(WorldPackets::Battleground::RequestPVP
void WorldSession::HandleAreaSpiritHealerQueryOpcode(WorldPackets::Battleground::AreaSpiritHealerQuery& areaSpiritHealerQuery)
{
Creature* unit = ObjectAccessor::GetCreature(*GetPlayer(), areaSpiritHealerQuery.HealerGuid);
if (!unit)
Player* player = GetPlayer();
Creature* spiritHealer = ObjectAccessor::GetCreature(*player, areaSpiritHealerQuery.HealerGuid);
if (!spiritHealer)
return;
if (!unit->IsSpiritService()) // it's not spirit service
if (!spiritHealer->IsAreaSpiritHealer())
return;
if (Battleground* bg = _player->GetBattleground())
sBattlegroundMgr->SendAreaSpiritHealerQueryOpcode(_player, bg, areaSpiritHealerQuery.HealerGuid);
if (_player->GetExactDist(spiritHealer) > MAX_AREA_SPIRIT_HEALER_RANGE)
return;
if (Battlefield* bf = sBattlefieldMgr->GetBattlefieldToZoneId(_player->GetMap(), _player->GetZoneId()))
bf->SendAreaSpiritHealerQueryOpcode(_player, areaSpiritHealerQuery.HealerGuid);
if (spiritHealer->IsAreaSpiritHealerIndividual())
{
if (Aura* aura = player->GetAura(SPELL_SPIRIT_HEAL_PLAYER_AURA))
{
player->SendAreaSpiritHealerTime(spiritHealer->GetGUID(), aura->GetDuration());
}
else if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(SPELL_SPIRIT_HEAL_PLAYER_AURA, DIFFICULTY_NONE))
{
spiritHealer->CastSpell(player, SPELL_SPIRIT_HEAL_PLAYER_AURA);
player->SendAreaSpiritHealerTime(spiritHealer->GetGUID(), spellInfo->GetDuration());
spiritHealer->CastSpell(nullptr, SPELL_SPIRIT_HEAL_CHANNEL_SELF);
}
}
else
_player->SendAreaSpiritHealerTime(spiritHealer);
}
void WorldSession::HandleAreaSpiritHealerQueueOpcode(WorldPackets::Battleground::AreaSpiritHealerQueue& areaSpiritHealerQueue)
{
Creature* unit = ObjectAccessor::GetCreature(*GetPlayer(), areaSpiritHealerQueue.HealerGuid);
if (!unit)
Creature* spiritHealer = ObjectAccessor::GetCreature(*GetPlayer(), areaSpiritHealerQueue.HealerGuid);
if (!spiritHealer)
return;
if (!unit->IsSpiritService()) // it's not spirit service
if (!spiritHealer->IsAreaSpiritHealer())
return;
if (Battleground* bg = _player->GetBattleground())
bg->AddPlayerToResurrectQueue(areaSpiritHealerQueue.HealerGuid, _player->GetGUID());
if (_player->GetExactDist(spiritHealer) > MAX_AREA_SPIRIT_HEALER_RANGE)
return;
if (Battlefield* bf = sBattlefieldMgr->GetBattlefieldToZoneId(_player->GetMap(), _player->GetZoneId()))
bf->AddPlayerToResurrectQueue(areaSpiritHealerQueue.HealerGuid, _player->GetGUID());
_player->SetAreaSpiritHealer(spiritHealer);
}
void WorldSession::HandleHearthAndResurrect(WorldPackets::Battleground::HearthAndResurrect& /*hearthAndResurrect*/)
+2 -8
View File
@@ -167,16 +167,10 @@ void WorldSession::HandleGossipHelloOpcode(WorldPackets::NPC::Hello& packet)
unit->PauseMovement(pause);
unit->SetHomePosition(unit->GetPosition());
// If spiritguide, no need for gossip menu, just put player into resurrect queue
if (unit->IsAreaSpiritHealer())
{
Battleground* bg = _player->GetBattleground();
if (bg)
{
bg->AddPlayerToResurrectQueue(unit->GetGUID(), _player->GetGUID());
sBattlegroundMgr->SendAreaSpiritHealerQueryOpcode(_player, bg, unit->GetGUID());
return;
}
_player->SetAreaSpiritHealer(unit);
_player->SendAreaSpiritHealerTime(unit);
}
_player->PlayerTalkClass->ClearMenus();
@@ -4662,16 +4662,6 @@ void AuraEffect::HandleAuraDummy(AuraApplication const* aurApp, uint8 mode, bool
case SPELLFAMILY_GENERIC:
switch (GetId())
{
case 2584: // Waiting to Resurrect
// Waiting to resurrect spell cancel, we must remove player from resurrect queue
if (target->GetTypeId() == TYPEID_PLAYER)
{
if (Battleground* bg = target->ToPlayer()->GetBattleground())
bg->RemovePlayerFromResurrectQueue(target->GetGUID());
if (Battlefield* bf = sBattlefieldMgr->GetBattlefieldToZoneId(target->GetMap(), target->GetZoneId()))
bf->RemovePlayerFromResurrectQueue(target->GetGUID());
}
break;
case 43681: // Inactive
{
if (target->GetTypeId() != TYPEID_PLAYER || aurApp->GetRemoveMode() != AURA_REMOVE_BY_EXPIRE)
+17 -14
View File
@@ -4488,26 +4488,29 @@ void Spell::EffectSkill()
TC_LOG_DEBUG("spells", "WORLD: SkillEFFECT");
}
/* There is currently no need for this effect. We handle it in Battleground.cpp
If we would handle the resurrection here, the spiritguide would instantly disappear as the
player revives, and so we wouldn't see the spirit heal visual effect on the npc.
This is why we use a half sec delay between the visual effect and the resurrection itself */
void Spell::EffectSpiritHeal()
{
Unit* caster = GetCaster()->ToUnit();
if (effectHandleMode == SPELL_EFFECT_HANDLE_HIT)
caster->CastSpell(nullptr, SPELL_RESURRECTION_VISUAL, true);
if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
return;
/*
if (unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
if (!unitTarget->IsInWorld())
return;
if (Player* playerTarget = unitTarget->ToPlayer())
{
if (!playerTarget->IsInWorld())
return;
//m_spellInfo->Effects[i].BasePoints; == 99 (percent?)
//unitTarget->ToPlayer()->setResurrect(m_caster->GetGUID(), unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(), unitTarget->GetMaxHealth(), unitTarget->GetMaxPower(POWER_MANA));
unitTarget->ToPlayer()->ResurrectPlayer(1.0f);
unitTarget->ToPlayer()->SpawnCorpseBones();
*/
// skip if player does not want to live
if (!playerTarget->CanAcceptAreaSpiritHealFrom(caster))
return;
playerTarget->ResurrectPlayer(1.0f);
playerTarget->CastSpell(playerTarget, SPELL_PET_SUMMONED, true);
playerTarget->CastSpell(playerTarget, SPELL_SPIRIT_HEAL_MANA, true);
playerTarget->SpawnCorpseBones(false);
}
}
// remove insignia spell effect
-2
View File
@@ -2052,8 +2052,6 @@ SpellCastResult SpellInfo::CheckLocation(uint32 map_id, uint32 zone_id, uint32 a
case 34976: // Netherstorm Flag
return map_id == 566 && player && player->InBattleground() ? SPELL_CAST_OK : SPELL_FAILED_REQUIRES_AREA;
case 2584: // Waiting to Resurrect
case 22011: // Spirit Heal Channel
case 22012: // Spirit Heal
case 42792: // Recently Dropped Flag
case 43681: // Inactive
case 44535: // Spirit Heal (mana)
@@ -511,7 +511,6 @@ void BattlefieldTB::OnCreatureCreate(Creature* creature)
case NPC_TB_GY_SPIRIT_EAST_SPIRE_H:
case NPC_TB_GY_SPIRIT_SOUTH_SPIRE_H:
creature->CastSpell(creature, SPELL_TB_SPIRITUAL_IMMUNITY, true);
creature->CastSpell(creature, SPELL_TB_SPIRIT_HEAL_CHANNEL, true);
break;
default:
break;
@@ -54,7 +54,6 @@ enum TolBaradSpells
SPELL_TB_SLOW_FALL = 88473,
SPELL_TB_VETERAN = 84655,
SPELL_TOWER_ATTACK_BONUS = 82629,
SPELL_TB_SPIRIT_HEAL_CHANNEL = 22011, // this spell replaces m_LastResurrectTimer in Battlefield.cpp?
SPELL_TB_SPIRITUAL_IMMUNITY = 95332,
// Vehicle
@@ -29,8 +29,6 @@
enum TBSpiritGuide
{
SPELL_CHANNEL_SPIRIT_HEAL = 22011,
GOSSIP_OPTION_ID_SLAGWORKS = 0,
GOSSIP_OPTION_ID_IRONCLAD_GARRISON = 1,
GOSSIP_OPTION_ID_WARDENS_VIGIL = 2,
@@ -39,61 +37,44 @@ enum TBSpiritGuide
GOSSIP_OPTION_ID_SOUTH_SPIRE = 5,
};
class npc_tb_spirit_guide : public CreatureScript
struct npc_tb_spirit_guide : public ScriptedAI
{
public:
npc_tb_spirit_guide() : CreatureScript("npc_tb_spirit_guide") { }
npc_tb_spirit_guide(Creature* creature) : ScriptedAI(creature) { }
struct npc_tb_spirit_guideAI : public ScriptedAI
bool OnGossipSelect(Player* player, uint32 /*menuId*/, uint32 gossipListId) override
{
player->PlayerTalkClass->SendCloseGossip();
uint32 areaId = 0;
switch (gossipListId)
{
npc_tb_spirit_guideAI(Creature* creature) : ScriptedAI(creature) { }
void UpdateAI(uint32 /*diff*/) override
{
if (!me->HasUnitState(UNIT_STATE_CASTING))
DoCast(me, SPELL_CHANNEL_SPIRIT_HEAL);
}
bool OnGossipSelect(Player* player, uint32 /*menuId*/, uint32 gossipListId) override
{
player->PlayerTalkClass->SendCloseGossip();
uint32 areaId = 0;
switch (gossipListId)
{
case GOSSIP_OPTION_ID_SLAGWORKS:
areaId = TB_GY_SLAGWORKS;
break;
case GOSSIP_OPTION_ID_IRONCLAD_GARRISON:
areaId = TB_GY_IRONCLAD_GARRISON;
break;
case GOSSIP_OPTION_ID_WARDENS_VIGIL:
areaId = TB_GY_WARDENS_VIGIL;
break;
case GOSSIP_OPTION_ID_EAST_SPIRE:
areaId = TB_GY_EAST_SPIRE;
break;
case GOSSIP_OPTION_ID_WEST_SPIRE:
areaId = TB_GY_WEST_SPIRE;
break;
case GOSSIP_OPTION_ID_SOUTH_SPIRE:
areaId = TB_GY_SOUTH_SPIRE;
break;
default:
return true;
}
if (WorldSafeLocsEntry const* safeLoc = sObjectMgr->GetWorldSafeLoc(areaId))
player->TeleportTo(safeLoc->Loc);
return false;
}
};
CreatureAI* GetAI(Creature* creature) const override
{
return new npc_tb_spirit_guideAI(creature);
case GOSSIP_OPTION_ID_SLAGWORKS:
areaId = TB_GY_SLAGWORKS;
break;
case GOSSIP_OPTION_ID_IRONCLAD_GARRISON:
areaId = TB_GY_IRONCLAD_GARRISON;
break;
case GOSSIP_OPTION_ID_WARDENS_VIGIL:
areaId = TB_GY_WARDENS_VIGIL;
break;
case GOSSIP_OPTION_ID_EAST_SPIRE:
areaId = TB_GY_EAST_SPIRE;
break;
case GOSSIP_OPTION_ID_WEST_SPIRE:
areaId = TB_GY_WEST_SPIRE;
break;
case GOSSIP_OPTION_ID_SOUTH_SPIRE:
areaId = TB_GY_SOUTH_SPIRE;
break;
default:
return true;
}
if (WorldSafeLocsEntry const* safeLoc = sObjectMgr->GetWorldSafeLoc(areaId))
player->TeleportTo(safeLoc->Loc);
return false;
}
};
// 85123 - Siege Cannon - selects random target
@@ -130,6 +111,6 @@ public:
void AddSC_tol_barad()
{
new npc_tb_spirit_guide();
RegisterCreatureAI(npc_tb_spirit_guide);
new spell_siege_cannon();
}
@@ -61,9 +61,6 @@ enum Spells
SPELL_RIDE_WG_VEHICLE = 60968,
SPELL_VEHICLE_TELEPORT = 49759,
// Spirit guide
SPELL_CHANNEL_SPIRIT_HEAL = 22011,
};
enum CreatureIds
@@ -192,12 +189,6 @@ struct npc_wg_spirit_guide : public ScriptedAI
{
npc_wg_spirit_guide(Creature* creature) : ScriptedAI(creature) { }
void UpdateAI(uint32 /*diff*/) override
{
if (!me->HasUnitState(UNIT_STATE_CASTING))
DoCast(me, SPELL_CHANNEL_SPIRIT_HEAL);
}
bool OnGossipHello(Player* player) override
{
if (me->IsQuestGiver())
+116
View File
@@ -5415,6 +5415,118 @@ private:
uint32 _exhaustionSpellId;
};
// AoE resurrections by spirit guides
// 22012 - Spirit Heal
class spell_gen_spirit_heal_aoe : public SpellScript
{
PrepareSpellScript(spell_gen_spirit_heal_aoe);
void FilterTargets(std::list<WorldObject*>& targets)
{
Unit* caster = GetCaster();
targets.remove_if([caster](WorldObject* target) -> bool
{
if (Player* playerTarget = target->ToPlayer())
return !playerTarget->CanAcceptAreaSpiritHealFrom(caster);
return true;
});
}
void Register() override
{
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_gen_spirit_heal_aoe::FilterTargets, EFFECT_0, TARGET_UNIT_DEST_AREA_ALLY);
}
};
// Personal resurrections in battlegrounds
// 156758 - Spirit Heal
class spell_gen_spirit_heal_personal : public AuraScript
{
static constexpr uint32 SPELL_SPIRIT_HEAL_EFFECT = 156763;
PrepareAuraScript(spell_gen_spirit_heal_personal);
void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
if (GetTargetApplication()->GetRemoveMode() != AURA_REMOVE_BY_EXPIRE)
return;
Player* targetPlayer = GetTarget()->ToPlayer();
if (!targetPlayer)
return;
Unit* caster = GetCaster();
if (!caster)
return;
if (targetPlayer->CanAcceptAreaSpiritHealFrom(caster))
caster->CastSpell(targetPlayer, SPELL_SPIRIT_HEAL_EFFECT);
}
void Register() override
{
AfterEffectRemove += AuraEffectRemoveFn(spell_gen_spirit_heal_personal::OnRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
}
};
class RecastSpiritHealChannelEvent : public BasicEvent
{
public:
RecastSpiritHealChannelEvent(Unit* caster) : _caster(caster) { }
bool Execute(uint64 /*e_time*/, uint32 /*p_time*/) override
{
if (_caster->GetChannelSpellId() == 0)
_caster->CastSpell(nullptr, SPELL_SPIRIT_HEAL_CHANNEL_AOE, false);
return true;
}
private:
Unit* _caster;
};
// 22011 - Spirit Heal Channel
class spell_gen_spirit_heal_channel : public AuraScript
{
PrepareAuraScript(spell_gen_spirit_heal_channel);
void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
if (GetTargetApplication()->GetRemoveMode() != AURA_REMOVE_BY_EXPIRE)
return;
Unit* target = GetTarget();
target->m_Events.AddEventAtOffset(new RecastSpiritHealChannelEvent(target), 1s);
}
void Register() override
{
AfterEffectRemove += AuraEffectRemoveFn(spell_gen_spirit_heal_channel::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL, AURA_EFFECT_HANDLE_REAL);
}
};
// 2584 - Waiting to Resurrect
class spell_gen_waiting_to_resurrect : public AuraScript
{
PrepareAuraScript(spell_gen_waiting_to_resurrect);
void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
Player* targetPlayer = GetTarget()->ToPlayer();
if (!targetPlayer)
return;
targetPlayer->SetAreaSpiritHealer(nullptr);
}
void Register() override
{
AfterEffectRemove += AuraEffectRemoveFn(spell_gen_waiting_to_resurrect::OnRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
}
};
void AddSC_generic_spell_scripts()
{
RegisterSpellScript(spell_gen_absorb0_hitlimit1);
@@ -5584,4 +5696,8 @@ void AddSC_generic_spell_scripts()
RegisterSpellScriptWithArgs(spell_gen_bloodlust, "spell_hun_primal_rage", SPELL_HUNTER_FATIGUED);
RegisterSpellScriptWithArgs(spell_gen_bloodlust, "spell_evo_fury_of_the_aspects", SPELL_EVOKER_EXHAUSTION);
RegisterSpellScriptWithArgs(spell_gen_bloodlust, "spell_item_bloodlust_drums", SPELL_SHAMAN_EXHAUSTION);
RegisterSpellScript(spell_gen_spirit_heal_aoe);
RegisterSpellScript(spell_gen_spirit_heal_personal);
RegisterSpellScript(spell_gen_spirit_heal_channel);
RegisterSpellScript(spell_gen_waiting_to_resurrect);
}