diff options
author | Jeremy <Golrag@users.noreply.github.com> | 2023-05-09 05:20:35 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-05-09 05:20:35 +0200 |
commit | 205aba1ff3a6f1ff92a8b26af646fd25f139c697 (patch) | |
tree | a2273ad956ee236dd4044d114759d9e24211468c /src | |
parent | dc284750968d1816cc4271f4c6a6dbcdcdfd3f51 (diff) |
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
Diffstat (limited to 'src')
25 files changed, 282 insertions, 414 deletions
diff --git a/src/server/game/Battlefield/Battlefield.cpp b/src/server/game/Battlefield/Battlefield.cpp index 3b641adcb95..7893b925bc3 100644 --- a/src/server/game/Battlefield/Battlefield.cpp +++ b/src/server/game/Battlefield/Battlefield.cpp @@ -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);*/ - m_ControlTeam = team; - // Teleport to other graveyard, player witch were on this graveyard - RelocateDeadPlayers(); -} + if (Creature* spiritHealer = m_Bf->GetCreature(m_SpiritGuide[team])) + spiritHealer->SummonGraveyardTeleporter(); -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); - } - } + m_ControlTeam = team; } bool BfGraveyard::HasNpc(ObjectGuid guid) diff --git a/src/server/game/Battlefield/Battlefield.h b/src/server/game/Battlefield/Battlefield.h index 5490b62ac54..fb95918d7a5 100644 --- a/src/server/game/Battlefield/Battlefield.h +++ b/src/server/game/Battlefield/Battlefield.h @@ -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 diff --git a/src/server/game/Battlegrounds/Battleground.cpp b/src/server/game/Battlegrounds/Battleground.cpp index ee768353eb7..198bf8f4f84 100644 --- a/src/server/game/Battlegrounds/Battleground.cpp +++ b/src/server/game/Battlegrounds/Battleground.cpp @@ -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(); diff --git a/src/server/game/Battlegrounds/Battleground.h b/src/server/game/Battlegrounds/Battleground.h index 5cb8976422d..bfa4cec6dbe 100644 --- a/src/server/game/Battlegrounds/Battleground.h +++ b/src/server/game/Battlegrounds/Battleground.h @@ -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 diff --git a/src/server/game/Battlegrounds/BattlegroundMgr.cpp b/src/server/game/Battlegrounds/BattlegroundMgr.cpp index c7808947032..aa903481d75 100644 --- a/src/server/game/Battlegrounds/BattlegroundMgr.cpp +++ b/src/server/game/Battlegrounds/BattlegroundMgr.cpp @@ -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 diff --git a/src/server/game/Battlegrounds/BattlegroundMgr.h b/src/server/game/Battlegrounds/BattlegroundMgr.h index 76ec8832ee9..8de23069e99 100644 --- a/src/server/game/Battlegrounds/BattlegroundMgr.h +++ b/src/server/game/Battlegrounds/BattlegroundMgr.h @@ -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); diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundAB.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundAB.cpp index 112558377af..045238009d0 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundAB.cpp +++ b/src/server/game/Battlegrounds/Zones/BattlegroundAB.cpp @@ -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 diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp index ee07e305e24..be75e338ed8 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp +++ b/src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp @@ -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); } diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundIC.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundIC.cpp index b8c9e8ed845..78ea466b716 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundIC.cpp +++ b/src/server/game/Battlegrounds/Zones/BattlegroundIC.cpp @@ -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) diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index 32690e08bff..d41b0162613 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -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); +} diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h index a8d14a0a9b0..9f1f57904a9 100644 --- a/src/server/game/Entities/Creature/Creature.h +++ b/src/server/game/Entities/Creature/Creature.h @@ -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); diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index ba8e83a5bf5..56cce2bf0a4 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -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; diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 798925e5c85..200b343b9c6 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -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); diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 6c7491f2c2e..91247e8166a 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -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(); diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index 9875c5eab70..06f8076df6d 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -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); } diff --git a/src/server/game/Handlers/BattleGroundHandler.cpp b/src/server/game/Handlers/BattleGroundHandler.cpp index a24e97ba821..1fafa48e9a9 100644 --- a/src/server/game/Handlers/BattleGroundHandler.cpp +++ b/src/server/game/Handlers/BattleGroundHandler.cpp @@ -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*/) diff --git a/src/server/game/Handlers/NPCHandler.cpp b/src/server/game/Handlers/NPCHandler.cpp index 5f706002ec4..c8a94c3f206 100644 --- a/src/server/game/Handlers/NPCHandler.cpp +++ b/src/server/game/Handlers/NPCHandler.cpp @@ -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(); diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index 2a205b09882..8992a14462c 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -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) diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index 2dab2a3d9c5..1dbc2269e84 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -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; + + // skip if player does not want to live + if (!playerTarget->CanAcceptAreaSpiritHealFrom(caster)) + 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(); - */ + 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 diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp index cf9c1fa9997..43844717a11 100644 --- a/src/server/game/Spells/SpellInfo.cpp +++ b/src/server/game/Spells/SpellInfo.cpp @@ -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) diff --git a/src/server/scripts/Battlefield/BattlefieldTB.cpp b/src/server/scripts/Battlefield/BattlefieldTB.cpp index c49d92eb6bc..9d9902adbe2 100644 --- a/src/server/scripts/Battlefield/BattlefieldTB.cpp +++ b/src/server/scripts/Battlefield/BattlefieldTB.cpp @@ -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; diff --git a/src/server/scripts/Battlefield/BattlefieldTB.h b/src/server/scripts/Battlefield/BattlefieldTB.h index ed274a2e49e..f39e39d690c 100644 --- a/src/server/scripts/Battlefield/BattlefieldTB.h +++ b/src/server/scripts/Battlefield/BattlefieldTB.h @@ -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 diff --git a/src/server/scripts/EasternKingdoms/zone_tol_barad.cpp b/src/server/scripts/EasternKingdoms/zone_tol_barad.cpp index d52d7f89eca..e0da4c64877 100644 --- a/src/server/scripts/EasternKingdoms/zone_tol_barad.cpp +++ b/src/server/scripts/EasternKingdoms/zone_tol_barad.cpp @@ -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") { } - - struct npc_tb_spirit_guideAI : public ScriptedAI - { - 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; - } + npc_tb_spirit_guide(Creature* creature) : ScriptedAI(creature) { } - if (WorldSafeLocsEntry const* safeLoc = sObjectMgr->GetWorldSafeLoc(areaId)) - player->TeleportTo(safeLoc->Loc); - - return false; - } - }; + bool OnGossipSelect(Player* player, uint32 /*menuId*/, uint32 gossipListId) override + { + player->PlayerTalkClass->SendCloseGossip(); - CreatureAI* GetAI(Creature* creature) const override + uint32 areaId = 0; + switch (gossipListId) { - 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(); } diff --git a/src/server/scripts/Northrend/zone_wintergrasp.cpp b/src/server/scripts/Northrend/zone_wintergrasp.cpp index e4a53d4c57f..011414865c7 100644 --- a/src/server/scripts/Northrend/zone_wintergrasp.cpp +++ b/src/server/scripts/Northrend/zone_wintergrasp.cpp @@ -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()) diff --git a/src/server/scripts/Spells/spell_generic.cpp b/src/server/scripts/Spells/spell_generic.cpp index e5346f910bb..3176c5704fa 100644 --- a/src/server/scripts/Spells/spell_generic.cpp +++ b/src/server/scripts/Spells/spell_generic.cpp @@ -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); } |