aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/server/game/Combat/CombatManager.cpp35
-rw-r--r--src/server/game/Combat/CombatManager.h11
-rw-r--r--src/server/game/Combat/ThreatManager.cpp13
-rw-r--r--src/server/game/Combat/ThreatManager.h2
-rw-r--r--src/server/game/Entities/Creature/Creature.h2
-rw-r--r--src/server/game/Entities/Creature/CreatureData.h2
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp25
-rw-r--r--src/server/game/Entities/Unit/Unit.h2
-rw-r--r--src/server/game/Spells/SpellEffects.cpp13
9 files changed, 72 insertions, 33 deletions
diff --git a/src/server/game/Combat/CombatManager.cpp b/src/server/game/Combat/CombatManager.cpp
index 721b8d5c3f5..18e084f8e0d 100644
--- a/src/server/game/Combat/CombatManager.cpp
+++ b/src/server/game/Combat/CombatManager.cpp
@@ -295,22 +295,31 @@ void CombatManager::EndCombatBeyondRange(float range, bool includingPvP)
}
}
-void CombatManager::SuppressPvPCombat()
+void CombatManager::SuppressPvPCombat(UnitFilter* unitFilter /*= nullptr*/)
{
- for (auto const& pair : _pvpRefs)
- pair.second->Suppress(_owner);
+ for (auto const& [guid, combatRef] : _pvpRefs)
+ if (!unitFilter || unitFilter(combatRef->GetOther(_owner)))
+ combatRef->Suppress(_owner);
+
if (UpdateOwnerCombatState())
if (UnitAI* ownerAI = _owner->GetAI())
ownerAI->JustExitedCombat();
}
-void CombatManager::EndAllPvECombat()
+void CombatManager::EndAllPvECombat(UnitFilter* unitFilter /*= nullptr*/)
{
// cannot have threat without combat
- _owner->GetThreatManager().RemoveMeFromThreatLists();
+ _owner->GetThreatManager().RemoveMeFromThreatLists(unitFilter);
_owner->GetThreatManager().ClearAllThreat();
- while (!_pveRefs.empty())
- _pveRefs.begin()->second->EndCombat();
+
+ std::vector<CombatReference*> combatReferencesToRemove;
+ combatReferencesToRemove.reserve(_pveRefs.size());
+ for (auto const& [guid, combatRef] : _pveRefs)
+ if (!unitFilter || unitFilter(combatRef->GetOther(_owner)))
+ combatReferencesToRemove.push_back(combatRef);
+
+ for (CombatReference* combatRef : combatReferencesToRemove)
+ combatRef->EndCombat();
}
void CombatManager::RevalidateCombat()
@@ -342,10 +351,16 @@ void CombatManager::RevalidateCombat()
}
}
-void CombatManager::EndAllPvPCombat()
+void CombatManager::EndAllPvPCombat(UnitFilter* unitFilter /*= nullptr*/)
{
- while (!_pvpRefs.empty())
- _pvpRefs.begin()->second->EndCombat();
+ std::vector<CombatReference*> combatReferencesToRemove;
+ combatReferencesToRemove.reserve(_pvpRefs.size());
+ for (auto const& [guid, combatRef] : _pvpRefs)
+ if (!unitFilter || unitFilter(combatRef->GetOther(_owner)))
+ combatReferencesToRemove.push_back(combatRef);
+
+ for (CombatReference* combatRef : combatReferencesToRemove)
+ combatRef->EndCombat();
}
/*static*/ void CombatManager::NotifyAICombat(Unit* me, Unit* other)
diff --git a/src/server/game/Combat/CombatManager.h b/src/server/game/Combat/CombatManager.h
index 1dfd926fa0f..d44aff87e1c 100644
--- a/src/server/game/Combat/CombatManager.h
+++ b/src/server/game/Combat/CombatManager.h
@@ -120,12 +120,15 @@ class TC_GAME_API CombatManager
bool IsInCombatWith(Unit const* who) const;
void InheritCombatStatesFrom(Unit const* who);
void EndCombatBeyondRange(float range, bool includingPvP = false);
+
+ using UnitFilter = bool(Unit const* otherUnit);
+
// flags any pvp refs for suppression on owner's side - these refs will not generate combat until refreshed
- void SuppressPvPCombat();
- void EndAllPvECombat();
+ void SuppressPvPCombat(UnitFilter* unitFilter = nullptr);
+ void EndAllPvECombat(UnitFilter* unitFilter = nullptr);
void RevalidateCombat();
- void EndAllPvPCombat();
- void EndAllCombat() { EndAllPvECombat(); EndAllPvPCombat(); }
+ void EndAllPvPCombat(UnitFilter* unitFilter = nullptr);
+ void EndAllCombat(UnitFilter* unitFilter = nullptr) { EndAllPvECombat(unitFilter); EndAllPvPCombat(unitFilter); }
CombatManager(CombatManager const&) = delete;
CombatManager& operator=(CombatManager const&) = delete;
diff --git a/src/server/game/Combat/ThreatManager.cpp b/src/server/game/Combat/ThreatManager.cpp
index 9376d42b010..04ff7e36da1 100644
--- a/src/server/game/Combat/ThreatManager.cpp
+++ b/src/server/game/Combat/ThreatManager.cpp
@@ -743,13 +743,16 @@ void ThreatManager::ForwardThreatForAssistingMe(Unit* assistant, float baseAmoun
threatened->GetThreatManager().AddThreat(assistant, 0.0f, spell, true);
}
-void ThreatManager::RemoveMeFromThreatLists()
+void ThreatManager::RemoveMeFromThreatLists(bool (*unitFilter)(Unit const* otherUnit))
{
- while (!_threatenedByMe.empty())
- {
- auto& ref = _threatenedByMe.begin()->second;
+ std::vector<ThreatReference*> threatReferencesToRemove;
+ threatReferencesToRemove.reserve(_threatenedByMe.size());
+ for (auto const& [guid, ref] : _threatenedByMe)
+ if (!unitFilter || unitFilter(ref->GetOwner()))
+ threatReferencesToRemove.push_back(ref);
+
+ for (ThreatReference* ref : threatReferencesToRemove)
ref->_mgr.ClearThreat(_owner);
- }
}
void ThreatManager::UpdateMyTempModifiers()
diff --git a/src/server/game/Combat/ThreatManager.h b/src/server/game/Combat/ThreatManager.h
index b78a2e59b37..8681d6af9d1 100644
--- a/src/server/game/Combat/ThreatManager.h
+++ b/src/server/game/Combat/ThreatManager.h
@@ -165,7 +165,7 @@ class TC_GAME_API ThreatManager
// what it says on the tin - call AddThreat on everything that's threatened by us with the specified params
void ForwardThreatForAssistingMe(Unit* assistant, float baseAmount, SpellInfo const* spell = nullptr, bool ignoreModifiers = false);
// delete all ThreatReferences with victim == owner
- void RemoveMeFromThreatLists();
+ void RemoveMeFromThreatLists(bool (*unitFilter)(Unit const* otherUnit));
// re-calculates the temporary threat modifier from auras on myself
void UpdateMyTempModifiers();
// re-calculate SPELL_AURA_MOD_THREAT modifiers
diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h
index 723b58afeb4..237b5f45310 100644
--- a/src/server/game/Entities/Creature/Creature.h
+++ b/src/server/game/Entities/Creature/Creature.h
@@ -320,6 +320,8 @@ class TC_GAME_API Creature : public Unit, public GridObject<Creature>, public Ma
bool CanAssistTo(Unit const* u, Unit const* enemy, bool checkfaction = true) const;
bool _IsTargetAcceptable(Unit const* target) const;
bool CanIgnoreFeignDeath() const { return (GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_IGNORE_FEIGN_DEATH) != 0; }
+ bool IsIgnoringSanctuarySpellEffect() const { return _staticFlags.HasFlag(CREATURE_STATIC_FLAG_2_IGNORE_SANCTUARY); }
+ void SetIngoreSanctuarySpellEffect(bool ignoreSanctuary) { _staticFlags.ApplyFlag(CREATURE_STATIC_FLAG_2_IGNORE_SANCTUARY, ignoreSanctuary); }
void RemoveCorpse(bool setSpawnTime = true, bool destroyForNearbyPlayers = true);
diff --git a/src/server/game/Entities/Creature/CreatureData.h b/src/server/game/Entities/Creature/CreatureData.h
index 79cdc6bdb8d..1e386ff2da5 100644
--- a/src/server/game/Entities/Creature/CreatureData.h
+++ b/src/server/game/Entities/Creature/CreatureData.h
@@ -82,7 +82,7 @@ enum CreatureStaticFlags2
CREATURE_STATIC_FLAG_2_NO_WOUNDED_SLOWDOWN = 0x00000040,
CREATURE_STATIC_FLAG_2_USE_CREATOR_BONUSES = 0x00000080,
CREATURE_STATIC_FLAG_2_IGNORE_FEIGN_DEATH = 0x00000100, // CREATURE_FLAG_EXTRA_IGNORE_FEIGN_DEATH
- CREATURE_STATIC_FLAG_2_IGNORE_SANCTUARY = 0x00000200,
+ CREATURE_STATIC_FLAG_2_IGNORE_SANCTUARY = 0x00000200, // Ignores SPELL_EFFECT_SANCTUARY
CREATURE_STATIC_FLAG_2_ACTION_TRIGGERS_WHILE_CHARMED = 0x00000400,
CREATURE_STATIC_FLAG_2_INTERACT_WHILE_DEAD = 0x00000800, // CREATURE_TYPE_FLAG_INTERACT_WHILE_DEAD
CREATURE_STATIC_FLAG_2_NO_INTERRUPT_SCHOOL_COOLDOWN = 0x00001000,
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index 8639c8e458b..ad8ebc33e94 100644
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -5822,23 +5822,32 @@ void Unit::ValidateAttackersAndOwnTarget()
AttackStop();
}
-void Unit::CombatStop(bool includingCast, bool mutualPvP)
+void Unit::CombatStop(bool includingCast, bool mutualPvP, bool (*unitFilter)(Unit const* otherUnit))
{
if (includingCast && IsNonMeleeSpellCast(false))
InterruptNonMeleeSpells(false);
AttackStop();
- RemoveAllAttackers();
+ if (!unitFilter)
+ RemoveAllAttackers();
+ else
+ {
+ std::vector<Unit*> attackersToRemove;
+ attackersToRemove.reserve(m_attackers.size());
+ std::copy_if(m_attackers.begin(), m_attackers.end(), std::back_inserter(attackersToRemove), unitFilter);
+
+ for (Unit* attacker : attackersToRemove)
+ attacker->AttackStop();
+ }
+
if (GetTypeId() == TYPEID_PLAYER)
ToPlayer()->SendAttackSwingCancelAttack(); // melee and ranged forced attack cancel
+ m_combatManager.EndAllPvECombat(unitFilter);
if (mutualPvP)
- ClearInCombat();
- else
- { // vanish and brethren are weird
- m_combatManager.EndAllPvECombat();
- m_combatManager.SuppressPvPCombat();
- }
+ m_combatManager.EndAllPvPCombat(unitFilter);
+ else // vanish and brethren are weird
+ m_combatManager.SuppressPvPCombat(unitFilter);
}
void Unit::CombatStopWithPets(bool includingCast)
diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h
index 47be2b81751..0c17b38a2fe 100644
--- a/src/server/game/Entities/Unit/Unit.h
+++ b/src/server/game/Entities/Unit/Unit.h
@@ -716,7 +716,7 @@ class TC_GAME_API Unit : public WorldObject
}
void ValidateAttackersAndOwnTarget();
- void CombatStop(bool includingCast = false, bool mutualPvP = true);
+ void CombatStop(bool includingCast = false, bool mutualPvP = true, bool (*unitFilter)(Unit const* otherUnit) = nullptr);
void CombatStopWithPets(bool includingCast = false);
void StopAttackFaction(uint32 faction_id);
Unit* SelectNearbyTarget(Unit* exclude = nullptr, float dist = NOMINAL_MELEE_RANGE) const;
diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp
index 72d0271d656..8c694c29f89 100644
--- a/src/server/game/Spells/SpellEffects.cpp
+++ b/src/server/game/Spells/SpellEffects.cpp
@@ -3130,16 +3130,23 @@ void Spell::EffectSanctuary()
if (!unitTarget)
return;
+ auto isAffectedBySanctuary = [](Unit const* attacker)
+ {
+ Creature const* attackerCreature = attacker->ToCreature();
+ return !attackerCreature || !attackerCreature->IsIgnoringSanctuarySpellEffect();
+ };
+
if (unitTarget->GetTypeId() == TYPEID_PLAYER && !unitTarget->GetMap()->IsDungeon())
{
// stop all pve combat for players outside dungeons, suppress pvp combat
- unitTarget->CombatStop(false, false);
+ unitTarget->CombatStop(false, false, isAffectedBySanctuary);
}
else
{
// in dungeons (or for nonplayers), reset this unit on all enemies' threat lists
- for (auto const& pair : unitTarget->GetThreatManager().GetThreatenedByMeList())
- pair.second->ScaleThreat(0.0f);
+ for (auto const& [guid, ref] : unitTarget->GetThreatManager().GetThreatenedByMeList())
+ if (isAffectedBySanctuary(ref->GetOwner()))
+ ref->ScaleThreat(0.0f);
}
// makes spells cast before this time fizzle