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
# 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)
AiPlayerbot.AutoAvoidAoe = 1
# Tell which spell is avoiding (experimental)
# Default: 1 (enable)
AiPlayerbot.TellWhenAvoidAoe = 1
# Only avoid aoe spells with a radius smaller than this value
AiPlayerbot.MaxAoeAvoidRadius = 15.0
# A whitelist of aoe spell IDs that should not be avoided
AiPlayerbot.AoeAvoidSpellWhitelist = 50759,57491
# Enable healer bot save mana
# Default: 1 (enable)
@@ -1281,6 +1283,10 @@ AiPlayerbot.LogInGroupOnly = 1
AiPlayerbot.LogValuesPerTick = 0
AiPlayerbot.RandomChangeMultiplier = 1
# Tell which spell is avoiding (experimental)
# Default: 0 (disable)
AiPlayerbot.TellWhenAvoidAoe = 0
# Enables/Disables performance monitor
AiPlayerbot.PerfMonEnabled = 0

View File

@@ -1624,10 +1624,10 @@ void PlayerbotAI::ResetStrategies(bool load)
// sPlayerbotDbStore->Load(this);
}
bool PlayerbotAI::IsRanged(Player* player)
bool PlayerbotAI::IsRanged(Player* player, bool bySpec)
{
PlayerbotAI* botAi = GET_PLAYERBOT_AI(player);
if (botAi)
if (!bySpec && botAi)
return botAi->ContainsStrategy(STRATEGY_TYPE_RANGED);
int tab = AiFactory::GetPlayerSpecTab(player);
@@ -1660,18 +1660,18 @@ bool PlayerbotAI::IsRanged(Player* player)
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);
return player->getClass() == CLASS_ROGUE ||
(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)
{
@@ -1894,10 +1894,10 @@ int32 PlayerbotAI::GetMeleeIndex(Player* player)
return 0;
}
bool PlayerbotAI::IsTank(Player* player)
bool PlayerbotAI::IsTank(Player* player, bool bySpec)
{
PlayerbotAI* botAi = GET_PLAYERBOT_AI(player);
if (botAi)
if (!bySpec && botAi)
return botAi->ContainsStrategy(STRATEGY_TYPE_TANK);
int tab = AiFactory::GetPlayerSpecTab(player);
@@ -1932,10 +1932,10 @@ bool PlayerbotAI::IsTank(Player* player)
return false;
}
bool PlayerbotAI::IsHeal(Player* player)
bool PlayerbotAI::IsHeal(Player* player, bool bySpec)
{
PlayerbotAI* botAi = GET_PLAYERBOT_AI(player);
if (botAi)
if (!bySpec && botAi)
return botAi->ContainsStrategy(STRATEGY_TYPE_HEAL);
int tab = AiFactory::GetPlayerSpecTab(player);
@@ -1969,10 +1969,10 @@ bool PlayerbotAI::IsHeal(Player* player)
return false;
}
bool PlayerbotAI::IsDps(Player* player)
bool PlayerbotAI::IsDps(Player* player, bool bySpec)
{
PlayerbotAI* botAi = GET_PLAYERBOT_AI(player);
if (botAi)
if (!bySpec && botAi)
return botAi->ContainsStrategy(STRATEGY_TYPE_DPS);
int tab = AiFactory::GetPlayerSpecTab(player);

View File

@@ -401,14 +401,14 @@ public:
void ResetStrategies(bool load = false);
void ReInitCurrentEngine();
void Reset(bool full = false);
static bool IsTank(Player* player);
static bool IsHeal(Player* player);
static bool IsDps(Player* player);
static bool IsRanged(Player* player);
static bool IsMelee(Player* player);
static bool IsCaster(Player* player);
static bool IsCombo(Player* player);
static bool IsRangedDps(Player* player);
static bool IsTank(Player* player, bool bySpec = false);
static bool IsHeal(Player* player, bool bySpec = false);
static bool IsDps(Player* player, bool bySpec = false);
static bool IsRanged(Player* player, bool bySpec = false);
static bool IsMelee(Player* player, bool bySpec = false);
static bool IsCaster(Player* player, bool bySpec = false);
static bool IsCombo(Player* player, bool bySpec = false);
static bool IsRangedDps(Player* player, bool bySpec = false);
static bool IsMainTank(Player* player);
bool IsAssistTank(Player* player);
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>
void LoadListString(std::string const value, T& list)
{
@@ -98,7 +111,10 @@ bool PlayerbotAIConfig::Initialize()
autoSaveMana = sConfigMgr->GetOption<bool>("AiPlayerbot.AutoSaveMana", true);
saveManaThreshold = sConfigMgr->GetOption<int32>("AiPlayerbot.SaveManaThreshold", 60);
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);
randomGearQualityLimit = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomGearQualityLimit", 3);
@@ -792,7 +808,8 @@ std::vector<std::vector<uint32>> PlayerbotAIConfig::ParseTempPetTalentsOrder(uin
if (!((1 << spec) & talentTabInfo->petTalentMask))
continue;
// 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;
spells.push_back(talentInfo);

View File

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

View File

@@ -1867,6 +1867,7 @@ void RandomPlayerbotMgr::GetBots()
PlayerbotsDatabase.GetPreparedStatement(PLAYERBOTS_SEL_RANDOM_BOTS_BY_OWNER_AND_EVENT);
stmt->SetData(0, 0);
stmt->SetData(1, "add");
uint32 maxAllowedBotCount = GetEventValue(0, "bot_count");
if (PreparedQueryResult result = PlayerbotsDatabase.Query(stmt))
{
do
@@ -1875,6 +1876,9 @@ void RandomPlayerbotMgr::GetBots()
uint32 bot = fields[0].Get<uint32>();
if (GetEventValue(bot, "add"))
currentBots.push_back(bot);
if (currentBots.size() >= maxAllowedBotCount)
break;
} while (result->NextRow());
}
}
@@ -2403,51 +2407,12 @@ void RandomPlayerbotMgr::PrintStats()
else
++engine_dead;
uint8 spec = AiFactory::GetPlayerSpecTab(bot);
switch (bot->getClass())
{
case CLASS_DRUID:
if (spec == 2)
++heal;
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 (botAI->IsHeal(bot, true))
++heal;
else if (botAI->IsTank(bot, true))
++tank;
else
++dps;
if (TravelTarget* target = botAI->GetAiObjectContext()->GetValue<TravelTarget*>("travel target")->Get())
{

View File

@@ -1819,12 +1819,17 @@ bool AvoidAoeAction::AvoidAuraWithDynamicObj()
{
return false;
}
if (sPlayerbotAIConfig->aoeAvoidSpellWhitelist.find(spellInfo->Id) != sPlayerbotAIConfig->aoeAvoidSpellWhitelist.end())
return false;
DynamicObject* dynOwner = aura->GetDynobjOwner();
if (!dynOwner || !dynOwner->IsInWorld())
{
return false;
}
float radius = dynOwner->GetRadius();
if (!radius || radius > sPlayerbotAIConfig->maxAoeAvoidRadius)
return false;
if (bot->GetDistance(dynOwner) > radius)
{
return false;
@@ -1838,7 +1843,7 @@ bool AvoidAoeAction::AvoidAuraWithDynamicObj()
lastTellTimer = time(NULL);
lastMoveTimer = getMSTime();
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);
}
return true;
@@ -1869,17 +1874,28 @@ bool AvoidAoeAction::AvoidGameObjectWithDamage()
{
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;
if (!spellId)
{
continue;
}
if (sPlayerbotAIConfig->aoeAvoidSpellWhitelist.find(spellId) != sPlayerbotAIConfig->aoeAvoidSpellWhitelist.end())
continue;
const SpellInfo* spellInfo = sSpellMgr->GetSpellInfo(spellId);
if (!spellInfo || spellInfo->IsPositive())
{
continue;
}
float radius = (float)goInfo->trap.diameter / 2;
if (!radius || radius > sPlayerbotAIConfig->maxAoeAvoidRadius)
continue;
// for (int i = 0; i < MAX_SPELL_EFFECTS; i++) {
// if (spellInfo->Effects[i].Effect == SPELL_EFFECT_APPLY_AURA) {
// if (spellInfo->Effects[i].ApplyAuraName == SPELL_AURA_PERIODIC_DAMAGE) {
@@ -1903,7 +1919,7 @@ bool AvoidAoeAction::AvoidGameObjectWithDamage()
lastTellTimer = time(NULL);
lastMoveTimer = getMSTime();
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);
}
return true;
@@ -1946,6 +1962,8 @@ bool AvoidAoeAction::AvoidUnitWithDamageAura()
sSpellMgr->GetSpellInfo(spellInfo->Effects[aurEff->GetEffIndex()].TriggerSpell);
if (!triggerSpellInfo)
continue;
if (sPlayerbotAIConfig->aoeAvoidSpellWhitelist.find(triggerSpellInfo->Id) != sPlayerbotAIConfig->aoeAvoidSpellWhitelist.end())
return false;
for (int j = 0; j < MAX_SPELL_EFFECTS; j++)
{
if (triggerSpellInfo->Effects[j].Effect == SPELL_EFFECT_SCHOOL_DAMAGE)
@@ -1955,6 +1973,8 @@ bool AvoidAoeAction::AvoidUnitWithDamageAura()
{
break;
}
if (!radius || radius > sPlayerbotAIConfig->maxAoeAvoidRadius)
continue;
std::ostringstream name;
name << triggerSpellInfo->SpellName[LOCALE_enUS]; //<< "] (unit)";
if (FleePosition(unit->GetPosition(), radius))
@@ -1964,7 +1984,7 @@ bool AvoidAoeAction::AvoidUnitWithDamageAura()
lastTellTimer = time(NULL);
lastMoveTimer = getMSTime();
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);
}
}

View File

@@ -64,6 +64,7 @@ public:
this->prev_phase = 0;
this->prev_erupt = 0;
this->prev_timer = 0;
ResetSafe();
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(2762.30f, -3684.59f));

View File

@@ -145,6 +145,9 @@ Aura* AreaDebuffValue::Calculate()
{
continue;
}
// float radius = dynOwner->GetRadius();
// if (radius > 12.0f)
// continue;
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)));
triggers.push_back(new TriggerNode(
"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(
new TriggerNode("bloodrage", NextAction::array(0, new NextAction("bloodrage", ACTION_HIGH + 2), nullptr)));
triggers.push_back(
@@ -76,5 +79,5 @@ void ArmsWarriorStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
triggers.push_back(new TriggerNode(
"critical health", NextAction::array(0, new NextAction("intimidating shout", ACTION_EMERGENCY), nullptr)));
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)));
}