From 659080b5a59740214c65cb9a3ed2c356688cff48 Mon Sep 17 00:00:00 2001 From: hondacrx Date: Wed, 24 Jan 2018 12:06:19 -0500 Subject: [PATCH] Core/Entities: fix interaction of traps with ffa pvp and sanctuary flags --- Source/Game/Entities/GameObject/GameObject.cs | 4 ++- Source/Game/Entities/Unit/Unit.Combat.cs | 35 +++++++++++++------ Source/Game/Entities/Unit/Unit.cs | 3 +- Source/Game/Maps/GridNotifiers.cs | 6 ++-- 4 files changed, 31 insertions(+), 17 deletions(-) diff --git a/Source/Game/Entities/GameObject/GameObject.cs b/Source/Game/Entities/GameObject/GameObject.cs index a562c18bc..071529ec6 100644 --- a/Source/Game/Entities/GameObject/GameObject.cs +++ b/Source/Game/Entities/GameObject/GameObject.cs @@ -565,7 +565,7 @@ namespace Game.Entities if (owner) { // Hunter trap: Search units which are unfriendly to the trap's owner - var checker = new NearestUnfriendlyNoTotemUnitInObjectRangeCheck(this, owner, radius); + var checker = new NearestAttackableNoTotemUnitInObjectRangeCheck(this, owner, radius); var searcher = new UnitLastSearcher(this, checker); Cell.VisitAllObjects(this, searcher, radius); target = searcher.GetTarget(); @@ -1944,6 +1944,8 @@ namespace Game.Entities trigger.SetFaction(owner.getFaction()); if (owner.HasFlag(UnitFields.Flags, UnitFlags.PvpAttackable)) trigger.SetFlag(UnitFields.Flags, UnitFlags.PvpAttackable); + // copy pvp state flags from owner + trigger.SetByteValue(UnitFields.Bytes2, UnitBytes2Offsets.PvpFlag, owner.GetByteValue(UnitFields.Bytes2, UnitBytes2Offsets.PvpFlag)); // needed for GO casts for proper target validation checks trigger.SetOwnerGUID(owner.GetGUID()); trigger.CastSpell(target != null ? target : trigger, spellInfo, triggered, null, null, owner.GetGUID()); diff --git a/Source/Game/Entities/Unit/Unit.Combat.cs b/Source/Game/Entities/Unit/Unit.Combat.cs index 67f33160d..01aa6d036 100644 --- a/Source/Game/Entities/Unit/Unit.Combat.cs +++ b/Source/Game/Entities/Unit/Unit.Combat.cs @@ -2903,10 +2903,26 @@ namespace Game.Entities || (target.IsTypeId(TypeId.Player) && target.ToPlayer().IsGameMaster())) return false; - // can't attack invisible (ignore stealth for aoe spells) also if the area being looked at is from a spell use the dynamic object created instead of the casting unit. Ignore stealth if target is player and unit in combat with same player - // skip visibility check for GO casts, needs removal when go cast is implemented - if (GetEntry() != SharedConst.WorldTrigger && (bySpell == null || !bySpell.HasAttribute(SpellAttr6.CanTargetInvisible)) && (obj ? !obj.CanSeeOrDetect(target, bySpell != null && bySpell.IsAffectingArea(GetMap().GetDifficultyID())) : !CanSeeOrDetect(target, (bySpell != null && bySpell.IsAffectingArea(GetMap().GetDifficultyID())) || (target.GetTypeId() == TypeId.Player && target.HasStealthAura() && target.IsInCombat() && IsInCombatWith(target))))) - return false; + // visibility checks + // skip visibility check for GO casts, needs removal when go cast is implemented. Also ignore for gameobject and dynauras + if (GetEntry() != SharedConst.WorldTrigger && (!obj || !obj.isTypeMask(TypeMask.GameObject | TypeMask.DynamicObject))) + { + // can't attack invisible + if (bySpell == null || !bySpell.HasAttribute(SpellAttr6.CanTargetInvisible)) + { + if (obj && !obj.CanSeeOrDetect(target, bySpell != null && bySpell.IsAffectingArea(GetMap().GetDifficultyID()))) + return false; + else if (!obj) + { + // ignore stealth for aoe spells. Ignore stealth if target is player and unit in combat with same player + bool ignoreStealthCheck = (bySpell != null && bySpell.IsAffectingArea(GetMap().GetDifficultyID())) || + (target.GetTypeId() == TypeId.Player && target.HasStealthAura() && target.IsInCombat() && IsInCombatWith(target)); + + if (!CanSeeOrDetect(target, ignoreStealthCheck)) + return false; + } + } + } // can't attack dead if ((bySpell == null || !bySpell.IsAllowingDeadTarget()) && !target.IsAlive()) @@ -2942,8 +2958,7 @@ namespace Game.Entities // PvP, PvC, CvP case // can't attack friendly targets - if (GetReactionTo(target) > ReputationRank.Neutral - || target.GetReactionTo(this) > ReputationRank.Neutral) + if (GetReactionTo(target) > ReputationRank.Neutral || target.GetReactionTo(this) > ReputationRank.Neutral) return false; Player playerAffectingAttacker = HasFlag(UnitFields.Flags, UnitFlags.PvpAttackable) ? GetAffectingPlayer() : null; @@ -2996,15 +3011,13 @@ namespace Game.Entities // additional checks - only PvP case if (playerAffectingAttacker != null && playerAffectingTarget != null) { - if (Convert.ToBoolean(target.GetByteValue(UnitFields.Bytes2, UnitBytes2Offsets.PvpFlag) & (byte)UnitBytes2Flags.PvP)) + if (target.IsPvP()) return true; - if (Convert.ToBoolean(GetByteValue(UnitFields.Bytes2, UnitBytes2Offsets.PvpFlag) & (byte)UnitBytes2Flags.FFAPvp) - && Convert.ToBoolean(target.GetByteValue(UnitFields.Bytes2, UnitBytes2Offsets.PvpFlag) & (byte)UnitBytes2Flags.FFAPvp)) + if (IsFFAPvP() && target.IsFFAPvP()) return true; - return (Convert.ToBoolean(GetByteValue(UnitFields.Bytes2, UnitBytes2Offsets.PvpFlag) & (byte)UnitBytes2Flags.Unk1) - || Convert.ToBoolean(target.GetByteValue(UnitFields.Bytes2, UnitBytes2Offsets.PvpFlag) & (byte)UnitBytes2Flags.Unk1)); + return HasByteFlag(UnitFields.Bytes2, UnitBytes2Offsets.PvpFlag, UnitBytes2Flags.Unk1) || target.HasByteFlag(UnitFields.Bytes2, UnitBytes2Offsets.PvpFlag, UnitBytes2Flags.Unk1); } return true; } diff --git a/Source/Game/Entities/Unit/Unit.cs b/Source/Game/Entities/Unit/Unit.cs index 7cadfd1cf..6bba882bd 100644 --- a/Source/Game/Entities/Unit/Unit.cs +++ b/Source/Game/Entities/Unit/Unit.cs @@ -2508,8 +2508,7 @@ namespace Game.Entities } // check FFA_PVP - if (Convert.ToBoolean(GetByteValue(UnitFields.Bytes2, UnitBytes2Offsets.PvpFlag) & (byte)UnitBytes2Flags.FFAPvp) - && Convert.ToBoolean(target.GetByteValue(UnitFields.Bytes2, UnitBytes2Offsets.PvpFlag) & (byte)UnitBytes2Flags.FFAPvp)) + if (IsFFAPvP() && target.IsFFAPvP()) return ReputationRank.Hostile; if (selfPlayerOwner != null) diff --git a/Source/Game/Maps/GridNotifiers.cs b/Source/Game/Maps/GridNotifiers.cs index 9ffdeb3e3..28a015c6a 100644 --- a/Source/Game/Maps/GridNotifiers.cs +++ b/Source/Game/Maps/GridNotifiers.cs @@ -1458,9 +1458,9 @@ namespace Game.Maps float i_range; } - public class NearestUnfriendlyNoTotemUnitInObjectRangeCheck : ICheck + public class NearestAttackableNoTotemUnitInObjectRangeCheck : ICheck { - public NearestUnfriendlyNoTotemUnitInObjectRangeCheck(WorldObject obj, Unit funit, float range) + public NearestAttackableNoTotemUnitInObjectRangeCheck(WorldObject obj, Unit funit, float range) { i_obj = obj; i_funit = funit; @@ -1481,7 +1481,7 @@ namespace Game.Maps if (!u.isTargetableForAttack(false)) return false; - if (!i_obj.IsWithinDistInMap(u, i_range) || i_funit.IsFriendlyTo(u)) + if (!i_obj.IsWithinDistInMap(u, i_range) || i_funit._IsValidAttackTarget(u, null, i_obj)) return false; i_range = i_obj.GetDistance(u);