aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/server/game/AI/CoreAI/UnitAI.cpp37
-rw-r--r--src/server/game/Grids/Notifiers/GridNotifiers.h15
-rw-r--r--src/server/game/Miscellaneous/SharedDefines.h4
-rw-r--r--src/server/game/Spells/Spell.cpp2
-rw-r--r--src/server/game/Spells/SpellInfo.cpp12
5 files changed, 60 insertions, 10 deletions
diff --git a/src/server/game/AI/CoreAI/UnitAI.cpp b/src/server/game/AI/CoreAI/UnitAI.cpp
index f9f44c15cfb..ee296611df1 100644
--- a/src/server/game/AI/CoreAI/UnitAI.cpp
+++ b/src/server/game/AI/CoreAI/UnitAI.cpp
@@ -129,8 +129,23 @@ SpellCastResult UnitAI::DoCast(uint32 spellId)
{
if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId, me->GetMap()->GetDifficultyID()))
{
- bool playerOnly = spellInfo->HasAttribute(SPELL_ATTR3_ONLY_ON_PLAYER);
- target = SelectTarget(SelectTargetMethod::Random, 0, spellInfo->GetMaxRange(false), playerOnly);
+ DefaultTargetSelector targetSelectorInner(me, spellInfo->GetMaxRange(false), false, true, 0);
+ auto targetSelector = [&](Unit const* candidate) -> bool
+ {
+ if (!candidate->IsPlayer())
+ {
+ if (spellInfo->HasAttribute(SPELL_ATTR3_ONLY_ON_PLAYER))
+ return false;
+
+ if (spellInfo->HasAttribute(SPELL_ATTR5_NOT_ON_PLAYER_CONTROLLED_NPC) && candidate->IsControlledByPlayer())
+ return false;
+ }
+ else if (spellInfo->HasAttribute(SPELL_ATTR5_NOT_ON_PLAYER))
+ return false;
+
+ return targetSelectorInner(candidate);
+ };
+ target = SelectTarget(SelectTargetMethod::Random, 0, targetSelector);
}
break;
}
@@ -144,10 +159,24 @@ SpellCastResult UnitAI::DoCast(uint32 spellId)
{
if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId, me->GetMap()->GetDifficultyID()))
{
- bool playerOnly = spellInfo->HasAttribute(SPELL_ATTR3_ONLY_ON_PLAYER);
float range = spellInfo->GetMaxRange(false);
- DefaultTargetSelector targetSelector(me, range, playerOnly, true, -(int32)spellId);
+ DefaultTargetSelector targetSelectorInner(me, range, false, true, -(int32)spellId);
+ auto targetSelector = [&](Unit const* candidate) -> bool
+ {
+ if (!candidate->IsPlayer())
+ {
+ if (spellInfo->HasAttribute(SPELL_ATTR3_ONLY_ON_PLAYER))
+ return false;
+
+ if (spellInfo->HasAttribute(SPELL_ATTR5_NOT_ON_PLAYER_CONTROLLED_NPC) && candidate->IsControlledByPlayer())
+ return false;
+ }
+ else if (spellInfo->HasAttribute(SPELL_ATTR5_NOT_ON_PLAYER))
+ return false;
+
+ return targetSelectorInner(candidate);
+ };
if (!spellInfo->HasAuraInterruptFlag(SpellAuraInterruptFlags::NOT_VICTIM) && targetSelector(me->GetVictim()))
target = me->GetVictim();
else
diff --git a/src/server/game/Grids/Notifiers/GridNotifiers.h b/src/server/game/Grids/Notifiers/GridNotifiers.h
index 90b1089c3e8..a293b8ad2c7 100644
--- a/src/server/game/Grids/Notifiers/GridNotifiers.h
+++ b/src/server/game/Grids/Notifiers/GridNotifiers.h
@@ -1159,8 +1159,19 @@ namespace Trinity
if (u->GetTypeId() == TYPEID_UNIT && u->IsTotem())
return false;
- if (_spellInfo && _spellInfo->HasAttribute(SPELL_ATTR3_ONLY_ON_PLAYER) && u->GetTypeId() != TYPEID_PLAYER)
- return false;
+ if (_spellInfo)
+ {
+ if (!u->IsPlayer())
+ {
+ if (_spellInfo->HasAttribute(SPELL_ATTR3_ONLY_ON_PLAYER))
+ return false;
+
+ if (_spellInfo->HasAttribute(SPELL_ATTR5_NOT_ON_PLAYER_CONTROLLED_NPC) && u->IsControlledByPlayer())
+ return false;
+ }
+ else if (_spellInfo->HasAttribute(SPELL_ATTR5_NOT_ON_PLAYER))
+ return false;
+ }
if (!i_funit->IsValidAttackTarget(u, _spellInfo))
return false;
diff --git a/src/server/game/Miscellaneous/SharedDefines.h b/src/server/game/Miscellaneous/SharedDefines.h
index 768a71dbc30..2b4e32cc726 100644
--- a/src/server/game/Miscellaneous/SharedDefines.h
+++ b/src/server/game/Miscellaneous/SharedDefines.h
@@ -596,8 +596,8 @@ enum SpellAttr5 : uint32
SPELL_ATTR5_TRIGGERS_CHANNELING = 0x00000010, // TITLE Triggers Channeling
SPELL_ATTR5_LIMIT_N = 0x00000020, // TITLE Limit N DESCRIPTION Remove previous application to another unit if applied
SPELL_ATTR5_IGNORE_AREA_EFFECT_PVP_CHECK = 0x00000040, // TITLE Ignore Area Effect PvP Check
- SPELL_ATTR5_NOT_ON_PLAYER = 0x00000080, /*NYI*/ // TITLE Not On Player
- SPELL_ATTR5_NOT_ON_PLAYER_CONTROLLED_NPC = 0x00000100, /*NYI*/ // TITLE Not On Player Controlled NPC
+ SPELL_ATTR5_NOT_ON_PLAYER = 0x00000080, // TITLE Not On Player
+ SPELL_ATTR5_NOT_ON_PLAYER_CONTROLLED_NPC = 0x00000100, // TITLE Not On Player Controlled NPC
SPELL_ATTR5_EXTRA_INITIAL_PERIOD = 0x00000200, // TITLE Extra Initial Period DESCRIPTION Immediately do periodic tick on apply
SPELL_ATTR5_DO_NOT_DISPLAY_DURATION = 0x00000400, // TITLE Do Not Display Duration
SPELL_ATTR5_IMPLIED_TARGETING = 0x00000800, // TITLE Implied Targeting (client only)
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp
index 630585884db..094bb17489f 100644
--- a/src/server/game/Spells/Spell.cpp
+++ b/src/server/game/Spells/Spell.cpp
@@ -2025,6 +2025,8 @@ uint32 Spell::GetSearcherTypeMask(SpellTargetObjectTypes objType, ConditionConta
retMask &= GRID_MAP_TYPE_MASK_CORPSE | GRID_MAP_TYPE_MASK_PLAYER;
if (m_spellInfo->HasAttribute(SPELL_ATTR3_ONLY_ON_GHOSTS))
retMask &= GRID_MAP_TYPE_MASK_PLAYER;
+ if (m_spellInfo->HasAttribute(SPELL_ATTR5_NOT_ON_PLAYER))
+ retMask &= ~GRID_MAP_TYPE_MASK_PLAYER;
if (condList)
retMask &= sConditionMgr->GetSearcherTypeMaskForConditionList(*condList);
diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp
index 5659c4625b3..8f5e8ccd5e3 100644
--- a/src/server/game/Spells/SpellInfo.cpp
+++ b/src/server/game/Spells/SpellInfo.cpp
@@ -2169,8 +2169,16 @@ SpellCastResult SpellInfo::CheckTarget(WorldObject const* caster, WorldObject co
else return SPELL_CAST_OK;
// corpseOwner and unit specific target checks
- if (HasAttribute(SPELL_ATTR3_ONLY_ON_PLAYER) && unitTarget->GetTypeId() != TYPEID_PLAYER)
- return SPELL_FAILED_TARGET_NOT_PLAYER;
+ if (!unitTarget->IsPlayer())
+ {
+ if (HasAttribute(SPELL_ATTR3_ONLY_ON_PLAYER))
+ return SPELL_FAILED_TARGET_NOT_PLAYER;
+
+ if (HasAttribute(SPELL_ATTR5_NOT_ON_PLAYER_CONTROLLED_NPC) && unitTarget->IsControlledByPlayer())
+ return SPELL_FAILED_TARGET_IS_PLAYER_CONTROLLED;
+ }
+ else if (HasAttribute(SPELL_ATTR5_NOT_ON_PLAYER))
+ return SPELL_FAILED_TARGET_IS_PLAYER;
if (!IsAllowingDeadTarget() && !unitTarget->IsAlive())
return SPELL_FAILED_TARGETS_DEAD;