diff --git a/src/server/game/AI/CoreAI/UnitAI.cpp b/src/server/game/AI/CoreAI/UnitAI.cpp index 8c9b4b9bd..5ec499af0 100644 --- a/src/server/game/AI/CoreAI/UnitAI.cpp +++ b/src/server/game/AI/CoreAI/UnitAI.cpp @@ -191,8 +191,23 @@ SpellCastResult UnitAI::DoCast(uint32 spellId) { if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId)) { - bool playerOnly = spellInfo->HasAttribute(SPELL_ATTR3_ONLY_ON_PLAYER); - target = SelectTarget(SelectTargetMethod::Random, 0, spellInfo->GetMaxRange(false), playerOnly); + DefaultTargetSelector targetSelector(me, spellInfo->GetMaxRange(false), false, true, 0); + target = SelectTarget(SelectTargetMethod::Random, 0, [&](Unit* target) { + if (target->IsPlayer()) + { + if (spellInfo->HasAttribute(SPELL_ATTR5_NOT_ON_PLAYER)) + return false; + } + else + { + if (spellInfo->HasAttribute(SPELL_ATTR3_ONLY_ON_PLAYER)) + return false; + + if (spellInfo->HasAttribute(SPELL_ATTR5_NOT_ON_PLAYER_CONTROLLED_NPC) && target->IsControlledByPlayer()) + return false; + } + return targetSelector(target); + }); } break; } @@ -206,12 +221,27 @@ SpellCastResult UnitAI::DoCast(uint32 spellId) { if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId)) { - bool playerOnly = spellInfo->HasAttribute(SPELL_ATTR3_ONLY_ON_PLAYER); float range = spellInfo->GetMaxRange(false); - DefaultTargetSelector targetSelector(me, range, playerOnly, true, -(int32)spellId); - if (!(spellInfo->AuraInterruptFlags & AURA_INTERRUPT_FLAG_NOT_VICTIM) - && targetSelector(me->GetVictim())) + DefaultTargetSelector defaultTargetSelector(me, range, false, true, -(int32)spellId); + auto targetSelector = [&](Unit* target) { + if (target->IsPlayer()) + { + if (spellInfo->HasAttribute(SPELL_ATTR5_NOT_ON_PLAYER)) + return false; + } + else + { + if (spellInfo->HasAttribute(SPELL_ATTR3_ONLY_ON_PLAYER)) + return false; + + if (spellInfo->HasAttribute(SPELL_ATTR5_NOT_ON_PLAYER_CONTROLLED_NPC) && target->IsControlledByPlayer()) + return false; + } + return defaultTargetSelector(target); + }; + + if (!(spellInfo->AuraInterruptFlags & AURA_INTERRUPT_FLAG_NOT_VICTIM) && targetSelector(me->GetVictim())) target = me->GetVictim(); else target = SelectTarget(SelectTargetMethod::Random, 0, targetSelector); diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 25505c3c4..eadb46eb3 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -2147,6 +2147,8 @@ uint32 Spell::GetSearcherTypeMask(SpellTargetObjectTypes objType, ConditionList* 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 e98c2f0a1..64a25a2b4 100644 --- a/src/server/game/Spells/SpellInfo.cpp +++ b/src/server/game/Spells/SpellInfo.cpp @@ -1863,8 +1863,19 @@ SpellCastResult SpellInfo::CheckTarget(Unit const* caster, WorldObject const* ta else return SPELL_CAST_OK; // corpseOwner and unit specific target checks - if (AttributesEx3 & SPELL_ATTR3_ONLY_ON_PLAYER && !unitTarget->ToPlayer()) - return SPELL_FAILED_TARGET_NOT_PLAYER; + if (unitTarget->IsPlayer()) + { + if (HasAttribute(SPELL_ATTR5_NOT_ON_PLAYER)) + return SPELL_FAILED_TARGET_IS_PLAYER; + } + else + { + 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; + } if (!IsAllowingDeadTarget() && !unitTarget->IsAlive()) return SPELL_FAILED_TARGETS_DEAD; diff --git a/src/server/shared/SharedDefines.h b/src/server/shared/SharedDefines.h index 8029bb6aa..ce3330770 100644 --- a/src/server/shared/SharedDefines.h +++ b/src/server/shared/SharedDefines.h @@ -571,7 +571,7 @@ enum SpellAttr5 : uint32 SPELL_ATTR5_TRIGGERS_CHANNELING = 0x00000010, // TITLE Unknown attribute 4@Attr5 SPELL_ATTR5_LIMIT_N = 0x00000020, // TITLE Single-target aura DESCRIPTION Remove previous application to another unit if applied SPELL_ATTR5_IGNORE_AREA_EFFECT_PVP_CHECK = 0x00000040, // TITLE Unknown attribute 6@Attr5 - SPELL_ATTR5_NOT_ON_PLAYER = 0x00000080, // TITLE Unknown attribute 7@Attr5 + SPELL_ATTR5_NOT_ON_PLAYER = 0x00000080, // TITLE Cannot target players SPELL_ATTR5_NOT_ON_PLAYER_CONTROLLED_NPC = 0x00000100, // TITLE Cannot target player controlled units but can target players SPELL_ATTR5_EXTRA_INITIAL_PERIOD = 0x00000200, // TITLE Immediately do periodic tick on apply SPELL_ATTR5_DO_NOT_DISPLAY_DURATION = 0x00000400, // TITLE Do not send aura duration to client