mirror of
https://github.com/TrinityCore/TrinityCore.git
synced 2026-01-16 07:30:42 +01:00
Core/Combat: Allow PvE combat references to become suppressed, just like PvP ones
(cherry picked from commit e8dfd8c25c)
This commit is contained in:
@@ -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<ObjectGuid const, CombatReference*> 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);
|
||||
|
||||
@@ -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<ObjectGuid, CombatReference*> 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);
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user