aboutsummaryrefslogtreecommitdiff
path: root/src/server/game/AI/CreatureAI.cpp
diff options
context:
space:
mode:
authorTreeston <treeston.mmoc@gmail.com>2018-01-03 20:04:19 +0100
committerShauren <shauren.trinity@gmail.com>2021-05-16 21:56:01 +0200
commit34c7810fe507eca1b8b9389630db5d5d26d92e77 (patch)
treee05653a0adaf4c4f5c406649f1bfe6573cbb22ff /src/server/game/AI/CreatureAI.cpp
parent5158136ee8a77046e37bafa192481b8b61d4a116 (diff)
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. (cherry picked from commit 532ab1c7f8653d1a2e48aa1f1f8a9ba1041d4bb7)
Diffstat (limited to 'src/server/game/AI/CreatureAI.cpp')
-rw-r--r--src/server/game/AI/CreatureAI.cpp66
1 files changed, 28 insertions, 38 deletions
diff --git a/src/server/game/AI/CreatureAI.cpp b/src/server/game/AI/CreatureAI.cpp
index 1b7234dd939..2c07dcd551d 100644
--- a/src/server/game/AI/CreatureAI.cpp
+++ b/src/server/game/AI/CreatureAI.cpp
@@ -67,61 +67,49 @@ void CreatureAI::DoZoneInCombat(Creature* creature /*= nullptr*/, float maxRange
if (!creature)
creature = me;
- if (!creature->CanHaveThreatList())
- return;
-
Map* map = creature->GetMap();
- if (!map->IsDungeon()) //use IsDungeon instead of Instanceable, in case battlegrounds will be instantiated
+ if (creature->CanHaveThreatList())
{
- TC_LOG_ERROR("misc", "DoZoneInCombat call for map that isn't an instance (creature entry = %d)", creature->GetTypeId() == TYPEID_UNIT ? creature->ToCreature()->GetEntry() : 0);
- return;
- }
+ if (!map->IsDungeon()) //use IsDungeon instead of Instanceable, in case battlegrounds will be instantiated
+ {
+ TC_LOG_ERROR("misc", "DoZoneInCombat call for map that isn't an instance (creature entry = %d)", creature->GetTypeId() == TYPEID_UNIT ? creature->ToCreature()->GetEntry() : 0);
+ return;
+ }
- if (!creature->HasReactState(REACT_PASSIVE) && !creature->GetVictim())
- {
- if (Unit* nearTarget = creature->SelectNearestTarget(maxRangeToNearestTarget))
- creature->AI()->AttackStart(nearTarget);
- else if (creature->IsSummon())
+ if (!creature->HasReactState(REACT_PASSIVE) && !creature->GetVictim())
{
- if (Unit* summoner = creature->ToTempSummon()->GetSummoner())
+ if (Unit* nearTarget = creature->SelectNearestTarget(maxRangeToNearestTarget))
+ creature->AI()->AttackStart(nearTarget);
+ else if (creature->IsSummon())
{
- Unit* target = summoner->getAttackerForHelper();
- if (!target && summoner->CanHaveThreatList() && !summoner->GetThreatManager().IsThreatListEmpty())
- target = summoner->GetThreatManager().GetAnyTarget();
- if (target && (creature->IsFriendlyTo(summoner) || creature->IsHostileTo(target)))
- creature->AI()->AttackStart(target);
+ if (Unit* summoner = creature->ToTempSummon()->GetSummoner())
+ {
+ Unit* target = summoner->getAttackerForHelper();
+ if (!target && !summoner->GetThreatManager().IsThreatListEmpty())
+ target = summoner->GetThreatManager().GetAnyTarget();
+ if (target && (creature->IsFriendlyTo(summoner) || creature->IsHostileTo(target)))
+ creature->AI()->AttackStart(target);
+ }
}
}
- }
- // Intended duplicated check, the code above this should select a victim
- // If it can't find a suitable attack target then we should error out.
- if (!creature->HasReactState(REACT_PASSIVE) && !creature->GetVictim())
- {
- TC_LOG_ERROR("misc.dozoneincombat", "DoZoneInCombat called for creature that has empty threat list (creature entry = %u)", creature->GetEntry());
- return;
+ // Intended duplicated check, the code above this should select a victim
+ // If it can't find a suitable attack target then we should error out.
+ if (!creature->HasReactState(REACT_PASSIVE) && !creature->GetVictim())
+ {
+ TC_LOG_ERROR("misc.dozoneincombat", "DoZoneInCombat called for creature that has empty threat list (creature entry = %u)", creature->GetEntry());
+ return;
+ }
}
Map::PlayerList const& playerList = map->GetPlayers();
-
if (playerList.isEmpty())
return;
for (Map::PlayerList::const_iterator itr = playerList.begin(); itr != playerList.end(); ++itr)
- {
if (Player* player = itr->GetSource())
- {
- if (player->IsGameMaster())
- continue;
-
if (player->IsAlive())
- {
creature->SetInCombatWith(player);
- player->SetInCombatWith(creature);
- creature->GetThreatManager().AddThreat(player, 0.0f, nullptr, true, true);
- }
- }
- }
}
// scripts does not take care about MoveInLineOfSight loops
@@ -249,11 +237,13 @@ bool CreatureAI::UpdateVictim()
return me->GetVictim() != nullptr;
}
- else if (me->GetThreatManager().IsThreatListEmpty())
+ else if (me->GetThreatManager().IsThreatListEmpty(true))
{
EnterEvadeMode(EVADE_REASON_NO_HOSTILES);
return false;
}
+ else
+ me->AttackStop();
return true;
}