diff --git a/conf/playerbots.conf.dist b/conf/playerbots.conf.dist index d673cd53e..69c84b4f2 100644 --- a/conf/playerbots.conf.dist +++ b/conf/playerbots.conf.dist @@ -89,11 +89,21 @@ AiPlayerbot.MinRandomBots = 500 AiPlayerbot.MaxRandomBots = 500 # Randombot accounts -# If you are not using any expansion at all, you may have to set this manually, in which case please -# ensure that RandomBotAccountCount is at least greater than (MaxRandomBots / 10 + AddClassAccountPoolSize) +# Set to 0 to automatically calculate needed accounts based on MaxRandomBots, EnablePeriodicOnlineOffline +# and its ratio, and AddClassAccountPoolSize. Set manually if you want to create more accounts than needed. +# If the manual value is less than the required, the system will override it with the required value. # Default: 0 (automatic) AiPlayerbot.RandomBotAccountCount = 0 +# Addclass accounts +# Number of accounts created for bots reserved for the addclass command. As with randombots, each account has +# 10 bots (or 9 if WotLK is disabled), one bot for each class. +AiPlayerbot.AddClassAccountPoolSize = 50 + +# Prefix for created bot accounts (of any type). +# Do not change this prefix while there are existing bot accounts. +AiPlayerbot.RandomBotAccountPrefix = "rndbot" + # Delete all randombot accounts # To apply this, set the number to 1 and run the Worldserver. Once deletion is complete, if you would # like to recreate randombots, set the number back to 0 and rerun the Worldserver. @@ -128,9 +138,6 @@ AiPlayerbot.MaxAddedBots = 40 # Default: 1 (enabled) AiPlayerbot.AddClassCommand = 1 -# Set the addclass command account pool size -AiPlayerbot.AddClassAccountPoolSize = 50 - # Bot group invitation permission level (0 = GM only, 1 = accept based on level, 2 = always accept) # Default: 1 (accept based on level) AiPlayerbot.GroupInvitationPermission = 1 @@ -680,9 +687,6 @@ AiPlayerbot.EndFishingWithMaster = 30.0 # Enable/Disable randomly generated password for randombot accounts AiPlayerbot.RandomBotRandomPassword = 0 -# Prefix for account names to create for randombots -AiPlayerbot.RandomBotAccountPrefix = "rndbot" - # Minimum and maximum levels for randombots AiPlayerbot.RandomBotMinLevel = 1 AiPlayerbot.RandomBotMaxLevel = 80 diff --git a/src/Ai/Base/ActionContext.h b/src/Ai/Base/ActionContext.h index 3026cfd50..7cde4dbfd 100644 --- a/src/Ai/Base/ActionContext.h +++ b/src/Ai/Base/ActionContext.h @@ -175,6 +175,8 @@ public: creators["berserking"] = &ActionContext::berserking; creators["every man for himself"] = &ActionContext::every_man_for_himself; creators["will of the forsaken"] = &ActionContext::will_of_the_forsaken; + creators["stoneform"] = &ActionContext::stoneform; + creators["escape artist"] = &ActionContext::escape_artist; creators["use trinket"] = &ActionContext::use_trinket; creators["auto talents"] = &ActionContext::auto_talents; creators["auto share quest"] = &ActionContext::auto_share_quest; @@ -380,6 +382,8 @@ private: static Action* berserking(PlayerbotAI* botAI) { return new CastBerserkingAction(botAI); } static Action* every_man_for_himself(PlayerbotAI* botAI) { return new CastEveryManForHimselfAction(botAI); } static Action* will_of_the_forsaken(PlayerbotAI* botAI) { return new CastWillOfTheForsakenAction(botAI); } + static Action* stoneform(PlayerbotAI* botAI) { return new CastStoneformAction(botAI); } + static Action* escape_artist(PlayerbotAI* botAI) { return new CastEscapeArtistAction(botAI); } static Action* use_trinket(PlayerbotAI* botAI) { return new UseTrinketAction(botAI); } static Action* auto_talents(PlayerbotAI* botAI) { return new AutoSetTalentsAction(botAI); } static Action* auto_share_quest(PlayerbotAI* ai) { return new AutoShareQuestAction(ai); } diff --git a/src/Ai/Base/Actions/FollowActions.cpp b/src/Ai/Base/Actions/FollowActions.cpp index f82b05368..baa6e3e41 100644 --- a/src/Ai/Base/Actions/FollowActions.cpp +++ b/src/Ai/Base/Actions/FollowActions.cpp @@ -259,6 +259,8 @@ bool FollowAction::isUseful() Unit* fTarget = nullptr; if (!target.empty()) fTarget = AI_VALUE(Unit*, target); + else if (botAI->GetMaster()) + fTarget = botAI->GetMaster(); else fTarget = AI_VALUE(Unit*, "group leader"); diff --git a/src/Ai/Base/Actions/GenericSpellActions.cpp b/src/Ai/Base/Actions/GenericSpellActions.cpp index 657fda7cd..50621484f 100644 --- a/src/Ai/Base/Actions/GenericSpellActions.cpp +++ b/src/Ai/Base/Actions/GenericSpellActions.cpp @@ -491,32 +491,13 @@ bool CastVehicleSpellAction::Execute(Event /*event*/) bool CastEveryManForHimselfAction::isPossible() { uint32 spellId = AI_VALUE2(uint32, "spell id", spell); - return spellId && bot->HasSpell(spellId) && !HasSpellOrCategoryCooldown(bot, spellId); -} - -bool CastEveryManForHimselfAction::isUseful() -{ - return (bot->HasAuraType(SPELL_AURA_MOD_STUN) || - bot->HasAuraType(SPELL_AURA_MOD_FEAR) || - bot->HasAuraType(SPELL_AURA_MOD_ROOT) || - bot->HasAuraType(SPELL_AURA_MOD_CONFUSE) || - bot->HasAuraType(SPELL_AURA_MOD_CHARM)) - && CastSpellAction::isUseful(); + return spellId && !HasSpellOrCategoryCooldown(bot, spellId); } bool CastWillOfTheForsakenAction::isPossible() { uint32 spellId = AI_VALUE2(uint32, "spell id", spell); - return spellId && bot->HasSpell(spellId) && !HasSpellOrCategoryCooldown(bot, spellId); -} - -bool CastWillOfTheForsakenAction::isUseful() -{ - return (bot->HasAuraType(SPELL_AURA_MOD_FEAR) || - bot->HasAuraType(SPELL_AURA_MOD_CHARM) || - bot->HasAuraType(SPELL_AURA_AOE_CHARM) || - bot->HasAuraWithMechanic(1 << MECHANIC_SLEEP)) - && CastSpellAction::isUseful(); + return spellId && !HasSpellOrCategoryCooldown(bot, spellId); } bool UseTrinketAction::Execute(Event /*event*/) diff --git a/src/Ai/Base/Actions/GenericSpellActions.h b/src/Ai/Base/Actions/GenericSpellActions.h index c17d96907..1d6e464ef 100644 --- a/src/Ai/Base/Actions/GenericSpellActions.h +++ b/src/Ai/Base/Actions/GenericSpellActions.h @@ -313,7 +313,6 @@ public: std::string const GetTargetName() override { return "self target"; } bool isPossible() override; - bool isUseful() override; }; class CastWillOfTheForsakenAction : public CastSpellAction @@ -323,7 +322,22 @@ public: std::string const GetTargetName() override { return "self target"; } bool isPossible() override; - bool isUseful() override; +}; + +class CastStoneformAction : public CastSpellAction +{ +public: + CastStoneformAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "stoneform") {} + + std::string const GetTargetName() override { return "self target"; } +}; + +class CastEscapeArtistAction : public CastSpellAction +{ +public: + CastEscapeArtistAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "escape artist") {} + + std::string const GetTargetName() override { return "self target"; } }; class UseTrinketAction : public Action diff --git a/src/Ai/Base/Strategy/RacialsStrategy.cpp b/src/Ai/Base/Strategy/RacialsStrategy.cpp index b5a84bbce..3382d3291 100644 --- a/src/Ai/Base/Strategy/RacialsStrategy.cpp +++ b/src/Ai/Base/Strategy/RacialsStrategy.cpp @@ -4,45 +4,104 @@ */ #include "RacialsStrategy.h" +#include "Playerbots.h" -class RacialsStrategyActionNodeFactory : public NamedObjectFactory +namespace { -public: - RacialsStrategyActionNodeFactory() { creators["lifeblood"] = &lifeblood; } - -private: - static ActionNode* lifeblood(PlayerbotAI* /*botAI*/) - { - return new ActionNode("lifeblood", - /*P*/ {}, - /*A*/ { NextAction("gift of the naaru") }, - /*C*/ {}); - } -}; - -void RacialsStrategy::InitTriggers(std::vector& triggers) -{ - triggers.push_back( - new TriggerNode("low health", { NextAction("lifeblood", ACTION_NORMAL + 5) })); - triggers.push_back( - new TriggerNode("medium aoe", { NextAction("war stomp", ACTION_NORMAL + 5) })); - triggers.push_back(new TriggerNode( - "low mana", { NextAction("arcane torrent", ACTION_NORMAL + 5) })); - - triggers.push_back(new TriggerNode( - "generic boost", { NextAction("blood fury", ACTION_NORMAL + 5), - NextAction("berserking", ACTION_NORMAL + 5), - NextAction("use trinket", ACTION_NORMAL + 4) })); - - triggers.push_back(new TriggerNode( - "loss of control", { NextAction("every man for himself", ACTION_EMERGENCY + 1) })); - - triggers.push_back(new TriggerNode( - "fear charm sleep", { NextAction("will of the forsaken", ACTION_EMERGENCY + 1) })); - + constexpr uint32 SPELL_ARCANE_TORRENT_ENERGY = 25046; + constexpr uint32 SPELL_ARCANE_TORRENT_MANA = 28730; + constexpr uint32 SPELL_ARCANE_TORRENT_RUNIC_POWER = 50613; + constexpr uint32 SPELL_WAR_STOMP = 20549; + constexpr uint32 SPELL_BERSERKING = 26297; + constexpr uint32 SPELL_EVERY_MAN_FOR_HIMSELF = 59752; + constexpr uint32 SPELL_WILL_OF_THE_FORSAKEN = 7744; + constexpr uint32 SPELL_STONEFORM = 20594; + constexpr uint32 SPELL_ESCAPE_ARTIST = 20589; } RacialsStrategy::RacialsStrategy(PlayerbotAI* botAI) : Strategy(botAI) { - actionNodeFactories.Add(new RacialsStrategyActionNodeFactory()); + // No custom ActionNodeFactory needed +} + +void RacialsStrategy::InitTriggers(std::vector& triggers) +{ + Player* bot = botAI->GetBot(); + + if (bot->HasSpell(SPELL_ARCANE_TORRENT_MANA)) + { + triggers.push_back(new TriggerNode( + "low mana", { NextAction("arcane torrent", ACTION_NORMAL + 5) })); + } + + if (bot->HasSpell(SPELL_ARCANE_TORRENT_ENERGY)) + { + triggers.push_back(new TriggerNode( + "low energy", { NextAction("arcane torrent", ACTION_NORMAL + 5) })); + } + + if (bot->HasSpell(SPELL_ARCANE_TORRENT_RUNIC_POWER)) + { + // No low runic power trigger exists; this trigger should be modified if one is added + triggers.push_back(new TriggerNode( + "generic boost", { NextAction("arcane torrent", ACTION_NORMAL + 5) })); + } + + if (bot->HasSpell(SPELL_WAR_STOMP)) + { + triggers.push_back(new TriggerNode( + "medium aoe", { NextAction("war stomp", ACTION_NORMAL + 5) })); + } + + if (bot->HasSpell(SPELL_BERSERKING)) + { + triggers.push_back(new TriggerNode( + "generic boost", { NextAction("berserking", ACTION_NORMAL + 5) })); + } + + if (bot->HasSpell(SPELL_EVERY_MAN_FOR_HIMSELF)) + { + triggers.push_back(new TriggerNode( + "loss of control", { NextAction("every man for himself", ACTION_EMERGENCY + 1) })); + } + + if (bot->HasSpell(SPELL_WILL_OF_THE_FORSAKEN)) + { + triggers.push_back(new TriggerNode( + "fear charm sleep", { NextAction("will of the forsaken", ACTION_EMERGENCY + 1) })); + } + + if (bot->HasSpell(SPELL_STONEFORM)) + { + triggers.push_back(new TriggerNode( + "poison disease bleed", { NextAction("stoneform", ACTION_DISPEL) })); + } + + if (bot->HasSpell(SPELL_ESCAPE_ARTIST)) + { + triggers.push_back(new TriggerNode( + "movement impaired", { NextAction("escape artist", ACTION_EMERGENCY + 1) })); + } + + if (botAI->HasSpell("blood fury")) + { + triggers.push_back(new TriggerNode( + "generic boost", { NextAction("blood fury", ACTION_NORMAL + 5) })); + } + + if (botAI->HasSpell("gift of the naaru")) + { + // Currently targets self only + triggers.push_back(new TriggerNode( + "medium health", { NextAction("gift of the naaru", ACTION_LIGHT_HEAL + 5) })); + } + + if (botAI->HasSpell("lifeblood")) + { + triggers.push_back(new TriggerNode( + "medium health", { NextAction("lifeblood", ACTION_LIGHT_HEAL + 5) })); + } + + triggers.push_back(new TriggerNode( + "generic boost", { NextAction("use trinket", ACTION_NORMAL + 4) })); } diff --git a/src/Ai/Base/Strategy/UsePotionsStrategy.cpp b/src/Ai/Base/Strategy/UsePotionsStrategy.cpp index 27f690cf1..8696784ff 100644 --- a/src/Ai/Base/Strategy/UsePotionsStrategy.cpp +++ b/src/Ai/Base/Strategy/UsePotionsStrategy.cpp @@ -32,5 +32,5 @@ void UsePotionsStrategy::InitTriggers(std::vector& triggers) triggers.push_back(new TriggerNode( "critical health", { NextAction("healthstone", ACTION_MEDIUM_HEAL + 1) })); triggers.push_back( - new TriggerNode("low mana", { NextAction("mana potion", ACTION_EMERGENCY) })); + new TriggerNode("medium mana", { NextAction("mana potion", ACTION_EMERGENCY) })); } diff --git a/src/Ai/Base/Trigger/GenericTriggers.cpp b/src/Ai/Base/Trigger/GenericTriggers.cpp index aac920b5b..308146467 100644 --- a/src/Ai/Base/Trigger/GenericTriggers.cpp +++ b/src/Ai/Base/Trigger/GenericTriggers.cpp @@ -491,6 +491,19 @@ bool FearSleepSapTrigger::IsActive() bot->HasAuraWithMechanic(1 << MECHANIC_SAPPED); } +bool PoisonDiseaseBleedTrigger::IsActive() +{ + return botAI->HasAuraToDispel(bot, DISPEL_POISON) || + botAI->HasAuraToDispel(bot, DISPEL_DISEASE) || + bot->HasAuraWithMechanic(1 << MECHANIC_BLEED); +} + +bool MovementImpairedTrigger::IsActive() +{ + return botAI->IsMovementImpaired(bot) && + !botAI->HasAnyAuraOf(bot, "stealth", "prowl", nullptr); +} + bool HasAuraStackTrigger::IsActive() { return botAI->GetAura(getName(), GetTarget(), false, true, stack); diff --git a/src/Ai/Base/Trigger/GenericTriggers.h b/src/Ai/Base/Trigger/GenericTriggers.h index 3e662eb3b..418949a85 100644 --- a/src/Ai/Base/Trigger/GenericTriggers.h +++ b/src/Ai/Base/Trigger/GenericTriggers.h @@ -752,6 +752,22 @@ public: bool IsActive() override; }; +class PoisonDiseaseBleedTrigger : public Trigger +{ +public: + PoisonDiseaseBleedTrigger(PlayerbotAI* botAI) : Trigger(botAI, "poison disease bleed", 1) {} + + bool IsActive() override; +}; + +class MovementImpairedTrigger : public Trigger +{ +public: + MovementImpairedTrigger(PlayerbotAI* botAI) : Trigger(botAI, "movement impaired", 1) {} + + bool IsActive() override; +}; + class IsSwimmingTrigger : public Trigger { public: diff --git a/src/Ai/Base/TriggerContext.h b/src/Ai/Base/TriggerContext.h index d440e5b5f..111597620 100644 --- a/src/Ai/Base/TriggerContext.h +++ b/src/Ai/Base/TriggerContext.h @@ -66,6 +66,8 @@ public: creators["loss of control"] = &TriggerContext::loss_of_control; creators["fear charm sleep"] = &TriggerContext::fear_charm_sleep; creators["fear sleep sap"] = &TriggerContext::fear_sleep_sap; + creators["poison disease bleed"] = &TriggerContext::poison_disease_bleed; + creators["movement impaired"] = &TriggerContext::movement_impaired; creators["protect party member"] = &TriggerContext::protect_party_member; @@ -382,6 +384,8 @@ private: static Trigger* loss_of_control(PlayerbotAI* botAI) { return new LossOfControlTrigger(botAI); } static Trigger* fear_charm_sleep(PlayerbotAI* botAI) { return new FearCharmSleepTrigger(botAI); } static Trigger* fear_sleep_sap(PlayerbotAI* botAI) { return new FearSleepSapTrigger(botAI); } + static Trigger* poison_disease_bleed(PlayerbotAI* botAI) { return new PoisonDiseaseBleedTrigger(botAI); } + static Trigger* movement_impaired(PlayerbotAI* botAI) { return new MovementImpairedTrigger(botAI); } static Trigger* PartyMemberCriticalHealth(PlayerbotAI* botAI) { return new PartyMemberCriticalHealthTrigger(botAI); diff --git a/src/Ai/Class/Dk/DKAiObjectContext.cpp b/src/Ai/Class/Dk/DKAiObjectContext.cpp index 85f8bc8cd..e8d7f2118 100644 --- a/src/Ai/Class/Dk/DKAiObjectContext.cpp +++ b/src/Ai/Class/Dk/DKAiObjectContext.cpp @@ -51,18 +51,6 @@ private: static Strategy* blood(PlayerbotAI* botAI) { return new BloodDKStrategy(botAI); } }; -class DeathKnightDKBuffStrategyFactoryInternal : public NamedObjectContext -{ -public: - DeathKnightDKBuffStrategyFactoryInternal() : NamedObjectContext(false, true) - { - creators["bdps"] = &DeathKnightDKBuffStrategyFactoryInternal::bdps; - } - -private: - static Strategy* bdps(PlayerbotAI* botAI) { return new DKBuffDpsStrategy(botAI); } -}; - class DeathKnightTriggerFactoryInternal : public NamedObjectContext { public: @@ -299,7 +287,6 @@ void DKAiObjectContext::BuildSharedStrategyContexts(SharedNamedObjectContextList AiObjectContext::BuildSharedStrategyContexts(strategyContexts); strategyContexts.Add(new DeathKnightStrategyFactoryInternal()); strategyContexts.Add(new DeathKnightCombatStrategyFactoryInternal()); - strategyContexts.Add(new DeathKnightDKBuffStrategyFactoryInternal()); } void DKAiObjectContext::BuildSharedActionContexts(SharedNamedObjectContextList& actionContexts) diff --git a/src/Ai/Class/Dk/Strategy/GenericDKNonCombatStrategy.cpp b/src/Ai/Class/Dk/Strategy/GenericDKNonCombatStrategy.cpp index 9bf2b54b1..a10d117f3 100644 --- a/src/Ai/Class/Dk/Strategy/GenericDKNonCombatStrategy.cpp +++ b/src/Ai/Class/Dk/Strategy/GenericDKNonCombatStrategy.cpp @@ -5,36 +5,9 @@ #include "GenericDKNonCombatStrategy.h" -class GenericDKNonCombatStrategyActionNodeFactory : public NamedObjectFactory -{ -public: - GenericDKNonCombatStrategyActionNodeFactory() - { - creators["bone shield"] = &bone_shield; - creators["horn of winter"] = &horn_of_winter; - } - -private: - static ActionNode* bone_shield([[maybe_unused]] PlayerbotAI* botAI) - { - return new ActionNode("bone shield", - /*P*/ {}, - /*A*/ {}, - /*C*/ {}); - } - - static ActionNode* horn_of_winter([[maybe_unused]] PlayerbotAI* botAI) - { - return new ActionNode("horn of winter", - /*P*/ {}, - /*A*/ {}, - /*C*/ {}); - } -}; - GenericDKNonCombatStrategy::GenericDKNonCombatStrategy(PlayerbotAI* botAI) : NonCombatStrategy(botAI) { - actionNodeFactories.Add(new GenericDKNonCombatStrategyActionNodeFactory()); + // No custom ActionNodeFactory needed } void GenericDKNonCombatStrategy::InitTriggers(std::vector& triggers) @@ -47,8 +20,3 @@ void GenericDKNonCombatStrategy::InitTriggers(std::vector& trigger triggers.push_back( new TriggerNode("bone shield", { NextAction("bone shield", 21.0f) })); } - -void DKBuffDpsStrategy::InitTriggers(std::vector& /*triggers*/) -{ - -} diff --git a/src/Ai/Class/Dk/Strategy/GenericDKNonCombatStrategy.h b/src/Ai/Class/Dk/Strategy/GenericDKNonCombatStrategy.h index 37e8c74bc..b7c3ad857 100644 --- a/src/Ai/Class/Dk/Strategy/GenericDKNonCombatStrategy.h +++ b/src/Ai/Class/Dk/Strategy/GenericDKNonCombatStrategy.h @@ -20,13 +20,4 @@ public: void InitTriggers(std::vector& triggers) override; }; -class DKBuffDpsStrategy : public Strategy -{ -public: - DKBuffDpsStrategy(PlayerbotAI* botAI) : Strategy(botAI) {} - - void InitTriggers(std::vector& triggers) override; - std::string const getName() override { return "bdps"; } -}; - #endif diff --git a/src/Ai/Class/Dk/Strategy/GenericDKStrategy.cpp b/src/Ai/Class/Dk/Strategy/GenericDKStrategy.cpp index 109341612..258dfad79 100644 --- a/src/Ai/Class/Dk/Strategy/GenericDKStrategy.cpp +++ b/src/Ai/Class/Dk/Strategy/GenericDKStrategy.cpp @@ -1,5 +1,6 @@ -#/* - * Copyright (C) 2016+ AzerothCore , released under GNU AGPL v3 license, you may redistribute it and/or modify it under version 3 of the License, or (at your option), any later version. +/* + * Copyright (C) 2016+ AzerothCore , released under GNU AGPL v3 license, you may redistribute it + * and/or modify it under version 3 of the License, or (at your option), any later version. */ #include "GenericDKStrategy.h" @@ -12,53 +13,12 @@ class GenericDKStrategyActionNodeFactory : public NamedObjectFactory public: GenericDKStrategyActionNodeFactory() { - // blood - // creators["rune tap"] = &rune_tap; cd - // creators["vampiric blood"] = &vampiric_blood; - // creators["death pact"] = &death_pact; - // creators["hysteria"] = &hysteria; boost party - // creators["dancing rune weapon"] = &dancing_rune_weapon; //cd - // creators["dark command"] = &dark_command; taunt - - // frost - // creators["chains of ice"] = &chains_of_ice; - // creators["icy clutch"] = &icy_clutch; - creators["horn of winter"] = &horn_of_winter; - creators["killing machine"] = &killing_machine; // buff - // creators["deathchill"] = &deathchill; //boost - creators["icebound fortitude"] = &icebound_fortitude; - // creators["mind freeze"] = &mind_freeze; interrupt - // creators["empower rune weapon"] = &empower_rune_weapon; boost - // creators["hungering cold"] = &hungering_cold; snare - // creators["unbreakable armor"] = &unbreakable_armor; boost +cd - // creators["improved icy talons"] = &improved_icy_talons; boost party - - // unholy - creators["death and decay"] = &death_and_decay; - // creators["raise dead"] = &raise_dead; - // creators["army of the dead"] = &army of the dead; - // creators["summon gargoyle"] = &army of the dead; - // creators["anti magic shell"] = &anti_magic_shell; cd + creators["killing machine"] = &killing_machine; creators["anti magic zone"] = &anti_magic_zone; - // creators["ghoul frenzy"] = &ghoul_frenzy; - creators["corpse explosion"] = &corpse_explosion; - creators["bone shield"] = &bone_shield; - creators["heart strike"] = &heart_strike; creators["death grip"] = &death_grip; - creators["plague strike"] = &plague_strike; - creators["pestilence"] = &pestilence; - creators["icy touch"] = &icy_touch; } private: - static ActionNode* death_coil([[maybe_unused]] PlayerbotAI* botAI) - { - return new ActionNode("death coil", - /*P*/ {}, - /*A*/ {}, - /*C*/ {}); - } - static ActionNode* death_grip([[maybe_unused]] PlayerbotAI* botAI) { return new ActionNode("death grip", @@ -67,54 +27,6 @@ private: /*C*/ {}); } - static ActionNode* plague_strike([[maybe_unused]] PlayerbotAI* botAI) - { - return new ActionNode("plague strike", - /*P*/ {}, - /*A*/ {}, - /*C*/ {}); - } - - static ActionNode* icy_touch([[maybe_unused]] PlayerbotAI* botAI) - { - return new ActionNode("icy touch", - /*P*/ {}, - /*A*/ {}, - /*C*/ {}); - } - - static ActionNode* heart_strike([[maybe_unused]] PlayerbotAI* botAI) - { - return new ActionNode("heart strike", - /*P*/ {}, - /*A*/ {}, - /*C*/ {}); - } - - static ActionNode* pestilence([[maybe_unused]] PlayerbotAI* botAI) - { - return new ActionNode("pestilence", - /*P*/ {}, - /*A*/ {}, - /*C*/ {}); - } - - static ActionNode* horn_of_winter([[maybe_unused]] PlayerbotAI* botAI) - { - return new ActionNode("horn of winter", - /*P*/ {}, - /*A*/ {}, - /*C*/ {}); - } - - static ActionNode* bone_shield([[maybe_unused]] PlayerbotAI* botAI) - { - return new ActionNode("bone shield", - /*P*/ {}, - /*A*/ {}, - /*C*/ {}); - } - static ActionNode* killing_machine([[maybe_unused]] PlayerbotAI* botAI) { return new ActionNode("killing machine", @@ -123,22 +35,6 @@ private: /*C*/ {}); } - static ActionNode* corpse_explosion([[maybe_unused]] PlayerbotAI* botAI) - { - return new ActionNode("corpse explosion", - /*P*/ {}, - /*A*/ {}, - /*C*/ {}); - } - - static ActionNode* death_and_decay([[maybe_unused]] PlayerbotAI* botAI) - { - return new ActionNode("death and decay", - /*P*/ {}, - /*A*/ {}, - /*C*/ {}); - } - static ActionNode* anti_magic_zone([[maybe_unused]] PlayerbotAI* botAI) { return new ActionNode("anti magic zone", @@ -146,14 +42,6 @@ private: /*A*/ { NextAction("anti magic shell") }, /*C*/ {}); } - - static ActionNode* icebound_fortitude([[maybe_unused]] PlayerbotAI* botAI) - { - return new ActionNode("icebound fortitude", - /*P*/ {}, - /*A*/ {}, - /*C*/ {}); - } }; GenericDKStrategy::GenericDKStrategy(PlayerbotAI* botAI) : MeleeCombatStrategy(botAI) diff --git a/src/Ai/Class/Dk/Strategy/UnholyDKStrategy.cpp b/src/Ai/Class/Dk/Strategy/UnholyDKStrategy.cpp index 40a0ac041..d7c321f35 100644 --- a/src/Ai/Class/Dk/Strategy/UnholyDKStrategy.cpp +++ b/src/Ai/Class/Dk/Strategy/UnholyDKStrategy.cpp @@ -1,5 +1,6 @@ /* - * Copyright (C) 2016+ AzerothCore , released under GNU AGPL v3 license, you may redistribute it and/or modify it under version 3 of the License, or (at your option), any later version. + * Copyright (C) 2016+ AzerothCore , released under GNU AGPL v3 license, you may redistribute it + * and/or modify it under version 3 of the License, or (at your option), any later version. */ #include "UnholyDKStrategy.h" diff --git a/src/Ai/Class/Druid/Strategy/BearDruidStrategy.cpp b/src/Ai/Class/Druid/Strategy/BearDruidStrategy.cpp index 418f057cd..b848a4595 100644 --- a/src/Ai/Class/Druid/Strategy/BearDruidStrategy.cpp +++ b/src/Ai/Class/Druid/Strategy/BearDruidStrategy.cpp @@ -13,16 +13,11 @@ public: BearDruidStrategyActionNodeFactory() { creators["feral charge - bear"] = &feral_charge_bear; - creators["swipe (bear)"] = &swipe_bear; - creators["bear form"] = &bear_form; creators["dire bear form"] = &dire_bear_form; - creators["mangle (bear)"] = &mangle_bear; creators["maul"] = &maul; creators["bash"] = &bash; creators["swipe"] = &swipe; creators["lacerate"] = &lacerate; - creators["demoralizing roar"] = &demoralizing_roar; - creators["taunt spell"] = &growl; } private: @@ -36,26 +31,6 @@ private: ); } - static ActionNode* swipe_bear([[maybe_unused]] PlayerbotAI* botAI) - { - return new ActionNode( - "swipe (bear)", - /*P*/ {}, - /*A*/ {}, - /*C*/ {} - ); - } - - static ActionNode* bear_form([[maybe_unused]] PlayerbotAI* botAI) - { - return new ActionNode( - "bear form", - /*P*/ {}, - /*A*/ {}, - /*C*/ {} - ); - } - static ActionNode* dire_bear_form([[maybe_unused]] PlayerbotAI* botAI) { return new ActionNode( @@ -66,16 +41,6 @@ private: ); } - static ActionNode* mangle_bear([[maybe_unused]] PlayerbotAI* botAI) - { - return new ActionNode( - "mangle (bear)", - /*P*/ {}, - /*A*/ {}, - /*C*/ {} - ); - } - static ActionNode* maul([[maybe_unused]] PlayerbotAI* botAI) { return new ActionNode( @@ -115,26 +80,6 @@ private: /*C*/ {} ); } - - static ActionNode* growl([[maybe_unused]] PlayerbotAI* botAI) - { - return new ActionNode( - "growl", - /*P*/ {}, - /*A*/ {}, - /*C*/ {} - ); - } - - static ActionNode* demoralizing_roar([[maybe_unused]] PlayerbotAI* botAI) - { - return new ActionNode( - "demoralizing roar", - /*P*/ {}, - /*A*/ {}, - /*C*/ {} - ); - } }; BearDruidStrategy::BearDruidStrategy(PlayerbotAI* botAI) : FeralDruidStrategy(botAI) diff --git a/src/Ai/Class/Druid/Strategy/CatDruidStrategy.cpp b/src/Ai/Class/Druid/Strategy/CatDruidStrategy.cpp index df6ba4a92..151eda277 100644 --- a/src/Ai/Class/Druid/Strategy/CatDruidStrategy.cpp +++ b/src/Ai/Class/Druid/Strategy/CatDruidStrategy.cpp @@ -12,41 +12,15 @@ class CatDruidStrategyActionNodeFactory : public NamedObjectFactory public: CatDruidStrategyActionNodeFactory() { - creators["faerie fire (feral)"] = &faerie_fire_feral; - creators["melee"] = &melee; creators["feral charge - cat"] = &feral_charge_cat; creators["cat form"] = &cat_form; creators["claw"] = &claw; - creators["mangle (cat)"] = &mangle_cat; - creators["rake"] = &rake; - creators["ferocious bite"] = &ferocious_bite; - creators["rip"] = &rip; creators["pounce"] = &pounce; creators["ravage"] = &ravage; creators["prowl"] = &prowl; } private: - static ActionNode* faerie_fire_feral([[maybe_unused]] PlayerbotAI* botAI) - { - return new ActionNode( - "faerie fire (feral)", - /*P*/ {}, - /*A*/ {}, - /*C*/ {} - ); - } - - static ActionNode* melee([[maybe_unused]] PlayerbotAI* botAI) - { - return new ActionNode( - "melee", - /*P*/ {}, - /*A*/ {}, - /*C*/ {} - ); - } - static ActionNode* feral_charge_cat([[maybe_unused]] PlayerbotAI* botAI) { return new ActionNode( @@ -77,46 +51,6 @@ private: ); } - static ActionNode* mangle_cat([[maybe_unused]] PlayerbotAI* botAI) - { - return new ActionNode( - "mangle (cat)", - /*P*/ {}, - /*A*/ {}, - /*C*/ {} - ); - } - - static ActionNode* rake([[maybe_unused]] PlayerbotAI* botAI) - { - return new ActionNode( - "rake", - /*P*/ {}, - /*A*/ {}, - /*C*/ {} - ); - } - - static ActionNode* ferocious_bite([[maybe_unused]] PlayerbotAI* botAI) - { - return new ActionNode( - "ferocious bite", - /*P*/ {}, - /*A*/ {}, - /*C*/ {} - ); - } - - static ActionNode* rip([[maybe_unused]] PlayerbotAI* botAI) - { - return new ActionNode( - "rip", - /*P*/ {}, - /*A*/ {}, - /*C*/ {} - ); - } - static ActionNode* ravage([[maybe_unused]] PlayerbotAI* botAI) { return new ActionNode( @@ -146,7 +80,6 @@ private: /*C*/ {} ); } - }; CatDruidStrategy::CatDruidStrategy(PlayerbotAI* botAI) : FeralDruidStrategy(botAI) diff --git a/src/Ai/Class/Druid/Strategy/GenericDruidNonCombatStrategy.cpp b/src/Ai/Class/Druid/Strategy/GenericDruidNonCombatStrategy.cpp index 0977540f6..b125a9dba 100644 --- a/src/Ai/Class/Druid/Strategy/GenericDruidNonCombatStrategy.cpp +++ b/src/Ai/Class/Druid/Strategy/GenericDruidNonCombatStrategy.cpp @@ -109,7 +109,6 @@ private: /*A*/ {}, /*C*/ {}); } - }; GenericDruidNonCombatStrategy::GenericDruidNonCombatStrategy(PlayerbotAI* botAI) : NonCombatStrategy(botAI) diff --git a/src/Ai/Class/Druid/Strategy/GenericDruidStrategy.cpp b/src/Ai/Class/Druid/Strategy/GenericDruidStrategy.cpp index d5e7b9f40..5895ac027 100644 --- a/src/Ai/Class/Druid/Strategy/GenericDruidStrategy.cpp +++ b/src/Ai/Class/Druid/Strategy/GenericDruidStrategy.cpp @@ -14,76 +14,12 @@ class GenericDruidStrategyActionNodeFactory : public NamedObjectFactory -{ -public: - RestoDruidStrategyActionNodeFactory() { - creators["nourish on party"] = &nourish_on_party; - } - -private: - static ActionNode* nourish_on_party([[maybe_unused]] PlayerbotAI* botAI) - { - return new ActionNode("nourish on party", - /*P*/ {}, - /*A*/ {}, - /*C*/ {}); - } -}; - RestoDruidStrategy::RestoDruidStrategy(PlayerbotAI* botAI) : GenericDruidStrategy(botAI) { - actionNodeFactories.Add(new RestoDruidStrategyActionNodeFactory()); + // No custom ActionNodeFactory needed } void RestoDruidStrategy::InitTriggers(std::vector& triggers) diff --git a/src/Ai/Class/Mage/Strategy/GenericMageStrategy.cpp b/src/Ai/Class/Mage/Strategy/GenericMageStrategy.cpp index 36b594ce9..9277cb651 100644 --- a/src/Ai/Class/Mage/Strategy/GenericMageStrategy.cpp +++ b/src/Ai/Class/Mage/Strategy/GenericMageStrategy.cpp @@ -28,7 +28,6 @@ public: creators["frostbolt"] = &frostbolt; creators["frostfire bolt"] = &frostfire_bolt; creators["scorch"] = &scorch; - creators["evocation"] = &evocation; creators["remove curse"] = &remove_curse; creators["remove curse on party"] = &remove_curse_on_party; creators["fireball"] = &fireball; @@ -59,14 +58,6 @@ private: /*C*/ {}); } - static ActionNode* evocation([[maybe_unused]] PlayerbotAI* botAI) - { - return new ActionNode("evocation", - /*P*/ {}, - /*A*/ { NextAction("mana potion") }, - /*C*/ {}); - } - static ActionNode* remove_curse([[maybe_unused]] PlayerbotAI* botAI) { return new ActionNode("remove curse", @@ -127,7 +118,6 @@ void GenericMageStrategy::InitTriggers(std::vector& triggers) else if (bot->HasSpell(SPELL_CONJURE_MANA_AGATE)) triggers.push_back(new TriggerNode("high mana", { NextAction("use mana agate", 90.0f) })); - triggers.push_back(new TriggerNode("medium mana", { NextAction("mana potion", 90.0f) })); triggers.push_back(new TriggerNode("low mana", { NextAction("evocation", 90.0f) })); // Counterspell / Spellsteal Triggers diff --git a/src/Ai/Class/Paladin/Strategy/DpsPaladinStrategy.cpp b/src/Ai/Class/Paladin/Strategy/DpsPaladinStrategy.cpp index fc6ae92a0..6598bc9da 100644 --- a/src/Ai/Class/Paladin/Strategy/DpsPaladinStrategy.cpp +++ b/src/Ai/Class/Paladin/Strategy/DpsPaladinStrategy.cpp @@ -16,7 +16,6 @@ public: creators["sanctity aura"] = &sanctity_aura; creators["retribution aura"] = &retribution_aura; creators["blessing of might"] = &blessing_of_might; - creators["crusader strike"] = &crusader_strike; creators["repentance"] = &repentance; creators["repentance on enemy healer"] = &repentance_on_enemy_healer; creators["repentance on snare target"] = &repentance_on_snare_target; @@ -34,16 +33,6 @@ private: ); } - static ActionNode* crusader_strike([[maybe_unused]] PlayerbotAI* botAI) - { - return new ActionNode( - "crusader strike", - /*P*/ {}, - /*A*/ {}, - /*C*/ {} - ); - } - static ActionNode* repentance([[maybe_unused]] PlayerbotAI* botAI) { return new ActionNode( diff --git a/src/Ai/Class/Paladin/Strategy/GenericPaladinStrategy.cpp b/src/Ai/Class/Paladin/Strategy/GenericPaladinStrategy.cpp index 315b4a96f..b258c5b9d 100644 --- a/src/Ai/Class/Paladin/Strategy/GenericPaladinStrategy.cpp +++ b/src/Ai/Class/Paladin/Strategy/GenericPaladinStrategy.cpp @@ -56,7 +56,6 @@ void PaladinCureStrategy::InitTriggers(std::vector& triggers) void PaladinBoostStrategy::InitTriggers(std::vector& /*triggers*/) { - // triggers.push_back(new TriggerNode("divine favor", { NextAction("divine favor", // ACTION_HIGH + 1) })); } diff --git a/src/Ai/Class/Paladin/Strategy/GenericPaladinStrategyActionNodeFactory.h b/src/Ai/Class/Paladin/Strategy/GenericPaladinStrategyActionNodeFactory.h index 1ac76dbd2..d73fcaabf 100644 --- a/src/Ai/Class/Paladin/Strategy/GenericPaladinStrategyActionNodeFactory.h +++ b/src/Ai/Class/Paladin/Strategy/GenericPaladinStrategyActionNodeFactory.h @@ -16,10 +16,8 @@ class GenericPaladinStrategyActionNodeFactory : public NamedObjectFactory -{ -}; - HealPaladinStrategy::HealPaladinStrategy(PlayerbotAI* botAI) : GenericPaladinStrategy(botAI) { - actionNodeFactories.Add(new HealPaladinStrategyActionNodeFactory()); + // No custom ActionNodeFactory needed } std::vector HealPaladinStrategy::getDefaultActions() diff --git a/src/Ai/Class/Paladin/Strategy/OffhealRetPaladinStrategy.cpp b/src/Ai/Class/Paladin/Strategy/OffhealRetPaladinStrategy.cpp index b25fc36b3..239882e13 100644 --- a/src/Ai/Class/Paladin/Strategy/OffhealRetPaladinStrategy.cpp +++ b/src/Ai/Class/Paladin/Strategy/OffhealRetPaladinStrategy.cpp @@ -18,8 +18,6 @@ public: 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["divine plea"] = &divine_plea; } private: @@ -72,26 +70,6 @@ private: /*C*/ {} ); } - - static ActionNode* crusader_strike([[maybe_unused]] PlayerbotAI* botAI) - { - return new ActionNode( - "crusader strike", - /*P*/ {}, - /*A*/ {}, - /*C*/ {} - ); - } - - static ActionNode* divine_plea([[maybe_unused]] PlayerbotAI* botAI) - { - return new ActionNode( - "divine plea", - /*P*/ {}, - /*A*/ {}, - /*C*/ {} - ); - } }; OffhealRetPaladinStrategy::OffhealRetPaladinStrategy(PlayerbotAI* botAI) : GenericPaladinStrategy(botAI) diff --git a/src/Ai/Class/Priest/Strategy/GenericPriestStrategyActionNodeFactory.h b/src/Ai/Class/Priest/Strategy/GenericPriestStrategyActionNodeFactory.h index ab6a0c2ba..904c39696 100644 --- a/src/Ai/Class/Priest/Strategy/GenericPriestStrategyActionNodeFactory.h +++ b/src/Ai/Class/Priest/Strategy/GenericPriestStrategyActionNodeFactory.h @@ -21,7 +21,6 @@ public: creators["divine spirit"] = &divine_spirit; creators["divine spirit on party"] = &divine_spirit_on_party; creators["power word: shield"] = &power_word_shield; - // creators["power word: shield on party"] = &power_word_shield_on_party; creators["renew"] = &renew; creators["renew on party"] = &renew_on_party; creators["greater heal"] = &greater_heal; @@ -33,8 +32,6 @@ public: creators["flash heal"] = &flash_heal; creators["flash heal on party"] = &flash_heal_on_party; creators["psychic scream"] = &psychic_scream; - // creators["fade"] = &fade; - creators["shadowfiend"] = &shadowfiend; } private: @@ -210,16 +207,6 @@ private: /*C*/ {} ); } - - static ActionNode* shadowfiend([[maybe_unused]] PlayerbotAI* botAI) - { - return new ActionNode( - "shadowfiend", - /*P*/ {}, - /*A*/ {}, - /*C*/ {} - ); - } }; class CurePriestStrategyActionNodeFactory : public NamedObjectFactory diff --git a/src/Ai/Class/Priest/Strategy/ShadowPriestStrategyActionNodeFactory.h b/src/Ai/Class/Priest/Strategy/ShadowPriestStrategyActionNodeFactory.h index 4efcc6f6a..27528be68 100644 --- a/src/Ai/Class/Priest/Strategy/ShadowPriestStrategyActionNodeFactory.h +++ b/src/Ai/Class/Priest/Strategy/ShadowPriestStrategyActionNodeFactory.h @@ -17,7 +17,6 @@ public: ShadowPriestStrategyActionNodeFactory() { creators["mind blast"] = &mind_blast; - creators["dispersion"] = &dispersion; creators["mind flay"] = &mind_flay; creators["smite"] = &smite; } @@ -47,13 +46,6 @@ private: /*C*/ {}); } - static ActionNode* dispersion([[maybe_unused]] PlayerbotAI* botAI) - { - return new ActionNode("dispersion", - /*P*/ {}, - /*A*/ { NextAction("mana potion") }, - /*C*/ {}); - } }; #endif diff --git a/src/Ai/Class/Rogue/Strategy/DpsRogueStrategy.cpp b/src/Ai/Class/Rogue/Strategy/DpsRogueStrategy.cpp index 06aeda57c..0c3405b94 100644 --- a/src/Ai/Class/Rogue/Strategy/DpsRogueStrategy.cpp +++ b/src/Ai/Class/Rogue/Strategy/DpsRogueStrategy.cpp @@ -14,7 +14,6 @@ public: { creators["sinister strike"] = &sinister_strike; creators["kick"] = &kick; - creators["kidney shot"] = &kidney_shot; creators["backstab"] = &backstab; creators["rupture"] = &rupture; } @@ -40,15 +39,6 @@ private: /*C*/ {} ); } - static ActionNode* kidney_shot([[maybe_unused]] PlayerbotAI* botAI) - { - return new ActionNode( - "kidney shot", - /*P*/ {}, - /*A*/ {}, - /*C*/ {} - ); - } static ActionNode* backstab([[maybe_unused]] PlayerbotAI* botAI) { return new ActionNode( @@ -235,9 +225,6 @@ public: StealthedRogueStrategyActionNodeFactory() { creators["ambush"] = &ambush; - creators["cheap shot"] = &cheap_shot; - creators["garrote"] = &garrote; - creators["sap"] = &sap; creators["sinister strike"] = &sinister_strike; } @@ -252,36 +239,6 @@ private: ); } - static ActionNode* cheap_shot([[maybe_unused]] PlayerbotAI* botAI) - { - return new ActionNode( - "cheap shot", - /*P*/ {}, - /*A*/ {}, - /*C*/ {} - ); - } - - static ActionNode* garrote([[maybe_unused]] PlayerbotAI* botAI) - { - return new ActionNode( - "garrote", - /*P*/ {}, - /*A*/ {}, - /*C*/ {} - ); - } - - static ActionNode* sap([[maybe_unused]] PlayerbotAI* botAI) - { - return new ActionNode( - "sap", - /*P*/ {}, - /*A*/ {}, - /*C*/ {} - ); - } - static ActionNode* sinister_strike([[maybe_unused]] PlayerbotAI* botAI) { return new ActionNode( diff --git a/src/Ai/Class/Warlock/Strategy/AfflictionWarlockStrategy.cpp b/src/Ai/Class/Warlock/Strategy/AfflictionWarlockStrategy.cpp index 78da04d99..93db05762 100644 --- a/src/Ai/Class/Warlock/Strategy/AfflictionWarlockStrategy.cpp +++ b/src/Ai/Class/Warlock/Strategy/AfflictionWarlockStrategy.cpp @@ -6,45 +6,9 @@ #include "AfflictionWarlockStrategy.h" #include "Playerbots.h" -// ===== Action Node Factory ===== -class AfflictionWarlockStrategyActionNodeFactory : public NamedObjectFactory -{ -public: - AfflictionWarlockStrategyActionNodeFactory() - { - creators["corruption"] = &corruption; - creators["corruption on attacker"] = &corruption; - creators["unstable affliction"] = &unstable_affliction; - creators["unstable affliction on attacker"] = &unstable_affliction; - creators["haunt"] = &haunt; - creators["shadow bolt"] = &shadow_bolt; - creators["drain soul"] = &drain_soul; - creators["life tap"] = &life_tap; - creators["shadowflame"] = &shadowflame; - creators["seed of corruption on attacker"] = &seed_of_corruption; - creators["seed of corruption"] = &seed_of_corruption; - creators["rain of fire"] = &rain_of_fire; - } - -private: - static ActionNode* corruption(PlayerbotAI*) { return new ActionNode("corruption", {}, {}, {}); } - static ActionNode* corruption_on_attacker(PlayerbotAI*) { return new ActionNode("corruption on attacker", {}, {}, {}); } - static ActionNode* unstable_affliction(PlayerbotAI*) { return new ActionNode("unstable affliction", {}, {}, {}); } - static ActionNode* unstable_affliction_on_attacker(PlayerbotAI*) { return new ActionNode("unstable affliction on attacker", {}, {}, {}); } - static ActionNode* haunt(PlayerbotAI*) { return new ActionNode("haunt", {}, {}, {}); } - static ActionNode* shadow_bolt(PlayerbotAI*) { return new ActionNode("shadow bolt", {}, {}, {}); } - static ActionNode* drain_soul(PlayerbotAI*) { return new ActionNode("drain soul", {}, {}, {}); } - static ActionNode* life_tap(PlayerbotAI*) { return new ActionNode("life tap", {}, {}, {}); } - static ActionNode* shadowflame(PlayerbotAI*) { return new ActionNode("shadowflame", {}, {}, {}); } - static ActionNode* seed_of_corruption_on_attacker(PlayerbotAI*) { return new ActionNode("seed of corruption on attacker", {}, {}, {}); } - static ActionNode* seed_of_corruption(PlayerbotAI*) { return new ActionNode("seed of corruption", {}, {}, {}); } - static ActionNode* rain_of_fire(PlayerbotAI*) { return new ActionNode("rain of fire", {}, {}, {}); } -}; - -// ===== Single Target Strategy ===== AfflictionWarlockStrategy::AfflictionWarlockStrategy(PlayerbotAI* botAI) : GenericWarlockStrategy(botAI) { - actionNodeFactories.Add(new AfflictionWarlockStrategyActionNodeFactory()); + // No custom ActionNodeFactory needed } // ===== Default Actions ===== diff --git a/src/Ai/Class/Warlock/Strategy/DemonologyWarlockStrategy.cpp b/src/Ai/Class/Warlock/Strategy/DemonologyWarlockStrategy.cpp index 6bb4e9de5..c8d68523a 100644 --- a/src/Ai/Class/Warlock/Strategy/DemonologyWarlockStrategy.cpp +++ b/src/Ai/Class/Warlock/Strategy/DemonologyWarlockStrategy.cpp @@ -6,53 +6,9 @@ #include "DemonologyWarlockStrategy.h" #include "Playerbots.h" -// ===== Action Node Factory ===== -class DemonologyWarlockStrategyActionNodeFactory : public NamedObjectFactory -{ -public: - DemonologyWarlockStrategyActionNodeFactory() - { - creators["metamorphosis"] = &metamorphosis; - creators["demonic empowerment"] = &demonic_empowerment; - creators["corruption"] = &corruption; - creators["corruption on attacker"] = &corruption_on_attacker; - creators["immolate"] = &immolate; - creators["immolate on attacker"] = &immolate_on_attacker; - creators["incinerate"] = &incinerate; - creators["soul fire"] = &soul_fire; - creators["shadow bolt"] = &shadow_bolt; - creators["life tap"] = &life_tap; - creators["immolation aura"] = &immolation_aura; - creators["shadowflame"] = &shadowflame; - creators["seed of corruption on attacker"] = &seed_of_corruption_on_attacker; - creators["seed of corruption"] = &seed_of_corruption; - creators["rain of fire"] = &rain_of_fire; - creators["demon charge"] = &demon_charge; - } - -private: - static ActionNode* metamorphosis(PlayerbotAI*) { return new ActionNode("metamorphosis", {}, {}, {}); } - static ActionNode* demonic_empowerment(PlayerbotAI*) { return new ActionNode("demonic empowerment", {}, {}, {}); } - static ActionNode* corruption(PlayerbotAI*) { return new ActionNode("corruption", {}, {}, {}); } - static ActionNode* corruption_on_attacker(PlayerbotAI*) { return new ActionNode("corruption on attacker", {}, {}, {}); } - static ActionNode* immolate(PlayerbotAI*) { return new ActionNode("immolate", {}, {}, {}); } - static ActionNode* immolate_on_attacker(PlayerbotAI*) { return new ActionNode("immolate on attacker", {}, {}, {}); } - static ActionNode* incinerate(PlayerbotAI*) { return new ActionNode("incinerate", {}, {}, {}); } - static ActionNode* soul_fire(PlayerbotAI*) { return new ActionNode("soul fire", {}, {}, {}); } - static ActionNode* shadow_bolt(PlayerbotAI*) { return new ActionNode("shadow bolt", {}, {}, {}); } - static ActionNode* life_tap(PlayerbotAI*) { return new ActionNode("life tap", {}, {}, {}); } - static ActionNode* immolation_aura(PlayerbotAI*) { return new ActionNode("immolation aura", {}, {}, {}); } - static ActionNode* shadowflame(PlayerbotAI*) { return new ActionNode("shadowflame", {}, {}, {}); } - static ActionNode* seed_of_corruption_on_attacker(PlayerbotAI*) { return new ActionNode("seed of corruption on attacker", {}, {}, {}); } - static ActionNode* seed_of_corruption(PlayerbotAI*) { return new ActionNode("seed of corruption", {}, {}, {}); } - static ActionNode* rain_of_fire(PlayerbotAI*) { return new ActionNode("rain of fire", {}, {}, {}); } - static ActionNode* demon_charge(PlayerbotAI*) { return new ActionNode("demon charge", {}, {}, {}); } -}; - -// ===== Single Target Strategy ===== DemonologyWarlockStrategy::DemonologyWarlockStrategy(PlayerbotAI* botAI) : GenericWarlockStrategy(botAI) { - actionNodeFactories.Add(new DemonologyWarlockStrategyActionNodeFactory()); + // No custom ActionNodeFactory needed } // ===== Default Actions ===== diff --git a/src/Ai/Class/Warlock/Strategy/DestructionWarlockStrategy.cpp b/src/Ai/Class/Warlock/Strategy/DestructionWarlockStrategy.cpp index af44de01c..2bbb32255 100644 --- a/src/Ai/Class/Warlock/Strategy/DestructionWarlockStrategy.cpp +++ b/src/Ai/Class/Warlock/Strategy/DestructionWarlockStrategy.cpp @@ -6,49 +6,9 @@ #include "DestructionWarlockStrategy.h" #include "Playerbots.h" -// ===== Action Node Factory ===== -class DestructionWarlockStrategyActionNodeFactory : public NamedObjectFactory -{ -public: - DestructionWarlockStrategyActionNodeFactory() - { - creators["immolate"] = &immolate; - creators["conflagrate"] = &conflagrate; - creators["chaos bolt"] = &chaos_bolt; - creators["incinerate"] = &incinerate; - creators["corruption"] = &corruption; - creators["corruption on attacker"] = &corruption_on_attacker; - creators["shadow bolt"] = &shadow_bolt; - creators["shadowburn"] = &shadowburn; - creators["life tap"] = &life_tap; - creators["shadowfury"] = &shadowfury; - creators["shadowflame"] = &shadowflame; - creators["seed of corruption"] = &seed_of_corruption; - creators["seed of corruption on attacker"] = &seed_of_corruption; - creators["rain of fire"] = &rain_of_fire; - } - -private: - static ActionNode* immolate(PlayerbotAI*) { return new ActionNode("immolate", {}, {}, {}); } - static ActionNode* conflagrate(PlayerbotAI*) { return new ActionNode("conflagrate", {}, {}, {}); } - static ActionNode* chaos_bolt(PlayerbotAI*) { return new ActionNode("chaos bolt", {}, {}, {}); } - static ActionNode* incinerate(PlayerbotAI*) { return new ActionNode("incinerate", {}, {}, {}); } - static ActionNode* corruption(PlayerbotAI*) { return new ActionNode("corruption", {}, {}, {}); } - static ActionNode* corruption_on_attacker(PlayerbotAI*) { return new ActionNode("corruption on attacker", {}, {}, {}); } - static ActionNode* shadow_bolt(PlayerbotAI*) { return new ActionNode("shadow bolt", {}, {}, {}); } - static ActionNode* shadowburn(PlayerbotAI*) { return new ActionNode("shadowburn", {}, {}, {}); } - static ActionNode* life_tap(PlayerbotAI*) { return new ActionNode("life tap", {}, {}, {}); } - static ActionNode* shadowfury(PlayerbotAI*) { return new ActionNode("shadowfury", {}, {}, {}); } - static ActionNode* shadowflame(PlayerbotAI*) { return new ActionNode("shadowflame", {}, {}, {}); } - static ActionNode* seed_of_corruption(PlayerbotAI*) { return new ActionNode("seed of corruption", {}, {}, {}); } - static ActionNode* seed_of_corruption_on_attacker(PlayerbotAI*) { return new ActionNode("seed of corruption on attacker", {}, {}, {}); } - static ActionNode* rain_of_fire(PlayerbotAI*) { return new ActionNode("rain of fire", {}, {}, {}); } -}; - -// ===== Single Target Strategy ===== DestructionWarlockStrategy::DestructionWarlockStrategy(PlayerbotAI* botAI) : GenericWarlockStrategy(botAI) { - actionNodeFactories.Add(new DestructionWarlockStrategyActionNodeFactory()); + // No custom ActionNodeFactory needed } // ===== Default Actions ===== diff --git a/src/Ai/Class/Warlock/Strategy/GenericWarlockStrategy.cpp b/src/Ai/Class/Warlock/Strategy/GenericWarlockStrategy.cpp index d5e06b54c..15fd1d57a 100644 --- a/src/Ai/Class/Warlock/Strategy/GenericWarlockStrategy.cpp +++ b/src/Ai/Class/Warlock/Strategy/GenericWarlockStrategy.cpp @@ -5,29 +5,9 @@ #include "GenericWarlockStrategy.h" -class GenericWarlockStrategyActionNodeFactory : public NamedObjectFactory -{ -public: - GenericWarlockStrategyActionNodeFactory() - { - creators["banish on cc"] = &banish_on_cc; - creators["fear on cc"] = &fear_on_cc; - creators["spell lock"] = &spell_lock; - creators["devour magic purge"] = &devour_magic_purge; - creators["devour magic cleanse"] = &devour_magic_cleanse; - } - -private: - static ActionNode* banish_on_cc(PlayerbotAI*) { return new ActionNode("banish on cc", {}, {}, {}); } - static ActionNode* fear_on_cc(PlayerbotAI*) { return new ActionNode("fear on cc", {}, {}, {}); } - static ActionNode* spell_lock(PlayerbotAI*) { return new ActionNode("spell lock", {}, {}, {}); } - static ActionNode* devour_magic_purge(PlayerbotAI*) { return new ActionNode("devour magic purge", {}, {}, {}); } - static ActionNode* devour_magic_cleanse(PlayerbotAI*) { return new ActionNode("devour magic cleanse", {}, {}, {}); } -}; - GenericWarlockStrategy::GenericWarlockStrategy(PlayerbotAI* botAI) : CombatStrategy(botAI) { - actionNodeFactories.Add(new GenericWarlockStrategyActionNodeFactory()); + // No custom ActionNodeFactory needed } std::vector GenericWarlockStrategy::getDefaultActions() diff --git a/src/Ai/Class/Warlock/Strategy/TankWarlockStrategy.cpp b/src/Ai/Class/Warlock/Strategy/TankWarlockStrategy.cpp index ce10e6b9c..6e3c6cdcc 100644 --- a/src/Ai/Class/Warlock/Strategy/TankWarlockStrategy.cpp +++ b/src/Ai/Class/Warlock/Strategy/TankWarlockStrategy.cpp @@ -5,36 +5,13 @@ #include "TankWarlockStrategy.h" -// Combat strategy for a Warlock Tank, for certain bosses like Twin Emperors -// Priority is set to spam Searing Pain and use Shadow Ward on CD -// Disabled by default -// To enable, type "co +tank" -// To disable, type "co -tank" - -// ===== Action Node Factory ===== -class TankWarlockStrategyActionNodeFactory : public NamedObjectFactory -{ -public: - TankWarlockStrategyActionNodeFactory() - { - creators["shadow ward"] = &shadow_ward; - creators["searing pain"] = &searing_pain; - } - -private: - static ActionNode* shadow_ward(PlayerbotAI*) { return new ActionNode("shadow ward", {}, {}, {}); } - static ActionNode* searing_pain(PlayerbotAI*) { return new ActionNode("searing pain", {}, {}, {}); } -}; - -// ===== Warlock Tank Combat Strategy ===== TankWarlockStrategy::TankWarlockStrategy(PlayerbotAI* botAI) : GenericWarlockStrategy(botAI) { - actionNodeFactories.Add(new TankWarlockStrategyActionNodeFactory()); + // No custom ActionNodeFactory needed } std::vector TankWarlockStrategy::getDefaultActions() { - // Shadow Ward is the highest priority, Searing Pain next. return { NextAction("shadow ward", 27.5f), NextAction("searing pain", 27.0f) diff --git a/src/Ai/Class/Warrior/Strategy/ArmsWarriorStrategy.cpp b/src/Ai/Class/Warrior/Strategy/ArmsWarriorStrategy.cpp index 193aab1d7..4addfa054 100644 --- a/src/Ai/Class/Warrior/Strategy/ArmsWarriorStrategy.cpp +++ b/src/Ai/Class/Warrior/Strategy/ArmsWarriorStrategy.cpp @@ -15,9 +15,6 @@ public: creators["piercing howl"] = &piercing_howl; creators["mocking blow"] = &mocking_blow; creators["heroic strike"] = &heroic_strike; - creators["enraged regeneration"] = &enraged_regeneration; - creators["retaliation"] = &retaliation; - creators["shattering throw"] = &shattering_throw; } private: @@ -70,36 +67,6 @@ private: /*C*/ {} ); } - - static ActionNode* enraged_regeneration(PlayerbotAI* /*botAI*/) - { - return new ActionNode( - "enraged regeneration", - /*P*/ {}, - /*A*/ {}, - /*C*/ {} - ); - } - - static ActionNode* retaliation(PlayerbotAI* /*botAI*/) - { - return new ActionNode( - "retaliation", - /*P*/ {}, - /*A*/ {}, - /*C*/ {} - ); - } - - static ActionNode* shattering_throw(PlayerbotAI* /*botAI*/) - { - return new ActionNode( - "shattering throw", - /*P*/ {}, - /*A*/ {}, - /*C*/ {} - ); - } }; ArmsWarriorStrategy::ArmsWarriorStrategy(PlayerbotAI* botAI) : GenericWarriorStrategy(botAI) diff --git a/src/Ai/Class/Warrior/Strategy/FuryWarriorStrategy.cpp b/src/Ai/Class/Warrior/Strategy/FuryWarriorStrategy.cpp index 24e05ffe9..c1999473f 100644 --- a/src/Ai/Class/Warrior/Strategy/FuryWarriorStrategy.cpp +++ b/src/Ai/Class/Warrior/Strategy/FuryWarriorStrategy.cpp @@ -14,7 +14,6 @@ public: creators["intercept"] = &intercept; creators["piercing howl"] = &piercing_howl; creators["pummel"] = &pummel; - creators["enraged regeneration"] = &enraged_regeneration; } private: @@ -57,16 +56,6 @@ private: /*C*/ {} ); } - - static ActionNode* enraged_regeneration(PlayerbotAI* /*botAI*/) - { - return new ActionNode( - "enraged regeneration", - /*P*/ {}, - /*A*/ {}, - /*C*/ {} - ); - } }; FuryWarriorStrategy::FuryWarriorStrategy(PlayerbotAI* botAI) : GenericWarriorStrategy(botAI) diff --git a/src/Ai/Class/Warrior/Strategy/TankWarriorStrategy.cpp b/src/Ai/Class/Warrior/Strategy/TankWarriorStrategy.cpp index f256f2093..727039e2e 100644 --- a/src/Ai/Class/Warrior/Strategy/TankWarriorStrategy.cpp +++ b/src/Ai/Class/Warrior/Strategy/TankWarriorStrategy.cpp @@ -19,8 +19,6 @@ public: creators["heroic throw taunt"] = &heroic_throw_taunt; creators["taunt"] = &taunt; creators["taunt spell"] = &taunt; - creators["vigilance"] = &vigilance; - creators["enraged regeneration"] = &enraged_regeneration; } private: @@ -103,26 +101,6 @@ private: /*C*/ {} ); } - - static ActionNode* vigilance(PlayerbotAI* /*botAI*/) - { - return new ActionNode( - "vigilance", - /*P*/ {}, - /*A*/ {}, - /*C*/ {} - ); - } - - static ActionNode* enraged_regeneration(PlayerbotAI* /*botAI*/) - { - return new ActionNode( - "enraged regeneration", - /*P*/ {}, - /*A*/ {}, - /*C*/ {} - ); - } }; TankWarriorStrategy::TankWarriorStrategy(PlayerbotAI* botAI) : GenericWarriorStrategy(botAI) diff --git a/src/Ai/Raid/MC/MCActionContext.h b/src/Ai/Raid/MC/MCActionContext.h index 3cc95257a..111e63922 100644 --- a/src/Ai/Raid/MC/MCActionContext.h +++ b/src/Ai/Raid/MC/MCActionContext.h @@ -26,6 +26,7 @@ public: creators["mc golemagg assist tank attack core rager"] = &RaidMcActionContext::golemagg_assist_tank_attack_core_rager; creators["mc majordomo shadow resistance"] = &RaidMcActionContext::majordomo_shadow_resistance; creators["mc ragnaros fire resistance"] = &RaidMcActionContext::ragnaros_fire_resistance; + creators["mc core hound mark"] = &RaidMcActionContext::core_hound_mark; } private: @@ -44,6 +45,7 @@ private: static Action* golemagg_assist_tank_attack_core_rager(PlayerbotAI* botAI) { return new McGolemaggAssistTankAttackCoreRagerAction(botAI); } static Action* majordomo_shadow_resistance(PlayerbotAI* botAI) { return new BossShadowResistanceAction(botAI, "majordomo executus"); } static Action* ragnaros_fire_resistance(PlayerbotAI* botAI) { return new BossFireResistanceAction(botAI, "ragnaros"); } + static Action* core_hound_mark(PlayerbotAI* botAI) { return new McCoreHoundMarkAction(botAI); } }; #endif diff --git a/src/Ai/Raid/MC/MCActions.cpp b/src/Ai/Raid/MC/MCActions.cpp index 96050ac43..f4868613d 100644 --- a/src/Ai/Raid/MC/MCActions.cpp +++ b/src/Ai/Raid/MC/MCActions.cpp @@ -212,3 +212,45 @@ bool McGolemaggAssistTankAttackCoreRagerAction::Execute(Event event) return false; } + +Unit* McCoreHoundMarkAction::GetTarget() +{ + Unit* highestHealthHound = nullptr; + for (auto const& [guid, ref] : bot->GetThreatMgr().GetThreatenedByMeList()) + { + Unit* unit = ref->GetOwner(); + if (unit && unit->IsAlive() && unit->GetEntry() == NPC_CORE_HOUND) + { + if (!highestHealthHound || unit->GetHealth() > highestHealthHound->GetHealth()) + highestHealthHound = unit; + } + } + + if (!highestHealthHound) + return nullptr; + + Group* group = bot->GetGroup(); + ObjectGuid currentSkullGuid = group ? group->GetTargetIcon(RtiTargetValue::skullIndex) : ObjectGuid::Empty; + if (!currentSkullGuid.IsEmpty() && currentSkullGuid != highestHealthHound->GetGUID()) + { + // Only switch skull if the new target has meaningfully more health (10% buffer) to prevent rapid re-marking + if (Unit* currentSkullUnit = botAI->GetUnit(currentSkullGuid)) + if (currentSkullUnit->IsAlive() && highestHealthHound->GetHealth() <= currentSkullUnit->GetHealth() * 1.10f) + return nullptr; + } + + if (currentSkullGuid.IsEmpty() || currentSkullGuid != highestHealthHound->GetGUID()) + return highestHealthHound; + + return nullptr; +} + +bool McCoreHoundMarkAction::Execute(Event /*event*/) +{ + Unit* target = GetTarget(); + if (!target) + return false; + + bot->GetGroup()->SetTargetIcon(RtiTargetValue::skullIndex, bot->GetGUID(), target->GetGUID()); + return true; +} diff --git a/src/Ai/Raid/MC/MCActions.h b/src/Ai/Raid/MC/MCActions.h index 680b311d3..ad4d47a91 100644 --- a/src/Ai/Raid/MC/MCActions.h +++ b/src/Ai/Raid/MC/MCActions.h @@ -64,4 +64,13 @@ public: bool Execute(Event event) override; }; +class McCoreHoundMarkAction : public Action +{ +public: + McCoreHoundMarkAction(PlayerbotAI* botAI, std::string const name = "mc core hound mark") + : Action(botAI, name) {}; + Unit* GetTarget() override; + bool Execute(Event event) override; +}; + #endif diff --git a/src/Ai/Raid/MC/MCHelpers.h b/src/Ai/Raid/MC/MCHelpers.h index 5dc821246..139cde423 100644 --- a/src/Ai/Raid/MC/MCHelpers.h +++ b/src/Ai/Raid/MC/MCHelpers.h @@ -7,6 +7,9 @@ enum MoltenCoreNPCs { // Golemagg NPC_CORE_RAGER = 11672, + + // Core Hound (trash) + NPC_CORE_HOUND = 11671, }; enum MoltenCoreSpells { diff --git a/src/Ai/Raid/MC/MCStrategy.cpp b/src/Ai/Raid/MC/MCStrategy.cpp index fc63c66b9..0b2eddd23 100644 --- a/src/Ai/Raid/MC/MCStrategy.cpp +++ b/src/Ai/Raid/MC/MCStrategy.cpp @@ -71,6 +71,11 @@ void RaidMcStrategy::InitTriggers(std::vector& triggers) triggers.push_back( new TriggerNode("mc ragnaros fire resistance", { NextAction("mc ragnaros fire resistance", ACTION_RAID) })); + + // Trash + triggers.push_back( + new TriggerNode("mc core hound mark", + { NextAction("mc core hound mark", ACTION_RAID) })); } void RaidMcStrategy::InitMultipliers(std::vector& multipliers) diff --git a/src/Ai/Raid/MC/MCTriggerContext.h b/src/Ai/Raid/MC/MCTriggerContext.h index 7efa95298..67d8b3935 100644 --- a/src/Ai/Raid/MC/MCTriggerContext.h +++ b/src/Ai/Raid/MC/MCTriggerContext.h @@ -25,6 +25,7 @@ public: creators["mc golemagg is assist tank"] = &RaidMcTriggerContext::golemagg_is_assist_tank; creators["mc majordomo shadow resistance"] = &RaidMcTriggerContext::majordomo_shadow_resistance; creators["mc ragnaros fire resistance"] = &RaidMcTriggerContext::ragnaros_fire_resistance; + creators["mc core hound mark"] = &RaidMcTriggerContext::core_hound_mark; } private: @@ -43,6 +44,7 @@ private: static Trigger* golemagg_is_assist_tank(PlayerbotAI* botAI) { return new McGolemaggIsAssistTankTrigger(botAI); } static Trigger* majordomo_shadow_resistance(PlayerbotAI* botAI) { return new BossShadowResistanceTrigger(botAI, "majordomo executus"); } static Trigger* ragnaros_fire_resistance(PlayerbotAI* botAI) { return new BossFireResistanceTrigger(botAI, "ragnaros"); } + static Trigger* core_hound_mark(PlayerbotAI* botAI) { return new McCoreHoundMarkTrigger(botAI); } }; #endif diff --git a/src/Ai/Raid/MC/MCTriggers.cpp b/src/Ai/Raid/MC/MCTriggers.cpp index b9b2aa1b7..d0571b1d2 100644 --- a/src/Ai/Raid/MC/MCTriggers.cpp +++ b/src/Ai/Raid/MC/MCTriggers.cpp @@ -38,3 +38,8 @@ bool McGolemaggIsAssistTankTrigger::IsActive() { return AI_VALUE2(Unit*, "find target", "golemagg the incinerator") && PlayerbotAI::IsAssistTank(bot); } + +bool McCoreHoundMarkTrigger::IsActive() +{ + return PlayerbotAI::IsMainTank(bot) && AI_VALUE2(Unit*, "find target", "core hound"); +} diff --git a/src/Ai/Raid/MC/MCTriggers.h b/src/Ai/Raid/MC/MCTriggers.h index 4cd84a2df..7d91bb1e7 100644 --- a/src/Ai/Raid/MC/MCTriggers.h +++ b/src/Ai/Raid/MC/MCTriggers.h @@ -47,4 +47,11 @@ public: bool IsActive() override; }; +class McCoreHoundMarkTrigger : public Trigger +{ +public: + McCoreHoundMarkTrigger(PlayerbotAI* botAI) : Trigger(botAI, "mc core hound mark") {} + bool IsActive() override; +}; + #endif diff --git a/src/Bot/Factory/RandomPlayerbotFactory.cpp b/src/Bot/Factory/RandomPlayerbotFactory.cpp index 530715191..6e5005723 100644 --- a/src/Bot/Factory/RandomPlayerbotFactory.cpp +++ b/src/Bot/Factory/RandomPlayerbotFactory.cpp @@ -334,18 +334,12 @@ uint32 RandomPlayerbotFactory::CalculateTotalAccountCount() sPlayerbotAIConfig.addClassAccountPoolSize == 0 ? 2 : -1); if (!res || res->Fetch()[0].Get() == 0) - { break; - } std::this_thread::sleep_for(std::chrono::milliseconds(50)); // Extra 50ms fixed delay for safety. } } - // Checks if randomBotAccountCount is set, otherwise calculate it dynamically. - if (sPlayerbotAIConfig.randomBotAccountCount > 0) - return sPlayerbotAIConfig.randomBotAccountCount; - // Check existing account types uint32 existingRndBotAccounts = 0; uint32 existingAddClassAccounts = 0; @@ -366,16 +360,14 @@ uint32 RandomPlayerbotFactory::CalculateTotalAccountCount() } while (typeCheck->NextRow()); } - // Determine divisor based on Death Knight login eligibility and requested A&H faction ratio + // Determine divisor based on Death Knight availability and requested A&H faction ratio int divisor = CalculateAvailableCharsPerAccount(); // Calculate max bots int maxBots = sPlayerbotAIConfig.maxRandomBots; - // Take periodic online - offline into account + // Take periodic online/offline into account if (sPlayerbotAIConfig.enablePeriodicOnlineOffline) - { maxBots *= sPlayerbotAIConfig.periodicOnlineOfflineRatio; - } // Calculate number of accounts needed for RNDbots // Result is rounded up for maxBots not cleanly divisible by the divisor @@ -416,11 +408,22 @@ uint32 RandomPlayerbotFactory::CalculateTotalAccountCount() } // Return existing total plus any additional accounts needed - return existingTotal + additionalAccountsNeeded; + uint32 calculatedTotal = existingTotal + additionalAccountsNeeded; + + // Manually set randomBotAccountCount meets the requirements + if (sPlayerbotAIConfig.randomBotAccountCount >= calculatedTotal) + return sPlayerbotAIConfig.randomBotAccountCount; + // Manually set randomBotAccountCount doesn't meet the requirements. Using calculated value + if (sPlayerbotAIConfig.randomBotAccountCount > 0) + LOG_WARN("playerbots", "RandomBotAccountCount ({}) is lower than the required calculated value ({}). Using the calculated value instead.", + sPlayerbotAIConfig.randomBotAccountCount, calculatedTotal); + + return calculatedTotal; } uint32 RandomPlayerbotFactory::CalculateAvailableCharsPerAccount() { + // Death Knight availability according to their login eligibility, and if WotLK is enabled at all. bool noDK = sPlayerbotAIConfig.disableDeathKnightLogin || sWorld->getIntConfig(CONFIG_EXPANSION) != EXPANSION_WRATH_OF_THE_LICH_KING; uint32 availableChars = noDK ? 9 : 10; @@ -434,11 +437,9 @@ uint32 RandomPlayerbotFactory::CalculateAvailableCharsPerAccount() float unavailableRatio = static_cast((std::max(hordeRatio, allianceRatio) - std::min(hordeRatio, allianceRatio))) / (std::max(hordeRatio, allianceRatio) * 2); + // Conservative floor to ensure enough characters (may result in more accounts than needed). if (unavailableRatio != 0) - { - // conservative floor to ensure enough chars (may result in more accounts than needed) availableChars = availableChars - availableChars * unavailableRatio; - } return availableChars; } diff --git a/src/Bot/PlayerbotMgr.cpp b/src/Bot/PlayerbotMgr.cpp index 9d9f5688f..511b21a9f 100644 --- a/src/Bot/PlayerbotMgr.cpp +++ b/src/Bot/PlayerbotMgr.cpp @@ -1068,6 +1068,7 @@ std::vector PlayerbotHolder::HandlePlayerbotCommand(char const* arg messages.push_back("Enable player botAI"); PlayerbotsMgr::instance().AddPlayerbotData(master, true); GET_PLAYERBOT_AI(master)->SetMaster(master); + PlayerbotRepository::instance().Load(GET_PLAYERBOT_AI(master)); } return messages;