diff --git a/conf/playerbots.conf.dist b/conf/playerbots.conf.dist index 8f6122d3..235940fc 100644 --- a/conf/playerbots.conf.dist +++ b/conf/playerbots.conf.dist @@ -116,8 +116,12 @@ AiPlayerbot.RandomBotSayWithoutMaster = 0 # Automation +# Bots keep looting when group loop method is free for all +# Default: 0 (disabled) +AiPlayerbot.FreeMethodLoot = 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 = yes +AiPlayerbot.AutoPickReward = no # Bots equip upgrades (Bots will equip any item obtained from looting or a quest if they are upgrades) # Default: 0 (disabled) @@ -158,9 +162,9 @@ AiPlayerbot.AutoTeleportForLevel = 1 # Default: 1 (enabled) AiPlayerbot.AutoPickTalents = 1 -# Bot automatically upgrade equipments on levelup, may cause lagging -# Default: 0 (enabled) -AiPlayerbot.AutoUpgradeEquip = 0 +# Bot automatically upgrade equipments on levelup +# Default: 1 (enabled) +AiPlayerbot.AutoUpgradeEquip = 1 # Random Bots will pick quests on their own and try to complete # Default: 1 (enabled) diff --git a/src/LootObjectStack.cpp b/src/LootObjectStack.cpp index e3f75ae0..d9121c53 100644 --- a/src/LootObjectStack.cpp +++ b/src/LootObjectStack.cpp @@ -206,11 +206,11 @@ bool LootObject::IsLootPossible(Player* bot) if (abs(GetWorldObject(bot)->GetPositionZ() - bot->GetPositionZ()) > INTERACTION_DISTANCE) return false; - + Creature* creature = botAI->GetCreature(guid); if (creature && creature->getDeathState() == CORPSE) { - if (!creature->loot.hasItemFor(bot) && skillId != SKILL_SKINNING) + if (!bot->isAllowedToLoot(creature) && skillId != SKILL_SKINNING) return false; } @@ -290,7 +290,7 @@ std::vector LootObjectStack::OrderByDistance(float maxDistance) LootObject lootObject(bot, guid); if (!lootObject.IsLootPossible(bot)) continue; - + float distance = bot->GetDistance(lootObject.GetWorldObject(bot)); if (!maxDistance || distance <= maxDistance) sortedMap[distance] = lootObject; diff --git a/src/PlayerbotAIConfig.cpp b/src/PlayerbotAIConfig.cpp index a04b895d..f21d0864 100644 --- a/src/PlayerbotAIConfig.cpp +++ b/src/PlayerbotAIConfig.cpp @@ -306,6 +306,7 @@ bool PlayerbotAIConfig::Initialize() randomBotPreQuests = sConfigMgr->GetOption("AiPlayerbot.PreQuests", true); // SPP automation + freeMethodLoot = sConfigMgr->GetOption("AiPlayerbot.FreeMethodLoot", false); autoPickReward = sConfigMgr->GetOption("AiPlayerbot.AutoPickReward", "yes"); autoEquipUpgradeLoot = sConfigMgr->GetOption("AiPlayerbot.AutoEquipUpgradeLoot", true); syncQuestWithPlayer = sConfigMgr->GetOption("AiPlayerbot.SyncQuestWithPlayer", false); diff --git a/src/PlayerbotAIConfig.h b/src/PlayerbotAIConfig.h index 8a1a4cf4..c7f04606 100644 --- a/src/PlayerbotAIConfig.h +++ b/src/PlayerbotAIConfig.h @@ -143,6 +143,7 @@ class PlayerbotAIConfig uint32 playerbotsXPrate; uint32 botActiveAlone; + bool freeMethodLoot; std::string autoPickReward; bool autoEquipUpgradeLoot; bool syncQuestWithPlayer; diff --git a/src/PlayerbotFactory.cpp b/src/PlayerbotFactory.cpp index 7e344ad1..ff065f82 100644 --- a/src/PlayerbotFactory.cpp +++ b/src/PlayerbotFactory.cpp @@ -3043,7 +3043,9 @@ float PlayerbotFactory::CalculateItemScore(uint32 item_id, Player* bot) + defense * 0.25 + dodge * 0.25 + armor * 0.5 + stamina * 1.5 + hit * 1 + crit * 1 + haste * 0.5 + expertise * 3; } - if (proto->Class == ITEM_CLASS_ARMOR && NotSameArmorType(proto->SubClass, bot)) + // penalty for different type armor + if (proto->Class == ITEM_CLASS_ARMOR && proto->SubClass >= ITEM_SUBCLASS_ARMOR_CLOTH && + proto->SubClass <= ITEM_SUBCLASS_ARMOR_PLATE && NotSameArmorType(proto->SubClass, bot)) { score *= 0.8; } @@ -3087,8 +3089,7 @@ float PlayerbotFactory::CalculateItemScore(uint32 item_id, Player* bot) score *= 0.1; } } - return (0.0001 + score) * itemLevel * (quality + 1); - // return score; + return (0.0001 + score) * itemLevel * (quality + 1); } bool PlayerbotFactory::IsShieldTank(Player* bot) diff --git a/src/strategy/actions/LootAction.cpp b/src/strategy/actions/LootAction.cpp index ad44a916..9bcd5530 100644 --- a/src/strategy/actions/LootAction.cpp +++ b/src/strategy/actions/LootAction.cpp @@ -9,6 +9,7 @@ #include "LootStrategyValue.h" #include "LootObjectStack.h" #include "GuildTaskMgr.h" +#include "PlayerbotAIConfig.h" #include "Playerbots.h" #include "ServerFacade.h" @@ -31,6 +32,10 @@ bool LootAction::Execute(Event event) return true; } +bool LootAction::isUseful() { + return sPlayerbotAIConfig->freeMethodLoot || !bot->GetGroup() || bot->GetGroup()->GetLootMethod() != FREE_FOR_ALL; +} + enum ProfessionSpells { ALCHEMY = 2259, @@ -406,9 +411,9 @@ bool StoreLootAction::Execute(Event event) if (proto->Quality >= ITEM_QUALITY_RARE && !urand(0, 1) && botAI->HasStrategy("emote", BOT_STATE_NON_COMBAT)) botAI->PlayEmote(TEXT_EMOTE_CHEER); - std::ostringstream out; - out << "Looting " << chat->FormatItem(proto); - botAI->TellMasterNoFacing(out.str()); + // std::ostringstream out; + // out << "Looting " << chat->FormatItem(proto); + // botAI->TellMasterNoFacing(out.str()); //ItemUsage usage = AI_VALUE2(ItemUsage, "item usage", proto->ItemId); //LOG_ERROR("playerbots", "Bot {} is looting {} {} for usage {}.", bot->GetName().c_str(), itemcount, proto->Name1.c_str(), usage); @@ -442,10 +447,7 @@ bool StoreLootAction::IsLootAllowed(uint32 itemid, PlayerbotAI* botAI) if (proto->StartQuest) { - if (sPlayerbotAIConfig->syncQuestWithPlayer) - return false; //Quest is autocomplete for the bot so no item needed. - else - return true; + return true; } for (uint8 slot = 0; slot < MAX_QUEST_LOG_SIZE; ++slot) @@ -459,14 +461,13 @@ bool StoreLootAction::IsLootAllowed(uint32 itemid, PlayerbotAI* botAI) { if (quest->RequiredItemId[i] == itemid) { - if (quest->RequiredItemId[i] == itemid && AI_VALUE2(uint32, "item count", proto->Name1) < quest->RequiredItemCount[i]) + if (AI_VALUE2(uint32, "item count", proto->Name1) < quest->RequiredItemCount[i]) { if (botAI->GetMaster() && sPlayerbotAIConfig->syncQuestWithPlayer) return false; //Quest is autocomplete for the bot so no item needed. } - if (AI_VALUE2(uint32, "item count", proto->Name1) < quest->RequiredItemCount[i]) - return false; + return true; } } } diff --git a/src/strategy/actions/LootAction.h b/src/strategy/actions/LootAction.h index 17fd6fe9..847d8c9d 100644 --- a/src/strategy/actions/LootAction.h +++ b/src/strategy/actions/LootAction.h @@ -19,6 +19,7 @@ class LootAction : public MovementAction LootAction(PlayerbotAI* botAI) : MovementAction(botAI, "loot") { } bool Execute(Event event) override; + bool isUseful() override; }; class OpenLootAction : public MovementAction diff --git a/src/strategy/values/ItemUsageValue.cpp b/src/strategy/values/ItemUsageValue.cpp index a2a40f6f..f07cf635 100644 --- a/src/strategy/values/ItemUsageValue.cpp +++ b/src/strategy/values/ItemUsageValue.cpp @@ -78,7 +78,7 @@ ItemUsage ItemUsageValue::Calculate() } } } - + if (bot->GetGuildId() && sGuildTaskMgr->IsGuildTaskItem(itemId, bot->GetGuildId())) return ITEM_USAGE_GUILD_TASK; @@ -202,13 +202,13 @@ ItemUsage ItemUsageValue::QueryItemUsageForEquip(ItemTemplate const* itemProto) return ITEM_USAGE_BAD_EQUIP; ItemTemplate const* oldItemProto = oldItem->GetTemplate(); + float oldScore = PlayerbotFactory::CalculateItemScore(oldItemProto->ItemId, bot); if (oldItem) { // uint32 oldStatWeight = sRandomItemMgr->GetLiveStatWeight(bot, oldItemProto->ItemId); - float oldScore = PlayerbotFactory::CalculateItemScore(oldItemProto->ItemId, bot); if (itemScore || oldScore) { - shouldEquip = itemScore >= oldScore * 1.5; + shouldEquip = itemScore > oldScore * 1.1; } } @@ -226,17 +226,17 @@ ItemUsage ItemUsageValue::QueryItemUsageForEquip(ItemTemplate const* itemProto) if (oldItemProto->Class == ITEM_CLASS_ARMOR && !sRandomItemMgr->CanEquipArmor(bot->getClass(), bot->getLevel(), oldItemProto)) existingShouldEquip = false; - uint32 oldItemPower = sRandomItemMgr->GetLiveStatWeight(bot, oldItemProto->ItemId); - uint32 newItemPower = sRandomItemMgr->GetLiveStatWeight(bot, itemProto->ItemId); + // uint32 oldItemPower = sRandomItemMgr->GetLiveStatWeight(bot, oldItemProto->ItemId); + // uint32 newItemPower = sRandomItemMgr->GetLiveStatWeight(bot, itemProto->ItemId); //Compare items based on item level, quality or itemId. bool isBetter = false; - if (newItemPower > oldItemPower) - isBetter = true; - else if (newItemPower == oldItemPower && itemProto->Quality > oldItemProto->Quality) - isBetter = true; - else if (newItemPower == oldItemPower && itemProto->Quality == oldItemProto->Quality && itemProto->ItemId > oldItemProto->ItemId) + if (itemScore > oldScore) isBetter = true; + // else if (newItemPower == oldScore && itemProto->Quality > oldItemProto->Quality) + // isBetter = true; + // else if (newItemPower == oldScore && itemProto->Quality == oldItemProto->Quality && itemProto->ItemId > oldItemProto->ItemId) + // isBetter = true; Item* item = CurrentItem(itemProto); bool itemIsBroken = item && item->GetUInt32Value(ITEM_FIELD_DURABILITY) == 0 && item->GetUInt32Value(ITEM_FIELD_MAXDURABILITY) > 0;