diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/server/game/Entities/Object/Object.cpp | 201 | ||||
-rw-r--r-- | src/server/game/Entities/Object/Object.h | 7 | ||||
-rw-r--r-- | src/server/game/Spells/Spell.cpp | 38 | ||||
-rw-r--r-- | src/server/game/Spells/SpellEffects.cpp | 4 |
4 files changed, 107 insertions, 143 deletions
diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp index bb2fddd6ad0..fc5af757490 100644 --- a/src/server/game/Entities/Object/Object.cpp +++ b/src/server/game/Entities/Object/Object.cpp @@ -2661,12 +2661,20 @@ void WorldObject::CastSpell(Position const& dest, uint32 spellId, CastSpellExtra } // function based on function Unit::CanAttack from 13850 client -bool WorldObject::IsValidAttackTarget(WorldObject const* target, SpellInfo const* bySpell /*= nullptr*/, bool spellCheck /*= true*/) const +bool WorldObject::IsValidAttackTarget(WorldObject const* target, SpellInfo const* bySpell /*= nullptr*/) const { ASSERT(target); - // can't attack self - if (this == target) + // some positive spells can be casted at hostile target + bool isPositiveSpell = bySpell && bySpell->IsPositive(); + + // can't attack self (spells can, attribute check) + if (!bySpell && this == target) + return false; + + // can't attack unattackable units + Unit const* unitTarget = target->ToUnit(); + if (unitTarget && unitTarget->HasUnitState(UNIT_STATE_UNATTACKABLE)) return false; // can't attack GMs @@ -2674,10 +2682,56 @@ bool WorldObject::IsValidAttackTarget(WorldObject const* target, SpellInfo const return false; Unit const* unit = ToUnit(); - Unit const* targetUnit = target->ToUnit(); + // visibility checks (only units) + if (unit) + { + // can't attack invisible + if (!bySpell || !bySpell->HasAttribute(SPELL_ATTR6_CAN_TARGET_INVISIBLE)) + { + if (!unit->CanSeeOrDetect(target, bySpell && bySpell->IsAffectingArea())) + return false; + } + } + + // can't attack dead + if ((!bySpell || !bySpell->IsAllowingDeadTarget()) && unitTarget && !unitTarget->IsAlive()) + return false; + + // can't attack untargetable + if ((!bySpell || !bySpell->HasAttribute(SPELL_ATTR6_CAN_TARGET_UNTARGETABLE)) && unitTarget && unitTarget->HasUnitFlag(UNIT_FLAG_NOT_SELECTABLE)) + return false; + + if (Player const* playerAttacker = ToPlayer()) + { + if (playerAttacker->HasPlayerFlag(PLAYER_FLAGS_UBER)) + return false; + } + + // check flags + if (unitTarget && unitTarget->HasUnitFlag(UnitFlags(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_TAXI_FLIGHT | UNIT_FLAG_NOT_ATTACKABLE_1 | UNIT_FLAG_UNK_16))) + return false; + + // ignore immunity flags when assisting + if (isPositiveSpell && !bySpell->HasAttribute(SPELL_ATTR6_ASSIST_IGNORE_IMMUNE_FLAG)) + { + if (unit && !unit->HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE) && unitTarget && unitTarget->IsImmuneToNPC()) + return false; + + if (unitTarget && !unitTarget->HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE) && unit && unit->IsImmuneToNPC()) + return false; + + if (!bySpell->HasAttribute(SPELL_ATTR8_ATTACK_IGNORE_IMMUNE_TO_PC_FLAG)) + { + if (unit && unit->HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE) && unitTarget && unitTarget->IsImmuneToPC()) + return false; + + if (unitTarget && unitTarget->HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE) && unit && unit->IsImmuneToPC()) + return false; + } + } // CvC case - can attack each other only when one of them is hostile - if (unit && !unit->HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE) && targetUnit && !targetUnit->HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE)) + if (unit && !unit->HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE) && unitTarget && !unitTarget->HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE)) return IsHostileTo(target) || target->IsHostileTo(this); // PvP, PvC, CvP case @@ -2686,14 +2740,14 @@ bool WorldObject::IsValidAttackTarget(WorldObject const* target, SpellInfo const return false; Player const* playerAffectingAttacker = unit && unit->HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE) ? GetAffectingPlayer() : nullptr; - Player const* playerAffectingTarget = targetUnit && targetUnit->HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE) ? target->GetAffectingPlayer() : nullptr; + Player const* playerAffectingTarget = unitTarget && unitTarget->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; - if (Unit const* creature = playerAffectingAttacker ? targetUnit : unit) + if (Unit const* creature = playerAffectingAttacker ? unitTarget : unit) { if (creature->IsContestedGuard() && player->HasPlayerFlag(PLAYER_FLAGS_CONTESTED_PVP)) return true; @@ -2714,85 +2768,6 @@ bool WorldObject::IsValidAttackTarget(WorldObject const* target, SpellInfo const if (creatureAttacker && (creatureAttacker->GetCreatureTemplate()->type_flags & CREATURE_TYPE_FLAG_TREAT_AS_RAID_UNIT)) return false; - if (!bySpell) - spellCheck = false; - - if (spellCheck && !IsValidSpellAttackTarget(target, bySpell)) - return false; - - return true; -} - -bool WorldObject::IsValidSpellAttackTarget(WorldObject const* target, SpellInfo const* bySpell) const -{ - ASSERT(target); - ASSERT(bySpell); - - // can't attack unattackable units - Unit const* unitTarget = target->ToUnit(); - if (unitTarget && unitTarget->HasUnitState(UNIT_STATE_UNATTACKABLE)) - return false; - - Unit const* unit = ToUnit(); - // visibility checks (only units) - if (unit) - { - // can't attack invisible - if (!bySpell->HasAttribute(SPELL_ATTR6_CAN_TARGET_INVISIBLE)) - { - if (!unit->CanSeeOrDetect(target, bySpell->IsAffectingArea())) - return false; - - /* - else if (!obj) - { - // ignore stealth for aoe spells. Ignore stealth if target is player and unit in combat with same player - bool const ignoreStealthCheck = (bySpell && bySpell->IsAffectingArea()) || - (target->GetTypeId() == TYPEID_PLAYER && target->HasStealthAura() && IsInCombatWith(target)); - - if (!CanSeeOrDetect(target, ignoreStealthCheck)) - return false; - } - */ - } - } - - // can't attack dead - if (!bySpell->IsAllowingDeadTarget() && unitTarget && !unitTarget->IsAlive()) - return false; - - // can't attack untargetable - if (!bySpell->HasAttribute(SPELL_ATTR6_CAN_TARGET_UNTARGETABLE) && unitTarget && unitTarget->HasUnitFlag(UNIT_FLAG_NOT_SELECTABLE)) - return false; - - if (Player const* playerAttacker = ToPlayer()) - { - if (playerAttacker->HasPlayerFlag(PLAYER_FLAGS_UBER)) - return false; - } - - // check flags - if (unitTarget && unitTarget->HasUnitFlag(UnitFlags(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_TAXI_FLIGHT | UNIT_FLAG_NOT_ATTACKABLE_1 | UNIT_FLAG_UNK_16))) - return false; - - if (unit && !unit->HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE) && unitTarget && unitTarget->IsImmuneToNPC()) - return false; - - if (unitTarget && !unitTarget->HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE) && unit && unit->IsImmuneToNPC()) - return false; - - if (!bySpell->HasAttribute(SPELL_ATTR8_ATTACK_IGNORE_IMMUNE_TO_PC_FLAG)) - { - if (unit && unit->HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE) && unitTarget && unitTarget->IsImmuneToPC()) - return false; - - if (unitTarget && unitTarget->HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE) && unit && unit->IsImmuneToPC()) - return false; - } - - // check duel - before sanctuary checks - Player const* playerAffectingAttacker = unit && unit->HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE) ? GetAffectingPlayer() : nullptr; - Player const* playerAffectingTarget = unitTarget && unitTarget->HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE) ? target->GetAffectingPlayer() : nullptr; if (playerAffectingAttacker && playerAffectingTarget) if (playerAffectingAttacker->duel && playerAffectingAttacker->duel->opponent == playerAffectingTarget && playerAffectingAttacker->duel->startTime != 0) return true; @@ -2819,41 +2794,26 @@ bool WorldObject::IsValidSpellAttackTarget(WorldObject const* target, SpellInfo } // function based on function Unit::CanAssist from 13850 client -bool WorldObject::IsValidAssistTarget(WorldObject const* target, SpellInfo const* bySpell /*= nullptr*/, bool spellCheck /*= true*/) const +bool WorldObject::IsValidAssistTarget(WorldObject const* target, SpellInfo const* bySpell /*= nullptr*/) const { ASSERT(target); + // some negative spells can be casted at friendly target + bool isNegativeSpell = bySpell && !bySpell->IsPositive(); + // can assist to self if (this == target) return true; - // 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 (!bySpell) - spellCheck = false; - - if (spellCheck && !IsValidSpellAssistTarget(target, bySpell)) - return false; - - return true; -} - -bool WorldObject::IsValidSpellAssistTarget(WorldObject const* target, SpellInfo const* bySpell) const -{ - ASSERT(target); - ASSERT(bySpell); - // can't assist unattackable units Unit const* unitTarget = target->ToUnit(); if (unitTarget && unitTarget->HasUnitState(UNIT_STATE_UNATTACKABLE)) return false; + // can't assist GMs + if (target->GetTypeId() == TYPEID_PLAYER && target->ToPlayer()->IsGameMaster()) + return false; + // can't assist own vehicle or passenger Unit const* unit = ToUnit(); if (unit && unitTarget && unit->GetVehicle()) @@ -2866,23 +2826,28 @@ bool WorldObject::IsValidSpellAssistTarget(WorldObject const* target, SpellInfo } // can't assist invisible - if (!bySpell->HasAttribute(SPELL_ATTR6_CAN_TARGET_INVISIBLE) && !CanSeeOrDetect(target, bySpell->IsAffectingArea())) + if ((!bySpell || !bySpell->HasAttribute(SPELL_ATTR6_CAN_TARGET_INVISIBLE)) && !CanSeeOrDetect(target, bySpell && bySpell->IsAffectingArea())) return false; // can't assist dead - if (!bySpell->IsAllowingDeadTarget() && unitTarget && !unitTarget->IsAlive()) + if ((!bySpell || !bySpell->IsAllowingDeadTarget()) && unitTarget && !unitTarget->IsAlive()) return false; // can't assist untargetable - if (!bySpell->HasAttribute(SPELL_ATTR6_CAN_TARGET_UNTARGETABLE) && unitTarget && unitTarget->HasUnitFlag(UNIT_FLAG_NOT_SELECTABLE)) + if ((!bySpell || !bySpell->HasAttribute(SPELL_ATTR6_CAN_TARGET_UNTARGETABLE)) && unitTarget && unitTarget->HasUnitFlag(UNIT_FLAG_NOT_SELECTABLE)) return false; - if (!bySpell->HasAttribute(SPELL_ATTR6_ASSIST_IGNORE_IMMUNE_FLAG)) + // check flags for negative spells + if (isNegativeSpell && unitTarget && unitTarget->HasUnitFlag(UnitFlags(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_TAXI_FLIGHT | UNIT_FLAG_NOT_ATTACKABLE_1 | UNIT_FLAG_UNK_16))) + return false; + + if (isNegativeSpell || !bySpell || !bySpell->HasAttribute(SPELL_ATTR6_ASSIST_IGNORE_IMMUNE_FLAG)) { if (unit && unit->HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE)) { - if (unitTarget && unitTarget->IsImmuneToPC()) - return false; + if (!bySpell || !bySpell->HasAttribute(SPELL_ATTR8_ATTACK_IGNORE_IMMUNE_TO_PC_FLAG)) + if (unitTarget && unitTarget->IsImmuneToPC()) + return false; } else { @@ -2891,6 +2856,10 @@ bool WorldObject::IsValidSpellAssistTarget(WorldObject const* target, SpellInfo } } + // 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; + // PvP case if (unitTarget && unitTarget->HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE)) { @@ -2918,7 +2887,7 @@ bool WorldObject::IsValidSpellAssistTarget(WorldObject const* target, SpellInfo // !target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE) && else if (unit && unit->HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE)) { - if (!bySpell->HasAttribute(SPELL_ATTR6_ASSIST_IGNORE_IMMUNE_FLAG)) + if (!bySpell || !bySpell->HasAttribute(SPELL_ATTR6_ASSIST_IGNORE_IMMUNE_FLAG)) if (unitTarget && !unitTarget->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)); diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h index 974c74a02bd..71cfdf548a6 100644 --- a/src/server/game/Entities/Object/Object.h +++ b/src/server/game/Entities/Object/Object.h @@ -599,11 +599,8 @@ class TC_GAME_API WorldObject : public Object, public WorldLocation void CastSpell(WorldObject* target, uint32 spellId, CastSpellExtraArgs const& args = { }); void CastSpell(Position const& dest, uint32 spellId, CastSpellExtraArgs const& args = { }); - bool IsValidAttackTarget(WorldObject const* target, SpellInfo const* bySpell = nullptr, bool spellCheck = true) const; - bool IsValidSpellAttackTarget(WorldObject const* target, SpellInfo const* bySpell) const; - - bool IsValidAssistTarget(WorldObject const* target, SpellInfo const* bySpell = nullptr, bool spellCheck = true) const; - bool IsValidSpellAssistTarget(WorldObject const* target, SpellInfo const* bySpell) const; + bool IsValidAttackTarget(WorldObject const* target, SpellInfo const* bySpell = nullptr) const; + bool IsValidAssistTarget(WorldObject const* target, SpellInfo const* bySpell = nullptr) const; Unit* GetMagicHitRedirectTarget(Unit* victim, SpellInfo const* spellInfo); diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 45b53f6f93b..ceca13fdfdf 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -2382,6 +2382,7 @@ void Spell::TargetInfo::PreprocessTarget(Spell* spell) if (missInfo != SPELL_MISS_MISS) spell->m_caster->ToUnit()->SendSpellMiss(unit, spell->m_spellInfo->Id, missInfo); spell->m_damage = 0; + spell->m_healing = 0; _spellHitTarget = nullptr; } } @@ -2645,6 +2646,20 @@ void Spell::TargetInfo::DoDamageAndTriggers(Spell* spell) else if (spell->m_caster->GetTypeId() == TYPEID_GAMEOBJECT && spell->m_caster->ToGameObject()->AI()) spell->m_caster->ToGameObject()->AI()->SpellHitTarget(_spellHitTarget, spell->m_spellInfo); + if (spell->_spellAura) + { + if (AuraApplication* aurApp = spell->_spellAura->GetApplicationOfTarget(_spellHitTarget->GetGUID())) + { + // only apply unapplied effects (for reapply case) + uint32 effMask = EffectMask & aurApp->GetEffectsToApply(); + for (uint8 i = 0; i < spell->m_spellInfo->GetEffects().size(); ++i) + if ((effMask & (1 << i)) && aurApp->HasEffect(i)) + effMask &= ~(1 << i); + + _spellHitTarget->_ApplyAura(aurApp, effMask); + } + } + // Needs to be called after dealing damage/healing to not remove breaking on damage auras spell->DoTriggersOnSpellHit(_spellHitTarget, EffectMask); @@ -2733,7 +2748,7 @@ SpellMissInfo Spell::PreprocessSpellHit(Unit* unit, TargetInfo& hitInfo) else if (m_caster->IsFriendlyTo(unit)) { // for delayed spells ignore negative spells (after duel end) for friendly targets - if (m_spellInfo->HasHitDelay() && unit->GetTypeId() == TYPEID_PLAYER && !IsPositive() && !m_caster->IsValidSpellAttackTarget(unit, m_spellInfo)) + if (m_spellInfo->HasHitDelay() && unit->GetTypeId() == TYPEID_PLAYER && !IsPositive() && !m_caster->IsValidAssistTarget(unit, m_spellInfo)) return SPELL_MISS_EVADE; // assisting case, healing and resurrection @@ -8170,13 +8185,13 @@ bool WorldObjectSpellTargetCheck::operator()(WorldObject* target) const case TARGET_CHECK_ENEMY: if (unitTarget->IsTotem()) return false; - if (!_caster->IsValidAttackTarget(unitTarget, _spellInfo, false)) + if (!_caster->IsValidAttackTarget(unitTarget, _spellInfo)) return false; break; case TARGET_CHECK_ALLY: if (unitTarget->IsTotem()) return false; - if (!_caster->IsValidAssistTarget(unitTarget, _spellInfo, false)) + if (!_caster->IsValidAssistTarget(unitTarget, _spellInfo)) return false; break; case TARGET_CHECK_PARTY: @@ -8184,7 +8199,7 @@ bool WorldObjectSpellTargetCheck::operator()(WorldObject* target) const return false; if (unitTarget->IsTotem()) return false; - if (!_caster->IsValidAssistTarget(unitTarget, _spellInfo, false)) + if (!_caster->IsValidAssistTarget(unitTarget, _spellInfo)) return false; if (!refUnit->IsInPartyWith(unitTarget)) return false; @@ -8200,7 +8215,7 @@ bool WorldObjectSpellTargetCheck::operator()(WorldObject* target) const return false; if (unitTarget->IsTotem()) return false; - if (!_caster->IsValidAssistTarget(unitTarget, _spellInfo, false)) + if (!_caster->IsValidAssistTarget(unitTarget, _spellInfo)) return false; if (!refUnit->IsInRaidWith(unitTarget)) return false; @@ -8235,19 +8250,6 @@ bool WorldObjectSpellTargetCheck::operator()(WorldObject* target) const 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) diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index de9e35cbd1c..a3507d6aeaa 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -1022,10 +1022,6 @@ void Spell::EffectApplyAura() aurApp = unitTarget->_CreateAuraApplication(_spellAura, 1 << effectInfo->EffectIndex); else aurApp->UpdateApplyEffectMask(aurApp->GetEffectsToApply() | 1 << effectInfo->EffectIndex); - - // apply effect on target (skip for reapply) - if (!aurApp->HasEffect(effectInfo->EffectIndex)) - unitTarget->_ApplyAuraEffect(_spellAura, effectInfo->EffectIndex); } void Spell::EffectUnlearnSpecialization() |