From b9dbfe9646e8b0bed622d6dc4060d82043581120 Mon Sep 17 00:00:00 2001 From: Tecc Date: Sat, 27 Sep 2025 22:50:14 +0200 Subject: [PATCH 1/7] fix: Allow following master's mount state regardless of group leader in CheckMountStateAction --- src/strategy/actions/CheckMountStateAction.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/strategy/actions/CheckMountStateAction.cpp b/src/strategy/actions/CheckMountStateAction.cpp index 0c36935e..589984ac 100644 --- a/src/strategy/actions/CheckMountStateAction.cpp +++ b/src/strategy/actions/CheckMountStateAction.cpp @@ -152,13 +152,9 @@ bool CheckMountStateAction::Execute(Event /*event*/) 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) { - Group* group = bot->GetGroup(); - if (!group || group->GetLeaderGUID() != master->GetGUID()) - return false; - if (ShouldFollowMasterMountState(master, noAttackers, shouldMount)) return Mount(); From e525c22d85c6959f2cc54543e984f54702b1dc59 Mon Sep 17 00:00:00 2001 From: crow Date: Sat, 27 Sep 2025 23:11:47 -0500 Subject: [PATCH 2/7] Fix SPEC_TAB names --- src/AiFactory.cpp | 4 ++-- src/PlayerbotAI.cpp | 2 +- src/PlayerbotAI.h | 8 ++++---- src/factory/StatsWeightCalculator.cpp | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/AiFactory.cpp b/src/AiFactory.cpp index 9bf3c551..75d51bf1 100644 --- a/src/AiFactory.cpp +++ b/src/AiFactory.cpp @@ -295,7 +295,7 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa { engine->addStrategiesNoInit("dps", "shadow debuff", "shadow aoe", nullptr); } - else if (tab == PRIEST_TAB_DISIPLINE) + else if (tab == PRIEST_TAB_DISCIPLINE) { engine->addStrategiesNoInit("heal", nullptr); } @@ -607,7 +607,7 @@ void AiFactory::AddDefaultNonCombatStrategies(Player* player, PlayerbotAI* const nonCombatEngine->addStrategy("dps assist", false); break; case CLASS_WARLOCK: - if (tab == WARLOCK_TAB_AFFLICATION) + if (tab == WARLOCK_TAB_AFFLICTION) { nonCombatEngine->addStrategiesNoInit("felhunter", "spellstone", nullptr); } diff --git a/src/PlayerbotAI.cpp b/src/PlayerbotAI.cpp index c2c34a11..d529ae34 100644 --- a/src/PlayerbotAI.cpp +++ b/src/PlayerbotAI.cpp @@ -2085,7 +2085,7 @@ bool PlayerbotAI::IsHeal(Player* player, bool bySpec) switch (player->getClass()) { case CLASS_PRIEST: - if (tab == PRIEST_TAB_DISIPLINE || tab == PRIEST_TAB_HOLY) + if (tab == PRIEST_TAB_DISCIPLINE || tab == PRIEST_TAB_HOLY) { return true; } diff --git a/src/PlayerbotAI.h b/src/PlayerbotAI.h index 67d72454..f112f9d0 100644 --- a/src/PlayerbotAI.h +++ b/src/PlayerbotAI.h @@ -276,7 +276,7 @@ enum BotRoles : uint8 enum HUNTER_TABS { - HUNTER_TAB_BEASTMASTER, + HUNTER_TAB_BEASTMASTERY, HUNTER_TAB_MARKSMANSHIP, HUNTER_TAB_SURVIVAL, }; @@ -285,12 +285,12 @@ enum ROGUE_TABS { ROGUE_TAB_ASSASSINATION, ROGUE_TAB_COMBAT, - ROGUE_TAB_SUBTLETY + ROGUE_TAB_SUBTLETY, }; enum PRIEST_TABS { - PRIEST_TAB_DISIPLINE, + PRIEST_TAB_DISCIPLINE, PRIEST_TAB_HOLY, PRIEST_TAB_SHADOW, }; @@ -332,7 +332,7 @@ enum PALADIN_TABS enum WARLOCK_TABS { - WARLOCK_TAB_AFFLICATION, + WARLOCK_TAB_AFFLICTION, WARLOCK_TAB_DEMONOLOGY, WARLOCK_TAB_DESTRUCTION, }; diff --git a/src/factory/StatsWeightCalculator.cpp b/src/factory/StatsWeightCalculator.cpp index 19491256..2963c741 100644 --- a/src/factory/StatsWeightCalculator.cpp +++ b/src/factory/StatsWeightCalculator.cpp @@ -184,7 +184,7 @@ void StatsWeightCalculator::GenerateBasicWeights(Player* player) stats_weights_[STATS_TYPE_MELEE_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_ATTACK_POWER] += 1.0f; From 34ce17fb3ab0d493e420b25fe378ad9e98fb2de0 Mon Sep 17 00:00:00 2001 From: privatecore Date: Sun, 28 Sep 2025 00:07:21 +0200 Subject: [PATCH 3/7] Fix wrong cast spell action passed to the PullPowerSparkAction constructor --- src/strategy/raids/eyeofeternity/RaidEoEActions.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/strategy/raids/eyeofeternity/RaidEoEActions.h b/src/strategy/raids/eyeofeternity/RaidEoEActions.h index d2d158c7..c6fe064c 100644 --- a/src/strategy/raids/eyeofeternity/RaidEoEActions.h +++ b/src/strategy/raids/eyeofeternity/RaidEoEActions.h @@ -30,7 +30,7 @@ class PullPowerSparkAction : public CastSpellAction { public: PullPowerSparkAction(PlayerbotAI* botAI, std::string const name = "pull power spark") - : CastSpellAction(botAI, "death grip") {} + : CastSpellAction(botAI, name) {} bool Execute(Event event) override; bool isPossible() override; bool isUseful() override; From c20fb3447076e98e6c56febbb8e84b458ccca5e7 Mon Sep 17 00:00:00 2001 From: kadeshar Date: Sun, 28 Sep 2025 13:39:59 +0200 Subject: [PATCH 4/7] - Added method to get translation bot text or default (#1678) --- src/PlayerbotTextMgr.cpp | 16 ++++++++++++++ src/PlayerbotTextMgr.h | 2 ++ src/strategy/actions/GenericBuffUtils.cpp | 27 +++++++---------------- 3 files changed, 26 insertions(+), 19 deletions(-) diff --git a/src/PlayerbotTextMgr.cpp b/src/PlayerbotTextMgr.cpp index 9a923de9..e758d630 100644 --- a/src/PlayerbotTextMgr.cpp +++ b/src/PlayerbotTextMgr.cpp @@ -101,6 +101,22 @@ std::string PlayerbotTextMgr::GetBotText(std::string name, std::map placeholders) +{ + std::string botText = GetBotText(name, placeholders); + if (botText.empty()) + { + for (std::map::iterator i = placeholders.begin(); i != placeholders.end(); ++i) + { + replaceAll(defaultText, i->first, i->second); + } + return defaultText; + } + + return botText; +} + // chat replies std::string PlayerbotTextMgr::GetBotText(ChatReplyType replyType, std::map placeholders) diff --git a/src/PlayerbotTextMgr.h b/src/PlayerbotTextMgr.h index 5ec3aaa6..05c47ce2 100644 --- a/src/PlayerbotTextMgr.h +++ b/src/PlayerbotTextMgr.h @@ -83,6 +83,8 @@ public: std::string GetBotText(ChatReplyType replyType, std::string name); bool GetBotText(std::string name, std::string& text); bool GetBotText(std::string name, std::string& text, std::map placeholders); + std::string GetBotTextOrDefault(std::string name, std::string defaultText, + std::map placeholders); void LoadBotTexts(); void LoadBotTextChance(); static void replaceAll(std::string& str, const std::string& from, const std::string& to); diff --git a/src/strategy/actions/GenericBuffUtils.cpp b/src/strategy/actions/GenericBuffUtils.cpp index e1dce004..d222667c 100644 --- a/src/strategy/actions/GenericBuffUtils.cpp +++ b/src/strategy/actions/GenericBuffUtils.cpp @@ -125,26 +125,15 @@ namespace ai::buff key = "rp_missing_reagent_generic"; // Placeholders - std::map ph; - ph["%group_spell"] = groupName; - ph["%base_spell"] = baseName; + std::map placeholders; + placeholders["%group_spell"] = groupName; + placeholders["%base_spell"] = baseName; - // Respecte ai_playerbot_texts_chance if present - std::string rp; - bool got = sPlayerbotTextMgr->GetBotText(key, rp, ph); - if (got && !rp.empty()) - { - announce(rp); - last = now; - } - else - { - // Minimal Fallback - std::ostringstream oss; - oss << "Out of components for " << groupName << ". Using " << baseName << "!"; - announce(oss.str()); - last = now; - } + std::string announceText = sPlayerbotTextMgr->GetBotTextOrDefault(key, + "Out of components for %group_spell. Using %base_spell!", placeholders); + + announce(announceText); + last = now; } } } From 30bd58be6746ed10d5ff242845e0252c45163210 Mon Sep 17 00:00:00 2001 From: privatecore Date: Sun, 28 Sep 2025 13:42:03 +0200 Subject: [PATCH 5/7] Fix wrong PlayerbotAI parameter name passed to the constructor (#1672) --- src/strategy/StrategyContext.h | 4 ++-- src/strategy/actions/ShareQuestAction.h | 2 +- src/strategy/generic/GrindingStrategy.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/strategy/StrategyContext.h b/src/strategy/StrategyContext.h index ff16df1a..a95ccbdf 100644 --- a/src/strategy/StrategyContext.h +++ b/src/strategy/StrategyContext.h @@ -184,8 +184,8 @@ private: static Strategy* grind(PlayerbotAI* botAI) { return new GrindingStrategy(botAI); } static Strategy* avoid_aoe(PlayerbotAI* botAI) { return new AvoidAoeStrategy(botAI); } static Strategy* tank_face(PlayerbotAI* botAI) { return new TankFaceStrategy(botAI); } - static Strategy* move_random(PlayerbotAI* ai) { return new MoveRandomStrategy(ai); } - static Strategy* combat_formation(PlayerbotAI* ai) { return new CombatFormationStrategy(ai); } + static Strategy* move_random(PlayerbotAI* botAI) { return new MoveRandomStrategy(botAI); } + static Strategy* combat_formation(PlayerbotAI* botAI) { return new CombatFormationStrategy(botAI); } static Strategy* move_from_group(PlayerbotAI* botAI) { return new MoveFromGroupStrategy(botAI); } static Strategy* world_buff(PlayerbotAI* botAI) { return new WorldBuffStrategy(botAI); } }; diff --git a/src/strategy/actions/ShareQuestAction.h b/src/strategy/actions/ShareQuestAction.h index d2289ab1..efc87010 100644 --- a/src/strategy/actions/ShareQuestAction.h +++ b/src/strategy/actions/ShareQuestAction.h @@ -20,7 +20,7 @@ public: class AutoShareQuestAction : public ShareQuestAction { public: - AutoShareQuestAction(PlayerbotAI* ai) : ShareQuestAction(botAI, "auto share quest") {} + AutoShareQuestAction(PlayerbotAI* botAI) : ShareQuestAction(botAI, "auto share quest") {} bool Execute(Event event) override; bool isUseful() override; diff --git a/src/strategy/generic/GrindingStrategy.h b/src/strategy/generic/GrindingStrategy.h index 6ab11904..d04060c4 100644 --- a/src/strategy/generic/GrindingStrategy.h +++ b/src/strategy/generic/GrindingStrategy.h @@ -24,7 +24,7 @@ public: class MoveRandomStrategy : public NonCombatStrategy { public: - MoveRandomStrategy(PlayerbotAI* ai) : NonCombatStrategy(botAI) {} + MoveRandomStrategy(PlayerbotAI* botAI) : NonCombatStrategy(botAI) {} std::string const getName() override { return "move random"; } void InitTriggers(std::vector& triggers) override; }; From b0f3de65f55cfd3f817a51c3c2fc23143321a89b Mon Sep 17 00:00:00 2001 From: privatecore Date: Sun, 28 Sep 2025 13:53:11 +0200 Subject: [PATCH 6/7] Fix warning: delete called on non-final that has virtual functions but non-virtual destructor (#1671) --- src/strategy/NamedObjectContext.h | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/strategy/NamedObjectContext.h b/src/strategy/NamedObjectContext.h index 69b38ce1..846026c2 100644 --- a/src/strategy/NamedObjectContext.h +++ b/src/strategy/NamedObjectContext.h @@ -47,6 +47,8 @@ public: std::unordered_map creators; public: + virtual ~NamedObjectFactory() = default; + virtual T* create(std::string name, PlayerbotAI* botAI) { size_t found = name.find("::"); @@ -147,9 +149,7 @@ public: { contexts.push_back(context); for (const auto& iter : context->creators) - { creators[iter.first] = iter.second; - } } }; @@ -208,6 +208,7 @@ public: if (T* object = create(name, botAI)) return created[name] = object; } + return created[name]; } @@ -236,7 +237,6 @@ public: for (auto i = contexts.begin(); i != contexts.end(); i++) { std::set supported = (*i)->supports(); - for (std::set::const_iterator j = supported.begin(); j != supported.end(); ++j) result.insert(*j); } @@ -248,9 +248,7 @@ public: { std::set result; for (typename std::unordered_map::const_iterator i = created.begin(); i != created.end(); i++) - { result.insert(i->first); - } return result; } @@ -297,15 +295,14 @@ public: { factories.push_back(context); for (const auto& iter : context->creators) - { creators[iter.first] = iter.second; - } } T* GetContextObject(const std::string& name, PlayerbotAI* botAI) { if (T* object = create(name, botAI)) return object; + return nullptr; } }; From 6f79193d7abb3927480ff915b7afa79bd0a4c8eb Mon Sep 17 00:00:00 2001 From: Iain Donnelly Date: Sun, 28 Sep 2025 14:04:09 +0100 Subject: [PATCH 7/7] Config option to set max number of guild members in random bot guilds --- conf/playerbots.conf.dist | 3 +++ src/PlayerbotAIConfig.cpp | 1 + src/PlayerbotAIConfig.h | 2 +- src/factory/PlayerbotFactory.cpp | 2 +- 4 files changed, 6 insertions(+), 2 deletions(-) diff --git a/conf/playerbots.conf.dist b/conf/playerbots.conf.dist index b4e715f9..1bf88955 100644 --- a/conf/playerbots.conf.dist +++ b/conf/playerbots.conf.dist @@ -159,6 +159,9 @@ AiPlayerbot.RandomBotGuildNearby = 0 # Number of guilds created by randombots 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 AiPlayerbot.DeleteRandomBotGuilds = 0 diff --git a/src/PlayerbotAIConfig.cpp b/src/PlayerbotAIConfig.cpp index 100bed92..d2a3ff8a 100644 --- a/src/PlayerbotAIConfig.cpp +++ b/src/PlayerbotAIConfig.cpp @@ -509,6 +509,7 @@ bool PlayerbotAIConfig::Initialize() randomBotAccountCount = sConfigMgr->GetOption("AiPlayerbot.RandomBotAccountCount", 0); deleteRandomBotAccounts = sConfigMgr->GetOption("AiPlayerbot.DeleteRandomBotAccounts", false); randomBotGuildCount = sConfigMgr->GetOption("AiPlayerbot.RandomBotGuildCount", 20); + randomBotGuildSizeMax = sConfigMgr->GetOption("AiPlayerbot.RandomBotGuildSizeMax", 15); deleteRandomBotGuilds = sConfigMgr->GetOption("AiPlayerbot.DeleteRandomBotGuilds", false); guildTaskEnabled = sConfigMgr->GetOption("AiPlayerbot.EnableGuildTasks", true); diff --git a/src/PlayerbotAIConfig.h b/src/PlayerbotAIConfig.h index 13427698..48e1b864 100644 --- a/src/PlayerbotAIConfig.h +++ b/src/PlayerbotAIConfig.h @@ -267,7 +267,7 @@ public: uint32 randomBotAccountCount; bool randomBotRandomPassword; bool deleteRandomBotAccounts; - uint32 randomBotGuildCount; + uint32 randomBotGuildCount, randomBotGuildSizeMax; bool deleteRandomBotGuilds; std::vector randomBotGuilds; std::vector pvpProhibitedZoneIds; diff --git a/src/factory/PlayerbotFactory.cpp b/src/factory/PlayerbotFactory.cpp index f9a5d007..60b6ec69 100644 --- a/src/factory/PlayerbotFactory.cpp +++ b/src/factory/PlayerbotFactory.cpp @@ -3992,7 +3992,7 @@ void PlayerbotFactory::InitGuild() return; } - if (guild->GetMemberSize() < urand(10, 15)) + if (guild->GetMemberSize() < urand(10, sPlayerbotAIConfig->randomBotGuildSizeMax)) guild->AddMember(bot->GetGUID(), urand(GR_OFFICER, GR_INITIATE)); // add guild tabard