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) for (auto const& [guid, combatRef] : _pvpRefs)
pair.second->Suppress(_owner); if (!unitFilter || unitFilter(combatRef->GetOther(_owner)))
combatRef->Suppress(_owner);
if (UpdateOwnerCombatState()) if (UpdateOwnerCombatState())
if (UnitAI* ownerAI = _owner->GetAI()) if (UnitAI* ownerAI = _owner->GetAI())
ownerAI->JustExitedCombat(); ownerAI->JustExitedCombat();
} }
void CombatManager::EndAllPvECombat() void CombatManager::EndAllPvECombat(UnitFilter* unitFilter /*= nullptr*/)
{ {
// cannot have threat without combat // cannot have threat without combat
_owner->GetThreatManager().RemoveMeFromThreatLists(); _owner->GetThreatManager().RemoveMeFromThreatLists(unitFilter);
_owner->GetThreatManager().ClearAllThreat(); _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() void CombatManager::RevalidateCombat()
@@ -324,12 +333,19 @@ void CombatManager::RevalidateCombat()
} }
} }
void CombatManager::EndAllPvPCombat() void CombatManager::EndAllPvPCombat(UnitFilter* unitFilter /*= nullptr*/)
{ {
while (!_pvpRefs.empty()) std::vector<CombatReference*> combatReferencesToRemove;
_pvpRefs.begin()->second->EndCombat(); 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) /*static*/ void CombatManager::NotifyAICombat(Unit* me, Unit* other)
{ {
if (UnitAI* ai = me->GetAI()) if (UnitAI* ai = me->GetAI())
+7 -4
View File
@@ -119,12 +119,15 @@ class TC_GAME_API CombatManager
bool IsInCombatWith(Unit const* who) const; bool IsInCombatWith(Unit const* who) const;
void InheritCombatStatesFrom(Unit const* who); void InheritCombatStatesFrom(Unit const* who);
void EndCombatBeyondRange(float range, bool includingPvP = false); 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 // flags any pvp refs for suppression on owner's side - these refs will not generate combat until refreshed
void SuppressPvPCombat(); void SuppressPvPCombat(UnitFilter* unitFilter = nullptr);
void EndAllPvECombat(); void EndAllPvECombat(UnitFilter* unitFilter = nullptr);
void RevalidateCombat(); void RevalidateCombat();
void EndAllPvPCombat(); void EndAllPvPCombat(UnitFilter* unitFilter = nullptr);
void EndAllCombat() { EndAllPvECombat(); EndAllPvPCombat(); } void EndAllCombat(UnitFilter* unitFilter = nullptr) { EndAllPvECombat(unitFilter); EndAllPvPCombat(unitFilter); }
CombatManager(CombatManager const&) = delete; CombatManager(CombatManager const&) = delete;
CombatManager& operator=(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); threatened->GetThreatManager().AddThreat(assistant, 0.0f, spell, true);
} }
void ThreatManager::RemoveMeFromThreatLists() void ThreatManager::RemoveMeFromThreatLists(bool (*unitFilter)(Unit const* otherUnit))
{ {
while (!_threatenedByMe.empty()) std::vector<ThreatReference*> threatReferencesToRemove;
{ threatReferencesToRemove.reserve(_threatenedByMe.size());
auto& ref = _threatenedByMe.begin()->second; for (auto const& [guid, ref] : _threatenedByMe)
if (!unitFilter || unitFilter(ref->GetOwner()))
threatReferencesToRemove.push_back(ref);
for (ThreatReference* ref : threatReferencesToRemove)
ref->_mgr.ClearThreat(_owner); ref->_mgr.ClearThreat(_owner);
}
} }
void ThreatManager::UpdateMyTempModifiers() 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 // 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); void ForwardThreatForAssistingMe(Unit* assistant, float baseAmount, SpellInfo const* spell = nullptr, bool ignoreModifiers = false);
// delete all ThreatReferences with victim == owner // 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 // re-calculates the temporary threat modifier from auras on myself
void UpdateMyTempModifiers(); void UpdateMyTempModifiers();
// re-calculate SPELL_AURA_MOD_THREAT modifiers // 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 CanAssistTo(const Unit* u, const Unit* enemy, bool checkfaction = true) const;
bool _IsTargetAcceptable(const Unit* target) const; bool _IsTargetAcceptable(const Unit* target) const;
bool CanIgnoreFeignDeath() const { return (GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_IGNORE_FEIGN_DEATH) != 0; } 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; } MovementGeneratorType GetDefaultMovementType() const { return m_defaultMovementType; }
void SetDefaultMovementType(MovementGeneratorType mgt) { m_defaultMovementType = mgt; } 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_NO_WOUNDED_SLOWDOWN = 0x00000040,
CREATURE_STATIC_FLAG_2_USE_CREATOR_BONUSES = 0x00000080, 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_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_ACTION_TRIGGERS_WHILE_CHARMED = 0x00000400,
CREATURE_STATIC_FLAG_2_INTERACT_WHILE_DEAD = 0x00000800, // CREATURE_TYPE_FLAG_INTERACT_WHILE_DEAD CREATURE_STATIC_FLAG_2_INTERACT_WHILE_DEAD = 0x00000800, // CREATURE_TYPE_FLAG_INTERACT_WHILE_DEAD
CREATURE_STATIC_FLAG_2_NO_INTERRUPT_SCHOOL_COOLDOWN = 0x00001000, CREATURE_STATIC_FLAG_2_NO_INTERRUPT_SCHOOL_COOLDOWN = 0x00001000,
+17 -8
View File
@@ -5530,23 +5530,32 @@ void Unit::ValidateAttackersAndOwnTarget()
AttackStop(); AttackStop();
} }
void Unit::CombatStop(bool includingCast, bool mutualPvP) void Unit::CombatStop(bool includingCast, bool mutualPvP, bool (*unitFilter)(Unit const* otherUnit))
{ {
if (includingCast && IsNonMeleeSpellCast(false)) if (includingCast && IsNonMeleeSpellCast(false))
InterruptNonMeleeSpells(false); InterruptNonMeleeSpells(false);
AttackStop(); 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) if (GetTypeId() == TYPEID_PLAYER)
ToPlayer()->SendAttackSwingCancelAttack(); // melee and ranged forced attack cancel ToPlayer()->SendAttackSwingCancelAttack(); // melee and ranged forced attack cancel
m_combatManager.EndAllPvECombat(unitFilter);
if (mutualPvP) if (mutualPvP)
ClearInCombat(); m_combatManager.EndAllPvPCombat(unitFilter);
else else // vanish and brethren are weird
{ // vanish and brethren are weird m_combatManager.SuppressPvPCombat(unitFilter);
m_combatManager.EndAllPvECombat();
m_combatManager.SuppressPvPCombat();
}
} }
void Unit::CombatStopWithPets(bool includingCast) void Unit::CombatStopWithPets(bool includingCast)
+1 -1
View File
@@ -865,7 +865,7 @@ class TC_GAME_API Unit : public WorldObject
} }
void ValidateAttackersAndOwnTarget(); 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 CombatStopWithPets(bool includingCast = false);
void StopAttackFaction(uint32 faction_id); void StopAttackFaction(uint32 faction_id);
Unit* SelectNearbyTarget(Unit* exclude = nullptr, float dist = NOMINAL_MELEE_RANGE) const; 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) if (!unitTarget)
return; return;
auto isAffectedBySanctuary = [](Unit const* attacker)
{
Creature const* attackerCreature = attacker->ToCreature();
return !attackerCreature || !attackerCreature->IsIgnoringSanctuarySpellEffect();
};
if (unitTarget->GetTypeId() == TYPEID_PLAYER && !unitTarget->GetMap()->IsDungeon()) if (unitTarget->GetTypeId() == TYPEID_PLAYER && !unitTarget->GetMap()->IsDungeon())
{ {
// stop all pve combat for players outside dungeons, suppress pvp combat // stop all pve combat for players outside dungeons, suppress pvp combat
unitTarget->CombatStop(false, false); unitTarget->CombatStop(false, false, isAffectedBySanctuary);
} }
else else
{ {
// in dungeons (or for nonplayers), reset this unit on all enemies' threat lists // in dungeons (or for nonplayers), reset this unit on all enemies' threat lists
for (auto const& pair : unitTarget->GetThreatManager().GetThreatenedByMeList()) for (auto const& [guid, ref] : unitTarget->GetThreatManager().GetThreatenedByMeList())
pair.second->ScaleThreat(0.0f); if (isAffectedBySanctuary(ref->GetOwner()))
ref->ScaleThreat(0.0f);
} }
// makes spells cast before this time fizzle // makes spells cast before this time fizzle