Core: Combat/threat system rewrite (PR #19930)

- PvE combat is now always mutual. UNIT_FLAG_IN_COMBAT is backed by actual references to the units we're in combat with.
- PvP combat is now also tracked, and almost always mutual; spells like Vanish and Feign Death can break this rule. That means we can easily determine a list of players we're fighting.
- By extension, IsInCombatWith now has sensible behavior when invoked on nonplayers.
- Threat and combat systems are no longer the same.
  - They still have an enforced relationship (threat implies combat - clearing combat clears threat)...
  - ...but we can have combat without threat. A creature (with threat list) isn't considered to be engaged until it has an entry on its threat list...
  - ...which means we can now faithfully replicate retail engage behavior. Combat on projectile launch - engagement start on projectile impact. Yay for progress!
- AI method refactor, as already ported in 6113b9d - `JustEngagedWith`, `JustEnteredCombat` and `JustExitedCombat`.
- Vehicle threat is now properly pooled on the main vehicle body (fixes #16542).
- Various edge case bug fixes for threat redirects (Misdirection "cancelling" Vigilance and similar).
- Target re-selection is now significantly faster.
- Fixed a ton of other smaller edge case bugs, probably.

Closes #7951 and #19998.
This commit is contained in:
Treeston authored and Ovahlord committed 2020-07-22 16:49:37 +02:00
1 parent 280b8dc799
commit 942c3a77da
53 files changed
+1607 -2232

No files matched your search

+74 -25
View File
@@ -848,23 +848,73 @@ public:
static bool HandleDebugThreatListCommand(ChatHandler* handler, char const* /*args*/)
{
Creature* target = handler->getSelectedCreature();
if (!target || target->IsTotem() || target->IsPet())
return false;
Unit* target = handler->getSelectedUnit();
if (!target)
target = handler->GetSession()->GetPlayer();
ThreatContainer::StorageType const& threatList = target->GetThreatManager().getThreatList();
ThreatContainer::StorageType::const_iterator itr;
uint32 count = 0;
handler->PSendSysMessage("Threat list of %s (guid %u)", target->GetName().c_str(), target->GetGUID().GetCounter());
for (itr = threatList.begin(); itr != threatList.end(); ++itr)
ThreatManager& mgr = target->GetThreatManager();
if (!target->IsAlive())
{
Unit* unit = (*itr)->getTarget();
if (!unit)
continue;
++count;
handler->PSendSysMessage(" %u. %s (guid %u) - threat %f", count, unit->GetName().c_str(), unit->GetGUID().GetCounter(), (*itr)->getThreat());
handler->PSendSysMessage("%s (guid %u) is not alive.", target->GetName().c_str(), target->GetGUID().GetCounter());
return true;
}
handler->SendSysMessage("End of threat list.");
if (!target->CanHaveThreatList())
handler->PSendSysMessage("%s (guid %u) cannot have a threat list.", target->GetName().c_str(), target->GetGUID().GetCounter());
uint32 count = 0;
auto const& threatenedByMe = target->GetThreatManager().GetThreatenedByMeList();
if (threatenedByMe.empty())
handler->PSendSysMessage("%s (guid %u) does not threaten any units.", target->GetName().c_str(), target->GetGUID().GetCounter());
else
{
handler->PSendSysMessage("List of units threatened by %s (guid %u)", target->GetName().c_str(), target->GetGUID().GetCounter());
for (auto const& pair : threatenedByMe)
{
Unit* unit = pair.second->GetOwner();
handler->PSendSysMessage(" %u. %s (current guid %u, DB guid %u) - threat %f", ++count, unit->GetName().c_str(), unit->GetGUID().GetCounter(), unit->GetTypeId() == TYPEID_UNIT ? unit->ToCreature()->GetSpawnId() : 0, pair.second->GetThreat());
}
handler->SendSysMessage("End of threatened-by-me list.");
}
if (!mgr.CanHaveThreatList())
return true;
if (mgr.IsEngaged())
{
count = 0;
handler->PSendSysMessage("Threat list of %s (guid %u, DB GUID %u)", target->GetName().c_str(), target->GetGUID().GetCounter(), target->GetTypeId() == TYPEID_UNIT ? target->ToCreature()->GetSpawnId() : 0);
for (ThreatReference const* ref : mgr.GetSortedThreatList())
{
Unit* unit = ref->GetVictim();
char const* onlineStr;
switch (ref->GetOnlineState())
{
case ThreatReference::ONLINE_STATE_SUPPRESSED:
onlineStr = " [SUPPRESSED]";
break;
case ThreatReference::ONLINE_STATE_OFFLINE:
onlineStr = " [OFFLINE]";
break;
default:
onlineStr = "";
}
char const* tauntStr;
switch (ref->GetTauntState())
{
case ThreatReference::TAUNT_STATE_TAUNT:
tauntStr = " [TAUNT]";
break;
case ThreatReference::TAUNT_STATE_DETAUNT:
tauntStr = " [DETAUNT]";
break;
default:
tauntStr = "";
}
handler->PSendSysMessage(" %u. %s (guid %u) - threat %f%s%s", ++count, unit->GetName().c_str(), unit->GetGUID().GetCounter(), ref->GetThreat(), tauntStr, onlineStr);
}
handler->SendSysMessage("End of threat list.");
}
else
handler->PSendSysMessage("%s (guid %u, DB GUID %u) is not currently engaged.", target->GetName().c_str(), target->GetGUID().GetCounter(), target->GetTypeId() == TYPEID_UNIT ? target->ToCreature()->GetSpawnId() : 0);
return true;
}
@@ -873,19 +923,18 @@ public:
Unit* target = handler->getSelectedUnit();
if (!target)
target = handler->GetSession()->GetPlayer();
HostileReference* ref = target->getHostileRefManager().getFirst();
uint32 count = 0;
handler->PSendSysMessage("Hostil reference list of %s (guid %u)", target->GetName().c_str(), target->GetGUID().GetCounter());
while (ref)
handler->PSendSysMessage("Combat refs: (Combat state: %d | Manager state: %d)", target->IsInCombat(), target->GetCombatManager().HasCombat());
for (auto const& ref : target->GetCombatManager().GetPvPCombatRefs())
{
if (Unit* unit = ref->GetSource()->GetOwner())
{
++count;
handler->PSendSysMessage(" %u. %s (current guid %u, DB guid %u) - threat %f", count, unit->GetName().c_str(), unit->GetGUID().GetCounter(), unit->GetTypeId() == TYPEID_UNIT ? unit->ToCreature()->GetSpawnId() : 0, ref->getThreat());
}
ref = ref->next();
Unit* unit = ref.second->GetOther(target);
handler->PSendSysMessage("[PvP] %s (DBGUID %u)", unit->GetName().c_str(), unit->GetTypeId() == TYPEID_UNIT ? unit->ToCreature()->GetSpawnId() : 0);
}
for (auto const& ref : target->GetCombatManager().GetPvECombatRefs())
{
Unit* unit = ref.second->GetOther(target);
handler->PSendSysMessage("[PvE] %s (DBGUID %u)", unit->GetName().c_str(), unit->GetTypeId() == TYPEID_UNIT ? unit->ToCreature()->GetSpawnId() : 0);
}
handler->SendSysMessage("End of hostil reference list.");
return true;
}