diff options
| author | Shauren <shauren.trinity@gmail.com> | 2024-03-04 00:05:35 +0100 | 
|---|---|---|
| committer | Shauren <shauren.trinity@gmail.com> | 2024-03-04 00:05:35 +0100 | 
| commit | 1369b8708458fb5020b6ab7a9608123459d4eb26 (patch) | |
| tree | 005298c2db7f1b5067f8e1746f74541cf1b9c9d8 /src | |
| parent | 74ec1d3cfb3172a7bb3c2d2317396ff82245418e (diff) | |
Core/Creatures: Implemented CREATURE_STATIC_FLAG_2_IGNORE_SANCTUARY (ignore SPELL_EFFECT_SANCTUARY, used by Vanish)
Diffstat (limited to 'src')
| -rw-r--r-- | src/server/game/Combat/CombatManager.cpp | 35 | ||||
| -rw-r--r-- | src/server/game/Combat/CombatManager.h | 11 | ||||
| -rw-r--r-- | src/server/game/Combat/ThreatManager.cpp | 13 | ||||
| -rw-r--r-- | src/server/game/Combat/ThreatManager.h | 2 | ||||
| -rw-r--r-- | src/server/game/Entities/Creature/Creature.h | 2 | ||||
| -rw-r--r-- | src/server/game/Entities/Creature/CreatureData.h | 2 | ||||
| -rw-r--r-- | src/server/game/Entities/Unit/Unit.cpp | 25 | ||||
| -rw-r--r-- | src/server/game/Entities/Unit/Unit.h | 2 | ||||
| -rw-r--r-- | src/server/game/Spells/SpellEffects.cpp | 13 | 
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  | 
