diff --git a/conf/playerbots.conf.dist b/conf/playerbots.conf.dist index 6580b845..09969ccb 100644 --- a/conf/playerbots.conf.dist +++ b/conf/playerbots.conf.dist @@ -790,7 +790,7 @@ AiPlayerbot.PremadeSpecLink.2.0.80 = 50350152220013053100515221-503201312 AiPlayerbot.PremadeSpecName.2.1 = prot pve AiPlayerbot.PremadeSpecGlyph.2.1 = 41100,43367,43869,43369,43365,45745 AiPlayerbot.PremadeSpecLink.2.1.60 = -05005135203102311333112321 -AiPlayerbot.PremadeSpecLink.2.1.80 = -05005135203132311333312321-5023005 +AiPlayerbot.PremadeSpecLink.2.1.80 = -05005135203102311333312321-502302012003 AiPlayerbot.PremadeSpecName.2.2 = ret pve AiPlayerbot.PremadeSpecGlyph.2.2 = 41092,43367,41099,43369,43365,43869 AiPlayerbot.PremadeSpecLink.2.2.60 = --05230051203331302133231131 diff --git a/src/PlayerbotAI.cpp b/src/PlayerbotAI.cpp index 7a4a803f..d319b05f 100644 --- a/src/PlayerbotAI.cpp +++ b/src/PlayerbotAI.cpp @@ -11,6 +11,7 @@ #include "AiFactory.h" #include "BudgetValues.h" +#include "ChannelMgr.h" #include "CharacterPackets.h" #include "CreatureAIImpl.h" #include "EmoteAction.h" @@ -45,10 +46,6 @@ #include "Unit.h" #include "UpdateTime.h" #include "Vehicle.h" -#include "GuildMgr.h" -#include "SayAction.h" -#include "ChannelMgr.h" - std::vector PlayerbotAI::dispel_whitelist = { "mutating injection", @@ -351,11 +348,12 @@ void PlayerbotAI::UpdateAIInternal([[maybe_unused]] uint32 elapsed, bool minimal return; std::string const mapString = WorldPosition(bot).isOverworld() ? std::to_string(bot->GetMapId()) : "I"; - PerformanceMonitorOperation* pmo = sPerformanceMonitor->start(PERF_MON_TOTAL, "PlayerbotAI::UpdateAIInternal " + mapString); + PerformanceMonitorOperation* pmo = + sPerformanceMonitor->start(PERF_MON_TOTAL, "PlayerbotAI::UpdateAIInternal " + mapString); ExternalEventHelper helper(aiObjectContext); // chat replies - for (auto it = chatReplies.begin(); it != chatReplies.end(); ) + for (auto it = chatReplies.begin(); it != chatReplies.end();) { time_t checkTime = it->m_time; if (checkTime && time(0) < checkTime) @@ -425,7 +423,7 @@ void PlayerbotAI::UpdateAIInternal([[maybe_unused]] uint32 elapsed, bool minimal void PlayerbotAI::HandleCommands() { ExternalEventHelper helper(aiObjectContext); - for (auto it = chatCommands.begin(); it != chatCommands.end(); ) + for (auto it = chatCommands.begin(); it != chatCommands.end();) { time_t& checkTime = it->GetTime(); if (checkTime && time(0) < checkTime) @@ -438,9 +436,9 @@ void PlayerbotAI::HandleCommands() Player* owner = it->GetOwner(); if (!helper.ParseChatCommand(command, owner) && it->GetType() == CHAT_MSG_WHISPER) { - //ostringstream out; out << "Unknown command " << command; - //TellPlayer(out); - //helper.ParseChatCommand("help"); + // ostringstream out; out << "Unknown command " << command; + // TellPlayer(out); + // helper.ParseChatCommand("help"); } it = chatCommands.erase(it); } @@ -451,15 +449,16 @@ void PlayerbotAI::HandleCommand(uint32 type, const std::string& text, Player& fr { std::string filtered = text; - if (!IsAllowedCommand(filtered) && !GetSecurity()->CheckLevelFor(PlayerbotSecurityLevel::PLAYERBOT_SECURITY_INVITE, type != CHAT_MSG_WHISPER, &fromPlayer)) + if (!IsAllowedCommand(filtered) && !GetSecurity()->CheckLevelFor(PlayerbotSecurityLevel::PLAYERBOT_SECURITY_INVITE, + type != CHAT_MSG_WHISPER, &fromPlayer)) return; if (type == CHAT_MSG_ADDON) return; - if (filtered.find("BOT\t") == 0) //Mangosbot has BOT prefix so we remove that. + if (filtered.find("BOT\t") == 0) // Mangosbot has BOT prefix so we remove that. filtered = filtered.substr(4); - else if (lang == LANG_ADDON) //Other addon messages should not command bots. + else if (lang == LANG_ADDON) // Other addon messages should not command bots. return; if (type == CHAT_MSG_SYSTEM) @@ -511,22 +510,26 @@ void PlayerbotAI::HandleCommand(uint32 type, const std::string& text, Player& fr { std::string response = HandleRemoteCommand(filtered.substr(6)); WorldPacket data; - ChatHandler::BuildChatPacket(data, CHAT_MSG_ADDON, response.c_str(), LANG_ADDON, - CHAT_TAG_NONE, bot->GetGUID(), bot->GetName()); + ChatHandler::BuildChatPacket(data, CHAT_MSG_ADDON, response.c_str(), LANG_ADDON, CHAT_TAG_NONE, bot->GetGUID(), + bot->GetName()); sServerFacade->SendPacket(&fromPlayer, &data); return; } - if (!IsAllowedCommand(filtered) && !GetSecurity()->CheckLevelFor(PlayerbotSecurityLevel::PLAYERBOT_SECURITY_ALLOW_ALL, type != CHAT_MSG_WHISPER, &fromPlayer)) + if (!IsAllowedCommand(filtered) && + !GetSecurity()->CheckLevelFor(PlayerbotSecurityLevel::PLAYERBOT_SECURITY_ALLOW_ALL, type != CHAT_MSG_WHISPER, + &fromPlayer)) return; - if (type == CHAT_MSG_RAID_WARNING && filtered.find(bot->GetName()) != std::string::npos && filtered.find("award") == std::string::npos) + if (type == CHAT_MSG_RAID_WARNING && filtered.find(bot->GetName()) != std::string::npos && + filtered.find("award") == std::string::npos) { chatCommands.push_back(ChatCommandHolder("warning", &fromPlayer, type)); return; } - if ((filtered.size() > 2 && filtered.substr(0, 2) == "d ") || (filtered.size() > 3 && filtered.substr(0, 3) == "do ")) + if ((filtered.size() > 2 && filtered.substr(0, 2) == "d ") || + (filtered.size() > 3 && filtered.substr(0, 3) == "do ")) { Event event("do", "", &fromPlayer); std::string action = filtered.substr(filtered.find(" ") + 1); @@ -590,7 +593,8 @@ void PlayerbotAI::HandleCommand(uint32 type, const std::string& text, Player& fr SetShouldLogOut(false); } } - else if ((filtered.size() > 5) && (filtered.substr(0, 5) == "wait ") && (filtered.find("wait for attack") == std::string::npos)) + else if ((filtered.size() > 5) && (filtered.substr(0, 5) == "wait ") && (filtered.find("wait for attack") == + std::string::npos)) { std::string remaining = filtered.substr(filtered.find(" ") + 1); uint32 delay = atof(remaining.c_str()) * IN_MILLISECONDS; @@ -928,10 +932,10 @@ void PlayerbotAI::HandleBotOutgoingPacket(WorldPacket const& packet) { if (!sPlayerbotAIConfig->randomBotTalk) return; - + if (!AllowActivity()) return; - + WorldPacket p(packet); if (!p.empty() && (p.GetOpcode() == SMSG_MESSAGECHAT || p.GetOpcode() == SMSG_GM_MESSAGECHAT)) { @@ -998,29 +1002,32 @@ void PlayerbotAI::HandleBotOutgoingPacket(WorldPacket const& packet) if (lang == LANG_ADDON) return; - if (message.starts_with(sPlayerbotAIConfig->toxicLinksPrefix) - && (GetChatHelper()->ExtractAllItemIds(message).size() > 0 || GetChatHelper()->ExtractAllQuestIds(message).size() > 0) - && sPlayerbotAIConfig->toxicLinksRepliesChance) - { - if (urand(0, 50) > 0 || urand(1, 100) > sPlayerbotAIConfig->toxicLinksRepliesChance) - { - return; - } - } - else if ((GetChatHelper()->ExtractAllItemIds(message).count(19019) && sPlayerbotAIConfig->thunderfuryRepliesChance)) - { - if (urand(0, 60) > 0 || urand(1, 100) > sPlayerbotAIConfig->thunderfuryRepliesChance) - { - return; - } - } - else + // Disable since ExtractAllItemIds bad performance + // if (message.starts_with(sPlayerbotAIConfig->toxicLinksPrefix) && + // (GetChatHelper()->ExtractAllItemIds(message).size() > 0 || + // GetChatHelper()->ExtractAllQuestIds(message).size() > 0) && + // sPlayerbotAIConfig->toxicLinksRepliesChance) + // { + // if (urand(0, 50) > 0 || urand(1, 100) > sPlayerbotAIConfig->toxicLinksRepliesChance) + // { + // return; + // } + // } + // else if ((GetChatHelper()->ExtractAllItemIds(message).count(19019) && + // sPlayerbotAIConfig->thunderfuryRepliesChance)) + // { + // if (urand(0, 60) > 0 || urand(1, 100) > sPlayerbotAIConfig->thunderfuryRepliesChance) + // { + // return; + // } + // } + // else { if (isFromFreeBot && urand(0, 20)) return; - //if (msgtype == CHAT_MSG_GUILD && (!sPlayerbotAIConfig->guildRepliesRate || urand(1, 100) >= sPlayerbotAIConfig->guildRepliesRate)) - //return; + // if (msgtype == CHAT_MSG_GUILD && (!sPlayerbotAIConfig->guildRepliesRate || urand(1, 100) >= + // sPlayerbotAIConfig->guildRepliesRate)) return; if (!isFromFreeBot) { @@ -1034,7 +1041,9 @@ void PlayerbotAI::HandleBotOutgoingPacket(WorldPacket const& packet) } } - QueueChatResponse(std::move(ChatQueuedReply{msgtype, guid1.GetCounter(), guid2.GetCounter(), message, chanName, name, time(nullptr) + urand(inCombat ? 10 : 5, inCombat ? 25 : 15)})); + QueueChatResponse( + std::move(ChatQueuedReply{msgtype, guid1.GetCounter(), guid2.GetCounter(), message, chanName, + name, time(nullptr) + urand(inCombat ? 10 : 5, inCombat ? 25 : 15)})); GetAiObjectContext()->GetValue("last said", "chat")->Set(time(0) + urand(5, 25)); return; } @@ -2182,19 +2191,21 @@ WorldObject* PlayerbotAI::GetWorldObject(ObjectGuid guid) const AreaTableEntry* PlayerbotAI::GetCurrentArea() { - return sAreaTableStore.LookupEntry(bot->GetMap()->GetAreaId(bot->GetPhaseMask(), bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ())); + return sAreaTableStore.LookupEntry( + bot->GetMap()->GetAreaId(bot->GetPhaseMask(), bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ())); } const AreaTableEntry* PlayerbotAI::GetCurrentZone() { - return sAreaTableStore.LookupEntry(bot->GetMap()->GetZoneId(bot->GetPhaseMask(), bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ())); + return sAreaTableStore.LookupEntry( + bot->GetMap()->GetZoneId(bot->GetPhaseMask(), bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ())); } std::string PlayerbotAI::GetLocalizedAreaName(const AreaTableEntry* entry) { if (entry) return entry->area_name[sWorld->GetDefaultDbcLocale()]; - + return ""; } @@ -2254,7 +2265,7 @@ bool PlayerbotAI::SayToWorld(const std::string& msg) if (!cMgr) return false; - //no zone + // no zone if (Channel* worldChannel = cMgr->GetChannel("World", bot)) { worldChannel->Say(bot->GetGUID(), msg.c_str(), LANG_UNIVERSAL); @@ -2277,7 +2288,7 @@ bool PlayerbotAI::SayToChannel(const std::string& msg, const ChatChannelId& chan const auto current_str_zone = GetLocalizedAreaName(current_zone); for (auto const& [key, channel] : cMgr->GetChannels()) { - //check for current zone + // check for current zone if (channel && channel->GetChannelId() == chanId) { const auto does_contains = channel->GetName().find(current_str_zone) != std::string::npos; @@ -2304,7 +2315,8 @@ bool PlayerbotAI::SayToParty(const std::string& msg) return false; WorldPacket data; - ChatHandler::BuildChatPacket(data, CHAT_MSG_PARTY, msg.c_str(), LANG_UNIVERSAL, CHAT_TAG_NONE, bot->GetGUID(), bot->GetName()); + ChatHandler::BuildChatPacket(data, CHAT_MSG_PARTY, msg.c_str(), LANG_UNIVERSAL, CHAT_TAG_NONE, bot->GetGUID(), + bot->GetName()); for (auto reciever : GetPlayersInGroup()) { @@ -2320,7 +2332,8 @@ bool PlayerbotAI::SayToRaid(const std::string& msg) return false; WorldPacket data; - ChatHandler::BuildChatPacket(data, CHAT_MSG_RAID, msg.c_str(), LANG_UNIVERSAL, CHAT_TAG_NONE, bot->GetGUID(), bot->GetName()); + ChatHandler::BuildChatPacket(data, CHAT_MSG_RAID, msg.c_str(), LANG_UNIVERSAL, CHAT_TAG_NONE, bot->GetGUID(), + bot->GetName()); for (auto reciever : GetPlayersInGroup()) { @@ -4767,27 +4780,18 @@ Item* PlayerbotAI::FindOilFor(Item* weapon) const return nullptr; // static const will only get created once whatever the call amout - static const std::vector uPriorizedWizardOilIds = - { - MINOR_WIZARD_OIL, MINOR_MANA_OIL, - LESSER_WIZARD_OIL, LESSER_MANA_OIL, - BRILLIANT_WIZARD_OIL, BRILLIANT_MANA_OIL, - WIZARD_OIL, SUPERIOR_MANA_OIL, SUPERIOR_WIZARD_OIL - }; + static const std::vector uPriorizedWizardOilIds = { + MINOR_WIZARD_OIL, MINOR_MANA_OIL, LESSER_WIZARD_OIL, LESSER_MANA_OIL, BRILLIANT_WIZARD_OIL, + BRILLIANT_MANA_OIL, WIZARD_OIL, SUPERIOR_MANA_OIL, SUPERIOR_WIZARD_OIL}; // static const will only get created once whatever the call amout - static const std::vector uPriorizedManaOilIds = - { - MINOR_MANA_OIL, MINOR_WIZARD_OIL, - LESSER_MANA_OIL, LESSER_WIZARD_OIL, - BRILLIANT_MANA_OIL, BRILLIANT_WIZARD_OIL, - SUPERIOR_MANA_OIL, WIZARD_OIL, SUPERIOR_WIZARD_OIL - }; + static const std::vector uPriorizedManaOilIds = { + MINOR_MANA_OIL, MINOR_WIZARD_OIL, LESSER_MANA_OIL, LESSER_WIZARD_OIL, BRILLIANT_MANA_OIL, + BRILLIANT_WIZARD_OIL, SUPERIOR_MANA_OIL, WIZARD_OIL, SUPERIOR_WIZARD_OIL}; Item* oil = nullptr; - if (item_template->SubClass == ITEM_SUBCLASS_WEAPON_SWORD || - item_template->SubClass == ITEM_SUBCLASS_WEAPON_STAFF || - item_template->SubClass == ITEM_SUBCLASS_WEAPON_DAGGER) + if (item_template->SubClass == ITEM_SUBCLASS_WEAPON_SWORD || + item_template->SubClass == ITEM_SUBCLASS_WEAPON_STAFF || item_template->SubClass == ITEM_SUBCLASS_WEAPON_DAGGER) { for (const auto& id : uPriorizedWizardOilIds) { @@ -4797,7 +4801,7 @@ Item* PlayerbotAI::FindOilFor(Item* weapon) const } } else if (item_template->SubClass == ITEM_SUBCLASS_WEAPON_MACE || - item_template->SubClass == ITEM_SUBCLASS_WEAPON_MACE2) + item_template->SubClass == ITEM_SUBCLASS_WEAPON_MACE2) { for (const auto& id : uPriorizedManaOilIds) { @@ -4940,7 +4944,6 @@ uint32 PlayerbotAI::GetInventoryItemsCountWithId(uint32 itemId) bool PlayerbotAI::HasItemInInventory(uint32 itemId) { - for (int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; ++i) { if (Bag* pBag = (Bag*)bot->GetItemByPos(INVENTORY_SLOT_BAG_0, i)) @@ -5167,10 +5170,7 @@ bool PlayerbotAI::IsInRealGuild() return !(sPlayerbotAIConfig->IsInRandomAccountList(leaderAccount)); } -void PlayerbotAI::QueueChatResponse(const ChatQueuedReply chatReply) -{ - chatReplies.push_back(std::move(chatReply)); -} +void PlayerbotAI::QueueChatResponse(const ChatQueuedReply chatReply) { chatReplies.push_back(std::move(chatReply)); } bool PlayerbotAI::EqualLowercaseName(std::string s1, std::string s2) { @@ -5507,11 +5507,13 @@ uint8 PlayerbotAI::FindEquipSlot(ItemTemplate const* proto, uint32 slot, bool sw bool PlayerbotAI::IsSafe(Player* player) { - return player && player->GetMapId() == bot->GetMapId() && player->GetInstanceId() == bot->GetInstanceId() && !player->IsBeingTeleported(); + return player && player->GetMapId() == bot->GetMapId() && player->GetInstanceId() == bot->GetInstanceId() && + !player->IsBeingTeleported(); } bool PlayerbotAI::IsSafe(WorldObject* obj) { - return obj && obj->GetMapId() == bot->GetMapId() && obj->GetInstanceId() == bot->GetInstanceId() && (!obj->IsPlayer() || !((Player*)obj)->IsBeingTeleported()); + return obj && obj->GetMapId() == bot->GetMapId() && obj->GetInstanceId() == bot->GetInstanceId() && + (!obj->IsPlayer() || !((Player*)obj)->IsBeingTeleported()); } ChatChannelSource PlayerbotAI::GetChatChannelSource(Player* bot, uint32 type, std::string channelName) { diff --git a/src/RandomItemMgr.cpp b/src/RandomItemMgr.cpp index 415ccb15..7a62891a 100644 --- a/src/RandomItemMgr.cpp +++ b/src/RandomItemMgr.cpp @@ -2197,6 +2197,46 @@ void RandomItemMgr::BuildEquipCache() void RandomItemMgr::BuildEquipCacheNew() { LOG_INFO("playerbots", "Loading equipments cache..."); + + std::unordered_set questItemIds; + ObjectMgr::QuestMap const& questTemplates = sObjectMgr->GetQuestTemplates(); + for (ObjectMgr::QuestMap::const_iterator i = questTemplates.begin(); i != questTemplates.end(); ++i) + { + uint32 questId = i->first; + Quest const* quest = i->second; + + if (quest->IsRepeatable()) + continue; + + if (quest->GetQuestLevel() <= 0) + continue; + + if (quest->GetRequiredClasses()) + continue; + + for (int j = 0; j < quest->GetRewChoiceItemsCount(); j++) + if (uint32 itemId = quest->RewardChoiceItemId[j]) + { + ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemId); + if (proto->Class != ITEM_CLASS_WEAPON && proto->Class != ITEM_CLASS_ARMOR) + continue; + int requiredLevel = std::max((int)proto->RequiredLevel, quest->GetQuestLevel()); + equipCacheNew[requiredLevel][proto->InventoryType].push_back(itemId); + questItemIds.insert(itemId); + } + + for (int j = 0; j < quest->GetRewItemsCount(); j++) + if (uint32 itemId = quest->RewardItemId[j]) + { + ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemId); + if (proto->Class != ITEM_CLASS_WEAPON && proto->Class != ITEM_CLASS_ARMOR) + continue; + int requiredLevel = std::max((int)proto->RequiredLevel, quest->GetQuestLevel()); + equipCacheNew[requiredLevel][proto->InventoryType].push_back(itemId); + questItemIds.insert(itemId); + } + } + ItemTemplateContainer const* itemTemplates = sObjectMgr->GetItemTemplateStore(); for (auto const& itr : *itemTemplates) { @@ -2204,6 +2244,10 @@ void RandomItemMgr::BuildEquipCacheNew() if (!proto) continue; uint32 itemId = proto->ItemId; + + if (questItemIds.find(itemId) != questItemIds.end()) + continue; + if (IsTestItem(itemId)) { continue; diff --git a/src/factory/PlayerbotFactory.cpp b/src/factory/PlayerbotFactory.cpp index 9f87bc74..7c969b95 100644 --- a/src/factory/PlayerbotFactory.cpp +++ b/src/factory/PlayerbotFactory.cpp @@ -1254,6 +1254,7 @@ bool PlayerbotFactory::CanEquipWeapon(ItemTemplate const* proto) case CLASS_ROGUE: if (proto->SubClass != ITEM_SUBCLASS_WEAPON_DAGGER && proto->SubClass != ITEM_SUBCLASS_WEAPON_SWORD && proto->SubClass != ITEM_SUBCLASS_WEAPON_FIST && proto->SubClass != ITEM_SUBCLASS_WEAPON_MACE && + proto->SubClass != ITEM_SUBCLASS_WEAPON_AXE && proto->SubClass != ITEM_SUBCLASS_WEAPON_GUN && proto->SubClass != ITEM_SUBCLASS_WEAPON_CROSSBOW && proto->SubClass != ITEM_SUBCLASS_WEAPON_BOW && proto->SubClass != ITEM_SUBCLASS_WEAPON_THROWN) return false; @@ -1263,14 +1264,11 @@ bool PlayerbotFactory::CanEquipWeapon(ItemTemplate const* proto) return true; } -bool PlayerbotFactory::CanEquipItem(ItemTemplate const* proto, uint32 desiredQuality) +bool PlayerbotFactory::CanEquipItem(ItemTemplate const* proto) { if (proto->Duration != 0) return false; - if (proto->Quality != desiredQuality) - return false; - if (proto->Bonding == BIND_QUEST_ITEM /*|| proto->Bonding == BIND_WHEN_USE*/) return false; @@ -1278,29 +1276,15 @@ bool PlayerbotFactory::CanEquipItem(ItemTemplate const* proto, uint32 desiredQua return true; uint32 requiredLevel = proto->RequiredLevel; - if (!requiredLevel) + bool hasItem = bot->HasItemCount(proto->ItemId, 1, true); + // bot->GetItemCount() + // !requiredLevel -> it's a quest reward item + if (!requiredLevel && hasItem) return false; uint32 level = bot->GetLevel(); - uint32 delta = 2; - if (level < 15) - delta = std::min(level, 15u); // urand(7, 15); - // else if (proto->Class == ITEM_CLASS_WEAPON || proto->SubClass == ITEM_SUBCLASS_ARMOR_SHIELD) - // delta = urand(2, 3); - // else if (!(level % 10) || (level % 10) == 9) - // delta = 2; - else if (level < 40) - delta = 10; // urand(5, 10); - else if (level < 60) - delta = 6; // urand(3, 7); - else if (level < 70) - delta = 9; // urand(2, 5); - else if (level < 80) - delta = 9; // urand(2, 4); - else if (level == 80) - delta = 9; // urand(2, 4); - if (desiredQuality > ITEM_QUALITY_NORMAL && (requiredLevel > level || requiredLevel < level - delta)) + if (requiredLevel > level) return false; return true; @@ -1492,7 +1476,6 @@ void PlayerbotFactory::InitEquipment(bool incremental) } do { - ItemTemplateContainer const* itemTemplate = sObjectMgr->GetItemTemplateStore(); for (uint32 requiredLevel = bot->GetLevel(); requiredLevel > std::max((int32)bot->GetLevel() - delta, 0); requiredLevel--) { @@ -1527,9 +1510,12 @@ void PlayerbotFactory::InitEquipment(bool incremental) if (proto->Class != ITEM_CLASS_WEAPON && proto->Class != ITEM_CLASS_ARMOR) continue; - if (!CanEquipItem(proto, desiredQuality)) + if (proto->Quality != desiredQuality) continue; + if (!CanEquipItem(proto)) + continue; + if (proto->Class == ITEM_CLASS_ARMOR && (slot == EQUIPMENT_SLOT_HEAD || slot == EQUIPMENT_SLOT_SHOULDERS || slot == EQUIPMENT_SLOT_CHEST || slot == EQUIPMENT_SLOT_WAIST || @@ -1594,6 +1580,11 @@ void PlayerbotFactory::InitEquipment(bool incremental) uint32 newItemId = ids[index]; uint16 dest; + + ItemTemplate const* proto = sObjectMgr->GetItemTemplate(newItemId); + + if (!CanEquipItem(proto)) + continue; if (oldItem && oldItem->GetTemplate()->ItemId == newItemId) continue; @@ -1608,36 +1599,12 @@ void PlayerbotFactory::InitEquipment(bool incremental) bestItemForSlot = newItemId; } } - // for (int attempts = 0; attempts < std::max((int)(ids.size() * 0.75), 1); attempts++) - // { - // uint32 index = urand(0, ids.size() - 1); - // uint32 newItemId = ids[index]; - - // uint16 dest; - - // if (oldItem && oldItem->GetTemplate()->ItemId == newItemId) - // continue; - - // if (!CanEquipUnseenItem(slot, dest, newItemId)) - // continue; - - // float cur_score = calculator.CalculateItem(newItemId); - // if (cur_score > bestScoreForSlot) - // { - // bestScoreForSlot = cur_score; - // bestItemForSlot = newItemId; - // } - // } if (bestItemForSlot == 0) { continue; } if (oldItem) { - // uint8 dstBag = NULL_BAG; - // WorldPacket packet(CMSG_AUTOSTORE_BAG_ITEM, 3); - // packet << INVENTORY_SLOT_BAG_0 << slot << dstBag; - // bot->GetSession()->HandleAutoStoreBagItemOpcode(packet); bot->DestroyItem(INVENTORY_SLOT_BAG_0, slot, true); } uint16 dest; @@ -3333,8 +3300,11 @@ void PlayerbotFactory::InitInventoryEquip() if (proto->Class == ITEM_CLASS_WEAPON && !CanEquipWeapon(proto)) continue; - - if (!CanEquipItem(proto, desiredQuality)) + + if (proto->Quality != desiredQuality) + continue; + + if (!CanEquipItem(proto)) continue; ids.push_back(itr.first); diff --git a/src/factory/PlayerbotFactory.h b/src/factory/PlayerbotFactory.h index 65de201b..f88ce96e 100644 --- a/src/factory/PlayerbotFactory.h +++ b/src/factory/PlayerbotFactory.h @@ -141,7 +141,7 @@ private: void Prepare(); // void InitSecondEquipmentSet(); // void InitEquipmentNew(bool incremental); - bool CanEquipItem(ItemTemplate const* proto, uint32 desiredQuality); + bool CanEquipItem(ItemTemplate const* proto); bool CanEquipUnseenItem(uint8 slot, uint16& dest, uint32 item); void InitTradeSkills(); void UpdateTradeSkills(); diff --git a/src/factory/StatsCollector.cpp b/src/factory/StatsCollector.cpp index 322e4742..1216b35c 100644 --- a/src/factory/StatsCollector.cpp +++ b/src/factory/StatsCollector.cpp @@ -89,13 +89,21 @@ void StatsCollector::CollectSpellStats(uint32 spellId, float multiplier, int32 s bool canNextTrigger = true; uint32 procFlags; + uint32 procChance; if (eventEntry && eventEntry->procFlags) procFlags = eventEntry->procFlags; else procFlags = spellInfo->ProcFlags; - - if (procFlags && !CanBeTriggeredByType(spellInfo, procFlags)) + + if (eventEntry && eventEntry->customChance) + procChance = eventEntry->customChance; + else + procChance = spellInfo->ProcChance; + bool lowChance = procChance <= 5; + + if (lowChance || (procFlags && !CanBeTriggeredByType(spellInfo, procFlags))) canNextTrigger = false; + if (spellInfo->StackAmount) { // Heuristic multiplier for spell with stackAmount since high stackAmount may not be available @@ -504,7 +512,8 @@ void StatsCollector::HandleApplyAura(const SpellEffectInfo& effectInfo, float mu break; } case SPELL_AURA_MOD_ATTACK_POWER: - stats[STATS_TYPE_ATTACK_POWER] += val * multiplier; + if (type_ == CollectorType::MELEE) + stats[STATS_TYPE_ATTACK_POWER] += val * multiplier; break; case SPELL_AURA_MOD_RANGED_ATTACK_POWER: if (type_ == CollectorType::RANGED) diff --git a/src/factory/StatsWeightCalculator.cpp b/src/factory/StatsWeightCalculator.cpp index 9ee2b487..6f6166e1 100644 --- a/src/factory/StatsWeightCalculator.cpp +++ b/src/factory/StatsWeightCalculator.cpp @@ -462,7 +462,7 @@ void StatsWeightCalculator::CalculateItemTypePenalty(ItemTemplate const* proto) weight_ *= 1.1; } if (cls == CLASS_WARRIOR && player_->HasAura(12785) - && (proto->SubClass == ITEM_SUBCLASS_WEAPON_THROWN || proto->SubClass == ITEM_SUBCLASS_WEAPON_AXE2)) + && (proto->SubClass == ITEM_SUBCLASS_WEAPON_POLEARM || proto->SubClass == ITEM_SUBCLASS_WEAPON_AXE2)) { weight_ *= 1.1; } diff --git a/src/factory/StatsWeightCalculator.h b/src/factory/StatsWeightCalculator.h index 030f1540..721eff9e 100644 --- a/src/factory/StatsWeightCalculator.h +++ b/src/factory/StatsWeightCalculator.h @@ -13,7 +13,8 @@ ((1 << ITEM_SUBCLASS_WEAPON_AXE) | (1 << ITEM_SUBCLASS_WEAPON_MACE) | (1 << ITEM_SUBCLASS_WEAPON_SWORD) | \ (1 << ITEM_SUBCLASS_WEAPON_DAGGER) | (1 << ITEM_SUBCLASS_WEAPON_FIST)) -enum StatsOverflowThreshold { +enum StatsOverflowThreshold +{ SPELL_HIT_OVERFLOW = 17, MELEE_HIT_OVERFLOW = 8, RANGED_HIT_OVERFLOW = 8, @@ -30,6 +31,10 @@ public: float CalculateItem(uint32 itemId); float CalculateEnchant(uint32 enchantId); + void SetOverflowPenalty(bool apply) { enable_overflow_penalty_ = apply; } + void SetItemSetBonus(bool apply) { enable_item_set_bonus_ = apply; } + void SetQualityBlend(bool apply) { enable_quality_blend_ = apply; } + private: void GenerateWeights(Player* player); void GenerateBasicWeights(Player* player); @@ -53,7 +58,7 @@ private: bool enable_overflow_penalty_; bool enable_item_set_bonus_; bool enable_quality_blend_; - + float weight_; float stats_weights_[STATS_TYPE_MAX]; }; diff --git a/src/strategy/actions/AcceptQuestAction.cpp b/src/strategy/actions/AcceptQuestAction.cpp index 72abeef9..fcbd2438 100644 --- a/src/strategy/actions/AcceptQuestAction.cpp +++ b/src/strategy/actions/AcceptQuestAction.cpp @@ -88,7 +88,7 @@ bool AcceptQuestAction::Execute(Event event) std::stringstream ss; ss << "AcceptQuestAction {" << qInfo->GetTitle() << "} - {" << std::to_string(qInfo->GetQuestId()) << "}"; LOG_INFO("playerbots", "{}", ss.str().c_str()); - botAI->TellMaster(ss.str()); + // botAI->TellMaster(ss.str()); } return hasAccept; diff --git a/src/strategy/actions/ChooseRpgTargetAction.cpp b/src/strategy/actions/ChooseRpgTargetAction.cpp index d376d236..dfd1cef5 100644 --- a/src/strategy/actions/ChooseRpgTargetAction.cpp +++ b/src/strategy/actions/ChooseRpgTargetAction.cpp @@ -195,9 +195,9 @@ bool ChooseRpgTargetAction::Execute(Event event) } } } - - if (possiblePlayers.size() > 200 || HasSameTarget(guidP, urand(5, 15), possiblePlayers)) - continue; + + // if (possiblePlayers.size() > 200 || HasSameTarget(guidP, urand(5, 15), possiblePlayers)) + // continue; float relevance = getMaxRelevance(guidP); diff --git a/src/strategy/actions/SayAction.cpp b/src/strategy/actions/SayAction.cpp index afd18353..6bf973ab 100644 --- a/src/strategy/actions/SayAction.cpp +++ b/src/strategy/actions/SayAction.cpp @@ -205,20 +205,21 @@ void ChatReplyAction::ChatReplyDo(Player* bot, uint32& type, uint32& guid1, uint return; } - //toxic links - if (msg.starts_with(sPlayerbotAIConfig->toxicLinksPrefix) - && (GET_PLAYERBOT_AI(bot)->GetChatHelper()->ExtractAllItemIds(msg).size() > 0 || GET_PLAYERBOT_AI(bot)->GetChatHelper()->ExtractAllQuestIds(msg).size() > 0)) - { - HandleToxicLinksReply(bot, chatChannelSource, msg, name); - return; - } + // Disable since ExtractAllItemIds bad performance + // //toxic links + // if (msg.starts_with(sPlayerbotAIConfig->toxicLinksPrefix) + // && (GET_PLAYERBOT_AI(bot)->GetChatHelper()->ExtractAllItemIds(msg).size() > 0 || GET_PLAYERBOT_AI(bot)->GetChatHelper()->ExtractAllQuestIds(msg).size() > 0)) + // { + // HandleToxicLinksReply(bot, chatChannelSource, msg, name); + // return; + // } - //thunderfury - if (GET_PLAYERBOT_AI(bot)->GetChatHelper()->ExtractAllItemIds(msg).count(19019)) - { - HandleThunderfuryReply(bot, chatChannelSource, msg, name); - return; - } + // //thunderfury + // if (GET_PLAYERBOT_AI(bot)->GetChatHelper()->ExtractAllItemIds(msg).count(19019)) + // { + // HandleThunderfuryReply(bot, chatChannelSource, msg, name); + // return; + // } auto messageRepy = GenerateReplyMessage(bot, msg, guid1, name); SendGeneralResponse(bot, chatChannelSource, messageRepy, name); @@ -316,6 +317,8 @@ bool ChatReplyAction::HandleToxicLinksReply(Player* bot, ChatChannelSource chatC } bool ChatReplyAction::HandleWTBItemsReply(Player* bot, ChatChannelSource chatChannelSource, std::string& msg, std::string& name) { + // Disable since ExtractAllItemIds bad performance + return false; auto messageItemIds = GET_PLAYERBOT_AI(bot)->GetChatHelper()->ExtractAllItemIds(msg); if (messageItemIds.empty()) @@ -409,6 +412,8 @@ bool ChatReplyAction::HandleWTBItemsReply(Player* bot, ChatChannelSource chatCha } bool ChatReplyAction::HandleLFGQuestsReply(Player* bot, ChatChannelSource chatChannelSource, std::string& msg, std::string& name) { + // Disable since ExtractAllQuestIds bad performance + return false; auto messageQuestIds = GET_PLAYERBOT_AI(bot)->GetChatHelper()->ExtractAllQuestIds(msg); if (messageQuestIds.empty()) diff --git a/src/strategy/paladin/DpsPaladinStrategy.cpp b/src/strategy/paladin/DpsPaladinStrategy.cpp index da74b42d..ecbe3af7 100644 --- a/src/strategy/paladin/DpsPaladinStrategy.cpp +++ b/src/strategy/paladin/DpsPaladinStrategy.cpp @@ -39,7 +39,7 @@ private: { return new ActionNode("seal of vengeance", /*P*/ nullptr, - /*A*/ NextAction::array(0, new NextAction("seal of righteousness"), nullptr), + /*A*/ NextAction::array(0, new NextAction("seal of command"), nullptr), /*C*/ nullptr); } @@ -47,7 +47,7 @@ private: { return new ActionNode("seal of command", /*P*/ nullptr, - /*A*/ NextAction::array(0, new NextAction("seal of corruption"), nullptr), + /*A*/ NextAction::array(0, new NextAction("seal of righteousness"), nullptr), /*C*/ nullptr); } @@ -94,7 +94,7 @@ void DpsPaladinStrategy::InitTriggers(std::vector& triggers) GenericPaladinStrategy::InitTriggers(triggers); triggers.push_back( - new TriggerNode("seal", NextAction::array(0, new NextAction("seal of command", ACTION_HIGH), NULL))); + new TriggerNode("seal", NextAction::array(0, new NextAction("seal of corruption", ACTION_HIGH), NULL))); // triggers.push_back(new TriggerNode("seal", NextAction::array(0, new NextAction("seal of command", 90.0f), // nullptr))); triggers.push_back( diff --git a/src/strategy/rogue/DpsRogueStrategy.cpp b/src/strategy/rogue/DpsRogueStrategy.cpp index 6fc450b9..91cc8044 100644 --- a/src/strategy/rogue/DpsRogueStrategy.cpp +++ b/src/strategy/rogue/DpsRogueStrategy.cpp @@ -99,10 +99,11 @@ void DpsRogueStrategy::InitTriggers(std::vector& triggers) "slice and dice", NextAction::array(0, new NextAction("slice and dice", ACTION_HIGH + 2), nullptr))); triggers.push_back(new TriggerNode("combo points available", - NextAction::array(0, new NextAction("rupture", ACTION_HIGH + 1), nullptr))); + NextAction::array(0, new NextAction("rupture", ACTION_HIGH + 1), + new NextAction("eviscerate", ACTION_HIGH), nullptr))); triggers.push_back(new TriggerNode("target with combo points almost dead", - NextAction::array(0, new NextAction("eviscerate", ACTION_HIGH + 1), nullptr))); + NextAction::array(0, new NextAction("eviscerate", ACTION_HIGH + 2), nullptr))); triggers.push_back( new TriggerNode("medium threat", NextAction::array(0, new NextAction("vanish", ACTION_HIGH), nullptr))); @@ -111,8 +112,8 @@ void DpsRogueStrategy::InitTriggers(std::vector& triggers) new TriggerNode("low health", NextAction::array(0, new NextAction("evasion", ACTION_HIGH + 9), new NextAction("feint", ACTION_HIGH + 8), nullptr))); - triggers.push_back( - new TriggerNode("critical health", NextAction::array(0, new NextAction("cloak of shadows", ACTION_HIGH + 7), nullptr))); + triggers.push_back(new TriggerNode( + "critical health", NextAction::array(0, new NextAction("cloak of shadows", ACTION_HIGH + 7), nullptr))); triggers.push_back( new TriggerNode("kick", NextAction::array(0, new NextAction("kick", ACTION_INTERRUPT + 2), nullptr))); @@ -128,8 +129,8 @@ void DpsRogueStrategy::InitTriggers(std::vector& triggers) triggers.push_back( new TriggerNode("light aoe", NextAction::array(0, new NextAction("blade flurry", ACTION_HIGH + 3), nullptr))); - triggers.push_back( - new TriggerNode("blade flurry", NextAction::array(0, new NextAction("blade flurry", ACTION_HIGH + 2), nullptr))); + triggers.push_back(new TriggerNode("blade flurry", + NextAction::array(0, new NextAction("blade flurry", ACTION_HIGH + 2), nullptr))); triggers.push_back(new TriggerNode( "enemy out of melee", diff --git a/src/strategy/shaman/CasterShamanStrategy.cpp b/src/strategy/shaman/CasterShamanStrategy.cpp index 050be6f1..88e3ca06 100644 --- a/src/strategy/shaman/CasterShamanStrategy.cpp +++ b/src/strategy/shaman/CasterShamanStrategy.cpp @@ -47,10 +47,13 @@ NextAction** CasterShamanStrategy::getDefaultActions() 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( + "enough mana", NextAction::array(0, new NextAction("chain lightning", ACTION_DEFAULT + 0.1f), 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), @@ -64,10 +67,12 @@ void CasterShamanStrategy::InitTriggers(std::vector& triggers) triggers.push_back( new TriggerNode("no fire totem", NextAction::array(0, new NextAction("totem of wrath", 15.0f), NULL))); - triggers.push_back(new TriggerNode("enemy is close", - NextAction::array(0, new NextAction("thunderstorm", ACTION_HIGH + 1), nullptr))); triggers.push_back( new TriggerNode("medium mana", NextAction::array(0, new NextAction("thunderstorm", ACTION_HIGH + 1), nullptr))); + + + triggers.push_back(new TriggerNode("enemy is close", + NextAction::array(0, new NextAction("thunderstorm", ACTION_HIGH + 1), nullptr))); triggers.push_back(new TriggerNode("enemy too close for spell", NextAction::array(0, new NextAction("flee", ACTION_MOVE + 9), nullptr))); diff --git a/src/strategy/shaman/MeleeShamanStrategy.cpp b/src/strategy/shaman/MeleeShamanStrategy.cpp index a840a9e8..0764f8a6 100644 --- a/src/strategy/shaman/MeleeShamanStrategy.cpp +++ b/src/strategy/shaman/MeleeShamanStrategy.cpp @@ -95,6 +95,9 @@ void MeleeShamanStrategy::InitTriggers(std::vector& triggers) triggers.push_back( new TriggerNode("medium mana", NextAction::array(0, new NextAction("shamanistic rage", 23.0f), nullptr))); + + triggers.push_back( + new TriggerNode("low health", NextAction::array(0, new NextAction("shamanistic rage", 23.0f), nullptr))); } void MeleeAoeShamanStrategy::InitTriggers(std::vector& triggers) diff --git a/src/strategy/values/ItemUsageValue.cpp b/src/strategy/values/ItemUsageValue.cpp index ca294165..9bdf206d 100644 --- a/src/strategy/values/ItemUsageValue.cpp +++ b/src/strategy/values/ItemUsageValue.cpp @@ -192,6 +192,9 @@ ItemUsage ItemUsageValue::QueryItemUsageForEquip(ItemTemplate const* itemProto) bool shouldEquip = false; // uint32 statWeight = sRandomItemMgr->GetLiveStatWeight(bot, itemProto->ItemId); StatsWeightCalculator calculator(bot); + calculator.SetItemSetBonus(false); + calculator.SetOverflowPenalty(false); + float itemScore = calculator.CalculateItem(itemProto->ItemId); if (itemScore) shouldEquip = true;