From 35961a0121d738f3643a807a3a54562da711d95b Mon Sep 17 00:00:00 2001 From: hondacrx Date: Sun, 21 May 2023 18:38:55 -0400 Subject: [PATCH] Core/Battlegrounds: Moved AreaSpiritHealer resurrection handling to respective npc flags Port From (https://github.com/TrinityCore/TrinityCore/commit/205aba1ff3a6f1ff92a8b26af646fd25f139c697) --- .../Framework/Constants/BattleGroundsConst.cs | 5 +- Source/Framework/Constants/PlayerConst.cs | 2 + Source/Game/BattleFields/BattleField.cs | 136 +----------------- Source/Game/BattleGrounds/BattleGround.cs | 129 +---------------- .../Game/BattleGrounds/BattleGroundManager.cs | 13 -- .../Game/BattleGrounds/Zones/ArathiBasin.cs | 2 - Source/Game/Entities/Creature/Creature.cs | 16 +++ Source/Game/Entities/Player/Player.Fields.cs | 1 + Source/Game/Entities/Player/Player.cs | 40 ++++++ Source/Game/Entities/Unit/Unit.cs | 4 + Source/Game/Handlers/BattleGroundHandler.cs | 51 ++++--- Source/Game/Handlers/NPCHandler.cs | 10 +- Source/Game/Spells/Auras/AuraEffect.cs | 12 -- Source/Game/Spells/Spell.cs | 2 + Source/Game/Spells/SpellEffects.cs | 24 +++- Source/Game/Spells/SpellInfo.cs | 2 - Source/Scripts/Spells/Generic.cs | 130 +++++++++++++++-- 17 files changed, 248 insertions(+), 331 deletions(-) diff --git a/Source/Framework/Constants/BattleGroundsConst.cs b/Source/Framework/Constants/BattleGroundsConst.cs index adcb9f01b..02c69ed7b 100644 --- a/Source/Framework/Constants/BattleGroundsConst.cs +++ b/Source/Framework/Constants/BattleGroundsConst.cs @@ -62,8 +62,10 @@ namespace Framework.Constants public const sbyte PlayerPositionArenaSlot5 = 6; //Spells + public const uint SpellSpiritHealChannelAoE = 22011; // used for AoE resurrections + public const uint SpellSpiritHealPlayerAura = 156758; // individual player timers for resurrection + public const uint SpellSpiritHealChannelSelf = 305122; // channel visual for individual area spirit healers public const uint SpellWaitingForResurrect = 2584; // Waiting To Resurrect - public const uint SpellSpiritHealChannel = 22011; // Spirit Heal Channel public const uint SpellSpiritHealChannelVisual = 3060; public const uint SpellSpiritHeal = 22012; // Spirit Heal public const uint SpellResurrectionVisual = 24171; // Resurrection Impact Visual @@ -81,6 +83,7 @@ namespace Framework.Constants public const uint SpellMercenaryAlliance1 = 193863; public const uint SpellMercenaryAllianceReactions = 195843; public const uint SpellMercenaryShapeshift = 193970; + public const uint SpellPetSummoned = 6962; // used after resurrection } public enum BattlegroundEventFlags diff --git a/Source/Framework/Constants/PlayerConst.cs b/Source/Framework/Constants/PlayerConst.cs index ab840d10f..ca73cd70d 100644 --- a/Source/Framework/Constants/PlayerConst.cs +++ b/Source/Framework/Constants/PlayerConst.cs @@ -62,6 +62,8 @@ namespace Framework.Constants public const uint SpellExperienceEliminated = 206662; public const uint CurrencyMaxCapAncientMana = 2000; + + public const float MaxAreaSpiritHealerRange = 20.0f; } public struct MoneyConstants diff --git a/Source/Game/BattleFields/BattleField.cs b/Source/Game/BattleFields/BattleField.cs index 023849856..caefc9d0e 100644 --- a/Source/Game/BattleFields/BattleField.cs +++ b/Source/Game/BattleFields/BattleField.cs @@ -31,8 +31,6 @@ namespace Game.BattleFields m_uiKickDontAcceptTimer = 1000; m_uiKickAfkPlayersTimer = 1000; - m_LastResurectTimer = 30 * Time.InMilliseconds; - m_Map = map; m_MapId = map.GetId(); @@ -99,7 +97,6 @@ namespace Game.BattleFields m_PlayersWillBeKick[player.GetTeamId()].Remove(player.GetGUID()); m_players[player.GetTeamId()].Remove(player.GetGUID()); SendRemoveWorldStates(player); - RemovePlayerFromResurrectQueue(player.GetGUID()); OnPlayerLeaveZone(player); } @@ -164,17 +161,6 @@ namespace Game.BattleFields objective_changed = true; } - - if (m_LastResurectTimer <= diff) - { - for (byte i = 0; i < m_GraveyardList.Count; i++) - if (GetGraveyardById(i) != null) - m_GraveyardList[i].Resurrect(); - m_LastResurectTimer = BattlegroundConst.ResurrectionInterval; - } - else - m_LastResurectTimer -= diff; - return objective_changed; } @@ -597,45 +583,6 @@ namespace Game.BattleFields return null; } - public virtual void AddPlayerToResurrectQueue(ObjectGuid npcGuid, ObjectGuid playerGuid) - { - for (byte i = 0; i < m_GraveyardList.Count; i++) - { - if (m_GraveyardList[i] == null) - continue; - - if (m_GraveyardList[i].HasNpc(npcGuid)) - { - m_GraveyardList[i].AddPlayer(playerGuid); - break; - } - } - } - - public void RemovePlayerFromResurrectQueue(ObjectGuid playerGuid) - { - for (byte i = 0; i < m_GraveyardList.Count; i++) - { - if (m_GraveyardList[i] == null) - continue; - - if (m_GraveyardList[i].HasPlayer(playerGuid)) - { - m_GraveyardList[i].RemovePlayer(playerGuid); - break; - } - } - } - - public void SendAreaSpiritHealerQuery(Player player, ObjectGuid guid) - { - AreaSpiritHealerTime areaSpiritHealerTime = new(); - areaSpiritHealerTime.HealerGuid = guid; - areaSpiritHealerTime.TimeLeft = m_LastResurectTimer;// resurrect every 30 seconds - - player.SendPacket(areaSpiritHealerTime); - } - public Creature SpawnCreature(uint entry, Position pos) { if (Global.ObjectMgr.GetCreatureTemplate(entry) == null) @@ -810,7 +757,6 @@ namespace Game.BattleFields // Graveyard variables protected List m_GraveyardList = new(); // Vector witch contain the different GY of the battle - uint m_LastResurectTimer; // Timer for resurect player every 30 sec protected uint m_StartGroupingTimer; // Timer for invite players in area 15 minute before start battle protected bool m_StartGrouping; // bool for know if all players in area has been invited @@ -856,58 +802,6 @@ namespace Game.BattleFields return player.GetDistance2d(safeLoc.Loc.GetPositionX(), safeLoc.Loc.GetPositionY()); } - public void AddPlayer(ObjectGuid playerGuid) - { - if (!m_ResurrectQueue.Contains(playerGuid)) - { - m_ResurrectQueue.Add(playerGuid); - Player player = Global.ObjAccessor.FindPlayer(playerGuid); - if (player) - player.CastSpell(player, BattlegroundConst.SpellWaitingForResurrect, true); - } - } - - public void RemovePlayer(ObjectGuid playerGuid) - { - m_ResurrectQueue.Remove(playerGuid); - - Player player = Global.ObjAccessor.FindPlayer(playerGuid); - if (player) - player.RemoveAurasDueToSpell(BattlegroundConst.SpellWaitingForResurrect); - } - - public void Resurrect() - { - if (m_ResurrectQueue.Empty()) - return; - - foreach (var guid in m_ResurrectQueue) - { - // Get player object from his guid - Player player = Global.ObjAccessor.FindPlayer(guid); - if (!player) - continue; - - // Check if the player is in world and on the good graveyard - if (player.IsInWorld) - { - Creature spirit = m_Bf.GetCreature(m_SpiritGuide[m_ControlTeam]); - if (spirit) - spirit.CastSpell(spirit, BattlegroundConst.SpellSpiritHeal, true); - } - - // Resurect player - player.CastSpell(player, BattlegroundConst.SpellResurrectionVisual, true); - player.ResurrectPlayer(1.0f); - player.CastSpell(player, 6962, true); - player.CastSpell(player, BattlegroundConst.SpellSpiritHealMana, true); - - player.SpawnCorpseBones(false); - } - - m_ResurrectQueue.Clear(); - } - // For changing graveyard control public void GiveControlTo(uint team) { @@ -918,29 +812,11 @@ namespace Game.BattleFields if (m_SpiritGuide[team]) m_SpiritGuide[team].SetVisible(true);*/ + Creature spiritHealer = m_Bf.GetCreature(m_SpiritGuide[team]); + if (spiritHealer != null) + spiritHealer.SummonGraveyardTeleporter(); + m_ControlTeam = team; - // Teleport to other graveyard, player witch were on this graveyard - RelocateDeadPlayers(); - } - - void RelocateDeadPlayers() - { - WorldSafeLocsEntry closestGrave = null; - foreach (var guid in m_ResurrectQueue) - { - Player player = Global.ObjAccessor.FindPlayer(guid); - if (!player) - continue; - - if (closestGrave != null) - player.TeleportTo(closestGrave.Loc); - else - { - closestGrave = m_Bf.GetClosestGraveYard(player); - if (closestGrave != null) - player.TeleportTo(closestGrave.Loc); - } - } } public bool HasNpc(ObjectGuid guid) @@ -955,9 +831,6 @@ namespace Game.BattleFields return (m_SpiritGuide[TeamId.Alliance] == guid || m_SpiritGuide[TeamId.Horde] == guid); } - // Check if a player is in this graveyard's ressurect queue - public bool HasPlayer(ObjectGuid guid) { return m_ResurrectQueue.Contains(guid); } - // Get the graveyard's ID. public uint GetGraveyardId() { return m_GraveyardId; } @@ -966,7 +839,6 @@ namespace Game.BattleFields uint m_ControlTeam; uint m_GraveyardId; ObjectGuid[] m_SpiritGuide = new ObjectGuid[SharedConst.PvpTeamsCount]; - List m_ResurrectQueue = new(); protected BattleField m_Bf; } diff --git a/Source/Game/BattleGrounds/BattleGround.cs b/Source/Game/BattleGrounds/BattleGround.cs index cf2f41c4c..86dae274f 100644 --- a/Source/Game/BattleGrounds/BattleGround.cs +++ b/Source/Game/BattleGrounds/BattleGround.cs @@ -117,7 +117,6 @@ namespace Game.BattleGrounds } else { - _ProcessRessurect(diff); if (Global.BattlegroundMgr.GetPrematureFinishTime() != 0 && (GetPlayersCountByTeam(Team.Alliance) < GetMinPlayersPerTeam() || GetPlayersCountByTeam(Team.Horde) < GetMinPlayersPerTeam())) _ProcessProgress(diff); else if (m_PrematureCountDown) @@ -214,61 +213,6 @@ namespace Game.BattleGrounds } } - void _ProcessRessurect(uint diff) - { - // ********************************************************* - // *** Battleground RESSURECTION SYSTEM *** - // ********************************************************* - // this should be handled by spell system - m_LastResurrectTime += diff; - if (m_LastResurrectTime >= BattlegroundConst.ResurrectionInterval) - { - if (GetReviveQueueSize() != 0) - { - Creature sh = null; - foreach (var pair in m_ReviveQueue) - { - Player player = Global.ObjAccessor.FindPlayer(pair.Value); - if (!player) - continue; - - if (!sh && player.IsInWorld) - { - sh = player.GetMap().GetCreature(pair.Key); - // only for visual effect - if (sh) - // Spirit Heal, effect 117 - sh.CastSpell(sh, BattlegroundConst.SpellSpiritHeal, true); - } - - // Resurrection visual - player.CastSpell(player, BattlegroundConst.SpellResurrectionVisual, true); - m_ResurrectQueue.Add(pair.Value); - } - - 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 - { - foreach (var guid in m_ResurrectQueue) - { - Player player = Global.ObjAccessor.FindPlayer(guid); - if (!player) - continue; - player.ResurrectPlayer(1.0f); - player.CastSpell(player, 6962, true); - player.CastSpell(player, BattlegroundConst.SpellSpiritHealMana, true); - player.SpawnCorpseBones(false); - } - m_ResurrectQueue.Clear(); - } - } - public virtual Team GetPrematureWinner() { Team winner = 0; @@ -835,8 +779,6 @@ namespace Game.BattleGrounds if (PlayerScores.ContainsKey(guid)) PlayerScores.Remove(guid); - RemovePlayerFromResurrectQueue(guid); - Player player = Global.ObjAccessor.FindPlayer(guid); if (player) { @@ -940,7 +882,6 @@ namespace Game.BattleGrounds SetStatus(BattlegroundStatus.WaitQueue); SetElapsedTime(0); SetRemainingTime(0); - SetLastResurrectTime(0); m_Events = 0; if (m_InvitedAlliance > 0 || m_InvitedHorde > 0) @@ -960,7 +901,6 @@ namespace Game.BattleGrounds public void StartBattleground() { SetElapsedTime(0); - SetLastResurrectTime(0); // add BG to free slot queue AddToBGFreeSlotQueue(); @@ -1313,56 +1253,6 @@ namespace Game.BattleGrounds return true; } - public void AddPlayerToResurrectQueue(ObjectGuid npc_guid, ObjectGuid player_guid) - { - m_ReviveQueue.Add(npc_guid, player_guid); - - Player player = Global.ObjAccessor.FindPlayer(player_guid); - if (!player) - return; - - player.CastSpell(player, BattlegroundConst.SpellWaitingForResurrect, true); - } - - public void RemovePlayerFromResurrectQueue(ObjectGuid player_guid) - { - foreach (var pair in m_ReviveQueue.KeyValueList) - { - if (pair.Value == player_guid) - { - m_ReviveQueue.Remove(pair); - Player player = Global.ObjAccessor.FindPlayer(player_guid); - if (player) - player.RemoveAurasDueToSpell(BattlegroundConst.SpellWaitingForResurrect); - return; - } - - } - } - - public void RelocateDeadPlayers(ObjectGuid guideGuid) - { - // Those who are waiting to resurrect at this node are taken to the closest own node's graveyard - List ghostList = m_ReviveQueue[guideGuid]; - if (!ghostList.Empty()) - { - WorldSafeLocsEntry closestGrave = null; - foreach (var guid in ghostList) - { - Player player = Global.ObjAccessor.FindPlayer(guid); - if (!player) - continue; - - if (closestGrave == null) - closestGrave = GetClosestGraveYard(player); - - if (closestGrave != null) - player.TeleportTo(closestGrave.Loc); - } - ghostList.Clear(); - } - } - public bool AddObject(int type, uint entry, float x, float y, float z, float o, float rotation0, float rotation1, float rotation2, float rotation3, uint respawnTime = 0, GameObjectState goState = GameObjectState.Ready) { Map map = FindBgMap(); @@ -1602,20 +1492,9 @@ namespace Game.BattleGrounds { uint entry = (uint)(teamIndex == TeamId.Alliance ? BattlegroundCreatures.A_SpiritGuide : BattlegroundCreatures.H_SpiritGuide); - Creature creature = AddCreature(entry, type, x, y, z, o); - if (creature) - { - creature.SetDeathState(DeathState.Dead); - creature.AddChannelObject(creature.GetGUID()); - // aura - //todo Fix display here - // creature.SetVisibleAura(0, SPELL_SPIRIT_HEAL_CHANNEL); - // casting visual effect - creature.SetChannelSpellId(BattlegroundConst.SpellSpiritHealChannel); - creature.SetChannelVisual(new SpellCastVisual(BattlegroundConst.SpellSpiritHealChannelVisual, 0)); - //creature.CastSpell(creature, SPELL_SPIRIT_HEAL_CHANNEL, true); + if (AddCreature(entry, type, x, y, z, o) != null) return true; - } + Log.outError(LogFilter.Battleground, $"Battleground.AddSpiritGuide: cannot create spirit guide (type: {type}, entry: {entry}) for BG (map: {GetMapId()}, instance id: {m_InstanceID})!"); EndNow(); return false; @@ -1965,7 +1844,6 @@ namespace Game.BattleGrounds public uint GetClientInstanceID() { return m_ClientInstanceID; } public uint GetElapsedTime() { return m_StartTime; } public uint GetRemainingTime() { return (uint)m_EndTime; } - public uint GetLastResurrectTime() { return m_LastResurrectTime; } int GetStartDelayTime() { return m_StartDelayTime; } public ArenaTypes GetArenaType() { return m_ArenaType; } @@ -1980,7 +1858,6 @@ namespace Game.BattleGrounds public void SetClientInstanceID(uint InstanceID) { m_ClientInstanceID = InstanceID; } public void SetElapsedTime(uint Time) { m_StartTime = Time; } public void SetRemainingTime(uint Time) { m_EndTime = (int)Time; } - public void SetLastResurrectTime(uint Time) { m_LastResurrectTime = Time; } public void SetRated(bool state) { m_IsRated = state; } public void SetArenaType(ArenaTypes type) { m_ArenaType = type; } public void SetWinner(PvPTeamId winnerTeamId) { _winnerTeamId = winnerTeamId; } @@ -2118,7 +1995,6 @@ namespace Game.BattleGrounds uint m_ResetStatTimer; uint m_ValidStartPositionTimer; int m_EndTime; // it is set to 120000 when bg is ending and it decreases itself - uint m_LastResurrectTime; ArenaTypes 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 @@ -2130,7 +2006,6 @@ namespace Game.BattleGrounds uint m_LastPlayerPositionBroadcast; // Player lists - List m_ResurrectQueue = new(); // Player GUID List m_OfflineQueue = new(); // 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/Source/Game/BattleGrounds/BattleGroundManager.cs b/Source/Game/BattleGrounds/BattleGroundManager.cs index 444015df7..d6ebf2004 100644 --- a/Source/Game/BattleGrounds/BattleGroundManager.cs +++ b/Source/Game/BattleGrounds/BattleGroundManager.cs @@ -452,19 +452,6 @@ namespace Game.BattleGrounds Log.outError(LogFilter.Battleground, $"BattlegroundMgr.SendToBattleground: Instance {instanceId} (bgType {bgTypeId}) not found while trying to teleport player {player.GetName()}"); } - public void SendAreaSpiritHealerQuery(Player player, Battleground bg, ObjectGuid guid) - { - uint time = 30000 - bg.GetLastResurrectTime(); // resurrect every 30 seconds - if (time == 0xFFFFFFFF) - time = 0; - - AreaSpiritHealerTime areaSpiritHealerTime = new(); - areaSpiritHealerTime.HealerGuid = guid; - areaSpiritHealerTime.TimeLeft = time; - - player.SendPacket(areaSpiritHealerTime); - } - bool IsArenaType(BattlegroundTypeId bgTypeId) { return bgTypeId == BattlegroundTypeId.AA || bgTypeId == BattlegroundTypeId.BE || bgTypeId == BattlegroundTypeId.NA diff --git a/Source/Game/BattleGrounds/Zones/ArathiBasin.cs b/Source/Game/BattleGrounds/Zones/ArathiBasin.cs index b6c919930..17139b4b9 100644 --- a/Source/Game/BattleGrounds/Zones/ArathiBasin.cs +++ b/Source/Game/BattleGrounds/Zones/ArathiBasin.cs @@ -377,8 +377,6 @@ namespace Game.BattleGrounds.Zones //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/Source/Game/Entities/Creature/Creature.cs b/Source/Game/Entities/Creature/Creature.cs index 6450a0443..acefe4cc1 100644 --- a/Source/Game/Entities/Creature/Creature.cs +++ b/Source/Game/Entities/Creature/Creature.cs @@ -427,6 +427,9 @@ namespace Game.Entities { if (IsAIEnabled() && triggerJustAppeared && m_deathState != DeathState.Dead) { + if (IsAreaSpiritHealer() && !IsAreaSpiritHealerIndividual()) + CastSpell(null, BattlegroundConst.SpellSpiritHealChannelAoE, false); + if (m_respawnCompatibilityMode && VehicleKit != null) VehicleKit.Reset(); @@ -1129,6 +1132,19 @@ namespace Game.Entities SetHomePosition(GetPosition()); } + public void SummonGraveyardTeleporter() + { + if (!IsAreaSpiritHealer()) + return; + + uint npcEntry = GetFaction() == (uint)FactionTemplates.AllianceGeneric ? 26350 : 26351u; + + // maybe NPC is summoned with these spells: + // ID - 24237 Summon Alliance Graveyard Teleporter (SERVERSIDE) + // ID - 46894 Summon Horde Graveyard Teleporter (SERVERSIDE) + SummonCreature(npcEntry, GetPosition(), TempSummonType.TimedDespawn, TimeSpan.FromSeconds(1), 0, 0); + } + public bool HasFlag(CreatureStaticFlags flag) { return _staticFlags.HasFlag(flag); } public bool HasFlag(CreatureStaticFlags2 flag) { return _staticFlags.HasFlag(flag); } public bool HasFlag(CreatureStaticFlags3 flag) { return _staticFlags.HasFlag(flag); } diff --git a/Source/Game/Entities/Player/Player.Fields.cs b/Source/Game/Entities/Player/Player.Fields.cs index 3217d3108..04b0b4d1e 100644 --- a/Source/Game/Entities/Player/Player.Fields.cs +++ b/Source/Game/Entities/Player/Player.Fields.cs @@ -55,6 +55,7 @@ namespace Game.Entities long m_lastHonorUpdateTime; uint m_contestedPvPTimer; bool _usePvpItemLevels; + ObjectGuid _areaSpiritHealerGUID; //Groups/Raids GroupReference m_group = new(); diff --git a/Source/Game/Entities/Player/Player.cs b/Source/Game/Entities/Player/Player.cs index aeffe3c16..b9141f7a8 100644 --- a/Source/Game/Entities/Player/Player.cs +++ b/Source/Game/Entities/Player/Player.cs @@ -3938,6 +3938,8 @@ namespace Game.Entities public void ResurrectPlayer(float restore_percent, bool applySickness = false) { + SetAreaSpiritHealer(null); + DeathReleaseLoc packet = new(); packet.MapID = -1; SendPacket(packet); @@ -4021,6 +4023,44 @@ namespace Game.Entities } } + ObjectGuid GetSpiritHealerGUID() { return _areaSpiritHealerGUID; } + + public bool CanAcceptAreaSpiritHealFrom(Unit spiritHealer) { return spiritHealer.GetGUID() == _areaSpiritHealerGUID; } + + public void SetAreaSpiritHealer(Creature creature) + { + if (!creature) + { + _areaSpiritHealerGUID = ObjectGuid.Empty; + RemoveAurasDueToSpell(BattlegroundConst.SpellWaitingForResurrect); + return; + } + + if (!creature.IsAreaSpiritHealer()) + return; + + _areaSpiritHealerGUID = creature.GetGUID(); + CastSpell(null, BattlegroundConst.SpellWaitingForResurrect); + } + + public void SendAreaSpiritHealerTime(Unit spiritHealer) + { + int timeLeft = 0; + Spell spell = spiritHealer.GetCurrentSpell(CurrentSpellTypes.Channeled); + if (spell != null) + timeLeft = spell.GetTimer(); + + SendAreaSpiritHealerTime(spiritHealer.GetGUID(), timeLeft); + } + + public void SendAreaSpiritHealerTime(ObjectGuid spiritHealerGUID, int timeLeft) + { + AreaSpiritHealerTime areaSpiritHealerTime = new(); + areaSpiritHealerTime.HealerGuid = spiritHealerGUID; + areaSpiritHealerTime.TimeLeft = (uint)timeLeft; + SendPacket(areaSpiritHealerTime); + } + public void KillPlayer() { if (IsFlying() && GetTransport() == null) diff --git a/Source/Game/Entities/Unit/Unit.cs b/Source/Game/Entities/Unit/Unit.cs index 3e87a2fab..64514026d 100644 --- a/Source/Game/Entities/Unit/Unit.cs +++ b/Source/Game/Entities/Unit/Unit.cs @@ -466,6 +466,9 @@ namespace Game.Entities if (IsInWorld) { + if (IsAreaSpiritHealer()) + ToCreature()?.SummonGraveyardTeleporter(); + m_duringRemoveFromWorld = true; UnitAI ai = GetAI(); if (ai != null) @@ -847,6 +850,7 @@ namespace Game.Entities NPCFlags.AreaSpiritHealer | NPCFlags.TabardDesigner | NPCFlags.Auctioneer); } public bool IsSpiritService() { return HasNpcFlag(NPCFlags.SpiritHealer | NPCFlags.AreaSpiritHealer); } + public bool IsAreaSpiritHealerIndividual() { return HasNpcFlag2(NPCFlags2.AreaSpiritHealerIndividual); } public bool IsCritter() { return GetCreatureType() == CreatureType.Critter; } public bool IsInFlight() { return HasUnitState(UnitState.InFlight); } diff --git a/Source/Game/Handlers/BattleGroundHandler.cs b/Source/Game/Handlers/BattleGroundHandler.cs index 728be0c06..6e9b6b8c3 100644 --- a/Source/Game/Handlers/BattleGroundHandler.cs +++ b/Source/Game/Handlers/BattleGroundHandler.cs @@ -10,6 +10,7 @@ using Game.Entities; using Game.Groups; using Game.Networking; using Game.Networking.Packets; +using Game.Spells; using System; using System.Collections.Generic; @@ -618,39 +619,53 @@ namespace Game [WorldPacketHandler(ClientOpcodes.AreaSpiritHealerQuery)] void HandleAreaSpiritHealerQuery(AreaSpiritHealerQuery areaSpiritHealerQuery) { - Creature unit = ObjectAccessor.GetCreature(GetPlayer(), areaSpiritHealerQuery.HealerGuid); - if (!unit) + Player player = GetPlayer(); + Creature spiritHealer = ObjectAccessor.GetCreature(player, areaSpiritHealerQuery.HealerGuid); + if (spiritHealer == null) return; - if (!unit.IsSpiritService()) // it's not spirit service + if (!spiritHealer.IsAreaSpiritHealer()) return; - Battleground bg = GetPlayer().GetBattleground(); - if (bg != null) - Global.BattlegroundMgr.SendAreaSpiritHealerQuery(GetPlayer(), bg, areaSpiritHealerQuery.HealerGuid); + if (_player.GetExactDist(spiritHealer) > PlayerConst.MaxAreaSpiritHealerRange) + return; - BattleField bf = Global.BattleFieldMgr.GetBattlefieldToZoneId(GetPlayer().GetMap(), GetPlayer().GetZoneId()); - if (bf != null) - bf.SendAreaSpiritHealerQuery(GetPlayer(), areaSpiritHealerQuery.HealerGuid); + if (spiritHealer.IsAreaSpiritHealerIndividual()) + { + Aura aura = player.GetAura(BattlegroundConst.SpellSpiritHealPlayerAura); + if (aura != null) + { + player.SendAreaSpiritHealerTime(spiritHealer.GetGUID(), aura.GetDuration()); + } + else + { + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(BattlegroundConst.SpellSpiritHealPlayerAura, Difficulty.None); + if (spellInfo != null) + { + spiritHealer.CastSpell(player, BattlegroundConst.SpellSpiritHealPlayerAura); + player.SendAreaSpiritHealerTime(spiritHealer.GetGUID(), spellInfo.GetDuration()); + spiritHealer.CastSpell(null, BattlegroundConst.SpellSpiritHealChannelSelf); + } + } + } + else + _player.SendAreaSpiritHealerTime(spiritHealer); } [WorldPacketHandler(ClientOpcodes.AreaSpiritHealerQueue)] void HandleAreaSpiritHealerQueue(AreaSpiritHealerQueue areaSpiritHealerQueue) { - Creature unit = ObjectAccessor.GetCreature(GetPlayer(), areaSpiritHealerQueue.HealerGuid); - if (!unit) + Creature spiritHealer = ObjectAccessor.GetCreature(GetPlayer(), areaSpiritHealerQueue.HealerGuid); + if (spiritHealer == null) return; - if (!unit.IsSpiritService()) // it's not spirit service + if (!spiritHealer.IsAreaSpiritHealer()) return; - Battleground bg = GetPlayer().GetBattleground(); - if (bg) - bg.AddPlayerToResurrectQueue(areaSpiritHealerQueue.HealerGuid, GetPlayer().GetGUID()); + if (_player.GetExactDist(spiritHealer) > PlayerConst.MaxAreaSpiritHealerRange) + return; - BattleField bf = Global.BattleFieldMgr.GetBattlefieldToZoneId(GetPlayer().GetMap(), GetPlayer().GetZoneId()); - if (bf != null) - bf.AddPlayerToResurrectQueue(areaSpiritHealerQueue.HealerGuid, GetPlayer().GetGUID()); + _player.SetAreaSpiritHealer(spiritHealer); } [WorldPacketHandler(ClientOpcodes.HearthAndResurrect)] diff --git a/Source/Game/Handlers/NPCHandler.cs b/Source/Game/Handlers/NPCHandler.cs index 6888e4335..248232838 100644 --- a/Source/Game/Handlers/NPCHandler.cs +++ b/Source/Game/Handlers/NPCHandler.cs @@ -138,16 +138,10 @@ namespace Game 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 = GetPlayer().GetBattleground(); - if (bg) - { - bg.AddPlayerToResurrectQueue(unit.GetGUID(), GetPlayer().GetGUID()); - Global.BattlegroundMgr.SendAreaSpiritHealerQuery(GetPlayer(), bg, unit.GetGUID()); - return; - } + _player.SetAreaSpiritHealer(unit); + _player.SendAreaSpiritHealerTime(unit); } _player.PlayerTalkClass.ClearMenus(); diff --git a/Source/Game/Spells/Auras/AuraEffect.cs b/Source/Game/Spells/Auras/AuraEffect.cs index 184dd03a5..27925d148 100644 --- a/Source/Game/Spells/Auras/AuraEffect.cs +++ b/Source/Game/Spells/Auras/AuraEffect.cs @@ -4317,18 +4317,6 @@ namespace Game.Spells case SpellFamilyNames.Generic: switch (GetId()) { - case 2584: // Waiting to Resurrect - // Waiting to resurrect spell cancel, we must remove player from resurrect queue - if (target.IsTypeId(TypeId.Player)) - { - Battleground bg = target.ToPlayer().GetBattleground(); - if (bg) - bg.RemovePlayerFromResurrectQueue(target.GetGUID()); - BattleField bf = Global.BattleFieldMgr.GetBattlefieldToZoneId(target.GetMap(), target.GetZoneId()); - if (bf != null) - bf.RemovePlayerFromResurrectQueue(target.GetGUID()); - } - break; case 36730: // Flame Strike target.CastSpell(target, 36731, new CastSpellExtraArgs(this)); break; diff --git a/Source/Game/Spells/Spell.cs b/Source/Game/Spells/Spell.cs index 0011d4b80..e95eb7f06 100644 --- a/Source/Game/Spells/Spell.cs +++ b/Source/Game/Spells/Spell.cs @@ -7960,6 +7960,8 @@ namespace Game.Spells public SpellInfo GetTriggeredByAuraSpell() { return m_triggeredByAuraSpell; } + public int GetTimer() { return m_timer; } + public static implicit operator bool(Spell spell) { return spell != null; diff --git a/Source/Game/Spells/SpellEffects.cs b/Source/Game/Spells/SpellEffects.cs index f3a6a158b..e87b317f3 100644 --- a/Source/Game/Spells/SpellEffects.cs +++ b/Source/Game/Spells/SpellEffects.cs @@ -4221,14 +4221,30 @@ namespace Game.Spells Log.outDebug(LogFilter.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 EffectSpiritHeal() { + Unit caster = GetCaster().ToUnit(); + if (effectHandleMode == SpellEffectHandleMode.Hit) + caster.CastSpell(null, BattlegroundConst.SpellResurrectionVisual, true); + if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; + + Player playerTarget = unitTarget.ToPlayer(); + if (playerTarget != null) + { + if (!playerTarget.IsInWorld) + return; + + // skip if player does not want to live + if (!playerTarget.CanAcceptAreaSpiritHealFrom(caster)) + return; + + playerTarget.ResurrectPlayer(1.0f); + playerTarget.CastSpell(playerTarget, BattlegroundConst.SpellPetSummoned, true); + playerTarget.CastSpell(playerTarget, BattlegroundConst.SpellSpiritHealMana, true); + playerTarget.SpawnCorpseBones(false); + } } // remove insignia spell effect diff --git a/Source/Game/Spells/SpellInfo.cs b/Source/Game/Spells/SpellInfo.cs index 5d16b4bdd..fde9a0ed9 100644 --- a/Source/Game/Spells/SpellInfo.cs +++ b/Source/Game/Spells/SpellInfo.cs @@ -902,8 +902,6 @@ namespace Game.Spells case 34976: // Netherstorm Flag return map_id == 566 && player != null && player.InBattleground() ? SpellCastResult.SpellCastOk : SpellCastResult.RequiresArea; 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/Source/Scripts/Spells/Generic.cs b/Source/Scripts/Spells/Generic.cs index bcf204af0..98de50586 100644 --- a/Source/Scripts/Spells/Generic.cs +++ b/Source/Scripts/Spells/Generic.cs @@ -1937,7 +1937,7 @@ namespace Scripts.Spells.Generic OnEffectRemove.Add(new EffectApplyHandler(OnRemove, 0, AuraType.Dummy, AuraEffectHandleModes.Real)); } } - + // 35357 - Spawn Feign Death [Script] // 51329 - Feign Death class spell_gen_feign_death_no_dyn_flag : AuraScript @@ -5010,17 +5010,17 @@ namespace Scripts.Spells.Generic } } - // 2825 - Bloodlust - // 32182 - Heroism - // 80353 - Time Warp - // 264667 - Primal Rage - // 390386 - Fury of the Aspects - // 146555 - Drums of Rage - // 178207 - Drums of Fury - // 230935 - Drums of the Mountain - // 256740 - Drums of the Maelstrom - // 309658 - Drums of Deathly Ferocity - // 381301 - Feral Hide Drums + // 2825 - Bloodlust + // 32182 - Heroism + // 80353 - Time Warp + // 264667 - Primal Rage + // 390386 - Fury of the Aspects + // 146555 - Drums of Rage + // 178207 - Drums of Fury + // 230935 - Drums of the Mountain + // 256740 - Drums of the Maelstrom + // 309658 - Drums of Deathly Ferocity + // 381301 - Feral Hide Drums [Script("spell_sha_bloodlust", SpellIds.ShamanSated)] [Script("spell_sha_heroism", SpellIds.ShamanExhaustion)] [Script("spell_mage_time_warp", SpellIds.MageTemporalDisplacement)] @@ -5071,6 +5071,112 @@ namespace Scripts.Spells.Generic } } + // AoE resurrections by spirit guides + [Script] // 22012 - Spirit Heal + class spell_gen_spirit_heal_aoe : SpellScript + { + void FilterTargets(List targets) + { + Unit caster = GetCaster(); + targets.RemoveAll(target => + { + Player playerTarget = target.ToPlayer(); + if (playerTarget != null) + return !playerTarget.CanAcceptAreaSpiritHealFrom(caster); + + return true; + }); + } + + public override void Register() + { + OnObjectAreaTargetSelect.Add(new ObjectAreaTargetSelectHandler(FilterTargets, 0, Targets.UnitDestAreaAlly)); + } + } + + // Personal resurrections in battlegrounds + [Script] // 156758 - Spirit Heal + class spell_gen_spirit_heal_personal : AuraScript + { + uint SPELL_SPIRIT_HEAL_EFFECT = 156763; + + void OnRemove(AuraEffect aurEff, AuraEffectHandleModes mode) + { + if (GetTargetApplication().GetRemoveMode() != AuraRemoveMode.Expire) + return; + + Player targetPlayer = GetTarget().ToPlayer(); + if (targetPlayer == null) + return; + + Unit caster = GetCaster(); + if (caster == null) + return; + + if (targetPlayer.CanAcceptAreaSpiritHealFrom(caster)) + caster.CastSpell(targetPlayer, SPELL_SPIRIT_HEAL_EFFECT); + } + + public override void Register() + { + AfterEffectRemove.Add(new EffectApplyHandler(OnRemove, 0, AuraType.Dummy, AuraEffectHandleModes.Real)); + } + } + + class RecastSpiritHealChannelEvent : BasicEvent + { + Unit _caster; + + public RecastSpiritHealChannelEvent(Unit caster) + { + _caster = caster; + } + + public override bool Execute(ulong e_time, uint p_time) + { + if (_caster.GetChannelSpellId() == 0) + _caster.CastSpell(null, BattlegroundConst.SpellSpiritHealChannelAoE, false); + + return true; + } + } + + [Script] // 22011 - Spirit Heal Channel + class spell_gen_spirit_heal_channel : AuraScript + { + void OnRemove(AuraEffect aurEff, AuraEffectHandleModes mode) + { + if (GetTargetApplication().GetRemoveMode() != AuraRemoveMode.Expire) + return; + + Unit target = GetTarget(); + target.m_Events.AddEventAtOffset(new RecastSpiritHealChannelEvent(target), TimeSpan.FromSeconds(1)); + } + + public override void Register() + { + AfterEffectRemove.Add(new EffectApplyHandler(OnRemove, 0, AuraType.PeriodicTriggerSpell, AuraEffectHandleModes.Real)); + } + } + + [Script] // 2584 - Waiting to Resurrect + class spell_gen_waiting_to_resurrect : AuraScript + { + void OnRemove(AuraEffect aurEff, AuraEffectHandleModes mode) + { + Player targetPlayer = GetTarget().ToPlayer(); + if (targetPlayer == null) + return; + + targetPlayer.SetAreaSpiritHealer(null); + } + + public override void Register() + { + AfterEffectRemove.Add(new EffectApplyHandler(OnRemove, 0, AuraType.Dummy, AuraEffectHandleModes.Real)); + } + } + // 40307 - Stasis Field class StasisFieldSearcher : ICheck {