From 9bfc29f4aff01cd7f366faffcda0a84071970d6a Mon Sep 17 00:00:00 2001 From: Shauren Date: Sun, 4 Sep 2022 21:34:47 +0200 Subject: Core/Combat: Allow PvE combat references to become suppressed, just like PvP ones (cherry picked from commit e8dfd8c25c69247b17bc9359dfbe3a1d96ef98bf) --- src/server/game/Combat/CombatManager.cpp | 65 +++++++++++++++++++------------- src/server/game/Combat/CombatManager.h | 27 ++++++------- src/server/game/Entities/Unit/Unit.h | 2 +- 3 files changed, 54 insertions(+), 40 deletions(-) (limited to 'src') diff --git a/src/server/game/Combat/CombatManager.cpp b/src/server/game/Combat/CombatManager.cpp index 96508afa938..6367c7f5f5e 100644 --- a/src/server/game/Combat/CombatManager.cpp +++ b/src/server/game/Combat/CombatManager.cpp @@ -84,18 +84,8 @@ void CombatReference::EndCombat() delete this; } -bool PvPCombatReference::Update(uint32 tdiff) +void CombatReference::Refresh() { - if (_combatTimer <= tdiff) - return false; - _combatTimer -= tdiff; - return true; -} - -void PvPCombatReference::Refresh() -{ - _combatTimer = PVP_COMBAT_TIMEOUT; - bool needFirstAI = false, needSecondAI = false; if (_suppressFirst) { @@ -114,7 +104,7 @@ void PvPCombatReference::Refresh() CombatManager::NotifyAICombat(second, first); } -void PvPCombatReference::SuppressFor(Unit* who) +void CombatReference::SuppressFor(Unit* who) { Suppress(who); if (who->GetCombatManager().UpdateOwnerCombatState()) @@ -122,6 +112,19 @@ void PvPCombatReference::SuppressFor(Unit* who) ai->JustExitedCombat(); } +bool PvPCombatReference::Update(uint32 tdiff) +{ + if (_combatTimer <= tdiff) + return false; + _combatTimer -= tdiff; + return true; +} + +void PvPCombatReference::RefreshTimer() +{ + _combatTimer = PVP_COMBAT_TIMEOUT; +} + CombatManager::~CombatManager() { ASSERT(_pveRefs.empty(), "CombatManager::~CombatManager - %s: we still have %zu PvE combat references, one of them is with %s", _owner->GetGUID().ToString().c_str(), _pveRefs.size(), _pveRefs.begin()->first.ToString().c_str()); @@ -144,10 +147,18 @@ void CombatManager::Update(uint32 tdiff) } } +bool CombatManager::HasPvECombat() const +{ + for (auto const& [guid, ref] : _pveRefs) + if (!ref->IsSuppressedFor(_owner)) + return true; + return false; +} + bool CombatManager::HasPvECombatWithPlayers() const { for (std::pair const& reference : _pveRefs) - if (reference.second->GetOther(_owner)->GetTypeId() == TYPEID_PLAYER) + if (!reference.second->IsSuppressedFor(_owner) && reference.second->GetOther(_owner)->GetTypeId() == TYPEID_PLAYER) return true; return false; @@ -163,25 +174,29 @@ bool CombatManager::HasPvPCombat() const Unit* CombatManager::GetAnyTarget() const { - if (!_pveRefs.empty()) - return _pveRefs.begin()->second->GetOther(_owner); + for (auto const& pair : _pveRefs) + if (!pair.second->IsSuppressedFor(_owner)) + return pair.second->GetOther(_owner); for (auto const& pair : _pvpRefs) if (!pair.second->IsSuppressedFor(_owner)) return pair.second->GetOther(_owner); return nullptr; } -bool CombatManager::SetInCombatWith(Unit* who, bool suppressPvpSecond) +bool CombatManager::SetInCombatWith(Unit* who, bool addSecondUnitSuppressed) { // Are we already in combat? If yes, refresh pvp combat - auto it = _pvpRefs.find(who->GetGUID()); - if (it != _pvpRefs.end()) + if (PvPCombatReference* existingPvpRef = Trinity::Containers::MapGetValuePtr(_pvpRefs, who->GetGUID())) { - it->second->Refresh(); + existingPvpRef->RefreshTimer(); + existingPvpRef->Refresh(); return true; } - else if (_pveRefs.find(who->GetGUID()) != _pveRefs.end()) + if (CombatReference* existingPveRef = Trinity::Containers::MapGetValuePtr(_pveRefs, who->GetGUID())) + { + existingPveRef->Refresh(); return true; + } // Otherwise, check validity... if (!CombatManager::CanBeginCombat(_owner, who)) @@ -190,15 +205,13 @@ bool CombatManager::SetInCombatWith(Unit* who, bool suppressPvpSecond) // ...then create new reference CombatReference* ref; if (_owner->IsControlledByPlayer() && who->IsControlledByPlayer()) - { - PvPCombatReference* refPvp = new PvPCombatReference(_owner, who); - if (suppressPvpSecond) - refPvp->SuppressFor(who); - ref = refPvp; - } + ref = new PvPCombatReference(_owner, who); else ref = new CombatReference(_owner, who); + if (addSecondUnitSuppressed) + ref->Suppress(who); + // ...and insert it into both managers PutReference(who->GetGUID(), ref); who->GetCombatManager().PutReference(_owner->GetGUID(), ref); diff --git a/src/server/game/Combat/CombatManager.h b/src/server/game/Combat/CombatManager.h index 7745458788c..1dfd926fa0f 100644 --- a/src/server/game/Combat/CombatManager.h +++ b/src/server/game/Combat/CombatManager.h @@ -29,14 +29,12 @@ class Unit; * (future devs: please keep this up-to-date if you change the system) * * CombatManager maintains a list of dynamically allocated CombatReference entries. Each entry represents a combat state between two distinct units. * * A unit is "in combat" iff it has one or more non-suppressed CombatReference entries in its CombatManager. No exceptions. * - * - Note: Only PvP combat references can be suppressed, and only because Vanish is a very silly spell. Sue Blizzard. * * * * A CombatReference object carries the following implicit guarantees by existing: * * - Both CombatReference.first and CombatReference.second are valid Units, distinct, not nullptr and currently in the world. * * - If the CombatReference was retrieved from the CombatManager of Unit* A, then exactly one of .first and .second is equal to A. * * - Note: Use CombatReference::GetOther to quickly get the other unit for a given reference. * * - Both .first and .second are currently in combat (IsInCombat will always be true) if either of the following hold: * - * - The reference is a PvE combat reference (_isPvP is false) * * - IsSuppressedFor returns false for the respective unit * * * * To end combat between two units, find their CombatReference and call EndCombat. * @@ -60,12 +58,23 @@ struct TC_GAME_API CombatReference void EndCombat(); + // suppressed combat refs do not generate a combat state for one side of the relation + // (used by: vanish, feign death and launched out of combat but not yet landed spell missiles) + void SuppressFor(Unit* who); + bool IsSuppressedFor(Unit const* who) const { return (who == first) ? _suppressFirst : _suppressSecond; } + CombatReference(CombatReference const&) = delete; CombatReference& operator=(CombatReference const&) = delete; protected: CombatReference(Unit* a, Unit* b, bool pvp = false) : first(a), second(b), _isPvP(pvp) { } + void Refresh(); + void Suppress(Unit* who) { (who == first ? _suppressFirst : _suppressSecond) = true; } + + bool _suppressFirst = false; + bool _suppressSecond = false; + friend class CombatManager; }; @@ -74,21 +83,13 @@ struct TC_GAME_API PvPCombatReference : public CombatReference { static const uint32 PVP_COMBAT_TIMEOUT = 5 * IN_MILLISECONDS; - // suppressed combat refs do not generate a combat state for one side of the relation - // (used by: vanish, feign death) - void SuppressFor(Unit* who); - bool IsSuppressedFor(Unit const* who) const { return (who == first) ? _suppressFirst : _suppressSecond; } - private: PvPCombatReference(Unit* first, Unit* second) : CombatReference(first, second, true) { } bool Update(uint32 tdiff); - void Refresh(); - void Suppress(Unit* who) { (who == first ? _suppressFirst : _suppressSecond) = true; } + void RefreshTimer(); uint32 _combatTimer = PVP_COMBAT_TIMEOUT; - bool _suppressFirst = false; - bool _suppressSecond = false; friend class CombatManager; }; @@ -105,7 +106,7 @@ class TC_GAME_API CombatManager Unit* GetOwner() const { return _owner; } bool HasCombat() const { return HasPvECombat() || HasPvPCombat(); } - bool HasPvECombat() const { return !_pveRefs.empty(); } + bool HasPvECombat() const; bool HasPvECombatWithPlayers() const; std::unordered_map const& GetPvECombatRefs() const { return _pveRefs; } bool HasPvPCombat() const; @@ -114,7 +115,7 @@ class TC_GAME_API CombatManager Unit* GetAnyTarget() const; // return value is the same as calling IsInCombatWith immediately after this returns - bool SetInCombatWith(Unit* who, bool suppressPvpSecond = false); + bool SetInCombatWith(Unit* who, bool addSecondUnitSuppressed = false); bool IsInCombatWith(ObjectGuid const& who) const; bool IsInCombatWith(Unit const* who) const; void InheritCombatStatesFrom(Unit const* who); diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index 4a26e5b2691..a9dcb0e3783 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -1150,7 +1150,7 @@ class TC_GAME_API Unit : public WorldObject bool IsInCombat() const { return HasUnitFlag(UNIT_FLAG_IN_COMBAT); } bool IsInCombatWith(Unit const* who) const { return who && m_combatManager.IsInCombatWith(who); } - void SetInCombatWith(Unit* enemy, bool suppressPvpTargetCombat = false) { if (enemy) m_combatManager.SetInCombatWith(enemy, suppressPvpTargetCombat); } + void SetInCombatWith(Unit* enemy, bool addSecondUnitSuppressed = false) { if (enemy) m_combatManager.SetInCombatWith(enemy, addSecondUnitSuppressed); } void ClearInCombat() { m_combatManager.EndAllCombat(); } void UpdatePetCombatState(); // Threat handling -- cgit v1.2.3