diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index 9181388dda..17c1d66a23 100644 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -748,6 +748,37 @@ bool GameObject::Create(ObjectGuid::LowType guidlow, uint32 name_id, Map* map, P 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)) + { + // 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 (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + { + SpellEffectInfo const& spellEffectInfo = trapSpell->Effects[i]; + 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; default: SetGoAnimProgress(animprogress); @@ -999,10 +1030,21 @@ void GameObject::Update(uint32 diff) /// @todo this hack with search required until GO casting not implemented if (GetOwner()) { - // 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)) + { + WorldObject* worldObjectTarget = nullptr; + Trinity::WorldObjectSpellNearbyTargetCheck checker(radius, this, trapSpell, m_goValue.Trap.TargetSearcherCheckType, nullptr); + Trinity::WorldObjectLastSearcher searcher(this, worldObjectTarget, checker, GRID_MAP_TYPE_MASK_CREATURE | GRID_MAP_TYPE_MASK_PLAYER); + Cell::VisitAllObjects(this, searcher, radius); + target = (worldObjectTarget && worldObjectTarget->IsUnit()) ? worldObjectTarget->ToUnit() : nullptr; + } + 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 9200b5b0dd..8ebaa3b7ee 100644 --- a/src/server/game/Entities/GameObject/GameObject.h +++ b/src/server/game/Entities/GameObject/GameObject.h @@ -35,6 +35,7 @@ class Transport; class TransportBase; class Unit; struct TransportAnimation; +enum SpellTargetCheckTypes : uint8; enum TriggerCastFlags : uint32; // Base class for GameObject type specific implementations @@ -75,6 +76,11 @@ private: union GameObjectValue { + //6 GAMEOBJECT_TYPE_TRAP + struct + { + SpellTargetCheckTypes TargetSearcherCheckType; + } Trap; //25 GAMEOBJECT_TYPE_FISHINGHOLE struct {