diff --git a/Source/Game/Entities/AreaTrigger/AreaTrigger.cs b/Source/Game/Entities/AreaTrigger/AreaTrigger.cs index a5e7fd851..304657b22 100644 --- a/Source/Game/Entities/AreaTrigger/AreaTrigger.cs +++ b/Source/Game/Entities/AreaTrigger/AreaTrigger.cs @@ -832,56 +832,71 @@ namespace Game.Entities // Handle after _insideUnits have been reinserted so we can use GetInsideUnits() in hooks foreach (Unit unit in enteringUnits) - { - Player player = unit.ToPlayer(); - if (player != null) - { - if (player.IsDebugAreaTriggers) - player.SendSysMessage(CypherStrings.DebugAreatriggerEntityEntered, GetEntry(), IsCustom(), IsStaticSpawn(), _spawnId); - - player.UpdateQuestObjectiveProgress(QuestObjectiveType.AreaTriggerEnter, (int)GetEntry(), 1); - - if (GetTemplate().ActionSetId != 0) - player.UpdateCriteria(CriteriaType.EnterAreaTriggerWithActionSet, GetTemplate().ActionSetId); - } - - DoActions(unit); - - _ai.OnUnitEnter(unit); - } + HandleUnitEnter(unit); foreach (ObjectGuid exitUnitGuid in exitUnits) { Unit leavingUnit = Global.ObjAccessor.GetUnit(this, exitUnitGuid); if (leavingUnit != null) - { - Player player = leavingUnit.ToPlayer(); - if (player != null) - { - if (player.IsDebugAreaTriggers) - player.SendSysMessage(CypherStrings.DebugAreatriggerEntityLeft, GetEntry(), IsCustom(), IsStaticSpawn(), _spawnId); - - player.UpdateQuestObjectiveProgress(QuestObjectiveType.AreaTriggerExit, (int)GetEntry(), 1); - - if (GetTemplate().ActionSetId != 0) - player.UpdateCriteria(CriteriaType.LeaveAreaTriggerWithActionSet, GetTemplate().ActionSetId); - } - - UndoActions(leavingUnit); - - _ai.OnUnitExit(leavingUnit); - } + HandleUnitExitInternal(leavingUnit); } - if (_insideUnits.Any(guid => guid.IsPlayer())) - SetAreaTriggerFlag(AreaTriggerFieldFlags.HasPlayers); - else - RemoveAreaTriggerFlag(AreaTriggerFieldFlags.HasPlayers); + UpdateHasPlayersFlag(); if (IsStaticSpawn()) SetActive(!_insideUnits.Empty()); } + void HandleUnitEnter(Unit unit) + { + Player player = unit.ToPlayer(); + if (player != null) + { + if (player.IsDebugAreaTriggers) + player.SendSysMessage(CypherStrings.DebugAreatriggerEntityEntered, GetEntry(), IsCustom(), IsStaticSpawn(), _spawnId); + + player.UpdateQuestObjectiveProgress(QuestObjectiveType.AreaTriggerEnter, (int)GetEntry(), 1); + + if (GetTemplate().ActionSetId != 0) + player.UpdateCriteria(CriteriaType.EnterAreaTriggerWithActionSet, GetTemplate().ActionSetId); + } + + DoActions(unit); + + _ai.OnUnitEnter(unit); + unit.EnterAreaTrigger(this); + } + + void HandleUnitExitInternal(Unit unit) + { + Player player = unit.ToPlayer(); + if (player != null) + { + if (player.IsDebugAreaTriggers) + player.SendSysMessage(CypherStrings.DebugAreatriggerEntityLeft, GetEntry(), IsCustom(), IsStaticSpawn(), _spawnId); + + player.UpdateQuestObjectiveProgress(QuestObjectiveType.AreaTriggerExit, (int)GetEntry(), 1); + + if (GetTemplate().ActionSetId != 0) + player.UpdateCriteria(CriteriaType.LeaveAreaTriggerWithActionSet, GetTemplate().ActionSetId); + } + + UndoActions(unit); + + _ai.OnUnitExit(unit); + unit.ExitAreaTrigger(this); + } + + public void HandleUnitExit(Unit unit) + { + _insideUnits.Remove(unit.GetGUID()); + + HandleUnitExitInternal(unit); + + UpdateHasPlayersFlag(); + } + + public AreaTriggerTemplate GetTemplate() { return _areaTriggerTemplate; @@ -1501,6 +1516,14 @@ namespace Game.Entities public bool IsStaticSpawn() { return _spawnId != 0; } public bool HasActionSetFlag(AreaTriggerActionSetFlag flag) { return _areaTriggerTemplate.ActionSetFlags.HasFlag(flag); } + void UpdateHasPlayersFlag() + { + if (_insideUnits.Any(guid => guid.IsPlayer())) + SetAreaTriggerFlag(AreaTriggerFieldFlags.HasPlayers); + else + RemoveAreaTriggerFlag(AreaTriggerFieldFlags.HasPlayers); + } + [System.Diagnostics.Conditional("DEBUG")] void DebugVisualizePosition() { diff --git a/Source/Game/Entities/Player/Player.cs b/Source/Game/Entities/Player/Player.cs index be53a15a5..4cd0a6f81 100644 --- a/Source/Game/Entities/Player/Player.cs +++ b/Source/Game/Entities/Player/Player.cs @@ -4795,6 +4795,9 @@ namespace Game.Entities pet.CombatStop(); + // exit areatriggers before saving to remove auras applied by them + pet.ExitAllAreaTriggers(); + // only if current pet in slot pet.SavePetToDB(mode); diff --git a/Source/Game/Entities/Unit/Unit.Fields.cs b/Source/Game/Entities/Unit/Unit.Fields.cs index 34fe80e43..cd21d3bfa 100644 --- a/Source/Game/Entities/Unit/Unit.Fields.cs +++ b/Source/Game/Entities/Unit/Unit.Fields.cs @@ -101,6 +101,7 @@ namespace Game.Entities DiminishingReturn[] m_Diminishing = new DiminishingReturn[(int)DiminishingGroup.Max]; protected List m_gameObj = new(); List m_areaTrigger = new(); + List m_insideAreaTriggers = new(); protected List m_dynObj = new(); protected float[] CreateStats = new float[(int)Stats.Max]; float[] m_floatStatPosBuff = new float[(int)Stats.Max]; diff --git a/Source/Game/Entities/Unit/Unit.cs b/Source/Game/Entities/Unit/Unit.cs index 9ae394593..1137eb1a2 100644 --- a/Source/Game/Entities/Unit/Unit.cs +++ b/Source/Game/Entities/Unit/Unit.cs @@ -877,6 +877,24 @@ namespace Game.Entities } } + public void EnterAreaTrigger(AreaTrigger areaTrigger) + { + m_insideAreaTriggers.Add(areaTrigger); + } + + public void ExitAreaTrigger(AreaTrigger areaTrigger) + { + m_insideAreaTriggers.Remove(areaTrigger); + } + + public void ExitAllAreaTriggers() + { + foreach (AreaTrigger at in m_insideAreaTriggers.ToList()) + at.HandleUnitExit(this); + } + + public List GetInsideAreaTriggers() { return m_insideAreaTriggers; } + public NPCFlags GetNpcFlags() { return (NPCFlags)m_unitData.NpcFlags.GetValue(); } public bool HasNpcFlag(NPCFlags flags) { return (m_unitData.NpcFlags & (uint)flags) != 0; } public void SetNpcFlag(NPCFlags flags) { SetUpdateFieldFlagValue(m_values.ModifyValue(m_unitData).ModifyValue(m_unitData.NpcFlags), (uint)flags); } diff --git a/Source/Game/Server/WorldSession.cs b/Source/Game/Server/WorldSession.cs index 75230012c..9a9ca124c 100644 --- a/Source/Game/Server/WorldSession.cs +++ b/Source/Game/Server/WorldSession.cs @@ -163,6 +163,9 @@ namespace Game _player.FailQuestsWithFlag(QuestFlags.FailOnLogout); + // exit areatriggers before saving to remove auras applied by them + _player.ExitAllAreaTriggers(); + // empty buyback items and save the player in the database // some save parts only correctly work in case player present in map/player_lists (pets, etc) if (save)