From b7e240804710f63245cb537a2c72dd6d2581452f Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Fri, 5 Jul 2024 11:55:07 +0800 Subject: [PATCH 01/51] [Configuration] Enable free food --- conf/playerbots.conf.dist | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/conf/playerbots.conf.dist b/conf/playerbots.conf.dist index 7d4f9a34..eb2fb3f1 100644 --- a/conf/playerbots.conf.dist +++ b/conf/playerbots.conf.dist @@ -224,8 +224,8 @@ AiPlayerbot.SyncQuestForPlayer = 0 AiPlayerbot.SyncLevelWithPlayers = 0 # Give free food to random bots -# Default: 0 (disabled) -AiPlayerbot.FreeFood = 0 +# Default: 1 (enabled) +AiPlayerbot.FreeFood = 1 # Bot automatically trains spells when talking to trainer (yes = train all available spells as long as the bot has the money, free = auto trains with no money cost, no = only list spells) # Only for random bots @@ -352,6 +352,10 @@ AiPlayerbot.AutoAvoidAoe = 1 # Default: 1 (enable) AiPlayerbot.TellWhenAvoidAoe = 1 +# Premade spell to avoid (undetected spells) +# spellid-radius, ... +AiPlayerbot.PremadeAvoidAoe = 62234-4 + # Random bot default strategies (applied after defaults) AiPlayerbot.RandomBotCombatStrategies = "+dps,+dps assist,-threat" # AiPlayerbot.RandomBotNonCombatStrategies = "+grind,+loot,+rpg,+custom::say" From 98560a18555824b172d54c017b9deabbe9d8215f Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Fri, 5 Jul 2024 12:01:25 +0800 Subject: [PATCH 02/51] [Initialization] Stop server after accounts deletion --- src/PlayerbotAIConfig.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/PlayerbotAIConfig.cpp b/src/PlayerbotAIConfig.cpp index 34e7a1bb..d468533c 100644 --- a/src/PlayerbotAIConfig.cpp +++ b/src/PlayerbotAIConfig.cpp @@ -327,6 +327,9 @@ bool PlayerbotAIConfig::Initialize() selfBotLevel = sConfigMgr->GetOption("AiPlayerbot.SelfBotLevel", 1); RandomPlayerbotFactory::CreateRandomBots(); + if (World::IsStopped()) { + return true; + } PlayerbotFactory::Init(); sRandomItemMgr->Init(); sRandomItemMgr->InitAfterAhBot(); From c63ee90cb284e96f580f405f5fd63785606dcf20 Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Fri, 5 Jul 2024 14:17:39 +0800 Subject: [PATCH 03/51] [Crash fix] Duplicate bots login --- src/PlayerbotMgr.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/PlayerbotMgr.cpp b/src/PlayerbotMgr.cpp index 4c8f984f..bd004267 100644 --- a/src/PlayerbotMgr.cpp +++ b/src/PlayerbotMgr.cpp @@ -363,6 +363,11 @@ Player* PlayerbotHolder::GetPlayerBot(ObjectGuid::LowType lowGuid) const void PlayerbotHolder::OnBotLogin(Player* const bot) { + // Prevent duplicate login + if (playerBots.find(bot->GetGUID()) != playerBots.end()) { + return; + } + sPlayerbotsMgr->AddPlayerbotData(bot, true); playerBots[bot->GetGUID()] = bot; OnBotLoginInternal(bot); From f26227027daf4b45bead7a91f25deb980373e1e8 Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Fri, 5 Jul 2024 18:00:35 +0800 Subject: [PATCH 04/51] [Combat formation] Combat formation set up --- src/AiFactory.cpp | 1 + src/strategy/StrategyContext.h | 2 + src/strategy/Value.h | 6 + src/strategy/actions/ActionContext.h | 4 + src/strategy/actions/MovementActions.cpp | 195 ++++++++++++++++-- src/strategy/actions/MovementActions.h | 47 ++++- .../generic/ChatCommandHandlerStrategy.cpp | 1 + src/strategy/generic/CombatStrategy.cpp | 9 +- src/strategy/generic/CombatStrategy.h | 8 + src/strategy/triggers/ChatTriggerContext.h | 2 + src/strategy/values/ValueContext.h | 2 + 11 files changed, 251 insertions(+), 26 deletions(-) diff --git a/src/AiFactory.cpp b/src/AiFactory.cpp index 063f3411..09401a82 100644 --- a/src/AiFactory.cpp +++ b/src/AiFactory.cpp @@ -274,6 +274,7 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa { engine->addStrategy("avoid aoe"); } + engine->addStrategy("combat formation"); switch (player->getClass()) { case CLASS_PRIEST: diff --git a/src/strategy/StrategyContext.h b/src/strategy/StrategyContext.h index 55bdc4bc..82090440 100644 --- a/src/strategy/StrategyContext.h +++ b/src/strategy/StrategyContext.h @@ -112,6 +112,7 @@ class StrategyContext : public NamedObjectContext creators["grind"] = &StrategyContext::grind; creators["avoid aoe"] = &StrategyContext::avoid_aoe; creators["move random"] = &StrategyContext::move_random; + creators["combat formation"] = &StrategyContext::combat_formation; } private: @@ -174,6 +175,7 @@ class StrategyContext : public NamedObjectContext static Strategy* grind(PlayerbotAI* botAI) { return new GrindingStrategy(botAI); } static Strategy* avoid_aoe(PlayerbotAI* botAI) { return new AvoidAoeStrategy(botAI); } static Strategy* move_random(PlayerbotAI* ai) { return new MoveRandomStrategy(ai); } + static Strategy* combat_formation(PlayerbotAI* ai) { return new CombatFormationStrategy(ai); } }; class MovementStrategyContext : public NamedObjectContext diff --git a/src/strategy/Value.h b/src/strategy/Value.h index 9cba6efe..e27600ad 100644 --- a/src/strategy/Value.h +++ b/src/strategy/Value.h @@ -326,4 +326,10 @@ class UnitManualSetValue : public ManualSetValue Unit* Get() override; }; +class DisperseDistanceValue : public ManualSetValue +{ + public: + DisperseDistanceValue(PlayerbotAI* botAI, float defaultValue = -1.0f, std::string const name = "disperse value") : + ManualSetValue(botAI, defaultValue, name) { } +}; #endif diff --git a/src/strategy/actions/ActionContext.h b/src/strategy/actions/ActionContext.h index 6cdc68b1..f2c1062c 100644 --- a/src/strategy/actions/ActionContext.h +++ b/src/strategy/actions/ActionContext.h @@ -89,6 +89,8 @@ class ActionContext : public NamedObjectContext creators["flee"] = &ActionContext::flee; creators["flee with pet"] = &ActionContext::flee_with_pet; creators["avoid aoe"] = &ActionContext::avoid_aoe; + creators["combat formation move"] = &ActionContext::combat_formation_move; + creators["disperse set"] = &ActionContext::disperse_set; creators["gift of the naaru"] = &ActionContext::gift_of_the_naaru; creators["shoot"] = &ActionContext::shoot; creators["lifeblood"] = &ActionContext::lifeblood; @@ -265,6 +267,8 @@ class ActionContext : public NamedObjectContext static Action* flee(PlayerbotAI* botAI) { return new FleeAction(botAI); } static Action* flee_with_pet(PlayerbotAI* botAI) { return new FleeWithPetAction(botAI); } static Action* avoid_aoe(PlayerbotAI* botAI) { return new AvoidAoeAction(botAI); } + static Action* combat_formation_move(PlayerbotAI* botAI) { return new CombatFormationMoveAction(botAI); } + static Action* disperse_set(PlayerbotAI* botAI) { return new DisperseSetAction(botAI); } static Action* gift_of_the_naaru(PlayerbotAI* botAI) { return new CastGiftOfTheNaaruAction(botAI); } static Action* lifeblood(PlayerbotAI* botAI) { return new CastLifeBloodAction(botAI); } static Action* arcane_torrent(PlayerbotAI* botAI) { return new CastArcaneTorrentAction(botAI); } diff --git a/src/strategy/actions/MovementActions.cpp b/src/strategy/actions/MovementActions.cpp index f2652168..0a47c8ea 100644 --- a/src/strategy/actions/MovementActions.cpp +++ b/src/strategy/actions/MovementActions.cpp @@ -12,6 +12,7 @@ #include "ObjectGuid.h" #include "PathGenerator.h" #include "PlayerbotAIConfig.h" +#include "Position.h" #include "Random.h" #include "SharedDefines.h" #include "SpellAuraEffects.h" @@ -25,10 +26,13 @@ #include "LootObjectStack.h" #include "Playerbots.h" #include "ServerFacade.h" +#include "Timer.h" #include "Transport.h" #include "Unit.h" #include "Vehicle.h" #include "WaypointMovementGenerator.h" +#include +#include MovementAction::MovementAction(PlayerbotAI* botAI, std::string const name) : Action(botAI, name) { @@ -1495,6 +1499,9 @@ bool FleeWithPetAction::Execute(Event event) bool AvoidAoeAction::isUseful() { + if (getMSTime() - moveInterval < lastMoveTimer) { + return false; + } GuidVector traps = AI_VALUE(GuidVector, "nearest trap with damage"); GuidVector triggers = AI_VALUE(GuidVector, "possible triggers"); return AI_VALUE(Aura*, "area debuff") || !traps.empty() || !triggers.empty(); @@ -1504,14 +1511,17 @@ bool AvoidAoeAction::Execute(Event event) { // Case #1: Aura with dynamic object (e.g. rain of fire) if (AvoidAuraWithDynamicObj()) { + lastMoveTimer = getMSTime(); return true; } // Case #2: Trap game object with spell (e.g. lava bomb) if (AvoidGameObjectWithDamage()) { + lastMoveTimer = getMSTime(); return true; } // Case #3: Trigger npc (e.g. Lesser shadow fissure) if (AvoidUnitWithDamageAura()) { + lastMoveTimer = getMSTime(); return true; } return false; @@ -1541,7 +1551,13 @@ bool AvoidAoeAction::AvoidAuraWithDynamicObj() } std::ostringstream name; name << spellInfo->SpellName[0]; // << "] (aura)"; - if (FleePosition(dynOwner->GetPosition(), radius, name.str())) { + if (FleePosition(dynOwner->GetPosition(), radius)) { + if (sPlayerbotAIConfig->tellWhenAvoidAoe && lastTellTimer < time(NULL) - 10) { + lastTellTimer = time(NULL); + std::ostringstream out; + out << "I'm avoiding " << name.str() << "..."; + bot->Say(out.str(), LANG_UNIVERSAL); + } return true; } return false; @@ -1592,7 +1608,13 @@ bool AvoidAoeAction::AvoidGameObjectWithDamage() } std::ostringstream name; name << spellInfo->SpellName[0]; // << "] (object)"; - if (FleePosition(go->GetPosition(), radius, name.str())) { + if (FleePosition(go->GetPosition(), radius)) { + if (sPlayerbotAIConfig->tellWhenAvoidAoe && lastTellTimer < time(NULL) - 10) { + lastTellTimer = time(NULL); + std::ostringstream out; + out << "I'm avoiding " << name.str() << "..."; + bot->Say(out.str(), LANG_UNIVERSAL); + } return true; } @@ -1634,8 +1656,13 @@ bool AvoidAoeAction::AvoidUnitWithDamageAura() } std::ostringstream name; name << triggerSpellInfo->SpellName[0]; //<< "] (unit)"; - if (FleePosition(unit->GetPosition(), radius, name.str())) { - return true; + if (FleePosition(unit->GetPosition(), radius)) { + if (sPlayerbotAIConfig->tellWhenAvoidAoe && lastTellTimer < time(NULL) - 10) { + lastTellTimer = time(NULL); + std::ostringstream out; + out << "I'm avoiding " << name.str() << "..."; + bot->Say(out.str(), LANG_UNIVERSAL); + } } } } @@ -1645,7 +1672,7 @@ bool AvoidAoeAction::AvoidUnitWithDamageAura() return false; } -Position AvoidAoeAction::BestPositionForMelee(Position pos, float radius) +Position MovementAction::BestPositionForMeleeToFlee(Position pos, float radius) { Unit* currentTarget = AI_VALUE(Unit*, "current target"); std::vector possibleAngles; @@ -1671,7 +1698,7 @@ Position AvoidAoeAction::BestPositionForMelee(Position pos, float radius) for (CheckAngle &checkAngle : possibleAngles) { float angle = checkAngle.angle; bool strict = checkAngle.strict; - float fleeDis = sPlayerbotAIConfig->fleeDistance; + float fleeDis = std::min(radius + 1.0f, sPlayerbotAIConfig->fleeDistance); Position fleePos{bot->GetPositionX() + cos(angle) * fleeDis, bot->GetPositionY() + sin(angle) * fleeDis, bot->GetPositionZ()}; @@ -1690,7 +1717,7 @@ Position AvoidAoeAction::BestPositionForMelee(Position pos, float radius) return Position(); } -Position AvoidAoeAction::BestPositionForRanged(Position pos, float radius) +Position MovementAction::BestPositionForRangedToFlee(Position pos, float radius) { Unit* currentTarget = AI_VALUE(Unit*, "current target"); std::vector possibleAngles; @@ -1714,7 +1741,7 @@ Position AvoidAoeAction::BestPositionForRanged(Position pos, float radius) for (CheckAngle &checkAngle : possibleAngles) { float angle = checkAngle.angle; bool strict = checkAngle.strict; - float fleeDis = sPlayerbotAIConfig->fleeDistance; + float fleeDis = std::min(radius + 1.0f, sPlayerbotAIConfig->fleeDistance); Position fleePos{bot->GetPositionX() + cos(angle) * fleeDis, bot->GetPositionY() + sin(angle) * fleeDis, bot->GetPositionZ()}; @@ -1737,28 +1764,162 @@ Position AvoidAoeAction::BestPositionForRanged(Position pos, float radius) return Position(); } -bool AvoidAoeAction::FleePosition(Position pos, float radius, std::string name) +bool MovementAction::FleePosition(Position pos, float radius) { Position bestPos; if (botAI->IsMelee(bot)) { - bestPos = BestPositionForMelee(pos, radius); + bestPos = BestPositionForMeleeToFlee(pos, radius); } else { - bestPos = BestPositionForRanged(pos, radius); + bestPos = BestPositionForRangedToFlee(pos, radius); } if (bestPos != Position()) { if (MoveTo(bot->GetMapId(), bestPos.GetPositionX(), bestPos.GetPositionY(), bestPos.GetPositionZ(), false, false, true)) { - if (sPlayerbotAIConfig->tellWhenAvoidAoe && lastTellTimer < time(NULL) - 10) { - lastTellTimer = time(NULL); - std::ostringstream out; - out << "I'm avoiding " << name << "..."; - bot->Say(out.str(), LANG_UNIVERSAL); - } return true; } } return false; } +bool CombatFormationMoveAction::isUseful() +{ + if (getMSTime() - moveInterval < lastMoveTimer) { + return false; + } + if (bot->GetCurrentSpell(CURRENT_CHANNELED_SPELL) != nullptr) { + return false; + } + float dis = AI_VALUE(float, "disperse distance"); + return dis > 0.0f; +} + +bool CombatFormationMoveAction::Execute(Event event) +{ + float dis = AI_VALUE(float, "disperse distance"); + Player* playerToLeave = NearestGroupMember(dis); + if (playerToLeave && bot->GetExactDist(playerToLeave) < dis) { + if (FleePosition(playerToLeave->GetPosition(), dis)) { + lastMoveTimer = getMSTime(); + } + } + return false; +} + +Position CombatFormationMoveAction::AverageGroupPos(float dis) +{ + float averageX = 0, averageY = 0, averageZ = 0; + int cnt = 0; + Group* group = bot->GetGroup(); + if (!group) { + return Position(); + } + Group::MemberSlotList const& groupSlot = group->GetMemberSlots(); + for (Group::member_citerator itr = groupSlot.begin(); itr != groupSlot.end(); itr++) + { + Player *member = ObjectAccessor::FindPlayer(itr->guid); + if (!member || !member->IsAlive() || member->GetMapId() != bot->GetMapId() || member->IsCharmed() || sServerFacade->GetDistance2d(bot, member) > dis) + continue; + cnt++; + averageX += member->GetPositionX(); + averageY += member->GetPositionY(); + averageZ += member->GetPositionZ(); + } + averageX /= cnt; + averageY /= cnt; + averageZ /= cnt; + return Position(averageX, averageY, averageZ); +} + +Player* CombatFormationMoveAction::NearestGroupMember(float dis) +{ + float nearestDis = 10000.0f; + Player* result = nullptr; + Group* group = bot->GetGroup(); + if (!group) { + return result; + } + Group::MemberSlotList const& groupSlot = group->GetMemberSlots(); + for (Group::member_citerator itr = groupSlot.begin(); itr != groupSlot.end(); itr++) + { + Player *member = ObjectAccessor::FindPlayer(itr->guid); + if (!member || !member->IsAlive() || member == bot || member->GetMapId() != bot->GetMapId() || member->IsCharmed() || sServerFacade->GetDistance2d(bot, member) > dis) + continue; + if (nearestDis > bot->GetExactDist(member)) { + result = member; + nearestDis = bot->GetExactDist(member); + } + } + return result; +} + +bool DisperseSetAction::Execute(Event event) +{ + std::string const text = event.getParam(); + if (text == "disable") { + RESET_AI_VALUE(float, "disperse distance"); + botAI->TellMasterNoFacing("Disable disperse"); + return true; + } + if (text == "enable" || text == "reset") { + if (botAI->IsMelee(bot)) { + SET_AI_VALUE(float, "disperse distance", DEFAULT_DISPERSE_DISTANCE_MELEE); + } else { + SET_AI_VALUE(float, "disperse distance", DEFAULT_DISPERSE_DISTANCE_RANGED); + } + float dis = AI_VALUE(float, "disperse distance"); + std::ostringstream out; + out << "Enable disperse distance " << std::setprecision(2) << dis; + botAI->TellMasterNoFacing(out.str()); + return true; + } + if (text == "increase") { + float dis = AI_VALUE(float, "disperse distance"); + std::ostringstream out; + if (dis <= 0.0f) { + out << "Enable disperse first"; + botAI->TellMasterNoFacing(out.str()); + return true; + } + dis += 1.0f; + SET_AI_VALUE(float, "disperse distance", dis); + out << "Increase disperse distance to " << std::setprecision(2) << dis; + botAI->TellMasterNoFacing(out.str()); + return true; + } + if (text == "decrease") { + float dis = AI_VALUE(float, "disperse distance"); + dis -= 1.0f; + if (dis <= 0.0f) { + dis += 1.0f; + } + SET_AI_VALUE(float, "disperse distance", dis); + std::ostringstream out; + out << "Increase disperse distance to " << std::setprecision(2) << dis; + botAI->TellMasterNoFacing(out.str()); + return true; + } + if (text.starts_with("set")) { + float dis = -1.0f;; + sscanf(text.c_str(), "set %f", &dis); + std::ostringstream out; + if (dis < 0 || dis > 100.0f) { + out << "Invalid disperse distance " << std::setprecision(2) << dis; + } else { + SET_AI_VALUE(float, "disperse distance", dis); + out << "Set disperse distance to " << std::setprecision(2) << dis; + } + botAI->TellMasterNoFacing(out.str()); + return true; + } + std::ostringstream out; + out << "Usage: disperse [enable|disable|increase|decrease|set {distance}]" << "\n"; + float dis = AI_VALUE(float, "disperse distance"); + if (dis > 0.0f) { + out << "Current disperse distance: " << std::setprecision(2) << dis; + } + botAI->TellMasterNoFacing(out.str()); + return true; +} + bool RunAwayAction::Execute(Event event) { return Flee(AI_VALUE(Unit*, "master target")); diff --git a/src/strategy/actions/MovementActions.h b/src/strategy/actions/MovementActions.h index f26991a4..ed9527af 100644 --- a/src/strategy/actions/MovementActions.h +++ b/src/strategy/actions/MovementActions.h @@ -41,6 +41,14 @@ class MovementAction : public Action bool MoveAway(Unit* target); bool MoveInside(uint32 mapId, float x, float y, float z, float distance = sPlayerbotAIConfig->followDistance); void CreateWp(Player* wpOwner, float x, float y, float z, float o, uint32 entry, bool important = false); + Position BestPositionForMeleeToFlee(Position pos, float radius); + Position BestPositionForRangedToFlee(Position pos, float radius); + bool FleePosition(Position pos, float radius); + protected: + struct CheckAngle { + float angle; + bool strict; + }; private: // float SearchBestGroundZForPath(float x, float y, float z, bool generatePath, float range = 20.0f, bool normal_only = false, float step = 8.0f); const Movement::PointsArray SearchForBestPath(float x, float y, float z, float &modified_z, int maxSearchCount = 5, bool normal_only = false, float step = 8.0f); @@ -69,7 +77,8 @@ class FleeWithPetAction : public MovementAction class AvoidAoeAction : public MovementAction { public: - AvoidAoeAction(PlayerbotAI* botAI) : MovementAction(botAI, "avoid aoe") { } + AvoidAoeAction(PlayerbotAI* botAI, int moveInterval = 1000) : MovementAction(botAI, "avoid aoe"), + moveInterval(moveInterval) { } bool isUseful() override; bool Execute(Event event) override; @@ -78,14 +87,36 @@ class AvoidAoeAction : public MovementAction bool AvoidAuraWithDynamicObj(); bool AvoidGameObjectWithDamage(); bool AvoidUnitWithDamageAura(); - Position BestPositionForMelee(Position pos, float radius); - Position BestPositionForRanged(Position pos, float radius); - bool FleePosition(Position pos, float radius, std::string name); time_t lastTellTimer = 0; - struct CheckAngle { - float angle; - bool strict; - }; + int lastMoveTimer = 0; + int moveInterval; + +}; + +class CombatFormationMoveAction : public MovementAction +{ + public: + CombatFormationMoveAction(PlayerbotAI* botAI, int moveInterval = 1000) : MovementAction(botAI, "combat formation move"), + moveInterval(moveInterval) { } + + bool isUseful() override; + bool Execute(Event event) override; + + protected: + Position AverageGroupPos(float dis = sPlayerbotAIConfig->sightDistance); + Player* NearestGroupMember(float dis = sPlayerbotAIConfig->sightDistance); + int lastMoveTimer = 0; + int moveInterval; +}; + +class DisperseSetAction : public Action +{ + public: + DisperseSetAction(PlayerbotAI* botAI, std::string const name = "disperse set") : Action(botAI, name) { } + + bool Execute(Event event) override; + float DEFAULT_DISPERSE_DISTANCE_RANGED = 5.0f; + float DEFAULT_DISPERSE_DISTANCE_MELEE = 2.0f; }; class RunAwayAction : public MovementAction diff --git a/src/strategy/generic/ChatCommandHandlerStrategy.cpp b/src/strategy/generic/ChatCommandHandlerStrategy.cpp index 4da74e5b..0f149960 100644 --- a/src/strategy/generic/ChatCommandHandlerStrategy.cpp +++ b/src/strategy/generic/ChatCommandHandlerStrategy.cpp @@ -61,6 +61,7 @@ void ChatCommandHandlerStrategy::InitTriggers(std::vector& trigger triggers.push_back(new TriggerNode("naxx", NextAction::array(0, new NextAction("naxx chat shortcut", relevance), NULL))); triggers.push_back(new TriggerNode("bwl", NextAction::array(0, new NextAction("bwl chat shortcut", relevance), NULL))); triggers.push_back(new TriggerNode("dps", NextAction::array(0, new NextAction("tell expected dps", relevance), NULL))); + triggers.push_back(new TriggerNode("disperse", NextAction::array(0, new NextAction("disperse set", relevance), NULL))); } ChatCommandHandlerStrategy::ChatCommandHandlerStrategy(PlayerbotAI* botAI) : PassTroughStrategy(botAI) diff --git a/src/strategy/generic/CombatStrategy.cpp b/src/strategy/generic/CombatStrategy.cpp index 3b72af7f..c9e3a95c 100644 --- a/src/strategy/generic/CombatStrategy.cpp +++ b/src/strategy/generic/CombatStrategy.cpp @@ -81,4 +81,11 @@ void AvoidAoeStrategy::InitTriggers(std::vector& triggers) void AvoidAoeStrategy::InitMultipliers(std::vector& multipliers) { // multipliers.push_back(new AvoidAoeStrategyMultiplier(botAI)); -} \ No newline at end of file +} + +NextAction** CombatFormationStrategy::getDefaultActions() +{ + return NextAction::array(0, + new NextAction("combat formation move", ACTION_EMERGENCY), + nullptr); +} diff --git a/src/strategy/generic/CombatStrategy.h b/src/strategy/generic/CombatStrategy.h index 33813615..7f618064 100644 --- a/src/strategy/generic/CombatStrategy.h +++ b/src/strategy/generic/CombatStrategy.h @@ -28,4 +28,12 @@ public: void InitTriggers(std::vector& triggers) override; }; +class CombatFormationStrategy : public Strategy +{ +public: + CombatFormationStrategy(PlayerbotAI* ai): Strategy(ai) {} + const std::string getName() override { return "combat formation"; } + NextAction** getDefaultActions() override; +}; + #endif diff --git a/src/strategy/triggers/ChatTriggerContext.h b/src/strategy/triggers/ChatTriggerContext.h index af52cd7e..598154ef 100644 --- a/src/strategy/triggers/ChatTriggerContext.h +++ b/src/strategy/triggers/ChatTriggerContext.h @@ -119,6 +119,7 @@ class ChatTriggerContext : public NamedObjectContext creators["naxx"] = &ChatTriggerContext::naxx; creators["bwl"] = &ChatTriggerContext::bwl; creators["dps"] = &ChatTriggerContext::dps; + creators["disperse"] = &ChatTriggerContext::disperse; } private: @@ -218,6 +219,7 @@ class ChatTriggerContext : public NamedObjectContext static Trigger* naxx(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "naxx"); } static Trigger* bwl(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "bwl"); } static Trigger* dps(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "dps"); } + static Trigger* disperse(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "disperse"); } }; #endif diff --git a/src/strategy/values/ValueContext.h b/src/strategy/values/ValueContext.h index 4298b44e..fe08de8b 100644 --- a/src/strategy/values/ValueContext.h +++ b/src/strategy/values/ValueContext.h @@ -301,6 +301,7 @@ class ValueContext : public NamedObjectContext creators["expected group dps"] = &ValueContext::expected_group_dps; creators["area debuff"] = &ValueContext::area_debuff; creators["nearest trap with damage"] = &ValueContext::nearest_trap_with_damange; + creators["disperse distance"] = &ValueContext::disperse_distance; } private: @@ -505,6 +506,7 @@ class ValueContext : public NamedObjectContext static UntypedValue* expected_group_dps(PlayerbotAI* ai) { return new ExpectedGroupDpsValue(ai); } static UntypedValue* area_debuff(PlayerbotAI* ai) { return new AreaDebuffValue(ai); } static UntypedValue* nearest_trap_with_damange(PlayerbotAI* ai) { return new NearestTrapWithDamageValue(ai); } + static UntypedValue* disperse_distance(PlayerbotAI* ai) { return new DisperseDistanceValue(ai); } }; #endif From 8ff016a67ec628ceb86554b0785aab35807b8cce Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Fri, 5 Jul 2024 18:41:20 +0800 Subject: [PATCH 05/51] [Class spell] Seed of corruption --- src/strategy/warlock/DpsWarlockStrategy.cpp | 5 ++++- src/strategy/warlock/WarlockActions.h | 20 +++++++++++++++++++ .../warlock/WarlockAiObjectContext.cpp | 2 ++ src/strategy/warlock/WarlockTriggers.h | 14 ++++++++++++- 4 files changed, 39 insertions(+), 2 deletions(-) diff --git a/src/strategy/warlock/DpsWarlockStrategy.cpp b/src/strategy/warlock/DpsWarlockStrategy.cpp index f5247c3f..3e79dfa8 100644 --- a/src/strategy/warlock/DpsWarlockStrategy.cpp +++ b/src/strategy/warlock/DpsWarlockStrategy.cpp @@ -87,7 +87,10 @@ void DpsWarlockStrategy::InitTriggers(std::vector& triggers) void DpsAoeWarlockStrategy::InitTriggers(std::vector& triggers) { - triggers.push_back(new TriggerNode("medium aoe", NextAction::array(0, new NextAction("rain of fire", 37.0f), nullptr))); + triggers.push_back(new TriggerNode("medium aoe", NextAction::array(0, + new NextAction("seed of corruption", 39.0f), + new NextAction("seed of corruption on attacker", 38.0f), + new NextAction("rain of fire", 37.0f), nullptr))); triggers.push_back(new TriggerNode("corruption on attacker", NextAction::array(0, new NextAction("corruption on attacker", 27.0f), nullptr))); triggers.push_back(new TriggerNode("unstable affliction on attacker", NextAction::array(0, new NextAction("unstable affliction on attacker", 26.0f), NULL))); triggers.push_back(new TriggerNode("curse of agony on attacker", NextAction::array(0, new NextAction("curse of agony on attacker", 25.0f), nullptr))); diff --git a/src/strategy/warlock/WarlockActions.h b/src/strategy/warlock/WarlockActions.h index 0ec8cfbb..813374a0 100644 --- a/src/strategy/warlock/WarlockActions.h +++ b/src/strategy/warlock/WarlockActions.h @@ -67,12 +67,20 @@ class CastCorruptionAction : public CastDebuffSpellAction { public: CastCorruptionAction(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "corruption", true) { } + bool isUseful() override { + return CastDebuffSpellAction::isUseful() && !botAI->HasAura("seed of corruption", GetTarget(), false, true) ; + } + ActionThreatType getThreatType() override { return ActionThreatType::Aoe; } }; class CastCorruptionOnAttackerAction : public CastDebuffSpellOnAttackerAction { public: CastCorruptionOnAttackerAction(PlayerbotAI* botAI) : CastDebuffSpellOnAttackerAction(botAI, "corruption", true) { } + bool isUseful() override { + return CastDebuffSpellOnAttackerAction::isUseful() && !botAI->HasAura("seed of corruption", GetTarget(), false, true) ; + } + ActionThreatType getThreatType() override { return ActionThreatType::Aoe; } }; class CastCurseOfAgonyOnAttackerAction : public CastDebuffSpellOnAttackerAction @@ -142,6 +150,18 @@ class CastSeedOfCorruptionAction : public CastDebuffSpellAction { public: CastSeedOfCorruptionAction(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "seed of corruption", true, 0) { } + bool isUseful() override { + return CastDebuffSpellAction::isUseful() && !botAI->HasAura("corruption", GetTarget(), false, true) ; + } +}; + +class CastSeedOfCorruptionOnAttackerAction : public CastDebuffSpellOnAttackerAction +{ + public: + CastSeedOfCorruptionOnAttackerAction(PlayerbotAI* botAI) : CastDebuffSpellOnAttackerAction(botAI, "seed of corruption", true, 0) { } + bool isUseful() override { + return CastDebuffSpellOnAttackerAction::isUseful() && !botAI->HasAura("corruption", GetTarget(), false, true) ; + } }; class CastRainOfFireAction : public CastSpellAction diff --git a/src/strategy/warlock/WarlockAiObjectContext.cpp b/src/strategy/warlock/WarlockAiObjectContext.cpp index 52e3a414..486c2cc2 100644 --- a/src/strategy/warlock/WarlockAiObjectContext.cpp +++ b/src/strategy/warlock/WarlockAiObjectContext.cpp @@ -158,6 +158,7 @@ class WarlockAiObjectContextInternal : public NamedObjectContext creators["banish"] = &WarlockAiObjectContextInternal::banish; creators["banish on cc"] = &WarlockAiObjectContextInternal::banish_on_cc; creators["seed of corruption"] = &WarlockAiObjectContextInternal::seed_of_corruption; + creators["seed of corruption on attacker"] = &WarlockAiObjectContextInternal::seed_of_corruption_on_attacker; creators["rain of fire"] = &WarlockAiObjectContextInternal::rain_of_fire; creators["shadowfury"] = &WarlockAiObjectContextInternal::shadowfury; creators["life tap"] = &WarlockAiObjectContextInternal::life_tap; @@ -209,6 +210,7 @@ class WarlockAiObjectContextInternal : public NamedObjectContext static Action* banish(PlayerbotAI* botAI) { return new CastBanishAction(botAI); } static Action* banish_on_cc(PlayerbotAI* botAI) { return new CastBanishAction(botAI); } static Action* seed_of_corruption(PlayerbotAI* botAI) { return new CastSeedOfCorruptionAction(botAI); } + static Action* seed_of_corruption_on_attacker(PlayerbotAI* botAI) { return new CastSeedOfCorruptionOnAttackerAction(botAI); } static Action* rain_of_fire(PlayerbotAI* botAI) { return new CastRainOfFireAction(botAI); } static Action* shadowfury(PlayerbotAI* botAI) { return new CastShadowfuryAction(botAI); } static Action* life_tap(PlayerbotAI* botAI) { return new CastLifeTapAction(botAI); } diff --git a/src/strategy/warlock/WarlockTriggers.h b/src/strategy/warlock/WarlockTriggers.h index 8578e43a..42c773f7 100644 --- a/src/strategy/warlock/WarlockTriggers.h +++ b/src/strategy/warlock/WarlockTriggers.h @@ -6,6 +6,7 @@ #define _PLAYERBOT_WARLOCKTRIGGERS_H #include "GenericTriggers.h" +#include "PlayerbotAI.h" class PlayerbotAI; @@ -32,13 +33,24 @@ class CurseOfAgonyTrigger : public DebuffTrigger CurseOfAgonyTrigger(PlayerbotAI* botAI) : DebuffTrigger(botAI, "curse of agony", 1, true, 20.0f) { } }; -DEBUFF_CHECKISOWNER_TRIGGER(CorruptionTrigger, "corruption"); +class CorruptionTrigger : public DebuffTrigger +{ + public: + CorruptionTrigger(PlayerbotAI* botAI) : DebuffTrigger(botAI, "corruption", 1, true) { } \ + bool IsActive() override { + return DebuffTrigger::IsActive() && !botAI->HasAura("seed of corruption", GetTarget(), false, true) ; + } +}; + DEBUFF_CHECKISOWNER_TRIGGER(SiphonLifeTrigger, "siphon life"); class CorruptionOnAttackerTrigger : public DebuffOnAttackerTrigger { public: CorruptionOnAttackerTrigger(PlayerbotAI* botAI) : DebuffOnAttackerTrigger(botAI, "corruption", true) { } + bool IsActive() override { + return DebuffOnAttackerTrigger::IsActive() && !botAI->HasAura("seed of corruption", GetTarget(), false, true) ; + } }; class CastCurseOfAgonyOnAttackerTrigger : public DebuffOnAttackerTrigger From 21ce849da7d900e5967faf710b39596e2e7e00fb Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Sun, 7 Jul 2024 13:32:26 +0800 Subject: [PATCH 06/51] [Command] Autogear command ammo --- src/strategy/actions/TrainerAction.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/strategy/actions/TrainerAction.cpp b/src/strategy/actions/TrainerAction.cpp index 2454e563..af1e7a7c 100644 --- a/src/strategy/actions/TrainerAction.cpp +++ b/src/strategy/actions/TrainerAction.cpp @@ -198,6 +198,7 @@ bool AutoGearAction::Execute(Event event) sPlayerbotAIConfig->autoGearQualityLimit, gs); factory.InitEquipment(true); + factory.InitAmmo(); if (bot->getLevel() >= sPlayerbotAIConfig->minEnchantingBotLevel) { factory.ApplyEnchantAndGemsNew(); } From 32d30eaf6bcf6a6414a7b9c134da0524478ce08c Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Sun, 7 Jul 2024 13:32:43 +0800 Subject: [PATCH 07/51] [Command] Disperse command tips --- src/strategy/actions/MovementActions.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/strategy/actions/MovementActions.cpp b/src/strategy/actions/MovementActions.cpp index 0a47c8ea..d9ab66fc 100644 --- a/src/strategy/actions/MovementActions.cpp +++ b/src/strategy/actions/MovementActions.cpp @@ -1911,10 +1911,10 @@ bool DisperseSetAction::Execute(Event event) return true; } std::ostringstream out; - out << "Usage: disperse [enable|disable|increase|decrease|set {distance}]" << "\n"; + out << "Usage: disperse [enable | disable | increase | decrease | set {distance}]"; float dis = AI_VALUE(float, "disperse distance"); if (dis > 0.0f) { - out << "Current disperse distance: " << std::setprecision(2) << dis; + out << "(Current disperse distance: " << std::setprecision(2) << dis << ")"; } botAI->TellMasterNoFacing(out.str()); return true; From 7325ba7dcb844227feccab19246117b08be1b01e Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Sun, 7 Jul 2024 21:51:19 +0800 Subject: [PATCH 08/51] [Class spell] Aoe threat check --- src/strategy/actions/UseMeetingStoneAction.cpp | 2 +- src/strategy/deathknight/DKActions.h | 2 -- src/strategy/mage/MageActions.h | 2 ++ src/strategy/priest/PriestActions.h | 1 + src/strategy/shaman/ShamanActions.h | 1 + src/strategy/values/PartyMemberToHeal.cpp | 2 +- src/strategy/warlock/WarlockActions.h | 4 ++-- 7 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/strategy/actions/UseMeetingStoneAction.cpp b/src/strategy/actions/UseMeetingStoneAction.cpp index 3ef46e21..b0a68990 100644 --- a/src/strategy/actions/UseMeetingStoneAction.cpp +++ b/src/strategy/actions/UseMeetingStoneAction.cpp @@ -82,7 +82,7 @@ bool SummonAction::Execute(Event event) } if (master->GetSession()->GetSecurity() >= SEC_PLAYER) { - botAI->GetAiObjectContext()->GetValue("prioritized targets")->Set({}); + // botAI->GetAiObjectContext()->GetValue("prioritized targets")->Set({}); return Teleport(master, bot); } diff --git a/src/strategy/deathknight/DKActions.h b/src/strategy/deathknight/DKActions.h index 6106af18..e4907ac8 100644 --- a/src/strategy/deathknight/DKActions.h +++ b/src/strategy/deathknight/DKActions.h @@ -234,8 +234,6 @@ class CastDeathAndDecayAction : public CastSpellAction { public: CastDeathAndDecayAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "death and decay") { } - - ActionThreatType getThreatType() override { return ActionThreatType::Aoe; } }; class CastHornOfWinterAction : public CastSpellAction diff --git a/src/strategy/mage/MageActions.h b/src/strategy/mage/MageActions.h index a2b83bf8..1303498a 100644 --- a/src/strategy/mage/MageActions.h +++ b/src/strategy/mage/MageActions.h @@ -203,12 +203,14 @@ class CastDragonsBreathAction : public CastSpellAction { public: CastDragonsBreathAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "dragon's breath") { } + ActionThreatType getThreatType() override { return ActionThreatType::Aoe; } }; class CastBlastWaveAction : public CastSpellAction { public: CastBlastWaveAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "blast wave") { } + ActionThreatType getThreatType() override { return ActionThreatType::Aoe; } }; class CastInvisibilityAction : public CastBuffSpellAction diff --git a/src/strategy/priest/PriestActions.h b/src/strategy/priest/PriestActions.h index 9aab4eb3..5e4737b9 100644 --- a/src/strategy/priest/PriestActions.h +++ b/src/strategy/priest/PriestActions.h @@ -161,5 +161,6 @@ class CastMindSearAction : public CastSpellAction { public: CastMindSearAction(PlayerbotAI* ai) : CastSpellAction(ai, "mind sear") {} + ActionThreatType getThreatType() override { return ActionThreatType::Aoe; } }; #endif diff --git a/src/strategy/shaman/ShamanActions.h b/src/strategy/shaman/ShamanActions.h index 24226b7a..c9467e49 100644 --- a/src/strategy/shaman/ShamanActions.h +++ b/src/strategy/shaman/ShamanActions.h @@ -323,6 +323,7 @@ class CastChainLightningAction : public CastSpellAction { public: CastChainLightningAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "chain lightning") { } + ActionThreatType getThreatType() override { return ActionThreatType::Aoe; } }; class CastLightningBoltAction : public CastSpellAction diff --git a/src/strategy/values/PartyMemberToHeal.cpp b/src/strategy/values/PartyMemberToHeal.cpp index 0f76b6e7..a7cba48e 100644 --- a/src/strategy/values/PartyMemberToHeal.cpp +++ b/src/strategy/values/PartyMemberToHeal.cpp @@ -74,7 +74,7 @@ bool PartyMemberToHeal::Check(Unit* player) { // return player && player != bot && player->GetMapId() == bot->GetMapId() && player->IsInWorld() && // sServerFacade->GetDistance2d(bot, player) < (player->IsPlayer() && botAI->IsTank((Player*)player) ? 50.0f : 40.0f); - return player->GetMapId() == bot->GetMapId() && + return player->GetMapId() == bot->GetMapId() && !player->IsCharmed() && bot->GetDistance2d(player) < sPlayerbotAIConfig->healDistance * 2 && bot->IsWithinLOS(player->GetPositionX(), player->GetPositionY(), player->GetPositionZ()); } diff --git a/src/strategy/warlock/WarlockActions.h b/src/strategy/warlock/WarlockActions.h index 813374a0..28f689d3 100644 --- a/src/strategy/warlock/WarlockActions.h +++ b/src/strategy/warlock/WarlockActions.h @@ -70,7 +70,6 @@ class CastCorruptionAction : public CastDebuffSpellAction bool isUseful() override { return CastDebuffSpellAction::isUseful() && !botAI->HasAura("seed of corruption", GetTarget(), false, true) ; } - ActionThreatType getThreatType() override { return ActionThreatType::Aoe; } }; class CastCorruptionOnAttackerAction : public CastDebuffSpellOnAttackerAction @@ -80,7 +79,6 @@ class CastCorruptionOnAttackerAction : public CastDebuffSpellOnAttackerAction bool isUseful() override { return CastDebuffSpellOnAttackerAction::isUseful() && !botAI->HasAura("seed of corruption", GetTarget(), false, true) ; } - ActionThreatType getThreatType() override { return ActionThreatType::Aoe; } }; class CastCurseOfAgonyOnAttackerAction : public CastDebuffSpellOnAttackerAction @@ -153,6 +151,7 @@ class CastSeedOfCorruptionAction : public CastDebuffSpellAction bool isUseful() override { return CastDebuffSpellAction::isUseful() && !botAI->HasAura("corruption", GetTarget(), false, true) ; } + ActionThreatType getThreatType() override { return ActionThreatType::Aoe; } }; class CastSeedOfCorruptionOnAttackerAction : public CastDebuffSpellOnAttackerAction @@ -162,6 +161,7 @@ class CastSeedOfCorruptionOnAttackerAction : public CastDebuffSpellOnAttackerAct bool isUseful() override { return CastDebuffSpellOnAttackerAction::isUseful() && !botAI->HasAura("corruption", GetTarget(), false, true) ; } + ActionThreatType getThreatType() override { return ActionThreatType::Aoe; } }; class CastRainOfFireAction : public CastSpellAction From b55c9b14d1280d34d6b6cad40fd1ce564ede2da2 Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Tue, 9 Jul 2024 00:08:20 +0800 Subject: [PATCH 09/51] [Combat formation] Last flee angle check --- src/strategy/Value.h | 17 +++++++++- src/strategy/actions/MovementActions.cpp | 42 ++++++++++++++++++++---- src/strategy/actions/MovementActions.h | 1 + src/strategy/values/ValueContext.h | 4 +++ 4 files changed, 57 insertions(+), 7 deletions(-) diff --git a/src/strategy/Value.h b/src/strategy/Value.h index e27600ad..1a7e05ef 100644 --- a/src/strategy/Value.h +++ b/src/strategy/Value.h @@ -329,7 +329,22 @@ class UnitManualSetValue : public ManualSetValue class DisperseDistanceValue : public ManualSetValue { public: - DisperseDistanceValue(PlayerbotAI* botAI, float defaultValue = -1.0f, std::string const name = "disperse value") : + DisperseDistanceValue(PlayerbotAI* botAI, float defaultValue = -1.0f, std::string const name = "disperse distance") : ManualSetValue(botAI, defaultValue, name) { } }; + +class LastFleeAngleValue : public ManualSetValue +{ + public: + LastFleeAngleValue(PlayerbotAI* botAI, float defaultValue = 0.0f, std::string const name = "last flee angle") : + ManualSetValue(botAI, defaultValue, name) { } +}; + +class LastFleeTimestampValue : public ManualSetValue +{ + public: + LastFleeTimestampValue(PlayerbotAI* botAI, uint32 defaultValue = 0, std::string const name = "last flee timestamp") : + ManualSetValue(botAI, defaultValue, name) { } +}; + #endif diff --git a/src/strategy/actions/MovementActions.cpp b/src/strategy/actions/MovementActions.cpp index d9ab66fc..06bc7d74 100644 --- a/src/strategy/actions/MovementActions.cpp +++ b/src/strategy/actions/MovementActions.cpp @@ -4,6 +4,7 @@ #include "MovementActions.h" #include "GameObject.h" +#include "Geometry.h" #include "Map.h" #include "MotionMaster.h" #include "MoveSplineInitArgs.h" @@ -31,6 +32,8 @@ #include "Unit.h" #include "Vehicle.h" #include "WaypointMovementGenerator.h" +#include +#include #include #include @@ -1511,17 +1514,14 @@ bool AvoidAoeAction::Execute(Event event) { // Case #1: Aura with dynamic object (e.g. rain of fire) if (AvoidAuraWithDynamicObj()) { - lastMoveTimer = getMSTime(); return true; } // Case #2: Trap game object with spell (e.g. lava bomb) if (AvoidGameObjectWithDamage()) { - lastMoveTimer = getMSTime(); return true; } // Case #3: Trigger npc (e.g. Lesser shadow fissure) if (AvoidUnitWithDamageAura()) { - lastMoveTimer = getMSTime(); return true; } return false; @@ -1550,10 +1550,11 @@ bool AvoidAoeAction::AvoidAuraWithDynamicObj() return false; } std::ostringstream name; - name << spellInfo->SpellName[0]; // << "] (aura)"; + name << spellInfo->SpellName[sWorld->GetDefaultDbcLocale()]; // << "] (aura)"; if (FleePosition(dynOwner->GetPosition(), radius)) { if (sPlayerbotAIConfig->tellWhenAvoidAoe && lastTellTimer < time(NULL) - 10) { lastTellTimer = time(NULL); + lastMoveTimer = getMSTime(); std::ostringstream out; out << "I'm avoiding " << name.str() << "..."; bot->Say(out.str(), LANG_UNIVERSAL); @@ -1607,10 +1608,11 @@ bool AvoidAoeAction::AvoidGameObjectWithDamage() continue; } std::ostringstream name; - name << spellInfo->SpellName[0]; // << "] (object)"; + name << spellInfo->SpellName[sWorld->GetDefaultDbcLocale()]; // << "] (object)"; if (FleePosition(go->GetPosition(), radius)) { if (sPlayerbotAIConfig->tellWhenAvoidAoe && lastTellTimer < time(NULL) - 10) { lastTellTimer = time(NULL); + lastMoveTimer = getMSTime(); std::ostringstream out; out << "I'm avoiding " << name.str() << "..."; bot->Say(out.str(), LANG_UNIVERSAL); @@ -1655,10 +1657,11 @@ bool AvoidAoeAction::AvoidUnitWithDamageAura() break; } std::ostringstream name; - name << triggerSpellInfo->SpellName[0]; //<< "] (unit)"; + name << triggerSpellInfo->SpellName[sWorld->GetDefaultDbcLocale()]; //<< "] (unit)"; if (FleePosition(unit->GetPosition(), radius)) { if (sPlayerbotAIConfig->tellWhenAvoidAoe && lastTellTimer < time(NULL) - 10) { lastTellTimer = time(NULL); + lastMoveTimer = getMSTime(); std::ostringstream out; out << "I'm avoiding " << name.str() << "..."; bot->Say(out.str(), LANG_UNIVERSAL); @@ -1697,6 +1700,11 @@ Position MovementAction::BestPositionForMeleeToFlee(Position pos, float radius) Position bestPos; for (CheckAngle &checkAngle : possibleAngles) { float angle = checkAngle.angle; + float lastFleeAngle = AI_VALUE(float, "last flee angle"); + uint32 lastFleeTimestamp = AI_VALUE(uint32, "last flee timestamp"); + if (!CheckLastFlee(angle, lastFleeAngle, lastFleeTimestamp)) { + continue; + } bool strict = checkAngle.strict; float fleeDis = std::min(radius + 1.0f, sPlayerbotAIConfig->fleeDistance); Position fleePos{bot->GetPositionX() + cos(angle) * fleeDis, @@ -1740,6 +1748,11 @@ Position MovementAction::BestPositionForRangedToFlee(Position pos, float radius) Position bestPos; for (CheckAngle &checkAngle : possibleAngles) { float angle = checkAngle.angle; + float lastFleeAngle = AI_VALUE(float, "last flee angle"); + uint32 lastFleeTimestamp = AI_VALUE(uint32, "last flee timestamp"); + if (!CheckLastFlee(angle, lastFleeAngle, lastFleeTimestamp)) { + continue; + } bool strict = checkAngle.strict; float fleeDis = std::min(radius + 1.0f, sPlayerbotAIConfig->fleeDistance); Position fleePos{bot->GetPositionX() + cos(angle) * fleeDis, @@ -1774,12 +1787,29 @@ bool MovementAction::FleePosition(Position pos, float radius) } if (bestPos != Position()) { if (MoveTo(bot->GetMapId(), bestPos.GetPositionX(), bestPos.GetPositionY(), bestPos.GetPositionZ(), false, false, true)) { + SET_AI_VALUE(float, "last flee angle", bot->GetAngle(&bestPos)); + SET_AI_VALUE(uint32, "last flee timestamp", getMSTime()); return true; } } return false; } +bool MovementAction::CheckLastFlee(float curAngle, float lastAngle, uint32 lastTS) +{ + // more than 5 sec + if (lastTS + 5000 < getMSTime()) { + return true; + } + float revAngle = fmod(lastAngle + M_PI, 2 * M_PI); + curAngle = fmod(curAngle, 2 * M_PI); + // angle too close + if (fabs(revAngle - curAngle) < M_PI / 8) { + return false; + } + return true; +} + bool CombatFormationMoveAction::isUseful() { if (getMSTime() - moveInterval < lastMoveTimer) { diff --git a/src/strategy/actions/MovementActions.h b/src/strategy/actions/MovementActions.h index ed9527af..0db8e7cd 100644 --- a/src/strategy/actions/MovementActions.h +++ b/src/strategy/actions/MovementActions.h @@ -44,6 +44,7 @@ class MovementAction : public Action Position BestPositionForMeleeToFlee(Position pos, float radius); Position BestPositionForRangedToFlee(Position pos, float radius); bool FleePosition(Position pos, float radius); + bool CheckLastFlee(float curAngle, float lastAngle, uint32 lastTS); protected: struct CheckAngle { float angle; diff --git a/src/strategy/values/ValueContext.h b/src/strategy/values/ValueContext.h index fe08de8b..e202ff8d 100644 --- a/src/strategy/values/ValueContext.h +++ b/src/strategy/values/ValueContext.h @@ -302,6 +302,8 @@ class ValueContext : public NamedObjectContext creators["area debuff"] = &ValueContext::area_debuff; creators["nearest trap with damage"] = &ValueContext::nearest_trap_with_damange; creators["disperse distance"] = &ValueContext::disperse_distance; + creators["last flee angle"] = &ValueContext::last_flee_angle; + creators["last flee timestamp"] = &ValueContext::last_flee_timestamp; } private: @@ -507,6 +509,8 @@ class ValueContext : public NamedObjectContext static UntypedValue* area_debuff(PlayerbotAI* ai) { return new AreaDebuffValue(ai); } static UntypedValue* nearest_trap_with_damange(PlayerbotAI* ai) { return new NearestTrapWithDamageValue(ai); } static UntypedValue* disperse_distance(PlayerbotAI* ai) { return new DisperseDistanceValue(ai); } + static UntypedValue* last_flee_angle(PlayerbotAI* ai) { return new LastFleeAngleValue(ai); } + static UntypedValue* last_flee_timestamp(PlayerbotAI* ai) { return new LastFleeTimestampValue(ai); } }; #endif From fe64d9ce005a9857a6b97ff59b31215c874bb94c Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Tue, 9 Jul 2024 16:39:50 +0800 Subject: [PATCH 10/51] [Combat formation] Avoid flee repeatly --- src/Playerbots.h | 2 + src/strategy/Value.h | 40 ++++++++++++++- src/strategy/actions/MovementActions.cpp | 50 ++++++++++++------- src/strategy/actions/MovementActions.h | 3 +- .../actions/UseMeetingStoneAction.cpp | 1 + src/strategy/values/ValueContext.h | 2 + 6 files changed, 79 insertions(+), 19 deletions(-) diff --git a/src/Playerbots.h b/src/Playerbots.h index 66ec850c..7e678af3 100644 --- a/src/Playerbots.h +++ b/src/Playerbots.h @@ -34,6 +34,8 @@ int strcmpi(char const* s1, char const* s2); #define AI_VALUE_LAZY(type, name) context->GetValue(name)->LazyGet() #define AI_VALUE2_LAZY(type, name, param) context->GetValue(name, param)->LazyGet() +#define AI_VALUE_REF(type, name) context->GetValue(name)->RefGet() + #define SET_AI_VALUE(type, name, value) context->GetValue(name)->Set(value) #define SET_AI_VALUE2(type, name, param, value) context->GetValue(name, param)->Set(value) #define RESET_AI_VALUE(type, name) context->GetValue(name)->Reset() diff --git a/src/strategy/Value.h b/src/strategy/Value.h index 1a7e05ef..4d4196a3 100644 --- a/src/strategy/Value.h +++ b/src/strategy/Value.h @@ -16,6 +16,16 @@ class PlayerbotAI; class Unit; +class FleeInfo +{ + public: + Position fromPos; + float radius; + float angle; + uint32 timestamp; + int GetAngleRangeIndex() { return (angle + 2 * M_PI) / (M_PI / 2); } // [0, 7) +}; + struct CreatureData; class UntypedValue : public AiNamedObject @@ -37,6 +47,7 @@ class Value virtual ~Value() { } virtual T Get() = 0; virtual T LazyGet() = 0; + virtual T& RefGet() = 0; virtual void Reset() { } virtual void Set(T value) = 0; operator T() { return Get(); } @@ -79,7 +90,26 @@ class CalculatedValue : public UntypedValue, public Value return value; } - + T& RefGet() override + { + if (checkInterval < 2) { + // PerformanceMonitorOperation* pmo = sPerformanceMonitor->start(PERF_MON_VALUE, this->getName(), this->context ? &this->context->performanceStack : nullptr); + value = Calculate(); + // if (pmo) + // pmo->finish(); + } else { + time_t now = getMSTime(); + if (!lastCheckTime || now - lastCheckTime >= checkInterval) + { + lastCheckTime = now; + // PerformanceMonitorOperation* pmo = sPerformanceMonitor->start(PERF_MON_VALUE, this->getName(), this->context ? &this->context->performanceStack : nullptr); + value = Calculate(); + // if (pmo) + // pmo->finish(); + } + } + return value; + } void Set(T val) override { value = val; } void Update() override {} void Reset() override { lastCheckTime = 0; } @@ -304,6 +334,7 @@ class ManualSetValue : public UntypedValue, public Value T Get() override { return value; } T LazyGet() override { return value; } + T& RefGet() override { return value; } void Set(T val) override { value = val; } void Update() override {} void Reset() override @@ -347,4 +378,11 @@ class LastFleeTimestampValue : public ManualSetValue ManualSetValue(botAI, defaultValue, name) { } }; +class RecentlyFleeInfo : public ManualSetValue> +{ + public: + RecentlyFleeInfo(PlayerbotAI* botAI, std::list defaultValue = {}, std::string const name = "recently flee info") : + ManualSetValue>(botAI, defaultValue, name) { } +}; + #endif diff --git a/src/strategy/actions/MovementActions.cpp b/src/strategy/actions/MovementActions.cpp index 06bc7d74..b1a1fbe3 100644 --- a/src/strategy/actions/MovementActions.cpp +++ b/src/strategy/actions/MovementActions.cpp @@ -1700,9 +1700,8 @@ Position MovementAction::BestPositionForMeleeToFlee(Position pos, float radius) Position bestPos; for (CheckAngle &checkAngle : possibleAngles) { float angle = checkAngle.angle; - float lastFleeAngle = AI_VALUE(float, "last flee angle"); - uint32 lastFleeTimestamp = AI_VALUE(uint32, "last flee timestamp"); - if (!CheckLastFlee(angle, lastFleeAngle, lastFleeTimestamp)) { + auto& infoList = AI_VALUE_REF(std::list, "recently flee info"); + if (!CheckLastFlee(angle, infoList)) { continue; } bool strict = checkAngle.strict; @@ -1748,9 +1747,8 @@ Position MovementAction::BestPositionForRangedToFlee(Position pos, float radius) Position bestPos; for (CheckAngle &checkAngle : possibleAngles) { float angle = checkAngle.angle; - float lastFleeAngle = AI_VALUE(float, "last flee angle"); - uint32 lastFleeTimestamp = AI_VALUE(uint32, "last flee timestamp"); - if (!CheckLastFlee(angle, lastFleeAngle, lastFleeTimestamp)) { + auto& infoList = AI_VALUE_REF(std::list, "recently flee info"); + if (!CheckLastFlee(angle, infoList)) { continue; } bool strict = checkAngle.strict; @@ -1787,25 +1785,43 @@ bool MovementAction::FleePosition(Position pos, float radius) } if (bestPos != Position()) { if (MoveTo(bot->GetMapId(), bestPos.GetPositionX(), bestPos.GetPositionY(), bestPos.GetPositionZ(), false, false, true)) { - SET_AI_VALUE(float, "last flee angle", bot->GetAngle(&bestPos)); - SET_AI_VALUE(uint32, "last flee timestamp", getMSTime()); + auto& infoList = AI_VALUE_REF(std::list, "recently flee info"); + uint32 curTS = getMSTime(); + while (!infoList.empty()) { + if (infoList.size() > 10 || infoList.front().timestamp + 5000 < curTS) { + infoList.pop_front(); + } else { + break; + } + } + infoList.push_back({pos, radius, bot->GetAngle(&bestPos), curTS}); return true; } } return false; } -bool MovementAction::CheckLastFlee(float curAngle, float lastAngle, uint32 lastTS) +bool MovementAction::CheckLastFlee(float curAngle, std::list& infoList) { - // more than 5 sec - if (lastTS + 5000 < getMSTime()) { - return true; - } - float revAngle = fmod(lastAngle + M_PI, 2 * M_PI); + uint32 curTS = getMSTime(); curAngle = fmod(curAngle, 2 * M_PI); - // angle too close - if (fabs(revAngle - curAngle) < M_PI / 8) { - return false; + while (!infoList.empty()) { + if (infoList.size() > 10 || infoList.front().timestamp + 5000 < curTS) { + infoList.pop_front(); + } else { + break; + } + } + for (FleeInfo& info : infoList) { + // more than 5 sec + if (info.timestamp + 5000 < curTS) { + continue; + } + float revAngle = fmod(info.angle + M_PI, 2 * M_PI); + // angle too close + if (fabs(revAngle - curAngle) < M_PI / 8) { + return false; + } } return true; } diff --git a/src/strategy/actions/MovementActions.h b/src/strategy/actions/MovementActions.h index 0db8e7cd..c00ee5c8 100644 --- a/src/strategy/actions/MovementActions.h +++ b/src/strategy/actions/MovementActions.h @@ -13,6 +13,7 @@ class Player; class PlayerbotAI; class Unit; class WorldObject; +class Position; class MovementAction : public Action { @@ -44,7 +45,7 @@ class MovementAction : public Action Position BestPositionForMeleeToFlee(Position pos, float radius); Position BestPositionForRangedToFlee(Position pos, float radius); bool FleePosition(Position pos, float radius); - bool CheckLastFlee(float curAngle, float lastAngle, uint32 lastTS); + bool CheckLastFlee(float curAngle, std::list& infoList); protected: struct CheckAngle { float angle; diff --git a/src/strategy/actions/UseMeetingStoneAction.cpp b/src/strategy/actions/UseMeetingStoneAction.cpp index b0a68990..0d4be53e 100644 --- a/src/strategy/actions/UseMeetingStoneAction.cpp +++ b/src/strategy/actions/UseMeetingStoneAction.cpp @@ -83,6 +83,7 @@ bool SummonAction::Execute(Event event) if (master->GetSession()->GetSecurity() >= SEC_PLAYER) { // botAI->GetAiObjectContext()->GetValue("prioritized targets")->Set({}); + SET_AI_VALUE(std::list, "recently flee info", {}); return Teleport(master, bot); } diff --git a/src/strategy/values/ValueContext.h b/src/strategy/values/ValueContext.h index e202ff8d..2888b246 100644 --- a/src/strategy/values/ValueContext.h +++ b/src/strategy/values/ValueContext.h @@ -304,6 +304,7 @@ class ValueContext : public NamedObjectContext creators["disperse distance"] = &ValueContext::disperse_distance; creators["last flee angle"] = &ValueContext::last_flee_angle; creators["last flee timestamp"] = &ValueContext::last_flee_timestamp; + creators["recently flee info"] = &ValueContext::recently_flee_info; } private: @@ -511,6 +512,7 @@ class ValueContext : public NamedObjectContext static UntypedValue* disperse_distance(PlayerbotAI* ai) { return new DisperseDistanceValue(ai); } static UntypedValue* last_flee_angle(PlayerbotAI* ai) { return new LastFleeAngleValue(ai); } static UntypedValue* last_flee_timestamp(PlayerbotAI* ai) { return new LastFleeTimestampValue(ai); } + static UntypedValue* recently_flee_info(PlayerbotAI* ai) { return new RecentlyFleeInfo(ai); } }; #endif From ff7b58082d6c2fec86c5b46223f6e81e5842f63f Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Tue, 9 Jul 2024 17:29:54 +0800 Subject: [PATCH 11/51] [Combat formation] Flee optimize --- src/strategy/actions/MovementActions.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/strategy/actions/MovementActions.cpp b/src/strategy/actions/MovementActions.cpp index b1a1fbe3..f86d539e 100644 --- a/src/strategy/actions/MovementActions.cpp +++ b/src/strategy/actions/MovementActions.cpp @@ -1710,7 +1710,8 @@ Position MovementAction::BestPositionForMeleeToFlee(Position pos, float radius) bot->GetPositionY() + sin(angle) * fleeDis, bot->GetPositionZ()}; if (strict && currentTarget - && fleePos.GetExactDist(currentTarget) - currentTarget->GetCombatReach() > sPlayerbotAIConfig->tooCloseDistance) { + && fleePos.GetExactDist(currentTarget) - currentTarget->GetCombatReach() > sPlayerbotAIConfig->tooCloseDistance + && bot->IsWithinMeleeRange(currentTarget)) { continue; } if (pos.GetExactDist(fleePos) > farestDis) { @@ -1819,7 +1820,7 @@ bool MovementAction::CheckLastFlee(float curAngle, std::list& infoList } float revAngle = fmod(info.angle + M_PI, 2 * M_PI); // angle too close - if (fabs(revAngle - curAngle) < M_PI / 8) { + if (fabs(revAngle - curAngle) < M_PI / 4) { return false; } } From bd9434373815d36931e35340cbe3107fb3e5f8ad Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Tue, 9 Jul 2024 17:32:13 +0800 Subject: [PATCH 12/51] [Configuration] Make some configs deprecated --- conf/playerbots.conf.dist | 135 ++++++++++++++++++++------------------ src/PlayerbotAI.cpp | 22 +++---- src/PlayerbotAIConfig.cpp | 4 +- 3 files changed, 83 insertions(+), 78 deletions(-) diff --git a/conf/playerbots.conf.dist b/conf/playerbots.conf.dist index eb2fb3f1..3a3c2736 100644 --- a/conf/playerbots.conf.dist +++ b/conf/playerbots.conf.dist @@ -21,18 +21,9 @@ AiPlayerbot.BotAutologin = 0 # Default: 0 (disabled) AiPlayerbot.AllowPlayerBots = 0 -# Guild Task system -AiPlayerbot.EnableGuildTasks = 0 - # Enable LFG for random bots AiPlayerbot.RandomBotJoinLfg = 1 -# Enable dungeon suggestions for random bots -AiPlayerbot.RandomBotSuggestDungeons = 1 - -# Enable dungeon suggestions in lower case randomly -AiPlayerbot.SuggestDungeonsInLowerCaseRandomly = 0 - # Enable BG/Arena for random Bots AiPlayerbot.RandomBotJoinBG = 1 @@ -60,12 +51,6 @@ AiPlayerbot.RotationPoolSize = 500 AiPlayerbot.RandomBotAccountPrefix = "rndbot" AiPlayerbot.RandomBotAccountCount = 200 -# Random bot guild count -AiPlayerbot.RandomBotGuildCount = 20 - -# Delete all random bot guilds -AiPlayerbot.DeleteRandomBotGuilds = 0 - # Random bot arena team count AiPlayerbot.RandomBotArenaTeamCount = 20 @@ -78,18 +63,6 @@ AiPlayerbot.RandomGearLoweringChance = 0 # Chance random bot has max level on first randomize (default 0.15) AiPlayerbot.RandomBotMaxLevelChance = 0.15 -# Chance bot chooses RPG (Teleport to random camp for their level) instead of grinding -AiPlayerbot.RandomBotRpgChance = 0.20 #unused now - -# Set randombots movement speed to walking anywhere -AiPlayerbot.RandombotsWalkingRPG = 0 - -# Set randombots movement speed to walking only inside buildings -AiPlayerbot.RandombotsWalkingRPG.InDoors = 0 - -# Bots greet to the players -AiPlayerbot.EnableGreet = 0 - # Bots will be summoned to player when accept group invitation AiPlayerbot.SummonWhenGroup = 1 @@ -116,10 +89,6 @@ AiPlayerbot.KillXPRate = 1 # Need to reset rndbot after changing the setting (.playerbot rndbot reset) AiPlayerbot.DisableDeathKnightLogin = 0 -# Specify percent of active bots -# The default is 10. With 10% of all bots going active or inactive each minute. -AiPlayerbot.BotActiveAlone = 100 - # Set minimum level of randombots where gets enchants on items (Maxlevel + 1 to disable) # Default: 60 AiPlayerbot.MinEnchantingBotLevel = 60 @@ -296,7 +265,7 @@ AiPlayerbot.ReactDelay = 100 AiPlayerbot.PassiveDelay = 10000 # Minimum delay between repeating actions (chat messages, emotes etc) -AiPlayerbot.RepeatDelay = 5000 +AiPlayerbot.RepeatDelay = 2000 # Delay timers AiPlayerbot.ErrorDelay = 100 @@ -352,10 +321,6 @@ AiPlayerbot.AutoAvoidAoe = 1 # Default: 1 (enable) AiPlayerbot.TellWhenAvoidAoe = 1 -# Premade spell to avoid (undetected spells) -# spellid-radius, ... -AiPlayerbot.PremadeAvoidAoe = 62234-4 - # Random bot default strategies (applied after defaults) AiPlayerbot.RandomBotCombatStrategies = "+dps,+dps assist,-threat" # AiPlayerbot.RandomBotNonCombatStrategies = "+grind,+loot,+rpg,+custom::say" @@ -363,27 +328,6 @@ AiPlayerbot.RandomBotNonCombatStrategies = "" AiPlayerbot.CombatStrategies = "" AiPlayerbot.NonCombatStrategies = "" -# How often tasks are changed -AiPlayerbot.MinGuildTaskChangeTime = 172800 -AiPlayerbot.MaxGuildTaskChangeTime = 432000 - -# Mail spam interval -AiPlayerbot.MinGuildTaskAdvertisementTime = 300 -AiPlayerbot.MaxGuildTaskAdvertisementTime = 28800 - -# Delay before reward is sent -AiPlayerbot.MinGuildTaskRewardTime = 300 -AiPlayerbot.MaxGuildTaskRewardTime = 3600 - -# Cleanup of guild tasks interval -AiPlayerbot.GuildTaskAdvertCleanupTime = 300 - -# Specify max distance between victim and bot when creating guild kill task -AiPlayerbot.GuildTaskKillTaskDistance = 200 - -# Distance margin for facade calculations -AiPlayerbot.TargetPosRecalcDistance = 0.1 - # Maps where bots can be teleported to AiPlayerbot.RandomBotMaps = 0,1,530,571 @@ -417,12 +361,8 @@ AiPlayerbot.RandomBotCountChangeMaxInterval = 7200 AiPlayerbot.MinRandomBotInWorldTime = 3600 AiPlayerbot.MaxRandomBotInWorldTime = 43200 AiPlayerbot.MinRandomBotRandomizeTime = 302400 -AiPlayerbot.MaxRandomRandomizeTime = 1209600 +AiPlayerbot.MaxRandomBotRandomizeTime = 1209600 AiPlayerbot.RandomBotsPerInterval = 500 -AiPlayerbot.MinRandomBotsPriceChangeInterval = 7200 -AiPlayerbot.MaxRandomBotsPriceChangeInterval = 172800 -AiPlayerbot.MinRandomBotChangeStrategyTime = 180 -AiPlayerbot.MaxRandomBotChangeStrategyTime = 720 AiPlayerbot.MinRandomBotReviveTime = 60 AiPlayerbot.MaxRandomBotReviveTime = 300 AiPlayerbot.MinRandomBotTeleportInterval = 3600 @@ -444,9 +384,6 @@ AiPlayerbot.CommandServerPort = 8888 # Enables/Disables performance monitor AiPlayerbot.PerfMonEnabled = 0 -# Allow bots to be summoned near innkeepers -AiPlayerbot.SummonAtInnkeepersEnabled = 1 - # Custom config to allow logfiles to be created. # Example: AiPlayerbot.AllowedLogFiles = travelNodes.csv,travelPaths.csv,TravelNodeStore.h,bot_movement.csv,bot_location.csv AiPlayerbot.AllowedLogFiles = "" @@ -748,6 +685,74 @@ AiPlayerbot.RandomClassSpecIndex.11.1 = 1 AiPlayerbot.RandomClassSpecProb.11.2 = 40 AiPlayerbot.RandomClassSpecIndex.11.2 = 2 +############################################## +# Deprecated (temporary) # +############################################## +# Guild Task system +AiPlayerbot.EnableGuildTasks = 0 + +# Enable dungeon suggestions for random bots +AiPlayerbot.RandomBotSuggestDungeons = 1 + +# Enable dungeon suggestions in lower case randomly +AiPlayerbot.SuggestDungeonsInLowerCaseRandomly = 0 + +# Random bot guild count +AiPlayerbot.RandomBotGuildCount = 20 + +# Delete all random bot guilds +AiPlayerbot.DeleteRandomBotGuilds = 0 + +# Chance bot chooses RPG (Teleport to random camp for their level) instead of grinding +AiPlayerbot.RandomBotRpgChance = 0.20 #unused now + +# Set randombots movement speed to walking anywhere +AiPlayerbot.RandombotsWalkingRPG = 0 + +# Set randombots movement speed to walking only inside buildings +AiPlayerbot.RandombotsWalkingRPG.InDoors = 0 + +# Bots greet to the players +AiPlayerbot.EnableGreet = 0 + +# Specify percent of active bots +# The default is 10. With 10% of all bots going active or inactive each minute. +AiPlayerbot.BotActiveAlone = 100 + +# Premade spell to avoid (undetected spells) +# spellid-radius, ... +AiPlayerbot.PremadeAvoidAoe = 62234-4 + +AiPlayerbot.MinRandomBotsPriceChangeInterval = 7200 +AiPlayerbot.MaxRandomBotsPriceChangeInterval = 172800 +AiPlayerbot.MinRandomBotChangeStrategyTime = 180 +AiPlayerbot.MaxRandomBotChangeStrategyTime = 720 + + +# How often tasks are changed +AiPlayerbot.MinGuildTaskChangeTime = 172800 +AiPlayerbot.MaxGuildTaskChangeTime = 432000 + +# Mail spam interval +AiPlayerbot.MinGuildTaskAdvertisementTime = 300 +AiPlayerbot.MaxGuildTaskAdvertisementTime = 28800 + +# Delay before reward is sent +AiPlayerbot.MinGuildTaskRewardTime = 300 +AiPlayerbot.MaxGuildTaskRewardTime = 3600 + +# Cleanup of guild tasks interval +AiPlayerbot.GuildTaskAdvertCleanupTime = 300 + +# Specify max distance between victim and bot when creating guild kill task +AiPlayerbot.GuildTaskKillTaskDistance = 200 + +# Distance margin for facade calculations +AiPlayerbot.TargetPosRecalcDistance = 0.1 + +# Allow bots to be summoned near innkeepers +AiPlayerbot.SummonAtInnkeepersEnabled = 1 + ################################################################################## # # # Logging Stuff # diff --git a/src/PlayerbotAI.cpp b/src/PlayerbotAI.cpp index 25d92a1d..42ea3b7d 100644 --- a/src/PlayerbotAI.cpp +++ b/src/PlayerbotAI.cpp @@ -1900,19 +1900,19 @@ bool PlayerbotAI::TellMasterNoFacing(std::string const text, PlayerbotSecurityLe return false; time_t lastSaid = whispers[text]; - // Yunfan: Remove tell cooldown - // if (!lastSaid || (time(nullptr) - lastSaid) >= sPlayerbotAIConfig->repeatDelay / 1000) - // { - whispers[text] = time(nullptr); + + if (!lastSaid || (time(nullptr) - lastSaid) >= sPlayerbotAIConfig->repeatDelay / 1000) + { + whispers[text] = time(nullptr); - ChatMsg type = CHAT_MSG_WHISPER; - if (currentChat.second - time(nullptr) >= 1) - type = currentChat.first; + ChatMsg type = CHAT_MSG_WHISPER; + if (currentChat.second - time(nullptr) >= 1) + type = currentChat.first; - WorldPacket data; - ChatHandler::BuildChatPacket(data, type == CHAT_MSG_ADDON ? CHAT_MSG_PARTY : type, type == CHAT_MSG_ADDON ? LANG_ADDON : LANG_UNIVERSAL, bot, nullptr, text.c_str()); - master->SendDirectMessage(&data); - // } + WorldPacket data; + ChatHandler::BuildChatPacket(data, type == CHAT_MSG_ADDON ? CHAT_MSG_PARTY : type, type == CHAT_MSG_ADDON ? LANG_ADDON : LANG_UNIVERSAL, bot, nullptr, text.c_str()); + master->SendDirectMessage(&data); + } return true; } diff --git a/src/PlayerbotAIConfig.cpp b/src/PlayerbotAIConfig.cpp index d468533c..ed840e9c 100644 --- a/src/PlayerbotAIConfig.cpp +++ b/src/PlayerbotAIConfig.cpp @@ -58,7 +58,7 @@ bool PlayerbotAIConfig::Initialize() dispelAuraDuration = sConfigMgr->GetOption("AiPlayerbot.DispelAuraDuration", 7000); reactDelay = sConfigMgr->GetOption("AiPlayerbot.ReactDelay", 500); passiveDelay = sConfigMgr->GetOption("AiPlayerbot.PassiveDelay", 10000); - repeatDelay = sConfigMgr->GetOption("AiPlayerbot.RepeatDelay", 5000); + repeatDelay = sConfigMgr->GetOption("AiPlayerbot.RepeatDelay", 2000); errorDelay = sConfigMgr->GetOption("AiPlayerbot.ErrorDelay", 5000); rpgDelay = sConfigMgr->GetOption("AiPlayerbot.RpgDelay", 10000); sitDelay = sConfigMgr->GetOption("AiPlayerbot.SitDelay", 30000); @@ -123,7 +123,7 @@ bool PlayerbotAIConfig::Initialize() minRandomBotInWorldTime = sConfigMgr->GetOption("AiPlayerbot.MinRandomBotInWorldTime", 2 * HOUR); maxRandomBotInWorldTime = sConfigMgr->GetOption("AiPlayerbot.MaxRandomBotInWorldTime", 12 * HOUR); minRandomBotRandomizeTime = sConfigMgr->GetOption("AiPlayerbot.MinRandomBotRandomizeTime", 2 * HOUR); - maxRandomBotRandomizeTime = sConfigMgr->GetOption("AiPlayerbot.MaxRandomRandomizeTime", 14 * 24 * HOUR); + maxRandomBotRandomizeTime = sConfigMgr->GetOption("AiPlayerbot.MaxRandomBotRandomizeTime", 14 * 24 * HOUR); minRandomBotChangeStrategyTime = sConfigMgr->GetOption("AiPlayerbot.MinRandomBotChangeStrategyTime", 30 * MINUTE); maxRandomBotChangeStrategyTime = sConfigMgr->GetOption("AiPlayerbot.MaxRandomBotChangeStrategyTime", 2 * HOUR); minRandomBotReviveTime = sConfigMgr->GetOption("AiPlayerbot.MinRandomBotReviveTime", MINUTE); From b1f5c1313c296c970ba669fa15b821980e9999d7 Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Tue, 9 Jul 2024 17:33:09 +0800 Subject: [PATCH 13/51] [Strategy] Enable cat strategy, remove threat by default, reset strategy on talents change --- src/AiFactory.cpp | 46 ++++++++++++-------- src/strategy/actions/ChangeTalentsAction.cpp | 2 + src/strategy/druid/BearTankDruidStrategy.cpp | 2 +- src/strategy/druid/CasterDruidStrategy.cpp | 10 +++++ src/strategy/druid/CatDpsDruidStrategy.cpp | 2 +- 5 files changed, 41 insertions(+), 21 deletions(-) diff --git a/src/AiFactory.cpp b/src/AiFactory.cpp index 09401a82..d6baa1eb 100644 --- a/src/AiFactory.cpp +++ b/src/AiFactory.cpp @@ -279,7 +279,7 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa { case CLASS_PRIEST: if (tab == 2) { - engine->addStrategies("dps", "shadow debuff", "shadow aoe", "threat", nullptr); + engine->addStrategies("dps", "shadow debuff", "shadow aoe", nullptr); } else if (tab == PRIEST_TAB_DISIPLINE) { engine->addStrategies("heal", nullptr); } else { @@ -290,11 +290,11 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa break; case CLASS_MAGE: if (tab == 0) - engine->addStrategies("arcane", "arcane aoe", "threat", nullptr); + engine->addStrategies("arcane", "arcane aoe", nullptr); else if (tab == 1) - engine->addStrategies("fire", "fire aoe", "threat", nullptr); + engine->addStrategies("fire", "fire aoe", nullptr); else - engine->addStrategies("frost", "frost aoe", "threat", nullptr); + engine->addStrategies("frost", "frost aoe", nullptr); engine->addStrategies("dps", "dps assist", "cure", nullptr); break; @@ -302,17 +302,17 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa if (tab == 2) engine->addStrategies("tank", "tank assist", "aoe", "mark rti", nullptr); else if (player->getLevel() < 36 || tab == 0) - engine->addStrategies("arms", "aoe", "dps assist", "threat", /*"behind",*/ nullptr); + engine->addStrategies("arms", "aoe", "dps assist",/*"behind",*/ nullptr); else - engine->addStrategies("fury", "aoe", "dps assist", "threat", /*"behind",*/ nullptr); + engine->addStrategies("fury", "aoe", "dps assist",/*"behind",*/ nullptr); break; case CLASS_SHAMAN: if (tab == 0) - engine->addStrategies("caster", "caster aoe", "bmana", "threat", nullptr); + engine->addStrategies("caster", "caster aoe", "bmana",nullptr); else if (tab == 2) engine->addStrategies("heal", "bmana", nullptr); else - engine->addStrategies("melee", "melee aoe", "bdps", "threat", nullptr); + engine->addStrategies("melee", "melee aoe", "bdps", nullptr); engine->addStrategies("dps assist", "cure", "totems", nullptr); break; @@ -328,38 +328,41 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa case CLASS_DRUID: if (tab == 0) { - engine->addStrategies("caster", "cure", "caster aoe", "threat", "dps assist", nullptr); + engine->addStrategies("caster", "cure", "caster aoe", "dps assist", nullptr); engine->addStrategy("caster debuff"); } else if (tab == 2) engine->addStrategies("heal", "cure", "dps assist", nullptr); else { - engine->removeStrategy("flee"); - engine->addStrategies("bear", "tank assist", nullptr); + if (player->GetLevel() >= 20 && !player->HasAura(16931)/*thick hide*/) { + engine->addStrategies("cat", "dps assist", nullptr); + } else { + engine->addStrategies("bear", "tank assist", nullptr); + } } break; case CLASS_HUNTER: - engine->addStrategies("dps", "aoe", "bdps", "threat", "dps assist", nullptr); + engine->addStrategies("dps", "aoe", "bdps", "dps assist", nullptr); engine->addStrategy("dps debuff"); break; case CLASS_ROGUE: if (tab == ROGUE_TAB_ASSASSINATION) { - engine->addStrategies("melee", "threat", "dps assist", "aoe", /*"behind",*/ nullptr); + engine->addStrategies("melee", "dps assist", "aoe", /*"behind",*/ nullptr); } else { - engine->addStrategies("dps", "threat", "dps assist", "aoe", /*"behind",*/ nullptr); + engine->addStrategies("dps", "dps assist", "aoe", /*"behind",*/ nullptr); } break; case CLASS_WARLOCK: - engine->addStrategies("dps assist", "dps", "dps debuff", "aoe", "threat", nullptr); + engine->addStrategies("dps assist", "dps", "dps debuff", "aoe", nullptr); break; case CLASS_DEATH_KNIGHT: if (tab == 0) engine->addStrategies("blood", "tank assist", nullptr); else if (tab == 1) - engine->addStrategies("frost", "frost aoe", "dps assist", "threat", nullptr); + engine->addStrategies("frost", "frost aoe", "dps assist", nullptr); else - engine->addStrategies("unholy", "unholy aoe", "dps assist", "threat", nullptr); + engine->addStrategies("unholy", "unholy aoe", "dps assist", nullptr); break; } @@ -505,8 +508,13 @@ void AiFactory::AddDefaultNonCombatStrategies(Player* player, PlayerbotAI* const nonCombatEngine->addStrategies("dps assist", "cure", nullptr); break; case CLASS_DRUID: - if (tab == 1) - nonCombatEngine->addStrategy("tank assist"); + if (tab == 1) { + if (player->GetLevel() >= 20 && !player->HasAura(16931)/*thick hide*/) { + nonCombatEngine->addStrategy("dps assist"); + } else { + nonCombatEngine->addStrategy("tank assist"); + } + } else nonCombatEngine->addStrategies("dps assist", "cure", nullptr); break; diff --git a/src/strategy/actions/ChangeTalentsAction.cpp b/src/strategy/actions/ChangeTalentsAction.cpp index 69a6b19f..75de8e22 100644 --- a/src/strategy/actions/ChangeTalentsAction.cpp +++ b/src/strategy/actions/ChangeTalentsAction.cpp @@ -44,9 +44,11 @@ bool ChangeTalentsAction::Execute(Event event) } else if (param.find("spec ") != std::string::npos) { param = param.substr(5); out << SpecPick(param); + botAI->ResetStrategies(); } else if (param.find("apply ") != std::string::npos) { param = param.substr(6); out << SpecApply(param); + botAI->ResetStrategies(); } else { out << "Unknown command."; } diff --git a/src/strategy/druid/BearTankDruidStrategy.cpp b/src/strategy/druid/BearTankDruidStrategy.cpp index 2ddee32d..ab74c3f2 100644 --- a/src/strategy/druid/BearTankDruidStrategy.cpp +++ b/src/strategy/druid/BearTankDruidStrategy.cpp @@ -69,7 +69,7 @@ class BearTankDruidStrategyActionNodeFactory : public NamedObjectFactory Date: Tue, 9 Jul 2024 19:26:44 +0200 Subject: [PATCH 14/51] Conditions for Summon --- .../actions/UseMeetingStoneAction.cpp | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/src/strategy/actions/UseMeetingStoneAction.cpp b/src/strategy/actions/UseMeetingStoneAction.cpp index 0d4be53e..81093a80 100644 --- a/src/strategy/actions/UseMeetingStoneAction.cpp +++ b/src/strategy/actions/UseMeetingStoneAction.cpp @@ -176,8 +176,28 @@ bool SummonAction::Teleport(Player* summoner, Player* player) if (summoner->IsWithinLOS(x, y, z)) { - bool allowed = sPlayerbotAIConfig->botReviveWhenSummon == 2 || (sPlayerbotAIConfig->botReviveWhenSummon == 1 && !master->IsInCombat() && master->IsAlive()); - if (allowed && bot->isDead()) + if (sPlayerbotAIConfig->botReviveWhenSummon < 2) + { + if (master->IsInCombat()) + { + botAI->TellError("You cannot summon me while you're in combat"); + return false; + } + + if (!master->IsAlive()) + { + botAI->TellError("You cannot summon me while you're dead"); + return false; + } + + if (bot->isDead() && !bot->HasPlayerFlag(PLAYER_FLAGS_GHOST)) + { + botAI->TellError("You cannot summon me while I'm dead, you need to release my spirit first"); + return false; + } + } + + if (sPlayerbotAIConfig->botReviveWhenSummon > 0 && bot->isDead()) { bot->ResurrectPlayer(1.0f, false); bot->DurabilityRepairAll(false, 1.0f, false); From bb5ebb62d0e0e76ab3ccedbc14393545dbf5f3e4 Mon Sep 17 00:00:00 2001 From: Revision Date: Wed, 10 Jul 2024 01:54:52 +0200 Subject: [PATCH 15/51] Fix hardcoded database name --- src/PlayerbotAI.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PlayerbotAI.cpp b/src/PlayerbotAI.cpp index 42ea3b7d..a6903f18 100644 --- a/src/PlayerbotAI.cpp +++ b/src/PlayerbotAI.cpp @@ -1810,7 +1810,7 @@ Player* PlayerbotAI::GetPlayer(ObjectGuid guid) uint32 GetCreatureIdForCreatureTemplateId(uint32 creatureTemplateId) { - QueryResult results = WorldDatabase.Query("SELECT guid FROM `acore_world`.`creature` WHERE id1 = {} LIMIT 1;", creatureTemplateId); + QueryResult results = WorldDatabase.Query("SELECT guid FROM `creature` WHERE id1 = {} LIMIT 1;", creatureTemplateId); if (results) { Field* fields = results->Fetch(); return fields[0].Get(); From 500de1de10f4b3fd90b01e3231ba3da5dea6cb64 Mon Sep 17 00:00:00 2001 From: Fuzz Date: Wed, 10 Jul 2024 22:13:12 +1000 Subject: [PATCH 16/51] optionally disable bots using MotionMaster::MoveSplitPath() for BG/Arena or everywhere (so that stuns stun/snare/root/etc can work against bots) --- conf/playerbots.conf.dist | 7 +++++++ src/PlayerbotAIConfig.cpp | 1 + src/PlayerbotAIConfig.h | 4 ++-- src/strategy/actions/MovementActions.cpp | 4 +++- 4 files changed, 13 insertions(+), 3 deletions(-) diff --git a/conf/playerbots.conf.dist b/conf/playerbots.conf.dist index 3a3c2736..016e322a 100644 --- a/conf/playerbots.conf.dist +++ b/conf/playerbots.conf.dist @@ -248,6 +248,13 @@ AiPlayerbot.GlobalCooldown = 500 # Max wait time when moving AiPlayerbot.MaxWaitForMove = 5000 +# Disables use of MoveSplinePath for bot movement, will result in more erratic bot movement but means stun/snare/root/etc +# will work on bots (they wont reliably work when MoveSplinePath is enabled, though slowing effects still work ok) +# Default: 0 - MoveSplinePath enabled +# 1 - MoveSplinePath disabled in BG/Arena only +# 2 - MoveSplinePath disabled everywhere +AiPlayerbot.DisableMoveSplinePath = 0 + # Max search time for movement (higher for better movement on slopes) # default: 3 AiPlayerbot.MaxMovementSearchTime = 3 diff --git a/src/PlayerbotAIConfig.cpp b/src/PlayerbotAIConfig.cpp index ed840e9c..f0921224 100644 --- a/src/PlayerbotAIConfig.cpp +++ b/src/PlayerbotAIConfig.cpp @@ -53,6 +53,7 @@ bool PlayerbotAIConfig::Initialize() globalCoolDown = sConfigMgr->GetOption("AiPlayerbot.GlobalCooldown", 1500); maxWaitForMove = sConfigMgr->GetOption("AiPlayerbot.MaxWaitForMove", 5000); + disableMoveSplinePath = sConfigMgr->GetOption("AiPlayerbot.DisableMoveSplinePath", 0); maxMovementSearchTime = sConfigMgr->GetOption("AiPlayerbot.MaxMovementSearchTime", 3); expireActionTime = sConfigMgr->GetOption("AiPlayerbot.ExpireActionTime", 5000); dispelAuraDuration = sConfigMgr->GetOption("AiPlayerbot.DispelAuraDuration", 7000); diff --git a/src/PlayerbotAIConfig.h b/src/PlayerbotAIConfig.h index 40a66034..477f9c51 100644 --- a/src/PlayerbotAIConfig.h +++ b/src/PlayerbotAIConfig.h @@ -54,8 +54,8 @@ class PlayerbotAIConfig bool enabled; bool allowGuildBots, allowPlayerBots; - uint32 globalCoolDown, reactDelay, maxWaitForMove, maxMovementSearchTime, expireActionTime, - dispelAuraDuration, passiveDelay, repeatDelay, + uint32 globalCoolDown, reactDelay, maxWaitForMove, disableMoveSplinePath, maxMovementSearchTime, + expireActionTime, dispelAuraDuration, passiveDelay, repeatDelay, errorDelay, rpgDelay, sitDelay, returnDelay, lootDelay; float sightDistance, spellDistance, reactDistance, grindDistance, lootDistance, shootDistance, fleeDistance, tooCloseDistance, meleeDistance, followDistance, whisperDistance, contactDistance, diff --git a/src/strategy/actions/MovementActions.cpp b/src/strategy/actions/MovementActions.cpp index f86d539e..6a67e01b 100644 --- a/src/strategy/actions/MovementActions.cpp +++ b/src/strategy/actions/MovementActions.cpp @@ -163,7 +163,9 @@ bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle, // } bool generatePath = !bot->HasAuraType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED) && !bot->IsFlying() && !bot->HasUnitMovementFlag(MOVEMENTFLAG_SWIMMING) && !bot->IsInWater(); - if (!generatePath) { + bool disableMoveSplinePath = sPlayerbotAIConfig->disableMoveSplinePath >= 2 || + (sPlayerbotAIConfig->disableMoveSplinePath == 1 && bot->InBattleground()); + if (disableMoveSplinePath || !generatePath) { float distance = bot->GetExactDist(x, y, z); if (distance > sPlayerbotAIConfig->contactDistance) { From 06379b1ad028f432c5585acf3987252fa7b900d1 Mon Sep 17 00:00:00 2001 From: Fuzz Date: Wed, 10 Jul 2024 22:25:59 +1000 Subject: [PATCH 17/51] improved path selection for non-WSG BG's (improvements to pathing in AB and AV especially) --- src/strategy/actions/BattleGroundTactics.cpp | 125 ++++++++----------- 1 file changed, 55 insertions(+), 70 deletions(-) diff --git a/src/strategy/actions/BattleGroundTactics.cpp b/src/strategy/actions/BattleGroundTactics.cpp index 226cce6f..919c5f71 100644 --- a/src/strategy/actions/BattleGroundTactics.cpp +++ b/src/strategy/actions/BattleGroundTactics.cpp @@ -4162,99 +4162,84 @@ bool BGTactics::selectObjectiveWp(std::vector const& vPaths) if (bgType == BATTLEGROUND_WS /* && (bot->HasAura(BG_WS_SPELL_WARSONG_FLAG) || bot->HasAura(BG_WS_SPELL_SILVERWING_FLAG))*/) return wsgPaths(); - BattleBotPath* pClosestPath = nullptr; - uint32 closestPoint = 0; - float closestDistanceToTarget = FLT_MAX; - bool reverse = false; - float maxDistanceToPoint = 50.0f; - if (bgType == BATTLEGROUND_IC) - maxDistanceToPoint = 80.0f; + float chosenPathScore = FLT_MAX;//lower score is better + BattleBotPath* chosenPath = nullptr; + uint32 chosenPathPoint = 0; + bool chosenPathReverse = false; - for (auto const& pPath : vPaths) + float botDistanceLimit = 50.0f; // limit for how far path can be from bot + float botDistanceScoreSubtract = 8.0f; // path score modifier - lower = less likely to chose a further path (it's basically the distance from bot that's ignored) + float botDistanceScoreMultiply = 3.0f; // path score modifier - higher = less likely to chose a further path (it's basically a multiplier on distance from bot - makes distance from bot more signifcant than distance from destination) + + if (bgType == BATTLEGROUND_IC) + botDistanceLimit = 80.0f; + else if (bgType == BATTLEGROUND_AB) + { + botDistanceScoreSubtract = 2.0f; + botDistanceScoreMultiply = 4.0f; + } + + for (auto const& path : vPaths) { // skip mine paths of own faction - if (bot->GetTeamId() == TEAM_ALLIANCE && std::find(vPaths_AllyMine.begin(), vPaths_AllyMine.end(), pPath) != vPaths_AllyMine.end()) + if (bot->GetTeamId() == TEAM_ALLIANCE && std::find(vPaths_AllyMine.begin(), vPaths_AllyMine.end(), path) != vPaths_AllyMine.end()) continue; - if (bot->GetTeamId() == TEAM_HORDE && std::find(vPaths_HordeMine.begin(), vPaths_HordeMine.end(), pPath) != vPaths_HordeMine.end()) + if (bot->GetTeamId() == TEAM_HORDE && std::find(vPaths_HordeMine.begin(), vPaths_HordeMine.end(), path) != vPaths_HordeMine.end()) continue; - BattleBotWaypoint& lastPoint = ((*pPath)[pPath->size() - 1]); - float const distanceFromPathEndToTarget = sqrt(Position(pos.x, pos.y, pos.z, 0.f).GetExactDist(lastPoint.x, lastPoint.y, lastPoint.z)); - if (closestDistanceToTarget > distanceFromPathEndToTarget) + BattleBotWaypoint& startPoint = ((*path)[0]); + float const startPointDistToDestination = sqrt(Position(pos.x, pos.y, pos.z, 0.f).GetExactDist(startPoint.x, startPoint.y, startPoint.z)); + BattleBotWaypoint& endPoint = ((*path)[path->size() - 1]); + float const endPointDistToDestination = sqrt(Position(pos.x, pos.y, pos.z, 0.f).GetExactDist(endPoint.x, endPoint.y, endPoint.z)); + + bool reverse = startPointDistToDestination < endPointDistToDestination; + + // dont travel reverse if it's a reverse paths + if (reverse && std::find(vPaths_NoReverseAllowed.begin(), vPaths_NoReverseAllowed.end(), path) != vPaths_NoReverseAllowed.end()) + continue; + + int closestPointIndex = -1; + float closestPointDistToBot = FLT_MAX; + for (uint32 i = 0; i < path->size(); i++) { - float closestDistanceFromMeToPoint = FLT_MAX; - - for (uint32 i = 0; i < pPath->size(); i++) + BattleBotWaypoint& waypoint = ((*path)[i]); + float const distToBot = sqrt(bot->GetDistance(waypoint.x, waypoint.y, waypoint.z)); + if (closestPointDistToBot > distToBot) { - BattleBotWaypoint& waypoint = ((*pPath)[i]); - float const distanceFromMeToPoint = sqrt(bot->GetDistance(waypoint.x, waypoint.y, waypoint.z)); - if (distanceFromMeToPoint < maxDistanceToPoint && closestDistanceFromMeToPoint > distanceFromMeToPoint) - { - reverse = false; - pClosestPath = pPath; - closestPoint = i; - closestDistanceToTarget = distanceFromPathEndToTarget; - closestDistanceFromMeToPoint = distanceFromMeToPoint; - } + closestPointDistToBot = distToBot; + closestPointIndex = i; } } - // skip no reverse paths - if (std::find(vPaths_NoReverseAllowed.begin(), vPaths_NoReverseAllowed.end(), pPath) != vPaths_NoReverseAllowed.end()) + // don't pick path where bot is already closest to the paths closest point to target (it means path cant lead it anywhere) + // don't pick path where closest point is too far away + if (closestPointIndex == (reverse ? 0 : path->size() - 1) || closestPointDistToBot > botDistanceLimit) continue; - // skip mine paths of own faction - if (bot->GetTeamId() == TEAM_ALLIANCE && std::find(vPaths_AllyMine.begin(), vPaths_AllyMine.end(), pPath) != vPaths_AllyMine.end()) - continue; - if (bot->GetTeamId() == TEAM_HORDE && std::find(vPaths_HordeMine.begin(), vPaths_HordeMine.end(), pPath) != vPaths_HordeMine.end()) - continue; + // creates a score based on dist-to-bot and dist-to-destination, where lower is better, and dist-to-bot is more important (when its beyond a certain distance) + // dist-to-bot is more important because otherwise they cant reach it at all (or will fly through air with MM::MovePoint()), also bot may need to use multiple + // paths (one after another) anyway + float distToDestination = reverse ? startPointDistToDestination : endPointDistToDestination; + float pathScore = (closestPointDistToBot < botDistanceScoreSubtract ? 0.0f : ((closestPointDistToBot - botDistanceScoreSubtract) * botDistanceScoreMultiply)) + distToDestination; - { - BattleBotWaypoint& firstPoint = ((*pPath)[0]); - float const distanceFromPathBeginToTarget = sqrt(Position(pos.x, pos.y, pos.z, 0).GetExactDist(firstPoint.x, firstPoint.y, firstPoint.z)); - if (closestDistanceToTarget > distanceFromPathBeginToTarget) - { - float closestDistanceFromMeToPoint = FLT_MAX; + //LOG_INFO("playerbots", "bot={}\t{:6.1f}\t{:4.1f}\t{:4.1f}\t{}", bot->GetName(), pathScore, closestPointDistToBot, distToDestination, vPaths_AB_name[pathNum]); - for (uint32 i = 0; i < pPath->size(); i++) - { - BattleBotWaypoint& waypoint = ((*pPath)[i]); - float const distanceFromMeToPoint = sqrt(bot->GetDistance(waypoint.x, waypoint.y, waypoint.z)); - if (distanceFromMeToPoint < maxDistanceToPoint && closestDistanceFromMeToPoint > distanceFromMeToPoint) - { - reverse = true; - pClosestPath = pPath; - closestPoint = i; - closestDistanceToTarget = distanceFromPathBeginToTarget; - closestDistanceFromMeToPoint = distanceFromMeToPoint; - } - } - } + if (chosenPathScore > pathScore) { + chosenPathScore = pathScore; + chosenPath = path; + chosenPathPoint = closestPointIndex; + chosenPathReverse = reverse; } } - if (!pClosestPath) + if (!chosenPath) return false; - // Prevent picking last point of path. - // It means we are already there. - if (reverse) - { - if (closestPoint == 0) - return false; - } - else - { - if (closestPoint == pClosestPath->size() - 1) - return false; - } + //LOG_INFO("playerbots", "bot={} {}", bot->GetName(), vPaths_AB_name[chosenPathNum]); - BattleBotPath* currentPath = pClosestPath; - uint32 currentPoint = reverse ? closestPoint + 1 : closestPoint - 1; - - return moveToObjectiveWp(currentPath, currentPoint, reverse); + return moveToObjectiveWp(chosenPath, chosenPathPoint, chosenPathReverse); return false; } From 3316490f5dc6db63ac9a08186dab8bad02e5db05 Mon Sep 17 00:00:00 2001 From: Fuzz Date: Wed, 10 Jul 2024 22:36:22 +1000 Subject: [PATCH 18/51] many many fixes for AV - fixed main path from horde cave starting too far away (flying bots, or bots going nowhere), fixed wrong objects targetted for objective-nodes (bots hanging around already captured points), wrong creatures targetted for boss and captain (bot running toward and away from captain, bot capturing every point then running home), wrong flag state checked for certain points (bot waiting forever in burning tower), fixed bots not moving close enough to flags in towers (bots sitting in towers forever), and more --- src/strategy/actions/BattleGroundTactics.cpp | 168 +++++++++++-------- 1 file changed, 98 insertions(+), 70 deletions(-) diff --git a/src/strategy/actions/BattleGroundTactics.cpp b/src/strategy/actions/BattleGroundTactics.cpp index 919c5f71..80eff17b 100644 --- a/src/strategy/actions/BattleGroundTactics.cpp +++ b/src/strategy/actions/BattleGroundTactics.cpp @@ -40,12 +40,16 @@ Position const WS_FLAG_HIDE_ALLIANCE_2 = { 1540.286f, 1476.026f, 352.692f, 2.91f Position const WS_FLAG_HIDE_ALLIANCE_3 = { 1495.807f, 1466.774f, 352.350f, 1.50f }; std::vector const WS_FLAG_HIDE_HORDE = { WS_FLAG_HIDE_HORDE_1 , WS_FLAG_HIDE_HORDE_2, WS_FLAG_HIDE_HORDE_3 }; std::vector const WS_FLAG_HIDE_ALLIANCE = { WS_FLAG_HIDE_ALLIANCE_1 , WS_FLAG_HIDE_ALLIANCE_2, WS_FLAG_HIDE_ALLIANCE_3 }; + Position const AB_WAITING_POS_HORDE = { 702.884f, 703.045f, -16.115f, 0.77f }; Position const AB_WAITING_POS_ALLIANCE = { 1286.054f, 1282.500f, -15.697f, 3.95f }; + Position const AV_WAITING_POS_ALLIANCE = { 793.627f, -493.814f, 99.689f, 3.09f }; Position const AV_WAITING_POS_HORDE = { -1381.865f, -544.872f, 54.773f, 0.76f }; -Position const AV_ICEBLOOD_GARRISON_WAITING_ALLIANCE = { -492.17f, -187.077f, 57.1342f, 2.77f }; -Position const AV_STONEHEARTH_WAITING_HORDE = { 28.1264f, -302.593f, 15.076f, 2.96f }; +Position const AV_ICEBLOOD_GARRISON_WAITING_ALLIANCE = { -523.105f, -182.178f, 57.956f, 2.77f }; +Position const AV_ICEBLOOD_GARRISON_ATTACKING_ALLIANCE = { -545.288f, -167.932f, 57.012f, 2.77f }; +Position const AV_STONEHEARTH_WAITING_HORDE = { -36.399f, -306.403f, 15.565f, 2.96f }; +Position const AV_STONEHEARTH_ATTACKING_HORDE = { -55.210f, -288.546f, 15.578f, 2.96f }; Position const EY_WAITING_POS_HORDE = { 1809.102f, 1540.854f, 1267.142f, 6.18f }; Position const EY_WAITING_POS_ALLIANCE = { 2526.020f, 1596.787f, 1270.127f, 3.14f }; @@ -799,7 +803,16 @@ BattleBotPath vPath_AB_Farm_to_LumberMill = BattleBotPath vPath_AV_Horde_Cave_to_Tower_Point_Crossroad = { - { -885.928f, -536.612f, 55.1936f, nullptr }, + { -1362.395f, -529.615f, 52.636f, nullptr }, + { -1327.036f, -511.374f, 51.138f, nullptr }, + { -1277.047f, -516.327f, 50.667f, nullptr }, + { -1214.901f, -529.350f, 52.251f, nullptr }, + { -1151.129f, -545.598f, 51.990f, nullptr }, + { -1085.775f, -538.719f, 47.905f, nullptr }, + { -1038.552f, -517.946f, 43.876f, nullptr }, + { -981.371f, -494.593f, 41.127f, nullptr }, + { -930.598f, -463.751f, 43.060f, nullptr }, + { -887.138f, -475.816f, 44.374f, nullptr }, { -880.957f, -525.119f, 53.6791f, nullptr }, { -839.408f, -499.746f, 49.7505f, nullptr }, { -820.21f, -469.193f, 49.4085f, nullptr }, @@ -2262,48 +2275,48 @@ std::vector const vPaths_HordeMine = &vPath_AV_Coldtooth_Mine_Entrance_to_Coldtooth_Mine_Boss, }; -static uint32 AV_HordeAttackObjectives[] = +static std::pair AV_HordeAttackObjectives[] = { // Attack - { BG_AV_NODES_STONEHEART_BUNKER }, - { BG_AV_NODES_STONEHEART_GRAVE }, - { BG_AV_NODES_ICEWING_BUNKER }, - { BG_AV_NODES_STORMPIKE_GRAVE }, - { BG_AV_NODES_DUNBALDAR_SOUTH }, - { BG_AV_NODES_DUNBALDAR_NORTH }, - { BG_AV_NODES_FIRSTAID_STATION } + { BG_AV_NODES_STONEHEART_BUNKER, BG_AV_OBJECT_FLAG_A_STONEHEART_BUNKER }, + { BG_AV_NODES_STONEHEART_GRAVE, BG_AV_OBJECT_FLAG_A_STONEHEART_GRAVE }, + { BG_AV_NODES_ICEWING_BUNKER, BG_AV_OBJECT_FLAG_A_ICEWING_BUNKER }, + { BG_AV_NODES_STORMPIKE_GRAVE, BG_AV_OBJECT_FLAG_A_STORMPIKE_GRAVE }, + { BG_AV_NODES_DUNBALDAR_SOUTH, BG_AV_OBJECT_FLAG_A_DUNBALDAR_SOUTH }, + { BG_AV_NODES_DUNBALDAR_NORTH, BG_AV_OBJECT_FLAG_A_DUNBALDAR_NORTH }, + { BG_AV_NODES_FIRSTAID_STATION, BG_AV_OBJECT_FLAG_A_FIRSTAID_STATION } }; -static uint32 AV_HordeDefendObjectives[] = +static std::pair AV_HordeDefendObjectives[] = { // Defend - { BG_AV_NODES_FROSTWOLF_GRAVE }, - { BG_AV_NODES_FROSTWOLF_ETOWER }, - { BG_AV_NODES_FROSTWOLF_WTOWER }, - { BG_AV_NODES_TOWER_POINT }, - { BG_AV_NODES_ICEBLOOD_TOWER }, + { BG_AV_NODES_FROSTWOLF_GRAVE, BG_AV_OBJECT_FLAG_H_FROSTWOLF_GRAVE }, + { BG_AV_NODES_FROSTWOLF_ETOWER, BG_AV_OBJECT_FLAG_H_FROSTWOLF_ETOWER }, + { BG_AV_NODES_FROSTWOLF_WTOWER, BG_AV_OBJECT_FLAG_H_FROSTWOLF_WTOWER }, + { BG_AV_NODES_TOWER_POINT, BG_AV_OBJECT_FLAG_H_TOWER_POINT }, + { BG_AV_NODES_ICEBLOOD_TOWER, BG_AV_OBJECT_FLAG_H_ICEBLOOD_TOWER }, }; -static uint32 AV_AllianceAttackObjectives[] = +static std::pair AV_AllianceAttackObjectives[] = { // Attack - { BG_AV_NODES_ICEBLOOD_TOWER }, - { BG_AV_NODES_ICEBLOOD_GRAVE }, - { BG_AV_NODES_TOWER_POINT }, - { BG_AV_NODES_FROSTWOLF_GRAVE }, - { BG_AV_NODES_FROSTWOLF_ETOWER }, - { BG_AV_NODES_FROSTWOLF_WTOWER }, - { BG_AV_NODES_FROSTWOLF_HUT }, + { BG_AV_NODES_ICEBLOOD_TOWER, BG_AV_OBJECT_FLAG_H_ICEBLOOD_TOWER}, + { BG_AV_NODES_ICEBLOOD_GRAVE, BG_AV_OBJECT_FLAG_H_ICEBLOOD_GRAVE}, + { BG_AV_NODES_TOWER_POINT, BG_AV_OBJECT_FLAG_H_TOWER_POINT }, + { BG_AV_NODES_FROSTWOLF_GRAVE, BG_AV_OBJECT_FLAG_H_FROSTWOLF_GRAVE }, + { BG_AV_NODES_FROSTWOLF_ETOWER, BG_AV_OBJECT_FLAG_H_FROSTWOLF_ETOWER }, + { BG_AV_NODES_FROSTWOLF_WTOWER, BG_AV_OBJECT_FLAG_H_FROSTWOLF_WTOWER }, + { BG_AV_NODES_FROSTWOLF_HUT, BG_AV_OBJECT_FLAG_H_FROSTWOLF_HUT }, }; -static uint32 AV_AllianceDefendObjectives[] = +static std::pair AV_AllianceDefendObjectives[] = { // Defend - { BG_AV_NODES_STORMPIKE_GRAVE }, - { BG_AV_NODES_DUNBALDAR_SOUTH }, - { BG_AV_NODES_DUNBALDAR_NORTH }, - { BG_AV_NODES_ICEWING_BUNKER }, - { BG_AV_NODES_STONEHEART_BUNKER }, + { BG_AV_NODES_STORMPIKE_GRAVE, BG_AV_OBJECT_FLAG_A_STORMPIKE_GRAVE }, + { BG_AV_NODES_DUNBALDAR_SOUTH, BG_AV_OBJECT_FLAG_A_DUNBALDAR_SOUTH }, + { BG_AV_NODES_DUNBALDAR_NORTH, BG_AV_OBJECT_FLAG_A_DUNBALDAR_NORTH }, + { BG_AV_NODES_ICEWING_BUNKER, BG_AV_OBJECT_FLAG_A_ICEWING_BUNKER }, + { BG_AV_NODES_STONEHEART_BUNKER, BG_AV_OBJECT_FLAG_A_STONEHEART_BUNKER }, }; static uint32 AB_AttackObjectives[] = @@ -2937,7 +2950,7 @@ bool BGTactics::selectObjective(bool reset) alterValleyBG->GetAVNodeInfo(BG_AV_NODES_STONEHEART_BUNKER).TotalOwnerId != TEAM_ALLIANCE && alterValleyBG->GetAVNodeInfo(BG_AV_NODES_FIRSTAID_STATION).TotalOwnerId != TEAM_ALLIANCE) { - if (Creature* pVanndar = bg->GetBGCreature(AV_NPC_A_BOSS)) + if (Creature* pVanndar = bg->GetBGCreature(AV_CPLACE_TRIGGER17)) { BgObjective = pVanndar; endBoss = true; @@ -2952,8 +2965,9 @@ bool BGTactics::selectObjective(bool reset) // Only go to Snowfall Graveyard if already close to it. // Need to fix AV script - if (!BgObjective && supporter && (alterValleyBG->GetAVNodeInfo(BG_AV_NODES_SNOWFALL_GRAVE).OwnerId == TEAM_ALLIANCE || - alterValleyBG->GetAVNodeInfo(BG_AV_NODES_SNOWFALL_GRAVE).OwnerId == TEAM_HORDE || alterValleyBG->GetAVNodeInfo(BG_AV_NODES_SNOWFALL_GRAVE).OwnerId == TEAM_OTHER)) + if (!BgObjective && supporter && + (alterValleyBG->GetAVNodeInfo(BG_AV_NODES_SNOWFALL_GRAVE).OwnerId == TEAM_ALLIANCE || + alterValleyBG->GetAVNodeInfo(BG_AV_NODES_SNOWFALL_GRAVE).OwnerId == TEAM_OTHER)) { if (GameObject* pGO = bg->GetBGObject(BG_AV_NODES_SNOWFALL_GRAVE)) if (bot->IsWithinDist(pGO, 200.f)) @@ -2967,19 +2981,20 @@ bool BGTactics::selectObjective(bool reset) if (!BgObjective && alterValleyBG->IsCaptainAlive(0)) { - if (Creature* pBalinda = bg->GetBGCreature(AV_NPC_A_CAPTAIN)) + if (Creature* pBalinda = bg->GetBGCreature(AV_CPLACE_TRIGGER16)) { if (pBalinda->getDeathState() != DeathState::Dead) { - uint32 attackCount = 0; - attackCount += getDefendersCount(AV_STONEHEARTH_WAITING_HORDE, 10.0f, false); + uint32 attackCount = getDefendersCount(AV_STONEHEARTH_WAITING_HORDE, 10.0f, false) + getDefendersCount(AV_STONEHEARTH_ATTACKING_HORDE, 10.0f, false); // prepare to attack Captain if (attackCount < 10 && !pBalinda->IsInCombat()) { // get in position to attack Captain - pos.Set(AV_STONEHEARTH_WAITING_HORDE.GetPositionX(), AV_STONEHEARTH_WAITING_HORDE.GetPositionY(), - AV_STONEHEARTH_WAITING_HORDE.GetPositionZ(), bg->GetMapId()); + pos.Set(AV_STONEHEARTH_WAITING_HORDE.GetPositionX(), + AV_STONEHEARTH_WAITING_HORDE.GetPositionY(), + AV_STONEHEARTH_WAITING_HORDE.GetPositionZ(), + bg->GetMapId()); std::ostringstream out; out << "Taking position at Stonehearth!"; @@ -2987,6 +3002,12 @@ bool BGTactics::selectObjective(bool reset) } else { + // they need help getting there (or did before I fixed the target creature, will leave in anyway, as it probably makes it more robust) + pos.Set(AV_STONEHEARTH_ATTACKING_HORDE.GetPositionX(), + AV_STONEHEARTH_ATTACKING_HORDE.GetPositionY(), + AV_STONEHEARTH_ATTACKING_HORDE.GetPositionZ(), + bg->GetMapId()); + std::ostringstream out; out << "Attacking Balinda!"; //bot->Say(out.str(), LANG_UNIVERSAL); @@ -3007,9 +3028,9 @@ bool BGTactics::selectObjective(bool reset) { for (const auto& objective : AV_HordeDefendObjectives) { - if (!BgObjective && alterValleyBG->GetAVNodeInfo(objective).OwnerId == TEAM_ALLIANCE) + if (!BgObjective && alterValleyBG->GetAVNodeInfo(objective.first).OwnerId == TEAM_ALLIANCE) { - if (GameObject* pGO = bg->GetBGObject(objective)) + if (GameObject* pGO = bg->GetBGObject(objective.second)) if (bot->IsWithinDist(pGO, 400.0f)) { BgObjective = pGO; @@ -3022,7 +3043,8 @@ bool BGTactics::selectObjective(bool reset) } // Mine capture (need paths & script fix) - if (!BgObjective && supporter && !endBoss && (alterValleyBG->GetMineOwner(AV_NORTH_MINE) == TEAM_ALLIANCE || alterValleyBG->GetMineOwner(AV_NORTH_MINE) == TEAM_OTHER) && + if (!BgObjective && supporter && !endBoss && + (alterValleyBG->GetMineOwner(AV_NORTH_MINE) == TEAM_ALLIANCE || alterValleyBG->GetMineOwner(AV_NORTH_MINE) == TEAM_OTHER) && alterValleyBG->GetAVNodeInfo(BG_AV_NODES_STORMPIKE_GRAVE).OwnerId != TEAM_ALLIANCE) { if (Creature* mBossNeutral = bg->GetBGCreature(AV_CPLACE_MINE_N_3)) @@ -3055,10 +3077,9 @@ bool BGTactics::selectObjective(bool reset) for (const auto& objective : AV_HordeAttackObjectives) { if ((!BgObjective/* || (supporter && objective.first == BG_AV_NODES_STONEHEART_BUNKER && !bg->IsActiveEvent(BG_AV_NODE_CAPTAIN_DEAD_A, 0))*/) && - (alterValleyBG->GetAVNodeInfo(objective).OwnerId == TEAM_ALLIANCE || alterValleyBG->GetAVNodeInfo(objective).TotalOwnerId == TEAM_ALLIANCE || - alterValleyBG->GetAVNodeInfo(objective).OwnerId == TEAM_OTHER)) + alterValleyBG->GetAVNodeInfo(objective.first).TotalOwnerId == TEAM_ALLIANCE)//need to check TotalOwnerId for attack objectives { - if (GameObject* pGO = bg->GetBGObject(objective)) + if (GameObject* pGO = bg->GetBGObject(objective.second)) { BgObjective = pGO; //std::ostringstream out; @@ -3073,11 +3094,13 @@ bool BGTactics::selectObjective(bool reset) { bool endBoss = false; // End boss - if (alterValleyBG->GetAVNodeInfo(BG_AV_NODES_ICEBLOOD_TOWER).OwnerId != TEAM_HORDE && alterValleyBG->GetAVNodeInfo(BG_AV_NODES_TOWER_POINT).OwnerId != TEAM_HORDE && - alterValleyBG->GetAVNodeInfo(BG_AV_NODES_FROSTWOLF_ETOWER).OwnerId != TEAM_HORDE && alterValleyBG->GetAVNodeInfo(BG_AV_NODES_FROSTWOLF_WTOWER).OwnerId != TEAM_HORDE && - alterValleyBG->GetAVNodeInfo(BG_AV_NODES_FROSTWOLF_HUT).OwnerId != TEAM_HORDE) + if (alterValleyBG->GetAVNodeInfo(BG_AV_NODES_ICEBLOOD_TOWER).TotalOwnerId != TEAM_HORDE && + alterValleyBG->GetAVNodeInfo(BG_AV_NODES_TOWER_POINT).TotalOwnerId != TEAM_HORDE && + alterValleyBG->GetAVNodeInfo(BG_AV_NODES_FROSTWOLF_ETOWER).TotalOwnerId != TEAM_HORDE && + alterValleyBG->GetAVNodeInfo(BG_AV_NODES_FROSTWOLF_WTOWER).TotalOwnerId != TEAM_HORDE && + alterValleyBG->GetAVNodeInfo(BG_AV_NODES_FROSTWOLF_HUT).TotalOwnerId != TEAM_HORDE) { - if (Creature* pDrek = bg->GetBGCreature(AV_NPC_H_BOSS)) + if (Creature* pDrek = bg->GetBGCreature(AV_CPLACE_TRIGGER19)) { BgObjective = pDrek; endBoss = true; @@ -3091,9 +3114,9 @@ bool BGTactics::selectObjective(bool reset) bool supporter = role < 3; // Only go to Snowfall Graveyard if already close to it. - if (!BgObjective && supporter && (alterValleyBG->GetAVNodeInfo(BG_AV_NODES_SNOWFALL_GRAVE).OwnerId == TEAM_HORDE || - alterValleyBG->GetAVNodeInfo(BG_AV_NODES_SNOWFALL_GRAVE).TotalOwnerId == TEAM_HORDE || - alterValleyBG->GetAVNodeInfo(BG_AV_NODES_SNOWFALL_GRAVE).TotalOwnerId == TEAM_OTHER)) + if (!BgObjective && supporter && + (alterValleyBG->GetAVNodeInfo(BG_AV_NODES_SNOWFALL_GRAVE).OwnerId == TEAM_HORDE || + alterValleyBG->GetAVNodeInfo(BG_AV_NODES_SNOWFALL_GRAVE).OwnerId == TEAM_OTHER)) { if (GameObject* pGO = bg->GetBGObject(BG_AV_NODES_SNOWFALL_GRAVE)) if (bot->IsWithinDist(pGO, 200.f)) @@ -3110,9 +3133,9 @@ bool BGTactics::selectObjective(bool reset) { for (const auto& objective : AV_AllianceDefendObjectives) { - if (!BgObjective && alterValleyBG->GetAVNodeInfo(objective).OwnerId == TEAM_HORDE) + if (!BgObjective && alterValleyBG->GetAVNodeInfo(objective.first).OwnerId == TEAM_HORDE) { - if (GameObject* pGO = bg->GetBGObject(objective)) + if (GameObject* pGO = bg->GetBGObject(objective.second)) { BgObjective = pGO; //std::ostringstream out; out << "Defending Node #" << objective.first; @@ -3123,8 +3146,8 @@ bool BGTactics::selectObjective(bool reset) } // Mine capture (need paths & script fix) - if (!BgObjective && supporter && !endBoss && (alterValleyBG->GetMineOwner(AV_SOUTH_MINE) == TEAM_HORDE || - alterValleyBG->GetMineOwner(AV_SOUTH_MINE) == TEAM_OTHER) && + if (!BgObjective && supporter && !endBoss && + (alterValleyBG->GetMineOwner(AV_SOUTH_MINE) == TEAM_HORDE || alterValleyBG->GetMineOwner(AV_SOUTH_MINE) == TEAM_OTHER) && alterValleyBG->GetAVNodeInfo(BG_AV_NODES_FROSTWOLF_GRAVE).TotalOwnerId != TEAM_HORDE) { if (Creature* mBossNeutral = bg->GetBGCreature(AV_CPLACE_MINE_S_3)) @@ -3158,17 +3181,18 @@ bool BGTactics::selectObjective(bool reset) if (alterValleyBG->IsCaptainAlive(1)) { - if (Creature* pGalvangar = bg->GetBGCreature(AV_NPC_H_CAPTAIN)) + if (Creature* pGalvangar = bg->GetBGCreature(AV_CPLACE_TRIGGER18)) { - uint32 attackCount = 0; - attackCount += getDefendersCount(AV_ICEBLOOD_GARRISON_WAITING_ALLIANCE, 10.0f, false); + uint32 attackCount = getDefendersCount(AV_ICEBLOOD_GARRISON_WAITING_ALLIANCE, 10.0f, false) + getDefendersCount(AV_ICEBLOOD_GARRISON_ATTACKING_ALLIANCE, 10.0f, false); // prepare to attack Captain if (attackCount < 10 && !pGalvangar->IsInCombat()) { // get in position to attack Captain - pos.Set(AV_ICEBLOOD_GARRISON_WAITING_ALLIANCE.GetPositionX(), AV_ICEBLOOD_GARRISON_WAITING_ALLIANCE.GetPositionY(), - AV_ICEBLOOD_GARRISON_WAITING_ALLIANCE.GetPositionZ(), bg->GetMapId()); + pos.Set(AV_ICEBLOOD_GARRISON_WAITING_ALLIANCE.GetPositionX(), + AV_ICEBLOOD_GARRISON_WAITING_ALLIANCE.GetPositionY(), + AV_ICEBLOOD_GARRISON_WAITING_ALLIANCE.GetPositionZ(), + bg->GetMapId()); //std::ostringstream out; //out << "Taking position at Iceblood Outpost!"; @@ -3176,6 +3200,12 @@ bool BGTactics::selectObjective(bool reset) } else { + // they need help getting there (or did before I fixed the target creature, will leave in anyway, as it probably makes it more robust) + pos.Set(AV_ICEBLOOD_GARRISON_ATTACKING_ALLIANCE.GetPositionX(), + AV_ICEBLOOD_GARRISON_ATTACKING_ALLIANCE.GetPositionY(), + AV_ICEBLOOD_GARRISON_ATTACKING_ALLIANCE.GetPositionZ(), + bg->GetMapId()); + //std::ostringstream out; // out << "Attacking Galvangar!"; //bot->Say(out.str(), LANG_UNIVERSAL); @@ -3187,11 +3217,9 @@ bool BGTactics::selectObjective(bool reset) for (const auto& objective : AV_AllianceAttackObjectives) { - if (alterValleyBG->GetAVNodeInfo(objective).OwnerId == TEAM_HORDE || - alterValleyBG->GetAVNodeInfo(objective).TotalOwnerId == TEAM_HORDE || - alterValleyBG->GetAVNodeInfo(objective).TotalOwnerId == TEAM_OTHER) + if (alterValleyBG->GetAVNodeInfo(objective.first).TotalOwnerId == TEAM_HORDE)//need to check TotalOwnerId for attack objectives { - if (GameObject* pGO = bg->GetBGObject(objective)) + if (GameObject* pGO = bg->GetBGObject(objective.second)) { float const distance = sqrt(bot->GetDistance(pGO)); if (attackObjectiveDistance > distance) @@ -4124,7 +4152,7 @@ bool BGTactics::moveToObjective() } // don't try to move if already close - if (sqrt(bot->GetDistance(pos.x, pos.y, pos.z)) < 5.0f) + if (sqrt(bot->GetDistance(pos.x, pos.y, pos.z)) < 2.0f) { resetObjective(); @@ -4134,8 +4162,8 @@ bool BGTactics::moveToObjective() //std::ostringstream out; out << "Moving to objective " << pos.x << ", " << pos.y << ", Distance: " << sServerFacade->GetDistance2d(bot, pos.x, pos.y); //bot->Say(out.str(), LANG_UNIVERSAL); - // more precise position for wsg - if (bgType == BATTLEGROUND_WS) + // more precise position for wsg and AV (flags in AV towers require precision) + if (bgType == BATTLEGROUND_WS || bgType == BATTLEGROUND_AV) return MoveTo(bot->GetMapId(), pos.x, pos.y, pos.z); else return MoveNear(bot->GetMapId(), pos.x, pos.y, pos.z, 3.0f); @@ -4946,9 +4974,9 @@ bool ArenaTactics::moveToCenter(Battleground* bg) case BATTLEGROUND_DS: if (!MoveTo(bg->GetMapId(), 1291.58f + frand(-5, +5), 790.87f + frand(-5, +5), 7.8f, false, true)) { // they like to hang around at the tip of the pipes doing nothing, so we just teleport them down - if (bot->GetDistance(1333.07f, 817.18f, 13.35f) < 2) + if (bot->GetDistance(1333.07f, 817.18f, 13.35f) < 4) bot->TeleportTo(bg->GetMapId(), 1330.96f, 816.75f, 3.2f, bot->GetOrientation()); - if (bot->GetDistance(1250.13f, 764.79f, 13.34f) < 2) + if (bot->GetDistance(1250.13f, 764.79f, 13.34f) < 4) bot->TeleportTo(bg->GetMapId(), 1252.19f, 765.41f, 3.2f, bot->GetOrientation()); } break; From 9accee0a64604909885cca01c5578d3c0e1c3740 Mon Sep 17 00:00:00 2001 From: Revision Date: Wed, 10 Jul 2024 19:20:43 +0200 Subject: [PATCH 19/51] Fix Draenei being created with expansion set to 0 --- src/RandomPlayerbotFactory.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/RandomPlayerbotFactory.cpp b/src/RandomPlayerbotFactory.cpp index 20ef853b..6721c8e4 100644 --- a/src/RandomPlayerbotFactory.cpp +++ b/src/RandomPlayerbotFactory.cpp @@ -55,9 +55,9 @@ RandomPlayerbotFactory::RandomPlayerbotFactory(uint32 accountId) : accountId(acc availableRaces[CLASS_PRIEST].push_back(RACE_NIGHTELF); availableRaces[CLASS_PRIEST].push_back(RACE_TROLL); availableRaces[CLASS_PRIEST].push_back(RACE_UNDEAD_PLAYER); - availableRaces[CLASS_PRIEST].push_back(RACE_DRAENEI); if(expansion >= EXPANSION_THE_BURNING_CRUSADE) { + availableRaces[CLASS_PRIEST].push_back(RACE_DRAENEI); availableRaces[CLASS_PRIEST].push_back(RACE_BLOODELF); } From 36c84d55f273bf60d5959ffb7a98563db96d6aef Mon Sep 17 00:00:00 2001 From: Chromie-WoW Date: Wed, 10 Jul 2024 15:13:22 -0700 Subject: [PATCH 20/51] Add option --- conf/playerbots.conf.dist | 6 +++++- src/PlayerbotAIConfig.cpp | 1 + src/PlayerbotAIConfig.h | 1 + src/strategy/actions/UseMeetingStoneAction.cpp | 4 +++- 4 files changed, 10 insertions(+), 2 deletions(-) diff --git a/conf/playerbots.conf.dist b/conf/playerbots.conf.dist index 3a3c2736..1aa0d97b 100644 --- a/conf/playerbots.conf.dist +++ b/conf/playerbots.conf.dist @@ -127,10 +127,14 @@ AiPlayerbot.EquipmentPersistenceLevel = 80 # default: 1 (accept based on level) AiPlayerbot.GroupInvitationPermission = 1 -# Enable/Disable bot revive and repair gear when summon (0 = never, 1 = enable when non-combat and alive, 2 = enable always) +# Enable/Disable bot revive when summon (0 = never, 1 = enable when non-combat and alive, 2 = enable always) # default: 1 (enable for non-combat) AiPlayerbot.BotReviveWhenSummon = 1 +# Enable/Disable bot repair gear when summon (0 = no, 1 = yes) +# default: 1 (enable for non-combat) +AiPlayerbot.BotRepairWhenSummon = 1 + # Non-GM player can only use init=auto to initialize bots based on their own level and gear score # default: 0 (non-gm player can use any intialization commands) AiPlayerbot.AutoInitOnly = 0 diff --git a/src/PlayerbotAIConfig.cpp b/src/PlayerbotAIConfig.cpp index ed840e9c..02d20e17 100644 --- a/src/PlayerbotAIConfig.cpp +++ b/src/PlayerbotAIConfig.cpp @@ -273,6 +273,7 @@ bool PlayerbotAIConfig::Initialize() equipmentPersistenceLevel = sConfigMgr->GetOption("AiPlayerbot.EquipmentPersistenceLevel", 80); groupInvitationPermission = sConfigMgr->GetOption("AiPlayerbot.GroupInvitationPermission", 1); botReviveWhenSummon = sConfigMgr->GetOption("AiPlayerbot.BotReviveWhenSummon", 1); + botRepairWhenSummon = sConfigMgr->GetOption("AiPlayerbot.BotRepairWhenSummon", false); autoInitOnly = sConfigMgr->GetOption("AiPlayerbot.AutoInitOnly", false); autoInitEquipLevelLimitRatio = sConfigMgr->GetOption("AiPlayerbot.AutoInitEquipLevelLimitRatio", 1.0); addClassCommand = sConfigMgr->GetOption("AiPlayerbot.AddClassCommand", 1); diff --git a/src/PlayerbotAIConfig.h b/src/PlayerbotAIConfig.h index 40a66034..d2488458 100644 --- a/src/PlayerbotAIConfig.h +++ b/src/PlayerbotAIConfig.h @@ -215,6 +215,7 @@ class PlayerbotAIConfig int32 equipmentPersistenceLevel; int32 groupInvitationPermission; int32 botReviveWhenSummon; + bool botRepairWhenSummon; bool autoInitOnly; float autoInitEquipLevelLimitRatio; int32 addClassCommand; diff --git a/src/strategy/actions/UseMeetingStoneAction.cpp b/src/strategy/actions/UseMeetingStoneAction.cpp index 81093a80..0f908530 100644 --- a/src/strategy/actions/UseMeetingStoneAction.cpp +++ b/src/strategy/actions/UseMeetingStoneAction.cpp @@ -176,6 +176,9 @@ bool SummonAction::Teleport(Player* summoner, Player* player) if (summoner->IsWithinLOS(x, y, z)) { + if (sPlayerbotAIConfig->botRepairWhenSummon) // .conf option to repair bot gear when summoned 0 = off, 1 = on + bot->DurabilityRepairAll(false, 1.0f, false); + if (sPlayerbotAIConfig->botReviveWhenSummon < 2) { if (master->IsInCombat()) @@ -200,7 +203,6 @@ bool SummonAction::Teleport(Player* summoner, Player* player) if (sPlayerbotAIConfig->botReviveWhenSummon > 0 && bot->isDead()) { bot->ResurrectPlayer(1.0f, false); - bot->DurabilityRepairAll(false, 1.0f, false); botAI->TellMasterNoFacing("I live, again!"); } From 72eb38af88d9146b446bf12792fa591620c39f5a Mon Sep 17 00:00:00 2001 From: Fuzz Date: Thu, 11 Jul 2024 13:06:17 +1000 Subject: [PATCH 21/51] fixed bots of same faction not fighting in arena until player triggers it --- src/strategy/values/AttackersValue.cpp | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/strategy/values/AttackersValue.cpp b/src/strategy/values/AttackersValue.cpp index 527b8def..cae2223a 100644 --- a/src/strategy/values/AttackersValue.cpp +++ b/src/strategy/values/AttackersValue.cpp @@ -47,8 +47,21 @@ GuidVector AttackersValue::Calculate() if (bot->duel && bot->duel->Opponent) result.push_back(bot->duel->Opponent->GetGUID()); - - return result; + + // workaround for bots of same faction not fighting in arena + if (bot->InArena()) + { + GuidVector possibleTargets = AI_VALUE(GuidVector, "possible targets"); + for (ObjectGuid const guid : possibleTargets) + { + Unit* unit = botAI->GetUnit(guid); + if (unit && unit->IsPlayer() && IsValidTarget(unit, bot)) { + result.push_back(unit->GetGUID()); + } + } + } + + return result; } void AttackersValue::AddAttackersOf(Group* group, std::unordered_set& targets) From be83a1b35fc5e5bb5397e372d738ce8b5463bfa5 Mon Sep 17 00:00:00 2001 From: Chromie-WoW Date: Thu, 11 Jul 2024 04:52:48 -0700 Subject: [PATCH 22/51] Repaironsummon change Removed repair on summon and added it as an option in .conf to turn off and on. --- conf/playerbots.conf.dist | 2 +- src/PlayerbotAIConfig.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/conf/playerbots.conf.dist b/conf/playerbots.conf.dist index 1aa0d97b..d91063a8 100644 --- a/conf/playerbots.conf.dist +++ b/conf/playerbots.conf.dist @@ -132,7 +132,7 @@ AiPlayerbot.GroupInvitationPermission = 1 AiPlayerbot.BotReviveWhenSummon = 1 # Enable/Disable bot repair gear when summon (0 = no, 1 = yes) -# default: 1 (enable for non-combat) +# default: 1 AiPlayerbot.BotRepairWhenSummon = 1 # Non-GM player can only use init=auto to initialize bots based on their own level and gear score diff --git a/src/PlayerbotAIConfig.cpp b/src/PlayerbotAIConfig.cpp index 02d20e17..91e69210 100644 --- a/src/PlayerbotAIConfig.cpp +++ b/src/PlayerbotAIConfig.cpp @@ -273,7 +273,7 @@ bool PlayerbotAIConfig::Initialize() equipmentPersistenceLevel = sConfigMgr->GetOption("AiPlayerbot.EquipmentPersistenceLevel", 80); groupInvitationPermission = sConfigMgr->GetOption("AiPlayerbot.GroupInvitationPermission", 1); botReviveWhenSummon = sConfigMgr->GetOption("AiPlayerbot.BotReviveWhenSummon", 1); - botRepairWhenSummon = sConfigMgr->GetOption("AiPlayerbot.BotRepairWhenSummon", false); + botRepairWhenSummon = sConfigMgr->GetOption("AiPlayerbot.BotRepairWhenSummon", true); autoInitOnly = sConfigMgr->GetOption("AiPlayerbot.AutoInitOnly", false); autoInitEquipLevelLimitRatio = sConfigMgr->GetOption("AiPlayerbot.AutoInitEquipLevelLimitRatio", 1.0); addClassCommand = sConfigMgr->GetOption("AiPlayerbot.AddClassCommand", 1); From 7309d8f3c9fb14cb5665b5b496a97bdb60a969e2 Mon Sep 17 00:00:00 2001 From: Revision Date: Thu, 11 Jul 2024 23:46:59 +0200 Subject: [PATCH 23/51] Add config options for the new summon conditions --- conf/playerbots.conf.dist | 14 +++++++- src/PlayerbotAIConfig.cpp | 3 ++ src/PlayerbotAIConfig.h | 3 ++ .../actions/UseMeetingStoneAction.cpp | 35 +++++++++---------- 4 files changed, 35 insertions(+), 20 deletions(-) diff --git a/conf/playerbots.conf.dist b/conf/playerbots.conf.dist index 8e91ec1d..b81cc222 100644 --- a/conf/playerbots.conf.dist +++ b/conf/playerbots.conf.dist @@ -127,7 +127,19 @@ AiPlayerbot.EquipmentPersistenceLevel = 80 # default: 1 (accept based on level) AiPlayerbot.GroupInvitationPermission = 1 -# Enable/Disable bot revive when summon (0 = never, 1 = enable when non-combat and alive, 2 = enable always) +# Enable/Disable summoning bots when the master is in combat +# default: 1 (enabled) +AiPlayerbot.AllowSummonInCombat = 1 + +# Enable/Disable summoning bots when the master is dead +# default: 1 (enabled) +AiPlayerbot.AllowSummonWhenMasterIsDead = 1 + +# Enable/Disable summoning bots when they are dead (0 = only when the bots are ghosts, 1 = always) +# default: 1 (enabled) +AiPlayerbot.AllowSummonWhenBotIsDead = 1 + +# Enable/Disable bot revive when summon (0 = never, 1 = enable when non-combat, 2 = enable always) # default: 1 (enable for non-combat) AiPlayerbot.BotReviveWhenSummon = 1 diff --git a/src/PlayerbotAIConfig.cpp b/src/PlayerbotAIConfig.cpp index 85ee2d56..79531200 100644 --- a/src/PlayerbotAIConfig.cpp +++ b/src/PlayerbotAIConfig.cpp @@ -273,6 +273,9 @@ bool PlayerbotAIConfig::Initialize() equipmentPersistence = sConfigMgr->GetOption("AiPlayerbot.EquipmentPersistence", false); equipmentPersistenceLevel = sConfigMgr->GetOption("AiPlayerbot.EquipmentPersistenceLevel", 80); groupInvitationPermission = sConfigMgr->GetOption("AiPlayerbot.GroupInvitationPermission", 1); + allowSummonInCombat = sConfigMgr->GetOption("AiPlayerbot.AllowSummonInCombat", true); + allowSummonWhenMasterIsDead = sConfigMgr->GetOption("AiPlayerbot.AllowSummonWhenMasterIsDead", true); + allowSummonWhenBotIsDead = sConfigMgr->GetOption("AiPlayerbot.AllowSummonWhenBotIsDead", true); botReviveWhenSummon = sConfigMgr->GetOption("AiPlayerbot.BotReviveWhenSummon", 1); botRepairWhenSummon = sConfigMgr->GetOption("AiPlayerbot.BotRepairWhenSummon", true); autoInitOnly = sConfigMgr->GetOption("AiPlayerbot.AutoInitOnly", false); diff --git a/src/PlayerbotAIConfig.h b/src/PlayerbotAIConfig.h index 5e63c745..3fb31410 100644 --- a/src/PlayerbotAIConfig.h +++ b/src/PlayerbotAIConfig.h @@ -214,6 +214,9 @@ class PlayerbotAIConfig bool equipmentPersistence; int32 equipmentPersistenceLevel; int32 groupInvitationPermission; + bool allowSummonInCombat; + bool allowSummonWhenMasterIsDead; + bool allowSummonWhenBotIsDead; int32 botReviveWhenSummon; bool botRepairWhenSummon; bool autoInitOnly; diff --git a/src/strategy/actions/UseMeetingStoneAction.cpp b/src/strategy/actions/UseMeetingStoneAction.cpp index 0f908530..f07ca217 100644 --- a/src/strategy/actions/UseMeetingStoneAction.cpp +++ b/src/strategy/actions/UseMeetingStoneAction.cpp @@ -179,28 +179,25 @@ bool SummonAction::Teleport(Player* summoner, Player* player) if (sPlayerbotAIConfig->botRepairWhenSummon) // .conf option to repair bot gear when summoned 0 = off, 1 = on bot->DurabilityRepairAll(false, 1.0f, false); - if (sPlayerbotAIConfig->botReviveWhenSummon < 2) + if (master->IsInCombat() && !sPlayerbotAIConfig->allowSummonInCombat) { - if (master->IsInCombat()) - { - botAI->TellError("You cannot summon me while you're in combat"); - return false; - } - - if (!master->IsAlive()) - { - botAI->TellError("You cannot summon me while you're dead"); - return false; - } - - if (bot->isDead() && !bot->HasPlayerFlag(PLAYER_FLAGS_GHOST)) - { - botAI->TellError("You cannot summon me while I'm dead, you need to release my spirit first"); - return false; - } + botAI->TellError("You cannot summon me while you're in combat"); + return false; } - if (sPlayerbotAIConfig->botReviveWhenSummon > 0 && bot->isDead()) + if (!master->IsAlive() && !sPlayerbotAIConfig->allowSummonWhenMasterIsDead) + { + botAI->TellError("You cannot summon me while you're dead"); + return false; + } + + if (bot->isDead() && !bot->HasPlayerFlag(PLAYER_FLAGS_GHOST) && !sPlayerbotAIConfig->allowSummonWhenBotIsDead) + { + botAI->TellError("You cannot summon me while I'm dead, you need to release my spirit first"); + return false; + } + + if (sPlayerbotAIConfig->botReviveWhenSummon == 2 || (sPlayerbotAIConfig->botReviveWhenSummon == 1 && !master->IsInCombat() && master->IsAlive())) { bot->ResurrectPlayer(1.0f, false); botAI->TellMasterNoFacing("I live, again!"); From 5362668690a33d2fc675b7573db22ae1c21afa4d Mon Sep 17 00:00:00 2001 From: Revision Date: Thu, 11 Jul 2024 23:50:24 +0200 Subject: [PATCH 24/51] Correction for the default value info --- conf/playerbots.conf.dist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/playerbots.conf.dist b/conf/playerbots.conf.dist index b81cc222..561bea76 100644 --- a/conf/playerbots.conf.dist +++ b/conf/playerbots.conf.dist @@ -136,7 +136,7 @@ AiPlayerbot.AllowSummonInCombat = 1 AiPlayerbot.AllowSummonWhenMasterIsDead = 1 # Enable/Disable summoning bots when they are dead (0 = only when the bots are ghosts, 1 = always) -# default: 1 (enabled) +# default: 1 (always) AiPlayerbot.AllowSummonWhenBotIsDead = 1 # Enable/Disable bot revive when summon (0 = never, 1 = enable when non-combat, 2 = enable always) From 031dd2c7befa3139a0ff9288597f9e4564c2719a Mon Sep 17 00:00:00 2001 From: Revision Date: Fri, 12 Jul 2024 13:48:46 +0200 Subject: [PATCH 25/51] Cleanup --- conf/playerbots.conf.dist | 6 +++--- src/PlayerbotAIConfig.cpp | 2 +- src/PlayerbotAIConfig.h | 2 +- src/strategy/actions/UseMeetingStoneAction.cpp | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/conf/playerbots.conf.dist b/conf/playerbots.conf.dist index 561bea76..348478b9 100644 --- a/conf/playerbots.conf.dist +++ b/conf/playerbots.conf.dist @@ -139,9 +139,9 @@ AiPlayerbot.AllowSummonWhenMasterIsDead = 1 # default: 1 (always) AiPlayerbot.AllowSummonWhenBotIsDead = 1 -# Enable/Disable bot revive when summon (0 = never, 1 = enable when non-combat, 2 = enable always) -# default: 1 (enable for non-combat) -AiPlayerbot.BotReviveWhenSummon = 1 +# Enable/Disable reviving the bots when summoning them +# default: 1 (enable) +AiPlayerbot.ReviveBotWhenSummoned = 1 # Enable/Disable bot repair gear when summon (0 = no, 1 = yes) # default: 1 diff --git a/src/PlayerbotAIConfig.cpp b/src/PlayerbotAIConfig.cpp index 79531200..4d6a2a50 100644 --- a/src/PlayerbotAIConfig.cpp +++ b/src/PlayerbotAIConfig.cpp @@ -276,7 +276,7 @@ bool PlayerbotAIConfig::Initialize() allowSummonInCombat = sConfigMgr->GetOption("AiPlayerbot.AllowSummonInCombat", true); allowSummonWhenMasterIsDead = sConfigMgr->GetOption("AiPlayerbot.AllowSummonWhenMasterIsDead", true); allowSummonWhenBotIsDead = sConfigMgr->GetOption("AiPlayerbot.AllowSummonWhenBotIsDead", true); - botReviveWhenSummon = sConfigMgr->GetOption("AiPlayerbot.BotReviveWhenSummon", 1); + reviveBotWhenSummoned = sConfigMgr->GetOption("AiPlayerbot.ReviveBotWhenSummoned", true); botRepairWhenSummon = sConfigMgr->GetOption("AiPlayerbot.BotRepairWhenSummon", true); autoInitOnly = sConfigMgr->GetOption("AiPlayerbot.AutoInitOnly", false); autoInitEquipLevelLimitRatio = sConfigMgr->GetOption("AiPlayerbot.AutoInitEquipLevelLimitRatio", 1.0); diff --git a/src/PlayerbotAIConfig.h b/src/PlayerbotAIConfig.h index 3fb31410..d347b87e 100644 --- a/src/PlayerbotAIConfig.h +++ b/src/PlayerbotAIConfig.h @@ -217,7 +217,7 @@ class PlayerbotAIConfig bool allowSummonInCombat; bool allowSummonWhenMasterIsDead; bool allowSummonWhenBotIsDead; - int32 botReviveWhenSummon; + bool reviveBotWhenSummoned; bool botRepairWhenSummon; bool autoInitOnly; float autoInitEquipLevelLimitRatio; diff --git a/src/strategy/actions/UseMeetingStoneAction.cpp b/src/strategy/actions/UseMeetingStoneAction.cpp index f07ca217..f0267e0c 100644 --- a/src/strategy/actions/UseMeetingStoneAction.cpp +++ b/src/strategy/actions/UseMeetingStoneAction.cpp @@ -197,7 +197,7 @@ bool SummonAction::Teleport(Player* summoner, Player* player) return false; } - if (sPlayerbotAIConfig->botReviveWhenSummon == 2 || (sPlayerbotAIConfig->botReviveWhenSummon == 1 && !master->IsInCombat() && master->IsAlive())) + if (bot->isDead() && sPlayerbotAIConfig->reviveBotWhenSummoned) { bot->ResurrectPlayer(1.0f, false); botAI->TellMasterNoFacing("I live, again!"); From 8292025bb4787ba0047afbffe3d12cf285c078db Mon Sep 17 00:00:00 2001 From: Chromie-WoW Date: Fri, 12 Jul 2024 05:05:11 -0700 Subject: [PATCH 26/51] Update playerbots.conf.dist --- conf/playerbots.conf.dist | 1461 +++++++++++++++++++++++++------------ 1 file changed, 1009 insertions(+), 452 deletions(-) diff --git a/conf/playerbots.conf.dist b/conf/playerbots.conf.dist index d91063a8..e469db3a 100644 --- a/conf/playerbots.conf.dist +++ b/conf/playerbots.conf.dist @@ -1,422 +1,81 @@ -########################################## -# Playerbot Configuration file # -########################################## - -# Enable or disable AI Playerbot -AiPlayerbot.Enabled = 1 - -# Enable random bot system -AiPlayerbot.RandomBotAutologin = 1 - -# Log on all random bots on start -AiPlayerbot.RandomBotLoginAtStartup = 1 - -# Delete all random bot accounts (reset randombots) -AiPlayerbot.DeleteRandomBotAccounts = 0 - -# auto-login all player alts as bots on player login -AiPlayerbot.BotAutologin = 0 - -# Allow login other players' characters as bots -# Default: 0 (disabled) -AiPlayerbot.AllowPlayerBots = 0 - -# Enable LFG for random bots -AiPlayerbot.RandomBotJoinLfg = 1 - -# Enable BG/Arena for random Bots -AiPlayerbot.RandomBotJoinBG = 1 - -# Enable Auto join BG - bots randomly join WSG and 2v2 Arena if server is not lagging -AiPlayerbot.RandomBotAutoJoinBG = 0 - -# Mark many quests <= Bot level as complete (slows down bot creation) -AiPlayerbot.PreQuests = 0 - -# Random bot count -AiPlayerbot.MinRandomBots = 50 -AiPlayerbot.MaxRandomBots = 50 -AiPlayerbot.RandomBotMinLevel = 1 -AiPlayerbot.RandomBotMaxLevel = 80 - -# Enable/Disable rotation of bots (randomly select a bot from the bots pool to go online and rotate them periodically) -# Need to reset rndbot after changing the setting (.playerbot rndbot reset) -# default: 0 (disable, the online bots are fixed) -AiPlayerbot.EnableRotation = 0 - -# Bots pool size for rotation (should be less than RandomBotAccountCount * 10) -AiPlayerbot.RotationPoolSize = 500 - -# Accounts to create for random bots -AiPlayerbot.RandomBotAccountPrefix = "rndbot" -AiPlayerbot.RandomBotAccountCount = 200 - -# Random bot arena team count -AiPlayerbot.RandomBotArenaTeamCount = 20 - -# Delete all random bot arena teams -AiPlayerbot.DeleteRandomBotArenaTeams = 0 - -# Change random bot has lower gear -AiPlayerbot.RandomGearLoweringChance = 0 - -# Chance random bot has max level on first randomize (default 0.15) -AiPlayerbot.RandomBotMaxLevelChance = 0.15 - -# Bots will be summoned to player when accept group invitation -AiPlayerbot.SummonWhenGroup = 1 - -# Show helmet and cloak on randombots (reset required) -AiPlayerbot.RandomBotShowHelmet = 1 -AiPlayerbot.RandomBotShowCloak = 1 - -# Fix the level of random bot (won't level up by grinding) -# Default: 0 (disable) -AiPlayerbot.RandomBotFixedLevel = 0 - -# Disable random levels for randombots -# Every bots started on the specified level and level up by killing mobs. -AiPlayerbot.DisableRandomLevels = 0 - -# Set randombots starting level here if "AiPlayerbot.DisableRandomLevels" enabled -AiPlayerbot.RandombotStartingLevel = 5 - -# Set kill XP rate for bots (default: 1) -# Server XP Rate * AiPlayerbot.KillXPRate -AiPlayerbot.KillXPRate = 1 - -# Disable death knight for bots login -# Need to reset rndbot after changing the setting (.playerbot rndbot reset) -AiPlayerbot.DisableDeathKnightLogin = 0 - -# Set minimum level of randombots where gets enchants on items (Maxlevel + 1 to disable) -# Default: 60 -AiPlayerbot.MinEnchantingBotLevel = 60 - -# Enable expansion limitation -# Default: 1 -AiPlayerbot.LimitEnchantExpansion = 1 - -# Randombots checking players gear score level and deny the group invite if it's too low -# Default: 0 (disabled) -AiPlayerbot.GearScoreCheck = 0 - -# Quest that will be completed and rewarded to all random bots -AiPlayerbot.RandomBotQuestIds = "7848,3802,5505,6502,7761,10277,10285,11492,24499,24511,24710,24712" - -# Randombots will group with nearby bots to do shared quests -AiPlayerbot.RandomBotGroupNearby = 0 - -# Bots without a master will say their lines -AiPlayerbot.RandomBotSayWithoutMaster = 0 - -# Bots will say information about items when collecting them -AiPlayerbot.SayWhenCollectingItems = 1 - -# Set RandomBotMaxLevel bots to RandomBotMinLevel or not -AiPlayerbot.DowngradeMaxLevelBot = 0 - -# Enable/Disable bot equipments persistence (stop random initialization) after certain level (EquipmentPersistenceLevel) -# default: 0 (disable) -AiPlayerbot.EquipmentPersistence = 0 - -# default: 80 -AiPlayerbot.EquipmentPersistenceLevel = 80 - -# 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 - -# Enable/Disable bot revive when summon (0 = never, 1 = enable when non-combat and alive, 2 = enable always) -# default: 1 (enable for non-combat) -AiPlayerbot.BotReviveWhenSummon = 1 - -# Enable/Disable bot repair gear when summon (0 = no, 1 = yes) -# default: 1 -AiPlayerbot.BotRepairWhenSummon = 1 - -# Non-GM player can only use init=auto to initialize bots based on their own level and gear score -# default: 0 (non-gm player can use any intialization commands) -AiPlayerbot.AutoInitOnly = 0 - -# The upper limit ratio of bot equipment level for init=auto -# default: 1.0 (same with the player) -AiPlayerbot.AutoInitEquipLevelLimitRatio = 1.0 - -# Enable/Disable create bot by addclass command (0 = GM only, 1 = enable) -# default: 1 (enable) -AiPlayerbot.AddClassCommand = 1 - -# Enable/Disable maintenance command, learn all available spells and skills, supplement consumables, repair, etc. -# default: 1 (enable) -AiPlayerbot.MaintenanceCommand = 1 - -# Enable/Disable autogear command, auto upgrade player bots gears, the quality is limited by AutoGearQualityLimit and AutoGearScoreLimit -# default: 1 (enable) -AiPlayerbot.AutoGearCommand = 1 - -# Equips quality limitation for auto gear command (1 = normal, 2 = uncommon, 3 = rare, 4 = epic, 5 = legendary) -# default: 3 (rare) -AiPlayerbot.AutoGearQualityLimit = 3 - -# Equips gear score limitation for auto gear command (0 = no limit) -# default: 0 (no limit) -AiPlayerbot.AutoGearScoreLimit = 0 - -# Automation - -# Bots keep looting when group loop method is free for all -# Default: 0 (disabled) -AiPlayerbot.FreeMethodLoot = 0 - -# Bots loot roll level (0 = pass, 1 = greed, 2 = need) -# Default: 1 (greed) -AiPlayerbot.LootRollLevel = 1 - -# Bots pick their quest reward (yes = picks first useful item, no = list all rewards, ask = pick useful item and lists if multiple) -AiPlayerbot.AutoPickReward = no - -# Bots equip upgrades (Bots will equip any item obtained from looting or a quest if they are upgrades) -# Default: 1 (enable) -AiPlayerbot.AutoEquipUpgradeLoot = 1 - -# Equip upgrade threshold for auto equip upgrade -# Default: 1.1 (Equip when the equipment score is 1.1 times higher than the current) -AiPlayerbot.EquipUpgradeThreshold = 1.1 - -# Sync quests with player (Bots will complete quests the moment you hand them in. Bots will ignore looting quest items.) -# Default: 1 (enable) -AiPlayerbot.SyncQuestWithPlayer = 1 - -# Bots will auto-complete quests for the player when handing in -# Default: 0 (disabled) -AiPlayerbot.SyncQuestForPlayer = 0 - -# Sync max random bot level with max level of online players -# Default: 0 (disabled) -AiPlayerbot.SyncLevelWithPlayers = 0 - -# Give free food to random bots -# Default: 1 (enabled) -AiPlayerbot.FreeFood = 1 - -# Bot automatically trains spells when talking to trainer (yes = train all available spells as long as the bot has the money, free = auto trains with no money cost, no = only list spells) -# Only for random bots -AiPlayerbot.AutoTrainSpells = yes - -# Bots automatically learn classquest reward spells on levelup -# Only for random bots -# Default: 0 (disabled) -AiPlayerbot.AutoLearnQuestSpells = 0 - -# Bots automatically learn trainable spells on levelup -# Only for random bots -# Default: 1 (enabled) -AiPlayerbot.AutoLearnTrainerSpells = 1 - -# Bots automatically teleport to another place for leveling on levelup -# Only for random bots -# Default: 1 (enabled) -AiPlayerbot.AutoTeleportForLevel = 1 - -# Bot automatically picks talent points on levelup -# Only for random bots -# Default: 1 (enabled) -AiPlayerbot.AutoPickTalents = 1 - -# Bot automatically upgrade equipments on levelup -# Only for random bots -# Default: 1 (enabled) -AiPlayerbot.AutoUpgradeEquip = 1 - -# Random Bots will pick quests on their own and try to complete -# Only for random bots -# Default: 1 (enabled) -AiPlayerbot.AutoDoQuests = 1 - -# Prefix for bot chat commands (e.g. follow, stay) -AiPlayerbot.CommandPrefix = "" - -# Separator for bot chat commands -AiPlayerbot.CommandSeparator = "\\\\" - -# Max AI iterations per tick -AiPlayerbot.IterationsPerTick = 10 - -# Allow/deny bots from your guild -AiPlayerbot.AllowGuildBots = 1 - -# Delay between two short-time spells cast -AiPlayerbot.GlobalCooldown = 500 - -# Max wait time when moving -AiPlayerbot.MaxWaitForMove = 5000 - -# Max search time for movement (higher for better movement on slopes) -# default: 3 -AiPlayerbot.MaxMovementSearchTime = 3 - -# Action expiration time -AiPlayerbot.ExpireActionTime = 5000 - -# Max dispel auras duration -AiPlayerbot.DispelAuraDuration = 700 - -# Delay between two bot actions -AiPlayerbot.ReactDelay = 100 - -# Inactivity delay -AiPlayerbot.PassiveDelay = 10000 - -# Minimum delay between repeating actions (chat messages, emotes etc) -AiPlayerbot.RepeatDelay = 2000 - -# Delay timers -AiPlayerbot.ErrorDelay = 100 -AiPlayerbot.RpgDelay = 10000 -AiPlayerbot.SitDelay = 20000 -# ReturnDelay has a minimum value of 2000 - lower values will cause a crash! -AiPlayerbot.ReturnDelay = 2000 -AiPlayerbot.LootDelay = 1000 - -# Distances -AiPlayerbot.FarDistance = 20.0 -AiPlayerbot.SightDistance = 75.0 -AiPlayerbot.SpellDistance = 28.5 -AiPlayerbot.ShootDistance = 5.0 -AiPlayerbot.ReactDistance = 150.0 -AiPlayerbot.GrindDistance = 75.0 -AiPlayerbot.HealDistance = 38.5 -AiPlayerbot.LootDistance = 15.0 -AiPlayerbot.FleeDistance = 5.0 -AiPlayerbot.TooCloseDistance = 5.0 -AiPlayerbot.MeleeDistance = 0.75 -AiPlayerbot.FollowDistance = 1.5 -AiPlayerbot.WhisperDistance = 6000.0 -AiPlayerbot.ContactDistance = 0.45 -AiPlayerbot.AoeRadius = 10 -AiPlayerbot.RpgDistance = 200 -AiPlayerbot.AggroDistance = 22 - -# Bot can flee for enemy -AiPlayerbot.FleeingEnabled = 1 - -# Health/Mana levels -AiPlayerbot.CriticalHealth = 25 -AiPlayerbot.LowHealth = 45 -AiPlayerbot.MediumHealth = 65 -AiPlayerbot.AlmostFullHealth = 85 -AiPlayerbot.LowMana = 15 -AiPlayerbot.MediumMana = 40 - -# Enable healer bot save mana -# Default: 1 (enable) -AiPlayerbot.AutoSaveMana = 1 - -# Healer bot save mana threshold -# Default: 60 (60%) -AiPlayerbot.SaveManaThreshold = 60 - -# Enable auto avoid aoe (experimental) -# Default: 1 (enable) -AiPlayerbot.AutoAvoidAoe = 1 - -# Tell which spell is avoiding (experimental) -# Default: 1 (enable) -AiPlayerbot.TellWhenAvoidAoe = 1 - -# Random bot default strategies (applied after defaults) -AiPlayerbot.RandomBotCombatStrategies = "+dps,+dps assist,-threat" -# AiPlayerbot.RandomBotNonCombatStrategies = "+grind,+loot,+rpg,+custom::say" -AiPlayerbot.RandomBotNonCombatStrategies = "" -AiPlayerbot.CombatStrategies = "" -AiPlayerbot.NonCombatStrategies = "" - -# Maps where bots can be teleported to -AiPlayerbot.RandomBotMaps = 0,1,530,571 - -# Probabilty bots teleport to banker (city) -# default: 0.25 -AiPlayerbot.ProbTeleToBankers = 0.25 - -# Quest items to leave (do not destroy) -AiPlayerbot.RandomBotQuestItems = "6948,5175,5176,5177,5178,16309,12382,13704,11000" - -# PvP Restricted Zones (bots don't pvp) -AiPlayerbot.PvpProhibitedZoneIds = "2255,656,2361,2362,2363,976,35,2268,3425,392,541,1446,3828,3712,3738,3565,3539,3623,4152,3988,4658,4284,4418,4436,4275,4323,4395,3703" # 33(stranglethorn vale),440(tanaris) - -# PvP Restricted Areas (bots don't pvp) -AiPlayerbot.PvpProhibitedAreaIds = "976,35,392" - -# Spells every random bot will learn on randomize (54197 - cold weather flying) -AiPlayerbot.RandomBotSpellIds = "54197" - -# Level diff between random bots and nearby creatures for random teleports -AiPlayerbot.RandomBotTeleLowerLevel = 3 -AiPlayerbot.RandomBotTeleHigherLevel = 1 - -# ID of spell to open lootable chests -AiPlayerbot.OpenGoSpell = 6477 - -# Intervals -AiPlayerbot.RandomBotUpdateInterval = 20 -AiPlayerbot.RandomBotCountChangeMinInterval = 1800 -AiPlayerbot.RandomBotCountChangeMaxInterval = 7200 -AiPlayerbot.MinRandomBotInWorldTime = 3600 -AiPlayerbot.MaxRandomBotInWorldTime = 43200 -AiPlayerbot.MinRandomBotRandomizeTime = 302400 -AiPlayerbot.MaxRandomBotRandomizeTime = 1209600 -AiPlayerbot.RandomBotsPerInterval = 500 -AiPlayerbot.MinRandomBotReviveTime = 60 -AiPlayerbot.MaxRandomBotReviveTime = 300 -AiPlayerbot.MinRandomBotTeleportInterval = 3600 -AiPlayerbot.MaxRandomBotTeleportInterval = 18000 -AiPlayerbot.RandomBotInWorldWithRotationDisabled = 31104000 - -# How far random bots are teleported after death -AiPlayerbot.RandomBotTeleportDistance = 100 - -# Debug switches -AiPlayerbot.SpellDump = 0 -AiPlayerbot.LogInGroupOnly = 1 -AiPlayerbot.LogValuesPerTick = 0 -AiPlayerbot.RandomChangeMultiplier = 1 - -# Command server port, 0 - disabled -AiPlayerbot.CommandServerPort = 8888 - -# Enables/Disables performance monitor -AiPlayerbot.PerfMonEnabled = 0 - -# Custom config to allow logfiles to be created. -# Example: AiPlayerbot.AllowedLogFiles = travelNodes.csv,travelPaths.csv,TravelNodeStore.h,bot_movement.csv,bot_location.csv -AiPlayerbot.AllowedLogFiles = "" - -# Applies a permanent buff to all bots. -# WorldBuff.Faction.Class.MinLevel.MaxLevel - -# Added following config -# Selfbot permission level (0 = disabled, 1 = gm only (default), 2 = all players, 3 = activate on login) -AiPlayerbot.SelfBotLevel = 1 - -# Enables/Disables bot cheating -AiPlayerbot.BotCheats = "taxi" - -# Enables/Disables password to bot account -AiPlayerbot.RandomBotRandomPassword = 0 - -# Diff with/without player in server. The server will tune bot activity to reach the desired server tick speed (in ms). -AiPlayerbot.EnablePrototypePerformanceDiff = 0 -AiPlayerbot.DiffWithPlayer = 100 -AiPlayerbot.DiffEmpty = 200 - -################################################################################## -# # -# Database Stuff # -# # -################################################################################## +################################################## +# PLAYERBOT CONFIGURATION FILE # +################################################## +################################################################################################### +# SECTION INDEX # +# PLAYERBOT SYSTEM SETTINGS +# DATABASE & CONNECTIONS +# DEBUG +# CHAT SETTINGS +# LOGS +# PLAYERBOT SETTINGS +# GENERAL +# SUMMON OPTIONS +# GEAR +# LOOTING +# TIMERS +# DISTANCES +# THRESHOLDS +# QUESTS +# COMBAT +# CHEATS +# SPELLS +# PREMADE SPECS +# INFORMATION +# WARRIOR +# PALADIN +# HUNTER +# ROGUE +# PRIEST +# DEATHKNIGHT +# SHAMAN +# MAGE +# WARLOCK +# DRUID +# PLAYERBOT RNDBOT SPECIFIC SETTINGS +# GENERAL +# ACCOUNT DELETE RNDBOTS +# LEVELS +# GEAR +# QUESTS +# PROFESSIONS +# SPELLS +# STRATEGIES +# TELEPORTS +# BATTLEGROUND & ARENA & PVP +# INTERVALS +# DEFAULT TALENT SPEC +# WARRIOR +# PALADIN +# HUNTER +# ROGUE +# PRIEST +# DEATHKNIGHT +# SHAMAN +# MAGE +# WARLOCK +# DRUID +# DEPRECIATED (TEMPORARY) +# +# +# +# +# +################################################################################################### + +################################### +# # +# PLAYERBOT SYSTEM SETTINGS # +# # +################################### + +#################################################################################################### +# DATABASE & CONNECTIONS +# +# + # PlayerbotsDatabaseInfo # Description: Database connection settings for the playerbots server. # Example: "hostname;port;username;password;database" @@ -453,16 +112,430 @@ PlayerbotsDatabase.SynchThreads = 1 Playerbots.Updates.EnableDatabases = 1 -############################################## -# PremadeSpec # -############################################## +# Command server port, 0 - disabled +AiPlayerbot.CommandServerPort = 8888 + +# Diff with/without player in server. The server will tune bot activity to reach the desired server tick speed (in ms).# PLAYERBOT SYSTEM SETTINGS # +AiPlayerbot.EnablePrototypePerformanceDiff = 0 +AiPlayerbot.DiffWithPlayer = 100 +AiPlayerbot.DiffEmpty = 200 + +# +# +# +#################################################################################################### + +#################################################################################################### +# DEBUG SWITCHES +# +# + +AiPlayerbot.SpellDump = 0 +AiPlayerbot.LogInGroupOnly = 1 +AiPlayerbot.LogValuesPerTick = 0 +AiPlayerbot.RandomChangeMultiplier = 1 + +# Enables/Disables performance monitor +AiPlayerbot.PerfMonEnabled = 0 + +# +# +# +#################################################################################################### + +#################################################################################################### +# CHAT SETTINGS +# +# + +# Prefix for bot chat commands (e.g. follow, stay) +AiPlayerbot.CommandPrefix = "" + +# Separator for bot chat commands +AiPlayerbot.CommandSeparator = "\\\\" + +# +# +# +#################################################################################################### + +#################################################################################################### +# LOGS +# +# + +# Custom config to allow logfiles to be created. +# Example: AiPlayerbot.AllowedLogFiles = travelNodes.csv,travelPaths.csv,TravelNodeStore.h,bot_movement.csv,bot_location.csv +AiPlayerbot.AllowedLogFiles = "" + +Appender.Playerbots=2,5,0,Playerbots.log,w +Logger.playerbots=5,Console Playerbots + +# +# +# +#################################################################################################### + +################################################################################################### + +################################### +# # +# PLAYERBOT SETTINGS # +# # +################################### + +#################################################################################################### + +#################################################################################################### +# GENERAL +# +# + +# Enable or disable AI Playerbot +AiPlayerbot.Enabled = 1 + +# Enable/Disable create bot by addclass command (0 = GM only, 1 = enable) +# default: 1 (enable) +AiPlayerbot.AddClassCommand = 1 + +# 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 + +# Non-GM player can only use init=auto to initialize bots based on their own level and gear score +# default: 0 (non-gm player can use any intialization commands) +AiPlayerbot.AutoInitOnly = 0 + +# Enable expansion limitation +# Default: 1 +AiPlayerbot.LimitEnchantExpansion = 1 + +# auto-login all player alts as bots on player login +AiPlayerbot.BotAutologin = 0 + +# Allow login other players' characters as bots +# Default: 0 (disabled) +AiPlayerbot.AllowPlayerBots = 0 + +# Bots will be summoned to player when accept group invitation +AiPlayerbot.SummonWhenGroup = 1 + +# Allow/deny bots from your guild +AiPlayerbot.AllowGuildBots = 1 + +# Sync max random bot level with max level of online players +# Default: 0 (disabled) +AiPlayerbot.SyncLevelWithPlayers = 0 + +# Added following config +# Selfbot permission level (0 = disabled, 1 = gm only (default), 2 = all players, 3 = activate on login) +AiPlayerbot.SelfBotLevel = 1 + +# +# +# +#################################################################################################### + +#################################################################################################### +# SUMMON OPTIONS +# +# + +# Enable/Disable summoning bots when the master is in combat +# default: 1 (enabled) +AiPlayerbot.AllowSummonInCombat = 1 + +# Enable/Disable summoning bots when the master is dead +# default: 1 (enabled) +AiPlayerbot.AllowSummonWhenMasterIsDead = 1 + +# Enable/Disable summoning bots when they are dead (0 = only when the bots are ghosts, 1 = always) +# default: 1 (always) +AiPlayerbot.AllowSummonWhenBotIsDead = 1 + +# Enable/Disable bot revive when summon (0 = never, 1 = enable when non-combat, 2 = enable always) +# default: 1 (enable for non-combat) +AiPlayerbot.BotReviveWhenSummon = 1 + +# Enable/Disable bot repair gear when summon (0 = no, 1 = yes) +# default: 1 +AiPlayerbot.BotRepairWhenSummon = 1 + +# +# +# +#################################################################################################### + +#################################################################################################### +# GEAR +# +# + +# Show helmet and cloak on randombots (reset required) +AiPlayerbot.RandomBotShowHelmet = 1 +AiPlayerbot.RandomBotShowCloak = 1 + + + +# The upper limit ratio of bot equipment level for init=auto +# default: 1.0 (same with the player) +AiPlayerbot.AutoInitEquipLevelLimitRatio = 1.0 + +# Enable/Disable autogear command, auto upgrade player bots gears, the quality is limited by AutoGearQualityLimit and AutoGearScoreLimit +# default: 1 (enable) +AiPlayerbot.AutoGearCommand = 1 + +# Equips quality limitation for auto gear command (1 = normal, 2 = uncommon, 3 = rare, 4 = epic, 5 = legendary) +# default: 3 (rare) +AiPlayerbot.AutoGearQualityLimit = 3 + +# Equips gear score limitation for auto gear command (0 = no limit) +# default: 0 (no limit) +AiPlayerbot.AutoGearScoreLimit = 0 + +# +# +# +#################################################################################################### + +#################################################################################################### +# LOOTING +# +# + +# Bots will say information about items when collecting them +AiPlayerbot.SayWhenCollectingItems = 1 + +# Bots keep looting when group loop method is free for all +# Default: 0 (disabled) +AiPlayerbot.FreeMethodLoot = 0 + +# Bots loot roll level (0 = pass, 1 = greed, 2 = need) +# Default: 1 (greed) +AiPlayerbot.LootRollLevel = 1 + +# Bots equip upgrades (Bots will equip any item obtained from looting or a quest if they are upgrades) +# Default: 1 (enable) +AiPlayerbot.AutoEquipUpgradeLoot = 1 + +# Equip upgrade threshold for auto equip upgrade +# Default: 1.1 (Equip when the equipment score is 1.1 times higher than the current) +AiPlayerbot.EquipUpgradeThreshold = 1.1 + +# +# +# +#################################################################################################### + +#################################################################################################### +# TIMERS +# +# + +# Max AI iterations per tick +AiPlayerbot.IterationsPerTick = 10 + +# Delay between two short-time spells cast +AiPlayerbot.GlobalCooldown = 500 + +# Max wait time when moving +AiPlayerbot.MaxWaitForMove = 5000 + +# Max search time for movement (higher for better movement on slopes) +# default: 3 +AiPlayerbot.MaxMovementSearchTime = 3 + +# Action expiration time +AiPlayerbot.ExpireActionTime = 5000 + +# Max dispel auras duration +AiPlayerbot.DispelAuraDuration = 700 + +# Delay between two bot actions +AiPlayerbot.ReactDelay = 100 + +# Inactivity delay +AiPlayerbot.PassiveDelay = 10000 + +# Minimum delay between repeating actions (chat messages, emotes etc) +AiPlayerbot.RepeatDelay = 2000 + +# Delay timers +AiPlayerbot.ErrorDelay = 100 +AiPlayerbot.RpgDelay = 10000 +AiPlayerbot.SitDelay = 20000 +# ReturnDelay has a minimum value of 2000 - lower values will cause a crash! +AiPlayerbot.ReturnDelay = 2000 +AiPlayerbot.LootDelay = 1000 + +# +# +# +#################################################################################################### + +#################################################################################################### +# DISTANCES +# +# + +AiPlayerbot.FarDistance = 20.0 +AiPlayerbot.SightDistance = 75.0 +AiPlayerbot.SpellDistance = 28.5 +AiPlayerbot.ShootDistance = 5.0 +AiPlayerbot.ReactDistance = 150.0 +AiPlayerbot.GrindDistance = 75.0 +AiPlayerbot.HealDistance = 38.5 +AiPlayerbot.LootDistance = 15.0 +AiPlayerbot.FleeDistance = 5.0 +AiPlayerbot.TooCloseDistance = 5.0 +AiPlayerbot.MeleeDistance = 0.75 +AiPlayerbot.FollowDistance = 1.5 +AiPlayerbot.WhisperDistance = 6000.0 +AiPlayerbot.ContactDistance = 0.45 +AiPlayerbot.AoeRadius = 10 +AiPlayerbot.RpgDistance = 200 +AiPlayerbot.AggroDistance = 22 + +# +# +# +#################################################################################################### + +#################################################################################################### +#THRESHOLDS +# +# + +# Set kill XP rate for bots (default: 1) +# Server XP Rate * AiPlayerbot.KillXPRate +AiPlayerbot.KillXPRate = 1 + +# Health/Mana levels +AiPlayerbot.CriticalHealth = 25 +AiPlayerbot.LowHealth = 45 +AiPlayerbot.MediumHealth = 65 +AiPlayerbot.AlmostFullHealth = 85 +AiPlayerbot.LowMana = 15 +AiPlayerbot.MediumMana = 40 + +# Enable healer bot save mana +# Default: 1 (enable) +AiPlayerbot.AutoSaveMana = 1 + +# Healer bot save mana threshold +# Default: 60 (60%) +AiPlayerbot.SaveManaThreshold = 60 + +# +# +# +#################################################################################################### + +#################################################################################################### +# QUESTS +# +# + +# Mark many quests <= Bot level as complete (slows down bot creation) +AiPlayerbot.PreQuests = 0 + +# Bots pick their quest reward (yes = picks first useful item, no = list all rewards, ask = pick useful item and lists if multiple) +AiPlayerbot.AutoPickReward = no + +# Sync quests with player (Bots will complete quests the moment you hand them in. Bots will ignore looting quest items.) +# Default: 1 (enable) +AiPlayerbot.SyncQuestWithPlayer = 1 + +# Bots will auto-complete quests for the player when handing in +# Default: 0 (disabled) +AiPlayerbot.SyncQuestForPlayer = 0 + +# +# +# +#################################################################################################### + +#################################################################################################### +# COMBAT +# +# + +# Bot can flee for enemy +AiPlayerbot.FleeingEnabled = 1 + +# Enable auto avoid aoe (experimental) +# Default: 1 (enable) +AiPlayerbot.AutoAvoidAoe = 1 + +# Tell which spell is avoiding (experimental) +# Default: 1 (enable) +AiPlayerbot.TellWhenAvoidAoe = 1 + +# +# +# +#################################################################################################### + +#################################################################################################### +# CHEATS +# +# + +# Enable/Disable maintenance command, learn all available spells and skills, supplement consumables, repair, etc. +# default: 1 (enable) +AiPlayerbot.MaintenanceCommand = 1 + +# Enables/Disables bot cheating +AiPlayerbot.BotCheats = "taxi" + +# +# +# +#################################################################################################### + +#################################################################################################### +# SPELLS +# +# + +# ID of spell to open lootable chests +AiPlayerbot.OpenGoSpell = 6477 + +# Applies a permanent buff to all bots. +# WorldBuff.Faction.Class.MinLevel.MaxLevel + +# +# +# +################################################################################################### + +################################### +# # +# PREMADE SPECS # +# # +################################### + +################################################################################################### +# INFORMATION +# +# + # AiPlayerbot.PremadeSpecName.. = #Name of the talent specialisation # AiPlayerbot.PremadeSpecLink... = #Wowhead style link the bot should work towards at given level. # AiPlayerbot.PremadeSpecGlyph.. = ,,,,, #ItemId of the glyphs # e.g., formulate the link on https://www.wowhead.com/wotlk/talent-calc/warrior/3022032123335100202012013031251-32505010002 # 0 <= specno < 20, 1 <= level <= 80 -# Warrior +# +# +# +################################################################################################### + +################################################################################################### +# WARRIOR +# +# + AiPlayerbot.PremadeSpecName.1.0 = arms pve AiPlayerbot.PremadeSpecGlyph.1.0 = 43418,43395,43423,43399,49084,43421 AiPlayerbot.PremadeSpecLink.1.0.60 = 3022032023335100202012013031241 @@ -476,7 +549,16 @@ AiPlayerbot.PremadeSpecGlyph.1.2 = 43424,43395,43425,43399,49084,45793 AiPlayerbot.PremadeSpecLink.1.2.60 = --053351225000210521030113321 AiPlayerbot.PremadeSpecLink.1.2.80 = 3500030023-301-053351225000210521030113321 -# Paladin +# +# +# +################################################################################################### + +################################################################################################### +# PALADIN +# +# + AiPlayerbot.PremadeSpecName.2.0 = holy pve AiPlayerbot.PremadeSpecGlyph.2.0 = 41106,43367,45741,43369,43365,41109 AiPlayerbot.PremadeSpecLink.2.0.60 = 50350151020013053100515221 @@ -491,7 +573,16 @@ AiPlayerbot.PremadeSpecLink.2.2.60 = --05230051203331302133231131 AiPlayerbot.PremadeSpecLink.2.2.65 = -05-05230051203331302133231131 AiPlayerbot.PremadeSpecLink.2.2.80 = 050501-05-05232051203331302133231331 -# Hunter +# +# +# +################################################################################################### + +################################################################################################### +# HUNTER +# +# + AiPlayerbot.PremadeSpecName.3.0 = bm pve AiPlayerbot.PremadeSpecGlyph.3.0 = 42912,43350,42902,43351,43338,45732 AiPlayerbot.PremadeSpecLink.3.0.60 = 51200201505112243100511351 @@ -505,7 +596,16 @@ AiPlayerbot.PremadeSpecGlyph.3.2 = 42912,43350,45731,43351,43338,45732 AiPlayerbot.PremadeSpecLink.3.2.60 = --5000032500033330502135001331 AiPlayerbot.PremadeSpecLink.3.2.80 = -005305101-5000032500033330522135301331 -# Rogue +# +# +# +################################################################################################### + +################################################################################################### +# ROGUE +# +# + AiPlayerbot.PremadeSpecName.4.0 = as pve AiPlayerbot.PremadeSpecGlyph.4.0 = 45768,43379,45761,43380,43378,45767 AiPlayerbot.PremadeSpecLink.4.0.60 = 005323005350100520103331051 @@ -519,7 +619,16 @@ AiPlayerbot.PremadeSpecGlyph.4.2 = 42967,43379,45764,43380,43378,45767 AiPlayerbot.PremadeSpecLink.4.2.60 = --5120122030321121050135031241 AiPlayerbot.PremadeSpecLink.4.2.80 = 0053231-2-5120222030321121050135231251 -# Priest +# +# +# +################################################################################################### + +################################################################################################### +# PRIEST +# +# + AiPlayerbot.PremadeSpecName.5.0 = disc pve AiPlayerbot.PremadeSpecGlyph.5.0 = 42408,43371,42400,43374,43342,45756 AiPlayerbot.PremadeSpecLink.5.0.60 = 0503203130300512301323131051 @@ -533,7 +642,16 @@ AiPlayerbot.PremadeSpecGlyph.5.2 = 42406,43371,42407,43374,43342,42415 AiPlayerbot.PremadeSpecLink.5.2.60 = --325003041203010323150301351 AiPlayerbot.PremadeSpecLink.5.2.80 = 0503203--325023051223010323152301351 -# DeathKnight +# +# +# +################################################################################################### + +################################################################################################### +# DEATHKNIGHT +# +# + AiPlayerbot.PremadeSpecName.6.0 = blood pve AiPlayerbot.PremadeSpecGlyph.6.0 = 45805,43673,43827,43544,43672,43554 AiPlayerbot.PremadeSpecLink.6.0.60 = 035502150300331320102013111-005 @@ -551,7 +669,16 @@ AiPlayerbot.PremadeSpecGlyph.6.3 = 45805,43673,43827,43544,43672,43554 AiPlayerbot.PremadeSpecLink.6.3.60 = 005512153330030320102013-305 AiPlayerbot.PremadeSpecLink.6.3.80 = 005512153330030320102013-3050505002023001-002 -# Shaman +# +# +# +################################################################################################### + +################################################################################################### +# SHAMAN +# +# + AiPlayerbot.PremadeSpecName.7.0 = ele pve AiPlayerbot.PremadeSpecGlyph.7.0 = 41536,43385,41532,43386,44923,45776 AiPlayerbot.PremadeSpecLink.7.0.60 = 4530001520213351102301351 @@ -565,7 +692,16 @@ AiPlayerbot.PremadeSpecGlyph.7.2 = 41517,43385,41527,43386,44923,45775 AiPlayerbot.PremadeSpecLink.7.2.60 = --50005301335310501002331241 AiPlayerbot.PremadeSpecLink.7.2.80 = -00505031-50005331335310501022331251 -# Mage +# +# +# +################################################################################################### + +################################################################################################### +# MAGE +# +# + AiPlayerbot.PremadeSpecName.8.0 = arcane pve AiPlayerbot.PremadeSpecGlyph.8.0 = 42735,43339,44955,43364,43361,42751 AiPlayerbot.PremadeSpecLink.8.0.60 = 23000503110033014032310150532 @@ -579,7 +715,16 @@ AiPlayerbot.PremadeSpecGlyph.8.2 = 42742,43339,50045,43364,43361,42751 AiPlayerbot.PremadeSpecLink.8.2.60 = --3533103310203100232102231151 AiPlayerbot.PremadeSpecLink.8.2.80 = 23002322010203--0533003313203100232112231151 -# Warlock +# +# +# +################################################################################################### + +################################################################################################### +# WARLOCK +# +# + AiPlayerbot.PremadeSpecName.9.0 = affli pve AiPlayerbot.PremadeSpecGlyph.9.0 = 45785,43390,50077,43394,43393,45779 AiPlayerbot.PremadeSpecLink.9.0.60 = 2350022001113510053500131151 @@ -595,7 +740,16 @@ AiPlayerbot.PremadeSpecGlyph.9.2 = 45785,43390,50077,43394,43393,42454 AiPlayerbot.PremadeSpecLink.9.2.60 = --05203205210131051313230341 AiPlayerbot.PremadeSpecLink.9.2.80 = -03310030003-05203205210331051335230351 -# Druid +# +# +# +################################################################################################### + +################################################################################################### +# DRUID +# +# + AiPlayerbot.PremadeSpecName.11.0 = balance pve AiPlayerbot.PremadeSpecGlyph.11.0 = 40916,43331,40921,43335,44922,40919 AiPlayerbot.PremadeSpecLink.11.0.60 = 5012203115331003213302301231 @@ -613,75 +767,476 @@ AiPlayerbot.PremadeSpecGlyph.11.3 = 40902,43331,40901,43335,44922,45604 AiPlayerbot.PremadeSpecLink.11.3.60 = -553202032322010052100030310501 AiPlayerbot.PremadeSpecLink.11.3.80 = -553202032322010053100030310511-205503012 -############################################## -# Default TalentSpec for random bots # -############################################## +# +# +# +################################################################################################### + +####################################### +# # +# PLAYERBOT RNDBOT SPECIFIC SETTINGS # +# # +####################################### + +#################################################################################################### +# GENERAL +# +# + +# Enable random bot system +AiPlayerbot.RandomBotAutologin = 1 + +# Enables/Disables password to bot account +AiPlayerbot.RandomBotRandomPassword = 0 + +# Log on all random bots on start +AiPlayerbot.RandomBotLoginAtStartup = 1 + +# Accounts to create for random bots +AiPlayerbot.RandomBotAccountPrefix = "rndbot" +AiPlayerbot.RandomBotAccountCount = 200 + +# Random bot count +AiPlayerbot.MinRandomBots = 50 +AiPlayerbot.MaxRandomBots = 50 +AiPlayerbot.RandomBotMinLevel = 1 +AiPlayerbot.RandomBotMaxLevel = 80 + +# Bots pool size for rotation (should be less than RandomBotAccountCount * 10) +AiPlayerbot.RotationPoolSize = 500 + +# Enable/Disable rotation of bots (randomly select a bot from the bots pool to go online and rotate them periodically) +# Need to reset rndbot after changing the setting (.playerbot rndbot reset) +# default: 0 (disable, the online bots are fixed) +AiPlayerbot.EnableRotation = 0 + +# Bots without a master will say their lines +AiPlayerbot.RandomBotSayWithoutMaster = 0 + +# Enable LFG for random bots +AiPlayerbot.RandomBotJoinLfg = 1 + +# Disable death knight for bots login +# Need to reset rndbot after changing the setting (.playerbot rndbot reset) +AiPlayerbot.DisableDeathKnightLogin = 0 + +# Give free food to random bots +# Default: 1 (enabled) +AiPlayerbot.FreeFood = 1 + +# Bots automatically teleport to another place for leveling on levelup +# Only for random bots +# Default: 1 (enabled) +AiPlayerbot.AutoTeleportForLevel = 1 + +# +# +# +#################################################################################################### + +#################################################################################################### +# ACCOUNTS DELETE RNDBOTS +# +# + +# Delete all random bot accounts (reset randombots) +AiPlayerbot.DeleteRandomBotAccounts = 0 + +# +# +# +#################################################################################################### + +#################################################################################################### +# LEVELS +# +# + +# Disable random levels for randombots +# Every bots started on the specified level and level up by killing mobs. +AiPlayerbot.DisableRandomLevels = 0 + +# Set randombots starting level here if "AiPlayerbot.DisableRandomLevels" enabled +AiPlayerbot.RandombotStartingLevel = 5 + +# Chance random bot has max level on first randomize (default 0.15) +AiPlayerbot.RandomBotMaxLevelChance = 0.15 + +# Fix the level of random bot (won't level up by grinding) +# Default: 0 (disable) +AiPlayerbot.RandomBotFixedLevel = 0 + +# Set RandomBotMaxLevel bots to RandomBotMinLevel or not +AiPlayerbot.DowngradeMaxLevelBot = 0 + +# Bot automatically picks talent points on levelup +# Only for random bots +# Default: 1 (enabled) +AiPlayerbot.AutoPickTalents = 1 + +# +# +# +#################################################################################################### + +#################################################################################################### +# GEAR +# +# + +# Change random bot has lower gear +AiPlayerbot.RandomGearLoweringChance = 0 + +# Randombots checking players gear score level and deny the group invite if it's too low +# Default: 0 (disabled) +AiPlayerbot.GearScoreCheck = 0 + +# Enable/Disable bot equipments persistence (stop random initialization) after certain level (EquipmentPersistenceLevel) +# default: 0 (disable) +AiPlayerbot.EquipmentPersistence = 0 + +# default: 80 +AiPlayerbot.EquipmentPersistenceLevel = 80 + +# Bot automatically upgrade equipments on levelup +# Only for random bots +# Default: 1 (enabled) +AiPlayerbot.AutoUpgradeEquip = 1 + +# +# +# +#################################################################################################### + +#################################################################################################### +# QUESTS +# +# + +# Quest that will be completed and rewarded to all random bots +AiPlayerbot.RandomBotQuestIds = "7848,3802,5505,6502,7761,10277,10285,11492,24499,24511,24710,24712" + +# Randombots will group with nearby bots to do shared quests +AiPlayerbot.RandomBotGroupNearby = 0 + +# Random Bots will pick quests on their own and try to complete +# Only for random bots +# Default: 1 (enabled) +AiPlayerbot.AutoDoQuests = 1 + +# Quest items to leave (do not destroy) +AiPlayerbot.RandomBotQuestItems = "6948,5175,5176,5177,5178,16309,12382,13704,11000" + +# +# +# +#################################################################################################### + +#################################################################################################### +# PROFESSIONS +# +# + +# Set minimum level of randombots where gets enchants on items (Maxlevel + 1 to disable) +# Default: 60 +AiPlayerbot.MinEnchantingBotLevel = 60 + +# +# +# +#################################################################################################### + +#################################################################################################### +# SPELLS +# +# + +# Bot automatically trains spells when talking to trainer (yes = train all available spells as long as the bot has the money, free = auto trains with no money cost, no = only list spells) +# Only for random bots +AiPlayerbot.AutoTrainSpells = yes + +# Bots automatically learn classquest reward spells on levelup +# Only for random bots +# Default: 0 (disabled) +AiPlayerbot.AutoLearnQuestSpells = 0 + +# Bots automatically learn trainable spells on levelup +# Only for random bots +# Default: 1 (enabled) +AiPlayerbot.AutoLearnTrainerSpells = 1 + +# Spells every random bot will learn on randomize (54197 - cold weather flying) +AiPlayerbot.RandomBotSpellIds = "54197" + +# +# +# +#################################################################################################### + +#################################################################################################### +# STRATEGIES +# +# + +# Random bot default strategies (applied after defaults) +AiPlayerbot.RandomBotCombatStrategies = "+dps,+dps assist,-threat" +# AiPlayerbot.RandomBotNonCombatStrategies = "+grind,+loot,+rpg,+custom::say" +AiPlayerbot.RandomBotNonCombatStrategies = "" +AiPlayerbot.CombatStrategies = "" +AiPlayerbot.NonCombatStrategies = "" + +# +# +# +#################################################################################################### + +#################################################################################################### +# TELEPORTS +# +# + +# Maps where bots can be teleported to +AiPlayerbot.RandomBotMaps = 0,1,530,571 + +# Probabilty bots teleport to banker (city) +# default: 0.25 +AiPlayerbot.ProbTeleToBankers = 0.25 + +# How far random bots are teleported after death +AiPlayerbot.RandomBotTeleportDistance = 100 + +# Level diff between random bots and nearby creatures for random teleports +AiPlayerbot.RandomBotTeleLowerLevel = 3 +AiPlayerbot.RandomBotTeleHigherLevel = 1 + +# +# +# +#################################################################################################### + +#################################################################################################### +# BATTLEGROUNDS & ARENAS & PVP +# +# + +# Enable BG/Arena for random Bots +AiPlayerbot.RandomBotJoinBG = 1 + +# Enable Auto join BG - bots randomly join WSG and 2v2 Arena if server is not lagging +AiPlayerbot.RandomBotAutoJoinBG = 0 + +# Random bot arena team count +AiPlayerbot.RandomBotArenaTeamCount = 20 + +# Delete all random bot arena teams +AiPlayerbot.DeleteRandomBotArenaTeams = 0 + +# PvP Restricted Zones (bots don't pvp) +AiPlayerbot.PvpProhibitedZoneIds = "2255,656,2361,2362,2363,976,35,2268,3425,392,541,1446,3828,3712,3738,3565,3539,3623,4152,3988,4658,4284,4418,4436,4275,4323,4395,3703" # 33(stranglethorn vale),440(tanaris) + +# PvP Restricted Areas (bots don't pvp) +AiPlayerbot.PvpProhibitedAreaIds = "976,35,392" + +# +# +# +#################################################################################################### + +#################################################################################################### +# INTERVALS +# +# + +AiPlayerbot.RandomBotUpdateInterval = 20 +AiPlayerbot.RandomBotCountChangeMinInterval = 1800 +AiPlayerbot.RandomBotCountChangeMaxInterval = 7200 +AiPlayerbot.MinRandomBotInWorldTime = 3600 +AiPlayerbot.MaxRandomBotInWorldTime = 43200 +AiPlayerbot.MinRandomBotRandomizeTime = 302400 +AiPlayerbot.MaxRandomBotRandomizeTime = 1209600 +AiPlayerbot.RandomBotsPerInterval = 500 +AiPlayerbot.MinRandomBotReviveTime = 60 +AiPlayerbot.MaxRandomBotReviveTime = 300 +AiPlayerbot.MinRandomBotTeleportInterval = 3600 +AiPlayerbot.MaxRandomBotTeleportInterval = 18000 +AiPlayerbot.RandomBotInWorldWithRotationDisabled = 31104000 + +# +# +# +#################################################################################################### + +#################################################################################################### +# DEFAULT TALENT SPEC +# +# + # AiPlayerbot.RandomClassSpecProb.. # The probability to choose the spec # AiPlayerbot.RandomClassSpecIndex.. # The spec index in PremadeSpec -# Warrior + +# +# +# +#################################################################################################### + +#################################################################################################### +# WARRIOR +# +# + AiPlayerbot.RandomClassSpecProb.1.0 = 20 AiPlayerbot.RandomClassSpecIndex.1.0 = 0 AiPlayerbot.RandomClassSpecProb.1.1 = 40 AiPlayerbot.RandomClassSpecIndex.1.1 = 1 AiPlayerbot.RandomClassSpecProb.1.2 = 40 AiPlayerbot.RandomClassSpecIndex.1.2 = 2 -# Paladin + +# +# +# +#################################################################################################### + +#################################################################################################### +# PALADIN +# +# + AiPlayerbot.RandomClassSpecProb.2.0 = 30 AiPlayerbot.RandomClassSpecIndex.2.0 = 0 AiPlayerbot.RandomClassSpecProb.2.1 = 40 AiPlayerbot.RandomClassSpecIndex.2.1 = 1 AiPlayerbot.RandomClassSpecProb.2.2 = 30 AiPlayerbot.RandomClassSpecIndex.2.2 = 2 -# Hunter + +# +# +# +#################################################################################################### + +#################################################################################################### +# HUNTER +# +# + AiPlayerbot.RandomClassSpecProb.3.0 = 33 AiPlayerbot.RandomClassSpecIndex.3.0 = 0 AiPlayerbot.RandomClassSpecProb.3.1 = 33 AiPlayerbot.RandomClassSpecIndex.3.1 = 1 AiPlayerbot.RandomClassSpecProb.3.2 = 33 AiPlayerbot.RandomClassSpecIndex.3.2 = 2 -# Rogue + +# +# +# +#################################################################################################### + +#################################################################################################### +# ROGUE +# +# + AiPlayerbot.RandomClassSpecProb.4.0 = 45 AiPlayerbot.RandomClassSpecIndex.4.0 = 0 AiPlayerbot.RandomClassSpecProb.4.1 = 45 AiPlayerbot.RandomClassSpecIndex.4.1 = 1 AiPlayerbot.RandomClassSpecProb.4.2 = 10 AiPlayerbot.RandomClassSpecIndex.4.2 = 2 -# Priest + +# +# +# +#################################################################################################### + +#################################################################################################### +# PRIEST +# +# + AiPlayerbot.RandomClassSpecProb.5.0 = 40 AiPlayerbot.RandomClassSpecIndex.5.0 = 0 AiPlayerbot.RandomClassSpecProb.5.1 = 35 AiPlayerbot.RandomClassSpecIndex.5.1 = 1 AiPlayerbot.RandomClassSpecProb.5.2 = 25 AiPlayerbot.RandomClassSpecIndex.5.2 = 2 -# DeathKnight + +# +# +# +#################################################################################################### + +#################################################################################################### +# DEATHKNIGHT +# +# + AiPlayerbot.RandomClassSpecProb.6.0 = 30 AiPlayerbot.RandomClassSpecIndex.6.0 = 0 AiPlayerbot.RandomClassSpecProb.6.1 = 40 AiPlayerbot.RandomClassSpecIndex.6.1 = 1 AiPlayerbot.RandomClassSpecProb.6.2 = 30 AiPlayerbot.RandomClassSpecIndex.6.2 = 2 -# Shaman + +# +# +# +#################################################################################################### + +#################################################################################################### +# SHAMAN +# +# + AiPlayerbot.RandomClassSpecProb.7.0 = 33 AiPlayerbot.RandomClassSpecIndex.7.0 = 0 AiPlayerbot.RandomClassSpecProb.7.1 = 33 AiPlayerbot.RandomClassSpecIndex.7.1 = 1 AiPlayerbot.RandomClassSpecProb.7.2 = 33 AiPlayerbot.RandomClassSpecIndex.7.2 = 2 -# Mage + +# +# +# +#################################################################################################### + +#################################################################################################### +# MAGE +# +# + AiPlayerbot.RandomClassSpecProb.8.0 = 30 AiPlayerbot.RandomClassSpecIndex.8.0 = 0 AiPlayerbot.RandomClassSpecProb.8.1 = 30 AiPlayerbot.RandomClassSpecIndex.8.1 = 1 AiPlayerbot.RandomClassSpecProb.8.2 = 40 AiPlayerbot.RandomClassSpecIndex.8.2 = 2 -# Warlock + +# +# +# +#################################################################################################### + +#################################################################################################### +# WARLOCK +# +# + AiPlayerbot.RandomClassSpecProb.9.0 = 40 AiPlayerbot.RandomClassSpecIndex.9.0 = 0 AiPlayerbot.RandomClassSpecProb.9.1 = 40 AiPlayerbot.RandomClassSpecIndex.9.1 = 1 AiPlayerbot.RandomClassSpecProb.9.2 = 20 AiPlayerbot.RandomClassSpecIndex.9.2 = 2 -# Druid + +# +# +# +#################################################################################################### + +#################################################################################################### +# DRUID +# +# + AiPlayerbot.RandomClassSpecProb.11.0 = 20 AiPlayerbot.RandomClassSpecIndex.11.0 = 0 AiPlayerbot.RandomClassSpecProb.11.1 = 40 @@ -689,6 +1244,17 @@ AiPlayerbot.RandomClassSpecIndex.11.1 = 1 AiPlayerbot.RandomClassSpecProb.11.2 = 40 AiPlayerbot.RandomClassSpecIndex.11.2 = 2 +# +# +# +################################################################################################### + +################################################################################################### +################################################################################################### +################################################################################################### +################################################################################################### +################################################################################################### + ############################################## # Deprecated (temporary) # ############################################## @@ -756,12 +1322,3 @@ AiPlayerbot.TargetPosRecalcDistance = 0.1 # Allow bots to be summoned near innkeepers AiPlayerbot.SummonAtInnkeepersEnabled = 1 - -################################################################################## -# # -# Logging Stuff # -# # -################################################################################## - -Appender.Playerbots=2,5,0,Playerbots.log,w -Logger.playerbots=5,Console Playerbots \ No newline at end of file From 9fa3fafb641b9557171ab4aee732bd2cf8a08697 Mon Sep 17 00:00:00 2001 From: Caffarius Date: Fri, 12 Jul 2024 13:10:46 -0400 Subject: [PATCH 27/51] Enable Compilation on More Platforms Solves the "fatal error: no member named 'find_if' in namespace 'std'" compiler error experienced by certain environments. --- src/Helpers.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Helpers.h b/src/Helpers.h index b2471c71..2d9e5454 100644 --- a/src/Helpers.h +++ b/src/Helpers.h @@ -15,6 +15,7 @@ #include #include #include +#include void split(std::vector& dest, std::string const str, char const* delim) { From 83ae7a7bd547ab571449a654b47e60fa6bf9e8c1 Mon Sep 17 00:00:00 2001 From: Ben Wagner Date: Fri, 12 Jul 2024 23:46:58 +0200 Subject: [PATCH 28/51] fixed: Bots are now able to join LFG - Missing worker activation implemented --- src/RandomPlayerbotMgr.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/RandomPlayerbotMgr.cpp b/src/RandomPlayerbotMgr.cpp index 334b6499..ae9a0c60 100644 --- a/src/RandomPlayerbotMgr.cpp +++ b/src/RandomPlayerbotMgr.cpp @@ -384,6 +384,12 @@ void RandomPlayerbotMgr::UpdateAIInternal(uint32 elapsed, bool /*minimal*/) activateCheckBgQueueThread(); } + if (sPlayerbotAIConfig->randomBotJoinLfg/* && !players.empty()*/) + { + if (time(nullptr) > (LfgCheckTimer + 30)) + activateCheckLfgQueueThread(); + } + uint32 updateBots = sPlayerbotAIConfig->randomBotsPerInterval * onlineBotFocus / 100; uint32 maxNewBots = onlineBotCount < maxAllowedBotCount ? maxAllowedBotCount - onlineBotCount : 0; uint32 loginBots = std::min(sPlayerbotAIConfig->randomBotsPerInterval - updateBots, maxNewBots); From 06ca0e14e5086ad4abff6abe58656f9fae3737af Mon Sep 17 00:00:00 2001 From: Ben Wagner Date: Sat, 13 Jul 2024 00:24:04 +0200 Subject: [PATCH 29/51] fixed: Warcraft Instant Messenger is causing massive spam by sending bots WIM-specific commands such as handshakes which can not be processed by the bot. --- src/PlayerbotAI.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/PlayerbotAI.cpp b/src/PlayerbotAI.cpp index a6903f18..6996d460 100644 --- a/src/PlayerbotAI.cpp +++ b/src/PlayerbotAI.cpp @@ -352,10 +352,16 @@ void PlayerbotAI::UpdateAIInternal([[maybe_unused]] uint32 elapsed, bool minimal Player* owner = holder.GetOwner(); if (!helper.ParseChatCommand(command, owner) && holder.GetType() == CHAT_MSG_WHISPER) { - std::ostringstream out; - out << "Unknown command " << command; - TellMaster(out); - helper.ParseChatCommand("help"); + // To prevent spam caused by WIM + if (!(command.rfind("WIM", 0) == 0) && + !(command.rfind("QHpr", 0) == 0) + ) + { + std::ostringstream out; + out << "Unknown command " << command; + TellMaster(out); + helper.ParseChatCommand("help"); + } } chatCommands.pop(); From 3881d7054b6e28250b46683b8fc8172bdd56c808 Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Tue, 9 Jul 2024 23:09:21 +0800 Subject: [PATCH 30/51] [Crash fix] Fix crash caused by duplicate login --- src/PlayerbotMgr.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/PlayerbotMgr.cpp b/src/PlayerbotMgr.cpp index bd004267..1de95c56 100644 --- a/src/PlayerbotMgr.cpp +++ b/src/PlayerbotMgr.cpp @@ -74,6 +74,12 @@ void PlayerbotHolder::AddPlayerBot(ObjectGuid playerGuid, uint32 masterAccountId void PlayerbotHolder::HandlePlayerBotLoginCallback(PlayerbotLoginQueryHolder const& holder) { + // has bot already been added? + Player* loginBot = ObjectAccessor::FindConnectedPlayer(holder.GetGuid()); + if (loginBot && loginBot->IsInWorld()) { + return; + } + uint32 botAccountId = holder.GetAccountId(); WorldSession* botSession = new WorldSession(botAccountId, "", nullptr, SEC_PLAYER, EXPANSION_WRATH_OF_THE_LICH_KING, time_t(0), LOCALE_enUS, 0, false, false, 0, true); From 80b7f18841b91df6d8c759957a1fc3f842222c6b Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Thu, 11 Jul 2024 11:28:01 +0800 Subject: [PATCH 31/51] [Misc] Cat druid equip score calculation --- src/PlayerbotFactory.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/PlayerbotFactory.cpp b/src/PlayerbotFactory.cpp index 82ad1279..d9f29740 100644 --- a/src/PlayerbotFactory.cpp +++ b/src/PlayerbotFactory.cpp @@ -3821,6 +3821,7 @@ float PlayerbotFactory::CalculateItemScore(uint32 item_id, Player* bot) score += (agility + strength + intellect + spirit + stamina + defense + dodge + parry + block + resilience + hit + crit + haste + expertise + attack_power + mana_regeneration + spell_power + armor_penetration + spell_penetration + armor + rangeDps + meleeDps) * 0.001; + // todo: remove duplicate code if (cls == CLASS_HUNTER) { // AGILITY only score += agility * 2.5 + attack_power + armor_penetration * 2 + rangeDps * 5 + hit * 2.5 + crit * 2 + haste * 2.5 + intellect; @@ -3840,7 +3841,7 @@ float PlayerbotFactory::CalculateItemScore(uint32 item_id, Player* bot) ) { // HEALER score += intellect * 0.5 + spirit * 0.5 + spell_power + mana_regeneration * 0.5 + crit * 0.5 + haste * 1 + rangeDps; - } else if (cls == CLASS_ROGUE) { + } else if (cls == CLASS_ROGUE || (cls == CLASS_DRUID && tab == 2 && !PlayerbotAI::IsTank(bot))) { // AGILITY mainly (STRENGTH also) score += agility * 2 + strength + attack_power + armor_penetration * 1 + meleeDps * 5 + hit * 2 + crit * 1.5 + haste * 1.5 + expertise * 2.5; } else if ((cls == CLASS_PALADIN && tab == 2) || // retribution @@ -4242,6 +4243,7 @@ float PlayerbotFactory::CalculateEnchantScore(uint32 enchant_id, Player* bot) float score = (agility + strength + intellect + spirit + stamina + defense + dodge + parry + block + resilience + hit + crit + haste + expertise + attack_power + mana_regeneration + spell_power + armor_penetration + spell_penetration + armor + dps) * 0.001; + // todo: remove duplicate code if (cls == CLASS_HUNTER) { // AGILITY only score += agility * 2.5 + attack_power + armor_penetration * 2 + dps * 5 + hit * 2.5 + crit * 2 + haste * 2.5 + intellect; @@ -4261,7 +4263,7 @@ float PlayerbotFactory::CalculateEnchantScore(uint32 enchant_id, Player* bot) ) { // HEALER score += intellect * 0.5 + spirit * 0.5 + spell_power + mana_regeneration * 0.5 + crit * 0.5 + haste * 1; - } else if (cls == CLASS_ROGUE) { + } else if (cls == CLASS_ROGUE || (cls == CLASS_DRUID && tab == 2 && !PlayerbotAI::IsTank(bot))) { // AGILITY mainly (STRENGTH also) score += agility * 2 + strength + attack_power + armor_penetration * 1 + dps * 5 + hit * 2 + crit * 1.5 + haste * 1.5 + expertise * 2.5; } else if ((cls == CLASS_PALADIN && tab == 2) || // retribution @@ -4521,6 +4523,7 @@ float PlayerbotFactory::CalculateSpellScore(uint32 spell_id, Player* bot, uint32 } } float score = 0; + // todo: remove duplicate code if (cls == CLASS_HUNTER) { // AGILITY only score += agility * 2.5 + attack_power + armor_penetration * 2 + rangeDps * 5 + hit * 2.5 + crit * 2 + haste * 2.5 + intellect; @@ -4540,7 +4543,7 @@ float PlayerbotFactory::CalculateSpellScore(uint32 spell_id, Player* bot, uint32 ) { // HEALER score += intellect * 0.5 + spirit * 0.5 + spell_power + mana_regeneration * 0.5 + crit * 0.5 + haste * 1 + rangeDps; - } else if (cls == CLASS_ROGUE) { + } else if (cls == CLASS_ROGUE || (cls == CLASS_DRUID && tab == 2 && !PlayerbotAI::IsTank(bot))) { // AGILITY mainly (STRENGTH also) score += agility * 2 + strength + attack_power + armor_penetration * 1 + meleeDps * 5 + hit * 2 + crit * 1.5 + haste * 1.5 + expertise * 2.5; } else if ((cls == CLASS_PALADIN && tab == 2) || // retribution From 53c4198afd0310916ba30dccdc32615c07efa8f8 Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Thu, 11 Jul 2024 11:28:57 +0800 Subject: [PATCH 32/51] [Attack target] Cancel mount aura and remove within dist check --- src/strategy/actions/AttackAction.cpp | 2 +- src/strategy/values/AttackersValue.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/strategy/actions/AttackAction.cpp b/src/strategy/actions/AttackAction.cpp index f0d85a8c..1ba9f4b5 100644 --- a/src/strategy/actions/AttackAction.cpp +++ b/src/strategy/actions/AttackAction.cpp @@ -95,7 +95,7 @@ bool AttackAction::Attack(Unit* target, bool with_pet /*true*/) return false; } - if (bot->IsMounted() && bot->IsWithinLOSInMap(target) && sServerFacade->GetDistance2d(bot, target) < 40.0f) + if (bot->IsMounted() && bot->IsWithinLOSInMap(target)) { WorldPacket emptyPacket; bot->GetSession()->HandleCancelMountAuraOpcode(emptyPacket); diff --git a/src/strategy/values/AttackersValue.cpp b/src/strategy/values/AttackersValue.cpp index cae2223a..177ff89f 100644 --- a/src/strategy/values/AttackersValue.cpp +++ b/src/strategy/values/AttackersValue.cpp @@ -172,7 +172,7 @@ bool AttackersValue::IsPossibleTarget(Unit* attacker, Player* bot, float range) // (inCannon || !attacker->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE)) && attacker->CanSeeOrDetect(bot) && // !(attacker->HasUnitState(UNIT_STATE_STUNNED) && botAI->HasAura("shackle undead", attacker)) && !((attacker->IsPolymorphed() || botAI->HasAura("sap", attacker) || /*attacker->IsCharmed() ||*/ attacker->isFeared()) && !rti) && /*!sServerFacade->IsInRoots(attacker) &&*/ - !attacker->IsFriendlyTo(bot) && bot->IsWithinDistInMap(attacker, range) && + !attacker->IsFriendlyTo(bot) && !attacker->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION) && // !(attacker->GetGUID().IsPet() && enemy) && !(attacker->GetCreatureType() == CREATURE_TYPE_CRITTER && !attacker->IsInCombat()) && From c362630ce6c75380c6440ecc9bbbf4cbd38873b8 Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Thu, 11 Jul 2024 11:29:34 +0800 Subject: [PATCH 33/51] [Class spell] Reduce reach spell relevance --- src/strategy/generic/CombatStrategy.cpp | 62 +++++++++++------------ src/strategy/values/PartyMemberToDispel.h | 2 +- 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/src/strategy/generic/CombatStrategy.cpp b/src/strategy/generic/CombatStrategy.cpp index c9e3a95c..b77277fd 100644 --- a/src/strategy/generic/CombatStrategy.cpp +++ b/src/strategy/generic/CombatStrategy.cpp @@ -8,7 +8,7 @@ void CombatStrategy::InitTriggers(std::vector &triggers) { - triggers.push_back(new TriggerNode("enemy out of spell", NextAction::array(0, new NextAction("reach spell", ACTION_MOVE + 11), nullptr))); + triggers.push_back(new TriggerNode("enemy out of spell", NextAction::array(0, new NextAction("reach spell", ACTION_HIGH), nullptr))); triggers.push_back(new TriggerNode("invalid target", NextAction::array(0, new NextAction("drop target", 100), nullptr))); triggers.push_back(new TriggerNode("mounted", NextAction::array(0, new NextAction("check mount state", 54), nullptr))); // triggers.push_back(new TriggerNode("out of react range", NextAction::array(0, new NextAction("flee to master", 55), nullptr))); @@ -24,44 +24,44 @@ AvoidAoeStrategy::AvoidAoeStrategy(PlayerbotAI* botAI) : Strategy(botAI) } -class AvoidAoeStrategyMultiplier : public Multiplier -{ -public: - AvoidAoeStrategyMultiplier(PlayerbotAI* botAI) : Multiplier(botAI, "run away on area debuff") {} +// class AvoidAoeStrategyMultiplier : public Multiplier +// { +// public: +// AvoidAoeStrategyMultiplier(PlayerbotAI* botAI) : Multiplier(botAI, "run away on area debuff") {} -public: - virtual float GetValue(Action* action); +// public: +// virtual float GetValue(Action* action); -private: -}; +// private: +// }; -float AvoidAoeStrategyMultiplier::GetValue(Action* action) -{ - if (!action) - return 1.0f; +// float AvoidAoeStrategyMultiplier::GetValue(Action* action) +// { +// if (!action) +// return 1.0f; - std::string name = action->getName(); - if (name == "follow" || name == "co" || name == "nc" || name == "drop target") - return 1.0f; +// std::string name = action->getName(); +// if (name == "follow" || name == "co" || name == "nc" || name == "drop target") +// return 1.0f; - uint32 spellId = AI_VALUE2(uint32, "spell id", name); - const SpellInfo* const pSpellInfo = sSpellMgr->GetSpellInfo(spellId); - if (!pSpellInfo) return 1.0f; +// uint32 spellId = AI_VALUE2(uint32, "spell id", name); +// const SpellInfo* const pSpellInfo = sSpellMgr->GetSpellInfo(spellId); +// if (!pSpellInfo) return 1.0f; - if (spellId && pSpellInfo->Targets & TARGET_FLAG_DEST_LOCATION) - return 1.0f; - else if (spellId && pSpellInfo->Targets & TARGET_FLAG_SOURCE_LOCATION) - return 1.0f; +// if (spellId && pSpellInfo->Targets & TARGET_FLAG_DEST_LOCATION) +// return 1.0f; +// else if (spellId && pSpellInfo->Targets & TARGET_FLAG_SOURCE_LOCATION) +// return 1.0f; - uint32 castTime = pSpellInfo->CalcCastTime(bot); +// uint32 castTime = pSpellInfo->CalcCastTime(bot); - if (AI_VALUE2(bool, "has area debuff", "self target") && spellId && castTime > 0) - { - return 0.0f; - } +// if (AI_VALUE2(bool, "has area debuff", "self target") && spellId && castTime > 0) +// { +// return 0.0f; +// } - return 1.0f; -} +// return 1.0f; +// } NextAction** AvoidAoeStrategy::getDefaultActions() { @@ -86,6 +86,6 @@ void AvoidAoeStrategy::InitMultipliers(std::vector& multipliers) NextAction** CombatFormationStrategy::getDefaultActions() { return NextAction::array(0, - new NextAction("combat formation move", ACTION_EMERGENCY), + new NextAction("combat formation move", ACTION_NORMAL), nullptr); } diff --git a/src/strategy/values/PartyMemberToDispel.h b/src/strategy/values/PartyMemberToDispel.h index 36197ea9..ac2c441f 100644 --- a/src/strategy/values/PartyMemberToDispel.h +++ b/src/strategy/values/PartyMemberToDispel.h @@ -14,7 +14,7 @@ class Unit; class PartyMemberToDispel : public PartyMemberValue, public Qualified { public: - PartyMemberToDispel(PlayerbotAI* botAI, std::string const name = "party member to dispel") : PartyMemberValue(botAI, name, 2 * 1000), Qualified() { } + PartyMemberToDispel(PlayerbotAI* botAI, std::string const name = "party member to dispel") : PartyMemberValue(botAI, name, 1000), Qualified() { } protected: Unit* Calculate() override; From adc9c96b29298cec44a0904903ca41393ec6ece0 Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Thu, 11 Jul 2024 12:32:22 +0800 Subject: [PATCH 34/51] [Configuration] Gear quality on random bots --- conf/playerbots.conf.dist | 8 ++++++++ src/PlayerbotAIConfig.cpp | 5 ++++- src/PlayerbotAIConfig.h | 2 ++ src/PlayerbotFactory.cpp | 5 ++++- 4 files changed, 18 insertions(+), 2 deletions(-) diff --git a/conf/playerbots.conf.dist b/conf/playerbots.conf.dist index be3ab4ba..7f6a7668 100644 --- a/conf/playerbots.conf.dist +++ b/conf/playerbots.conf.dist @@ -891,6 +891,14 @@ AiPlayerbot.AutoPickTalents = 1 # # +# Equips quality limitation for random bots (1 = normal, 2 = uncommon, 3 = rare, 4 = epic, 5 = legendary) +# default: 3 (rare) +AiPlayerbot.RandomGearQualityLimit = 3 + +# Equips gear score limitation for random bots (0 = no limit) +# default: 0 (no limit) +AiPlayerbot.RandomGearScoreLimit = 0 + # Change random bot has lower gear AiPlayerbot.RandomGearLoweringChance = 0 diff --git a/src/PlayerbotAIConfig.cpp b/src/PlayerbotAIConfig.cpp index 4d6a2a50..66148931 100644 --- a/src/PlayerbotAIConfig.cpp +++ b/src/PlayerbotAIConfig.cpp @@ -95,7 +95,10 @@ bool PlayerbotAIConfig::Initialize() autoAvoidAoe = sConfigMgr->GetOption("AiPlayerbot.AutoAvoidAoe", true); tellWhenAvoidAoe = sConfigMgr->GetOption("AiPlayerbot.TellWhenAvoidAoe", true); - randomGearLoweringChance = sConfigMgr->GetOption("AiPlayerbot.RandomGearLoweringChance", 0.15f); + randomGearLoweringChance = sConfigMgr->GetOption("AiPlayerbot.RandomGearLoweringChance", 0.0f); + randomGearQualityLimit = sConfigMgr->GetOption("AiPlayerbot.AutoGearQualityLimit", 3); + randomGearScoreLimit = sConfigMgr->GetOption("AiPlayerbot.AutoGearScoreLimit", 0); + randomBotMaxLevelChance = sConfigMgr->GetOption("AiPlayerbot.RandomBotMaxLevelChance", 0.15f); randomBotRpgChance = sConfigMgr->GetOption("AiPlayerbot.RandomBotRpgChance", 0.20f); diff --git a/src/PlayerbotAIConfig.h b/src/PlayerbotAIConfig.h index d347b87e..7bbc0512 100644 --- a/src/PlayerbotAIConfig.h +++ b/src/PlayerbotAIConfig.h @@ -79,6 +79,8 @@ class PlayerbotAIConfig std::vector randomBotQuestIds; uint32 randomBotTeleportDistance; float randomGearLoweringChance; + int32 randomGearQualityLimit; + int32 randomGearScoreLimit; float randomBotMaxLevelChance; float randomBotRpgChance; uint32 minRandomBots, maxRandomBots; diff --git a/src/PlayerbotFactory.cpp b/src/PlayerbotFactory.cpp index d9f29740..8f95d9a7 100644 --- a/src/PlayerbotFactory.cpp +++ b/src/PlayerbotFactory.cpp @@ -149,7 +149,10 @@ void PlayerbotFactory::Prepare() { if (!itemQuality) { - itemQuality = ITEM_QUALITY_RARE; + uint32 gs = sPlayerbotAIConfig->randomGearScoreLimit == 0 ? 0 : + PlayerbotFactory::CalcMixedGearScore(sPlayerbotAIConfig->randomGearScoreLimit, sPlayerbotAIConfig->randomGearQualityLimit); + itemQuality = sPlayerbotAIConfig->randomGearScoreLimit; + gearScoreLimit = gs; } if (bot->isDead()) From 487796e7e1d0eb0586049ff0f167c8f1bd90d441 Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Thu, 11 Jul 2024 13:14:17 +0800 Subject: [PATCH 35/51] [Initialization] Fix random bot gear quality --- src/PlayerbotAIConfig.cpp | 4 ++-- src/PlayerbotFactory.cpp | 44 +++++++++++++++++++-------------------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/PlayerbotAIConfig.cpp b/src/PlayerbotAIConfig.cpp index 66148931..48783180 100644 --- a/src/PlayerbotAIConfig.cpp +++ b/src/PlayerbotAIConfig.cpp @@ -96,8 +96,8 @@ bool PlayerbotAIConfig::Initialize() tellWhenAvoidAoe = sConfigMgr->GetOption("AiPlayerbot.TellWhenAvoidAoe", true); randomGearLoweringChance = sConfigMgr->GetOption("AiPlayerbot.RandomGearLoweringChance", 0.0f); - randomGearQualityLimit = sConfigMgr->GetOption("AiPlayerbot.AutoGearQualityLimit", 3); - randomGearScoreLimit = sConfigMgr->GetOption("AiPlayerbot.AutoGearScoreLimit", 0); + randomGearQualityLimit = sConfigMgr->GetOption("AiPlayerbot.RandomGearQualityLimit", 3); + randomGearScoreLimit = sConfigMgr->GetOption("AiPlayerbot.RandomGearScoreLimit", 0); randomBotMaxLevelChance = sConfigMgr->GetOption("AiPlayerbot.RandomBotMaxLevelChance", 0.15f); randomBotRpgChance = sConfigMgr->GetOption("AiPlayerbot.RandomBotRpgChance", 0.20f); diff --git a/src/PlayerbotFactory.cpp b/src/PlayerbotFactory.cpp index 8f95d9a7..c74b722d 100644 --- a/src/PlayerbotFactory.cpp +++ b/src/PlayerbotFactory.cpp @@ -151,7 +151,7 @@ void PlayerbotFactory::Prepare() { uint32 gs = sPlayerbotAIConfig->randomGearScoreLimit == 0 ? 0 : PlayerbotFactory::CalcMixedGearScore(sPlayerbotAIConfig->randomGearScoreLimit, sPlayerbotAIConfig->randomGearQualityLimit); - itemQuality = sPlayerbotAIConfig->randomGearScoreLimit; + itemQuality = sPlayerbotAIConfig->randomGearQualityLimit; gearScoreLimit = gs; } @@ -3827,7 +3827,7 @@ float PlayerbotFactory::CalculateItemScore(uint32 item_id, Player* bot) // todo: remove duplicate code if (cls == CLASS_HUNTER) { // AGILITY only - score += agility * 2.5 + attack_power + armor_penetration * 2 + rangeDps * 5 + hit * 2.5 + crit * 2 + haste * 2.5 + intellect; + score += agility * 2.5 + attack_power + armor_penetration * 2 + rangeDps * 5 + hit * 2 + crit * 2 + haste * 2 + intellect; } else if (cls == CLASS_WARLOCK || cls == CLASS_MAGE || (cls == CLASS_PRIEST && tab == 2) || // shadow @@ -3836,7 +3836,7 @@ float PlayerbotFactory::CalculateItemScore(uint32 item_id, Player* bot) ) { // SPELL DPS score += intellect * 0.5 + spirit * 0.5 + spell_power + spell_penetration - + hit * 1.2 + crit * 0.7 + haste * 1 + rangeDps; + + hit * 1 + crit * 0.7 + haste * 1 + rangeDps; } else if ((cls == CLASS_PALADIN && tab == 0) || // holy (cls == CLASS_PRIEST && tab != 2) || // discipline / holy (cls == CLASS_SHAMAN && tab == 2) || // heal @@ -3846,7 +3846,7 @@ float PlayerbotFactory::CalculateItemScore(uint32 item_id, Player* bot) score += intellect * 0.5 + spirit * 0.5 + spell_power + mana_regeneration * 0.5 + crit * 0.5 + haste * 1 + rangeDps; } else if (cls == CLASS_ROGUE || (cls == CLASS_DRUID && tab == 2 && !PlayerbotAI::IsTank(bot))) { // AGILITY mainly (STRENGTH also) - score += agility * 2 + strength + attack_power + armor_penetration * 1 + meleeDps * 5 + hit * 2 + crit * 1.5 + haste * 1.5 + expertise * 2.5; + score += agility * 2 + strength + attack_power + armor_penetration * 1 + meleeDps * 5 + hit * 1.5 + crit * 1.5 + haste * 1.5 + expertise * 2.5; } else if ((cls == CLASS_PALADIN && tab == 2) || // retribution (cls == CLASS_WARRIOR && tab != 2) || // arm / fury (cls == CLASS_DEATH_KNIGHT && tab != 0) // ice / unholy @@ -3856,20 +3856,20 @@ float PlayerbotFactory::CalculateItemScore(uint32 item_id, Player* bot) } else if ((cls == CLASS_SHAMAN && tab == 1)) { // enhancement // STRENGTH mainly (AGILITY, INTELLECT also) score += strength * 1 + agility * 1.5 + intellect * 1.5 + attack_power + spell_power * 1.5 + armor_penetration * 0.5 + meleeDps * 5 - + hit * 2 + crit * 1.5 + haste * 1.5 + expertise * 2; + + hit * 1.5 + crit * 1.5 + haste * 1.5 + expertise * 2; } else if ((cls == CLASS_WARRIOR && tab == 2) || (cls == CLASS_PALADIN && tab == 1)) { // TANK WITH SHIELD score += strength * 1 + agility * 2 + attack_power * 0.2 + defense * 2.5 + parry * 2 + dodge * 2 + resilience * 2 + block * 2 + armor * 0.3 + stamina * 3 - + hit * 1 + crit * 0.2 + haste * 0.5 + expertise * 3; + + hit * 0.5 + crit * 0.2 + haste * 0.5 + expertise * 3; } else if (cls == CLASS_DEATH_KNIGHT && tab == 0){ // BLOOD DK TANK score += strength * 1 + agility * 2 + attack_power * 0.2 + defense * 3.5 + parry * 2 + dodge * 2 + resilience * 2 + armor * 0.3 + stamina * 2.5 - + hit * 2 + crit * 0.5 + haste * 0.5 + expertise * 3.5; + + hit * 0.5 + crit * 0.5 + haste * 0.5 + expertise * 3.5; } else { - // BEAR DRUID TANK (AND FERAL DRUID...?) + // BEAR DRUID TANK score += agility * 1.5 + strength * 1 + attack_power * 0.5 + armor_penetration * 0.5 + meleeDps * 2 + defense * 0.25 + dodge * 0.25 + armor * 0.3 + stamina * 1.5 + hit * 1 + crit * 1 + haste * 0.5 + expertise * 3; @@ -4249,7 +4249,7 @@ float PlayerbotFactory::CalculateEnchantScore(uint32 enchant_id, Player* bot) // todo: remove duplicate code if (cls == CLASS_HUNTER) { // AGILITY only - score += agility * 2.5 + attack_power + armor_penetration * 2 + dps * 5 + hit * 2.5 + crit * 2 + haste * 2.5 + intellect; + score += agility * 2.5 + attack_power + armor_penetration * 2 + dps * 5 + hit * 2 + crit * 2 + haste * 2.5 + intellect; } else if (cls == CLASS_WARLOCK || cls == CLASS_MAGE || (cls == CLASS_PRIEST && tab == 2) || // shadow @@ -4258,7 +4258,7 @@ float PlayerbotFactory::CalculateEnchantScore(uint32 enchant_id, Player* bot) ) { // SPELL DPS score += intellect * 0.5 + spirit * 0.5 + spell_power + spell_penetration - + hit * 1.2 + crit * 0.7 + haste * 1; + + hit * 1 + crit * 0.7 + haste * 1; } else if ((cls == CLASS_PALADIN && tab == 0) || // holy (cls == CLASS_PRIEST && tab != 2) || // discipline / holy (cls == CLASS_SHAMAN && tab == 2) || // heal @@ -4268,7 +4268,7 @@ float PlayerbotFactory::CalculateEnchantScore(uint32 enchant_id, Player* bot) score += intellect * 0.5 + spirit * 0.5 + spell_power + mana_regeneration * 0.5 + crit * 0.5 + haste * 1; } else if (cls == CLASS_ROGUE || (cls == CLASS_DRUID && tab == 2 && !PlayerbotAI::IsTank(bot))) { // AGILITY mainly (STRENGTH also) - score += agility * 2 + strength + attack_power + armor_penetration * 1 + dps * 5 + hit * 2 + crit * 1.5 + haste * 1.5 + expertise * 2.5; + score += agility * 2 + strength + attack_power + armor_penetration * 1 + dps * 5 + hit * 1.5 + crit * 1.5 + haste * 1.5 + expertise * 2.5; } else if ((cls == CLASS_PALADIN && tab == 2) || // retribution (cls == CLASS_WARRIOR && tab != 2) || // arm / fury (cls == CLASS_DEATH_KNIGHT && tab != 0) // ice / unholy @@ -4278,20 +4278,20 @@ float PlayerbotFactory::CalculateEnchantScore(uint32 enchant_id, Player* bot) } else if ((cls == CLASS_SHAMAN && tab == 1)) { // enhancement // STRENGTH mainly (AGILITY, INTELLECT also) score += strength * 1 + agility * 1.5 + intellect * 1.5 + attack_power + spell_power * 1.5 + armor_penetration * 0.5 + dps * 5 - + hit * 2 + crit * 1.5 + haste * 1.5 + expertise * 2; + + hit * 1.5 + crit * 1.5 + haste * 1.5 + expertise * 2; } else if ((cls == CLASS_WARRIOR && tab == 2) || (cls == CLASS_PALADIN && tab == 1)) { // TANK WITH SHIELD score += strength * 1 + agility * 2 + attack_power * 0.2 + defense * 2.5 + parry * 2 + dodge * 2 + resilience * 2 + block * 2 + armor * 0.3 + stamina * 3 - + hit * 1 + crit * 0.2 + haste * 0.5 + expertise * 3; + + hit * 0.5 + crit * 0.2 + haste * 0.5 + expertise * 3; } else if (cls == CLASS_DEATH_KNIGHT && tab == 0){ // BLOOD DK TANK score += strength * 1 + agility * 2 + attack_power * 0.2 + defense * 3.5 + parry * 2 + dodge * 2 + resilience * 2 + armor * 0.3 + stamina * 2.5 - + hit * 2 + crit * 0.5 + haste * 0.5 + expertise * 3.5; + + hit * 0.5 + crit * 0.5 + haste * 0.5 + expertise * 3.5; } else { - // BEAR DRUID TANK (AND FERAL DRUID...?) + // BEAR DRUID TANK score += agility * 1.5 + strength * 1 + attack_power * 0.5 + armor_penetration * 0.5 + dps * 2 + defense * 0.25 + dodge * 0.25 + armor * 0.3 + stamina * 1.5 + hit * 1 + crit * 1 + haste * 0.5 + expertise * 3; @@ -4529,7 +4529,7 @@ float PlayerbotFactory::CalculateSpellScore(uint32 spell_id, Player* bot, uint32 // todo: remove duplicate code if (cls == CLASS_HUNTER) { // AGILITY only - score += agility * 2.5 + attack_power + armor_penetration * 2 + rangeDps * 5 + hit * 2.5 + crit * 2 + haste * 2.5 + intellect; + score += agility * 2.5 + attack_power + armor_penetration * 2 + rangeDps * 5 + hit * 2 + crit * 2 + haste * 2.5 + intellect; } else if (cls == CLASS_WARLOCK || cls == CLASS_MAGE || (cls == CLASS_PRIEST && tab == 2) || // shadow @@ -4538,7 +4538,7 @@ float PlayerbotFactory::CalculateSpellScore(uint32 spell_id, Player* bot, uint32 ) { // SPELL DPS score += intellect * 0.5 + spirit * 0.5 + spell_power + spell_penetration - + hit * 1.2 + crit * 0.7 + haste * 1 + rangeDps; + + hit * 1 + crit * 0.7 + haste * 1 + rangeDps; } else if ((cls == CLASS_PALADIN && tab == 0) || // holy (cls == CLASS_PRIEST && tab != 2) || // discipline / holy (cls == CLASS_SHAMAN && tab == 2) || // heal @@ -4548,7 +4548,7 @@ float PlayerbotFactory::CalculateSpellScore(uint32 spell_id, Player* bot, uint32 score += intellect * 0.5 + spirit * 0.5 + spell_power + mana_regeneration * 0.5 + crit * 0.5 + haste * 1 + rangeDps; } else if (cls == CLASS_ROGUE || (cls == CLASS_DRUID && tab == 2 && !PlayerbotAI::IsTank(bot))) { // AGILITY mainly (STRENGTH also) - score += agility * 2 + strength + attack_power + armor_penetration * 1 + meleeDps * 5 + hit * 2 + crit * 1.5 + haste * 1.5 + expertise * 2.5; + score += agility * 2 + strength + attack_power + armor_penetration * 1 + meleeDps * 5 + hit * 1.5 + crit * 1.5 + haste * 1.5 + expertise * 2.5; } else if ((cls == CLASS_PALADIN && tab == 2) || // retribution (cls == CLASS_WARRIOR && tab != 2) || // arm / fury (cls == CLASS_DEATH_KNIGHT && tab != 0) // ice / unholy @@ -4558,20 +4558,20 @@ float PlayerbotFactory::CalculateSpellScore(uint32 spell_id, Player* bot, uint32 } else if ((cls == CLASS_SHAMAN && tab == 1)) { // enhancement // STRENGTH mainly (AGILITY, INTELLECT also) score += strength * 1 + agility * 1.5 + intellect * 1.5 + attack_power + spell_power * 1.5 + armor_penetration * 0.5 + meleeDps * 5 - + hit * 2 + crit * 1.5 + haste * 1.5 + expertise * 2; + + hit * 1.5 + crit * 1.5 + haste * 1.5 + expertise * 2; } else if ((cls == CLASS_WARRIOR && tab == 2) || (cls == CLASS_PALADIN && tab == 1)) { // TANK WITH SHIELD score += strength * 1 + agility * 2 + attack_power * 0.2 + defense * 2.5 + parry * 2 + dodge * 2 + resilience * 2 + block * 2 + armor * 0.3 + stamina * 3 - + hit * 1 + crit * 0.2 + haste * 0.5 + expertise * 3; + + hit * 0.5 + crit * 0.2 + haste * 0.5 + expertise * 3; } else if (cls == CLASS_DEATH_KNIGHT && tab == 0){ // BLOOD DK TANK score += strength * 1 + agility * 2 + attack_power * 0.2 + defense * 3.5 + parry * 2 + dodge * 2 + resilience * 2 + armor * 0.3 + stamina * 2.5 - + hit * 2 + crit * 0.5 + haste * 0.5 + expertise * 3.5; + + hit * 0.5 + crit * 0.5 + haste * 0.5 + expertise * 3.5; } else { - // BEAR DRUID TANK (AND FERAL DRUID...?) + // BEAR DRUID TANK score += agility * 1.5 + strength * 1 + attack_power * 0.5 + armor_penetration * 0.5 + meleeDps * 2 + defense * 0.25 + dodge * 0.25 + armor * 0.3 + stamina * 1.5 + hit * 1 + crit * 1 + haste * 0.5 + expertise * 3; From 68565dd813ea95e7e6704cd899ab0aecf7ab9b74 Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Thu, 11 Jul 2024 15:48:23 +0800 Subject: [PATCH 36/51] [Class spell] Shaman elemental mastery --- src/strategy/shaman/CasterShamanStrategy.cpp | 1 + src/strategy/shaman/ShamanActions.h | 6 ++++++ src/strategy/shaman/ShamanAiObjectContext.cpp | 4 ++++ src/strategy/shaman/ShamanTriggers.h | 6 ++++++ 4 files changed, 17 insertions(+) diff --git a/src/strategy/shaman/CasterShamanStrategy.cpp b/src/strategy/shaman/CasterShamanStrategy.cpp index aa1fef0a..61a31b32 100644 --- a/src/strategy/shaman/CasterShamanStrategy.cpp +++ b/src/strategy/shaman/CasterShamanStrategy.cpp @@ -52,6 +52,7 @@ void CasterShamanStrategy::InitTriggers(std::vector& triggers) triggers.push_back(new TriggerNode("shaman weapon", NextAction::array(0, new NextAction("flametongue weapon", 23.0f), nullptr))); // triggers.push_back(new TriggerNode("searing totem", NextAction::array(0, new NextAction("searing totem", 19.0f), nullptr))); triggers.push_back(new TriggerNode("flame shock", NextAction::array(0, new NextAction("flame shock", 20.0f), nullptr))); + triggers.push_back(new TriggerNode("elemental mastery", NextAction::array(0, new NextAction("elemental mastery", 27.0f), nullptr))); // triggers.push_back(new TriggerNode("frost shock snare", NextAction::array(0, new NextAction("frost shock", 21.0f), nullptr))); triggers.push_back(new TriggerNode( "no fire totem", diff --git a/src/strategy/shaman/ShamanActions.h b/src/strategy/shaman/ShamanActions.h index c9467e49..2db469fb 100644 --- a/src/strategy/shaman/ShamanActions.h +++ b/src/strategy/shaman/ShamanActions.h @@ -350,6 +350,12 @@ class CastBloodlustAction : public CastBuffSpellAction CastBloodlustAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "bloodlust") { } }; +class CastElementalMasteryAction : public CastBuffSpellAction +{ + public: + CastElementalMasteryAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "elemental mastery") { } +}; + class CastWindShearOnEnemyHealerAction : public CastSpellOnEnemyHealerAction { public: diff --git a/src/strategy/shaman/ShamanAiObjectContext.cpp b/src/strategy/shaman/ShamanAiObjectContext.cpp index c40f4957..819cf3d1 100644 --- a/src/strategy/shaman/ShamanAiObjectContext.cpp +++ b/src/strategy/shaman/ShamanAiObjectContext.cpp @@ -96,6 +96,7 @@ class ShamanATriggerFactoryInternal : public NamedObjectContext creators["frost shock snare"] = &ShamanATriggerFactoryInternal::frost_shock_snare; creators["heroism"] = &ShamanATriggerFactoryInternal::heroism; creators["bloodlust"] = &ShamanATriggerFactoryInternal::bloodlust; + creators["elemental mastery"] = &ShamanATriggerFactoryInternal::elemental_mastery; creators["wind shear on enemy healer"] = &ShamanATriggerFactoryInternal::wind_shear_on_enemy_healer; creators["cure poison"] = &ShamanATriggerFactoryInternal::cure_poison; creators["party member cure poison"] = &ShamanATriggerFactoryInternal::party_member_cure_poison; @@ -114,6 +115,7 @@ class ShamanATriggerFactoryInternal : public NamedObjectContext static Trigger* maelstrom_weapon(PlayerbotAI* botAI) { return new MaelstromWeaponTrigger(botAI); } static Trigger* heroism(PlayerbotAI* botAI) { return new HeroismTrigger(botAI); } static Trigger* bloodlust(PlayerbotAI* botAI) { return new BloodlustTrigger(botAI); } + static Trigger* elemental_mastery(PlayerbotAI* botAI) { return new ElementalMasteryTrigger(botAI); } static Trigger* party_member_cleanse_disease(PlayerbotAI* botAI) { return new PartyMemberCleanseSpiritDiseaseTrigger(botAI); } static Trigger* party_member_cleanse_curse(PlayerbotAI* botAI) { return new PartyMemberCleanseSpiritCurseTrigger(botAI); } static Trigger* party_member_cleanse_poison(PlayerbotAI* botAI) { return new PartyMemberCleanseSpiritPoisonTrigger(botAI); } @@ -206,6 +208,7 @@ class ShamanAiObjectContextInternal : public NamedObjectContext creators["thunderstorm"] = &ShamanAiObjectContextInternal::thunderstorm; creators["heroism"] = &ShamanAiObjectContextInternal::heroism; creators["bloodlust"] = &ShamanAiObjectContextInternal::bloodlust; + creators["elemental mastery"] = &ShamanAiObjectContextInternal::elemental_mastery; // creators["cure disease"] = &ShamanAiObjectContextInternal::cure_disease; // creators["cure disease on party"] = &ShamanAiObjectContextInternal::cure_disease_on_party; // creators["cure poison"] = &ShamanAiObjectContextInternal::cure_poison; @@ -222,6 +225,7 @@ class ShamanAiObjectContextInternal : public NamedObjectContext private: static Action* heroism(PlayerbotAI* botAI) { return new CastHeroismAction(botAI); } static Action* bloodlust(PlayerbotAI* botAI) { return new CastBloodlustAction(botAI); } + static Action* elemental_mastery(PlayerbotAI* botAI) { return new CastElementalMasteryAction(botAI); } static Action* thunderstorm(PlayerbotAI* botAI) { return new CastThunderstormAction(botAI); } static Action* lightning_bolt(PlayerbotAI* botAI) { return new CastLightningBoltAction(botAI); } static Action* chain_lightning(PlayerbotAI* botAI) { return new CastChainLightningAction(botAI); } diff --git a/src/strategy/shaman/ShamanTriggers.h b/src/strategy/shaman/ShamanTriggers.h index 54395b4b..d85f0888 100644 --- a/src/strategy/shaman/ShamanTriggers.h +++ b/src/strategy/shaman/ShamanTriggers.h @@ -201,6 +201,12 @@ class BloodlustTrigger : public BoostTrigger BloodlustTrigger(PlayerbotAI* botAI) : BoostTrigger(botAI, "bloodlust") { } }; +class ElementalMasteryTrigger : public BoostTrigger +{ + public: + ElementalMasteryTrigger(PlayerbotAI* botAI) : BoostTrigger(botAI, "elemental mastery") { } +}; + class MaelstromWeaponTrigger : public HasAuraStackTrigger { public: From 8358ea71549b8ae4caea6aafcca84cf93929f780 Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Thu, 11 Jul 2024 15:48:44 +0800 Subject: [PATCH 37/51] [Configuration] Talents for fire mage and resto shaman --- conf/playerbots.conf.dist | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/conf/playerbots.conf.dist b/conf/playerbots.conf.dist index 7f6a7668..e9e53a62 100644 --- a/conf/playerbots.conf.dist +++ b/conf/playerbots.conf.dist @@ -696,8 +696,8 @@ AiPlayerbot.PremadeSpecLink.7.1.60 = -30205033005001333031131131051 AiPlayerbot.PremadeSpecLink.7.1.80 = 053030052-30205033005021333031131131051 AiPlayerbot.PremadeSpecName.7.2 = resto pve AiPlayerbot.PremadeSpecGlyph.7.2 = 41517,43385,41527,43386,44923,45775 -AiPlayerbot.PremadeSpecLink.7.2.60 = --50005301335310501002331241 -AiPlayerbot.PremadeSpecLink.7.2.80 = -00505031-50005331335310501022331251 +AiPlayerbot.PremadeSpecLink.7.2.60 = --50005301235310501102321251 +AiPlayerbot.PremadeSpecLink.7.2.80 = -00502033-50005331335310501122331251 # # @@ -715,8 +715,8 @@ AiPlayerbot.PremadeSpecLink.8.0.60 = 23000503110033014032310150532 AiPlayerbot.PremadeSpecLink.8.0.80 = 23000523310033015032310250532-03-203203001 AiPlayerbot.PremadeSpecName.8.1 = fire pve AiPlayerbot.PremadeSpecGlyph.8.1 = 42739,43339,45737,43364,44920,42751 -AiPlayerbot.PremadeSpecLink.8.1.60 = -0055030012303330053120300351 -AiPlayerbot.PremadeSpecLink.8.1.80 = 23000503310003-0055030012303330053120300351 +AiPlayerbot.PremadeSpecLink.8.1.60 = -0055030011302231053120321341 +AiPlayerbot.PremadeSpecLink.8.1.80 = 23000503110003-0055030011302331053120321351 AiPlayerbot.PremadeSpecName.8.2 = frost pve AiPlayerbot.PremadeSpecGlyph.8.2 = 42742,43339,50045,43364,43361,42751 AiPlayerbot.PremadeSpecLink.8.2.60 = --3533103310203100232102231151 From 05e799cff40af8ee5196d4c35e13e86c027547a7 Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Thu, 11 Jul 2024 21:54:08 +0800 Subject: [PATCH 38/51] [Class spell] Improve warrior, dk, paladin --- src/strategy/deathknight/DKAiObjectContext.cpp | 4 ++-- src/strategy/deathknight/DKTriggers.cpp | 2 +- src/strategy/deathknight/DKTriggers.h | 4 ++-- src/strategy/deathknight/GenericDKStrategy.cpp | 2 +- src/strategy/paladin/PaladinActions.cpp | 2 +- src/strategy/paladin/TankPaladinStrategy.cpp | 3 +++ src/strategy/triggers/GenericTriggers.cpp | 5 +++++ src/strategy/triggers/GenericTriggers.h | 8 ++++++++ src/strategy/triggers/TriggerContext.h | 2 ++ src/strategy/warrior/ArmsWarriorStrategy.cpp | 5 ++++- src/strategy/warrior/FuryWarriorStrategy.cpp | 2 +- src/strategy/warrior/TankWarriorStrategy.cpp | 2 ++ src/strategy/warrior/WarriorAiObjectContext.cpp | 2 +- 13 files changed, 33 insertions(+), 10 deletions(-) diff --git a/src/strategy/deathknight/DKAiObjectContext.cpp b/src/strategy/deathknight/DKAiObjectContext.cpp index 99883cbc..e7641e71 100644 --- a/src/strategy/deathknight/DKAiObjectContext.cpp +++ b/src/strategy/deathknight/DKAiObjectContext.cpp @@ -67,7 +67,7 @@ class DeathKnightTriggerFactoryInternal : public NamedObjectContext DeathKnightTriggerFactoryInternal() { creators["bone shield"] = &DeathKnightTriggerFactoryInternal::bone_shield; - creators["pestilence"] = &DeathKnightTriggerFactoryInternal::pestilence; + creators["pestilence glyph"] = &DeathKnightTriggerFactoryInternal::pestilence_glyph; creators["blood strike"] = &DeathKnightTriggerFactoryInternal::blood_strike; creators["plague strike"] = &DeathKnightTriggerFactoryInternal::plague_strike; creators["plague strike on attacker"] = &DeathKnightTriggerFactoryInternal::plague_strike_on_attacker; @@ -94,7 +94,7 @@ class DeathKnightTriggerFactoryInternal : public NamedObjectContext private: static Trigger* bone_shield(PlayerbotAI* botAI) { return new BoneShieldTrigger(botAI); } - static Trigger* pestilence(PlayerbotAI* botAI) { return new PestilenceTrigger(botAI); } + static Trigger* pestilence_glyph(PlayerbotAI* botAI) { return new PestilenceGlyphTrigger(botAI); } static Trigger* blood_strike(PlayerbotAI* botAI) { return new BloodStrikeTrigger(botAI); } static Trigger* plague_strike(PlayerbotAI* botAI) { return new PlagueStrikeDebuffTrigger(botAI); } static Trigger* plague_strike_on_attacker(PlayerbotAI* botAI) { return new PlagueStrikeDebuffOnAttackerTrigger(botAI); } diff --git a/src/strategy/deathknight/DKTriggers.cpp b/src/strategy/deathknight/DKTriggers.cpp index 8eee1045..3f7f696e 100644 --- a/src/strategy/deathknight/DKTriggers.cpp +++ b/src/strategy/deathknight/DKTriggers.cpp @@ -14,7 +14,7 @@ bool DKPresenceTrigger::IsActive() return !botAI->HasAura("blood presence", target) && !botAI->HasAura("unholy presence", target) && !botAI->HasAura("frost presence", target); } -bool PestilenceTrigger::IsActive() { +bool PestilenceGlyphTrigger::IsActive() { if (!SpellTrigger::IsActive()) { return false; } diff --git a/src/strategy/deathknight/DKTriggers.h b/src/strategy/deathknight/DKTriggers.h index 08b91a82..f9dc88dc 100644 --- a/src/strategy/deathknight/DKTriggers.h +++ b/src/strategy/deathknight/DKTriggers.h @@ -71,10 +71,10 @@ class DeathCoilTrigger : public SpellCanBeCastTrigger DeathCoilTrigger(PlayerbotAI* botAI) : SpellCanBeCastTrigger(botAI, "death coil") { } }; -class PestilenceTrigger : public DebuffTrigger +class PestilenceGlyphTrigger : public SpellTrigger { public: - PestilenceTrigger(PlayerbotAI* botAI) : DebuffTrigger(botAI, "pestilence") { } + PestilenceGlyphTrigger(PlayerbotAI* botAI) : SpellTrigger(botAI, "pestilence") { } virtual bool IsActive() override; }; diff --git a/src/strategy/deathknight/GenericDKStrategy.cpp b/src/strategy/deathknight/GenericDKStrategy.cpp index 42c4ffa4..3e26cae2 100644 --- a/src/strategy/deathknight/GenericDKStrategy.cpp +++ b/src/strategy/deathknight/GenericDKStrategy.cpp @@ -192,5 +192,5 @@ void GenericDKStrategy::InitTriggers(std::vector& triggers) // triggers.push_back(new TriggerNode("light aoe", NextAction::array(0, // new NextAction("pestilence", ACTION_NORMAL + 4), // nullptr))); - triggers.push_back(new TriggerNode("pestilence", NextAction::array(0, new NextAction("pestilence", ACTION_HIGH + 9), NULL))); + triggers.push_back(new TriggerNode("pestilence glyph", NextAction::array(0, new NextAction("pestilence", ACTION_HIGH + 9), NULL))); } diff --git a/src/strategy/paladin/PaladinActions.cpp b/src/strategy/paladin/PaladinActions.cpp index b2291d3d..6a56478b 100644 --- a/src/strategy/paladin/PaladinActions.cpp +++ b/src/strategy/paladin/PaladinActions.cpp @@ -153,7 +153,7 @@ bool CastMeleeConsecrationAction::isUseful() { Unit* target = GetTarget(); // float dis = distance + CONTACT_DISTANCE; - return target && bot->IsWithinCombatRange(target, sPlayerbotAIConfig->meleeDistance); // sServerFacade->IsDistanceGreaterThan(AI_VALUE2(float, "distance", GetTargetName()), distance); + return target && bot->IsWithinMeleeRange(target); // sServerFacade->IsDistanceGreaterThan(AI_VALUE2(float, "distance", GetTargetName()), distance); } bool CastDivineSacrificeAction::isUseful() diff --git a/src/strategy/paladin/TankPaladinStrategy.cpp b/src/strategy/paladin/TankPaladinStrategy.cpp index bbbeac00..cb1ca7b5 100644 --- a/src/strategy/paladin/TankPaladinStrategy.cpp +++ b/src/strategy/paladin/TankPaladinStrategy.cpp @@ -94,6 +94,9 @@ void TankPaladinStrategy::InitTriggers(std::vector& triggers) triggers.push_back(new TriggerNode( "medium group heal occasion", NextAction::array(0, new NextAction("divine sacrifice", ACTION_HIGH + 5), nullptr))); + triggers.push_back(new TriggerNode( + "enough mana", + NextAction::array(0, new NextAction("melee consecration", ACTION_HIGH + 4), nullptr))); triggers.push_back(new TriggerNode( "not facing target", NextAction::array(0, new NextAction("set facing", ACTION_NORMAL + 7), nullptr))); diff --git a/src/strategy/triggers/GenericTriggers.cpp b/src/strategy/triggers/GenericTriggers.cpp index 6d2a9d0a..dff60e0d 100644 --- a/src/strategy/triggers/GenericTriggers.cpp +++ b/src/strategy/triggers/GenericTriggers.cpp @@ -64,6 +64,11 @@ bool AlmostFullManaTrigger::IsActive() return AI_VALUE2(bool, "has mana", "self target") && AI_VALUE2(uint8, "mana", "self target") > 85; } +bool EnoughManaTrigger::IsActive() +{ + return AI_VALUE2(bool, "has mana", "self target") && AI_VALUE2(uint8, "mana", "self target") > 65; +} + bool RageAvailable::IsActive() { return AI_VALUE2(uint8, "rage", "self target") >= amount; diff --git a/src/strategy/triggers/GenericTriggers.h b/src/strategy/triggers/GenericTriggers.h index 2731f9ef..4f5cee27 100644 --- a/src/strategy/triggers/GenericTriggers.h +++ b/src/strategy/triggers/GenericTriggers.h @@ -30,6 +30,14 @@ class HighManaTrigger : public Trigger bool IsActive() override; }; +class EnoughManaTrigger : public Trigger +{ + public: + EnoughManaTrigger(PlayerbotAI* botAI) : Trigger(botAI, "enough mana") { } + + bool IsActive() override; +}; + class AlmostFullManaTrigger : public Trigger { public: diff --git a/src/strategy/triggers/TriggerContext.h b/src/strategy/triggers/TriggerContext.h index 34ef3480..df04b983 100644 --- a/src/strategy/triggers/TriggerContext.h +++ b/src/strategy/triggers/TriggerContext.h @@ -45,6 +45,7 @@ class TriggerContext : public NamedObjectContext creators["medium mana"] = &TriggerContext::MediumMana; creators["high mana"] = &TriggerContext::HighMana; creators["almost full mana"] = &TriggerContext::AlmostFullMana; + creators["enough mana"] = &TriggerContext::EnoughMana; creators["party member critical health"] = &TriggerContext::PartyMemberCriticalHealth; creators["party member low health"] = &TriggerContext::PartyMemberLowHealth; @@ -253,6 +254,7 @@ class TriggerContext : public NamedObjectContext static Trigger* MediumMana(PlayerbotAI* botAI) { return new MediumManaTrigger(botAI); } static Trigger* HighMana(PlayerbotAI* botAI) { return new HighManaTrigger(botAI); } static Trigger* AlmostFullMana(PlayerbotAI* botAI) { return new AlmostFullManaTrigger(botAI); } + static Trigger* EnoughMana(PlayerbotAI* botAI) { return new EnoughManaTrigger(botAI); } static Trigger* LightRageAvailable(PlayerbotAI* botAI) { return new LightRageAvailableTrigger(botAI); } static Trigger* MediumRageAvailable(PlayerbotAI* botAI) { return new MediumRageAvailableTrigger(botAI); } static Trigger* HighRageAvailable(PlayerbotAI* botAI) { return new HighRageAvailableTrigger(botAI); } diff --git a/src/strategy/warrior/ArmsWarriorStrategy.cpp b/src/strategy/warrior/ArmsWarriorStrategy.cpp index c6314bae..ef27b800 100644 --- a/src/strategy/warrior/ArmsWarriorStrategy.cpp +++ b/src/strategy/warrior/ArmsWarriorStrategy.cpp @@ -32,7 +32,9 @@ ArmsWarriorStrategy::ArmsWarriorStrategy(PlayerbotAI* botAI) : GenericWarriorStr NextAction** ArmsWarriorStrategy::getDefaultActions() { - return NextAction::array(0, new NextAction("heroic strike", ACTION_DEFAULT), nullptr); + return NextAction::array(0, + new NextAction("bladestorm", ACTION_DEFAULT + 0.1f), + new NextAction("melee", ACTION_DEFAULT), nullptr); } void ArmsWarriorStrategy::InitTriggers(std::vector& triggers) @@ -56,4 +58,5 @@ void ArmsWarriorStrategy::InitTriggers(std::vector& triggers) triggers.push_back(new TriggerNode("rend", NextAction::array(0, new NextAction("rend", ACTION_HIGH + 5), nullptr))); triggers.push_back(new TriggerNode("rend on attacker", NextAction::array(0, new NextAction("rend on attacker", ACTION_HIGH + 5), nullptr))); triggers.push_back(new TriggerNode("critical health", NextAction::array(0, new NextAction("intimidating shout", ACTION_EMERGENCY), nullptr))); + triggers.push_back(new TriggerNode("medium rage available", NextAction::array(0, new NextAction("thunder clap", ACTION_HIGH + 1), nullptr))); } diff --git a/src/strategy/warrior/FuryWarriorStrategy.cpp b/src/strategy/warrior/FuryWarriorStrategy.cpp index 60cece7b..57cf118e 100644 --- a/src/strategy/warrior/FuryWarriorStrategy.cpp +++ b/src/strategy/warrior/FuryWarriorStrategy.cpp @@ -61,7 +61,7 @@ void FuryWarriorStrategy::InitTriggers(std::vector &triggers) triggers.push_back(new TriggerNode("bloodthirst", NextAction::array(0, new NextAction("bloodthirst", ACTION_HIGH + 7), nullptr))); triggers.push_back(new TriggerNode("instant slam", NextAction::array(0, new NextAction("slam", ACTION_HIGH + 5), nullptr))); triggers.push_back(new TriggerNode("bloodrage", NextAction::array(0, new NextAction("bloodrage", ACTION_HIGH + 2), nullptr))); - triggers.push_back(new TriggerNode("high rage available", NextAction::array(0, new NextAction("heroic strike", ACTION_HIGH + 1), NULL))); + triggers.push_back(new TriggerNode("medium rage available", NextAction::array(0, new NextAction("heroic strike", ACTION_HIGH + 1), NULL))); // triggers.push_back(new TriggerNode("berserker rage", NextAction::array(0, new NextAction("berserker rage", ACTION_HIGH + 2), nullptr))); // triggers.push_back(new TriggerNode("light aoe", NextAction::array(0, // new NextAction("whirlwind", ACTION_HIGH + 2), diff --git a/src/strategy/warrior/TankWarriorStrategy.cpp b/src/strategy/warrior/TankWarriorStrategy.cpp index 42f71fa2..bbdfb740 100644 --- a/src/strategy/warrior/TankWarriorStrategy.cpp +++ b/src/strategy/warrior/TankWarriorStrategy.cpp @@ -88,4 +88,6 @@ void TankWarriorStrategy::InitTriggers(std::vector& triggers) triggers.push_back(new TriggerNode("rend", NextAction::array(0, new NextAction("rend", ACTION_NORMAL + 1), nullptr))); triggers.push_back(new TriggerNode("rend on attacker", NextAction::array(0, new NextAction("rend on attacker", ACTION_NORMAL + 1), nullptr))); triggers.push_back(new TriggerNode("protect party member", NextAction::array(0, new NextAction("intervene", ACTION_EMERGENCY), nullptr))); + triggers.push_back(new TriggerNode("high rage available", NextAction::array(0, new NextAction("heroic strike", ACTION_HIGH + 1), nullptr))); + triggers.push_back(new TriggerNode("medium rage available", NextAction::array(0, new NextAction("thunder clap", ACTION_HIGH + 1), nullptr))); } diff --git a/src/strategy/warrior/WarriorAiObjectContext.cpp b/src/strategy/warrior/WarriorAiObjectContext.cpp index 90917300..1cabf441 100644 --- a/src/strategy/warrior/WarriorAiObjectContext.cpp +++ b/src/strategy/warrior/WarriorAiObjectContext.cpp @@ -117,7 +117,7 @@ class WarriorTriggerFactoryInternal : public NamedObjectContext static Trigger* SwordAndBoard(PlayerbotAI* botAI) { return new SwordAndBoardTrigger(botAI); } static Trigger* shield_bash_on_enemy_healer(PlayerbotAI* botAI) { return new ShieldBashInterruptEnemyHealerSpellTrigger(botAI); } - static Trigger* thunderclap_and_rage(PlayerbotAI* botAI) { return new TwoTriggers(botAI, "thunderclap", "light rage available"); } + static Trigger* thunderclap_and_rage(PlayerbotAI* botAI) { return new TwoTriggers(botAI, "thunder clap", "light rage available"); } static Trigger* intercept_can_cast(PlayerbotAI* botAI) { return new InterceptCanCastTrigger(botAI); } static Trigger* intercept_and_far_enemy(PlayerbotAI* botAI) { return new TwoTriggers(botAI, "enemy is out of melee", "intercept can cast"); } static Trigger* intercept_and_rage(PlayerbotAI* botAI) { return new TwoTriggers(botAI, "intercept and far enemy", "light rage available"); } From 2a542b13457c361905d44985fcd93cdc6458a73b Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Thu, 11 Jul 2024 21:54:22 +0800 Subject: [PATCH 39/51] [Configuration] Rogue glyphs --- conf/playerbots.conf.dist | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/conf/playerbots.conf.dist b/conf/playerbots.conf.dist index e9e53a62..d955b9c2 100644 --- a/conf/playerbots.conf.dist +++ b/conf/playerbots.conf.dist @@ -614,11 +614,11 @@ AiPlayerbot.PremadeSpecLink.3.2.80 = -005305101-5000032500033330522135301331 # AiPlayerbot.PremadeSpecName.4.0 = as pve -AiPlayerbot.PremadeSpecGlyph.4.0 = 45768,43379,45761,43380,43378,45767 +AiPlayerbot.PremadeSpecGlyph.4.0 = 45768,43379,45761,43380,43378,45766 AiPlayerbot.PremadeSpecLink.4.0.60 = 005323005350100520103331051 AiPlayerbot.PremadeSpecLink.4.0.80 = 005323005350100520103331051-005005005003-2 AiPlayerbot.PremadeSpecName.4.1 = combat pve -AiPlayerbot.PremadeSpecGlyph.4.1 = 45762,43379,45767,43380,43378,45766 +AiPlayerbot.PremadeSpecGlyph.4.1 = 42962,43379,45762,43380,43378,42969 AiPlayerbot.PremadeSpecLink.4.1.60 = -0252051000035015223100501251 AiPlayerbot.PremadeSpecLink.4.1.80 = 00532000523-0252051000035015223100501251 AiPlayerbot.PremadeSpecName.4.2 = subtlety pve From db1cfa6abc63db576bda65586a7364f778093417 Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Thu, 11 Jul 2024 23:01:25 +0800 Subject: [PATCH 40/51] [Random bots] Ensure teleport after randomize --- src/strategy/actions/ActionContext.h | 2 ++ src/strategy/actions/AutoLearnSpellAction.cpp | 13 ++++++++++++- src/strategy/actions/AutoLearnSpellAction.h | 8 ++++++++ src/strategy/actions/AutoTeleportForLevelAction.cpp | 13 ------------- src/strategy/actions/AutoTeleportForLevelAction.h | 2 -- src/strategy/generic/WorldPacketHandlerStrategy.cpp | 7 ++++--- 6 files changed, 26 insertions(+), 19 deletions(-) diff --git a/src/strategy/actions/ActionContext.h b/src/strategy/actions/ActionContext.h index f2c1062c..ea8b3362 100644 --- a/src/strategy/actions/ActionContext.h +++ b/src/strategy/actions/ActionContext.h @@ -152,6 +152,7 @@ class ActionContext : public NamedObjectContext creators["auto talents"] = &ActionContext::auto_talents; creators["auto learn spell"] = &ActionContext::auto_learn_spell; creators["auto teleport for level"] = &ActionContext::auto_teleport_for_level; + creators["auto upgrade equip"] = &ActionContext::auto_upgrade_equip; creators["xp gain"] = &ActionContext::xp_gain; creators["invite nearby"] = &ActionContext::invite_nearby; creators["invite guild"] = &ActionContext::invite_guild; @@ -319,6 +320,7 @@ class ActionContext : public NamedObjectContext static Action* auto_talents(PlayerbotAI* botAI) { return new AutoSetTalentsAction(botAI); } static Action* auto_learn_spell(PlayerbotAI* botAI) { return new AutoLearnSpellAction(botAI); } static Action* auto_teleport_for_level(PlayerbotAI* botAI) { return new AutoTeleportForLevelAction(botAI); } + static Action* auto_upgrade_equip(PlayerbotAI* botAI) { return new AutoUpgradeEquipAction(botAI); } static Action* xp_gain(PlayerbotAI* botAI) { return new XpGainAction(botAI); } static Action* invite_nearby(PlayerbotAI* botAI) { return new InviteNearbyToGroupAction(botAI); } static Action* invite_guild(PlayerbotAI* botAI) { return new InviteGuildToGroupAction(botAI); } diff --git a/src/strategy/actions/AutoLearnSpellAction.cpp b/src/strategy/actions/AutoLearnSpellAction.cpp index 3202eb96..d742d4ad 100644 --- a/src/strategy/actions/AutoLearnSpellAction.cpp +++ b/src/strategy/actions/AutoLearnSpellAction.cpp @@ -24,7 +24,6 @@ bool AutoLearnSpellAction::Execute(Event event) out << "."; botAI->TellMaster(out); } - return true; } @@ -181,3 +180,15 @@ void AutoLearnSpellAction::LearnSpell(uint32 spellId, std::ostringstream* out) } } } + +bool AutoUpgradeEquipAction::Execute(Event event) { + if (!sPlayerbotAIConfig->autoUpgradeEquip || !sRandomPlayerbotMgr->IsRandomBot(bot)) { + return false; + } + PlayerbotFactory factory(bot, bot->GetLevel(), ITEM_QUALITY_RARE); + if (!sPlayerbotAIConfig->equipmentPersistence || bot->GetLevel() < sPlayerbotAIConfig->equipmentPersistenceLevel) { + factory.InitEquipment(true); + } + factory.InitAmmo(); + return true; +} diff --git a/src/strategy/actions/AutoLearnSpellAction.h b/src/strategy/actions/AutoLearnSpellAction.h index 9e6267c3..1cefaf48 100644 --- a/src/strategy/actions/AutoLearnSpellAction.h +++ b/src/strategy/actions/AutoLearnSpellAction.h @@ -23,4 +23,12 @@ class AutoLearnSpellAction : public Action void LearnSpell(uint32 spellId, std::ostringstream* out); }; +class AutoUpgradeEquipAction : public Action +{ + public: + AutoUpgradeEquipAction(PlayerbotAI* botAI, std::string const name = "auto upgrade equip") : Action(botAI, name) { } + + bool Execute(Event event); +}; + #endif diff --git a/src/strategy/actions/AutoTeleportForLevelAction.cpp b/src/strategy/actions/AutoTeleportForLevelAction.cpp index 1ad4e0c4..0f4c8f63 100644 --- a/src/strategy/actions/AutoTeleportForLevelAction.cpp +++ b/src/strategy/actions/AutoTeleportForLevelAction.cpp @@ -6,8 +6,6 @@ #include "SharedDefines.h" bool AutoTeleportForLevelAction::Execute(Event event) { - AutoUpgradeEquip(); - if (!sPlayerbotAIConfig->autoTeleportForLevel || !sRandomPlayerbotMgr->IsRandomBot(bot)) { return false; } @@ -16,15 +14,4 @@ bool AutoTeleportForLevelAction::Execute(Event event) { } sRandomPlayerbotMgr->RandomTeleportForLevel(bot); return true; -} - -void AutoTeleportForLevelAction::AutoUpgradeEquip() { - if (!sPlayerbotAIConfig->autoUpgradeEquip || !sRandomPlayerbotMgr->IsRandomBot(bot)) { - return; - } - PlayerbotFactory factory(bot, bot->GetLevel(), ITEM_QUALITY_RARE); - if (!sPlayerbotAIConfig->equipmentPersistence || bot->GetLevel() < sPlayerbotAIConfig->equipmentPersistenceLevel) { - factory.InitEquipment(true); - } - factory.InitAmmo(); } \ No newline at end of file diff --git a/src/strategy/actions/AutoTeleportForLevelAction.h b/src/strategy/actions/AutoTeleportForLevelAction.h index c8397d53..ca13edf2 100644 --- a/src/strategy/actions/AutoTeleportForLevelAction.h +++ b/src/strategy/actions/AutoTeleportForLevelAction.h @@ -15,8 +15,6 @@ class AutoTeleportForLevelAction : public Action AutoTeleportForLevelAction(PlayerbotAI* botAI, std::string const name = "auto teleport for level") : Action(botAI, name) { } bool Execute(Event event); - private: - void AutoUpgradeEquip(); }; #endif diff --git a/src/strategy/generic/WorldPacketHandlerStrategy.cpp b/src/strategy/generic/WorldPacketHandlerStrategy.cpp index a5c1065d..2db5ed84 100644 --- a/src/strategy/generic/WorldPacketHandlerStrategy.cpp +++ b/src/strategy/generic/WorldPacketHandlerStrategy.cpp @@ -37,9 +37,10 @@ void WorldPacketHandlerStrategy::InitTriggers(std::vector& trigger triggers.push_back(new TriggerNode("bg status", NextAction::array(0, new NextAction("bg status", relevance), nullptr))); triggers.push_back(new TriggerNode("xpgain", NextAction::array(0, new NextAction("xp gain", relevance), nullptr))); triggers.push_back(new TriggerNode("levelup", NextAction::array(0, - new NextAction("auto talents", relevance), - new NextAction("auto learn spell", relevance), - new NextAction("auto teleport for level", relevance), + new NextAction("auto teleport for level", relevance + 3), + new NextAction("auto talents", relevance + 2), + new NextAction("auto learn spell", relevance + 1), + new NextAction("auto upgrade equip", relevance), nullptr))); // triggers.push_back(new TriggerNode("group destroyed", NextAction::array(0, new NextAction("reset botAI", relevance), nullptr))); triggers.push_back(new TriggerNode("questgiver quest details", NextAction::array(0, new NextAction("turn in query quest", relevance), nullptr))); From 266aa1ec888c9589d4d47cd57da7faa515e91898 Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Fri, 12 Jul 2024 00:26:42 +0800 Subject: [PATCH 41/51] [Warnings] Fix warnings --- src/strategy/actions/BattleGroundTactics.cpp | 7 +++++-- src/strategy/actions/BuyAction.cpp | 2 ++ src/strategy/actions/CastCustomSpellAction.cpp | 4 ++-- src/strategy/actions/CustomStrategyEditAction.cpp | 2 +- src/strategy/actions/RangeAction.cpp | 2 +- src/strategy/actions/TalkToQuestGiverAction.cpp | 4 ++++ src/strategy/actions/WhoAction.cpp | 4 ++-- src/strategy/values/BudgetValues.cpp | 2 ++ src/strategy/values/ItemForSpellValue.cpp | 4 ++-- 9 files changed, 21 insertions(+), 10 deletions(-) diff --git a/src/strategy/actions/BattleGroundTactics.cpp b/src/strategy/actions/BattleGroundTactics.cpp index 80eff17b..a9e916d3 100644 --- a/src/strategy/actions/BattleGroundTactics.cpp +++ b/src/strategy/actions/BattleGroundTactics.cpp @@ -4115,7 +4115,8 @@ bool BGTactics::selectObjective(bool reset) } break; } - + default: + break; } return false; @@ -4503,7 +4504,7 @@ bool BGTactics::atFlag(std::vector const& vPaths, std::vectorisSpawned() || !go->GetGoState() == GO_STATE_READY) + if (!go->isSpawned() || go->GetGoState() != GO_STATE_READY) continue; if (!bot->CanUseBattlegroundObject(go) && bgType != BATTLEGROUND_WS) @@ -4644,6 +4645,8 @@ bool BGTactics::atFlag(std::vector const& vPaths, std::vectorFormatQuest(quest); @@ -257,6 +259,8 @@ bool TurnInQueryQuestAction::Execute(Event event) case QUEST_STATUS_REWARDED: out << "|cffff0000Rewarded|r"; break; + default: + break; } out << ": " << chat->FormatQuest(quest); diff --git a/src/strategy/actions/WhoAction.cpp b/src/strategy/actions/WhoAction.cpp index 76bfd608..d7b9f2bc 100644 --- a/src/strategy/actions/WhoAction.cpp +++ b/src/strategy/actions/WhoAction.cpp @@ -11,8 +11,8 @@ #ifndef WIN32 inline int strcmpi(char const* s1, char const* s2) { - for (; *s1 && *s2 && (toupper(*s1) == toupper(*s2)); ++s1, ++s2); - return *s1 - *s2; + for (; *s1 && *s2 && (toupper(*s1) == toupper(*s2)); ++s1, ++s2) {} + return *s1 - *s2; } #endif diff --git a/src/strategy/values/BudgetValues.cpp b/src/strategy/values/BudgetValues.cpp index b1045d1f..d9806087 100644 --- a/src/strategy/values/BudgetValues.cpp +++ b/src/strategy/values/BudgetValues.cpp @@ -180,6 +180,8 @@ uint32 MoneyNeededForValue::Calculate() case NeedMoneyFor::tradeskill: moneyWanted = (level * level * level); //Or level^3 (10s @ lvl10, 3g @ lvl30, 20g @ lvl60, 50g @ lvl80): Todo replace (Should be buyable reagents that combined allow crafting of usefull items) break; + default: + break; } return moneyWanted; diff --git a/src/strategy/values/ItemForSpellValue.cpp b/src/strategy/values/ItemForSpellValue.cpp index e52bbbf6..58c4fae1 100644 --- a/src/strategy/values/ItemForSpellValue.cpp +++ b/src/strategy/values/ItemForSpellValue.cpp @@ -8,8 +8,8 @@ #ifndef WIN32 inline int strcmpi(char const* s1, char const* s2) { - for (; *s1 && *s2 && (toupper(*s1) == toupper(*s2)); ++s1, ++s2); - return *s1 - *s2; + for (; *s1 && *s2 && (toupper(*s1) == toupper(*s2)); ++s1, ++s2) {} + return *s1 - *s2; } #endif From 2d1fc5b932908aa768c1efde3dd710ee12642051 Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Sat, 13 Jul 2024 11:39:06 +0800 Subject: [PATCH 42/51] [Warnings] Fix --- src/strategy/actions/ChooseTravelTargetAction.cpp | 10 +++++----- src/strategy/actions/LootRollAction.cpp | 2 ++ 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/strategy/actions/ChooseTravelTargetAction.cpp b/src/strategy/actions/ChooseTravelTargetAction.cpp index f6b37494..614a8b73 100644 --- a/src/strategy/actions/ChooseTravelTargetAction.cpp +++ b/src/strategy/actions/ChooseTravelTargetAction.cpp @@ -46,19 +46,19 @@ void ChooseTravelTargetAction::getNewTarget(TravelTarget* newTarget, TravelTarge foundTarget = SetNpcFlagTarget(newTarget, { UNIT_NPC_FLAG_BANKER,UNIT_NPC_FLAG_BATTLEMASTER,UNIT_NPC_FLAG_AUCTIONEER }); //Grind for money - if (!foundTarget && AI_VALUE(bool, "should get money")) + if (!foundTarget && AI_VALUE(bool, "should get money")) { if (urand(1, 100) > 66) { foundTarget = SetQuestTarget(newTarget, true); //Turn in quests for money. if (!foundTarget) foundTarget = SetQuestTarget(newTarget); //Do low level quests - } - else if (urand(1, 100) > 50) + } else if (urand(1, 100) > 50) { foundTarget = SetGrindTarget(newTarget); //Go grind mobs for money - else + } else { foundTarget = SetNewQuestTarget(newTarget); //Find a low level quest to do - + } + } //Continue if (!foundTarget && urand(1, 100) > 10) //90% chance diff --git a/src/strategy/actions/LootRollAction.cpp b/src/strategy/actions/LootRollAction.cpp index 9f5db411..5b4835b4 100644 --- a/src/strategy/actions/LootRollAction.cpp +++ b/src/strategy/actions/LootRollAction.cpp @@ -147,6 +147,8 @@ RollVote LootRollAction::CalculateRollVote(ItemTemplate const* proto) case ITEM_USAGE_VENDOR: needVote = GREED; break; + default: + break; } return StoreLootAction::IsLootAllowed(proto->ItemId, GET_PLAYERBOT_AI(bot)) ? needVote : PASS; From 49db219b4a9f4c60b1e6d93f7c5b9a0f7d402ca9 Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Sat, 13 Jul 2024 21:30:15 +0800 Subject: [PATCH 43/51] [Configuration] Reorder config file --- conf/playerbots.conf.dist | 955 +++++++++++++++++++------------------- 1 file changed, 472 insertions(+), 483 deletions(-) diff --git a/conf/playerbots.conf.dist b/conf/playerbots.conf.dist index d955b9c2..443f6cdc 100644 --- a/conf/playerbots.conf.dist +++ b/conf/playerbots.conf.dist @@ -4,12 +4,7 @@ ################################################################################################### # SECTION INDEX -# -# PLAYERBOT SYSTEM SETTINGS -# DATABASE & CONNECTIONS -# DEBUG -# CHAT SETTINGS -# LOGS +# GENERAL SETTINGS # PLAYERBOT SETTINGS # GENERAL # SUMMON OPTIONS @@ -22,6 +17,16 @@ # COMBAT # CHEATS # SPELLS +# PLAYERBOT RNDBOT SPECIFIC SETTINGS +# GENERAL +# LEVELS +# GEAR +# QUESTS +# SPELLS +# STRATEGIES +# TELEPORTS +# BATTLEGROUND & ARENA & PVP +# INTERVALS # PREMADE SPECS # INFORMATION # WARRIOR @@ -34,29 +39,22 @@ # MAGE # WARLOCK # DRUID -# PLAYERBOT RNDBOT SPECIFIC SETTINGS -# GENERAL -# ACCOUNT DELETE RNDBOTS -# LEVELS -# GEAR -# QUESTS -# PROFESSIONS -# SPELLS -# STRATEGIES -# TELEPORTS -# BATTLEGROUND & ARENA & PVP -# INTERVALS -# DEFAULT TALENT SPEC -# WARRIOR -# PALADIN -# HUNTER -# ROGUE -# PRIEST -# DEATHKNIGHT -# SHAMAN -# MAGE -# WARLOCK -# DRUID +# RANDOM BOT DEFAULT TALENT SPEC +# WARRIOR +# PALADIN +# HUNTER +# ROGUE +# PRIEST +# DEATHKNIGHT +# SHAMAN +# MAGE +# WARLOCK +# DRUID +# PLAYERBOT SYSTEM SETTINGS +# DATABASE & CONNECTIONS +# DEBUG +# CHAT SETTINGS +# LOGS # DEPRECIATED (TEMPORARY) # # @@ -65,116 +63,31 @@ # ################################################################################################### +################################################################################################### + ################################### # # -# PLAYERBOT SYSTEM SETTINGS # +# GENERAL SETTINGS # # # ################################### #################################################################################################### -# DATABASE & CONNECTIONS -# -# -# PlayerbotsDatabaseInfo -# Description: Database connection settings for the playerbots server. -# Example: "hostname;port;username;password;database" -# ".;somenumber;username;password;database" - (Use named pipes on Windows -# "enable-named-pipe" to [mysqld] -# section my.ini) -# ".;/path/to/unix_socket;username;password;database" - (use Unix sockets on -# Unix/Linux) -# Default: "127.0.0.1;3306;acore;acore;acore_playerbots" - (PlayerbotDatabaseInfo) +# Enable or disable AI Playerbot +AiPlayerbot.Enabled = 1 -PlayerbotsDatabaseInfo = "127.0.0.1;3306;acore;acore;acore_playerbots" +# Enable random bot system +AiPlayerbot.RandomBotAutologin = 1 -# -# PlayerbotsDatabase.WorkerThreads -# Description: The amount of worker threads spawned to handle asynchronous (delayed) MySQL -# statements. Each worker thread is mirrored with its own connection to the -# MySQL server and their own thread on the MySQL server. -# Default: 1 - (PlayerbotsDatabase.WorkerThreads) +# Random bot account +AiPlayerbot.RandomBotAccountCount = 200 -PlayerbotsDatabase.WorkerThreads = 1 +# Random bot count +AiPlayerbot.MinRandomBots = 50 +AiPlayerbot.MaxRandomBots = 50 -# -# PlayerbotsDatabase.SynchThreads -# Description: The amount of MySQL connections spawned to handle. -# Default: 1 - (PlayerbotDatabase.WorkerThreads) - -PlayerbotsDatabase.SynchThreads = 1 - -# Playerbot.Updates.EnableDatabases -# Description: Determined if updates system work with playerbot database. -# -# Default: 1 - (Enabled) -# 0 - (Disabled) - -Playerbots.Updates.EnableDatabases = 1 - -# Command server port, 0 - disabled -AiPlayerbot.CommandServerPort = 8888 - -# Diff with/without player in server. The server will tune bot activity to reach the desired server tick speed (in ms).# PLAYERBOT SYSTEM SETTINGS # -AiPlayerbot.EnablePrototypePerformanceDiff = 0 -AiPlayerbot.DiffWithPlayer = 100 -AiPlayerbot.DiffEmpty = 200 - -# -# -# -#################################################################################################### - -#################################################################################################### -# DEBUG SWITCHES -# -# - -AiPlayerbot.SpellDump = 0 -AiPlayerbot.LogInGroupOnly = 1 -AiPlayerbot.LogValuesPerTick = 0 -AiPlayerbot.RandomChangeMultiplier = 1 - -# Enables/Disables performance monitor -AiPlayerbot.PerfMonEnabled = 0 - -# -# -# -#################################################################################################### - -#################################################################################################### -# CHAT SETTINGS -# -# - -# Prefix for bot chat commands (e.g. follow, stay) -AiPlayerbot.CommandPrefix = "" - -# Separator for bot chat commands -AiPlayerbot.CommandSeparator = "\\\\" - -# -# -# -#################################################################################################### - -#################################################################################################### -# LOGS -# -# - -# Custom config to allow logfiles to be created. -# Example: AiPlayerbot.AllowedLogFiles = travelNodes.csv,travelPaths.csv,TravelNodeStore.h,bot_movement.csv,bot_location.csv -AiPlayerbot.AllowedLogFiles = "" - -Appender.Playerbots=2,5,0,Playerbots.log,w -Logger.playerbots=5,Console Playerbots - -# -# -# -#################################################################################################### +# Delete all random bot accounts (reset randombots) +AiPlayerbot.DeleteRandomBotAccounts = 0 ################################################################################################### @@ -191,9 +104,6 @@ Logger.playerbots=5,Console Playerbots # # -# Enable or disable AI Playerbot -AiPlayerbot.Enabled = 1 - # Enable/Disable create bot by addclass command (0 = GM only, 1 = enable) # default: 1 (enable) AiPlayerbot.AddClassCommand = 1 @@ -202,14 +112,6 @@ AiPlayerbot.AddClassCommand = 1 # default: 1 (accept based on level) AiPlayerbot.GroupInvitationPermission = 1 -# Non-GM player can only use init=auto to initialize bots based on their own level and gear score -# default: 0 (non-gm player can use any intialization commands) -AiPlayerbot.AutoInitOnly = 0 - -# Enable expansion limitation -# Default: 1 -AiPlayerbot.LimitEnchantExpansion = 1 - # auto-login all player alts as bots on player login AiPlayerbot.BotAutologin = 0 @@ -223,14 +125,25 @@ AiPlayerbot.SummonWhenGroup = 1 # Allow/deny bots from your guild AiPlayerbot.AllowGuildBots = 1 -# Sync max random bot level with max level of online players -# Default: 0 (disabled) -AiPlayerbot.SyncLevelWithPlayers = 0 - # Added following config # Selfbot permission level (0 = disabled, 1 = gm only (default), 2 = all players, 3 = activate on login) AiPlayerbot.SelfBotLevel = 1 +# Give free food to bots +# Default: 1 (enabled) +AiPlayerbot.FreeFood = 1 + +# Non-GM player can only use init=auto to initialize bots based on their own level and gear score +# default: 0 (non-gm player can use any intialization commands) +AiPlayerbot.AutoInitOnly = 0 + +# The upper limit ratio of bot equipment level for init=auto +# default: 1.0 (same with the player) +AiPlayerbot.AutoInitEquipLevelLimitRatio = 1.0 + +# Bot automatically trains spells when talking to trainer (yes = train all available spells as long as the bot has the money, free = auto trains with no money cost, no = only list spells) +AiPlayerbot.AutoTrainSpells = yes + # # # @@ -275,23 +188,13 @@ AiPlayerbot.BotRepairWhenSummon = 1 AiPlayerbot.RandomBotShowHelmet = 1 AiPlayerbot.RandomBotShowCloak = 1 +# Bots equip upgrades (Bots will equip any item obtained from looting or a quest if they are upgrades) +# Default: 1 (enable) +AiPlayerbot.AutoEquipUpgradeLoot = 1 - -# The upper limit ratio of bot equipment level for init=auto -# default: 1.0 (same with the player) -AiPlayerbot.AutoInitEquipLevelLimitRatio = 1.0 - -# Enable/Disable autogear command, auto upgrade player bots gears, the quality is limited by AutoGearQualityLimit and AutoGearScoreLimit -# default: 1 (enable) -AiPlayerbot.AutoGearCommand = 1 - -# Equips quality limitation for auto gear command (1 = normal, 2 = uncommon, 3 = rare, 4 = epic, 5 = legendary) -# default: 3 (rare) -AiPlayerbot.AutoGearQualityLimit = 3 - -# Equips gear score limitation for auto gear command (0 = no limit) -# default: 0 (no limit) -AiPlayerbot.AutoGearScoreLimit = 0 +# Equip upgrade threshold for auto equip upgrade +# Default: 1.1 (Equip when the equipment score is 1.1 times higher than the current) +AiPlayerbot.EquipUpgradeThreshold = 1.1 # # @@ -314,14 +217,6 @@ AiPlayerbot.FreeMethodLoot = 0 # Default: 1 (greed) AiPlayerbot.LootRollLevel = 1 -# Bots equip upgrades (Bots will equip any item obtained from looting or a quest if they are upgrades) -# Default: 1 (enable) -AiPlayerbot.AutoEquipUpgradeLoot = 1 - -# Equip upgrade threshold for auto equip upgrade -# Default: 1.1 (Equip when the equipment score is 1.1 times higher than the current) -AiPlayerbot.EquipUpgradeThreshold = 1.1 - # # # @@ -425,14 +320,6 @@ AiPlayerbot.AlmostFullHealth = 85 AiPlayerbot.LowMana = 15 AiPlayerbot.MediumMana = 40 -# Enable healer bot save mana -# Default: 1 (enable) -AiPlayerbot.AutoSaveMana = 1 - -# Healer bot save mana threshold -# Default: 60 (60%) -AiPlayerbot.SaveManaThreshold = 60 - # # # @@ -443,9 +330,6 @@ AiPlayerbot.SaveManaThreshold = 60 # # -# Mark many quests <= Bot level as complete (slows down bot creation) -AiPlayerbot.PreQuests = 0 - # Bots pick their quest reward (yes = picks first useful item, no = list all rewards, ask = pick useful item and lists if multiple) AiPlayerbot.AutoPickReward = no @@ -478,6 +362,14 @@ AiPlayerbot.AutoAvoidAoe = 1 # Default: 1 (enable) AiPlayerbot.TellWhenAvoidAoe = 1 +# Enable healer bot save mana +# Default: 1 (enable) +AiPlayerbot.AutoSaveMana = 1 + +# Healer bot save mana threshold +# Default: 60 (60%) +AiPlayerbot.SaveManaThreshold = 60 + # # # @@ -492,6 +384,18 @@ AiPlayerbot.TellWhenAvoidAoe = 1 # default: 1 (enable) AiPlayerbot.MaintenanceCommand = 1 +# Enable/Disable autogear command, auto upgrade player bots gears, the quality is limited by AutoGearQualityLimit and AutoGearScoreLimit +# default: 1 (enable) +AiPlayerbot.AutoGearCommand = 1 + +# Equips quality limitation for auto gear command (1 = normal, 2 = uncommon, 3 = rare, 4 = epic, 5 = legendary) +# default: 3 (rare) +AiPlayerbot.AutoGearQualityLimit = 3 + +# Equips gear score limitation for auto gear command (0 = no limit) +# default: 0 (no limit) +AiPlayerbot.AutoGearScoreLimit = 0 + # Enables/Disables bot cheating AiPlayerbot.BotCheats = "taxi" @@ -508,14 +412,279 @@ AiPlayerbot.BotCheats = "taxi" # ID of spell to open lootable chests AiPlayerbot.OpenGoSpell = 6477 -# Applies a permanent buff to all bots. -# WorldBuff.Faction.Class.MinLevel.MaxLevel - # # # ################################################################################################### +####################################### +# # +# PLAYERBOT RNDBOT SPECIFIC SETTINGS # +# # +####################################### + +#################################################################################################### +# GENERAL +# +# + +# Enables/Disables password to bot account +AiPlayerbot.RandomBotRandomPassword = 0 + +# Accounts to create for random bots +AiPlayerbot.RandomBotAccountPrefix = "rndbot" + +# Enable/Disable rotation of bots (randomly select a bot from the bots pool to go online and rotate them periodically) +# Need to reset rndbot after changing the setting (.playerbot rndbot reset) +# default: 0 (disable, the online bots are fixed) +AiPlayerbot.EnableRotation = 0 + +# Bots pool size for rotation (should be less than RandomBotAccountCount * 10) +AiPlayerbot.RotationPoolSize = 500 + +AiPlayerbot.RandomBotMinLevel = 1 +AiPlayerbot.RandomBotMaxLevel = 80 + +# Sync max random bot level with max level of online players +# Default: 0 (disabled) +AiPlayerbot.SyncLevelWithPlayers = 0 + +# Mark many quests <= Bot level as complete (slows down bot creation) +AiPlayerbot.PreQuests = 0 + +# Bots without a master will say their lines +AiPlayerbot.RandomBotSayWithoutMaster = 0 + +# Enable LFG for random bots +AiPlayerbot.RandomBotJoinLfg = 1 + +# Disable death knight for bots login +# Need to reset rndbot after changing the setting (.playerbot rndbot reset) +AiPlayerbot.DisableDeathKnightLogin = 0 + +# +# +# +#################################################################################################### + +#################################################################################################### +# LEVELS +# +# + +# Disable random levels for randombots +# Every bots started on the specified level and level up by killing mobs. +AiPlayerbot.DisableRandomLevels = 0 + +# Set randombots starting level here if "AiPlayerbot.DisableRandomLevels" enabled +AiPlayerbot.RandombotStartingLevel = 5 + +# Chance random bot has max level on first randomize (default 0.15) +AiPlayerbot.RandomBotMaxLevelChance = 0.15 + +# Fix the level of random bot (won't level up by grinding) +# Default: 0 (disable) +AiPlayerbot.RandomBotFixedLevel = 0 + +# Set RandomBotMaxLevel bots to RandomBotMinLevel or not +AiPlayerbot.DowngradeMaxLevelBot = 0 + +# +# +# +#################################################################################################### + +#################################################################################################### +# GEAR +# +# + +# Equips quality limitation for random bots (1 = normal, 2 = uncommon, 3 = rare, 4 = epic, 5 = legendary) +# default: 3 (rare) +AiPlayerbot.RandomGearQualityLimit = 3 + +# Equips gear score limitation for random bots (0 = no limit) +# default: 0 (no limit) +AiPlayerbot.RandomGearScoreLimit = 0 + +# Set minimum level of randombots where gets enchants on items (Maxlevel + 1 to disable) +# Default: 60 +AiPlayerbot.MinEnchantingBotLevel = 60 + +# Enable expansion limitation +# Default: 1 +AiPlayerbot.LimitEnchantExpansion = 1 + +# Change random bot has lower gear +AiPlayerbot.RandomGearLoweringChance = 0 + +# Randombots checking players gear score level and deny the group invite if it's too low +# Default: 0 (disabled) +AiPlayerbot.GearScoreCheck = 0 + +# Enable/Disable bot equipments persistence (stop random initialization) after certain level (EquipmentPersistenceLevel) +# default: 0 (disable) +AiPlayerbot.EquipmentPersistence = 0 + +# default: 80 +AiPlayerbot.EquipmentPersistenceLevel = 80 + +# Bot automatically upgrade equipments on levelup +# Default: 1 (enabled) +AiPlayerbot.AutoUpgradeEquip = 1 + +# +# +# +#################################################################################################### + +#################################################################################################### +# QUESTS +# +# + +# Quest that will be completed and rewarded to all random bots +AiPlayerbot.RandomBotQuestIds = "7848,3802,5505,6502,7761,10277,10285,11492,24499,24511,24710,24712" + +# Randombots will group with nearby bots to do shared quests +AiPlayerbot.RandomBotGroupNearby = 0 + +# Random Bots will pick quests on their own and try to complete +# Default: 1 (enabled) +AiPlayerbot.AutoDoQuests = 1 + +# Quest items to leave (do not destroy) +AiPlayerbot.RandomBotQuestItems = "6948,5175,5176,5177,5178,16309,12382,13704,11000" + +# +# +# +#################################################################################################### + +#################################################################################################### +# SPELLS +# +# + +# Bots automatically learn classquest reward spells on levelup +# Default: 0 (disabled) +AiPlayerbot.AutoLearnQuestSpells = 0 + +# Bots automatically learn trainable spells on levelup +# Default: 1 (enabled) +AiPlayerbot.AutoLearnTrainerSpells = 1 + +# Bot automatically picks talent points on levelup +# Default: 1 (enabled) +AiPlayerbot.AutoPickTalents = 1 + +# Spells every random bot will learn on randomize (54197 - cold weather flying) +AiPlayerbot.RandomBotSpellIds = "54197" + +# +# +# +#################################################################################################### + +#################################################################################################### +# STRATEGIES +# +# + +# Random bot default strategies (applied after defaults) +AiPlayerbot.RandomBotCombatStrategies = "+dps,+dps assist,-threat" +# AiPlayerbot.RandomBotNonCombatStrategies = "+grind,+loot,+rpg,+custom::say" +AiPlayerbot.RandomBotNonCombatStrategies = "" +AiPlayerbot.CombatStrategies = "" +AiPlayerbot.NonCombatStrategies = "" + +# +# +# +#################################################################################################### + +#################################################################################################### +# TELEPORTS +# +# + +# Maps where bots can be teleported to +AiPlayerbot.RandomBotMaps = 0,1,530,571 + +# Probabilty bots teleport to banker (city) +# default: 0.25 +AiPlayerbot.ProbTeleToBankers = 0.25 + +# How far random bots are teleported after death +AiPlayerbot.RandomBotTeleportDistance = 100 + +# Level diff between random bots and nearby creatures for random teleports +AiPlayerbot.RandomBotTeleLowerLevel = 3 +AiPlayerbot.RandomBotTeleHigherLevel = 1 + +# Bots automatically teleport to another place for leveling on levelup +# Only for random bots +# Default: 1 (enabled) +AiPlayerbot.AutoTeleportForLevel = 1 + +# +# +# +#################################################################################################### + +#################################################################################################### +# BATTLEGROUNDS & ARENAS & PVP +# +# + +# Enable BG/Arena for random Bots +AiPlayerbot.RandomBotJoinBG = 1 + +# Enable Auto join BG - bots randomly join WSG and 2v2 Arena if server is not lagging +AiPlayerbot.RandomBotAutoJoinBG = 0 + +# Random bot arena team count +AiPlayerbot.RandomBotArenaTeamCount = 20 + +# Delete all random bot arena teams +AiPlayerbot.DeleteRandomBotArenaTeams = 0 + +# PvP Restricted Zones (bots don't pvp) +AiPlayerbot.PvpProhibitedZoneIds = "2255,656,2361,2362,2363,976,35,2268,3425,392,541,1446,3828,3712,3738,3565,3539,3623,4152,3988,4658,4284,4418,4436,4275,4323,4395,3703" # 33(stranglethorn vale),440(tanaris) + +# PvP Restricted Areas (bots don't pvp) +AiPlayerbot.PvpProhibitedAreaIds = "976,35,392" + +# +# +# +#################################################################################################### + +#################################################################################################### +# INTERVALS +# +# + +# All In seconds +AiPlayerbot.RandomBotUpdateInterval = 20 +AiPlayerbot.RandomBotCountChangeMinInterval = 1800 +AiPlayerbot.RandomBotCountChangeMaxInterval = 7200 +AiPlayerbot.MinRandomBotInWorldTime = 3600 +AiPlayerbot.MaxRandomBotInWorldTime = 43200 +AiPlayerbot.MinRandomBotRandomizeTime = 302400 +AiPlayerbot.MaxRandomBotRandomizeTime = 1209600 +AiPlayerbot.RandomBotsPerInterval = 500 +AiPlayerbot.MinRandomBotReviveTime = 60 +AiPlayerbot.MaxRandomBotReviveTime = 300 +AiPlayerbot.MinRandomBotTeleportInterval = 3600 +AiPlayerbot.MaxRandomBotTeleportInterval = 18000 +AiPlayerbot.RandomBotInWorldWithRotationDisabled = 31104000 + +# +# +# +#################################################################################################### + ################################### # # # PREMADE SPECS # @@ -779,310 +948,14 @@ AiPlayerbot.PremadeSpecLink.11.3.80 = -553202032322010053100030310511-205503012 # ################################################################################################### -####################################### -# # -# PLAYERBOT RNDBOT SPECIFIC SETTINGS # -# # -####################################### +################################### +# # +# RANDOM BOT DEFAULT TALENT SPEC # +# # +################################### #################################################################################################### -# GENERAL -# -# - -# Enable random bot system -AiPlayerbot.RandomBotAutologin = 1 - -# Enables/Disables password to bot account -AiPlayerbot.RandomBotRandomPassword = 0 - -# Log on all random bots on start -AiPlayerbot.RandomBotLoginAtStartup = 1 - -# Accounts to create for random bots -AiPlayerbot.RandomBotAccountPrefix = "rndbot" -AiPlayerbot.RandomBotAccountCount = 200 - -# Random bot count -AiPlayerbot.MinRandomBots = 50 -AiPlayerbot.MaxRandomBots = 50 -AiPlayerbot.RandomBotMinLevel = 1 -AiPlayerbot.RandomBotMaxLevel = 80 - -# Bots pool size for rotation (should be less than RandomBotAccountCount * 10) -AiPlayerbot.RotationPoolSize = 500 - -# Enable/Disable rotation of bots (randomly select a bot from the bots pool to go online and rotate them periodically) -# Need to reset rndbot after changing the setting (.playerbot rndbot reset) -# default: 0 (disable, the online bots are fixed) -AiPlayerbot.EnableRotation = 0 - -# Bots without a master will say their lines -AiPlayerbot.RandomBotSayWithoutMaster = 0 - -# Enable LFG for random bots -AiPlayerbot.RandomBotJoinLfg = 1 - -# Disable death knight for bots login -# Need to reset rndbot after changing the setting (.playerbot rndbot reset) -AiPlayerbot.DisableDeathKnightLogin = 0 - -# Give free food to random bots -# Default: 1 (enabled) -AiPlayerbot.FreeFood = 1 - -# Bots automatically teleport to another place for leveling on levelup -# Only for random bots -# Default: 1 (enabled) -AiPlayerbot.AutoTeleportForLevel = 1 - -# -# -# -#################################################################################################### - -#################################################################################################### -# ACCOUNTS DELETE RNDBOTS -# -# - -# Delete all random bot accounts (reset randombots) -AiPlayerbot.DeleteRandomBotAccounts = 0 - -# -# -# -#################################################################################################### - -#################################################################################################### -# LEVELS -# -# - -# Disable random levels for randombots -# Every bots started on the specified level and level up by killing mobs. -AiPlayerbot.DisableRandomLevels = 0 - -# Set randombots starting level here if "AiPlayerbot.DisableRandomLevels" enabled -AiPlayerbot.RandombotStartingLevel = 5 - -# Chance random bot has max level on first randomize (default 0.15) -AiPlayerbot.RandomBotMaxLevelChance = 0.15 - -# Fix the level of random bot (won't level up by grinding) -# Default: 0 (disable) -AiPlayerbot.RandomBotFixedLevel = 0 - -# Set RandomBotMaxLevel bots to RandomBotMinLevel or not -AiPlayerbot.DowngradeMaxLevelBot = 0 - -# Bot automatically picks talent points on levelup -# Only for random bots -# Default: 1 (enabled) -AiPlayerbot.AutoPickTalents = 1 - -# -# -# -#################################################################################################### - -#################################################################################################### -# GEAR -# -# - -# Equips quality limitation for random bots (1 = normal, 2 = uncommon, 3 = rare, 4 = epic, 5 = legendary) -# default: 3 (rare) -AiPlayerbot.RandomGearQualityLimit = 3 - -# Equips gear score limitation for random bots (0 = no limit) -# default: 0 (no limit) -AiPlayerbot.RandomGearScoreLimit = 0 - -# Change random bot has lower gear -AiPlayerbot.RandomGearLoweringChance = 0 - -# Randombots checking players gear score level and deny the group invite if it's too low -# Default: 0 (disabled) -AiPlayerbot.GearScoreCheck = 0 - -# Enable/Disable bot equipments persistence (stop random initialization) after certain level (EquipmentPersistenceLevel) -# default: 0 (disable) -AiPlayerbot.EquipmentPersistence = 0 - -# default: 80 -AiPlayerbot.EquipmentPersistenceLevel = 80 - -# Bot automatically upgrade equipments on levelup -# Only for random bots -# Default: 1 (enabled) -AiPlayerbot.AutoUpgradeEquip = 1 - -# -# -# -#################################################################################################### - -#################################################################################################### -# QUESTS -# -# - -# Quest that will be completed and rewarded to all random bots -AiPlayerbot.RandomBotQuestIds = "7848,3802,5505,6502,7761,10277,10285,11492,24499,24511,24710,24712" - -# Randombots will group with nearby bots to do shared quests -AiPlayerbot.RandomBotGroupNearby = 0 - -# Random Bots will pick quests on their own and try to complete -# Only for random bots -# Default: 1 (enabled) -AiPlayerbot.AutoDoQuests = 1 - -# Quest items to leave (do not destroy) -AiPlayerbot.RandomBotQuestItems = "6948,5175,5176,5177,5178,16309,12382,13704,11000" - -# -# -# -#################################################################################################### - -#################################################################################################### -# PROFESSIONS -# -# - -# Set minimum level of randombots where gets enchants on items (Maxlevel + 1 to disable) -# Default: 60 -AiPlayerbot.MinEnchantingBotLevel = 60 - -# -# -# -#################################################################################################### - -#################################################################################################### -# SPELLS -# -# - -# Bot automatically trains spells when talking to trainer (yes = train all available spells as long as the bot has the money, free = auto trains with no money cost, no = only list spells) -# Only for random bots -AiPlayerbot.AutoTrainSpells = yes - -# Bots automatically learn classquest reward spells on levelup -# Only for random bots -# Default: 0 (disabled) -AiPlayerbot.AutoLearnQuestSpells = 0 - -# Bots automatically learn trainable spells on levelup -# Only for random bots -# Default: 1 (enabled) -AiPlayerbot.AutoLearnTrainerSpells = 1 - -# Spells every random bot will learn on randomize (54197 - cold weather flying) -AiPlayerbot.RandomBotSpellIds = "54197" - -# -# -# -#################################################################################################### - -#################################################################################################### -# STRATEGIES -# -# - -# Random bot default strategies (applied after defaults) -AiPlayerbot.RandomBotCombatStrategies = "+dps,+dps assist,-threat" -# AiPlayerbot.RandomBotNonCombatStrategies = "+grind,+loot,+rpg,+custom::say" -AiPlayerbot.RandomBotNonCombatStrategies = "" -AiPlayerbot.CombatStrategies = "" -AiPlayerbot.NonCombatStrategies = "" - -# -# -# -#################################################################################################### - -#################################################################################################### -# TELEPORTS -# -# - -# Maps where bots can be teleported to -AiPlayerbot.RandomBotMaps = 0,1,530,571 - -# Probabilty bots teleport to banker (city) -# default: 0.25 -AiPlayerbot.ProbTeleToBankers = 0.25 - -# How far random bots are teleported after death -AiPlayerbot.RandomBotTeleportDistance = 100 - -# Level diff between random bots and nearby creatures for random teleports -AiPlayerbot.RandomBotTeleLowerLevel = 3 -AiPlayerbot.RandomBotTeleHigherLevel = 1 - -# -# -# -#################################################################################################### - -#################################################################################################### -# BATTLEGROUNDS & ARENAS & PVP -# -# - -# Enable BG/Arena for random Bots -AiPlayerbot.RandomBotJoinBG = 1 - -# Enable Auto join BG - bots randomly join WSG and 2v2 Arena if server is not lagging -AiPlayerbot.RandomBotAutoJoinBG = 0 - -# Random bot arena team count -AiPlayerbot.RandomBotArenaTeamCount = 20 - -# Delete all random bot arena teams -AiPlayerbot.DeleteRandomBotArenaTeams = 0 - -# PvP Restricted Zones (bots don't pvp) -AiPlayerbot.PvpProhibitedZoneIds = "2255,656,2361,2362,2363,976,35,2268,3425,392,541,1446,3828,3712,3738,3565,3539,3623,4152,3988,4658,4284,4418,4436,4275,4323,4395,3703" # 33(stranglethorn vale),440(tanaris) - -# PvP Restricted Areas (bots don't pvp) -AiPlayerbot.PvpProhibitedAreaIds = "976,35,392" - -# -# -# -#################################################################################################### - -#################################################################################################### -# INTERVALS -# -# - -AiPlayerbot.RandomBotUpdateInterval = 20 -AiPlayerbot.RandomBotCountChangeMinInterval = 1800 -AiPlayerbot.RandomBotCountChangeMaxInterval = 7200 -AiPlayerbot.MinRandomBotInWorldTime = 3600 -AiPlayerbot.MaxRandomBotInWorldTime = 43200 -AiPlayerbot.MinRandomBotRandomizeTime = 302400 -AiPlayerbot.MaxRandomBotRandomizeTime = 1209600 -AiPlayerbot.RandomBotsPerInterval = 500 -AiPlayerbot.MinRandomBotReviveTime = 60 -AiPlayerbot.MaxRandomBotReviveTime = 300 -AiPlayerbot.MinRandomBotTeleportInterval = 3600 -AiPlayerbot.MaxRandomBotTeleportInterval = 18000 -AiPlayerbot.RandomBotInWorldWithRotationDisabled = 31104000 - -# -# -# -#################################################################################################### - -#################################################################################################### -# DEFAULT TALENT SPEC +# # # @@ -1264,6 +1137,118 @@ AiPlayerbot.RandomClassSpecIndex.11.2 = 2 # ################################################################################################### + +################################### +# # +# PLAYERBOT SYSTEM SETTINGS # +# # +################################### + +#################################################################################################### +# DATABASE & CONNECTIONS +# +# + +# PlayerbotsDatabaseInfo +# Description: Database connection settings for the playerbots server. +# Example: "hostname;port;username;password;database" +# ".;somenumber;username;password;database" - (Use named pipes on Windows +# "enable-named-pipe" to [mysqld] +# section my.ini) +# ".;/path/to/unix_socket;username;password;database" - (use Unix sockets on +# Unix/Linux) +# Default: "127.0.0.1;3306;acore;acore;acore_playerbots" - (PlayerbotDatabaseInfo) + +PlayerbotsDatabaseInfo = "127.0.0.1;3306;acore;acore;acore_playerbots" + +# +# PlayerbotsDatabase.WorkerThreads +# Description: The amount of worker threads spawned to handle asynchronous (delayed) MySQL +# statements. Each worker thread is mirrored with its own connection to the +# MySQL server and their own thread on the MySQL server. +# Default: 1 - (PlayerbotsDatabase.WorkerThreads) + +PlayerbotsDatabase.WorkerThreads = 1 + +# +# PlayerbotsDatabase.SynchThreads +# Description: The amount of MySQL connections spawned to handle. +# Default: 1 - (PlayerbotDatabase.WorkerThreads) + +PlayerbotsDatabase.SynchThreads = 1 + +# Playerbot.Updates.EnableDatabases +# Description: Determined if updates system work with playerbot database. +# +# Default: 1 - (Enabled) +# 0 - (Disabled) + +Playerbots.Updates.EnableDatabases = 1 + +# Command server port, 0 - disabled +AiPlayerbot.CommandServerPort = 8888 + +# Diff with/without player in server. The server will tune bot activity to reach the desired server tick speed (in ms).# PLAYERBOT SYSTEM SETTINGS # +AiPlayerbot.EnablePrototypePerformanceDiff = 0 +AiPlayerbot.DiffWithPlayer = 100 +AiPlayerbot.DiffEmpty = 200 + +# +# +# +#################################################################################################### + +#################################################################################################### +# DEBUG SWITCHES +# +# + +AiPlayerbot.SpellDump = 0 +AiPlayerbot.LogInGroupOnly = 1 +AiPlayerbot.LogValuesPerTick = 0 +AiPlayerbot.RandomChangeMultiplier = 1 + +# Enables/Disables performance monitor +AiPlayerbot.PerfMonEnabled = 0 + +# +# +# +#################################################################################################### + +#################################################################################################### +# CHAT SETTINGS +# +# + +# Prefix for bot chat commands (e.g. follow, stay) +AiPlayerbot.CommandPrefix = "" + +# Separator for bot chat commands +AiPlayerbot.CommandSeparator = "\\\\" + +# +# +# +#################################################################################################### + +#################################################################################################### +# LOGS +# +# + +# Custom config to allow logfiles to be created. +# Example: AiPlayerbot.AllowedLogFiles = travelNodes.csv,travelPaths.csv,TravelNodeStore.h,bot_movement.csv,bot_location.csv +AiPlayerbot.AllowedLogFiles = "" + +Appender.Playerbots=2,5,0,Playerbots.log,w +Logger.playerbots=5,Console Playerbots + +# +# +# +#################################################################################################### + ################################################################################################### ################################################################################################### ################################################################################################### @@ -1273,6 +1258,10 @@ AiPlayerbot.RandomClassSpecIndex.11.2 = 2 ############################################## # Deprecated (temporary) # ############################################## + +# Log on all random bots on start +AiPlayerbot.RandomBotLoginAtStartup = 1 + # Guild Task system AiPlayerbot.EnableGuildTasks = 0 From 24853a3fa308cec3d08fbd3703f714f3fb529071 Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Sat, 13 Jul 2024 21:36:19 +0800 Subject: [PATCH 44/51] [Crash fix] Fix a crash in bg join with group --- src/strategy/actions/BattleGroundJoinAction.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/strategy/actions/BattleGroundJoinAction.cpp b/src/strategy/actions/BattleGroundJoinAction.cpp index cfd552b4..c9c0c396 100644 --- a/src/strategy/actions/BattleGroundJoinAction.cpp +++ b/src/strategy/actions/BattleGroundJoinAction.cpp @@ -459,7 +459,7 @@ bool BGJoinAction::JoinQueue(uint32 type) // get BG MapId uint32 bgTypeId_ = bgTypeId; uint32 instanceId = 0; // 0 = First Available - bool joinAsGroup = bot->GetGroup() && bot->GetGroup()->GetLeaderGUID() == bot->GetGUID(); + bool isPremade = false; bool isArena = false; bool isRated = false; @@ -483,6 +483,11 @@ bool BGJoinAction::JoinQueue(uint32 type) return false; } + // refresh food/regs + sRandomPlayerbotMgr->Refresh(bot); + + bool joinAsGroup = bot->GetGroup() && bot->GetGroup()->GetLeaderGUID() == bot->GetGUID(); + // in wotlk only arena requires battlemaster guid ObjectGuid guid = isArena ? unit->GetGUID() : bot->GetGUID(); @@ -546,8 +551,6 @@ bool BGJoinAction::JoinQueue(uint32 type) bot->GetGUID().ToString().c_str(), bot->GetTeamId() == TEAM_ALLIANCE ? "A" : "H", bot->getLevel(), bot->GetName().c_str(), _bgType.c_str(), isRated ? "Rated Arena" : isArena ? "Arena" : ""); - // refresh food/regs - sRandomPlayerbotMgr->Refresh(bot); if (isArena) { From 6dd5494cfd4113dd9cb0efc56e7f8820c584b8cf Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Sat, 13 Jul 2024 21:42:47 +0800 Subject: [PATCH 45/51] [Initialization] Disable init command during combat --- src/PlayerbotMgr.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/PlayerbotMgr.cpp b/src/PlayerbotMgr.cpp index 1de95c56..665c7fdf 100644 --- a/src/PlayerbotMgr.cpp +++ b/src/PlayerbotMgr.cpp @@ -575,6 +575,13 @@ std::string const PlayerbotHolder::ProcessBotCommand(std::string const cmd, Obje return "ERROR: You can not use this command on non-summoned random bot."; } + if (!admin) { + Player* master = ObjectAccessor::FindConnectedPlayer(masterguid); + if (master && (master->IsInCombat() || bot->IsInCombat())) { + return "ERROR: You can not use this command during combat."; + } + } + if (GET_PLAYERBOT_AI(bot)) { if (Player* master = GET_PLAYERBOT_AI(bot)->GetMaster()) { From 8ebd6544175a97e444770f0a0b212baf89d67913 Mon Sep 17 00:00:00 2001 From: Caffarius Date: Sat, 13 Jul 2024 18:55:55 -0400 Subject: [PATCH 46/51] Add DK starter map to PvpProhibitedZoneIds Adds "Plaguelands: The Scarlet Enclave" (zoneid 4298) to the list to prevent a mountain of corpses where DKs start. They shouldn't hate eachother until they gain freedom from Arthas and leave the zone. --- conf/playerbots.conf.dist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/playerbots.conf.dist b/conf/playerbots.conf.dist index 443f6cdc..4ae02b69 100644 --- a/conf/playerbots.conf.dist +++ b/conf/playerbots.conf.dist @@ -650,7 +650,7 @@ AiPlayerbot.RandomBotArenaTeamCount = 20 AiPlayerbot.DeleteRandomBotArenaTeams = 0 # PvP Restricted Zones (bots don't pvp) -AiPlayerbot.PvpProhibitedZoneIds = "2255,656,2361,2362,2363,976,35,2268,3425,392,541,1446,3828,3712,3738,3565,3539,3623,4152,3988,4658,4284,4418,4436,4275,4323,4395,3703" # 33(stranglethorn vale),440(tanaris) +AiPlayerbot.PvpProhibitedZoneIds = "2255,656,2361,2362,2363,976,35,2268,3425,392,541,1446,3828,3712,3738,3565,3539,3623,4152,3988,4658,4284,4418,4436,4275,4323,4395,3703,4298" # 33(stranglethorn vale),440(tanaris) # PvP Restricted Areas (bots don't pvp) AiPlayerbot.PvpProhibitedAreaIds = "976,35,392" From a1fe7e5d24d844c3647d915c679d4c84deb63550 Mon Sep 17 00:00:00 2001 From: Bobblybook Date: Sun, 14 Jul 2024 14:09:55 +1000 Subject: [PATCH 47/51] Fix/rewrite Shaman weapon buff checking (incl. dual wield support) Replace the self-weapon shaman imbues with buff checking similar to rogue poisons. Includes support for buffing offhand for enhancement DW shamans. --- src/strategy/shaman/CasterShamanStrategy.cpp | 4 ++-- src/strategy/shaman/GenericShamanStrategy.cpp | 6 +++--- src/strategy/shaman/HealShamanStrategy.cpp | 3 ++- src/strategy/shaman/MeleeShamanStrategy.cpp | 4 +++- src/strategy/shaman/ShamanAiObjectContext.cpp | 8 ++++++-- src/strategy/shaman/ShamanTriggers.cpp | 16 ++++++++++++++++ src/strategy/shaman/ShamanTriggers.h | 16 ++++++++++++++++ 7 files changed, 48 insertions(+), 9 deletions(-) diff --git a/src/strategy/shaman/CasterShamanStrategy.cpp b/src/strategy/shaman/CasterShamanStrategy.cpp index 61a31b32..efa3a9e1 100644 --- a/src/strategy/shaman/CasterShamanStrategy.cpp +++ b/src/strategy/shaman/CasterShamanStrategy.cpp @@ -49,10 +49,10 @@ void CasterShamanStrategy::InitTriggers(std::vector& triggers) GenericShamanStrategy::InitTriggers(triggers); // triggers.push_back(new TriggerNode("enemy out of spell", NextAction::array(0, new NextAction("reach spell", ACTION_NORMAL + 9), nullptr))); - triggers.push_back(new TriggerNode("shaman weapon", NextAction::array(0, new NextAction("flametongue weapon", 23.0f), nullptr))); + // triggers.push_back(new TriggerNode("shaman weapon", NextAction::array(0, new NextAction("flametongue weapon", 23.0f), nullptr))); + triggers.push_back(new TriggerNode("main hand weapon no imbue", NextAction::array(0, new NextAction("flametongue weapon", 22.0f), nullptr))); // triggers.push_back(new TriggerNode("searing totem", NextAction::array(0, new NextAction("searing totem", 19.0f), nullptr))); triggers.push_back(new TriggerNode("flame shock", NextAction::array(0, new NextAction("flame shock", 20.0f), nullptr))); - triggers.push_back(new TriggerNode("elemental mastery", NextAction::array(0, new NextAction("elemental mastery", 27.0f), nullptr))); // triggers.push_back(new TriggerNode("frost shock snare", NextAction::array(0, new NextAction("frost shock", 21.0f), nullptr))); triggers.push_back(new TriggerNode( "no fire totem", diff --git a/src/strategy/shaman/GenericShamanStrategy.cpp b/src/strategy/shaman/GenericShamanStrategy.cpp index de5229e1..96a31cbf 100644 --- a/src/strategy/shaman/GenericShamanStrategy.cpp +++ b/src/strategy/shaman/GenericShamanStrategy.cpp @@ -35,7 +35,7 @@ class GenericShamanStrategyActionNodeFactory : public NamedObjectFactory& triggers) GenericShamanStrategy::InitTriggers(triggers); // triggers.push_back(new TriggerNode("enemy out of spell", NextAction::array(0, new NextAction("reach spell", ACTION_NORMAL + 9), nullptr))); - triggers.push_back(new TriggerNode("shaman weapon", NextAction::array(0, new NextAction("earthliving weapon", 22.0f), nullptr))); + // triggers.push_back(new TriggerNode("shaman weapon", NextAction::array(0, new NextAction("earthliving weapon", 22.0f), nullptr))); + triggers.push_back(new TriggerNode("main hand weapon no imbue", NextAction::array(0, new NextAction("earthliving weapon", 22.0f), nullptr))); triggers.push_back(new TriggerNode( "group heal occasion", NextAction::array(0, new NextAction("riptide on party", 23.0f), new NextAction("chain heal", 22.0f), NULL))); diff --git a/src/strategy/shaman/MeleeShamanStrategy.cpp b/src/strategy/shaman/MeleeShamanStrategy.cpp index fff1d05c..6b8bce24 100644 --- a/src/strategy/shaman/MeleeShamanStrategy.cpp +++ b/src/strategy/shaman/MeleeShamanStrategy.cpp @@ -63,7 +63,9 @@ void MeleeShamanStrategy::InitTriggers(std::vector& triggers) { GenericShamanStrategy::InitTriggers(triggers); - triggers.push_back(new TriggerNode("shaman weapon", NextAction::array(0, new NextAction("flametongue weapon", 22.0f), nullptr))); + //triggers.push_back(new TriggerNode("shaman weapon", NextAction::array(0, new NextAction("flametongue weapon", 22.0f), nullptr))); + triggers.push_back(new TriggerNode("main hand weapon no imbue", NextAction::array(0, new NextAction("windfury weapon", 22.0f), nullptr))); + triggers.push_back(new TriggerNode("off hand weapon no imbue", NextAction::array(0, new NextAction("flametongue weapon", 21.0f), nullptr))); // triggers.push_back(new TriggerNode("searing totem", NextAction::array(0, new NextAction("reach melee", 22.0f), new NextAction("searing totem", 22.0f), nullptr))); triggers.push_back(new TriggerNode("flame shock", NextAction::array(0, new NextAction("flame shock", 20.0f), nullptr))); triggers.push_back(new TriggerNode( diff --git a/src/strategy/shaman/ShamanAiObjectContext.cpp b/src/strategy/shaman/ShamanAiObjectContext.cpp index 819cf3d1..cee208c2 100644 --- a/src/strategy/shaman/ShamanAiObjectContext.cpp +++ b/src/strategy/shaman/ShamanAiObjectContext.cpp @@ -79,7 +79,9 @@ class ShamanATriggerFactoryInternal : public NamedObjectContext creators["searing totem"] = &ShamanATriggerFactoryInternal::searing_totem; creators["wind shear"] = &ShamanATriggerFactoryInternal::wind_shear; creators["purge"] = &ShamanATriggerFactoryInternal::purge; - creators["shaman weapon"] = &ShamanATriggerFactoryInternal::shaman_weapon; + //creators["shaman weapon"] = &ShamanATriggerFactoryInternal::shaman_weapon; + creators["main hand weapon no imbue"] = &ShamanATriggerFactoryInternal::main_hand_weapon_no_imbue; + creators["off hand weapon no imbue"] = &ShamanATriggerFactoryInternal::off_hand_weapon_no_imbue; creators["water shield"] = &ShamanATriggerFactoryInternal::water_shield; creators["lightning shield"] = &ShamanATriggerFactoryInternal::lightning_shield; creators["water breathing"] = &ShamanATriggerFactoryInternal::water_breathing; @@ -136,7 +138,9 @@ class ShamanATriggerFactoryInternal : public NamedObjectContext static Trigger* searing_totem(PlayerbotAI* botAI) { return new SearingTotemTrigger(botAI); } static Trigger* wind_shear(PlayerbotAI* botAI) { return new WindShearInterruptSpellTrigger(botAI); } static Trigger* purge(PlayerbotAI* botAI) { return new PurgeTrigger(botAI); } - static Trigger* shaman_weapon(PlayerbotAI* botAI) { return new ShamanWeaponTrigger(botAI); } + //static Trigger* shaman_weapon(PlayerbotAI* botAI) { return new ShamanWeaponTrigger(botAI); } + static Trigger* main_hand_weapon_no_imbue(PlayerbotAI* botAI) { return new MainHandWeaponNoImbueTrigger(botAI); } + static Trigger* off_hand_weapon_no_imbue(PlayerbotAI* botAI) { return new OffHandWeaponNoImbueTrigger(botAI); } static Trigger* water_shield(PlayerbotAI* botAI) { return new WaterShieldTrigger(botAI); } static Trigger* lightning_shield(PlayerbotAI* botAI) { return new LightningShieldTrigger(botAI); } static Trigger* shock(PlayerbotAI* botAI) { return new ShockTrigger(botAI); } diff --git a/src/strategy/shaman/ShamanTriggers.cpp b/src/strategy/shaman/ShamanTriggers.cpp index 459b9bc6..d0651378 100644 --- a/src/strategy/shaman/ShamanTriggers.cpp +++ b/src/strategy/shaman/ShamanTriggers.cpp @@ -5,6 +5,7 @@ #include "ShamanTriggers.h" #include "Playerbots.h" +/* std::vector ShamanWeaponTrigger::spells; bool ShamanWeaponTrigger::IsActive() @@ -30,6 +31,21 @@ bool ShamanWeaponTrigger::IsActive() return false; } +*/ + +bool MainHandWeaponNoImbueTrigger::IsActive() { + Item* const itemForSpell = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND ); + if (!itemForSpell || itemForSpell->GetEnchantmentId(TEMP_ENCHANTMENT_SLOT)) + return false; + return true; +} + +bool OffHandWeaponNoImbueTrigger::IsActive() { + Item* const itemForSpell = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND ); + if (!itemForSpell || itemForSpell->GetEnchantmentId(TEMP_ENCHANTMENT_SLOT)) + return false; + return true; +} bool ShockTrigger::IsActive() { diff --git a/src/strategy/shaman/ShamanTriggers.h b/src/strategy/shaman/ShamanTriggers.h index d85f0888..c4350f79 100644 --- a/src/strategy/shaman/ShamanTriggers.h +++ b/src/strategy/shaman/ShamanTriggers.h @@ -11,6 +11,7 @@ class PlayerbotAI; +/* class ShamanWeaponTrigger : public BuffTrigger { public: @@ -21,6 +22,21 @@ class ShamanWeaponTrigger : public BuffTrigger private: static std::vector spells; }; +*/ + +class MainHandWeaponNoImbueTrigger : public BuffTrigger +{ + public: + MainHandWeaponNoImbueTrigger(PlayerbotAI* ai) : BuffTrigger(ai, "main hand", 1) {} + virtual bool IsActive(); +}; + +class OffHandWeaponNoImbueTrigger : public BuffTrigger +{ + public: + OffHandWeaponNoImbueTrigger(PlayerbotAI* ai) : BuffTrigger(ai, "off hand", 1) {} + virtual bool IsActive(); +}; class TotemTrigger : public Trigger { From 936fa40a62217bea5b64303a43c5602e5074e04c Mon Sep 17 00:00:00 2001 From: Bobblybook Date: Sun, 14 Jul 2024 14:23:38 +1000 Subject: [PATCH 48/51] Update CasterShamanStrategy.cpp Re-add new ele mastery trigger --- src/strategy/shaman/CasterShamanStrategy.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/strategy/shaman/CasterShamanStrategy.cpp b/src/strategy/shaman/CasterShamanStrategy.cpp index efa3a9e1..381e7070 100644 --- a/src/strategy/shaman/CasterShamanStrategy.cpp +++ b/src/strategy/shaman/CasterShamanStrategy.cpp @@ -53,6 +53,7 @@ void CasterShamanStrategy::InitTriggers(std::vector& triggers) triggers.push_back(new TriggerNode("main hand weapon no imbue", NextAction::array(0, new NextAction("flametongue weapon", 22.0f), nullptr))); // triggers.push_back(new TriggerNode("searing totem", NextAction::array(0, new NextAction("searing totem", 19.0f), nullptr))); triggers.push_back(new TriggerNode("flame shock", NextAction::array(0, new NextAction("flame shock", 20.0f), nullptr))); + triggers.push_back(new TriggerNode("elemental mastery", NextAction::array(0, new NextAction("elemental mastery", 27.0f), nullptr))); // triggers.push_back(new TriggerNode("frost shock snare", NextAction::array(0, new NextAction("frost shock", 21.0f), nullptr))); triggers.push_back(new TriggerNode( "no fire totem", From 5e2d06d6ebd1b646e9642133fe209b0b276bdb64 Mon Sep 17 00:00:00 2001 From: Fuzz Date: Sun, 14 Jul 2024 18:43:20 +1000 Subject: [PATCH 49/51] added AiPlayerbot.LimitGearExpansion option so that bots <= 60 can be limited to expansions gear based on level (bot-level <= 60 gets vanilla gear, bot <= 70 gets TBC gear). also modified level thresholds for LimitEnchantExpansion option (which were <= 69 for vanilla enchants and <= 79 for TBC - those dont seem right because 61-69 are TBC levels, not vanilla, same for 71-79 being WOTLK) --- conf/playerbots.conf.dist | 12 +++++++++--- src/PlayerbotAIConfig.cpp | 3 ++- src/PlayerbotAIConfig.h | 1 + src/PlayerbotFactory.cpp | 17 +++++++++++------ 4 files changed, 23 insertions(+), 10 deletions(-) diff --git a/conf/playerbots.conf.dist b/conf/playerbots.conf.dist index 4ae02b69..eab4de36 100644 --- a/conf/playerbots.conf.dist +++ b/conf/playerbots.conf.dist @@ -511,9 +511,15 @@ AiPlayerbot.RandomGearScoreLimit = 0 # Default: 60 AiPlayerbot.MinEnchantingBotLevel = 60 -# Enable expansion limitation -# Default: 1 -AiPlayerbot.LimitEnchantExpansion = 1 +# Enable expansion limitation for enchants - ie: level <= 60 bot only uses enchants +# available in vanilla, level <= 70 bot only uses enchants available in TBC) +# Default: 0 +AiPlayerbot.LimitEnchantExpansion = 0 + +# Enable expansion limitation for gear - ie: level <= 60 bot only uses gear +# available in vanilla, level <= 70 bot only uses gear available in TBC) +# Default: 0 +AiPlayerbot.LimitGearExpansion = 0 # Change random bot has lower gear AiPlayerbot.RandomGearLoweringChance = 0 diff --git a/src/PlayerbotAIConfig.cpp b/src/PlayerbotAIConfig.cpp index 48783180..a6bcf470 100644 --- a/src/PlayerbotAIConfig.cpp +++ b/src/PlayerbotAIConfig.cpp @@ -300,7 +300,8 @@ bool PlayerbotAIConfig::Initialize() randombotsWalkingRPG = sConfigMgr->GetOption("AiPlayerbot.RandombotsWalkingRPG", false); randombotsWalkingRPGInDoors = sConfigMgr->GetOption("AiPlayerbot.RandombotsWalkingRPG.InDoors", false); minEnchantingBotLevel = sConfigMgr->GetOption("AiPlayerbot.MinEnchantingBotLevel", 60); - limitEnchantExpansion = sConfigMgr->GetOption("AiPlayerbot.LimitEnchantExpansion", 1); + limitEnchantExpansion = sConfigMgr->GetOption("AiPlayerbot.LimitEnchantExpansion", 0); + limitGearExpansion = sConfigMgr->GetOption("AiPlayerbot.LimitGearExpansion", 0); randombotStartingLevel = sConfigMgr->GetOption("AiPlayerbot.RandombotStartingLevel", 5); enableRotation = sConfigMgr->GetOption("AiPlayerbot.EnableRotation", false); rotationPoolSize = sConfigMgr->GetOption("AiPlayerbot.RotationPoolSize", 500); diff --git a/src/PlayerbotAIConfig.h b/src/PlayerbotAIConfig.h index 7bbc0512..17da007d 100644 --- a/src/PlayerbotAIConfig.h +++ b/src/PlayerbotAIConfig.h @@ -136,6 +136,7 @@ class PlayerbotAIConfig bool randombotsWalkingRPGInDoors; uint32 minEnchantingBotLevel; uint32 limitEnchantExpansion; + uint32 limitGearExpansion; uint32 randombotStartingLevel; bool enableRotation; uint32 rotationPoolSize; diff --git a/src/PlayerbotFactory.cpp b/src/PlayerbotFactory.cpp index c74b722d..26f9e3a6 100644 --- a/src/PlayerbotFactory.cpp +++ b/src/PlayerbotFactory.cpp @@ -1456,6 +1456,14 @@ void PlayerbotFactory::InitEquipment(bool incremental) if (itemId == 46978) { // shaman earth ring totem continue; } + + // disable next expansion gear + if (sPlayerbotAIConfig->limitGearExpansion && bot->GetLevel() <= 60 && itemId >= 23728) + continue; + + if (sPlayerbotAIConfig->limitGearExpansion && bot->GetLevel() <= 70 && itemId >= 35570 && itemId != 36737 && itemId != 37739 && itemId != 37740)//transition point from TBC -> WOTLK isn't as clear, and there are other wearable TBC items above 35570 but nothing of significance + continue; + ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemId); if (!proto) continue; @@ -3454,15 +3462,12 @@ void PlayerbotFactory::ApplyEnchantAndGemsNew(bool destoryOld) continue; } - // disable next expansion - if (sPlayerbotAIConfig->limitEnchantExpansion && bot->GetLevel() <= 69 && enchantSpell >= 25072) { + // disable next expansion enchantments + if (sPlayerbotAIConfig->limitEnchantExpansion && bot->GetLevel() <= 60 && enchantSpell >= 25072) continue; - } - if (sPlayerbotAIConfig->limitEnchantExpansion && bot->GetLevel() <= 79 && enchantSpell > 48557) { + if (sPlayerbotAIConfig->limitEnchantExpansion && bot->GetLevel() <= 70 && enchantSpell > 48557) continue; - } - for (uint8 j = 0; j < MAX_SPELL_EFFECTS; ++j) { From 159980f76eb0a84be56f68dbfe224be8147767f4 Mon Sep 17 00:00:00 2001 From: Jgoodwin64 <94092417+Jgoodwin64@users.noreply.github.com> Date: Sun, 14 Jul 2024 20:30:43 -0400 Subject: [PATCH 50/51] Fixed bug in StayActions.cpp The bot used to wait till it got done with it's current path. Now the bot stays immediately on the stayAction is loaded. --- src/strategy/actions/StayActions.cpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/strategy/actions/StayActions.cpp b/src/strategy/actions/StayActions.cpp index 1b810dd4..ca8a83b1 100644 --- a/src/strategy/actions/StayActions.cpp +++ b/src/strategy/actions/StayActions.cpp @@ -13,7 +13,6 @@ bool StayActionBase::Stay() //if (!urand(0, 10)) //botAI->PlaySound(TEXT_EMOTE_YAWN); - if (bot->GetMotionMaster()->GetCurrentMovementGeneratorType() == FLIGHT_MOTION_TYPE) return false; @@ -26,12 +25,13 @@ bool StayActionBase::Stay() context->GetValue("stay time")->Set(stayTime); } - if (!bot->isMoving()) - return false; - - bot->StopMoving(); - bot->ClearUnitState(UNIT_STATE_CHASE); - bot->ClearUnitState(UNIT_STATE_FOLLOW); + // Stop the bot from moving immediately when action is called + if (bot->isMoving()) + { + bot->StopMoving(); + bot->ClearUnitState(UNIT_STATE_CHASE); + bot->ClearUnitState(UNIT_STATE_FOLLOW); + } return true; } @@ -43,7 +43,8 @@ bool StayAction::Execute(Event event) bool StayAction::isUseful() { - return !AI_VALUE2(bool, "moving", "self target"); + // Only useful if the bot is currently moving + return AI_VALUE2(bool, "moving", "self target"); } bool SitAction::Execute(Event event) From 3e20d837bde6efd455eb6ed32a8b267aaeeadc0e Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Tue, 16 Jul 2024 11:00:19 +0800 Subject: [PATCH 51/51] [Crash fix] Owner check for AvoidAuraWithDynamicObj --- src/strategy/actions/MovementActions.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/strategy/actions/MovementActions.cpp b/src/strategy/actions/MovementActions.cpp index 6a67e01b..0dfea873 100644 --- a/src/strategy/actions/MovementActions.cpp +++ b/src/strategy/actions/MovementActions.cpp @@ -1535,6 +1535,9 @@ bool AvoidAoeAction::AvoidAuraWithDynamicObj() if (!aura || aura->IsRemoved() || aura->IsExpired()) { return false; } + if (!aura->GetOwner() || !aura->GetOwner()->IsInWorld()) { + return false; + } // Crash fix: maybe change owner due to check interval if (aura->GetType() != DYNOBJ_AURA_TYPE) { return false;