From d31fbc0353a6b298ffef71d9058c4e02f50da68d Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Sat, 5 Aug 2023 18:41:15 +0800 Subject: [PATCH] automatically action for random bots --- conf/playerbots.conf.dist | 27 +++-- src/PlayerbotAIConfig.cpp | 6 +- src/PlayerbotAIConfig.h | 4 +- src/PlayerbotFactory.cpp | 8 +- src/PlayerbotFactory.h | 8 +- src/RandomPlayerbotMgr.cpp | 4 +- src/strategy/actions/ActionContext.h | 3 + src/strategy/actions/AutoLearnSpellAction.cpp | 110 +++++++++--------- .../actions/AutoTeleportForLevelAction.cpp | 24 ++++ .../actions/AutoTeleportForLevelAction.h | 22 ++++ src/strategy/actions/ChangeTalentsAction.cpp | 10 +- .../generic/WorldPacketHandlerStrategy.cpp | 6 +- 12 files changed, 153 insertions(+), 79 deletions(-) create mode 100644 src/strategy/actions/AutoTeleportForLevelAction.cpp create mode 100644 src/strategy/actions/AutoTeleportForLevelAction.h diff --git a/conf/playerbots.conf.dist b/conf/playerbots.conf.dist index b9ff26be..e8bacd6b 100644 --- a/conf/playerbots.conf.dist +++ b/conf/playerbots.conf.dist @@ -109,7 +109,7 @@ AiPlayerbot.GearScoreCheck = 0 AiPlayerbot.RandomBotQuestIds = "7848,3802,5505,6502,7761" # Randombots will group with nearby bots to do shared quests -AiPlayerbot.RandomBotGroupNearby = 1 +AiPlayerbot.RandomBotGroupNearby = 0 # Bots without a master will say their lines AiPlayerbot.RandomBotSayWithoutMaster = 0 @@ -142,19 +142,28 @@ 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) AiPlayerbot.AutoTrainSpells = yes -# Bot automatically picks talent points based on current spec (full = pick spec based on probability if multiple are like current spec, semi = only apply points if 1 spec looks like current spec, no = no auto talent points) -AiPlayerbot.AutoPickTalents = no - -# Bots automatically learn trainable spells on levelup -# Default: 0 (disabled) -AiPlayerbot.AutoLearnTrainerSpells = 0 - # 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 + +# Bots automatically teleport to another place for leveling on levelup +# Default: 1 (enabled) +AiPlayerbot.AutoTeleportForLevel = 1 + +# Bot automatically picks talent points on levelup +# Default: 1 (enabled) +AiPlayerbot.AutoPickTalents = 1 + +# Bot automatically upgrade equipments on levelup, may cause lagging +# Default: 0 (enabled) +AiPlayerbot.AutoUpgradeEquip = 0 + # Random Bots will pick quests on their own and try to complete -# Default: 0 (disabled) +# Default: 1 (enabled) AiPlayerbot.AutoDoQuests = 1 ################################################################################## diff --git a/src/PlayerbotAIConfig.cpp b/src/PlayerbotAIConfig.cpp index db30eda1..a04b895d 100644 --- a/src/PlayerbotAIConfig.cpp +++ b/src/PlayerbotAIConfig.cpp @@ -311,9 +311,11 @@ bool PlayerbotAIConfig::Initialize() syncQuestWithPlayer = sConfigMgr->GetOption("AiPlayerbot.SyncQuestWithPlayer", false); syncQuestForPlayer = sConfigMgr->GetOption("AiPlayerbot.SyncQuestForPlayer", false); autoTrainSpells = sConfigMgr->GetOption("AiPlayerbot.AutoTrainSpells", "yes"); - autoPickTalents = sConfigMgr->GetOption("AiPlayerbot.AutoPickTalents", "full"); - autoLearnTrainerSpells = sConfigMgr->GetOption("AiPlayerbot.AutoLearnTrainerSpells", false); + autoPickTalents = sConfigMgr->GetOption("AiPlayerbot.AutoPickTalents", true); + autoUpgradeEquip = sConfigMgr->GetOption("AiPlayerbot.AutoUpgradeEquip", false); + autoLearnTrainerSpells = sConfigMgr->GetOption("AiPlayerbot.AutoLearnTrainerSpells", true); autoLearnQuestSpells = sConfigMgr->GetOption("AiPlayerbot.AutoLearnQuestSpells", false); + autoTeleportForLevel = sConfigMgr->GetOption("AiPlayerbot.AutoTeleportForLevel", false); autoDoQuests = sConfigMgr->GetOption("AiPlayerbot.AutoDoQuests", false); syncLevelWithPlayers = sConfigMgr->GetOption("AiPlayerbot.SyncLevelWithPlayers", false); freeFood = sConfigMgr->GetOption("AiPlayerbot.FreeFood", true); diff --git a/src/PlayerbotAIConfig.h b/src/PlayerbotAIConfig.h index 94d39147..8a1a4cf4 100644 --- a/src/PlayerbotAIConfig.h +++ b/src/PlayerbotAIConfig.h @@ -148,12 +148,14 @@ class PlayerbotAIConfig bool syncQuestWithPlayer; bool syncQuestForPlayer; std::string autoTrainSpells; - std::string autoPickTalents; + bool autoPickTalents; + bool autoUpgradeEquip; bool autoLearnTrainerSpells; bool autoDoQuests; bool syncLevelWithPlayers; bool freeFood; bool autoLearnQuestSpells; + bool autoTeleportForLevel; bool randomBotSayWithoutMaster; bool randomBotGroupNearby; uint32 tweakValue; //Debugging config diff --git a/src/PlayerbotFactory.cpp b/src/PlayerbotFactory.cpp index d31990ca..3eedaf40 100644 --- a/src/PlayerbotFactory.cpp +++ b/src/PlayerbotFactory.cpp @@ -1149,12 +1149,14 @@ void PlayerbotFactory::InitEquipmentNew(bool incremental) void PlayerbotFactory::InitEquipment(bool incremental) { + // todo(yunfan): to be refactored, too much time overhead - DestroyItemsVisitor visitor(bot); - IterateItems(&visitor, ITERATE_ALL_ITEMS); + // DestroyItemsVisitor visitor(bot); + // IterateItems(&visitor, ITERATE_ALL_ITEMS); std::map > items; int tab = AiFactory::GetPlayerSpecTab(bot); + // todo(yunfan): make cache for this for(uint8 slot = 0; slot < EQUIPMENT_SLOT_END; ++slot) { if (slot == EQUIPMENT_SLOT_TABARD || slot == EQUIPMENT_SLOT_BODY) @@ -1277,7 +1279,7 @@ bool PlayerbotFactory::IsDesiredReplacement(Item* item) { requiredLevel = sRandomItemMgr->GetMinLevelFromCache(proto->ItemId); } - + uint32 delta = 1 + (80 - bot->getLevel()) / 10; return int32(bot->getLevel() - requiredLevel) > delta; } diff --git a/src/PlayerbotFactory.h b/src/PlayerbotFactory.h index 9418b85a..4e675084 100644 --- a/src/PlayerbotFactory.h +++ b/src/PlayerbotFactory.h @@ -115,11 +115,14 @@ class PlayerbotFactory : public InventoryAction static uint32 tradeSkills[]; static float CalculateItemScore(uint32 item_id, Player* bot); + void InitTalentsTree(bool incremental = false, bool use_template = true); + void InitAvailableSpells(); + void InitClassSpells(); + void InitEquipment(bool incremental); private: void Prepare(); void InitSecondEquipmentSet(); - void InitEquipment(bool incremental); void InitEquipmentNew(bool incremental); bool CanEquipItem(ItemTemplate const* proto, uint32 desiredQuality); bool CanEquipUnseenItem(uint8 slot, uint16& dest, uint32 item); @@ -129,10 +132,7 @@ class PlayerbotFactory : public InventoryAction void InitSpells(); void ClearSpells(); void ClearSkills(); - void InitAvailableSpells(); - void InitClassSpells(); void InitSpecialSpells(); - void InitTalentsTree(bool incremental = false, bool use_template = true); void InitTalents(uint32 specNo); void InitTalentsByTemplate(uint32 specNo); void InitQuests(std::list& questMap); diff --git a/src/RandomPlayerbotMgr.cpp b/src/RandomPlayerbotMgr.cpp index ec7e4dbb..bf941da0 100644 --- a/src/RandomPlayerbotMgr.cpp +++ b/src/RandomPlayerbotMgr.cpp @@ -800,7 +800,7 @@ bool RandomPlayerbotMgr::ProcessBot(uint32 bot) AddPlayerBot(botGUID, 0); SetEventValue(bot, "login", 1, sPlayerbotAIConfig->randomBotUpdateInterval); - uint32 randomTime = urand(sPlayerbotAIConfig->minRandomBotReviveTime, sPlayerbotAIConfig->maxRandomBotReviveTime * 5); + uint32 randomTime = urand(sPlayerbotAIConfig->minRandomBotReviveTime, sPlayerbotAIConfig->maxRandomBotReviveTime); SetEventValue(bot, "update", 1, randomTime); return true; @@ -812,7 +812,7 @@ bool RandomPlayerbotMgr::ProcessBot(uint32 bot) return false; uint32 update = GetEventValue(bot, "update"); - if (!update && !sPlayerbotAIConfig->disableRandomLevels) + if (!update) { if (botAI) botAI->GetAiObjectContext()->GetValue("random bot update")->Set(true); diff --git a/src/strategy/actions/ActionContext.h b/src/strategy/actions/ActionContext.h index bfbc620f..4d77159c 100644 --- a/src/strategy/actions/ActionContext.h +++ b/src/strategy/actions/ActionContext.h @@ -58,6 +58,7 @@ #include "VehicleActions.h" #include "WorldBuffAction.h" #include "RaidNaxxActions.h" +#include "AutoTeleportForLevelAction.h" class PlayerbotAI; @@ -146,6 +147,7 @@ class ActionContext : public NamedObjectContext creators["war stomp"] = &ActionContext::war_stomp; 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["xp gain"] = &ActionContext::xp_gain; creators["invite nearby"] = &ActionContext::invite_nearby; creators["invite guild"] = &ActionContext::invite_guild; @@ -308,6 +310,7 @@ class ActionContext : public NamedObjectContext static Action* war_stomp(PlayerbotAI* botAI) { return new CastWarStompAction(botAI); } 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* 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 f1cc813b..106e68a9 100644 --- a/src/strategy/actions/AutoLearnSpellAction.cpp +++ b/src/strategy/actions/AutoLearnSpellAction.cpp @@ -4,6 +4,7 @@ #include "AutoLearnSpellAction.h" #include "Event.h" +#include "PlayerbotFactory.h" #include "Playerbots.h" bool AutoLearnSpellAction::Execute(Event event) @@ -30,78 +31,81 @@ bool AutoLearnSpellAction::Execute(Event event) void AutoLearnSpellAction::LearnSpells(std::ostringstream* out) { - if (sPlayerbotAIConfig->autoLearnTrainerSpells)// || (!botAI->GetMaster() && sRandomPlayerbotMgr->IsRandomBot(bot))) + if (sPlayerbotAIConfig->autoLearnTrainerSpells && sRandomPlayerbotMgr->IsRandomBot(bot))// || (!botAI->GetMaster() && sRandomPlayerbotMgr->IsRandomBot(bot))) LearnTrainerSpells(out); - if (sPlayerbotAIConfig->autoLearnQuestSpells)// || (!botAI->GetMaster() && sRandomPlayerbotMgr->IsRandomBot(bot))) + if (sPlayerbotAIConfig->autoLearnQuestSpells && sRandomPlayerbotMgr->IsRandomBot(bot))// || (!botAI->GetMaster() && sRandomPlayerbotMgr->IsRandomBot(bot))) LearnQuestSpells(out); } void AutoLearnSpellAction::LearnTrainerSpells(std::ostringstream* out) { - bot->LearnDefaultSkills(); + PlayerbotFactory factory(bot, bot->GetLevel()); + factory.InitClassSpells(); + factory.InitAvailableSpells(); + // bot->LearnDefaultSkills(); - CreatureTemplateContainer const* creatureTemplateContainer = sObjectMgr->GetCreatureTemplates(); - for (CreatureTemplateContainer::const_iterator i = creatureTemplateContainer->begin(); i != creatureTemplateContainer->end(); ++i) - { - CreatureTemplate const& co = i->second; - if (co.trainer_type != TRAINER_TYPE_TRADESKILLS && co.trainer_type != TRAINER_TYPE_CLASS) - continue; + // CreatureTemplateContainer const* creatureTemplateContainer = sObjectMgr->GetCreatureTemplates(); + // for (CreatureTemplateContainer::const_iterator i = creatureTemplateContainer->begin(); i != creatureTemplateContainer->end(); ++i) + // { + // CreatureTemplate const& co = i->second; + // if (co.trainer_type != TRAINER_TYPE_TRADESKILLS && co.trainer_type != TRAINER_TYPE_CLASS) + // continue; - if (co.trainer_type == TRAINER_TYPE_CLASS && co.trainer_class != bot->getClass()) - continue; + // if (co.trainer_type == TRAINER_TYPE_CLASS && co.trainer_class != bot->getClass()) + // continue; - uint32 trainerId = co.Entry; + // uint32 trainerId = co.Entry; - TrainerSpellData const* trainer_spells = sObjectMgr->GetNpcTrainerSpells(trainerId); - if (!trainer_spells) - trainer_spells = sObjectMgr->GetNpcTrainerSpells(trainerId); + // TrainerSpellData const* trainer_spells = sObjectMgr->GetNpcTrainerSpells(trainerId); + // if (!trainer_spells) + // trainer_spells = sObjectMgr->GetNpcTrainerSpells(trainerId); - if (!trainer_spells) - continue; + // if (!trainer_spells) + // continue; - for (TrainerSpellMap::const_iterator itr = trainer_spells->spellList.begin(); itr != trainer_spells->spellList.end(); ++itr) - { - TrainerSpell const* tSpell = &itr->second; + // for (TrainerSpellMap::const_iterator itr = trainer_spells->spellList.begin(); itr != trainer_spells->spellList.end(); ++itr) + // { + // TrainerSpell const* tSpell = &itr->second; - if (!tSpell) - continue; + // if (!tSpell) + // continue; - if (!tSpell->learnedSpell[0] && !bot->IsSpellFitByClassAndRace(tSpell->learnedSpell[0])) - continue; + // if (!tSpell->learnedSpell[0] && !bot->IsSpellFitByClassAndRace(tSpell->learnedSpell[0])) + // continue; - TrainerSpellState state = bot->GetTrainerSpellState(tSpell); - if (state != TRAINER_SPELL_GREEN) - continue; + // TrainerSpellState state = bot->GetTrainerSpellState(tSpell); + // if (state != TRAINER_SPELL_GREEN) + // continue; - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(tSpell->spell); - bool learn = true; - for (uint8 j = 0; j < 3; ++j) - { - if (!tSpell->learnedSpell[j] && !bot->IsSpellFitByClassAndRace(tSpell->learnedSpell[j])) - continue; + // SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(tSpell->spell); + // bool learn = true; + // for (uint8 j = 0; j < 3; ++j) + // { + // if (!tSpell->learnedSpell[j] && !bot->IsSpellFitByClassAndRace(tSpell->learnedSpell[j])) + // continue; - if (spellInfo->Effects[j].Effect == SPELL_EFFECT_PROFICIENCY || - spellInfo->Effects[j].Effect == SPELL_EFFECT_SKILL_STEP || - spellInfo->Effects[j].Effect == SPELL_EFFECT_DUAL_WIELD) - { - learn = false; - break; - } - } - if (!learn) { - continue; - } + // if (spellInfo->Effects[j].Effect == SPELL_EFFECT_PROFICIENCY || + // spellInfo->Effects[j].Effect == SPELL_EFFECT_SKILL_STEP || + // spellInfo->Effects[j].Effect == SPELL_EFFECT_DUAL_WIELD) + // { + // learn = false; + // break; + // } + // } + // if (!learn) { + // continue; + // } - if (tSpell->learnedSpell[0]) { - bot->learnSpell(tSpell->learnedSpell[0], false); - } - else { - LOG_INFO("playerbots", "!tSpell->learnedSpell[0] {}", tSpell->spell); - botAI->CastSpell(tSpell->spell, bot); - } - } - } + // if (tSpell->learnedSpell[0]) { + // bot->learnSpell(tSpell->learnedSpell[0], false); + // } + // else { + // LOG_INFO("playerbots", "!tSpell->learnedSpell[0] {}", tSpell->spell); + // botAI->CastSpell(tSpell->spell, bot); + // } + // } + // } } void AutoLearnSpellAction::LearnQuestSpells(std::ostringstream* out) diff --git a/src/strategy/actions/AutoTeleportForLevelAction.cpp b/src/strategy/actions/AutoTeleportForLevelAction.cpp new file mode 100644 index 00000000..3f1fa33a --- /dev/null +++ b/src/strategy/actions/AutoTeleportForLevelAction.cpp @@ -0,0 +1,24 @@ +#include "AutoTeleportForLevelAction.h" +#include "PlayerbotAIConfig.h" +#include "PlayerbotFactory.h" +#include "RandomPlayerbotMgr.h" +#include "Playerbots.h" +#include "SharedDefines.h" + +bool AutoTeleportForLevelAction::Execute(Event event) { + AutoUpgradeEquip(); + + if (!sPlayerbotAIConfig->autoTeleportForLevel || !sRandomPlayerbotMgr->IsRandomBot(bot)) { + return false; + } + sRandomPlayerbotMgr->RandomTeleportForLevel(bot); + return true; +} + +void AutoTeleportForLevelAction::AutoUpgradeEquip() { + if (!sPlayerbotAIConfig->autoUpgradeEquip || !sRandomPlayerbotMgr->IsRandomBot(bot)) { + return; + } + PlayerbotFactory factory(bot, bot->GetLevel(), ITEM_QUALITY_RARE); + factory.InitEquipment(true); +} \ No newline at end of file diff --git a/src/strategy/actions/AutoTeleportForLevelAction.h b/src/strategy/actions/AutoTeleportForLevelAction.h new file mode 100644 index 00000000..c8397d53 --- /dev/null +++ b/src/strategy/actions/AutoTeleportForLevelAction.h @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2016+ AzerothCore , released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version. + */ + +#ifndef _PLAYERBOT_AUTOTELEPORTFORLEVELACTION_H +#define _PLAYERBOT_AUTOTELEPORTFORLEVELACTION_H + +#include "Action.h" + +class PlayerbotAI; + +class AutoTeleportForLevelAction : public Action +{ + public: + 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/actions/ChangeTalentsAction.cpp b/src/strategy/actions/ChangeTalentsAction.cpp index fd7d3a55..17a0d0a6 100644 --- a/src/strategy/actions/ChangeTalentsAction.cpp +++ b/src/strategy/actions/ChangeTalentsAction.cpp @@ -5,6 +5,7 @@ #include "ChangeTalentsAction.h" #include "ChatHelper.h" #include "Event.h" +#include "PlayerbotFactory.h" #include "Playerbots.h" bool ChangeTalentsAction::Execute(Event event) @@ -82,7 +83,7 @@ bool ChangeTalentsAction::Execute(Event event) out.str(""); out.clear(); - if (paths.size() > 1 && sPlayerbotAIConfig->autoPickTalents != "full") + if (paths.size() > 1 && false/*!sPlayerbotAIConfig->autoPickTalents*/) { out << "Found multiple specs: "; listPremadePaths(paths, &out); @@ -278,7 +279,7 @@ bool ChangeTalentsAction::AutoSelectTalents(std::ostringstream* out) specId = -1; // specLink = ""; } - else if (paths.size() > 1 && sPlayerbotAIConfig->autoPickTalents != "full" && !sRandomPlayerbotMgr->IsRandomBot(bot)) + else if (paths.size() > 1 && false/*!sPlayerbotAIConfig->autoPickTalents*/ && !sRandomPlayerbotMgr->IsRandomBot(bot)) { *out << "Found multiple specs: "; listPremadePaths(paths, out); @@ -328,13 +329,14 @@ bool AutoSetTalentsAction::Execute(Event event) { std::ostringstream out; - if (sPlayerbotAIConfig->autoPickTalents == "no" && !sRandomPlayerbotMgr->IsRandomBot(bot)) + if (!sPlayerbotAIConfig->autoPickTalents || !sRandomPlayerbotMgr->IsRandomBot(bot)) return false; if (bot->GetFreeTalentPoints() <= 0) return false; - AutoSelectTalents(&out); + PlayerbotFactory factory(bot, bot->GetLevel()); + factory.InitTalentsTree(true); botAI->TellMaster(out); diff --git a/src/strategy/generic/WorldPacketHandlerStrategy.cpp b/src/strategy/generic/WorldPacketHandlerStrategy.cpp index 5e27b7e9..b06b3a6a 100644 --- a/src/strategy/generic/WorldPacketHandlerStrategy.cpp +++ b/src/strategy/generic/WorldPacketHandlerStrategy.cpp @@ -35,7 +35,11 @@ void WorldPacketHandlerStrategy::InitTriggers(std::vector& trigger //triggers.push_back(new TriggerNode("no non bot players around", NextAction::array(0, new NextAction("delay", relevance), nullptr))); 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), 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), + nullptr))); triggers.push_back(new TriggerNode("see spell", NextAction::array(0, new NextAction("see spell", relevance), nullptr))); triggers.push_back(new TriggerNode("release spirit", NextAction::array(0, new NextAction("release", relevance), nullptr))); triggers.push_back(new TriggerNode("revive from corpse", NextAction::array(0, new NextAction("revive from corpse", relevance), nullptr)));