diff options
author | ariel- <ariel-@users.noreply.github.com> | 2016-11-19 15:43:22 -0300 |
---|---|---|
committer | joschiwald <joschiwald.trinity@gmail.com> | 2018-01-21 14:51:49 +0100 |
commit | 2c022a5aa8123d12cfdc681000eeb62be039aff1 (patch) | |
tree | fb175272c335e108d80aed3c73d074f4438862e4 | |
parent | 771ec0b2256e0f88b365e47af5b8d837a3cae445 (diff) |
Core/Entities: fix interaction of traps with ffa pvp and sanctuary flags
- Traps should select ATTACKABLE not UNFRIENDLY targets (it shouldn't attack unfriendly targets on sanctuary zones for example)
- Made more readable the nasty oneliner in Unit::_IsValidAttackTarget
Closes #6464
Closes #18271
(cherry picked from commit ef227d7e64a3dc62fbf0cba0209202310b1af00b)
-rw-r--r-- | src/server/game/Entities/GameObject/GameObject.cpp | 6 | ||||
-rw-r--r-- | src/server/game/Entities/Unit/Unit.cpp | 44 | ||||
-rw-r--r-- | src/server/game/Grids/Notifiers/GridNotifiers.h | 8 |
3 files changed, 36 insertions, 22 deletions
diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index 7e6a557c499..e33d099b2ac 100644 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -608,8 +608,8 @@ void GameObject::Update(uint32 diff) if (Unit* owner = GetOwner()) { // Hunter trap: Search units which are unfriendly to the trap's owner - Trinity::NearestUnfriendlyNoTotemUnitInObjectRangeCheck checker(this, owner, radius); - Trinity::UnitLastSearcher<Trinity::NearestUnfriendlyNoTotemUnitInObjectRangeCheck> searcher(this, target, checker); + Trinity::NearestAttackableNoTotemUnitInObjectRangeCheck checker(this, owner, radius); + Trinity::UnitLastSearcher<Trinity::NearestAttackableNoTotemUnitInObjectRangeCheck> searcher(this, target, checker); Cell::VisitAllObjects(this, searcher, radius); } else @@ -1980,6 +1980,8 @@ void GameObject::CastSpell(Unit* target, uint32 spellId, TriggerCastFlags trigge trigger->setFaction(owner->getFaction()); if (owner->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE)) trigger->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE); + // copy pvp state flags from owner + trigger->SetByteValue(UNIT_FIELD_BYTES_2, UNIT_BYTES_2_OFFSET_PVP_FLAG, owner->GetByteValue(UNIT_FIELD_BYTES_2, UNIT_BYTES_2_OFFSET_PVP_FLAG)); // needed for GO casts for proper target validation checks trigger->SetOwnerGUID(owner->GetGUID()); trigger->CastSpell(target ? target : trigger, spellInfo, triggered, nullptr, nullptr, owner->GetGUID()); diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index c4c47317f25..f80966aeaf1 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -5319,8 +5319,7 @@ ReputationRank Unit::GetReactionTo(Unit const* target) const } // check FFA_PVP - if (GetByteValue(UNIT_FIELD_BYTES_2, UNIT_BYTES_2_OFFSET_PVP_FLAG) & UNIT_BYTE2_FLAG_FFA_PVP - && target->GetByteValue(UNIT_FIELD_BYTES_2, UNIT_BYTES_2_OFFSET_PVP_FLAG) & UNIT_BYTE2_FLAG_FFA_PVP) + if (IsFFAPvP() && target->IsFFAPvP()) return REP_HOSTILE; if (selfPlayerOwner) @@ -7911,10 +7910,26 @@ bool Unit::_IsValidAttackTarget(Unit const* target, SpellInfo const* bySpell, Wo || (target->GetTypeId() == 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() != WORLD_TRIGGER && (!bySpell || !bySpell->HasAttribute(SPELL_ATTR6_CAN_TARGET_INVISIBLE)) && (obj ? !obj->CanSeeOrDetect(target, bySpell && bySpell->IsAffectingArea(GetMap()->GetDifficultyID())) : !CanSeeOrDetect(target, (bySpell && 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() != WORLD_TRIGGER && (!obj || !obj->isType(TYPEMASK_GAMEOBJECT | TYPEMASK_DYNAMICOBJECT))) + { + // can't attack invisible + if (!bySpell || !bySpell->HasAttribute(SPELL_ATTR6_CAN_TARGET_INVISIBLE)) + { + if (obj && !obj->CanSeeOrDetect(target, bySpell && 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 const ignoreStealthCheck = (bySpell && 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 || !bySpell->IsAllowingDeadTarget()) && !target->IsAlive()) @@ -7949,7 +7964,7 @@ bool Unit::_IsValidAttackTarget(Unit const* target, SpellInfo const* bySpell, Wo // PvP, PvC, CvP case // can't attack friendly targets - if ( GetReactionTo(target) > REP_NEUTRAL + if (GetReactionTo(target) > REP_NEUTRAL || target->GetReactionTo(this) > REP_NEUTRAL) return false; @@ -7957,10 +7972,8 @@ bool Unit::_IsValidAttackTarget(Unit const* target, SpellInfo const* bySpell, Wo Player const* playerAffectingTarget = target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE) ? target->GetAffectingPlayer() : nullptr; // Not all neutral creatures can be attacked (even some unfriendly faction does not react aggresive to you, like Sporaggar) - if ( - (playerAffectingAttacker && !playerAffectingTarget) || - (!playerAffectingAttacker && playerAffectingTarget) - ) + if ((playerAffectingAttacker && !playerAffectingTarget) || + (!playerAffectingAttacker && playerAffectingTarget)) { Player const* player = playerAffectingAttacker ? playerAffectingAttacker : playerAffectingTarget; Unit const* creature = playerAffectingAttacker ? target : this; @@ -7994,15 +8007,14 @@ bool Unit::_IsValidAttackTarget(Unit const* target, SpellInfo const* bySpell, Wo // additional checks - only PvP case if (playerAffectingAttacker && playerAffectingTarget) { - if (target->GetByteValue(UNIT_FIELD_BYTES_2, UNIT_BYTES_2_OFFSET_PVP_FLAG) & UNIT_BYTE2_FLAG_PVP) + if (target->IsPvP()) return true; - if (GetByteValue(UNIT_FIELD_BYTES_2, UNIT_BYTES_2_OFFSET_PVP_FLAG) & UNIT_BYTE2_FLAG_FFA_PVP - && target->GetByteValue(UNIT_FIELD_BYTES_2, UNIT_BYTES_2_OFFSET_PVP_FLAG) & UNIT_BYTE2_FLAG_FFA_PVP) + if (IsFFAPvP() && target->IsFFAPvP()) return true; - return (GetByteValue(UNIT_FIELD_BYTES_2, UNIT_BYTES_2_OFFSET_PVP_FLAG) & UNIT_BYTE2_FLAG_UNK1) - || (target->GetByteValue(UNIT_FIELD_BYTES_2, UNIT_BYTES_2_OFFSET_PVP_FLAG) & UNIT_BYTE2_FLAG_UNK1); + return HasByteFlag(UNIT_FIELD_BYTES_2, UNIT_BYTES_2_OFFSET_PVP_FLAG, UNIT_BYTE2_FLAG_UNK1) + || target->HasByteFlag(UNIT_FIELD_BYTES_2, UNIT_BYTES_2_OFFSET_PVP_FLAG, UNIT_BYTE2_FLAG_UNK1); } return true; } diff --git a/src/server/game/Grids/Notifiers/GridNotifiers.h b/src/server/game/Grids/Notifiers/GridNotifiers.h index 9c678db944e..f2611edab14 100644 --- a/src/server/game/Grids/Notifiers/GridNotifiers.h +++ b/src/server/game/Grids/Notifiers/GridNotifiers.h @@ -862,10 +862,10 @@ namespace Trinity float i_range; }; - class NearestUnfriendlyNoTotemUnitInObjectRangeCheck + class NearestAttackableNoTotemUnitInObjectRangeCheck { public: - NearestUnfriendlyNoTotemUnitInObjectRangeCheck(WorldObject const* obj, Unit const* funit, float range) : i_obj(obj), i_funit(funit), i_range(range) { } + NearestAttackableNoTotemUnitInObjectRangeCheck(WorldObject const* obj, Unit const* funit, float range) : i_obj(obj), i_funit(funit), i_range(range) { } bool operator()(Unit* u) { @@ -875,13 +875,13 @@ namespace Trinity if (u->GetCreatureType() == CREATURE_TYPE_NON_COMBAT_PET) return false; - if (u->GetTypeId() == TYPEID_UNIT && ((Creature*)u)->IsTotem()) + if (u->GetTypeId() == TYPEID_UNIT && u->ToCreature()->IsTotem()) return false; 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, nullptr, i_obj)) return false; i_range = i_obj->GetDistance(*u); |