diff options
-rw-r--r-- | src/server/game/AI/CoreAI/UnitAI.cpp | 37 | ||||
-rw-r--r-- | src/server/game/Grids/Notifiers/GridNotifiers.h | 15 | ||||
-rw-r--r-- | src/server/game/Miscellaneous/SharedDefines.h | 4 | ||||
-rw-r--r-- | src/server/game/Spells/Spell.cpp | 2 | ||||
-rw-r--r-- | src/server/game/Spells/SpellInfo.cpp | 12 |
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; |