Core/GameObjects: Fixed traps not being able to trigger for friendly targets

Closes #27210
Closes #28945

(cherry picked from commit 3993c45a040c01a6708850adfb014489b0e0ed8d)
This commit is contained in:
Shauren
2026-05-25 19:36:12 +02:00
parent 723554d663
commit ae41cce53f
2 changed files with 50 additions and 4 deletions
@@ -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<GameObjectType::ControlZone>(*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<Trinity::NearestAttackableNoTotemUnitInObjectRangeCheck> 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<Trinity::NearestAttackableNoTotemUnitInObjectRangeCheck> searcher(this, target, checker);
Cell::VisitAllObjects(this, searcher, radius);
}
}
else
{
@@ -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
{