diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index 681d6e9627..278761ce6e 100644 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -1130,6 +1130,35 @@ bool GameObject::Create(uint32 entry, Map* map, Position const& pos, QuaternionD m_invisibility.AddFlag(INVISIBILITY_TRAP); m_invisibility.AddValue(INVISIBILITY_TRAP, 300); } + + m_goValue.Trap.TargetSearcherCheckType = TARGET_CHECK_ENEMY; + if (SpellInfo const* trapSpell = sSpellMgr->GetSpellInfo(goInfo->trap.spell, map->GetDifficultyID())) + { + // positive spells may require enemy targets + if (trapSpell->IsPositive()) + { + bool targetsAlly = false; + bool targetsEnemy = false; + auto isAllyTarget = [](SpellImplicitTargetInfo const& targetInfo) + { + return targetInfo.GetObjectType() == TARGET_OBJECT_TYPE_UNIT && targetInfo.GetCheckType() == TARGET_CHECK_ALLY; + }; + auto isEnemyTarget = [](SpellImplicitTargetInfo const& targetInfo) + { + return targetInfo.GetObjectType() == TARGET_OBJECT_TYPE_UNIT && targetInfo.GetCheckType() == TARGET_CHECK_ENEMY; + }; + for (SpellEffectInfo const& spellEffectInfo : trapSpell->GetEffects()) + { + if (!spellEffectInfo.IsEffect()) + continue; + + targetsAlly = targetsAlly || isAllyTarget(spellEffectInfo.TargetA) || isAllyTarget(spellEffectInfo.TargetB); + targetsEnemy = targetsEnemy || isEnemyTarget(spellEffectInfo.TargetA) || isEnemyTarget(spellEffectInfo.TargetB); + } + if (targetsAlly) + m_goValue.Trap.TargetSearcherCheckType = targetsEnemy ? TARGET_CHECK_DEFAULT : TARGET_CHECK_ALLY; + } + } break; case GAMEOBJECT_TYPE_CONTROL_ZONE: m_goTypeImpl = std::make_unique(*this); @@ -1472,10 +1501,21 @@ void GameObject::Update(uint32 diff) if (GetOwner() || goInfo->trap.Checkallunits) { - // Hunter trap: Search units which are unfriendly to the trap's owner - Trinity::NearestAttackableNoTotemUnitInObjectRangeCheck checker(this, radius); - Trinity::UnitLastSearcher searcher(this, target, checker); - Cell::VisitAllObjects(this, searcher, radius); + // summoned traps: Search targets fit to trap spell data + if (SpellInfo const* trapSpell = sSpellMgr->GetSpellInfo(goInfo->trap.spell, GetMap()->GetDifficultyID())) + { + WorldObject* worldObjectTarget = nullptr; + Trinity::WorldObjectSpellNearbyTargetCheck checker(radius, this, trapSpell, m_goValue.Trap.TargetSearcherCheckType, nullptr, TARGET_OBJECT_TYPE_UNIT); + Trinity::WorldObjectLastSearcher searcher(this, worldObjectTarget, checker, GRID_MAP_TYPE_MASK_CREATURE | GRID_MAP_TYPE_MASK_PLAYER); + Cell::VisitAllObjects(this, searcher, radius); + target = Object::ToUnit(worldObjectTarget); + } + else + { + Trinity::NearestAttackableNoTotemUnitInObjectRangeCheck checker(this, radius); + Trinity::UnitLastSearcher searcher(this, target, checker); + Cell::VisitAllObjects(this, searcher, radius); + } } else { diff --git a/src/server/game/Entities/GameObject/GameObject.h b/src/server/game/Entities/GameObject/GameObject.h index 43b3e063ae..e5da7fb977 100644 --- a/src/server/game/Entities/GameObject/GameObject.h +++ b/src/server/game/Entities/GameObject/GameObject.h @@ -33,6 +33,7 @@ class TransportBase; class Unit; struct Loot; struct TransportAnimation; +enum SpellTargetCheckTypes : uint8; enum TriggerCastFlags : uint32; namespace Vignettes @@ -122,6 +123,11 @@ private: union GameObjectValue { + //6 GAMEOBJECT_TYPE_TRAP + struct + { + SpellTargetCheckTypes TargetSearcherCheckType; + } Trap; //25 GAMEOBJECT_TYPE_FISHINGHOLE struct {