diff options
author | ariel- <ariel-@users.noreply.github.com> | 2018-01-23 01:40:58 -0300 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2021-08-28 15:59:11 +0200 |
commit | 52ae3c89d1d4dbcff309d940fd41c7212edc77b7 (patch) | |
tree | dc7940d0ea54ed3cad40edbf1df48a622860593c | |
parent | 1e1415a49128d034c8d48aa8cbb5d157200371b0 (diff) |
Core/Spells: rework part 2: Split up target selection logic
Target check only determines what kind of entities we can target, spell positivity determines if that entity is valid for attack/assist
Closes #8844
(cherry picked from commit 9b38a6352c0fe2499de54fd769aa1c721a410bda)
-rw-r--r-- | src/server/game/Entities/AreaTrigger/AreaTrigger.cpp | 4 | ||||
-rw-r--r-- | src/server/game/Entities/Unit/Unit.cpp | 190 | ||||
-rw-r--r-- | src/server/game/Entities/Unit/Unit.h | 8 | ||||
-rw-r--r-- | src/server/game/Entities/Unit/UnitDefines.h | 4 | ||||
-rw-r--r-- | src/server/game/Grids/Notifiers/GridNotifiers.h | 4 | ||||
-rw-r--r-- | src/server/game/Spells/Spell.cpp | 33 | ||||
-rw-r--r-- | src/server/game/Spells/SpellInfo.cpp | 4 |
7 files changed, 140 insertions, 107 deletions
diff --git a/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp b/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp index e389d58d543..773226e43fe 100644 --- a/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp +++ b/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp @@ -605,11 +605,11 @@ bool UnitFitToActionRequirement(Unit* unit, Unit* caster, AreaTriggerAction cons { case AREATRIGGER_ACTION_USER_FRIEND: { - return caster->_IsValidAssistTarget(unit, sSpellMgr->GetSpellInfo(action.Param, caster->GetMap()->GetDifficultyID())); + return caster->IsValidAssistTarget(unit, sSpellMgr->GetSpellInfo(action.Param, caster->GetMap()->GetDifficultyID())); } case AREATRIGGER_ACTION_USER_ENEMY: { - return caster->_IsValidAttackTarget(unit, sSpellMgr->GetSpellInfo(action.Param, caster->GetMap()->GetDifficultyID())); + return caster->IsValidAttackTarget(unit, sSpellMgr->GetSpellInfo(action.Param, caster->GetMap()->GetDifficultyID())); } case AREATRIGGER_ACTION_USER_RAID: { diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 94cbeaf9bc0..fadd871a970 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -6540,7 +6540,7 @@ Unit* Unit::GetMagicHitRedirectTarget(Unit* victim, SpellInfo const* spellInfo) { if (Unit* magnet = (*itr)->GetBase()->GetCaster()) if (spellInfo->CheckExplicitTarget(this, magnet) == SPELL_CAST_OK - && _IsValidAttackTarget(magnet, spellInfo)) + && IsValidAttackTarget(magnet, spellInfo)) { /// @todo handle this charge drop by proc in cast phase on explicit target if (spellInfo->HasHitDelay()) @@ -6571,7 +6571,7 @@ Unit* Unit::GetMeleeHitRedirectTarget(Unit* victim, SpellInfo const* spellInfo / for (AuraEffectList::const_iterator i = interceptAuras.begin(); i != interceptAuras.end(); ++i) { if (Unit* magnet = (*i)->GetBase()->GetCaster()) - if (_IsValidAttackTarget(magnet, spellInfo) && magnet->IsWithinLOSInMap(this) + if (IsValidAttackTarget(magnet, spellInfo) && magnet->IsWithinLOSInMap(this) && (!spellInfo || (spellInfo->CheckExplicitTarget(this, magnet) == SPELL_CAST_OK && spellInfo->CheckTarget(this, magnet, false) == SPELL_CAST_OK))) { @@ -8270,13 +8270,8 @@ bool Unit::isTargetableForAttack(bool checkFakeDeath) const return !HasUnitState(UNIT_STATE_UNATTACKABLE) && (!checkFakeDeath || !HasUnitState(UNIT_STATE_DIED)); } -bool Unit::IsValidAttackTarget(Unit const* target) const -{ - return _IsValidAttackTarget(target, nullptr); -} - // function based on function Unit::CanAttack from 13850 client -bool Unit::_IsValidAttackTarget(Unit const* target, SpellInfo const* bySpell, WorldObject const* obj) const +bool Unit::IsValidAttackTarget(Unit const* target, SpellInfo const* bySpell /*= nullptr*/, WorldObject const* obj /*= nullptr*/, bool spellCheck /*= true*/) const { ASSERT(target); @@ -8284,9 +8279,56 @@ bool Unit::_IsValidAttackTarget(Unit const* target, SpellInfo const* bySpell, Wo if (this == target) return false; - // can't attack unattackable units or GMs - if (target->HasUnitState(UNIT_STATE_UNATTACKABLE) - || (target->GetTypeId() == TYPEID_PLAYER && target->ToPlayer()->IsGameMaster())) + // can't attack GMs + if (target->GetTypeId() == TYPEID_PLAYER && target->ToPlayer()->IsGameMaster()) + return false; + + // CvC case - can attack each other only when one of them is hostile + if (!HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE) && !target->HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE)) + return IsHostileTo(target) || target->IsHostileTo(this); + + // PvP, PvC, CvP case + // can't attack friendly targets + if (IsFriendlyTo(target) || target->IsFriendlyTo(this)) + return false; + + Player const* playerAffectingAttacker = HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE) ? GetAffectingPlayer() : nullptr; + Player const* playerAffectingTarget = target->HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE) ? target->GetAffectingPlayer() : nullptr; + + // Not all neutral creatures can be attacked (even some unfriendly faction does not react aggresive to you, like Sporaggar) + if ((playerAffectingAttacker && !playerAffectingTarget) || (!playerAffectingAttacker && playerAffectingTarget)) + { + Player const* player = playerAffectingAttacker ? playerAffectingAttacker : playerAffectingTarget; + Unit const* creature = playerAffectingAttacker ? target : this; + + if (creature->IsContestedGuard() && player->HasPlayerFlag(PLAYER_FLAGS_CONTESTED_PVP)) + return true; + + if (FactionTemplateEntry const* factionTemplate = creature->GetFactionTemplateEntry()) + { + if (!(player->GetReputationMgr().GetForcedRankIfAny(factionTemplate))) + if (FactionEntry const* factionEntry = sFactionStore.LookupEntry(factionTemplate->Faction)) + if (FactionState const* repState = player->GetReputationMgr().GetState(factionEntry)) + if (!repState->Flags.HasFlag(ReputationFlags::AtWar)) + return false; + + } + } + + Creature const* creatureAttacker = ToCreature(); + if (creatureAttacker && (creatureAttacker->GetCreatureTemplate()->type_flags & CREATURE_TYPE_FLAG_TREAT_AS_RAID_UNIT)) + return false; + + if (spellCheck && !IsValidSpellAttackTarget(target, bySpell, obj)) + return false; + + return true; +} + +bool Unit::IsValidSpellAttackTarget(Unit const* target, SpellInfo const* bySpell, WorldObject const* obj /*= nullptr*/) const +{ + // can't attack unattackable units + if (target->HasUnitState(UNIT_STATE_UNATTACKABLE)) return false; // visibility checks @@ -8312,7 +8354,7 @@ bool Unit::_IsValidAttackTarget(Unit const* target, SpellInfo const* bySpell, Wo // can't attack dead if ((!bySpell || !bySpell->IsAllowingDeadTarget()) && !target->IsAlive()) - return false; + return false; // can't attack untargetable if ((!bySpell || !bySpell->HasAttribute(SPELL_ATTR6_CAN_TARGET_UNTARGETABLE)) @@ -8326,56 +8368,28 @@ bool Unit::_IsValidAttackTarget(Unit const* target, SpellInfo const* bySpell, Wo } // check flags - if (target->HasUnitFlag(UnitFlags(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_TAXI_FLIGHT | UNIT_FLAG_NOT_ATTACKABLE_1 | UNIT_FLAG_UNK_16)) - || (!HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE) && target->IsImmuneToNPC()) - || (!target->HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE) && IsImmuneToNPC())) + if (target->HasUnitFlag(UnitFlags(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_TAXI_FLIGHT | UNIT_FLAG_NOT_ATTACKABLE_1 | UNIT_FLAG_UNK_16))) return false; - if ((!bySpell || !bySpell->HasAttribute(SPELL_ATTR8_ATTACK_IGNORE_IMMUNE_TO_PC_FLAG)) - && (HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE) && target->IsImmuneToPC()) - // check if this is a world trigger cast - GOs are using world triggers to cast their spells, so we need to ignore their immunity flag here, this is a temp workaround, needs removal when go cast is implemented properly - && GetEntry() != WORLD_TRIGGER) + if (!HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE) && target->IsImmuneToNPC()) return false; - // CvC case - can attack each other only when one of them is hostile - if (!HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE) && !target->HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE)) - return GetReactionTo(target) <= REP_HOSTILE || target->GetReactionTo(this) <= REP_HOSTILE; - - // PvP, PvC, CvP case - // can't attack friendly targets - if (GetReactionTo(target) > REP_NEUTRAL - || target->GetReactionTo(this) > REP_NEUTRAL) + if (!target->HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE) && IsImmuneToNPC()) return false; - Player const* playerAffectingAttacker = HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE) ? GetAffectingPlayer() : nullptr; - Player const* playerAffectingTarget = target->HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE) ? target->GetAffectingPlayer() : nullptr; - - // Not all neutral creatures can be attacked (even some unfriendly faction does not react aggresive to you, like Sporaggar) - if ((playerAffectingAttacker && !playerAffectingTarget) || - (!playerAffectingAttacker && playerAffectingTarget)) - { - Player const* player = playerAffectingAttacker ? playerAffectingAttacker : playerAffectingTarget; - Unit const* creature = playerAffectingAttacker ? target : this; - - if (creature->IsContestedGuard() && player->HasPlayerFlag(PLAYER_FLAGS_CONTESTED_PVP)) - return true; - - if (FactionTemplateEntry const* factionTemplate = creature->GetFactionTemplateEntry()) - { - if (!(player->GetReputationMgr().GetForcedRankIfAny(factionTemplate))) - if (FactionEntry const* factionEntry = sFactionStore.LookupEntry(factionTemplate->Faction)) - if (FactionState const* repState = player->GetReputationMgr().GetState(factionEntry)) - if (!repState->Flags.HasFlag(ReputationFlags::AtWar)) - return false; + if ((!bySpell || bySpell->HasAttribute(SPELL_ATTR8_ATTACK_IGNORE_IMMUNE_TO_PC_FLAG)) + && HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE) && target->IsImmuneToPC()) + return false; - } - } + // check if this is a world trigger cast - GOs are using world triggers to cast their spells, so we need to ignore their immunity flag here, this is a temp workaround, needs removal when go cast is implemented properly + if (target->HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE) && IsImmuneToPC()) + if (GetEntry() != WORLD_TRIGGER && (!obj || !obj->isType(TYPEMASK_GAMEOBJECT | TYPEMASK_DYNAMICOBJECT))) + return false; - Creature const* creatureAttacker = ToCreature(); - if (creatureAttacker && creatureAttacker->GetCreatureTemplate()->type_flags & CREATURE_TYPE_FLAG_TREAT_AS_RAID_UNIT) - return false; // check duel - before sanctuary checks + Player const* playerAffectingAttacker = HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE) ? GetAffectingPlayer() : nullptr; + Player const* playerAffectingTarget = target->HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE) ? target->GetAffectingPlayer() : nullptr; if (playerAffectingAttacker && playerAffectingTarget) if (playerAffectingAttacker->duel && playerAffectingAttacker->duel->opponent == playerAffectingTarget && playerAffectingAttacker->duel->startTime != 0) return true; @@ -8397,16 +8411,12 @@ bool Unit::_IsValidAttackTarget(Unit const* target, SpellInfo const* bySpell, Wo return HasPvpFlag(UNIT_BYTE2_FLAG_UNK1) || target->HasPvpFlag(UNIT_BYTE2_FLAG_UNK1); } - return true; -} -bool Unit::IsValidAssistTarget(Unit const* target) const -{ - return _IsValidAssistTarget(target, nullptr); + return true; } // function based on function Unit::CanAssist from 13850 client -bool Unit::_IsValidAssistTarget(Unit const* target, SpellInfo const* bySpell) const +bool Unit::IsValidAssistTarget(Unit const* target, SpellInfo const* bySpell /*= nullptr*/, bool spellCheck /*= true*/) const { ASSERT(target); @@ -8414,27 +8424,46 @@ bool Unit::_IsValidAssistTarget(Unit const* target, SpellInfo const* bySpell) co if (this == target) return true; - // can't assist unattackable units or GMs - if (target->HasUnitState(UNIT_STATE_UNATTACKABLE) - || (target->GetTypeId() == TYPEID_PLAYER && target->ToPlayer()->IsGameMaster())) + // can't assist GMs + if (target->GetTypeId() == TYPEID_PLAYER && target->ToPlayer()->IsGameMaster()) + return false; + + // can't assist non-friendly targets + if (GetReactionTo(target) < REP_NEUTRAL && target->GetReactionTo(this) < REP_NEUTRAL && (!ToCreature() || !(ToCreature()->GetCreatureTemplate()->type_flags & CREATURE_TYPE_FLAG_TREAT_AS_RAID_UNIT))) + return false; + + if (spellCheck && !IsValidSpellAssistTarget(target, bySpell)) + return false; + + return true; +} + +bool Unit::IsValidSpellAssistTarget(Unit const* target, SpellInfo const* bySpell) const +{ + // can't assist unattackable units + if (target->HasUnitState(UNIT_STATE_UNATTACKABLE)) return false; // can't assist own vehicle or passenger if (m_vehicle) - if (IsOnVehicle(target) || m_vehicle->GetBase()->IsOnVehicle(target)) + { + if (IsOnVehicle(target)) return false; + if (m_vehicle->GetBase()->IsOnVehicle(target)) + return false; + } + // can't assist invisible if ((!bySpell || !bySpell->HasAttribute(SPELL_ATTR6_CAN_TARGET_INVISIBLE)) && !CanSeeOrDetect(target, bySpell && bySpell->IsAffectingArea())) return false; // can't assist dead if ((!bySpell || !bySpell->IsAllowingDeadTarget()) && !target->IsAlive()) - return false; + return false; // can't assist untargetable - if ((!bySpell || !bySpell->HasAttribute(SPELL_ATTR6_CAN_TARGET_UNTARGETABLE)) - && target->HasUnitFlag(UNIT_FLAG_NOT_SELECTABLE)) + if ((!bySpell || !bySpell->HasAttribute(SPELL_ATTR6_CAN_TARGET_UNTARGETABLE)) && target->HasUnitFlag(UNIT_FLAG_NOT_SELECTABLE)) return false; if (!bySpell || !bySpell->HasAttribute(SPELL_ATTR6_ASSIST_IGNORE_IMMUNE_FLAG)) @@ -8451,17 +8480,8 @@ bool Unit::_IsValidAssistTarget(Unit const* target, SpellInfo const* bySpell) co } } - // can't assist non-friendly targets - if (GetReactionTo(target) < REP_NEUTRAL - && target->GetReactionTo(this) < REP_NEUTRAL - && (!ToCreature() || !(ToCreature()->GetCreatureTemplate()->type_flags & CREATURE_TYPE_FLAG_TREAT_AS_RAID_UNIT))) - return false; - - // Controlled player case, we can assist creatures (reaction already checked above, our faction == charmer faction) - if (GetTypeId() == TYPEID_PLAYER && IsCharmed() && GetCharmerGUID().IsCreature()) - return true; // PvP case - else if (target->HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE)) + if (target->HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE)) { Player const* targetPlayerOwner = target->GetAffectingPlayer(); if (HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE)) @@ -8470,29 +8490,29 @@ bool Unit::_IsValidAssistTarget(Unit const* target, SpellInfo const* bySpell) co if (selfPlayerOwner && targetPlayerOwner) { // can't assist player which is dueling someone - if (selfPlayerOwner != targetPlayerOwner - && targetPlayerOwner->duel) + if (selfPlayerOwner != targetPlayerOwner && targetPlayerOwner->duel) return false; } // can't assist player in ffa_pvp zone from outside - if (target->HasPvpFlag(UNIT_BYTE2_FLAG_FFA_PVP) - && !HasPvpFlag(UNIT_BYTE2_FLAG_FFA_PVP)) + if (target->IsFFAPvP() && !IsFFAPvP()) return false; + // can't assist player out of sanctuary from sanctuary if has pvp enabled - if (target->HasPvpFlag(UNIT_BYTE2_FLAG_PVP)) + if (target->IsPvP()) if (IsInSanctuary() && !target->IsInSanctuary()) return false; } } // PvC case - player can assist creature only if has specific type flags // !target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE) && - else if (HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE) - && (!bySpell || !bySpell->HasAttribute(SPELL_ATTR6_ASSIST_IGNORE_IMMUNE_FLAG)) - && !target->HasPvpFlag(UNIT_BYTE2_FLAG_PVP)) + else if (HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE)) { - if (Creature const* creatureTarget = target->ToCreature()) - return creatureTarget->GetCreatureTemplate()->type_flags & CREATURE_TYPE_FLAG_TREAT_AS_RAID_UNIT || creatureTarget->GetCreatureTemplate()->type_flags & CREATURE_TYPE_FLAG_CAN_ASSIST; + if (!bySpell || !bySpell->HasAttribute(SPELL_ATTR6_ASSIST_IGNORE_IMMUNE_FLAG)) + if (!target->IsPvP()) + if (Creature const* creatureTarget = target->ToCreature()) + return creatureTarget->GetCreatureTemplate()->type_flags & CREATURE_TYPE_FLAG_TREAT_AS_RAID_UNIT || creatureTarget->GetCreatureTemplate()->type_flags & CREATURE_TYPE_FLAG_CAN_ASSIST; } + return true; } diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index da63f0558c7..a2bb7f1a301 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -1161,11 +1161,11 @@ class TC_GAME_API Unit : public WorldObject bool isTargetableForAttack(bool checkFakeDeath = true) const; - bool IsValidAttackTarget(Unit const* target) const; - bool _IsValidAttackTarget(Unit const* target, SpellInfo const* bySpell, WorldObject const* obj = nullptr) const; + bool IsValidAttackTarget(Unit const* target, SpellInfo const* bySpell = nullptr, WorldObject const* obj = nullptr, bool spellCheck = true) const; + bool IsValidSpellAttackTarget(Unit const* target, SpellInfo const* bySpell, WorldObject const* obj = nullptr) const; - bool IsValidAssistTarget(Unit const* target) const; - bool _IsValidAssistTarget(Unit const* target, SpellInfo const* bySpell) const; + bool IsValidAssistTarget(Unit const* target, SpellInfo const* bySpell = nullptr, bool spellCheck = true) const; + bool IsValidSpellAssistTarget(Unit const* target, SpellInfo const* bySpell) const; virtual bool IsInWater() const; virtual bool IsUnderWater() const; diff --git a/src/server/game/Entities/Unit/UnitDefines.h b/src/server/game/Entities/Unit/UnitDefines.h index b0191780ae8..fac8eda8d46 100644 --- a/src/server/game/Entities/Unit/UnitDefines.h +++ b/src/server/game/Entities/Unit/UnitDefines.h @@ -124,8 +124,8 @@ enum UnitFlags : uint32 UNIT_FLAG_PREPARATION = 0x00000020, // don't take reagents for spells with SPELL_ATTR5_NO_REAGENT_WHILE_PREP UNIT_FLAG_UNK_6 = 0x00000040, UNIT_FLAG_NOT_ATTACKABLE_1 = 0x00000080, // ?? (UNIT_FLAG_PVP_ATTACKABLE | UNIT_FLAG_NOT_ATTACKABLE_1) is NON_PVP_ATTACKABLE - UNIT_FLAG_IMMUNE_TO_PC = 0x00000100, // disables combat/assistance with PlayerCharacters (PC) - see Unit::_IsValidAttackTarget, Unit::_IsValidAssistTarget - UNIT_FLAG_IMMUNE_TO_NPC = 0x00000200, // disables combat/assistance with NonPlayerCharacters (NPC) - see Unit::_IsValidAttackTarget, Unit::_IsValidAssistTarget + UNIT_FLAG_IMMUNE_TO_PC = 0x00000100, // disables combat/assistance with PlayerCharacters (PC) - see Unit::IsValidAttackTarget, Unit::IsValidAssistTarget + UNIT_FLAG_IMMUNE_TO_NPC = 0x00000200, // disables combat/assistance with NonPlayerCharacters (NPC) - see Unit::IsValidAttackTarget, Unit::IsValidAssistTarget UNIT_FLAG_LOOTING = 0x00000400, // loot animation UNIT_FLAG_PET_IN_COMBAT = 0x00000800, // on player pets: whether the pet is chasing a target to attack || on other units: whether any of the unit's minions is in combat UNIT_FLAG_PVP = 0x00001000, // changed in 3.0.3 diff --git a/src/server/game/Grids/Notifiers/GridNotifiers.h b/src/server/game/Grids/Notifiers/GridNotifiers.h index 0f584f9a999..31fb37fd15e 100644 --- a/src/server/game/Grids/Notifiers/GridNotifiers.h +++ b/src/server/game/Grids/Notifiers/GridNotifiers.h @@ -951,7 +951,7 @@ namespace Trinity if (!u->isTargetableForAttack(false)) return false; - if (!i_obj->IsWithinDistInMap(u, i_range) || !i_funit->_IsValidAttackTarget(u, nullptr, i_obj)) + if (!i_obj->IsWithinDistInMap(u, i_range) || !i_funit->IsValidAttackTarget(u)) return false; i_range = i_obj->GetDistance(*u); @@ -1106,7 +1106,7 @@ namespace Trinity if (_spellInfo && _spellInfo->HasAttribute(SPELL_ATTR3_ONLY_TARGET_PLAYERS) && u->GetTypeId() != TYPEID_PLAYER) return false; - if (!i_funit->_IsValidAttackTarget(u, _spellInfo, i_obj->GetTypeId() == TYPEID_DYNAMICOBJECT ? i_obj : nullptr)) + if (!i_funit->IsValidAttackTarget(u, _spellInfo)) return false; float searchRadius = i_range; diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index f803210e6d2..cfb0e4703e9 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -2718,15 +2718,12 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask) if (m_spellInfo->HasHitDelay() && unit->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE) && unit->GetCharmerOrOwnerGUID() != m_caster->GetGUID()) return SPELL_MISS_EVADE; - if (m_caster->_IsValidAttackTarget(unit, m_spellInfo)) + if (m_caster->IsValidAttackTarget(unit, m_spellInfo)) unit->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::HostileActionReceived); else if (m_caster->IsFriendlyTo(unit)) { // for delayed spells ignore negative spells (after duel end) for friendly targets - /// @todo this cause soul transfer bugged - // 63881 - Malady of the Mind jump spell (Yogg-Saron) - // 45034 - Curse of Boundless Agony jump spell (Kalecgos) - if (m_spellInfo->HasHitDelay() && unit->GetTypeId() == TYPEID_PLAYER && !IsPositive() && m_spellInfo->Id != 63881 && m_spellInfo->Id != 45034) + if (m_spellInfo->HasHitDelay() && unit->GetTypeId() == TYPEID_PLAYER && !IsPositive() && !m_caster->IsValidSpellAttackTarget(unit, m_spellInfo)) return SPELL_MISS_EVADE; // assisting case, healing and resurrection @@ -8090,32 +8087,34 @@ bool WorldObjectSpellTargetCheck::operator()(WorldObject* target) Unit* unitTarget = target->ToUnit(); if (Corpse* corpseTarget = target->ToCorpse()) { - // use ofter for party/assistance checks + // use owner for party/assistance checks if (Player* owner = ObjectAccessor::FindPlayer(corpseTarget->GetOwnerGUID())) unitTarget = owner; else return false; } + if (unitTarget) { + // do only faction checks here switch (_targetSelectionType) { case TARGET_CHECK_ENEMY: if (unitTarget->IsTotem()) return false; - if (!_caster->_IsValidAttackTarget(unitTarget, _spellInfo)) + if (!_caster->IsValidAttackTarget(unitTarget, _spellInfo, nullptr, false)) return false; break; case TARGET_CHECK_ALLY: if (unitTarget->IsTotem()) return false; - if (!_caster->_IsValidAssistTarget(unitTarget, _spellInfo)) + if (!_caster->IsValidAssistTarget(unitTarget, _spellInfo, false)) return false; break; case TARGET_CHECK_PARTY: if (unitTarget->IsTotem()) return false; - if (!_caster->_IsValidAssistTarget(unitTarget, _spellInfo)) + if (!_caster->IsValidAssistTarget(unitTarget, _spellInfo, false)) return false; if (!_referer->IsInPartyWith(unitTarget)) return false; @@ -8127,7 +8126,7 @@ bool WorldObjectSpellTargetCheck::operator()(WorldObject* target) case TARGET_CHECK_RAID: if (unitTarget->IsTotem()) return false; - if (!_caster->_IsValidAssistTarget(unitTarget, _spellInfo)) + if (!_caster->IsValidAssistTarget(unitTarget, _spellInfo, false)) return false; if (!_referer->IsInRaidWith(unitTarget)) return false; @@ -8162,7 +8161,21 @@ bool WorldObjectSpellTargetCheck::operator()(WorldObject* target) default: break; } + + // then check actual spell positivity to determine if the target is valid + // (negative spells may be targeted on allies) + if (_spellInfo->IsPositive()) + { + if (!_caster->IsValidSpellAssistTarget(unitTarget, _spellInfo)) + return false; + } + else + { + if (!_caster->IsValidSpellAttackTarget(unitTarget, _spellInfo)) + return false; + } } + if (!_condSrcInfo) return true; _condSrcInfo->mConditionTargets[0] = target; diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp index 5e319774fc4..e1aceb1de97 100644 --- a/src/server/game/Spells/SpellInfo.cpp +++ b/src/server/game/Spells/SpellInfo.cpp @@ -2265,12 +2265,12 @@ SpellCastResult SpellInfo::CheckExplicitTarget(Unit const* caster, WorldObject c if (neededTargets & (TARGET_FLAG_UNIT_ENEMY | TARGET_FLAG_UNIT_ALLY | TARGET_FLAG_UNIT_RAID | TARGET_FLAG_UNIT_PARTY | TARGET_FLAG_UNIT_MINIPET | TARGET_FLAG_UNIT_PASSENGER)) { if (neededTargets & TARGET_FLAG_UNIT_ENEMY) - if (caster->_IsValidAttackTarget(unitTarget, this)) + if (caster->IsValidAttackTarget(unitTarget, this)) return SPELL_CAST_OK; if (neededTargets & TARGET_FLAG_UNIT_ALLY || (neededTargets & TARGET_FLAG_UNIT_PARTY && caster->IsInPartyWith(unitTarget)) || (neededTargets & TARGET_FLAG_UNIT_RAID && caster->IsInRaidWith(unitTarget))) - if (caster->_IsValidAssistTarget(unitTarget, this)) + if (caster->IsValidAssistTarget(unitTarget, this)) return SPELL_CAST_OK; if (neededTargets & TARGET_FLAG_UNIT_MINIPET) if (unitTarget->GetGUID() == caster->GetCritterGUID()) |