Compare commits

..

No commits in common. "9f875a7c81124baca6392d83240c637e17b6140e" and "2b273f6a2c8ffea04fc41d3bb58788af1a67d1d9" have entirely different histories.

16 changed files with 189 additions and 119 deletions

View File

@ -1387,8 +1387,8 @@ bool MovementAction::Flee(Unit* target)
}
}
Unit* currentVictim = target->GetThreatMgr().GetCurrentVictim();
if (currentVictim && currentVictim == bot) // bot is target - try to flee to tank or master
HostileReference* ref = target->GetThreatMgr().getCurrentVictim();
if (ref && ref->getTarget() == bot) // bot is target - try to flee to tank or master
{
if (Group* group = bot->GetGroup())
{

View File

@ -6,8 +6,7 @@
#include "TellTargetAction.h"
#include "Event.h"
#include "CombatManager.h"
#include "ThreatManager.h"
#include "ThreatMgr.h"
#include "AiObjectContext.h"
#include "PlayerbotAI.h"
@ -43,21 +42,21 @@ bool TellAttackersAction::Execute(Event /*event*/)
botAI->TellMaster("--- Threat ---");
auto const& threatenedByMe = bot->GetThreatMgr().GetThreatenedByMeList();
if (threatenedByMe.empty())
HostileReference* ref = bot->getHostileRefMgr().getFirst();
if (!ref)
return true;
for (auto const& [guid, ref] : threatenedByMe)
while (ref)
{
Unit* unit = ref->GetOwner();
if (!unit)
continue;
ThreatMgr* threatMgr = ref->GetSource();
Unit* unit = threatMgr->GetOwner();
float threat = ref->GetThreat();
std::ostringstream out;
out << unit->GetName() << " (" << threat << ")";
botAI->TellMaster(out);
ref = ref->next();
}
return true;

View File

@ -16,7 +16,7 @@
#include "PositionValue.h"
#include "SharedDefines.h"
#include "TemporarySummon.h"
#include "ThreatManager.h"
#include "ThreatMgr.h"
#include "Timer.h"
#include "PlayerbotAI.h"
#include "Player.h"
@ -217,7 +217,7 @@ bool LowTankThreatTrigger::IsActive()
if (!current_target)
return false;
ThreatManager& mgr = current_target->GetThreatMgr();
ThreatMgr& mgr = current_target->GetThreatMgr();
float threat = mgr.GetThreat(bot);
float tankThreat = mgr.GetThreat(mt);
return tankThreat == 0.0f || threat > tankThreat * 0.5f;

View File

@ -92,15 +92,21 @@ void AttackersValue::AddAttackersOf(Player* player, std::unordered_set<Unit*>& t
if (!player || !player->IsInWorld() || player->IsBeingTeleported())
return;
for (auto const& [guid, ref] : player->GetThreatMgr().GetThreatenedByMeList())
HostileRefMgr& refManager = player->getHostileRefMgr();
HostileReference* ref = refManager.getFirst();
if (!ref)
return;
while (ref)
{
Unit* attacker = ref->GetOwner();
if (!attacker)
continue;
ThreatMgr* threatMgr = ref->GetSource();
Unit* attacker = threatMgr->GetOwner();
if (player->IsValidAttackTarget(attacker) &&
player->GetDistance2d(attacker) < sPlayerbotAIConfig.sightDistance)
targets.insert(attacker);
ref = ref->next();
}
}
@ -125,6 +131,7 @@ bool AttackersValue::hasRealThreat(Unit* attacker)
return attacker && attacker->IsInWorld() && attacker->IsAlive() && !attacker->IsPolymorphed() &&
// !attacker->isInRoots() &&
!attacker->IsFriendlyTo(bot);
(attacker->GetThreatMgr().getCurrentVictim() || dynamic_cast<Player*>(attacker));
}
bool AttackersValue::IsPossibleTarget(Unit* attacker, Player* bot, float /*range*/)
@ -234,6 +241,9 @@ bool AttackersValue::IsPossibleTarget(Unit* attacker, Player* bot, float /*range
bool AttackersValue::IsValidTarget(Unit* attacker, Player* bot)
{
return IsPossibleTarget(attacker, bot) && bot->IsWithinLOSInMap(attacker);
// (attacker->GetThreatMgr().getCurrentVictim() || attacker->GetGuidValue(UNIT_FIELD_TARGET) ||
// attacker->GetGUID().IsPlayer() || attacker->GetGUID() ==
// GET_PLAYERBOT_AI(bot)->GetAiObjectContext()->GetValue<ObjectGuid>("pull target")->Get());
}
bool PossibleAddsValue::Calculate()
@ -245,11 +255,13 @@ bool PossibleAddsValue::Calculate()
{
if (find(attackers.begin(), attackers.end(), guid) != attackers.end())
continue;
Unit* add = botAI->GetUnit(guid);
if (!add || !add->IsInWorld() || add->IsDuringRemoveFromWorld())
if (Unit* add = botAI->GetUnit(guid))
{
if (!add->IsInWorld() || add->IsDuringRemoveFromWorld())
continue;
if (!add->GetTarget() && !add->GetThreatMgr().GetLastVictim() && add->IsHostileTo(bot))
if (!add->GetTarget() && !add->GetThreatMgr().getCurrentVictim() && add->IsHostileTo(bot))
{
for (ObjectGuid const attackerGUID : attackers)
{
@ -266,6 +278,7 @@ bool PossibleAddsValue::Calculate()
}
}
}
}
return false;
}

View File

@ -20,7 +20,7 @@ public:
}
public:
void CheckAttacker(Unit* creature, ThreatManager* threatMgr) override
void CheckAttacker(Unit* creature, ThreatMgr* threatMgr) override
{
Player* bot = botAI->GetBot();
if (!botAI->CanCastSpell(spell, creature))

View File

@ -13,7 +13,7 @@ public:
{
}
void CheckAttacker(Unit* attacker, ThreatManager* threatMgr) override
void CheckAttacker(Unit* attacker, ThreatMgr* threatMgr) override
{
if (botAI->HasAura(spell, attacker))
result = attacker;

View File

@ -13,14 +13,16 @@ class FindMaxThreatGapTargetStrategy : public FindTargetStrategy
public:
FindMaxThreatGapTargetStrategy(PlayerbotAI* botAI) : FindTargetStrategy(botAI), minThreat(0) {}
void CheckAttacker(Unit* attacker, ThreatManager* threatMgr) override
void CheckAttacker(Unit* attacker, ThreatMgr* threatMgr) override
{
if (!attacker->IsAlive())
{
return;
}
if (foundHighPriority)
{
return;
}
if (IsHighPriority(attacker))
{
result = attacker;
@ -30,7 +32,7 @@ public:
if (!result || CalcThreatGap(attacker, threatMgr) > CalcThreatGap(result, &result->GetThreatMgr()))
result = attacker;
}
float CalcThreatGap(Unit* attacker, ThreatManager* threatMgr)
float CalcThreatGap(Unit* attacker, ThreatMgr* threatMgr)
{
Unit* victim = attacker->GetVictim();
return threatMgr->GetThreat(victim) - threatMgr->GetThreat(attacker);
@ -50,7 +52,7 @@ public:
result = nullptr;
}
void CheckAttacker(Unit* attacker, ThreatManager* threatMgr) override
void CheckAttacker(Unit* attacker, ThreatMgr* threatMgr) override
{
if (Group* group = botAI->GetBot()->GetGroup())
{
@ -59,11 +61,13 @@ public:
return;
}
if (!attacker->IsAlive())
{
return;
}
if (foundHighPriority)
{
return;
}
if (IsHighPriority(attacker))
{
result = attacker;
@ -86,19 +90,24 @@ public:
int new_level = GetIntervalLevel(new_unit);
int old_level = GetIntervalLevel(old_unit);
if (new_level != old_level)
{
return new_level > old_level;
}
int32_t level = new_level;
if (level % 10 == 2 || level % 10 == 0)
{
return new_time < old_time;
}
// dont switch targets when all of them with low health
Unit* currentTarget = botAI->GetAiObjectContext()->GetValue<Unit*>("current target")->Get();
if (currentTarget == new_unit)
{
return true;
}
if (currentTarget == old_unit)
{
return false;
}
return new_time > old_time;
}
int32_t GetIntervalLevel(Unit* unit)
@ -110,11 +119,13 @@ public:
attackRange += 5.0f;
int level = dis < attackRange ? 10 : 0;
if (time >= 5 && time <= 30)
{
return level + 2;
}
if (time > 30)
{
return level;
}
return level + 1;
}
@ -132,7 +143,7 @@ public:
{
}
void CheckAttacker(Unit* attacker, ThreatManager*) override
void CheckAttacker(Unit* attacker, ThreatMgr*) override
{
if (Group* group = botAI->GetBot()->GetGroup())
{
@ -141,11 +152,13 @@ public:
return;
}
if (!attacker->IsAlive())
{
return;
}
if (foundHighPriority)
{
return;
}
if (IsHighPriority(attacker))
{
result = attacker;
@ -173,8 +186,9 @@ public:
// attack enemy in range and with lowest health
int level = new_level;
if (level == 10)
{
return new_time < old_time;
}
// all targets are far away, choose the closest one
return botAI->GetBot()->GetDistance(new_unit) < botAI->GetBot()->GetDistance(old_unit);
}
@ -202,7 +216,7 @@ public:
{
}
void CheckAttacker(Unit* attacker, ThreatManager*) override
void CheckAttacker(Unit* attacker, ThreatMgr*) override
{
if (Group* group = botAI->GetBot()->GetGroup())
{
@ -211,11 +225,13 @@ public:
return;
}
if (!attacker->IsAlive())
{
return;
}
if (foundHighPriority)
{
return;
}
if (IsHighPriority(attacker))
{
result = attacker;
@ -238,8 +254,9 @@ public:
int new_level = GetIntervalLevel(new_unit);
int old_level = GetIntervalLevel(old_unit);
if (new_level != old_level)
{
return new_level > old_level;
}
// attack enemy in range and with lowest health
int level = new_level;
Player* bot = botAI->GetBot();
@ -247,8 +264,9 @@ public:
{
Unit* combo_unit = bot->GetComboTarget();
if (new_unit == combo_unit)
{
return true;
}
return new_time < old_time;
}
// all targets are far away, choose the closest one
@ -301,7 +319,7 @@ class FindMaxHpTargetStrategy : public FindTargetStrategy
public:
FindMaxHpTargetStrategy(PlayerbotAI* botAI) : FindTargetStrategy(botAI), maxHealth(0) {}
void CheckAttacker(Unit* attacker, ThreatManager*) override
void CheckAttacker(Unit* attacker, ThreatMgr*) override
{
if (Group* group = botAI->GetBot()->GetGroup())
{

View File

@ -5,7 +5,6 @@
#include "EnemyPlayerValue.h"
#include "CombatManager.h"
#include "Playerbots.h"
#include "ServerFacade.h"
#include "Vehicle.h"
@ -52,22 +51,35 @@ Unit* EnemyPlayerValue::Calculate()
controllingVehicle = true;
}
// 1. Check units we are currently in PvP combat with.
// 1. Check units we are currently in combat with.
std::vector<Unit*> targets;
Unit* pVictim = bot->GetVictim();
for (auto const& [guid, combatRef] : bot->GetCombatManager().GetPvPCombatRefs())
HostileReference* pReference = bot->getHostileRefMgr().getFirst();
while (pReference)
{
Unit* pTarget = combatRef->GetOther(bot);
if (!pTarget || pTarget == pVictim || !pTarget->IsPlayer() || !pTarget->CanSeeOrDetect(bot) ||
!bot->IsWithinDist(pTarget, VISIBILITY_DISTANCE_NORMAL))
continue;
if ((bot->GetTeamId() == TEAM_HORDE && Target->HasAura(23333)) ||
(bot->GetTeamId() == TEAM_ALLIANCE && pTarget->HasAura(23335)))
ThreatMgr* threatMgr = pReference->GetSource();
if (Unit* pTarget = threatMgr->GetOwner())
{
if (pTarget != pVictim && pTarget->IsPlayer() && pTarget->CanSeeOrDetect(bot) &&
bot->IsWithinDist(pTarget, VISIBILITY_DISTANCE_NORMAL))
{
if (bot->GetTeamId() == TEAM_HORDE)
{
if (pTarget->HasAura(23333))
return pTarget;
}
else
{
if (pTarget->HasAura(23335))
return pTarget;
}
targets.push_back(pTarget);
}
}
pReference = pReference->next();
}
if (!targets.empty())
{

View File

@ -13,7 +13,7 @@ class FindLeastHpTargetStrategy : public FindNonCcTargetStrategy
public:
FindLeastHpTargetStrategy(PlayerbotAI* botAI) : FindNonCcTargetStrategy(botAI), minHealth(0) {}
void CheckAttacker(Unit* attacker, ThreatManager* threatMgr) override
void CheckAttacker(Unit* attacker, ThreatMgr* threatMgr) override
{
if (IsCcTarget(attacker))
return;

View File

@ -15,11 +15,12 @@ class FindTargetForTankStrategy : public FindNonCcTargetStrategy
public:
FindTargetForTankStrategy(PlayerbotAI* botAI) : FindNonCcTargetStrategy(botAI), minThreat(0) {}
void CheckAttacker(Unit* creature, ThreatManager* threatMgr) override
void CheckAttacker(Unit* creature, ThreatMgr* threatMgr) override
{
if (!creature || !creature->IsAlive())
{
return;
}
Player* bot = botAI->GetBot();
float threat = threatMgr->GetThreat(bot);
if (!result)
@ -28,11 +29,15 @@ public:
result = creature;
}
// neglect if victim is main tank, or no victim (for untauntable target)
if (Unit* victim = threatMgr->GetCurrentVictim())
if (threatMgr->getCurrentVictim())
{
// float max_threat = threatMgr->GetThreat(threatMgr->getCurrentVictim()->getTarget());
Unit* victim = threatMgr->getCurrentVictim()->getTarget();
if (victim && victim->ToPlayer() && botAI->IsMainTank(victim->ToPlayer()))
{
if (victim->ToPlayer() && botAI->IsMainTank(victim->ToPlayer()))
return;
}
}
if (minThreat >= threat)
{
minThreat = threat;
@ -49,7 +54,7 @@ class FindTankTargetSmartStrategy : public FindTargetStrategy
public:
FindTankTargetSmartStrategy(PlayerbotAI* botAI) : FindTargetStrategy(botAI) {}
void CheckAttacker(Unit* attacker, ThreatManager* threatMgr) override
void CheckAttacker(Unit* attacker, ThreatMgr* threatMgr) override
{
if (Group* group = botAI->GetBot()->GetGroup())
{
@ -58,11 +63,14 @@ public:
return;
}
if (!attacker->IsAlive())
{
return;
}
if (!result || IsBetter(attacker, result))
{
result = attacker;
}
}
bool IsBetter(Unit* new_unit, Unit* old_unit)
{
Player* bot = botAI->GetBot();
@ -72,7 +80,6 @@ public:
{
if (old_unit == currentTarget)
return false;
if (new_unit == currentTarget)
return true;
}
@ -82,22 +89,26 @@ public:
float old_dis = bot->GetDistance(old_unit);
// hasAggro? -> withinMelee? -> threat
if (GetIntervalLevel(new_unit) != GetIntervalLevel(old_unit))
{
return GetIntervalLevel(new_unit) > GetIntervalLevel(old_unit);
}
int32_t interval = GetIntervalLevel(new_unit);
if (interval == 2)
{
return new_dis < old_dis;
}
return new_threat < old_threat;
}
int32_t GetIntervalLevel(Unit* unit)
{
if (!botAI->HasAggro(unit))
{
return 2;
}
if (botAI->GetBot()->IsWithinMeleeRange(unit))
{
return 1;
}
return 0;
}
};

View File

@ -5,13 +5,12 @@
#include "TargetValue.h"
#include "CombatManager.h"
#include "LastMovementValue.h"
#include "ObjectGuid.h"
#include "Playerbots.h"
#include "RtiTargetValue.h"
#include "ScriptedCreature.h"
#include "ThreatManager.h"
#include "ThreatMgr.h"
Unit* FindTargetStrategy::GetResult() { return result; }
@ -24,8 +23,8 @@ Unit* TargetValue::FindTarget(FindTargetStrategy* strategy)
if (!unit)
continue;
ThreatManager& threatMgr = unit->GetThreatMgr();
strategy->CheckAttacker(unit, &threatMgr);
ThreatMgr& ThreatMgr = unit->GetThreatMgr();
strategy->CheckAttacker(unit, &ThreatMgr);
}
return strategy->GetResult();
@ -145,23 +144,24 @@ Unit* FindTargetValue::Calculate()
{
return nullptr;
}
for (auto const& [guid, ref] : bot->GetThreatMgr().GetThreatenedByMeList())
HostileReference* ref = bot->getHostileRefMgr().getFirst();
while (ref)
{
Unit* unit = ref->GetOwner();
if (!unit)
continue;
ThreatMgr* threatManager = ref->GetSource();
Unit* unit = threatManager->GetOwner();
std::wstring wnamepart;
Utf8toWStr(unit->GetName(), wnamepart);
wstrToLower(wnamepart);
if (!qualifier.empty() && qualifier.length() == wnamepart.length() && Utf8FitTo(qualifier, wnamepart))
{
return unit;
}
ref = ref->next();
}
return nullptr;
}
void FindBossTargetStrategy::CheckAttacker(Unit* attacker, ThreatManager* threatManager)
void FindBossTargetStrategy::CheckAttacker(Unit* attacker, ThreatMgr* threatManager)
{
UnitAI* unitAI = attacker->GetAI();
BossAI* bossAI = dynamic_cast<BossAI*>(unitAI);

View File

@ -11,7 +11,7 @@
#include "Value.h"
class PlayerbotAI;
class ThreatManager;
class ThreatMgr;
class Unit;
class FindTargetStrategy
@ -20,7 +20,7 @@ public:
FindTargetStrategy(PlayerbotAI* botAI) : result(nullptr), botAI(botAI) {}
Unit* GetResult();
virtual void CheckAttacker(Unit* attacker, ThreatManager* threatMgr) = 0;
virtual void CheckAttacker(Unit* attacker, ThreatMgr* threatMgr) = 0;
void GetPlayerCount(Unit* creature, uint32* tankCount, uint32* dpsCount);
bool IsHighPriority(Unit* attacker);
@ -129,7 +129,7 @@ class FindBossTargetStrategy : public FindTargetStrategy
{
public:
FindBossTargetStrategy(PlayerbotAI* ai) : FindTargetStrategy(ai) {}
virtual void CheckAttacker(Unit* attacker, ThreatManager* threatManager);
virtual void CheckAttacker(Unit* attacker, ThreatMgr* threatManager);
};
class BossTargetValue : public TargetValue, public Qualified

View File

@ -6,7 +6,7 @@
#include "ThreatValues.h"
#include "Playerbots.h"
#include "ThreatManager.h"
#include "ThreatMgr.h"
uint8 ThreatValue::Calculate()
{

View File

@ -15,6 +15,9 @@ public:
{
creators["sanctity aura"] = &sanctity_aura;
creators["retribution aura"] = &retribution_aura;
creators["seal of corruption"] = &seal_of_corruption;
creators["seal of vengeance"] = &seal_of_vengeance;
creators["seal of command"] = &seal_of_command;
creators["blessing of might"] = &blessing_of_might;
creators["crusader strike"] = &crusader_strike;
creators["repentance"] = &repentance;
@ -24,6 +27,36 @@ public:
}
private:
static ActionNode* seal_of_corruption([[maybe_unused]] PlayerbotAI* botAI)
{
return new ActionNode(
"seal of corruption",
/*P*/ {},
/*A*/ { NextAction("seal of vengeance") },
/*C*/ {}
);
}
static ActionNode* seal_of_vengeance([[maybe_unused]] PlayerbotAI* botAI)
{
return new ActionNode(
"seal of vengeance",
/*P*/ {},
/*A*/ { NextAction("seal of command") },
/*C*/ {}
);
}
static ActionNode* seal_of_command([[maybe_unused]] PlayerbotAI* botAI)
{
return new ActionNode(
"seal of command",
/*P*/ {},
/*A*/ { NextAction("seal of righteousness") },
/*C*/ {}
);
}
static ActionNode* blessing_of_might([[maybe_unused]] PlayerbotAI* botAI)
{
return new ActionNode(

View File

@ -22,9 +22,6 @@ public:
creators["cleanse magic"] = &cleanse_magic;
creators["cleanse poison on party"] = &cleanse_poison_on_party;
creators["cleanse disease on party"] = &cleanse_disease_on_party;
creators["seal of corruption"] = &seal_of_corruption;
creators["seal of vengeance"] = &seal_of_vengeance;
creators["seal of command"] = &seal_of_command;
creators["seal of wisdom"] = &seal_of_wisdom;
creators["seal of justice"] = &seal_of_justice;
creators["hand of reckoning"] = &hand_of_reckoning;
@ -44,6 +41,7 @@ public:
creators["blessing of wisdom on party"] = &blessing_of_wisdom_on_party;
creators["blessing of sanctuary on party"] = &blessing_of_sanctuary_on_party;
creators["blessing of sanctuary"] = &blessing_of_sanctuary;
creators["seal of command"] = &seal_of_command;
creators["taunt spell"] = &hand_of_reckoning;
creators["righteous defense"] = &righteous_defense;
creators["avenger's shield"] = &avengers_shield;
@ -157,39 +155,18 @@ private:
/*A*/ { NextAction("purify disease on party") },
/*C*/ {});
}
static ActionNode* seal_of_corruption(PlayerbotAI* /* ai */)
{
return new ActionNode("seal of corruption",
/*P*/ {},
/*A*/ { NextAction("seal of vengeance") },
/*C*/ {});
}
static ActionNode* seal_of_vengeance(PlayerbotAI* /* ai */)
{
return new ActionNode("seal of vengeance",
/*P*/ {},
/*A*/ { NextAction("seal of command") },
/*C*/ {});
}
static ActionNode* seal_of_command(PlayerbotAI* /* ai */)
{
return new ActionNode("seal of command",
/*P*/ {},
/*A*/ { NextAction("seal of righteousness") },
/*C*/ {});
}
static ActionNode* seal_of_wisdom(PlayerbotAI* /* ai */)
{
return new ActionNode ("seal of wisdom",
/*P*/ {},
/*A*/ { NextAction("seal of corruption") },
/*A*/ { NextAction("seal of righteousness") },
/*C*/ {});
}
static ActionNode* seal_of_justice(PlayerbotAI* /* ai */)
{
return new ActionNode("seal of justice",
/*P*/ {},
/*A*/ { NextAction("seal of corruption") },
/*A*/ { NextAction("seal of righteousness") },
/*C*/ {});
}
static ActionNode* hand_of_reckoning(PlayerbotAI* /* ai */)
@ -269,6 +246,13 @@ private:
/*A*/ {},
/*C*/ {});
}
static ActionNode* seal_of_command(PlayerbotAI* /* ai */)
{
return new ActionNode("seal of command",
/*P*/ {},
/*A*/ { NextAction("seal of righteousness") },
/*C*/ {});
}
};
#endif

View File

@ -30,7 +30,7 @@ void HealPaladinStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
new TriggerNode(
"seal",
{
NextAction("seal of wisdom", ACTION_HIGH),
NextAction("seal of wisdom", ACTION_HIGH)
}
)
);