diff options
author | Treeston <treeston.mmoc@gmail.com> | 2018-01-03 20:04:19 +0100 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2021-05-16 21:56:01 +0200 |
commit | 34c7810fe507eca1b8b9389630db5d5d26d92e77 (patch) | |
tree | e05653a0adaf4c4f5c406649f1bfe6573cbb22ff /src/server/game/AI/CreatureAI.cpp | |
parent | 5158136ee8a77046e37bafa192481b8b61d4a116 (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.cpp | 66 |
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; } |