Merge remote-tracking branch 'upstream/master' into karazhan

This commit is contained in:
crow
2025-09-28 17:06:55 -05:00
17 changed files with 50 additions and 46 deletions

View File

@@ -159,6 +159,9 @@ AiPlayerbot.RandomBotGuildNearby = 0
# Number of guilds created by randombots # Number of guilds created by randombots
AiPlayerbot.RandomBotGuildCount = 20 AiPlayerbot.RandomBotGuildCount = 20
# Maximum number of members in randombot guilds (minimum is hardcoded to 10)
AiPlayerbot.RandomBotGuildSizeMax = 15
# Delete all randombot guilds if set to 1 # Delete all randombot guilds if set to 1
AiPlayerbot.DeleteRandomBotGuilds = 0 AiPlayerbot.DeleteRandomBotGuilds = 0

View File

@@ -295,7 +295,7 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa
{ {
engine->addStrategiesNoInit("dps", "shadow debuff", "shadow aoe", nullptr); engine->addStrategiesNoInit("dps", "shadow debuff", "shadow aoe", nullptr);
} }
else if (tab == PRIEST_TAB_DISIPLINE) else if (tab == PRIEST_TAB_DISCIPLINE)
{ {
engine->addStrategiesNoInit("heal", nullptr); engine->addStrategiesNoInit("heal", nullptr);
} }
@@ -607,7 +607,7 @@ void AiFactory::AddDefaultNonCombatStrategies(Player* player, PlayerbotAI* const
nonCombatEngine->addStrategy("dps assist", false); nonCombatEngine->addStrategy("dps assist", false);
break; break;
case CLASS_WARLOCK: case CLASS_WARLOCK:
if (tab == WARLOCK_TAB_AFFLICATION) if (tab == WARLOCK_TAB_AFFLICTION)
{ {
nonCombatEngine->addStrategiesNoInit("felhunter", "spellstone", nullptr); nonCombatEngine->addStrategiesNoInit("felhunter", "spellstone", nullptr);
} }

View File

@@ -2088,7 +2088,7 @@ bool PlayerbotAI::IsHeal(Player* player, bool bySpec)
switch (player->getClass()) switch (player->getClass())
{ {
case CLASS_PRIEST: case CLASS_PRIEST:
if (tab == PRIEST_TAB_DISIPLINE || tab == PRIEST_TAB_HOLY) if (tab == PRIEST_TAB_DISCIPLINE || tab == PRIEST_TAB_HOLY)
{ {
return true; return true;
} }

View File

@@ -276,7 +276,7 @@ enum BotRoles : uint8
enum HUNTER_TABS enum HUNTER_TABS
{ {
HUNTER_TAB_BEASTMASTER, HUNTER_TAB_BEASTMASTERY,
HUNTER_TAB_MARKSMANSHIP, HUNTER_TAB_MARKSMANSHIP,
HUNTER_TAB_SURVIVAL, HUNTER_TAB_SURVIVAL,
}; };
@@ -285,12 +285,12 @@ enum ROGUE_TABS
{ {
ROGUE_TAB_ASSASSINATION, ROGUE_TAB_ASSASSINATION,
ROGUE_TAB_COMBAT, ROGUE_TAB_COMBAT,
ROGUE_TAB_SUBTLETY ROGUE_TAB_SUBTLETY,
}; };
enum PRIEST_TABS enum PRIEST_TABS
{ {
PRIEST_TAB_DISIPLINE, PRIEST_TAB_DISCIPLINE,
PRIEST_TAB_HOLY, PRIEST_TAB_HOLY,
PRIEST_TAB_SHADOW, PRIEST_TAB_SHADOW,
}; };
@@ -332,7 +332,7 @@ enum PALADIN_TABS
enum WARLOCK_TABS enum WARLOCK_TABS
{ {
WARLOCK_TAB_AFFLICATION, WARLOCK_TAB_AFFLICTION,
WARLOCK_TAB_DEMONOLOGY, WARLOCK_TAB_DEMONOLOGY,
WARLOCK_TAB_DESTRUCTION, WARLOCK_TAB_DESTRUCTION,
}; };

View File

@@ -509,6 +509,7 @@ bool PlayerbotAIConfig::Initialize()
randomBotAccountCount = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotAccountCount", 0); randomBotAccountCount = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotAccountCount", 0);
deleteRandomBotAccounts = sConfigMgr->GetOption<bool>("AiPlayerbot.DeleteRandomBotAccounts", false); deleteRandomBotAccounts = sConfigMgr->GetOption<bool>("AiPlayerbot.DeleteRandomBotAccounts", false);
randomBotGuildCount = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotGuildCount", 20); randomBotGuildCount = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotGuildCount", 20);
randomBotGuildSizeMax = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotGuildSizeMax", 15);
deleteRandomBotGuilds = sConfigMgr->GetOption<bool>("AiPlayerbot.DeleteRandomBotGuilds", false); deleteRandomBotGuilds = sConfigMgr->GetOption<bool>("AiPlayerbot.DeleteRandomBotGuilds", false);
guildTaskEnabled = sConfigMgr->GetOption<bool>("AiPlayerbot.EnableGuildTasks", true); guildTaskEnabled = sConfigMgr->GetOption<bool>("AiPlayerbot.EnableGuildTasks", true);

View File

@@ -267,7 +267,7 @@ public:
uint32 randomBotAccountCount; uint32 randomBotAccountCount;
bool randomBotRandomPassword; bool randomBotRandomPassword;
bool deleteRandomBotAccounts; bool deleteRandomBotAccounts;
uint32 randomBotGuildCount; uint32 randomBotGuildCount, randomBotGuildSizeMax;
bool deleteRandomBotGuilds; bool deleteRandomBotGuilds;
std::vector<uint32> randomBotGuilds; std::vector<uint32> randomBotGuilds;
std::vector<uint32> pvpProhibitedZoneIds; std::vector<uint32> pvpProhibitedZoneIds;

View File

@@ -101,6 +101,22 @@ std::string PlayerbotTextMgr::GetBotText(std::string name, std::map<std::string,
return botText; return botText;
} }
std::string PlayerbotTextMgr::GetBotTextOrDefault(std::string name, std::string defaultText,
std::map<std::string, std::string> placeholders)
{
std::string botText = GetBotText(name, placeholders);
if (botText.empty())
{
for (std::map<std::string, std::string>::iterator i = placeholders.begin(); i != placeholders.end(); ++i)
{
replaceAll(defaultText, i->first, i->second);
}
return defaultText;
}
return botText;
}
// chat replies // chat replies
std::string PlayerbotTextMgr::GetBotText(ChatReplyType replyType, std::map<std::string, std::string> placeholders) std::string PlayerbotTextMgr::GetBotText(ChatReplyType replyType, std::map<std::string, std::string> placeholders)

View File

@@ -83,6 +83,8 @@ public:
std::string GetBotText(ChatReplyType replyType, std::string name); std::string GetBotText(ChatReplyType replyType, std::string name);
bool GetBotText(std::string name, std::string& text); bool GetBotText(std::string name, std::string& text);
bool GetBotText(std::string name, std::string& text, std::map<std::string, std::string> placeholders); bool GetBotText(std::string name, std::string& text, std::map<std::string, std::string> placeholders);
std::string GetBotTextOrDefault(std::string name, std::string defaultText,
std::map<std::string, std::string> placeholders);
void LoadBotTexts(); void LoadBotTexts();
void LoadBotTextChance(); void LoadBotTextChance();
static void replaceAll(std::string& str, const std::string& from, const std::string& to); static void replaceAll(std::string& str, const std::string& from, const std::string& to);

View File

@@ -3992,7 +3992,7 @@ void PlayerbotFactory::InitGuild()
return; return;
} }
if (guild->GetMemberSize() < urand(10, 15)) if (guild->GetMemberSize() < urand(10, sPlayerbotAIConfig->randomBotGuildSizeMax))
guild->AddMember(bot->GetGUID(), urand(GR_OFFICER, GR_INITIATE)); guild->AddMember(bot->GetGUID(), urand(GR_OFFICER, GR_INITIATE));
// add guild tabard // add guild tabard

View File

@@ -184,7 +184,7 @@ void StatsWeightCalculator::GenerateBasicWeights(Player* player)
stats_weights_[STATS_TYPE_MELEE_DPS] += 0.01f; stats_weights_[STATS_TYPE_MELEE_DPS] += 0.01f;
stats_weights_[STATS_TYPE_RANGED_DPS] += 0.01f; stats_weights_[STATS_TYPE_RANGED_DPS] += 0.01f;
if (cls == CLASS_HUNTER && (tab == HUNTER_TAB_BEASTMASTER || tab == HUNTER_TAB_SURVIVAL)) if (cls == CLASS_HUNTER && (tab == HUNTER_TAB_BEASTMASTERY || tab == HUNTER_TAB_SURVIVAL))
{ {
stats_weights_[STATS_TYPE_AGILITY] += 2.5f; stats_weights_[STATS_TYPE_AGILITY] += 2.5f;
stats_weights_[STATS_TYPE_ATTACK_POWER] += 1.0f; stats_weights_[STATS_TYPE_ATTACK_POWER] += 1.0f;

View File

@@ -47,6 +47,8 @@ public:
std::unordered_map<std::string, ObjectCreator> creators; std::unordered_map<std::string, ObjectCreator> creators;
public: public:
virtual ~NamedObjectFactory() = default;
virtual T* create(std::string name, PlayerbotAI* botAI) virtual T* create(std::string name, PlayerbotAI* botAI)
{ {
size_t found = name.find("::"); size_t found = name.find("::");
@@ -147,9 +149,7 @@ public:
{ {
contexts.push_back(context); contexts.push_back(context);
for (const auto& iter : context->creators) for (const auto& iter : context->creators)
{
creators[iter.first] = iter.second; creators[iter.first] = iter.second;
}
} }
}; };
@@ -208,6 +208,7 @@ public:
if (T* object = create(name, botAI)) if (T* object = create(name, botAI))
return created[name] = object; return created[name] = object;
} }
return created[name]; return created[name];
} }
@@ -236,7 +237,6 @@ public:
for (auto i = contexts.begin(); i != contexts.end(); i++) for (auto i = contexts.begin(); i != contexts.end(); i++)
{ {
std::set<std::string> supported = (*i)->supports(); std::set<std::string> supported = (*i)->supports();
for (std::set<std::string>::const_iterator j = supported.begin(); j != supported.end(); ++j) for (std::set<std::string>::const_iterator j = supported.begin(); j != supported.end(); ++j)
result.insert(*j); result.insert(*j);
} }
@@ -248,9 +248,7 @@ public:
{ {
std::set<std::string> result; std::set<std::string> result;
for (typename std::unordered_map<std::string, T*>::const_iterator i = created.begin(); i != created.end(); i++) for (typename std::unordered_map<std::string, T*>::const_iterator i = created.begin(); i != created.end(); i++)
{
result.insert(i->first); result.insert(i->first);
}
return result; return result;
} }
@@ -297,15 +295,14 @@ public:
{ {
factories.push_back(context); factories.push_back(context);
for (const auto& iter : context->creators) for (const auto& iter : context->creators)
{
creators[iter.first] = iter.second; creators[iter.first] = iter.second;
}
} }
T* GetContextObject(const std::string& name, PlayerbotAI* botAI) T* GetContextObject(const std::string& name, PlayerbotAI* botAI)
{ {
if (T* object = create(name, botAI)) if (T* object = create(name, botAI))
return object; return object;
return nullptr; return nullptr;
} }
}; };

View File

@@ -184,8 +184,8 @@ private:
static Strategy* grind(PlayerbotAI* botAI) { return new GrindingStrategy(botAI); } static Strategy* grind(PlayerbotAI* botAI) { return new GrindingStrategy(botAI); }
static Strategy* avoid_aoe(PlayerbotAI* botAI) { return new AvoidAoeStrategy(botAI); } static Strategy* avoid_aoe(PlayerbotAI* botAI) { return new AvoidAoeStrategy(botAI); }
static Strategy* tank_face(PlayerbotAI* botAI) { return new TankFaceStrategy(botAI); } static Strategy* tank_face(PlayerbotAI* botAI) { return new TankFaceStrategy(botAI); }
static Strategy* move_random(PlayerbotAI* ai) { return new MoveRandomStrategy(ai); } static Strategy* move_random(PlayerbotAI* botAI) { return new MoveRandomStrategy(botAI); }
static Strategy* combat_formation(PlayerbotAI* ai) { return new CombatFormationStrategy(ai); } static Strategy* combat_formation(PlayerbotAI* botAI) { return new CombatFormationStrategy(botAI); }
static Strategy* move_from_group(PlayerbotAI* botAI) { return new MoveFromGroupStrategy(botAI); } static Strategy* move_from_group(PlayerbotAI* botAI) { return new MoveFromGroupStrategy(botAI); }
static Strategy* world_buff(PlayerbotAI* botAI) { return new WorldBuffStrategy(botAI); } static Strategy* world_buff(PlayerbotAI* botAI) { return new WorldBuffStrategy(botAI); }
}; };

View File

@@ -152,13 +152,9 @@ bool CheckMountStateAction::Execute(Event /*event*/)
bool inBattleground = bot->InBattleground(); bool inBattleground = bot->InBattleground();
// If there is a master and bot not in BG // If there is a master and bot not in BG, follow master's mount state regardless of group leader
if (master && !inBattleground) if (master && !inBattleground)
{ {
Group* group = bot->GetGroup();
if (!group || group->GetLeaderGUID() != master->GetGUID())
return false;
if (ShouldFollowMasterMountState(master, noAttackers, shouldMount)) if (ShouldFollowMasterMountState(master, noAttackers, shouldMount))
return Mount(); return Mount();

View File

@@ -125,26 +125,15 @@ namespace ai::buff
key = "rp_missing_reagent_generic"; key = "rp_missing_reagent_generic";
// Placeholders // Placeholders
std::map<std::string, std::string> ph; std::map<std::string, std::string> placeholders;
ph["%group_spell"] = groupName; placeholders["%group_spell"] = groupName;
ph["%base_spell"] = baseName; placeholders["%base_spell"] = baseName;
// Respecte ai_playerbot_texts_chance if present std::string announceText = sPlayerbotTextMgr->GetBotTextOrDefault(key,
std::string rp; "Out of components for %group_spell. Using %base_spell!", placeholders);
bool got = sPlayerbotTextMgr->GetBotText(key, rp, ph);
if (got && !rp.empty()) announce(announceText);
{ last = now;
announce(rp);
last = now;
}
else
{
// Minimal Fallback
std::ostringstream oss;
oss << "Out of components for " << groupName << ". Using " << baseName << "!";
announce(oss.str());
last = now;
}
} }
} }
} }

View File

@@ -20,7 +20,7 @@ public:
class AutoShareQuestAction : public ShareQuestAction class AutoShareQuestAction : public ShareQuestAction
{ {
public: public:
AutoShareQuestAction(PlayerbotAI* ai) : ShareQuestAction(botAI, "auto share quest") {} AutoShareQuestAction(PlayerbotAI* botAI) : ShareQuestAction(botAI, "auto share quest") {}
bool Execute(Event event) override; bool Execute(Event event) override;
bool isUseful() override; bool isUseful() override;

View File

@@ -24,7 +24,7 @@ public:
class MoveRandomStrategy : public NonCombatStrategy class MoveRandomStrategy : public NonCombatStrategy
{ {
public: public:
MoveRandomStrategy(PlayerbotAI* ai) : NonCombatStrategy(botAI) {} MoveRandomStrategy(PlayerbotAI* botAI) : NonCombatStrategy(botAI) {}
std::string const getName() override { return "move random"; } std::string const getName() override { return "move random"; }
void InitTriggers(std::vector<TriggerNode*>& triggers) override; void InitTriggers(std::vector<TriggerNode*>& triggers) override;
}; };

View File

@@ -30,7 +30,7 @@ class PullPowerSparkAction : public CastSpellAction
{ {
public: public:
PullPowerSparkAction(PlayerbotAI* botAI, std::string const name = "pull power spark") PullPowerSparkAction(PlayerbotAI* botAI, std::string const name = "pull power spark")
: CastSpellAction(botAI, "death grip") {} : CastSpellAction(botAI, name) {}
bool Execute(Event event) override; bool Execute(Event event) override;
bool isPossible() override; bool isPossible() override;
bool isUseful() override; bool isUseful() override;