Core/Creatures: Implemented CREATURE_STATIC_FLAG_2_IGNORE_SANCTUARY (ignore SPELL_EFFECT_SANCTUARY, used by Vanish)

This commit is contained in:
Shauren authored and Ovahlord committed 2025-03-15 07:16:45 +01:00
1 parent a4aa09de52
commit a7644b03d4
9 files changed
+73 -33

No files matched your search

+26 -10
View File
@@ -277,22 +277,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()
@@ -324,12 +333,19 @@ 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)
{
if (UnitAI* ai = me->GetAI())
+7 -4
View File
@@ -119,12 +119,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;
+8 -5
View File
@@ -752,13 +752,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()
+1 -1
View File
@@ -167,7 +167,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
@@ -277,6 +277,8 @@ class TC_GAME_API Creature : public Unit, public GridObject<Creature>, public Ma
bool CanAssistTo(const Unit* u, const Unit* enemy, bool checkfaction = true) const;
bool _IsTargetAcceptable(const Unit* 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); }
MovementGeneratorType GetDefaultMovementType() const { return m_defaultMovementType; }
void SetDefaultMovementType(MovementGeneratorType mgt) { m_defaultMovementType = mgt; }
@@ -126,7 +126,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,
+17 -8
View File
@@ -5530,23 +5530,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)
+1 -1
View File
@@ -865,7 +865,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;
+10 -3
View File
@@ -3573,16 +3573,23 @@ void Spell::EffectSanctuary(SpellEffIndex /*effIndex*/)
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