Avoid aoe max radius and whitelist

This commit is contained in:
Yunfan Li
2024-09-08 12:53:08 +08:00
parent 00268ac19d
commit 4de02481be
10 changed files with 96 additions and 79 deletions

View File

@@ -357,7 +357,7 @@ AiPlayerbot.HighMana = 65
# #
# #
# Bots pick their quest reward (yes = picks first useful item, no = list all rewards, ask = pick useful item and lists if multiple) # Bots pick their quest reward (yes = picks the most useful item, no = list all rewards, ask = pick useful item and lists if multiple)
AiPlayerbot.AutoPickReward = yes AiPlayerbot.AutoPickReward = yes
# Sync quests with player (Bots will complete quests the moment you hand them in. Bots will ignore looting quest items.) # Sync quests with player (Bots will complete quests the moment you hand them in. Bots will ignore looting quest items.)
@@ -385,9 +385,11 @@ AiPlayerbot.ApplyInstanceStrategies = 1
# Default: 1 (enable) # Default: 1 (enable)
AiPlayerbot.AutoAvoidAoe = 1 AiPlayerbot.AutoAvoidAoe = 1
# Tell which spell is avoiding (experimental) # Only avoid aoe spells with a radius smaller than this value
# Default: 1 (enable) AiPlayerbot.MaxAoeAvoidRadius = 15.0
AiPlayerbot.TellWhenAvoidAoe = 1
# A whitelist of aoe spell IDs that should not be avoided
AiPlayerbot.AoeAvoidSpellWhitelist = 50759,57491
# Enable healer bot save mana # Enable healer bot save mana
# Default: 1 (enable) # Default: 1 (enable)
@@ -1281,6 +1283,10 @@ AiPlayerbot.LogInGroupOnly = 1
AiPlayerbot.LogValuesPerTick = 0 AiPlayerbot.LogValuesPerTick = 0
AiPlayerbot.RandomChangeMultiplier = 1 AiPlayerbot.RandomChangeMultiplier = 1
# Tell which spell is avoiding (experimental)
# Default: 0 (disable)
AiPlayerbot.TellWhenAvoidAoe = 0
# Enables/Disables performance monitor # Enables/Disables performance monitor
AiPlayerbot.PerfMonEnabled = 0 AiPlayerbot.PerfMonEnabled = 0

View File

@@ -1624,10 +1624,10 @@ void PlayerbotAI::ResetStrategies(bool load)
// sPlayerbotDbStore->Load(this); // sPlayerbotDbStore->Load(this);
} }
bool PlayerbotAI::IsRanged(Player* player) bool PlayerbotAI::IsRanged(Player* player, bool bySpec)
{ {
PlayerbotAI* botAi = GET_PLAYERBOT_AI(player); PlayerbotAI* botAi = GET_PLAYERBOT_AI(player);
if (botAi) if (!bySpec && botAi)
return botAi->ContainsStrategy(STRATEGY_TYPE_RANGED); return botAi->ContainsStrategy(STRATEGY_TYPE_RANGED);
int tab = AiFactory::GetPlayerSpecTab(player); int tab = AiFactory::GetPlayerSpecTab(player);
@@ -1660,18 +1660,18 @@ bool PlayerbotAI::IsRanged(Player* player)
return true; return true;
} }
bool PlayerbotAI::IsMelee(Player* player) { return !IsRanged(player); } bool PlayerbotAI::IsMelee(Player* player, bool bySpec) { return !IsRanged(player, bySpec); }
bool PlayerbotAI::IsCaster(Player* player) { return IsRanged(player) && player->getClass() != CLASS_HUNTER; } bool PlayerbotAI::IsCaster(Player* player, bool bySpec) { return IsRanged(player, bySpec) && player->getClass() != CLASS_HUNTER; }
bool PlayerbotAI::IsCombo(Player* player) bool PlayerbotAI::IsCombo(Player* player, bool bySpec)
{ {
// int tab = AiFactory::GetPlayerSpecTab(player); // int tab = AiFactory::GetPlayerSpecTab(player);
return player->getClass() == CLASS_ROGUE || return player->getClass() == CLASS_ROGUE ||
(player->getClass() == CLASS_DRUID && player->HasAura(768)); // cat druid (player->getClass() == CLASS_DRUID && player->HasAura(768)); // cat druid
} }
bool PlayerbotAI::IsRangedDps(Player* player) { return IsRanged(player) && IsDps(player); } bool PlayerbotAI::IsRangedDps(Player* player, bool bySpec) { return IsRanged(player, bySpec) && IsDps(player, bySpec); }
bool PlayerbotAI::IsHealAssistantOfIndex(Player* player, int index) bool PlayerbotAI::IsHealAssistantOfIndex(Player* player, int index)
{ {
@@ -1894,10 +1894,10 @@ int32 PlayerbotAI::GetMeleeIndex(Player* player)
return 0; return 0;
} }
bool PlayerbotAI::IsTank(Player* player) bool PlayerbotAI::IsTank(Player* player, bool bySpec)
{ {
PlayerbotAI* botAi = GET_PLAYERBOT_AI(player); PlayerbotAI* botAi = GET_PLAYERBOT_AI(player);
if (botAi) if (!bySpec && botAi)
return botAi->ContainsStrategy(STRATEGY_TYPE_TANK); return botAi->ContainsStrategy(STRATEGY_TYPE_TANK);
int tab = AiFactory::GetPlayerSpecTab(player); int tab = AiFactory::GetPlayerSpecTab(player);
@@ -1932,10 +1932,10 @@ bool PlayerbotAI::IsTank(Player* player)
return false; return false;
} }
bool PlayerbotAI::IsHeal(Player* player) bool PlayerbotAI::IsHeal(Player* player, bool bySpec)
{ {
PlayerbotAI* botAi = GET_PLAYERBOT_AI(player); PlayerbotAI* botAi = GET_PLAYERBOT_AI(player);
if (botAi) if (!bySpec && botAi)
return botAi->ContainsStrategy(STRATEGY_TYPE_HEAL); return botAi->ContainsStrategy(STRATEGY_TYPE_HEAL);
int tab = AiFactory::GetPlayerSpecTab(player); int tab = AiFactory::GetPlayerSpecTab(player);
@@ -1969,10 +1969,10 @@ bool PlayerbotAI::IsHeal(Player* player)
return false; return false;
} }
bool PlayerbotAI::IsDps(Player* player) bool PlayerbotAI::IsDps(Player* player, bool bySpec)
{ {
PlayerbotAI* botAi = GET_PLAYERBOT_AI(player); PlayerbotAI* botAi = GET_PLAYERBOT_AI(player);
if (botAi) if (!bySpec && botAi)
return botAi->ContainsStrategy(STRATEGY_TYPE_DPS); return botAi->ContainsStrategy(STRATEGY_TYPE_DPS);
int tab = AiFactory::GetPlayerSpecTab(player); int tab = AiFactory::GetPlayerSpecTab(player);

View File

@@ -401,14 +401,14 @@ public:
void ResetStrategies(bool load = false); void ResetStrategies(bool load = false);
void ReInitCurrentEngine(); void ReInitCurrentEngine();
void Reset(bool full = false); void Reset(bool full = false);
static bool IsTank(Player* player); static bool IsTank(Player* player, bool bySpec = false);
static bool IsHeal(Player* player); static bool IsHeal(Player* player, bool bySpec = false);
static bool IsDps(Player* player); static bool IsDps(Player* player, bool bySpec = false);
static bool IsRanged(Player* player); static bool IsRanged(Player* player, bool bySpec = false);
static bool IsMelee(Player* player); static bool IsMelee(Player* player, bool bySpec = false);
static bool IsCaster(Player* player); static bool IsCaster(Player* player, bool bySpec = false);
static bool IsCombo(Player* player); static bool IsCombo(Player* player, bool bySpec = false);
static bool IsRangedDps(Player* player); static bool IsRangedDps(Player* player, bool bySpec = false);
static bool IsMainTank(Player* player); static bool IsMainTank(Player* player);
bool IsAssistTank(Player* player); bool IsAssistTank(Player* player);
bool IsAssistTankOfIndex(Player* player, int index); bool IsAssistTankOfIndex(Player* player, int index);

View File

@@ -29,6 +29,19 @@ void LoadList(std::string const value, T& list)
} }
} }
template <class T>
void LoadSet(std::string const value, T& set)
{
std::vector<std::string> ids = split(value, ',');
for (std::vector<std::string>::iterator i = ids.begin(); i != ids.end(); i++)
{
uint32 id = atoi((*i).c_str());
// if (!id)
// continue;
set.insert(id);
}
}
template <class T> template <class T>
void LoadListString(std::string const value, T& list) void LoadListString(std::string const value, T& list)
{ {
@@ -98,7 +111,10 @@ bool PlayerbotAIConfig::Initialize()
autoSaveMana = sConfigMgr->GetOption<bool>("AiPlayerbot.AutoSaveMana", true); autoSaveMana = sConfigMgr->GetOption<bool>("AiPlayerbot.AutoSaveMana", true);
saveManaThreshold = sConfigMgr->GetOption<int32>("AiPlayerbot.SaveManaThreshold", 60); saveManaThreshold = sConfigMgr->GetOption<int32>("AiPlayerbot.SaveManaThreshold", 60);
autoAvoidAoe = sConfigMgr->GetOption<bool>("AiPlayerbot.AutoAvoidAoe", true); autoAvoidAoe = sConfigMgr->GetOption<bool>("AiPlayerbot.AutoAvoidAoe", true);
tellWhenAvoidAoe = sConfigMgr->GetOption<bool>("AiPlayerbot.TellWhenAvoidAoe", true); maxAoeAvoidRadius = sConfigMgr->GetOption<float>("AiPlayerbot.MaxAoeAvoidRadius", 15.0f);
LoadSet<std::set<uint32>>(sConfigMgr->GetOption<std::string>("AiPlayerbot.AoeAvoidSpellWhitelist", "50759,57491"),
aoeAvoidSpellWhitelist);
tellWhenAvoidAoe = sConfigMgr->GetOption<bool>("AiPlayerbot.TellWhenAvoidAoe", false);
randomGearLoweringChance = sConfigMgr->GetOption<float>("AiPlayerbot.RandomGearLoweringChance", 0.0f); randomGearLoweringChance = sConfigMgr->GetOption<float>("AiPlayerbot.RandomGearLoweringChance", 0.0f);
randomGearQualityLimit = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomGearQualityLimit", 3); randomGearQualityLimit = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomGearQualityLimit", 3);
@@ -792,9 +808,10 @@ std::vector<std::vector<uint32>> PlayerbotAIConfig::ParseTempPetTalentsOrder(uin
if (!((1 << spec) & talentTabInfo->petTalentMask)) if (!((1 << spec) & talentTabInfo->petTalentMask))
continue; continue;
// skip some duplicate spells like dash/dive // skip some duplicate spells like dash/dive
if (talentInfo->TalentID == 2201 || talentInfo->TalentID == 2208 || talentInfo->TalentID == 2219 || talentInfo->TalentID == 2203) if (talentInfo->TalentID == 2201 || talentInfo->TalentID == 2208 || talentInfo->TalentID == 2219 ||
talentInfo->TalentID == 2203)
continue; continue;
spells.push_back(talentInfo); spells.push_back(talentInfo);
} }
std::sort(spells.begin(), spells.end(), std::sort(spells.begin(), spells.end(),

View File

@@ -67,6 +67,8 @@ public:
bool autoSaveMana; bool autoSaveMana;
uint32 saveManaThreshold; uint32 saveManaThreshold;
bool autoAvoidAoe; bool autoAvoidAoe;
float maxAoeAvoidRadius;
std::set<uint32> aoeAvoidSpellWhitelist;
bool tellWhenAvoidAoe; bool tellWhenAvoidAoe;
uint32 openGoSpell; uint32 openGoSpell;

View File

@@ -1867,6 +1867,7 @@ void RandomPlayerbotMgr::GetBots()
PlayerbotsDatabase.GetPreparedStatement(PLAYERBOTS_SEL_RANDOM_BOTS_BY_OWNER_AND_EVENT); PlayerbotsDatabase.GetPreparedStatement(PLAYERBOTS_SEL_RANDOM_BOTS_BY_OWNER_AND_EVENT);
stmt->SetData(0, 0); stmt->SetData(0, 0);
stmt->SetData(1, "add"); stmt->SetData(1, "add");
uint32 maxAllowedBotCount = GetEventValue(0, "bot_count");
if (PreparedQueryResult result = PlayerbotsDatabase.Query(stmt)) if (PreparedQueryResult result = PlayerbotsDatabase.Query(stmt))
{ {
do do
@@ -1875,6 +1876,9 @@ void RandomPlayerbotMgr::GetBots()
uint32 bot = fields[0].Get<uint32>(); uint32 bot = fields[0].Get<uint32>();
if (GetEventValue(bot, "add")) if (GetEventValue(bot, "add"))
currentBots.push_back(bot); currentBots.push_back(bot);
if (currentBots.size() >= maxAllowedBotCount)
break;
} while (result->NextRow()); } while (result->NextRow());
} }
} }
@@ -2402,53 +2406,14 @@ void RandomPlayerbotMgr::PrintStats()
++engine_combat; ++engine_combat;
else else
++engine_dead; ++engine_dead;
uint8 spec = AiFactory::GetPlayerSpecTab(bot); if (botAI->IsHeal(bot, true))
switch (bot->getClass()) ++heal;
{ else if (botAI->IsTank(bot, true))
case CLASS_DRUID: ++tank;
if (spec == 2) else
++heal; ++dps;
else
++dps;
break;
case CLASS_PALADIN:
if (spec == 1)
++tank;
else if (spec == 0)
++heal;
else
++dps;
break;
case CLASS_PRIEST:
if (spec != 2)
++heal;
else
++dps;
break;
case CLASS_SHAMAN:
if (spec == 2)
++heal;
else
++dps;
break;
case CLASS_WARRIOR:
if (spec == 2)
++tank;
else
++dps;
break;
case CLASS_DEATH_KNIGHT:
if (spec == 0)
tank++;
else
dps++;
break;
default:
++dps;
break;
}
if (TravelTarget* target = botAI->GetAiObjectContext()->GetValue<TravelTarget*>("travel target")->Get()) if (TravelTarget* target = botAI->GetAiObjectContext()->GetValue<TravelTarget*>("travel target")->Get())
{ {
TravelState state = target->getTravelState(); TravelState state = target->getTravelState();

View File

@@ -1819,12 +1819,17 @@ bool AvoidAoeAction::AvoidAuraWithDynamicObj()
{ {
return false; return false;
} }
if (sPlayerbotAIConfig->aoeAvoidSpellWhitelist.find(spellInfo->Id) != sPlayerbotAIConfig->aoeAvoidSpellWhitelist.end())
return false;
DynamicObject* dynOwner = aura->GetDynobjOwner(); DynamicObject* dynOwner = aura->GetDynobjOwner();
if (!dynOwner || !dynOwner->IsInWorld()) if (!dynOwner || !dynOwner->IsInWorld())
{ {
return false; return false;
} }
float radius = dynOwner->GetRadius(); float radius = dynOwner->GetRadius();
if (!radius || radius > sPlayerbotAIConfig->maxAoeAvoidRadius)
return false;
if (bot->GetDistance(dynOwner) > radius) if (bot->GetDistance(dynOwner) > radius)
{ {
return false; return false;
@@ -1838,7 +1843,7 @@ bool AvoidAoeAction::AvoidAuraWithDynamicObj()
lastTellTimer = time(NULL); lastTellTimer = time(NULL);
lastMoveTimer = getMSTime(); lastMoveTimer = getMSTime();
std::ostringstream out; std::ostringstream out;
out << "I'm avoiding " << name.str() << "..."; out << "I'm avoiding " << name.str() << " (" << spellInfo->Id << ")" << " Radius " << radius << " - [Aura]";
bot->Say(out.str(), LANG_UNIVERSAL); bot->Say(out.str(), LANG_UNIVERSAL);
} }
return true; return true;
@@ -1869,17 +1874,28 @@ bool AvoidAoeAction::AvoidGameObjectWithDamage()
{ {
continue; continue;
} }
// 0 trap with no despawn after cast. 1 trap despawns after cast. 2 bomb casts on spawn.
if (goInfo->trap.type != 0)
continue;
uint32 spellId = goInfo->trap.spellId; uint32 spellId = goInfo->trap.spellId;
if (!spellId) if (!spellId)
{ {
continue; continue;
} }
if (sPlayerbotAIConfig->aoeAvoidSpellWhitelist.find(spellId) != sPlayerbotAIConfig->aoeAvoidSpellWhitelist.end())
continue;
const SpellInfo* spellInfo = sSpellMgr->GetSpellInfo(spellId); const SpellInfo* spellInfo = sSpellMgr->GetSpellInfo(spellId);
if (!spellInfo || spellInfo->IsPositive()) if (!spellInfo || spellInfo->IsPositive())
{ {
continue; continue;
} }
float radius = (float)goInfo->trap.diameter / 2; float radius = (float)goInfo->trap.diameter / 2;
if (!radius || radius > sPlayerbotAIConfig->maxAoeAvoidRadius)
continue;
// for (int i = 0; i < MAX_SPELL_EFFECTS; i++) { // for (int i = 0; i < MAX_SPELL_EFFECTS; i++) {
// if (spellInfo->Effects[i].Effect == SPELL_EFFECT_APPLY_AURA) { // if (spellInfo->Effects[i].Effect == SPELL_EFFECT_APPLY_AURA) {
// if (spellInfo->Effects[i].ApplyAuraName == SPELL_AURA_PERIODIC_DAMAGE) { // if (spellInfo->Effects[i].ApplyAuraName == SPELL_AURA_PERIODIC_DAMAGE) {
@@ -1903,7 +1919,7 @@ bool AvoidAoeAction::AvoidGameObjectWithDamage()
lastTellTimer = time(NULL); lastTellTimer = time(NULL);
lastMoveTimer = getMSTime(); lastMoveTimer = getMSTime();
std::ostringstream out; std::ostringstream out;
out << "I'm avoiding " << name.str() << "..."; out << "I'm avoiding " << name.str() << " (" << spellInfo->Id << ")" << " Radius " << radius << " - [Trap]";
bot->Say(out.str(), LANG_UNIVERSAL); bot->Say(out.str(), LANG_UNIVERSAL);
} }
return true; return true;
@@ -1946,6 +1962,8 @@ bool AvoidAoeAction::AvoidUnitWithDamageAura()
sSpellMgr->GetSpellInfo(spellInfo->Effects[aurEff->GetEffIndex()].TriggerSpell); sSpellMgr->GetSpellInfo(spellInfo->Effects[aurEff->GetEffIndex()].TriggerSpell);
if (!triggerSpellInfo) if (!triggerSpellInfo)
continue; continue;
if (sPlayerbotAIConfig->aoeAvoidSpellWhitelist.find(triggerSpellInfo->Id) != sPlayerbotAIConfig->aoeAvoidSpellWhitelist.end())
return false;
for (int j = 0; j < MAX_SPELL_EFFECTS; j++) for (int j = 0; j < MAX_SPELL_EFFECTS; j++)
{ {
if (triggerSpellInfo->Effects[j].Effect == SPELL_EFFECT_SCHOOL_DAMAGE) if (triggerSpellInfo->Effects[j].Effect == SPELL_EFFECT_SCHOOL_DAMAGE)
@@ -1955,6 +1973,8 @@ bool AvoidAoeAction::AvoidUnitWithDamageAura()
{ {
break; break;
} }
if (!radius || radius > sPlayerbotAIConfig->maxAoeAvoidRadius)
continue;
std::ostringstream name; std::ostringstream name;
name << triggerSpellInfo->SpellName[LOCALE_enUS]; //<< "] (unit)"; name << triggerSpellInfo->SpellName[LOCALE_enUS]; //<< "] (unit)";
if (FleePosition(unit->GetPosition(), radius)) if (FleePosition(unit->GetPosition(), radius))
@@ -1964,7 +1984,7 @@ bool AvoidAoeAction::AvoidUnitWithDamageAura()
lastTellTimer = time(NULL); lastTellTimer = time(NULL);
lastMoveTimer = getMSTime(); lastMoveTimer = getMSTime();
std::ostringstream out; std::ostringstream out;
out << "I'm avoiding " << name.str() << "..."; out << "I'm avoiding " << name.str() << " (" << triggerSpellInfo->Id << ")" << " Radius " << radius << " - [Unit Trigger]";
bot->Say(out.str(), LANG_UNIVERSAL); bot->Say(out.str(), LANG_UNIVERSAL);
} }
} }

View File

@@ -64,6 +64,7 @@ public:
this->prev_phase = 0; this->prev_phase = 0;
this->prev_erupt = 0; this->prev_erupt = 0;
this->prev_timer = 0; this->prev_timer = 0;
ResetSafe();
waypoints.push_back(std::make_pair(2793.58f, -3665.93f)); waypoints.push_back(std::make_pair(2793.58f, -3665.93f));
waypoints.push_back(std::make_pair(2775.49f, -3674.43f)); waypoints.push_back(std::make_pair(2775.49f, -3674.43f));
waypoints.push_back(std::make_pair(2762.30f, -3684.59f)); waypoints.push_back(std::make_pair(2762.30f, -3684.59f));

View File

@@ -145,6 +145,9 @@ Aura* AreaDebuffValue::Calculate()
{ {
continue; continue;
} }
// float radius = dynOwner->GetRadius();
// if (radius > 12.0f)
// continue;
return aura; return aura;
} }
} }

View File

@@ -65,7 +65,10 @@ void ArmsWarriorStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
"victory rush", NextAction::array(0, new NextAction("victory rush", ACTION_INTERRUPT), nullptr))); "victory rush", NextAction::array(0, new NextAction("victory rush", ACTION_INTERRUPT), nullptr)));
triggers.push_back(new TriggerNode( triggers.push_back(new TriggerNode(
"high rage available", NextAction::array(0, new NextAction("heroic strike", ACTION_HIGH + 10), nullptr))); "high rage available", NextAction::array(0, new NextAction("heroic strike", ACTION_HIGH + 10), nullptr)));
triggers.push_back(new TriggerNode("medium rage available", NextAction::array(0, new NextAction("slam", ACTION_HIGH + 1), nullptr))); triggers.push_back(new TriggerNode("medium rage available",
NextAction::array(0, new NextAction("slam", ACTION_HIGH + 1),
new NextAction("thunder clap", ACTION_HIGH),
nullptr)));
triggers.push_back( triggers.push_back(
new TriggerNode("bloodrage", NextAction::array(0, new NextAction("bloodrage", ACTION_HIGH + 2), nullptr))); new TriggerNode("bloodrage", NextAction::array(0, new NextAction("bloodrage", ACTION_HIGH + 2), nullptr)));
triggers.push_back( triggers.push_back(
@@ -76,5 +79,5 @@ void ArmsWarriorStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
triggers.push_back(new TriggerNode( triggers.push_back(new TriggerNode(
"critical health", NextAction::array(0, new NextAction("intimidating shout", ACTION_EMERGENCY), nullptr))); "critical health", NextAction::array(0, new NextAction("intimidating shout", ACTION_EMERGENCY), nullptr)));
triggers.push_back(new TriggerNode("medium aoe", triggers.push_back(new TriggerNode("medium aoe",
NextAction::array(0, new NextAction("thunder clap", ACTION_HIGH + 1), nullptr))); NextAction::array(0, new NextAction("thunder clap", ACTION_HIGH + 2), nullptr)));
} }