From 3716de4c967f604e2d90c5b95f6e930a074462c8 Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Fri, 19 Jul 2024 13:42:25 +0800 Subject: [PATCH 01/61] [Command] Fix sell item command --- src/strategy/actions/SellAction.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/strategy/actions/SellAction.cpp b/src/strategy/actions/SellAction.cpp index cafe9192..9bcf8dac 100644 --- a/src/strategy/actions/SellAction.cpp +++ b/src/strategy/actions/SellAction.cpp @@ -74,7 +74,7 @@ bool SellAction::Execute(Event event) return true; } - if (text == "all") + if (text != "") { std::vector items = parseItems(text, ITERATE_ITEMS_IN_BAGS); for (Item *item : items) @@ -84,7 +84,7 @@ bool SellAction::Execute(Event event) return true; } - botAI->TellError("Usage: s gray/*/vendor/all"); + botAI->TellError("Usage: s gray/*/vendor/[item link]"); return false; } From fce0f431e14dc99e818502de8687f133fe5637db Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Fri, 19 Jul 2024 13:43:18 +0800 Subject: [PATCH 02/61] [Command] Enable to cancel self command --- conf/playerbots.conf.dist | 15 +++++++------- src/PlayerbotAI.cpp | 2 +- src/PlayerbotMgr.cpp | 43 +++++++++++++++++++++++++-------------- src/PlayerbotMgr.h | 5 +++-- 4 files changed, 39 insertions(+), 26 deletions(-) diff --git a/conf/playerbots.conf.dist b/conf/playerbots.conf.dist index d10f0348..5f0e64d3 100644 --- a/conf/playerbots.conf.dist +++ b/conf/playerbots.conf.dist @@ -125,12 +125,12 @@ AiPlayerbot.BotAutologin = 0 # 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 +# Bots will be summoned to player when accept group invitation +AiPlayerbot.SummonWhenGroup = 1 + # Added following config # Selfbot permission level (0 = disabled, 1 = gm only (default), 2 = all players, 3 = activate on login) AiPlayerbot.SelfBotLevel = 1 @@ -541,7 +541,7 @@ AiPlayerbot.EquipmentPersistence = 0 # default: 80 AiPlayerbot.EquipmentPersistenceLevel = 80 -# Bot automatically upgrade equipments on levelup +# Randombots automatically upgrade equipments on levelup # Default: 1 (enabled) AiPlayerbot.AutoUpgradeEquip = 1 @@ -578,15 +578,15 @@ AiPlayerbot.RandomBotQuestItems = "6948,5175,5176,5177,5178,16309,12382,13704,11 # # -# Bots automatically learn classquest reward spells on levelup +# Randombots automatically learn classquest reward spells on levelup # Default: 0 (disabled) AiPlayerbot.AutoLearnQuestSpells = 0 -# Bots automatically learn trainable spells on levelup +# Randombots automatically learn trainable spells on levelup # Default: 1 (enabled) AiPlayerbot.AutoLearnTrainerSpells = 1 -# Bot automatically picks talent points on levelup +# Randombots automatically picks talent points on levelup # Default: 1 (enabled) AiPlayerbot.AutoPickTalents = 1 @@ -635,7 +635,6 @@ 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 diff --git a/src/PlayerbotAI.cpp b/src/PlayerbotAI.cpp index 71235156..2210b263 100644 --- a/src/PlayerbotAI.cpp +++ b/src/PlayerbotAI.cpp @@ -191,7 +191,7 @@ PlayerbotAI::~PlayerbotAI() delete aiObjectContext; if (bot) - sPlayerbotsMgr->RemovePlayerBotData(bot->GetGUID()); + sPlayerbotsMgr->RemovePlayerBotData(bot->GetGUID(), true); } void PlayerbotAI::UpdateAI(uint32 elapsed, bool minimal) diff --git a/src/PlayerbotMgr.cpp b/src/PlayerbotMgr.cpp index 2429e369..3a36dbd8 100644 --- a/src/PlayerbotMgr.cpp +++ b/src/PlayerbotMgr.cpp @@ -1214,7 +1214,7 @@ PlayerbotMgr::PlayerbotMgr(Player* const master) : PlayerbotHolder(), master(ma PlayerbotMgr::~PlayerbotMgr() { if (master) - sPlayerbotsMgr->RemovePlayerBotData(master->GetGUID()); + sPlayerbotsMgr->RemovePlayerBotData(master->GetGUID(), false); } void PlayerbotMgr::UpdateAIInternal(uint32 elapsed, bool /*minimal*/) @@ -1427,31 +1427,44 @@ void PlayerbotsMgr::AddPlayerbotData(Player* player, bool isBotAI) return; } // If the guid already exists in the map, remove it - std::unordered_map::iterator itr = _playerbotsMap.find(player->GetGUID()); - if (itr != _playerbotsMap.end()) + std::unordered_map::iterator itr = _playerbotsAIMap.find(player->GetGUID()); + if (itr != _playerbotsAIMap.end()) { - _playerbotsMap.erase(itr); + _playerbotsAIMap.erase(itr); + } + itr = _playerbotsMgrMap.find(player->GetGUID()); + if (itr != _playerbotsMgrMap.end()) + { + _playerbotsMgrMap.erase(itr); } if (!isBotAI) { PlayerbotMgr* playerbotMgr = new PlayerbotMgr(player); - ASSERT(_playerbotsMap.emplace(player->GetGUID(), playerbotMgr).second); + ASSERT(_playerbotsAIMap.emplace(player->GetGUID(), playerbotMgr).second); playerbotMgr->OnPlayerLogin(player); } else { PlayerbotAI* botAI = new PlayerbotAI(player); - ASSERT(_playerbotsMap.emplace(player->GetGUID(), botAI).second); + ASSERT(_playerbotsMgrMap.emplace(player->GetGUID(), botAI).second); } } -void PlayerbotsMgr::RemovePlayerBotData(ObjectGuid const& guid) +void PlayerbotsMgr::RemovePlayerBotData(ObjectGuid const& guid, bool is_AI) { - std::unordered_map::iterator itr = _playerbotsMap.find(guid); - if (itr != _playerbotsMap.end()) - { - _playerbotsMap.erase(itr); + if (is_AI) { + std::unordered_map::iterator itr = _playerbotsAIMap.find(guid); + if (itr != _playerbotsAIMap.end()) + { + _playerbotsAIMap.erase(itr); + } + } else { + std::unordered_map::iterator itr = _playerbotsMgrMap.find(guid); + if (itr != _playerbotsMgrMap.end()) + { + _playerbotsMgrMap.erase(itr); + } } } @@ -1464,8 +1477,8 @@ PlayerbotAI* PlayerbotsMgr::GetPlayerbotAI(Player* player) // if (player->GetSession()->isLogingOut() || player->IsDuringRemoveFromWorld()) { // return nullptr; // } - auto itr = _playerbotsMap.find(player->GetGUID()); - if (itr != _playerbotsMap.end()) + auto itr = _playerbotsAIMap.find(player->GetGUID()); + if (itr != _playerbotsAIMap.end()) { if (itr->second->IsBotAI()) return reinterpret_cast(itr->second); @@ -1480,8 +1493,8 @@ PlayerbotMgr* PlayerbotsMgr::GetPlayerbotMgr(Player* player) { return nullptr; } - auto itr = _playerbotsMap.find(player->GetGUID()); - if (itr != _playerbotsMap.end()) + auto itr = _playerbotsMgrMap.find(player->GetGUID()); + if (itr != _playerbotsMgrMap.end()) { if (!itr->second->IsBotAI()) return reinterpret_cast(itr->second); diff --git a/src/PlayerbotMgr.h b/src/PlayerbotMgr.h index d430d414..c8297c0a 100644 --- a/src/PlayerbotMgr.h +++ b/src/PlayerbotMgr.h @@ -99,13 +99,14 @@ class PlayerbotsMgr } void AddPlayerbotData(Player* player, bool isBotAI); - void RemovePlayerBotData(ObjectGuid const& guid); + void RemovePlayerBotData(ObjectGuid const& guid, bool is_AI); PlayerbotAI* GetPlayerbotAI(Player* player); PlayerbotMgr* GetPlayerbotMgr(Player* player); private: - std::unordered_map _playerbotsMap; + std::unordered_map _playerbotsAIMap; + std::unordered_map _playerbotsMgrMap; }; #define sPlayerbotsMgr PlayerbotsMgr::instance() From 2f93eeedc9c4a5bffd3791d759dbf254c681062f Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Fri, 19 Jul 2024 13:43:30 +0800 Subject: [PATCH 03/61] [Crash fix] Fix a possible crash --- src/strategy/actions/InviteToGroupAction.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/strategy/actions/InviteToGroupAction.cpp b/src/strategy/actions/InviteToGroupAction.cpp index 0b7b5e8a..8c8bd74b 100644 --- a/src/strategy/actions/InviteToGroupAction.cpp +++ b/src/strategy/actions/InviteToGroupAction.cpp @@ -19,7 +19,7 @@ bool InviteToGroupAction::Execute(Event event) bool InviteToGroupAction::Invite(Player* player) { - if (!player) + if (!player || !player->IsInWorld()) return false; if (!GET_PLAYERBOT_AI(player) && !botAI->GetSecurity()->CheckLevelFor(PLAYERBOT_SECURITY_INVITE, true, player)) From cdd4ab70800036bff2a4ff204b815f3aef67eaa0 Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Fri, 19 Jul 2024 14:52:19 +0800 Subject: [PATCH 04/61] [Command] Fix self command --- src/PlayerbotMgr.cpp | 30 ++++++++++++++++-------------- src/Playerbots.cpp | 2 +- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/src/PlayerbotMgr.cpp b/src/PlayerbotMgr.cpp index 3a36dbd8..3aea6da0 100644 --- a/src/PlayerbotMgr.cpp +++ b/src/PlayerbotMgr.cpp @@ -842,7 +842,7 @@ std::vector PlayerbotHolder::HandlePlayerbotCommand(char const* arg if (GET_PLAYERBOT_AI(master)) { messages.push_back("Disable player botAI"); - DisablePlayerBot(master->GetGUID()); + delete GET_PLAYERBOT_AI(master); } else if (sPlayerbotAIConfig->selfBotLevel == 0) messages.push_back("Self-bot is disabled"); @@ -851,7 +851,8 @@ std::vector PlayerbotHolder::HandlePlayerbotCommand(char const* arg else { messages.push_back("Enable player botAI"); - OnBotLogin(master); + sPlayerbotsMgr->AddPlayerbotData(master, true); + GET_PLAYERBOT_AI(master)->SetMaster(master); } return messages; @@ -1427,27 +1428,28 @@ void PlayerbotsMgr::AddPlayerbotData(Player* player, bool isBotAI) return; } // If the guid already exists in the map, remove it - std::unordered_map::iterator itr = _playerbotsAIMap.find(player->GetGUID()); - if (itr != _playerbotsAIMap.end()) - { - _playerbotsAIMap.erase(itr); - } - itr = _playerbotsMgrMap.find(player->GetGUID()); - if (itr != _playerbotsMgrMap.end()) - { - _playerbotsMgrMap.erase(itr); - } + if (!isBotAI) { + std::unordered_map::iterator itr = _playerbotsMgrMap.find(player->GetGUID()); + if (itr != _playerbotsMgrMap.end()) + { + _playerbotsMgrMap.erase(itr); + } PlayerbotMgr* playerbotMgr = new PlayerbotMgr(player); - ASSERT(_playerbotsAIMap.emplace(player->GetGUID(), playerbotMgr).second); + ASSERT(_playerbotsMgrMap.emplace(player->GetGUID(), playerbotMgr).second); playerbotMgr->OnPlayerLogin(player); } else { + std::unordered_map::iterator itr = _playerbotsAIMap.find(player->GetGUID()); + if (itr != _playerbotsAIMap.end()) + { + _playerbotsAIMap.erase(itr); + } PlayerbotAI* botAI = new PlayerbotAI(player); - ASSERT(_playerbotsMgrMap.emplace(player->GetGUID(), botAI).second); + ASSERT(_playerbotsAIMap.emplace(player->GetGUID(), botAI).second); } } diff --git a/src/Playerbots.cpp b/src/Playerbots.cpp index 6b6462cc..ad519e13 100644 --- a/src/Playerbots.cpp +++ b/src/Playerbots.cpp @@ -299,7 +299,7 @@ class PlayerbotsScript : public PlayerbotScript { botAI->HandleBotOutgoingPacket(*packet); } - else if (PlayerbotMgr* playerbotMgr = GET_PLAYERBOT_MGR(player)) + if (PlayerbotMgr* playerbotMgr = GET_PLAYERBOT_MGR(player)) { playerbotMgr->HandleMasterOutgoingPacket(*packet); } From e7fe79d946bf638318adac2ec86eead9f4b72136 Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Fri, 19 Jul 2024 15:40:31 +0800 Subject: [PATCH 05/61] [Initialization] Send talent packet after intialization --- src/AiFactory.cpp | 2 +- src/PlayerbotFactory.cpp | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/AiFactory.cpp b/src/AiFactory.cpp index d6baa1eb..54d189dc 100644 --- a/src/AiFactory.cpp +++ b/src/AiFactory.cpp @@ -553,7 +553,7 @@ void AiFactory::AddDefaultNonCombatStrategies(Player* player, PlayerbotAI* const if (sPlayerbotAIConfig->autoSaveMana) { nonCombatEngine->addStrategy("auto save mana"); } - if ((facade->IsRealPlayer() || sRandomPlayerbotMgr->IsRandomBot(player)) && !player->InBattleground()) + if ((sRandomPlayerbotMgr->IsRandomBot(player)) && !player->InBattleground()) { Player* master = facade->GetMaster(); diff --git a/src/PlayerbotFactory.cpp b/src/PlayerbotFactory.cpp index 26f9e3a6..c6f78887 100644 --- a/src/PlayerbotFactory.cpp +++ b/src/PlayerbotFactory.cpp @@ -644,6 +644,7 @@ void PlayerbotFactory::InitPetTalents() spells_row.erase(spells_row.begin() + index); } } + bot->SendTalentsInfoData(true); } void PlayerbotFactory::InitPet() @@ -870,6 +871,7 @@ void PlayerbotFactory::InitTalentsTree(bool increment/*false*/, bool use_templat if (bot->GetFreeTalentPoints()) InitTalents((specTab + 1) % 3); } + bot->SendTalentsInfoData(false); } void PlayerbotFactory::InitTalentsBySpecNo(Player* bot, int specNo, bool reset) @@ -933,6 +935,7 @@ void PlayerbotFactory::InitTalentsBySpecNo(Player* bot, int specNo, bool reset) break; } } + bot->SendTalentsInfoData(false); } void PlayerbotFactory::InitTalentsByParsedSpecLink(Player* bot, std::vector> parsedSpecLink, bool reset) @@ -983,6 +986,7 @@ void PlayerbotFactory::InitTalentsByParsedSpecLink(Player* bot, std::vectorSendTalentsInfoData(false); } class DestroyItemsVisitor : public IterateItemsVisitor @@ -2983,6 +2987,7 @@ void PlayerbotFactory::InitGlyphs(bool increment) } } } + bot->SendTalentsInfoData(false); } void PlayerbotFactory::CancelAuras() From b4201e1d84df3bd38f7aae7e0b1c0f7cf45b017a Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Fri, 19 Jul 2024 16:59:00 +0800 Subject: [PATCH 06/61] [Misc] Init bag, hunter spell --- src/PlayerbotFactory.cpp | 2 +- src/strategy/hunter/HunterTriggers.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/PlayerbotFactory.cpp b/src/PlayerbotFactory.cpp index c6f78887..200402d3 100644 --- a/src/PlayerbotFactory.cpp +++ b/src/PlayerbotFactory.cpp @@ -1738,7 +1738,7 @@ void PlayerbotFactory::InitBags(bool destroyOld) bot->DestroyItem(INVENTORY_SLOT_BAG_0, slot, true); } if (old_bag) { - return; + continue; } Item* newItem = bot->EquipNewItem(dest, newItemId, true); if (newItem) diff --git a/src/strategy/hunter/HunterTriggers.h b/src/strategy/hunter/HunterTriggers.h index b64c4b65..6896fd32 100644 --- a/src/strategy/hunter/HunterTriggers.h +++ b/src/strategy/hunter/HunterTriggers.h @@ -88,10 +88,10 @@ class FreezingTrapTrigger : public HasCcTargetTrigger FreezingTrapTrigger(PlayerbotAI* botAI) : HasCcTargetTrigger(botAI, "freezing trap") { } }; -class RapidFireTrigger : public BuffTrigger +class RapidFireTrigger : public BoostTrigger { public: - RapidFireTrigger(PlayerbotAI* botAI) : BuffTrigger(botAI, "rapid fire") { } + RapidFireTrigger(PlayerbotAI* botAI) : BoostTrigger(botAI, "rapid fire") { } }; class TrueshotAuraTrigger : public BuffTrigger From 400f9821019a486c1b497d9f8f4f85f53b821108 Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Sun, 21 Jul 2024 22:20:59 +0800 Subject: [PATCH 07/61] [Class spell] Mirror image --- src/strategy/mage/GenericMageStrategy.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/strategy/mage/GenericMageStrategy.cpp b/src/strategy/mage/GenericMageStrategy.cpp index e6bff447..793ad49a 100644 --- a/src/strategy/mage/GenericMageStrategy.cpp +++ b/src/strategy/mage/GenericMageStrategy.cpp @@ -153,7 +153,7 @@ void MageBoostStrategy::InitTriggers(std::vector& triggers) triggers.push_back(new TriggerNode("icy veins", NextAction::array(0, new NextAction("icy veins", 50.0f), nullptr))); triggers.push_back(new TriggerNode("presence of mind", NextAction::array(0, new NextAction("presence of mind", 42.0f), nullptr))); // triggers.push_back(new TriggerNode("arcane power", NextAction::array(0, new NextAction("arcane power", 41.0f), nullptr))); - // triggers.push_back(new TriggerNode("mirror image", NextAction::array(0, new NextAction("mirror image", 41.0f), nullptr))); + triggers.push_back(new TriggerNode("mirror image", NextAction::array(0, new NextAction("mirror image", 41.0f), nullptr))); } void MageCcStrategy::InitTriggers(std::vector& triggers) From 00e24b2681ad932176ef26fa6f55c23c674c54d2 Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Sun, 21 Jul 2024 22:23:03 +0800 Subject: [PATCH 08/61] [Command] Send talents info data after glyph changed --- src/strategy/actions/TrainerAction.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/strategy/actions/TrainerAction.cpp b/src/strategy/actions/TrainerAction.cpp index 231dea7d..15179234 100644 --- a/src/strategy/actions/TrainerAction.cpp +++ b/src/strategy/actions/TrainerAction.cpp @@ -172,6 +172,7 @@ bool MaintenanceAction::Execute(Event event) factory.ApplyEnchantAndGemsNew(); } bot->DurabilityRepairAll(false, 1.0f, false); + bot->SendTalentsInfoData(false); return true; } @@ -181,6 +182,7 @@ bool RemoveGlyphAction::Execute(Event event) { bot->SetGlyph(slotIndex, 0, true); } + bot->SendTalentsInfoData(false); return true; } From dd942bf4493d06180c4e8b95ba49381169e2ea43 Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Sun, 21 Jul 2024 23:04:16 +0800 Subject: [PATCH 09/61] Addclass command account id check --- src/PlayerbotMgr.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/PlayerbotMgr.cpp b/src/PlayerbotMgr.cpp index 3aea6da0..bd93a8f8 100644 --- a/src/PlayerbotMgr.cpp +++ b/src/PlayerbotMgr.cpp @@ -939,20 +939,22 @@ std::vector PlayerbotHolder::HandlePlayerbotCommand(char const* arg race_limit = "2, 5, 6, 8, 10"; break; } + uint32 maxAccountId = sPlayerbotAIConfig->randomBotAccounts.back(); // find a bot fit conditions and not in any guild QueryResult results = CharacterDatabase.Query("SELECT guid FROM characters " "WHERE name IN (SELECT name FROM playerbots_names) AND class = '{}' AND online = 0 AND race IN ({}) AND guid NOT IN ( SELECT guid FROM guild_member ) " - "ORDER BY account DESC LIMIT 1", claz, race_limit); + "AND account <= {} " + "ORDER BY account DESC LIMIT 1", claz, race_limit, maxAccountId); if (results) { Field* fields = results->Fetch(); ObjectGuid guid = ObjectGuid(HighGuid::Player, fields[0].Get()); AddPlayerBot(guid, master->GetSession()->GetAccountId()); - messages.push_back("addclass " + std::string(charname) + " ok"); + messages.push_back("Add class " + std::string(charname)); return messages; } - messages.push_back("addclass failed."); + messages.push_back("Add class failed."); return messages; } From 5ebba9cdb3941180cae425b7fc3c97ca1bd9ae04 Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Sun, 21 Jul 2024 23:53:47 +0800 Subject: [PATCH 10/61] Fix spell cast after self bot --- src/strategy/values/SpellIdValue.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/strategy/values/SpellIdValue.cpp b/src/strategy/values/SpellIdValue.cpp index 0e7eef38..beb445f8 100644 --- a/src/strategy/values/SpellIdValue.cpp +++ b/src/strategy/values/SpellIdValue.cpp @@ -6,6 +6,7 @@ #include "ChatHelper.h" #include "Playerbots.h" #include "Vehicle.h" +#include "World.h" SpellIdValue::SpellIdValue(PlayerbotAI* botAI) : CalculatedValue(botAI, "spell id", 20 * 1000) { @@ -34,7 +35,7 @@ uint32 SpellIdValue::Calculate() char firstSymbol = tolower(namepart[0]); int spellLength = wnamepart.length(); - LocaleConstant loc = bot->GetSession()->GetSessionDbcLocale(); + LocaleConstant loc = LOCALE_enUS; std::set spellIds; for (PlayerSpellMap::iterator itr = bot->GetSpellMap().begin(); itr != bot->GetSpellMap().end(); ++itr) From b741d50d726a1c36ea840f372ff4444719c6d732 Mon Sep 17 00:00:00 2001 From: antony Date: Wed, 24 Jul 2024 14:30:15 +0200 Subject: [PATCH 11/61] Fix LFG random classic dungeon limitation level issue --- src/strategy/actions/LfgActions.cpp | 108 ++-------------------------- 1 file changed, 6 insertions(+), 102 deletions(-) diff --git a/src/strategy/actions/LfgActions.cpp b/src/strategy/actions/LfgActions.cpp index 45f3b16c..4cb0bada 100644 --- a/src/strategy/actions/LfgActions.cpp +++ b/src/strategy/actions/LfgActions.cpp @@ -103,14 +103,13 @@ bool LfgJoinAction::JoinLFG() if (!dungeon || (dungeon->TypeID != LFG_TYPE_RANDOM && dungeon->TypeID != LFG_TYPE_DUNGEON && dungeon->TypeID != LFG_TYPE_HEROIC && dungeon->TypeID != LFG_TYPE_RAID)) continue; - uint32 botLevel = bot->GetLevel(); - if (dungeon->MinLevel && botLevel < dungeon->MinLevel) - continue; + const auto& botLevel = bot->GetLevel(); - if (dungeon->MinLevel && botLevel > dungeon->MinLevel + 10) - continue; - - if (dungeon->MaxLevel && botLevel > dungeon->MaxLevel) + /*LFG_TYPE_RANDOM on classic is 15-58 so bot over level 25 will never queue*/ + if (dungeon->MinLevel && (botLevel < dungeon->MinLevel || botLevel > dungeon->MaxLevel) + || + (botLevel > dungeon->MinLevel + 10 && dungeon->TypeID == LFG_TYPE_DUNGEON) + ) continue; selected.push_back(dungeon->ID); @@ -126,41 +125,8 @@ bool LfgJoinAction::JoinLFG() bool many = list.size() > 1; LFGDungeonEntry const* dungeon = sLFGDungeonStore.LookupEntry(*list.begin()); - /*for (uint32 i = 0; i < sLFGDungeonStore.GetNumRows(); ++i) - { - LFGDungeonEntry const* dungeon = sLFGDungeonStore.LookupEntry(i); - if (!dungeon || (dungeon->type != LFG_TYPE_RANDOM_DUNGEON && dungeon->type != LFG_TYPE_DUNGEON && dungeon->type != LFG_TYPE_HEROIC_DUNGEON && - dungeon->type != LFG_TYPE_RAID)) - continue; - - uint32 botLevel = bot->GetLevel(); - if (dungeon->MinLevel && botLevel < dungeon->MinLevel) - continue; - - if (dungeon->MinLevel && botLevel > dungeon->MinLevel + 10) - continue; - - if (dungeon->MaxLevel && botLevel > dungeon->MaxLevel) - continue; - - if (heroic && !dungeon->difficulty) - continue; - - if (rbotAId && dungeon->type != LFG_TYPE_RAID) - continue; - - if (!random && !rbotAId && !heroic && dungeon->type != LFG_TYPE_DUNGEON) - continue; - - list.insert(dungeon); - } - - if (list.empty() && !random) - return false;*/ - // check role for console msg std::string _roles = "multiple roles"; - uint32 roleMask = GetRoles(); if (roleMask & PLAYER_ROLE_TANK) _roles = "TANK"; @@ -175,70 +141,8 @@ bool LfgJoinAction::JoinLFG() bot->GetGUID().ToString().c_str(), bot->GetTeamId() == TEAM_ALLIANCE ? "A" : "H", bot->GetLevel(), bot->GetName().c_str(), _roles, many ? "several dungeons" : dungeon->Name[0]); - /*if (lfgState->IsSingleRole()) - { - if (lfgState->HasRole(ROLE_TANK)) - _roles = "TANK"; - if (lfgState->HasRole(ROLE_HEALER)) - _roles = "HEAL"; - if (lfgState->HasRole(ROLE_DAMAGE)) - _roles = "DPS"; - }*/ - - /*LFGDungeonEntry const* dungeon; - - if(!random) - dungeon = *list.begin(); - - bool many = list.size() > 1; - - if (random) - { - LFGDungeonSet randList = sLFGMgr->GetRandomDungeonsForPlayer(bot); - for (LFGDungeonSet::const_iterator itr = randList.begin(); itr != randList.end(); ++itr) - { - LFGDungeonEntry const* dungeon = *itr; - - if (!dungeon) - continue; - - idx.push_back(dungeon->ID); - } - if (idx.empty()) - return false; - - // choose random dungeon - dungeon = sLFGDungeonStore.LookupEntry(idx[urand(0, idx.size() - 1)]); - list.insert(dungeon); - - pState->SetType(LFG_TYPE_RANDOM_DUNGEON); - LOG_INFO("playerbots", "Bot {} {}:{} <{}>: queues LFG, Random Dungeon as {} ({})", - bot->GetGUID().ToString().c_str(), bot->GetTeamId() == TEAM_ALLIANCE ? "A" : "H", bot->GetLevel(), bot->GetName().c_str(), _roles, dungeon->Name[0]); - return true; - } - else if (heroic) - { - pState->SetType(LFG_TYPE_HEROIC_DUNGEON); - LOG_INFO("playerbots", "Bot {} {}:{} <{}>: queues LFG, Heroic Dungeon as {} ({})", - bot->GetGUID().ToString().c_str(), bot->GetTeamId() == TEAM_ALLIANCE ? "A" : "H", - bot->GetLevel(), bot->GetName().c_str(), _roles, many ? "several dungeons" : dungeon->Name[0]); - } - else if (rbotAId) - { - pState->SetType(LFG_TYPE_RAID); - LOG_INFO("playerbots", "Bot {} {}:{} <{}>: queues LFG, RbotAId as {} ({})", - bot->GetGUID().ToString().c_str(), bot->GetTeamId() == TEAM_ALLIANCE ? "A" : "H", bot->GetLevel(), bot->GetName().c_str(), _roles, many ? "several dungeons" : dungeon->Name[0]); - } - else - { - pState->SetType(LFG_TYPE_DUNGEON); - LOG_INFO("playerbots", "Bot {} {}:{} <{}>: queues LFG, Dungeon as {} ({})", - bot->GetGUID().ToString().c_str(), bot->GetTeamId() == TEAM_ALLIANCE ? "A" : "H", bot->GetLevel(), bot->GetName().c_str(), _roles, many ? "several dungeons" : dungeon->Name[0]); - }*/ - // Set RbotAId Browser comment std::string const _gs = std::to_string(botAI->GetEquipGearScore(bot, false, false)); - sLFGMgr->JoinLfg(bot, roleMask, list, _gs); return true; From f9bcfeb0008d9bc060fa7663de9059099bfb78a1 Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Mon, 22 Jul 2024 20:17:49 +0800 Subject: [PATCH 12/61] [Interaction] Set the group inviter as master instead of the group leader --- src/strategy/actions/AcceptInvitationAction.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/strategy/actions/AcceptInvitationAction.cpp b/src/strategy/actions/AcceptInvitationAction.cpp index ce2ea360..5bd261c1 100644 --- a/src/strategy/actions/AcceptInvitationAction.cpp +++ b/src/strategy/actions/AcceptInvitationAction.cpp @@ -4,17 +4,24 @@ #include "AcceptInvitationAction.h" #include "Event.h" +#include "ObjectAccessor.h" #include "PlayerbotAIConfig.h" #include "Playerbots.h" #include "PlayerbotSecurity.h" +#include "WorldPacket.h" bool AcceptInvitationAction::Execute(Event event) { Group* grp = bot->GetGroupInvite(); if (!grp) return false; + WorldPacket packet = event.getPacket(); + uint8 flag; + std::string name; + packet >> flag >> name; - Player* inviter = ObjectAccessor::FindPlayer(grp->GetLeaderGUID()); + // Player* inviter = ObjectAccessor::FindPlayer(grp->GetLeaderGUID()); + Player* inviter = ObjectAccessor::FindPlayerByName(name, true); if (!inviter) return false; From c191dfc35f725591a1168a6124c7dddcda4c9d38 Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Mon, 22 Jul 2024 20:18:50 +0800 Subject: [PATCH 13/61] [Command] Only follow the command given by master when multiple player one group --- src/PlayerbotAI.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PlayerbotAI.cpp b/src/PlayerbotAI.cpp index 45f832d5..6a4c7b3f 100644 --- a/src/PlayerbotAI.cpp +++ b/src/PlayerbotAI.cpp @@ -350,7 +350,7 @@ void PlayerbotAI::UpdateAIInternal([[maybe_unused]] uint32 elapsed, bool minimal std::string const command = holder.GetCommand(); Player* owner = holder.GetOwner(); - if (!helper.ParseChatCommand(command, owner) && holder.GetType() == CHAT_MSG_WHISPER) + if (owner == master && !helper.ParseChatCommand(command, owner) && holder.GetType() == CHAT_MSG_WHISPER) { // To prevent spam caused by WIM if (!(command.rfind("WIM", 0) == 0) && From ed80744891091b800f37e4cd34b228dccf18caef Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Tue, 23 Jul 2024 23:40:37 +0800 Subject: [PATCH 14/61] [Command] Language locale check --- src/ChatHelper.cpp | 10 ++++++---- src/strategy/actions/TellLosAction.cpp | 3 ++- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/ChatHelper.cpp b/src/ChatHelper.cpp index cec5d696..a181ac89 100644 --- a/src/ChatHelper.cpp +++ b/src/ChatHelper.cpp @@ -288,7 +288,7 @@ std::string const ChatHelper::FormatQuest(Quest const* quest) std::string const ChatHelper::FormatGameobject(GameObject* go) { std::ostringstream out; - out << "|cFFFFFF00|Hfound:" << go->GetGUID().GetRawValue() << ":" << go->GetEntry() << ":" << "|h[" << go->GetGOInfo()->name << "]|h|r"; + out << "|cFFFFFF00|Hfound:" << go->GetGUID().GetRawValue() << ":" << go->GetEntry() << ":" << "|h[" << go->GetNameForLocaleIdx(sWorld->GetDefaultDbcLocale()) << "]|h|r"; return out.str(); } @@ -296,7 +296,7 @@ std::string const ChatHelper::FormatWorldobject(WorldObject* wo) { std::ostringstream out; out << "|cFFFFFF00|Hfound:" << wo->GetGUID().GetRawValue() << ":" << wo->GetEntry() << ":" << "|h["; - out << (wo->ToGameObject() ? ((GameObject*)wo)->GetGOInfo()->name : wo->GetName()) << "]|h|r"; + out << (wo->ToGameObject() ? ((GameObject*)wo)->GetNameForLocaleIdx(sWorld->GetDefaultDbcLocale()) : wo->GetNameForLocaleIdx(sWorld->GetDefaultDbcLocale())) << "]|h|r"; return out.str(); } @@ -327,7 +327,7 @@ std::string const ChatHelper::FormatWorldEntry(int32 entry) std::string const ChatHelper::FormatSpell(SpellInfo const* spellInfo) { std::ostringstream out; - out << "|cffffffff|Hspell:" << spellInfo->Id << "|h[" << spellInfo->SpellName[LOCALE_enUS] << "]|h|r"; + out << "|cffffffff|Hspell:" << spellInfo->Id << "|h[" << spellInfo->SpellName[sWorld->GetDefaultDbcLocale()] << "]|h|r"; return out.str(); } @@ -336,9 +336,11 @@ std::string const ChatHelper::FormatItem(ItemTemplate const* proto, uint32 count char color[32]; sprintf(color, "%x", ItemQualityColors[proto->Quality]); + const std::string &name = sObjectMgr->GetItemLocale(proto->ItemId)->Name[sWorld->GetDefaultDbcLocale()]; + std::ostringstream out; out << "|c" << color << "|Hitem:" << proto->ItemId - << ":0:0:0:0:0:0:0" << "|h[" << proto->Name1 + << ":0:0:0:0:0:0:0" << "|h[" << name << "]|h|r"; if (count > 1) diff --git a/src/strategy/actions/TellLosAction.cpp b/src/strategy/actions/TellLosAction.cpp index 8c729cf3..688599ff 100644 --- a/src/strategy/actions/TellLosAction.cpp +++ b/src/strategy/actions/TellLosAction.cpp @@ -6,6 +6,7 @@ #include "Event.h" #include "ChatHelper.h" #include "Playerbots.h" +#include "World.h" bool TellLosAction::Execute(Event event) { @@ -52,7 +53,7 @@ void TellLosAction::ListUnits(std::string const title, GuidVector units) for (ObjectGuid const guid : units) { if (Unit* unit = botAI->GetUnit(guid)) { - botAI->TellMaster(unit->GetName()); + botAI->TellMaster(unit->GetNameForLocaleIdx(sWorld->GetDefaultDbcLocale())); } } From 1f7ab72b0449827476353da47f60b19b394e7f8e Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Wed, 24 Jul 2024 21:13:32 +0800 Subject: [PATCH 15/61] [Configuration] Make more options for ReviveBotWhenSummoned --- conf/playerbots.conf.dist | 4 ++-- src/PlayerbotAIConfig.cpp | 2 +- src/PlayerbotAIConfig.h | 2 +- src/strategy/actions/UseMeetingStoneAction.cpp | 3 ++- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/conf/playerbots.conf.dist b/conf/playerbots.conf.dist index 5f0e64d3..e7826de0 100644 --- a/conf/playerbots.conf.dist +++ b/conf/playerbots.conf.dist @@ -172,8 +172,8 @@ AiPlayerbot.AllowSummonWhenMasterIsDead = 1 # default: 1 (always) AiPlayerbot.AllowSummonWhenBotIsDead = 1 -# Enable/Disable reviving the bots when summoning them -# default: 1 (enable) +# Enable/Disable reviving the bots when summoning them (0 = disable, 1 = disable in combat, 2 = enable) +# default: 1 (disable in combat) AiPlayerbot.ReviveBotWhenSummoned = 1 # Enable/Disable bot repair gear when summon (0 = no, 1 = yes) diff --git a/src/PlayerbotAIConfig.cpp b/src/PlayerbotAIConfig.cpp index b28aeeba..94e290fe 100644 --- a/src/PlayerbotAIConfig.cpp +++ b/src/PlayerbotAIConfig.cpp @@ -279,7 +279,7 @@ bool PlayerbotAIConfig::Initialize() allowSummonInCombat = sConfigMgr->GetOption("AiPlayerbot.AllowSummonInCombat", true); allowSummonWhenMasterIsDead = sConfigMgr->GetOption("AiPlayerbot.AllowSummonWhenMasterIsDead", true); allowSummonWhenBotIsDead = sConfigMgr->GetOption("AiPlayerbot.AllowSummonWhenBotIsDead", true); - reviveBotWhenSummoned = sConfigMgr->GetOption("AiPlayerbot.ReviveBotWhenSummoned", true); + reviveBotWhenSummoned = sConfigMgr->GetOption("AiPlayerbot.ReviveBotWhenSummoned", 1); 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 32bd1c59..5ce7d39e 100644 --- a/src/PlayerbotAIConfig.h +++ b/src/PlayerbotAIConfig.h @@ -220,7 +220,7 @@ class PlayerbotAIConfig bool allowSummonInCombat; bool allowSummonWhenMasterIsDead; bool allowSummonWhenBotIsDead; - bool reviveBotWhenSummoned; + int reviveBotWhenSummoned; bool botRepairWhenSummon; bool autoInitOnly; float autoInitEquipLevelLimitRatio; diff --git a/src/strategy/actions/UseMeetingStoneAction.cpp b/src/strategy/actions/UseMeetingStoneAction.cpp index 5cf93e14..2bc87266 100644 --- a/src/strategy/actions/UseMeetingStoneAction.cpp +++ b/src/strategy/actions/UseMeetingStoneAction.cpp @@ -206,7 +206,8 @@ bool SummonAction::Teleport(Player* summoner, Player* player) return false; } - if (bot->isDead() && sPlayerbotAIConfig->reviveBotWhenSummoned) + bool revive = sPlayerbotAIConfig->reviveBotWhenSummoned == 2 || (sPlayerbotAIConfig->reviveBotWhenSummoned == 1 && !master->IsInCombat()); + if (bot->isDead() && revive) { bot->ResurrectPlayer(1.0f, false); botAI->TellMasterNoFacing("I live, again!"); From a2db0e3ad1214a08bc1a5cbdedcb31bbd5cb117b Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Wed, 24 Jul 2024 23:43:16 +0800 Subject: [PATCH 16/61] [Initialization] Remove duplicate mount init --- conf/playerbots.conf.dist | 2 +- src/PlayerbotFactory.cpp | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/conf/playerbots.conf.dist b/conf/playerbots.conf.dist index e7826de0..e14601e9 100644 --- a/conf/playerbots.conf.dist +++ b/conf/playerbots.conf.dist @@ -1289,7 +1289,7 @@ AiPlayerbot.RandomBotGuildCount = 20 AiPlayerbot.DeleteRandomBotGuilds = 0 # Chance bot chooses RPG (Teleport to random camp for their level) instead of grinding -AiPlayerbot.RandomBotRpgChance = 0.20 #unused now +AiPlayerbot.RandomBotRpgChance = 0.20 # Set randombots movement speed to walking anywhere AiPlayerbot.RandombotsWalkingRPG = 0 diff --git a/src/PlayerbotFactory.cpp b/src/PlayerbotFactory.cpp index 8ddf2086..21409f18 100644 --- a/src/PlayerbotFactory.cpp +++ b/src/PlayerbotFactory.cpp @@ -2620,6 +2620,16 @@ void PlayerbotFactory::InitMounts() for (uint32 type = 0; type < 4; type++) { + bool hasMount = false; + for (uint32 &spell : mounts[bot->getRace()][type]) { + if (bot->HasSpell(spell)) { + hasMount = true; + break; + } + } + if (hasMount) + continue; + if (bot->GetLevel() < secondmount && type == 1) continue; From ec04b28a95f6baf2df52e70176aa96fff3becf7f Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Wed, 24 Jul 2024 23:47:24 +0800 Subject: [PATCH 17/61] [Avoid aoe] Fix crash --- src/strategy/actions/MovementActions.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/strategy/actions/MovementActions.cpp b/src/strategy/actions/MovementActions.cpp index 0aef8b4e..ed002f53 100644 --- a/src/strategy/actions/MovementActions.cpp +++ b/src/strategy/actions/MovementActions.cpp @@ -1595,7 +1595,7 @@ bool AvoidAoeAction::AvoidGameObjectWithDamage() continue; } const SpellInfo* spellInfo = sSpellMgr->GetSpellInfo(spellId); - if (spellInfo->IsPositive()) { + if (!spellInfo || spellInfo->IsPositive()) { continue; } float radius = (float)goInfo->trap.diameter / 2; From bc784b2b9497e0bd3be7322a8e16c1b4a970812c Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Wed, 24 Jul 2024 23:54:28 +0800 Subject: [PATCH 18/61] [Warning] Fix warnings --- src/strategy/actions/BattleGroundTactics.cpp | 18 +++++++++--------- src/strategy/actions/EmoteAction.cpp | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/strategy/actions/BattleGroundTactics.cpp b/src/strategy/actions/BattleGroundTactics.cpp index e2ec787c..07aca77b 100644 --- a/src/strategy/actions/BattleGroundTactics.cpp +++ b/src/strategy/actions/BattleGroundTactics.cpp @@ -2390,19 +2390,19 @@ static std::pair AV_AllianceDefendObjectives[] = static uint32 AB_AttackObjectives[] = { // Attack - { BG_AB_NODE_STABLES }, - { BG_AB_NODE_BLACKSMITH }, - { BG_AB_NODE_FARM }, - { BG_AB_NODE_LUMBER_MILL }, - { BG_AB_NODE_GOLD_MINE } + BG_AB_NODE_STABLES, + BG_AB_NODE_BLACKSMITH, + BG_AB_NODE_FARM, + BG_AB_NODE_LUMBER_MILL, + BG_AB_NODE_GOLD_MINE }; static uint32 EY_AttackObjectives[] = { - { POINT_FEL_REAVER }, - { POINT_BLOOD_ELF }, - { POINT_DRAENEI_RUINS }, - { POINT_MAGE_TOWER } + POINT_FEL_REAVER, + POINT_BLOOD_ELF, + POINT_DRAENEI_RUINS, + POINT_MAGE_TOWER }; // useful commands for fixing BG bugs and checking waypoints/paths diff --git a/src/strategy/actions/EmoteAction.cpp b/src/strategy/actions/EmoteAction.cpp index b13a7a12..2ef6e90a 100644 --- a/src/strategy/actions/EmoteAction.cpp +++ b/src/strategy/actions/EmoteAction.cpp @@ -447,7 +447,7 @@ bool EmoteActionBase::ReceiveEmote(Player* source, uint32 emote, bool verbal) case TEXT_EMOTE_RASP: emoteId = EMOTE_ONESHOT_RUDE; textEmote = TEXT_EMOTE_RASP; - emoteText = "Right back at you, bub!", LANG_UNIVERSAL; + emoteText = "Right back at you, bub!"; // , LANG_UNIVERSAL; break; case TEXT_EMOTE_ROAR: case TEXT_EMOTE_THREATEN: From 0112b7d82dabd3a47137e180cdc1ef44c751e706 Mon Sep 17 00:00:00 2001 From: antony Date: Thu, 25 Jul 2024 09:56:04 +0200 Subject: [PATCH 19/61] More french translation --- sql/playerbots/base/playerbots_text.sql | 190 ++++++++++++------------ 1 file changed, 95 insertions(+), 95 deletions(-) diff --git a/sql/playerbots/base/playerbots_text.sql b/sql/playerbots/base/playerbots_text.sql index 73d1967e..095bd062 100644 --- a/sql/playerbots/base/playerbots_text.sql +++ b/sql/playerbots/base/playerbots_text.sql @@ -18,27 +18,27 @@ CREATE TABLE IF NOT EXISTS `ai_playerbot_texts` ( /*!40000 ALTER TABLE `ai_playerbot_texts` DISABLE KEYS */; INSERT INTO `ai_playerbot_texts` (`id`, `name`, `text`, `say_type`, `reply_type`, `text_loc1`, `text_loc2`, `text_loc3`, `text_loc4`, `text_loc5`, `text_loc6`, `text_loc7`, `text_loc8`) VALUES - (1, 'suggest_instance', 'Anyone wants %instance?', 0, 0, '', 'Quelqu\'un fait %instance ?', '', '', '', '', '', ''), - (2, 'suggest_instance', 'Any groups for %instance?', 0, 0, '', 'Des groupes pour %instance ?', '', '', '', '', '', ''), - (3, 'suggest_instance', 'Need help for %instance?', 0, 0, '', 'Besoin d\'aide pour %instance ?', '', '', '', '', '', ''), - (4, 'suggest_instance', 'LFD: %instance.', 0, 0, '', 'Cherche à faire : %instance', '', '', '', '', '', ''), - (5, 'suggest_instance', 'Anyone needs %role for %instance?', 0, 0, '', 'Quelqu\'un a besoin de %role pour %instance ?', '', '', '', '', '', ''), - (6, 'suggest_instance', 'Missing %role for %instance?', 0, 0, '', '%role manquant pour %instance ?', '', '', '', '', '', ''), - (7, 'suggest_instance', 'Can be a %role for %instance.', 0, 0, '', 'Peut être un %role pour %instance', '', '', '', '', '', ''), - (8, 'suggest_instance', 'Need help with %instance?', 0, 0, '', 'Besoin d\'aide avec %instance ?', '', '', '', '', '', ''), - (9, 'suggest_instance', 'Need %role help with %instance?', 0, 0, '', 'Besoin d\'aide %role avec %instance ?', '', '', '', '', '', ''), - (10, 'suggest_instance', 'Anyone needs gear from %instance?', 0, 0, '', 'Quelqu\'un a besoin d\'équipement de %instance ?', '', '', '', '', '', ''), - (11, 'suggest_instance', 'A little grind in %instance?', 0, 0, '', 'Un peu de grind dans %instance ?', '', '', '', '', '', ''), - (12, 'suggest_instance', 'WTR %instance', 0, 0, '', 'Cherche à rejoindre %instance', '', '', '', '', '', ''), - (13, 'suggest_instance', 'Need help for %instance.', 0, 0, '', 'Besoin d\'aide pour %instance', '', '', '', '', '', ''), - (14, 'suggest_instance', 'Wanna run %instance.', 0, 0, '', 'Je veux faire %instance', '', '', '', '', '', ''), - (15, 'suggest_instance', '%role looks for %instance.', 0, 0, '', '%role recherche %instance', '', '', '', '', '', ''), - (16, 'suggest_instance', 'What about %instance?', 0, 0, '', 'Et %instance ?', '', '', '', '', '', ''), - (17, 'suggest_instance', 'Who wants to farm %instance?', 0, 0, '', 'Qui veut exploiter %instance ?', '', '', '', '', '', ''), - (18, 'suggest_instance', 'Go in %instance?', 0, 0, '', 'Aller à %instance ?', '', '', '', '', '', ''), - (19, 'suggest_instance', 'Looking for %instance.', 0, 0, '', 'À la recherche de %instance', '', '', '', '', '', ''), + (1, 'suggest_instance', 'Anyone wants %instance?', 0, 0, '', 'Quelqu\'un fait %instance ?', '', '', '', '', '', ''), + (2, 'suggest_instance', 'Any groups for %instance?', 0, 0, '', 'Des groupes pour %instance ?', '', '', '', '', '', ''), + (3, 'suggest_instance', 'Need help for %instance?', 0, 0, '', 'Besoin d\'aide pour %instance ?', '', '', '', '', '', ''), + (4, 'suggest_instance', 'LFD: %instance.', 0, 0, '', 'Cherche à faire : %instance', '', '', '', '', '', ''), + (5, 'suggest_instance', 'Anyone needs %role for %instance?',0, 0, '', 'Quelqu\'un a besoin de %role pour %instance ?', '', '', '', '', '', ''), + (6, 'suggest_instance', 'Missing %role for %instance?', 0, 0, '', '%role manquant pour %instance ?', '', '', '', '', '', ''), + (7, 'suggest_instance', 'Can be a %role for %instance.', 0, 0, '', '%role disponible pour %instance', '', '', '', '', '', ''), + (8, 'suggest_instance', 'Need help with %instance?', 0, 0, '', 'Besoin d\'aide avec %instance ?', '', '', '', '', '', ''), + (9, 'suggest_instance', 'Need %role help with %instance?', 0, 0, '', 'Besoin d\'aide %role avec %instance ?', '', '', '', '', '', ''), + (10, 'suggest_instance', 'Anyone needs gear from %instance?',0, 0, '', 'Quelqu\'un a besoin d\'équipement de %instance ?', '', '', '', '', '', ''), + (11, 'suggest_instance', 'A little grind in %instance?', 0, 0, '', 'Un peu de grind dans %instance ?', '', '', '', '', '', ''), + (12, 'suggest_instance', 'WTR %instance', 0, 0, '', 'Cherche à rejoindre %instance', '', '', '', '', '', ''), + (13, 'suggest_instance', 'Need help for %instance.', 0, 0, '', 'Besoin d\'aide pour %instance', '', '', '', '', '', ''), + (14, 'suggest_instance', 'Wanna run %instance.', 0, 0, '', 'Je veux faire %instance', '', '', '', '', '', ''), + (15, 'suggest_instance', '%role looks for %instance.', 0, 0, '', '%role recherche %instance', '', '', '', '', '', ''), + (16, 'suggest_instance', 'What about %instance?', 0, 0, '', 'Et %instance ?', '', '', '', '', '', ''), + (17, 'suggest_instance', 'Who wants to farm %instance?', 0, 0, '', 'Qui veut exploiter %instance ?', '', '', '', '', '', ''), + (18, 'suggest_instance', 'Go in %instance?', 0, 0, '', 'Aller à %instance ?', '', '', '', '', '', ''), + (19, 'suggest_instance', 'Looking for %instance.', 0, 0, '', 'À la recherche de %instance', '', '', '', '', '', ''), (20, 'suggest_instance', 'Need help with %instance quests?', 0, 0, '', 'Besoin d\'aide pour les quêtes %instance ?', '', '', '', '', '', ''), - (21, 'suggest_instance', 'Wanna quest in %instance.', 0, 0, '', 'Je veux une quête dans %instance', '', '', '', '', '', ''), + (21, 'suggest_instance', 'Wanna quest in %instance.', 0, 0, '', 'Je veux une quête dans %instance', '', '', '', '', '', ''), (22, 'suggest_instance', 'Anyone with quests in %instance?', 0, 0, '', 'Quelqu\'un a des quêtes dans %instance ?', '', '', '', '', '', ''), (23, 'suggest_instance', 'Could help with quests in %instance.', 0, 0, '', 'Peux aider pour les quêtes dans %instance', '', '', '', '', '', ''), (24, 'suggest_instance', '%role: any place in group for %instance?', 0, 0, '', '%role : n\'importe quel rôle dans le groupe pour %instance ?', '', '', '', '', '', ''), @@ -47,62 +47,62 @@ INSERT INTO `ai_playerbot_texts` (`id`, `name`, `text`, `say_type`, `reply_type` (27, 'suggest_instance', 'Is there any point being %role in %instance?', 0, 0, '', 'Y a-t-il un intérêt à être %role dans %instance ?', '', '', '', '', '', ''), (28, 'suggest_instance', 'It is really worth to go to %instance?', 0, 0, '', 'Cela vaut-il vraiment la peine d\'aller dans %instance ?', '', '', '', '', '', ''), (29, 'suggest_instance', 'Anybody needs more people for %instance?', 0, 0, '', 'Quelqu\'un a besoin de plus de personnes pour %instance ?', '', '', '', '', '', ''), - (30, 'suggest_instance', '%instance bosses drop good gear. Wanna run?', 0, 0, '', 'Les boss %instance drop du bon équipement. Tu veux courir ?', '', '', '', '', '', ''), - (31, 'suggest_instance', 'What about %instance?', 0, 0, '', 'Et %instance ?', '', '', '', '', '', ''), - (32, 'suggest_instance', 'Anybody needs %role?', 0, 0, '', 'Quelqu\'un a besoin de %role ?', '', '', '', '', '', ''), - (33, 'suggest_instance', 'Anyone needs %role?', 0, 0, '', 'Quelqu\'un a besoin de %role ?', '', '', '', '', '', ''), - (34, 'suggest_instance', 'Who wants %instance?', 0, 0, '', 'Qui veut %instance ?', '', '', '', '', '', ''), + (30, 'suggest_instance', '%instance bosses drop good gear. Wanna run?', 0, 0, '', 'Les boss %instance drop du bon équipement. Tu veux nous rejoindre ?', '', '', '', '', '', ''), + (31, 'suggest_instance', 'What about %instance?', 0, 0, '', 'Et %instance ?', '', '', '', '', '', ''), + (32, 'suggest_instance', 'Anybody needs %role?', 0, 0, '', 'Quelqu\'un a besoin de %role ?', '', '', '', '', '', ''), + (33, 'suggest_instance', 'Anyone needs %role?', 0, 0, '', 'Quelqu\'un a besoin de %role ?', '', '', '', '', '', ''), + (34, 'suggest_instance', 'Who wants %instance?', 0, 0, '', 'Qui veut %instance ?', '', '', '', '', '', ''), (35, 'suggest_instance', 'Can anybody summon me at %instance?', 0, 0, '', 'Quelqu\'un peut-il me TP à %instance ?', '', '', '', '', '', ''), - (36, 'suggest_instance', 'Meet me in %instance', 0, 0, '', 'Rencontrez-moi dans %instance', '', '', '', '', '', ''), - (37, 'suggest_instance', 'Wanna quick %instance run', 0, 0, '', 'Je veux faire rapidement %instance', '', '', '', '', '', ''), - (38, 'suggest_instance', 'Wanna full %instance run', 0, 0, '', 'Je veux faire %instance complètement', '', '', '', '', '', ''), + (36, 'suggest_instance', 'Meet me in %instance', 0, 0, '', 'Rencontrez-moi dans %instance', '', '', '', '', '', ''), + (37, 'suggest_instance', 'Wanna quick %instance run', 0, 0, '', 'Je veux faire rapidement %instance', '', '', '', '', '', ''), + (38, 'suggest_instance', 'Wanna full %instance run', 0, 0, '', 'Je veux faire %instance complètement', '', '', '', '', '', ''), (39, 'suggest_instance', 'How many times were you in %instance?', 0, 0, '', 'Combien de fois avez-vous été dans %instance ?', '', '', '', '', '', ''), - (40, 'suggest_instance', 'Another %instance run?', 0, 0, '', 'Une autre exécution de %instance ?', '', '', '', '', '', ''), + (40, 'suggest_instance', 'Another %instance run?', 0, 0, '', 'Une autre exécution de %instance ?', '', '', '', '', '', ''), (41, 'suggest_instance', 'Wiped in %instance? Take me instead!', 0, 0, '', 'Effacé dans %instance ? Prends-moi plutôt !', '', '', '', '', '', ''), - (42, 'suggest_instance', 'Take me in %instance please.', 0, 0, '', 'Prenez-moi dans %instance s\'il vous plaît.', '', '', '', '', '', ''), - (43, 'suggest_instance', 'Quick %instance run?', 0, 0, '', 'Faire rapidement %instance ?', '', '', '', '', '', ''), - (44, 'suggest_instance', 'Full %instance run?', 0, 0, '', 'Clean complet dans %instance ?', '', '', '', '', '', ''), + (42, 'suggest_instance', 'Take me in %instance please.', 0, 0, '', 'Prenez-moi dans %instance s\'il vous plaît.', '', '', '', '', '', ''), + (43, 'suggest_instance', 'Quick %instance run?', 0, 0, '', 'Faire rapidement %instance ?', '', '', '', '', '', ''), + (44, 'suggest_instance', 'Full %instance run?', 0, 0, '', 'Clean complet dans %instance ?', '', '', '', '', '', ''), (45, 'suggest_instance', 'Who can take %role to %instance?', 0, 0, '', 'Qui peut prendre %role à %instance ?', '', '', '', '', '', ''), - (46, 'suggest_quest', 'Need help with %quest?', 0, 0, '', 'Besoin d\'aide avec %quest ?', '', '', '', '', '', ''), - (47, 'suggest_quest', 'Anyone wants to share %quest?', 0, 0, '', 'Quelqu\'un veut partager %quest ?', '', '', '', '', '', ''), - (48, 'suggest_quest', 'Anyone doing %quest?', 0, 0, '', 'Quelqu\'un fait %quest ?', '', '', '', '', '', ''), - (49, 'suggest_quest', 'Wanna do %quest.', 0, 0, '', 'Je veux faire %quest', '', '', '', '', '', ''), - (50, 'suggest_trade', 'Anyone to farm %category?', 0, 0, '', 'Quelqu\'un pour farm %category ?', '', '', '', '', '', ''), + (46, 'suggest_quest', 'Need help with %quest?', 0, 0, '', 'Besoin d\'aide avec %quest ?', '', '', '', '', '', ''), + (47, 'suggest_quest', 'Anyone wants to share %quest?', 0, 0, '', 'Quelqu\'un veut partager %quest ?', '', '', '', '', '', ''), + (48, 'suggest_quest', 'Anyone doing %quest?', 0, 0, '', 'Quelqu\'un fait %quest ?', '', '', '', '', '', ''), + (49, 'suggest_quest', 'Wanna do %quest.', 0, 0, '', 'Je veux faire %quest', '', '', '', '', '', ''), + (50, 'suggest_trade', 'Anyone to farm %category?', 0, 0, '', 'Quelqu\'un pour farm %category ?', '', '', '', '', '', ''), (51, 'suggest_trade', 'Looking for help farming %category.', 0, 0, '', 'Vous cherchez de l\'aide pour farmer %category', '', '', '', '', '', ''), - (52, 'suggest_trade', 'Damn %category are so expensive!', 0, 0, '', 'Putain %category sont si chers!', '', '', '', '', '', ''), - (53, 'suggest_trade', 'Wanna %category.', 0, 0, '', 'Je veux %category', '', '', '', '', '', ''), - (54, 'suggest_trade', 'Need help with %category.', 0, 0, '', 'Besoin d\'aide avec %category', '', '', '', '', '', ''), - (55, 'suggest_trade', 'WTB %category.', 0, 0, '', 'Cherche à acheter %category', '', '', '', '', '', ''), - (56, 'suggest_trade', 'Anyone interested in %category?', 0, 0, '', 'Quiconque est intéressé par %category?', '', '', '', '', '', ''), - (57, 'suggest_trade', 'WTS %category.', 0, 0, '', 'Cherche à vendre %category', '', '', '', '', '', ''), + (52, 'suggest_trade', 'Damn %category are so expensive!', 0, 0, '', 'Putain %category sont si chers!', '', '', '', '', '', ''), + (53, 'suggest_trade', 'Wanna %category.', 0, 0, '', 'Je veux %category', '', '', '', '', '', ''), + (54, 'suggest_trade', 'Need help with %category.', 0, 0, '', 'Besoin d\'aide avec %category', '', '', '', '', '', ''), + (55, 'suggest_trade', 'WTB %category.', 0, 0, '', 'Cherche à acheter %category', '', '', '', '', '', ''), + (56, 'suggest_trade', 'Anyone interested in %category?', 0, 0, '', 'Quiconque est intéressé par %category?', '', '', '', '', '', ''), + (57, 'suggest_trade', 'WTS %category.', 0, 0, '', 'Cherche à vendre %category', '', '', '', '', '', ''), (58, 'suggest_trade', 'I am selling %category cheaper than AH.', 0, 0, '', 'Je vends %category moins cher que l\'hôtel des ventes.', '', '', '', '', '', ''), - (59, 'suggest_trade', 'Who wants to farm %category?', 0, 0, '', 'Qui veut farmer %category ?', '', '', '', '', '', ''), - (60, 'suggest_trade', 'Wanna farm %category.', 0, 0, '', 'Je veux farmer %category', '', '', '', '', '', ''), + (59, 'suggest_trade', 'Who wants to farm %category?', 0, 0, '', 'Qui veut farmer %category ?', '', '', '', '', '', ''), + (60, 'suggest_trade', 'Wanna farm %category.', 0, 0, '', 'Je veux farmer %category', '', '', '', '', '', ''), (61, 'suggest_trade', 'Looking for party after %category.', 0, 0, '', 'Recherche de partie après %category', '', '', '', '', '', ''), - (62, 'suggest_trade', 'Any %category are appreciated.', 0, 0, '', 'Toute %category est appréciée.', '', '', '', '', '', ''), - (63, 'suggest_trade', 'Buying anything of %category.', 0, 0, '', 'Acheter quoi que ce soit de %category', '', '', '', '', '', ''), + (62, 'suggest_trade', 'Any %category are appreciated.', 0, 0, '', 'Toute %category est appréciée.', '', '', '', '', '', ''), + (63, 'suggest_trade', 'Buying anything of %category.', 0, 0, '', 'Acheter quoi que ce soit de %category', '', '', '', '', '', ''), (64, 'suggest_trade', 'Wow, anybody is farming %category!', 0, 0, '', 'Wow, quelqu\'un farm %category !', '', '', '', '', '', ''), (65, 'suggest_trade', '%category are selling mad in the AH.', 0, 0, '', '%category se vendent follement dans l\'hôtel des ventes.', '', '', '', '', '', ''), - (66, 'suggest_trade', 'AH is hot for %category.', 0, 0, '', 'Hôtel des ventes est chaud pour %category', '', '', '', '', '', ''), - (67, 'suggest_trade', '%category are on the market.', 0, 0, '', '%category sont sur le marché.', '', '', '', '', '', ''), - (68, 'suggest_trade', 'Wanna trade some %category.', 0, 0, '', 'Je veux échanger une %category', '', '', '', '', '', ''), - (69, 'suggest_trade', 'Need more %category.', 0, 0, '', 'Besoin de plus de %category', '', '', '', '', '', ''), - (70, 'suggest_trade', 'Anybody can spare some %category?', 0, 0, '', 'Quelqu\'un peut-il épargner une %category ?', '', '', '', '', '', ''), - (71, 'suggest_trade', 'Who wants %category?', 0, 0, '', 'Qui veut %category ?', '', '', '', '', '', ''), - (72, 'suggest_trade', 'Some %category please?', 0, 0, '', 'Une %category s\'il vous plaît ?', '', '', '', '', '', ''), + (66, 'suggest_trade', 'AH is hot for %category.', 0, 0, '', 'Hôtel des ventes est chaud pour %category', '', '', '', '', '', ''), + (67, 'suggest_trade', '%category are on the market.', 0, 0, '', '%category sont sur le marché.', '', '', '', '', '', ''), + (68, 'suggest_trade', 'Wanna trade some %category.', 0, 0, '', 'Je veux échanger une %category', '', '', '', '', '', ''), + (69, 'suggest_trade', 'Need more %category.', 0, 0, '', 'Besoin de plus de %category', '', '', '', '', '', ''), + (70, 'suggest_trade', 'Anybody can spare some %category?', 0, 0, '', 'Quelqu\'un peut-il épargner une %category ?', '', '', '', '', '', ''), + (71, 'suggest_trade', 'Who wants %category?', 0, 0, '', 'Qui veut %category ?', '', '', '', '', '', ''), + (72, 'suggest_trade', 'Some %category please?', 0, 0, '', 'Une %category s\'il vous plaît ?', '', '', '', '', '', ''), (73, 'suggest_trade', 'I should have got skill for %category.', 0, 0, '', 'J\'aurais dû avoir une compétence pour %category', '', '', '', '', '', ''), - (74, 'suggest_trade', 'I am dying for %category.', 0, 0, '', 'Je meurs d\'envie pour %category', '', '', '', '', '', ''), - (75, 'suggest_trade', 'People are killing for %category.', 0, 0, '', 'Les gens tuent pour %category', '', '', '', '', '', ''), - (76, 'suggest_trade', '%category is a great bargain!', 0, 0, '', '%category est une bonne affaire!', '', '', '', '', '', ''), - (77, 'suggest_trade', 'Everybody is mad for %category!', 0, 0, '', 'Tout le monde est fou de %category !', '', '', '', '', '', ''), + (74, 'suggest_trade', 'I am dying for %category.', 0, 0, '', 'Je meurs d\'envie pour %category', '', '', '', '', '', ''), + (75, 'suggest_trade', 'People are killing for %category.', 0, 0, '', 'Les gens tuent pour %category', '', '', '', '', '', ''), + (76, 'suggest_trade', '%category is a great bargain!', 0, 0, '', '%category est une bonne affaire!', '', '', '', '', '', ''), + (77, 'suggest_trade', 'Everybody is mad for %category!', 0, 0, '', 'Tout le monde est fou de %category !', '', '', '', '', '', ''), (78, 'suggest_trade', 'Where is the best place to farm for %category?', 0, 0, '', 'Quel est le meilleur endroit pour farmer pour %category ?', '', '', '', '', '', ''), - (79, 'suggest_trade', 'I am all set for %category.', 0, 0, '', 'Je suis prêt pour %category', '', '', '', '', '', ''), - (80, 'suggest_trade', 'Is it good to sell %category?', 0, 0, '', 'Est-il bon de vendre %category ?', '', '', '', '', '', ''), + (79, 'suggest_trade', 'I am all set for %category.', 0, 0, '', 'Je suis prêt pour %category', '', '', '', '', '', ''), + (80, 'suggest_trade', 'Is it good to sell %category?', 0, 0, '', 'Est-il bon de vendre %category ?', '', '', '', '', '', ''), (81, 'suggest_trade', 'I\'d probably keep all my %category with me.', 0, 0, '', 'Je garderais probablement toute ma %category avec moi.', '', '', '', '', '', ''), (82, 'suggest_trade', 'Need group? Maybe to farm some %category?', 0, 0, '', 'Besoin de groupe ? Peut-être pour farmer une certaine %category ?', '', '', '', '', '', ''), (83, 'suggest_trade', 'I am still thinking about %category.', 0, 0, '', 'Je pense toujours à %category', '', '', '', '', '', ''), (84, 'suggest_trade', 'I heard about %category already, but my pockets are empty.', 0, 0, '', 'J\'ai déjà entendu parler de %category , mais mes poches sont vides.', '', '', '', '', '', ''), - (85, 'suggest_trade', 'LFG for %category', 0, 0, '', 'Cherche un groupe pour %category', '', '', '', '', '', ''), + (85, 'suggest_trade', 'LFG for %category', 0, 0, '', 'Cherche un groupe pour %category', '', '', '', '', '', ''), (86, 'suggest_trade', 'Would selling %category make me rich?', 0, 0, '', 'Vendre %category me rendrait-il riche?', '', '', '', '', '', ''), (87, 'suggest_trade', 'OK. I an farming %category tomorrow.', 0, 0, '', 'D\'ACCORD. Je farm %category demain.', '', '', '', '', '', ''), (88, 'suggest_trade', 'Everyone is talking about %category.', 0, 0, '', 'Tout le monde parle de %category', '', '', '', '', '', ''), @@ -518,41 +518,41 @@ INSERT INTO `ai_playerbot_texts` (`id`, `name`, `text`, `say_type`, `reply_type` (498, 'no ammo', 'That\'s it! No !', 0, 0, '', 'C\'est ça! Pas de !', '', '', '', '', '', ''), (499, 'no ammo', 'And you have my bow... Oops, no !', 0, 0, '', 'Et vous avez mon arc... Oups, pas de !', '', '', '', '', '', ''), (500, 'no ammo', 'Need ammo!', 0, 0, '', 'Besoin de munitions!', '', '', '', '', '', ''), - (501, 'hello', 'Hello', 0, 0, '', '', '', '', '', '', '', 'Привет'), - (502, 'hello', 'Hello!', 0, 0, '', '', '', '', '', '', '', 'Привет!'), - (503, 'hello', 'Hi', 0, 0, '', '', '', '', '', '', '', 'Прив'), - (504, 'hello', 'Hi!', 0, 0, '', '', '', '', '', '', '', 'Прив!'), - (505, 'hello', 'Hello there!', 0, 0, '', '', '', '', '', '', '', 'Здарова!'), - (506, 'hello_follow', 'Hello, I follow you!', 0, 0, '', '', '', '', '', '', '', 'Привет, иду за тобой!'), - (507, 'hello_follow', 'Hello, lead the way!', 0, 0, '', '', '', '', '', '', '', 'Привет, веди!'), - (508, 'hello_follow', 'Hi, lead the way!', 0, 0, '', '', '', '', '', '', '', 'Прив, веди!'), - (509, 'logout_cancel', 'Logout cancelled!', 0, 0, '', '', '', '', '', '', '', 'Логаут отменен!'), - (510, 'logout_start', 'I\'m logging out!', 0, 0, '', '', '', '', '', '', '', 'Я выхожу из игры!'), - (511, 'goodbye', 'Goodbye!', 0, 0, '', '', '', '', '', '', '', 'Пока!'), - (512, 'goodbye', 'Bye bye!', 0, 0, '', '', '', '', '', '', '', 'Пока пока!'), - (513, 'goodbye', 'See you later!', 0, 0, '', '', '', '', '', '', '', 'Увидимся позже!'), - (514, 'quest_accept', 'Quest accepted', 0, 0, '', '', '', '', '', '', '', 'Квест взят'), - (515, 'quest_remove', 'Quest removed', 0, 0, '', '', '', '', '', '', '', 'Квест отменен'), - (516, 'quest_cant_take', 'I can\'t take this quest', 0, 0, '', '', '', '', '', '', '', 'Я не могу взять этот квест'), - (517, 'following', 'Following', 0, 0, '', '', '', '', '', '', '', 'Следую'), - (518, 'staying', 'Staying', 0, 0, '', '', '', '', '', '', '', 'Стою'), - (519, 'fleeing', 'Fleeing', 0, 0, '', '', '', '', '', '', '', 'Убегаю'), - (520, 'fleeing_far', 'I won\'t flee with you, you are too far away', 0, 0, '', '', '', '', '', '', '', 'Я с тобой не побегу, ты слишком далеко'), - (521, 'grinding', 'Grinding', 0, 0, '', '', '', '', '', '', '', 'Гриндю'), - (522, 'attacking', 'Attacking', 0, 0, '', '', '', '', '', '', '', 'Атакую'), - (523, 'wait_travel_close', 'I am close, wait for me!', 0, 0, '', '', '', '', '', '', '', 'Я тут рядом, подожди!'), - (524, 'wait_travel_close', 'I\'m not far, please wait!', 0, 0, '', '', '', '', '', '', '', 'Я недалеко, погодите!'), - (525, 'wait_travel_medium', 'I\'m heading to your location', 0, 0, '', '', '', '', '', '', '', 'Двигаюсь к тебе'), - (526, 'wait_travel_medium', 'I\'m coming to you', 0, 0, '', '', '', '', '', '', '', 'Иду к тебе'), - (527, 'wait_travel_far', 'I\'m traveling to your location', 0, 0, '', '', '', '', '', '', '', 'Направляюсь к тебе'), - (528, 'wait_travel_far', 'I\'m trying to get to you', 0, 0, '', '', '', '', '', '', '', 'Пытаюсь до тебя добраться'), - (529, 'error_far', 'It is too far away', 0, 0, '', '', '', '', '', '', '', 'Слишком далеко'), - (530, 'error_water', 'It is under water', 0, 0, '', '', '', '', '', '', '', 'Это под водой'), - (531, 'error_cant_go', 'I can\'t go there', 0, 0, '', '', '', '', '', '', '', 'Я не могу туда пройти'), - (532, 'error_guild', 'I\'m not in your guild!', 0, 0, '', '', '', '', '', '', '', 'Я не в твоей гильдии'), - (533, 'error_gbank_found', 'Can not find a guild bank nearby', 0, 0, '', '', '', '', '', '', '', 'Не могу найти гильд банк рядом'), + (501, 'hello', 'Hello', 0, 0, '', 'Salut', '', '', '', '', '', 'Привет'), + (502, 'hello', 'Hello!', 0, 0, '', 'Salut !', '', '', '', '', '', 'Привет!'), + (503, 'hello', 'Hi', 0, 0, '', 'Bonjour', '', '', '', '', '', 'Прив'), + (504, 'hello', 'Hi!', 0, 0, '', 'Bonjour !', '', '', '', '', '', 'Прив!'), + (505, 'hello', 'Hello there!', 0, 0, '', 'Salut par ici !', '', '', '', '', '', 'Здарова!'), + (506, 'hello_follow', 'Hello, I follow you!', 0, 0, '', 'Salut, je te suis !', '', '', '', '', '', 'Привет, иду за тобой!'), + (507, 'hello_follow', 'Hello, lead the way!', 0, 0, '', 'Salut, après toi !', '', '', '', '', '', 'Привет, веди!'), + (508, 'hello_follow', 'Hi, lead the way!', 0, 0, '', 'Bonjour, après vous !', '', '', '', '', '', 'Прив, веди!'), + (509, 'logout_cancel', 'Logout cancelled!', 0, 0, '', 'Logout annulé', '', '', '', '', '', 'Логаут отменен!'), + (510, 'logout_start', 'I\'m logging out!', 0, 0, '', 'Je déconnecte', '', '', '', '', '', 'Я выхожу из игры!'), + (511, 'goodbye', 'Goodbye!', 0, 0, '', 'Au revoir', '', '', '', '', '', 'Пока!'), + (512, 'goodbye', 'Bye bye!', 0, 0, '', 'Salut salut++', '', '', '', '', '', 'Пока пока!'), + (513, 'goodbye', 'See you later!', 0, 0, '', 'A plus tard', '', '', '', '', '', 'Увидимся позже!'), + (514, 'quest_accept', 'Quest accepted', 0, 0, '', 'Quête accepté', '', '', '', '', '', 'Квест взят'), + (515, 'quest_remove', 'Quest removed', 0, 0, '', 'Quête supprimé', '', '', '', '', '', 'Квест отменен'), + (516, 'quest_cant_take', 'I can\'t take this quest', 0, 0, '', 'Je ne peut pas prendre la quête', '', '', '', '', '', 'Я не могу взять этот квест'), + (517, 'following', 'Following', 0, 0, '', 'Je vous suis', '', '', '', '', '', 'Следую'), + (518, 'staying', 'Staying', 0, 0, '', 'Je reste en position', '', '', '', '', '', 'Стою'), + (519, 'fleeing', 'Fleeing', 0, 0, '', 'Au secours !!', '', '', '', '', '', 'Убегаю'), + (520, 'fleeing_far', 'I won\'t flee with you, you are too far away', 0, 0, '', 'Tu es trop loin je ne peut pas fuir avec toi', '', '', '', '', '', 'Я с тобой не побегу, ты слишком далеко'), + (521, 'grinding', 'Grinding', 0, 0, '', 'Je grind', '', '', '', '', '', 'Гриндю'), + (522, 'attacking', 'Attacking', 0, 0, '', 'J'attack', '', '', '', '', '', 'Атакую'), + (523, 'wait_travel_close', 'I am close, wait for me!', 0, 0, '', 'Attends moi je suis proche', '', '', '', '', '', 'Я тут рядом, подожди!'), + (524, 'wait_travel_close', 'I\'m not far, please wait!', 0, 0, '', 'Je suis à côté s\'il te plait attends moi !', '', '', '', '', '', 'Я недалеко, погодите!'), + (525, 'wait_travel_medium', 'I\'m heading to your location', 0, 0, '', 'J\'arrive sur ta position', '', '', '', '', '', 'Двигаюсь к тебе'), + (526, 'wait_travel_medium', 'I\'m coming to you', 0, 0, '', 'Je viens à toi', '', '', '', '', '', 'Иду к тебе'), + (527, 'wait_travel_far', 'I\'m traveling to your location', 0, 0, '', 'Je voyage jusqu\'à toi'', '', '', '', '', '', 'Направляюсь к тебе'), + (528, 'wait_travel_far', 'I\'m trying to get to you', 0, 0, '', 'J\'essai de vous rejoindre', '', '', '', '', '', 'Пытаюсь до тебя добраться'), + (529, 'error_far', 'It is too far away', 0, 0, '', 'C\'est trop loin'', '', '', '', '', '', 'Слишком далеко'), + (530, 'error_water', 'It is under water', 0, 0, '', 'C\'est sous l\'eau', '', '', '', '', '', 'Это под водой'), + (531, 'error_cant_go', 'I can\'t go there', 0, 0, '', 'Je ne peut pas atteindre cette destination', '', '', '', '', '', 'Я не могу туда пройти'), + (532, 'error_guild', 'I\'m not in your guild!', 0, 0, '', 'Je ne fais pas parti de ta guilde', '', '', '', '', '', 'Я не в твоей гильдии'), + (533, 'error_gbank_found', 'Can not find a guild bank nearby', 0, 0, '', 'Il n\'y a pas de coffre de guilde à proximité'', '', '', '', '', '', 'Не могу найти гильд банк рядом'), (534, 'error_cant_put', 'I can\'t put ', 0, 0, '', '', '', '', '', '', '', 'Я не могу положить'), - (535, 'error_gbank_rights', 'I have no rights to put items in the first guild bank tab', 0, 0, '', '', '', '', '', '', '', 'Нет прав чтобы класть вещи в первую вкладку гильд банка'), + (535, 'error_gbank_rights', 'I have no rights to put items in the first guild bank tab', 0, 0, '', 'Je n'ai pas les droits de dépôt à la banque', '', '', '', '', '', 'Нет прав чтобы класть вещи в первую вкладку гильд банка'), (536, 'gbank_put', ' put to guild bank', 0, 0, '', '', '', '', '', '', '', ' теперь в гильд банке'); /*!40000 ALTER TABLE `ai_playerbot_texts` ENABLE KEYS */; From 21a6628161d5367c5d18f090d31cad54c8417fe1 Mon Sep 17 00:00:00 2001 From: antony Date: Thu, 25 Jul 2024 13:31:08 +0200 Subject: [PATCH 20/61] French + locale dbc use fix --- src/PlayerbotMgr.cpp | 6 +- src/PlayerbotTextMgr.cpp | 2 + src/strategy/actions/SayAction.cpp | 15 ++- .../actions/SuggestWhatToDoAction.cpp | 119 ++++++++++++++---- src/strategy/actions/SuggestWhatToDoAction.h | 2 + 5 files changed, 110 insertions(+), 34 deletions(-) diff --git a/src/PlayerbotMgr.cpp b/src/PlayerbotMgr.cpp index f236d769..c72e7a7b 100644 --- a/src/PlayerbotMgr.cpp +++ b/src/PlayerbotMgr.cpp @@ -544,13 +544,13 @@ void PlayerbotHolder::OnBotLogin(Player* const bot) Channel* new_channel = nullptr; if (isLfg) { - std::string lfgChannelName = channel->pattern[0]; - new_channel = cMgr->GetJoinChannel("LookingForGroup", channel->ChannelID); + std::string lfgChannelName = channel->pattern[sWorld->GetDefaultDbcLocale()]; + new_channel = cMgr->GetJoinChannel(lfgChannelName, channel->ChannelID); } else { char new_channel_name_buf[100]; - snprintf(new_channel_name_buf, 100, channel->pattern[0], current_zone_name.c_str()); + snprintf(new_channel_name_buf, 100, channel->pattern[sWorld->GetDefaultDbcLocale()], current_zone_name.c_str()); new_channel = cMgr->GetJoinChannel(new_channel_name_buf, channel->ChannelID); } if (new_channel && new_channel->GetName().length() > 0) diff --git a/src/PlayerbotTextMgr.cpp b/src/PlayerbotTextMgr.cpp index acfaada8..64261314 100644 --- a/src/PlayerbotTextMgr.cpp +++ b/src/PlayerbotTextMgr.cpp @@ -191,6 +191,8 @@ uint32 PlayerbotTextMgr::GetLocalePriority() if (botTextLocalePriority[i] > topLocale) topLocale = i; } + + LOG_INFO("playerbots", "GetLocalePriority: {}", topLocale); return topLocale; } diff --git a/src/strategy/actions/SayAction.cpp b/src/strategy/actions/SayAction.cpp index 02f03499..4b68a323 100644 --- a/src/strategy/actions/SayAction.cpp +++ b/src/strategy/actions/SayAction.cpp @@ -105,6 +105,9 @@ bool SayAction::isUseful() if (!botAI->AllowActivity()) return false; + if (botAI->HasStrategy("silent", BotState::BOT_STATE_NON_COMBAT)) + return false; + time_t lastSaid = AI_VALUE2(time_t, "last said", qualifier); return (time(nullptr) - lastSaid) > 30; } @@ -160,7 +163,8 @@ void ChatReplyAction::ChatReplyDo(Player* bot, uint32 type, uint32 guid1, uint32 // } // } // - if (word[i] == "hi" || word[i] == "hey" || word[i] == "hello" || word[i] == "wazzup") + if (word[i] == "hi" || word[i] == "hey" || word[i] == "hello" || word[i] == "wazzup" + || word[i] == "salut" || word[i] == "plop" || word[i] == "yo") { replyType = REPLY_HELLO; found = true; @@ -169,22 +173,23 @@ void ChatReplyAction::ChatReplyDo(Player* bot, uint32 type, uint32 guid1, uint32 if (verb_type < 4) { - if (word[i] == "am" || word[i] == "are" || word[i] == "is") + if (word[i] == "am" || word[i] == "are" || word[i] == "is" || word[i] == "suis" || word[i] == "a" || word[i] == "est" + || word[i] == "dois" || word[i] == "doit") { verb_pos = i; verb_type = 2; // present } - else if (word[i] == "will") + else if (word[i] == "will" || word[i] == "vais" || word[i] == "sera") { verb_pos = i; verb_type = 3; // future } - else if (word[i] == "was" || word[i] == "were") + else if (word[i] == "was" || word[i] == "were" || word[i] == "été" || word[i] == "ai" || word[i] == "eu" || word[i] == "étions" || word[i] == "etion" ) { verb_pos = i; verb_type = 1; // past } - else if (word[i] == "shut" || word[i] == "noob") + else if (word[i] == "shut" || word[i] == "noob" || word[i] == "tg") { if (msg.find(bot->GetName()) == std::string::npos) { diff --git a/src/strategy/actions/SuggestWhatToDoAction.cpp b/src/strategy/actions/SuggestWhatToDoAction.cpp index 3c797193..fa8eada1 100644 --- a/src/strategy/actions/SuggestWhatToDoAction.cpp +++ b/src/strategy/actions/SuggestWhatToDoAction.cpp @@ -11,15 +11,39 @@ #include "Playerbots.h" #include "PlayerbotTextMgr.h" #include "GuildMgr.h" +#include "Config.h" + +enum eTalkType +{ + General = ChannelFlags::CHANNEL_FLAG_GENERAL | ChannelFlags::CHANNEL_FLAG_NOT_LFG, + Trade = ChannelFlags::CHANNEL_FLAG_CITY | ChannelFlags::CHANNEL_FLAG_GENERAL | ChannelFlags::CHANNEL_FLAG_NOT_LFG | ChannelFlags::CHANNEL_FLAG_TRADE, + LocalDefence = ChannelFlags::CHANNEL_FLAG_GENERAL | ChannelFlags::CHANNEL_FLAG_NOT_LFG, + GuildRecruitment = ChannelFlags::CHANNEL_FLAG_CITY | ChannelFlags::CHANNEL_FLAG_GENERAL | ChannelFlags::CHANNEL_FLAG_NOT_LFG, + LookingForGroup = ChannelFlags::CHANNEL_FLAG_LFG | ChannelFlags::CHANNEL_FLAG_GENERAL +}; std::map SuggestWhatToDoAction::instances; std::map SuggestWhatToDoAction::factions; -SuggestWhatToDoAction::SuggestWhatToDoAction(PlayerbotAI* botAI, std::string const name) : InventoryAction(botAI, name) +SuggestWhatToDoAction::SuggestWhatToDoAction(PlayerbotAI* botAI, std::string const name) + : InventoryAction{ botAI, name } + , _dbc_locale{ sWorld->GetDefaultDbcLocale() } { suggestions.push_back(&SuggestWhatToDoAction::specificQuest); suggestions.push_back(&SuggestWhatToDoAction::grindReputation); suggestions.push_back(&SuggestWhatToDoAction::something); + suggestions.push_back(&SuggestWhatToDoAction::instance); + suggestions.push_back(&SuggestWhatToDoAction::grindMaterials); +} + +bool SuggestWhatToDoAction::isUseful() +{ + if (!sRandomPlayerbotMgr->IsRandomBot(bot) || bot->GetGroup() || bot->GetInstanceId()) + return false; + + std::string qualifier = "suggest what to do"; + time_t lastSaid = AI_VALUE2(time_t, "last said", qualifier); + return (time(0) - lastSaid) > 30; } bool SuggestWhatToDoAction::Execute(Event event) @@ -85,12 +109,12 @@ void SuggestWhatToDoAction::instance() instances["Halls of Reflection"] = 80; } - std::vector allowedInstances; - for (auto & instance : instances) + std::vector allowedInstances; + for (const auto& instance : instances) { - if (bot->GetLevel() >= instance.second) allowedInstances.push_back(instance.first); + if (bot->GetLevel() >= instance.second) + allowedInstances.push_back(instance.first); } - if (allowedInstances.empty()) return; std::map placeholders; @@ -101,7 +125,7 @@ void SuggestWhatToDoAction::instance() itemout << allowedInstances[urand(0, allowedInstances.size() - 1)]; placeholders["%instance"] = itemout.str(); - spam(BOT_TEXT2("suggest_instance", placeholders), urand(0, 1) ? 0x50 : 0, urand(0, 2), urand(0, 2)); + spam(BOT_TEXT2("suggest_instance", placeholders), urand(0, 1) ? eTalkType::LookingForGroup : 0, urand(0, 2), urand(0, 2)); } std::vector SuggestWhatToDoAction::GetIncompletedQuests() @@ -136,7 +160,52 @@ void SuggestWhatToDoAction::specificQuest() placeholders["%role"] = chat->FormatClass(bot, AiFactory::GetPlayerSpecTab(bot)); placeholders["%quest"] = chat->FormatQuest(quest); - spam(BOT_TEXT2("suggest_quest", placeholders), urand(0, 1) ? 0x18 : 0, urand(0, 2), urand(0, 2)); + spam(BOT_TEXT2("suggest_quest", placeholders), urand(0, 1) ? eTalkType::General : 0, urand(0, 2), urand(0, 2)); +} + +void SuggestWhatToDoAction::grindMaterials() +{ + /*if (bot->GetLevel() <= 5) + return; + + auto result = CharacterDatabase.Query("SELECT distinct category, multiplier FROM ahbot_category where category not in ('other', 'quest', 'trade', 'reagent') and multiplier > 3 order by multiplier desc limit 10"); + if (!result) + return; + + std::map categories; + do + { + Field* fields = result->Fetch(); + categories[fields[0].Get()] = fields[1].Get(); + } while (result->NextRow()); + + for (std::map::iterator i = categories.begin(); i != categories.end(); ++i) + { + if (urand(0, 10) < 3) { + std::string name = i->first; + double multiplier = i->second; + + for (int j = 0; j < ahbot::CategoryList::instance.size(); j++) + { + ahbot::Category* category = ahbot::CategoryList::instance[j]; + if (name == category->GetName()) + { + std::string item = category->GetLabel(); + transform(item.begin(), item.end(), item.begin(), ::tolower); + std::ostringstream itemout; + itemout << "|c0000b000" << item << "|r"; + item = itemout.str(); + + std::map placeholders; + placeholders["%role"] = chat->formatClass(bot, AiFactory::GetPlayerSpecTab(bot)); + placeholders["%category"] = item; + + spam(BOT_TEXT2("suggest_trade", placeholders), urand(0, 1) ? 0x3C : 0x18, !urand(0, 2), !urand(0, 3)); + return; + } + } + } + }*/ } void SuggestWhatToDoAction::grindReputation() @@ -179,18 +248,17 @@ void SuggestWhatToDoAction::grindReputation() factions["The Wyrmrest Accord"] = 77; } - std::vector levels; + std::vector levels; levels.push_back("honored"); levels.push_back("revered"); levels.push_back("exalted"); - std::vector allowedFactions; - for (std::map::iterator i = factions.begin(); i != factions.end(); ++i) + std::vector allowedFactions; + for (const auto& i : factions) { - if (bot->GetLevel() >= i->second) - allowedFactions.push_back(i->first); + if (bot->GetLevel() >= i.second) + allowedFactions.push_back(i.first); } - if (allowedFactions.empty()) return; @@ -207,7 +275,7 @@ void SuggestWhatToDoAction::grindReputation() itemout << allowedFactions[urand(0, allowedFactions.size() - 1)]; placeholders["%faction"] = itemout.str(); - spam(BOT_TEXT2("suggest_faction", placeholders), 0x18, true); + spam(BOT_TEXT2("suggest_faction", placeholders), eTalkType::General, true); } void SuggestWhatToDoAction::something() @@ -221,10 +289,10 @@ void SuggestWhatToDoAction::something() std::ostringstream out; // out << "|cffb04040" << entry->area_name[0] << "|r"; - out << entry->area_name[0]; + out << entry->area_name[_dbc_locale]; placeholders["%zone"] = out.str(); - spam(BOT_TEXT2("suggest_something", placeholders), urand(0, 1) ? 0x18 : 0, urand(0, 2), urand(0, 2)); + spam(BOT_TEXT2("suggest_something", placeholders), urand(0, 1) ? eTalkType::General : 0, urand(0, 2), urand(0, 2)); } void SuggestWhatToDoAction::spam(std::string msg, uint8 flags, bool worldChat, bool guild) @@ -237,12 +305,13 @@ void SuggestWhatToDoAction::spam(std::string msg, uint8 flags, bool worldChat, b if (!cMgr) return; - for (uint32 i = 0; i < sChatChannelsStore.GetNumRows(); ++i) { ChatChannelsEntry const* channel = sChatChannelsStore.LookupEntry(i); if (!channel) continue; + LOG_INFO("playerbots", "Loop on channel: {}", channel->pattern[_dbc_locale]); + for (AreaTableEntry const* current_zone : sAreaTableStore) { if (!current_zone) @@ -254,13 +323,15 @@ void SuggestWhatToDoAction::spam(std::string msg, uint8 flags, bool worldChat, b Channel* chn = nullptr; if ((channel->flags & CHANNEL_DBC_FLAG_LFG) != 0) { - std::string chanName = channel->pattern[0]; + std::string chanName = channel->pattern[_dbc_locale]; + LOG_INFO("playerbots", "Trying to chat on channel: {}", chanName); chn = cMgr->GetChannel(chanName, bot); } else { - snprintf(channelName, 100, channel->pattern[0], current_zone->area_name[0]); + snprintf(channelName, 100, channel->pattern[_dbc_locale], current_zone->area_name[_dbc_locale]); chn = cMgr->GetChannel(channelName, bot); + LOG_INFO("playerbots", "Trying to chat on channel: {}", channelName); } if (!chn) continue; @@ -287,8 +358,11 @@ void SuggestWhatToDoAction::spam(std::string msg, uint8 flags, bool worldChat, b if (!channelNames.empty()) { std::string randomName = channelNames[urand(0, channelNames.size() - 1)]; + LOG_INFO("playerbots", "Chatting on channel: {}", randomName); if (Channel* chn = cMgr->GetChannel(randomName, bot)) + { chn->Say(bot->GetGUID(), msg.c_str(), LANG_UNIVERSAL); + } } if (worldChat) @@ -403,10 +477,3 @@ bool SuggestTradeAction::Execute(Event event) spam(BOT_TEXT2("suggest_sell", placeholders), urand(0, 1) ? 0x3C : 0, urand(0, 1), urand(0, 5)); return true; } - -bool SuggestWhatToDoAction::isUseful() -{ - std::string const qualifier = "suggest what to do"; - time_t lastSaid = AI_VALUE2(time_t, "last said", qualifier); - return (time(nullptr) - lastSaid) > 30; -} diff --git a/src/strategy/actions/SuggestWhatToDoAction.h b/src/strategy/actions/SuggestWhatToDoAction.h index 4bff50cf..58fafd59 100644 --- a/src/strategy/actions/SuggestWhatToDoAction.h +++ b/src/strategy/actions/SuggestWhatToDoAction.h @@ -23,6 +23,7 @@ class SuggestWhatToDoAction : public InventoryAction void instance(); void specificQuest(); void grindReputation(); + void grindMaterials(); void something(); void spam(std::string msg, uint8 flags = 0, bool worldChat = false, bool guild = false); @@ -31,6 +32,7 @@ class SuggestWhatToDoAction : public InventoryAction private: static std::map instances; static std::map factions; + const int32_t& _dbc_locale; }; class SuggestTradeAction : public SuggestWhatToDoAction From 44b1b32e06ef2c0d8ad2db7aefd911e951981fb1 Mon Sep 17 00:00:00 2001 From: antony Date: Thu, 25 Jul 2024 15:06:25 +0200 Subject: [PATCH 21/61] Say debug + fixes --- src/strategy/actions/SayAction.cpp | 90 ++++++++++++++++++++++-------- 1 file changed, 68 insertions(+), 22 deletions(-) diff --git a/src/strategy/actions/SayAction.cpp b/src/strategy/actions/SayAction.cpp index 4b68a323..71b7664e 100644 --- a/src/strategy/actions/SayAction.cpp +++ b/src/strategy/actions/SayAction.cpp @@ -10,6 +10,16 @@ #include "GuildMgr.h" #include +static const std::unordered_set noReplyMsgs = { + "join", "leave", "follow", "attack", "pull", "flee", "reset", "reset ai", + "all ?", "talents", "talents list", "talents auto", "talk", "stay", "stats", + "who", "items", "leave", "join", "repair", "summon", "nc ?", "co ?", "de ?", + "dead ?", "follow", "los", "guard", "do accept invitation", "stats", "react ?", + "reset strats", "home", +}; +static const std::unordered_set noReplyMsgParts = { "+", "-","@" , "follow target", "focus heal", "cast ", "accept [", "e [", "destroy [", "go zone" }; +static const std::unordered_set noReplyMsgStarts = { "e ", "accept ", "cast ", "destroy " }; + SayAction::SayAction(PlayerbotAI* botAI) : Action(botAI, "say"), Qualified() { } @@ -114,9 +124,41 @@ bool SayAction::isUseful() void ChatReplyAction::ChatReplyDo(Player* bot, uint32 type, uint32 guid1, uint32 guid2, std::string msg, std::string chanName, std::string name) { + LOG_INFO("playerbots", "{} Handle chat reply", bot->GetName()); + ChatReplyType replyType = REPLY_NOT_UNDERSTAND; // default not understand std::string respondsText = ""; + // if we're just commanding bots around, don't respond... + // first one is for exact word matches + if (noReplyMsgs.find(msg) != noReplyMsgs.end()) { + std::ostringstream out; + out << "DEBUG ChatReplyDo decided to ignore exact blocklist match" << msg; + bot->Say(out.str(), LANG_UNIVERSAL); + return; + } + + // second one is for partial matches like + or - where we change strats + if (std::any_of(noReplyMsgParts.begin(), noReplyMsgParts.end(), [&msg](const std::string& part) { return msg.find(part) != std::string::npos; })) { + std::ostringstream out; + out << "DEBUG ChatReplyDo decided to ignore partial blocklist match" << msg; + bot->Say(out.str(), LANG_UNIVERSAL); + + return; + } + + if (std::any_of(noReplyMsgStarts.begin(), noReplyMsgStarts.end(), [&msg](const std::string& start) { + return msg.find(start) == 0; // Check if the start matches the beginning of msg + })) { + std::ostringstream out; + out << "DEBUG ChatReplyDo decided to ignore start blocklist match" << msg; + bot->Say(out.str(), LANG_UNIVERSAL); + return; + } + + ObjectGuid receiver = sCharacterCache->GetCharacterGuidByName(name); + Player* plr = ObjectAccessor::FindPlayer(receiver); + // Chat Logic int32 verb_pos = -1; int32 verb_type = -1; @@ -152,17 +194,14 @@ void ChatReplyAction::ChatReplyDo(Player* bot, uint32 type, uint32 guid1, uint32 // Responds for (uint32 i = 0; i < 8; i++) { -// // blame gm with chat tag -// if (Player* plr = sObjectMgr->GetPlayer(ObjectGuid(HIGHGUID_PLAYER, guid1))) -// { -// if (plr->isGMChat()) -// { -// replyType = REPLY_ADMIN_ABUSE; -// found = true; -// break; -// } -// } -// + // blame gm with chat tag + if (plr && plr->isGMChat()) + { + replyType = REPLY_ADMIN_ABUSE; + found = true; + break; + } + if (word[i] == "hi" || word[i] == "hey" || word[i] == "hello" || word[i] == "wazzup" || word[i] == "salut" || word[i] == "plop" || word[i] == "yo") { @@ -173,11 +212,13 @@ void ChatReplyAction::ChatReplyDo(Player* bot, uint32 type, uint32 guid1, uint32 if (verb_type < 4) { - if (word[i] == "am" || word[i] == "are" || word[i] == "is" || word[i] == "suis" || word[i] == "a" || word[i] == "est" + if (word[i] == "am" || word[i] == "are" || word[i] == "is" || word[i] == "suis" || word[i] == "as" || word[i] == "est" || word[i] == "dois" || word[i] == "doit") { verb_pos = i; verb_type = 2; // present + if (verb_pos == 0) + is_quest = 1; } else if (word[i] == "will" || word[i] == "vais" || word[i] == "sera") { @@ -605,19 +646,19 @@ void ChatReplyAction::ChatReplyDo(Player* bot, uint32 type, uint32 guid1, uint32 { if (type == CHAT_MSG_WHISPER) { - ObjectGuid receiver = sCharacterCache->GetCharacterGuidByName(name); - if (!receiver || !receiver.IsPlayer() || !ObjectAccessor::FindPlayer(receiver)) + if (plr) { - return; - } - if (bot->GetTeamId() == TEAM_ALLIANCE) - { - bot->Whisper(c, LANG_COMMON, ObjectAccessor::FindPlayer(receiver)); + if (bot->GetTeamId() == TEAM_ALLIANCE) + { + bot->Whisper(c, LANG_COMMON, plr); + } + else + { + bot->Whisper(c, LANG_ORCISH, plr); + } } else - { - bot->Whisper(c, LANG_ORCISH, ObjectAccessor::FindPlayer(receiver)); - } + LOG_ERROR("playerbots", "plr pointer is nullptr chat whisper"); } if (type == CHAT_MSG_SAY) @@ -647,6 +688,11 @@ void ChatReplyAction::ChatReplyDo(Player* bot, uint32 type, uint32 guid1, uint32 guild->BroadcastToGuild(bot->GetSession(), false, respondsText, LANG_UNIVERSAL); } + + else + { + LOG_ERROR("playerbots", "Unknown chat type {}", type); + } } GET_PLAYERBOT_AI(bot)->GetAiObjectContext()->GetValue("last said", "chat")->Set(time(nullptr) + urand(5, 25)); } From 9830992000f1fcf361348340f1fa723a49f2e783 Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Thu, 25 Jul 2024 21:25:18 +0800 Subject: [PATCH 22/61] [Console] Fix .playerbot bot console message --- src/PlayerbotMgr.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/PlayerbotMgr.cpp b/src/PlayerbotMgr.cpp index f236d769..088901bf 100644 --- a/src/PlayerbotMgr.cpp +++ b/src/PlayerbotMgr.cpp @@ -736,7 +736,7 @@ bool PlayerbotMgr::HandlePlayerbotMgrCommand(ChatHandler* handler, char const* a for (std::vector::iterator i = messages.begin(); i != messages.end(); ++i) { - handler->PSendSysMessage("%s", i->c_str()); + handler->PSendSysMessage("{}", i->c_str()); } return true; @@ -748,8 +748,8 @@ std::vector PlayerbotHolder::HandlePlayerbotCommand(char const* arg if (!*args) { - messages.push_back("usage: list/reload/tweak/self or add/init/remove PLAYERNAME"); - messages.push_back(" addclass CLASSNAME"); + messages.push_back("usage: list/reload/tweak/self or add/init/remove PLAYERNAME\n"); + messages.push_back("usage: addclass CLASSNAME"); return messages; } From a837d7f55b565c7c2a8088831066d2f0575bd42a Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Thu, 25 Jul 2024 21:34:06 +0800 Subject: [PATCH 23/61] [Class spell] Optimize toggle pet spell --- src/strategy/actions/GenericActions.cpp | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/strategy/actions/GenericActions.cpp b/src/strategy/actions/GenericActions.cpp index 5e292369..9b16ee7a 100644 --- a/src/strategy/actions/GenericActions.cpp +++ b/src/strategy/actions/GenericActions.cpp @@ -20,6 +20,7 @@ bool TogglePetSpellAutoCastAction::Execute(Event event) { if (!pet) { return false; } + bool toggled = false; for (PetSpellMap::const_iterator itr = pet->m_spells.begin(); itr != pet->m_spells.end(); ++itr) { if(itr->second.state == PETSPELL_REMOVED) @@ -29,17 +30,29 @@ bool TogglePetSpellAutoCastAction::Execute(Event event) { const SpellInfo* spellInfo = sSpellMgr->GetSpellInfo(spellId); if (spellInfo->IsPassive()) continue; - + + bool shouldApply = true; // imp's spell, felhunte's intelligence, ghoul's leap, cat stealth if (spellId == 4511 || spellId == 1742 || spellId == 54424 || spellId == 57564 || spellId == 57565 || spellId == 57566 || spellId == 57567 || spellId == 47482 || spellId == 24450) { - pet->ToggleAutocast(spellInfo, false); - } else { - pet->ToggleAutocast(spellInfo, true); + shouldApply = false; + } + bool isAutoCast = false; + for (unsigned int &m_autospell : pet->m_autospells) + { + if (m_autospell == spellId) + { + isAutoCast = true; + break; + } + } + if (shouldApply != isAutoCast) { + pet->ToggleAutocast(spellInfo, shouldApply); + toggled = true; } } - return true; + return toggled; } bool PetAttackAction::Execute(Event event) From 6f63ed10a3816ae072b489c92a74e04dc9ced7ce Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Thu, 25 Jul 2024 21:48:57 +0800 Subject: [PATCH 24/61] [Configuration] Better frost mage talent --- 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 e14601e9..40a44683 100644 --- a/conf/playerbots.conf.dist +++ b/conf/playerbots.conf.dist @@ -899,8 +899,8 @@ 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 -AiPlayerbot.PremadeSpecLink.8.2.80 = 23002322010203--0533003313203100232112231151 +AiPlayerbot.PremadeSpecLink.8.2.60 = --0533030313203100030152231151 +AiPlayerbot.PremadeSpecLink.8.2.80 = 23002303110003--0533030313203100030152231351 # # From ffbd97604260066d6bf75faebfe60d46910626b1 Mon Sep 17 00:00:00 2001 From: Revision Date: Thu, 25 Jul 2024 17:07:37 +0200 Subject: [PATCH 25/61] Fix import issues after French translation commit --- sql/playerbots/base/playerbots_text.sql | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sql/playerbots/base/playerbots_text.sql b/sql/playerbots/base/playerbots_text.sql index 095bd062..e4a3c6bf 100644 --- a/sql/playerbots/base/playerbots_text.sql +++ b/sql/playerbots/base/playerbots_text.sql @@ -539,20 +539,20 @@ INSERT INTO `ai_playerbot_texts` (`id`, `name`, `text`, `say_type`, `reply_type` (519, 'fleeing', 'Fleeing', 0, 0, '', 'Au secours !!', '', '', '', '', '', 'Убегаю'), (520, 'fleeing_far', 'I won\'t flee with you, you are too far away', 0, 0, '', 'Tu es trop loin je ne peut pas fuir avec toi', '', '', '', '', '', 'Я с тобой не побегу, ты слишком далеко'), (521, 'grinding', 'Grinding', 0, 0, '', 'Je grind', '', '', '', '', '', 'Гриндю'), - (522, 'attacking', 'Attacking', 0, 0, '', 'J'attack', '', '', '', '', '', 'Атакую'), + (522, 'attacking', 'Attacking', 0, 0, '', 'J\'attack', '', '', '', '', '', 'Атакую'), (523, 'wait_travel_close', 'I am close, wait for me!', 0, 0, '', 'Attends moi je suis proche', '', '', '', '', '', 'Я тут рядом, подожди!'), (524, 'wait_travel_close', 'I\'m not far, please wait!', 0, 0, '', 'Je suis à côté s\'il te plait attends moi !', '', '', '', '', '', 'Я недалеко, погодите!'), (525, 'wait_travel_medium', 'I\'m heading to your location', 0, 0, '', 'J\'arrive sur ta position', '', '', '', '', '', 'Двигаюсь к тебе'), (526, 'wait_travel_medium', 'I\'m coming to you', 0, 0, '', 'Je viens à toi', '', '', '', '', '', 'Иду к тебе'), - (527, 'wait_travel_far', 'I\'m traveling to your location', 0, 0, '', 'Je voyage jusqu\'à toi'', '', '', '', '', '', 'Направляюсь к тебе'), + (527, 'wait_travel_far', 'I\'m traveling to your location', 0, 0, '', 'Je voyage jusqu\'à toi', '', '', '', '', '', 'Направляюсь к тебе'), (528, 'wait_travel_far', 'I\'m trying to get to you', 0, 0, '', 'J\'essai de vous rejoindre', '', '', '', '', '', 'Пытаюсь до тебя добраться'), - (529, 'error_far', 'It is too far away', 0, 0, '', 'C\'est trop loin'', '', '', '', '', '', 'Слишком далеко'), + (529, 'error_far', 'It is too far away', 0, 0, '', 'C\'est trop loin', '', '', '', '', '', 'Слишком далеко'), (530, 'error_water', 'It is under water', 0, 0, '', 'C\'est sous l\'eau', '', '', '', '', '', 'Это под водой'), (531, 'error_cant_go', 'I can\'t go there', 0, 0, '', 'Je ne peut pas atteindre cette destination', '', '', '', '', '', 'Я не могу туда пройти'), (532, 'error_guild', 'I\'m not in your guild!', 0, 0, '', 'Je ne fais pas parti de ta guilde', '', '', '', '', '', 'Я не в твоей гильдии'), - (533, 'error_gbank_found', 'Can not find a guild bank nearby', 0, 0, '', 'Il n\'y a pas de coffre de guilde à proximité'', '', '', '', '', '', 'Не могу найти гильд банк рядом'), + (533, 'error_gbank_found', 'Can not find a guild bank nearby', 0, 0, '', 'Il n\'y a pas de coffre de guilde à proximité', '', '', '', '', '', 'Не могу найти гильд банк рядом'), (534, 'error_cant_put', 'I can\'t put ', 0, 0, '', '', '', '', '', '', '', 'Я не могу положить'), - (535, 'error_gbank_rights', 'I have no rights to put items in the first guild bank tab', 0, 0, '', 'Je n'ai pas les droits de dépôt à la banque', '', '', '', '', '', 'Нет прав чтобы класть вещи в первую вкладку гильд банка'), + (535, 'error_gbank_rights', 'I have no rights to put items in the first guild bank tab', 0, 0, '', 'Je n\'ai pas les droits de dépôt à la banque', '', '', '', '', '', 'Нет прав чтобы класть вещи в первую вкладку гильд банка'), (536, 'gbank_put', ' put to guild bank', 0, 0, '', '', '', '', '', '', '', ' теперь в гильд банке'); /*!40000 ALTER TABLE `ai_playerbot_texts` ENABLE KEYS */; From 916a0002e8984e17f62e536a84307139d0b61506 Mon Sep 17 00:00:00 2001 From: Atidot3 Date: Thu, 25 Jul 2024 17:56:53 +0200 Subject: [PATCH 26/61] Fix crash --- src/PlayerbotMgr.cpp | 2 +- src/PlayerbotTextMgr.cpp | 1 - src/strategy/actions/SayAction.cpp | 9 +++++---- src/strategy/actions/SuggestWhatToDoAction.cpp | 11 +++++++---- 4 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/PlayerbotMgr.cpp b/src/PlayerbotMgr.cpp index f8923316..2582fd5b 100644 --- a/src/PlayerbotMgr.cpp +++ b/src/PlayerbotMgr.cpp @@ -545,7 +545,7 @@ void PlayerbotHolder::OnBotLogin(Player* const bot) if (isLfg) { std::string lfgChannelName = channel->pattern[sWorld->GetDefaultDbcLocale()]; - new_channel = cMgr->GetJoinChannel(lfgChannelName, channel->ChannelID); + new_channel = cMgr->GetJoinChannel("LookingForGroup", channel->ChannelID); } else { diff --git a/src/PlayerbotTextMgr.cpp b/src/PlayerbotTextMgr.cpp index 64261314..fd3a95a6 100644 --- a/src/PlayerbotTextMgr.cpp +++ b/src/PlayerbotTextMgr.cpp @@ -192,7 +192,6 @@ uint32 PlayerbotTextMgr::GetLocalePriority() topLocale = i; } - LOG_INFO("playerbots", "GetLocalePriority: {}", topLocale); return topLocale; } diff --git a/src/strategy/actions/SayAction.cpp b/src/strategy/actions/SayAction.cpp index 71b7664e..46bcf089 100644 --- a/src/strategy/actions/SayAction.cpp +++ b/src/strategy/actions/SayAction.cpp @@ -661,15 +661,16 @@ void ChatReplyAction::ChatReplyDo(Player* bot, uint32 type, uint32 guid1, uint32 LOG_ERROR("playerbots", "plr pointer is nullptr chat whisper"); } - if (type == CHAT_MSG_SAY) + else if (type == CHAT_MSG_SAY) { + LOG_INFO("playerbots", "say respond: {}", respondsText); if (bot->GetTeamId() == TEAM_ALLIANCE) bot->Say(respondsText, LANG_COMMON); else bot->Say(respondsText, LANG_ORCISH); } - if (type == CHAT_MSG_YELL) + else if (type == CHAT_MSG_YELL) { if (bot->GetTeamId() == TEAM_ALLIANCE) bot->Yell(respondsText, LANG_COMMON); @@ -677,7 +678,7 @@ void ChatReplyAction::ChatReplyDo(Player* bot, uint32 type, uint32 guid1, uint32 bot->Yell(respondsText, LANG_ORCISH); } - if (type == CHAT_MSG_GUILD) + else if (type == CHAT_MSG_GUILD) { if (!bot->GetGuildId()) return; @@ -696,4 +697,4 @@ void ChatReplyAction::ChatReplyDo(Player* bot, uint32 type, uint32 guid1, uint32 } GET_PLAYERBOT_AI(bot)->GetAiObjectContext()->GetValue("last said", "chat")->Set(time(nullptr) + urand(5, 25)); } -} \ No newline at end of file +} diff --git a/src/strategy/actions/SuggestWhatToDoAction.cpp b/src/strategy/actions/SuggestWhatToDoAction.cpp index fa8eada1..0fd543c5 100644 --- a/src/strategy/actions/SuggestWhatToDoAction.cpp +++ b/src/strategy/actions/SuggestWhatToDoAction.cpp @@ -109,7 +109,7 @@ void SuggestWhatToDoAction::instance() instances["Halls of Reflection"] = 80; } - std::vector allowedInstances; + std::vector allowedInstances; for (const auto& instance : instances) { if (bot->GetLevel() >= instance.second) @@ -248,12 +248,12 @@ void SuggestWhatToDoAction::grindReputation() factions["The Wyrmrest Accord"] = 77; } - std::vector levels; + std::vector levels; levels.push_back("honored"); levels.push_back("revered"); levels.push_back("exalted"); - std::vector allowedFactions; + std::vector allowedFactions; for (const auto& i : factions) { if (bot->GetLevel() >= i.second) @@ -310,7 +310,10 @@ void SuggestWhatToDoAction::spam(std::string msg, uint8 flags, bool worldChat, b ChatChannelsEntry const* channel = sChatChannelsStore.LookupEntry(i); if (!channel) continue; - LOG_INFO("playerbots", "Loop on channel: {}", channel->pattern[_dbc_locale]); + if (channel->pattern[_dbc_locale]) + LOG_INFO("playerbots", "Loop on channel: {}", channel->pattern[_dbc_locale]); + else + LOG_ERROR("playerbots", "channel->pattern[_dbc_locale] is null"); for (AreaTableEntry const* current_zone : sAreaTableStore) { From 50bd63575d5155701ce9a2751024ff53129b3d45 Mon Sep 17 00:00:00 2001 From: Atidot3 Date: Thu, 25 Jul 2024 23:18:04 +0200 Subject: [PATCH 27/61] Progress on channels and say yell etc --- src/AiFactory.cpp | 4 +-- src/PlayerbotTextMgr.cpp | 5 ++-- src/strategy/actions/EmoteAction.cpp | 8 ++--- src/strategy/actions/SayAction.cpp | 11 ------- .../actions/SuggestWhatToDoAction.cpp | 30 ++++++++----------- src/strategy/actions/SuggestWhatToDoAction.h | 4 +-- 6 files changed, 24 insertions(+), 38 deletions(-) diff --git a/src/AiFactory.cpp b/src/AiFactory.cpp index 2eb4453e..e932a111 100644 --- a/src/AiFactory.cpp +++ b/src/AiFactory.cpp @@ -264,7 +264,7 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa if (!player->InBattleground()) { - engine->addStrategies("racials", "chat", "default", "cast time", "duel", "boost", nullptr); + engine->addStrategies("racials", "chat", "default", "cast time", "duel", "boost", "emote", nullptr); } if (sPlayerbotAIConfig->autoSaveMana) { @@ -548,7 +548,7 @@ void AiFactory::AddDefaultNonCombatStrategies(Player* player, PlayerbotAI* const if (!player->InBattleground()) { nonCombatEngine->addStrategies("nc", "food", "chat", "follow", - "default", "quest", "loot", "gather", "duel", "buff", "mount", nullptr); + "default", "quest", "loot", "gather", "duel", "buff", "mount", "emote", nullptr); } if (sPlayerbotAIConfig->autoSaveMana) { nonCombatEngine->addStrategy("auto save mana"); diff --git a/src/PlayerbotTextMgr.cpp b/src/PlayerbotTextMgr.cpp index fd3a95a6..7041185c 100644 --- a/src/PlayerbotTextMgr.cpp +++ b/src/PlayerbotTextMgr.cpp @@ -28,12 +28,13 @@ void PlayerbotTextMgr::LoadBotTexts() Field* fields = result->Fetch(); std::string name = fields[0].Get(); text[0] = fields[1].Get(); - uint32 sayType = fields[2].Get(); - uint32 replyType = fields[3].Get(); + uint8 sayType = fields[2].Get(); + uint8 replyType = fields[3].Get(); for (uint8 i = 1; i < MAX_LOCALES; ++i) { text[i] = fields[i + 3].Get(); } + botTexts[name].push_back(BotTextEntry(name, text, sayType, replyType)); ++count; } diff --git a/src/strategy/actions/EmoteAction.cpp b/src/strategy/actions/EmoteAction.cpp index 2ef6e90a..8fe57374 100644 --- a/src/strategy/actions/EmoteAction.cpp +++ b/src/strategy/actions/EmoteAction.cpp @@ -671,9 +671,9 @@ bool EmoteAction::Execute(Event event) if (pSource && (pSource->GetGUID() != bot->GetGUID()) && ((urand(0, 1) && bot->HasInArc(static_cast(M_PI), pSource, 10.0f)) || (namlen > 1 && strstri(bot->GetName().c_str(), nam.c_str())))) { - LOG_INFO("playerbots", "Bot {} {}:{} <{}> received SMSG_TEXT_EMOTE {} from player {} <{}>", + /*LOG_INFO("playerbots", "Bot {} {}:{} <{}> received SMSG_TEXT_EMOTE {} from player {} <{}>", bot->GetGUID().ToString().c_str(), bot->GetTeamId() == TEAM_ALLIANCE ? "A" : "H", bot->GetLevel(), - bot->GetName(), text_emote, pSource->GetGUID().ToString().c_str(), pSource->GetName()); + bot->GetName(), text_emote, pSource->GetGUID().ToString().c_str(), pSource->GetName());*/ emote = text_emote; } @@ -693,9 +693,9 @@ bool EmoteAction::Execute(Event event) if ((pSource->GetGUID() != bot->GetGUID()) && (pSource->GetTarget() == bot->GetGUID() || (urand(0, 1) && bot->HasInArc(static_cast(M_PI), pSource, 10.0f)))) { - LOG_INFO("playerbots", "Bot {} {}:{} <{}> received SMSG_EMOTE {} from player {} <{}>", + /*LOG_INFO("playerbots", "Bot {} {}:{} <{}> received SMSG_EMOTE {} from player {} <{}>", bot->GetGUID().ToString().c_str(), bot->GetTeamId() == TEAM_ALLIANCE ? "A" : "H", bot->GetLevel(), bot->GetName(), - emoteId, pSource->GetGUID().ToString().c_str(), pSource->GetName()); + emoteId, pSource->GetGUID().ToString().c_str(), pSource->GetName());*/ std::vector types; for (int32 i = sEmotesTextStore.GetNumRows(); i >= 0; --i) diff --git a/src/strategy/actions/SayAction.cpp b/src/strategy/actions/SayAction.cpp index 46bcf089..67395b2e 100644 --- a/src/strategy/actions/SayAction.cpp +++ b/src/strategy/actions/SayAction.cpp @@ -124,8 +124,6 @@ bool SayAction::isUseful() void ChatReplyAction::ChatReplyDo(Player* bot, uint32 type, uint32 guid1, uint32 guid2, std::string msg, std::string chanName, std::string name) { - LOG_INFO("playerbots", "{} Handle chat reply", bot->GetName()); - ChatReplyType replyType = REPLY_NOT_UNDERSTAND; // default not understand std::string respondsText = ""; @@ -143,7 +141,6 @@ void ChatReplyAction::ChatReplyDo(Player* bot, uint32 type, uint32 guid1, uint32 std::ostringstream out; out << "DEBUG ChatReplyDo decided to ignore partial blocklist match" << msg; bot->Say(out.str(), LANG_UNIVERSAL); - return; } @@ -657,13 +654,10 @@ void ChatReplyAction::ChatReplyDo(Player* bot, uint32 type, uint32 guid1, uint32 bot->Whisper(c, LANG_ORCISH, plr); } } - else - LOG_ERROR("playerbots", "plr pointer is nullptr chat whisper"); } else if (type == CHAT_MSG_SAY) { - LOG_INFO("playerbots", "say respond: {}", respondsText); if (bot->GetTeamId() == TEAM_ALLIANCE) bot->Say(respondsText, LANG_COMMON); else @@ -689,11 +683,6 @@ void ChatReplyAction::ChatReplyDo(Player* bot, uint32 type, uint32 guid1, uint32 guild->BroadcastToGuild(bot->GetSession(), false, respondsText, LANG_UNIVERSAL); } - - else - { - LOG_ERROR("playerbots", "Unknown chat type {}", type); - } } GET_PLAYERBOT_AI(bot)->GetAiObjectContext()->GetValue("last said", "chat")->Set(time(nullptr) + urand(5, 25)); } diff --git a/src/strategy/actions/SuggestWhatToDoAction.cpp b/src/strategy/actions/SuggestWhatToDoAction.cpp index 0fd543c5..81c5f540 100644 --- a/src/strategy/actions/SuggestWhatToDoAction.cpp +++ b/src/strategy/actions/SuggestWhatToDoAction.cpp @@ -13,6 +13,8 @@ #include "GuildMgr.h" #include "Config.h" +#include + enum eTalkType { General = ChannelFlags::CHANNEL_FLAG_GENERAL | ChannelFlags::CHANNEL_FLAG_NOT_LFG, @@ -29,11 +31,11 @@ SuggestWhatToDoAction::SuggestWhatToDoAction(PlayerbotAI* botAI, std::string con : InventoryAction{ botAI, name } , _dbc_locale{ sWorld->GetDefaultDbcLocale() } { - suggestions.push_back(&SuggestWhatToDoAction::specificQuest); - suggestions.push_back(&SuggestWhatToDoAction::grindReputation); - suggestions.push_back(&SuggestWhatToDoAction::something); - suggestions.push_back(&SuggestWhatToDoAction::instance); - suggestions.push_back(&SuggestWhatToDoAction::grindMaterials); + suggestions.push_back(std::bind(&SuggestWhatToDoAction::specificQuest, this)); + suggestions.push_back(std::bind(&SuggestWhatToDoAction::grindReputation, this)); + suggestions.push_back(std::bind(&SuggestWhatToDoAction::something, this)); + suggestions.push_back(std::bind(&SuggestWhatToDoAction::instance, this)); + suggestions.push_back(std::bind(&SuggestWhatToDoAction::grindMaterials, this)); } bool SuggestWhatToDoAction::isUseful() @@ -48,11 +50,9 @@ bool SuggestWhatToDoAction::isUseful() bool SuggestWhatToDoAction::Execute(Event event) { - if (!sRandomPlayerbotMgr->IsRandomBot(bot) || bot->GetGroup() || bot->GetInstanceId()) - return false; - uint32 index = rand() % suggestions.size(); - (this->*suggestions[index])(); + auto fnct_ptr = suggestions[index]; + fnct_ptr(); std::string const qualifier = "suggest what to do"; time_t lastSaid = AI_VALUE2(time_t, "last said", qualifier); @@ -310,11 +310,6 @@ void SuggestWhatToDoAction::spam(std::string msg, uint8 flags, bool worldChat, b ChatChannelsEntry const* channel = sChatChannelsStore.LookupEntry(i); if (!channel) continue; - if (channel->pattern[_dbc_locale]) - LOG_INFO("playerbots", "Loop on channel: {}", channel->pattern[_dbc_locale]); - else - LOG_ERROR("playerbots", "channel->pattern[_dbc_locale] is null"); - for (AreaTableEntry const* current_zone : sAreaTableStore) { if (!current_zone) @@ -327,14 +322,12 @@ void SuggestWhatToDoAction::spam(std::string msg, uint8 flags, bool worldChat, b if ((channel->flags & CHANNEL_DBC_FLAG_LFG) != 0) { std::string chanName = channel->pattern[_dbc_locale]; - LOG_INFO("playerbots", "Trying to chat on channel: {}", chanName); chn = cMgr->GetChannel(chanName, bot); } else { snprintf(channelName, 100, channel->pattern[_dbc_locale], current_zone->area_name[_dbc_locale]); chn = cMgr->GetChannel(channelName, bot); - LOG_INFO("playerbots", "Trying to chat on channel: {}", channelName); } if (!chn) continue; @@ -355,16 +348,19 @@ void SuggestWhatToDoAction::spam(std::string msg, uint8 flags, bool worldChat, b channelNames.push_back(chn->GetName()); } else + { chn->Say(bot->GetGUID(), msg.c_str(), LANG_UNIVERSAL); + LOG_DEBUG("playerbots", "send grind {} - {}", bot->GetName().c_str(), msg.c_str()); + } } if (!channelNames.empty()) { std::string randomName = channelNames[urand(0, channelNames.size() - 1)]; - LOG_INFO("playerbots", "Chatting on channel: {}", randomName); if (Channel* chn = cMgr->GetChannel(randomName, bot)) { chn->Say(bot->GetGUID(), msg.c_str(), LANG_UNIVERSAL); + LOG_DEBUG("playerbots", "send grind {} - {}", bot->GetName().c_str(), msg.c_str()); } } diff --git a/src/strategy/actions/SuggestWhatToDoAction.h b/src/strategy/actions/SuggestWhatToDoAction.h index 58fafd59..2a942e34 100644 --- a/src/strategy/actions/SuggestWhatToDoAction.h +++ b/src/strategy/actions/SuggestWhatToDoAction.h @@ -18,7 +18,7 @@ class SuggestWhatToDoAction : public InventoryAction bool isUseful() override; protected: - typedef void (SuggestWhatToDoAction::*Suggestion)(); + using Suggestion = std::function; std::vector suggestions; void instance(); void specificQuest(); @@ -32,7 +32,7 @@ class SuggestWhatToDoAction : public InventoryAction private: static std::map instances; static std::map factions; - const int32_t& _dbc_locale; + const int32_t _dbc_locale; }; class SuggestTradeAction : public SuggestWhatToDoAction From 8d43ab8cb47355b537570a797ee70d07ac3914d0 Mon Sep 17 00:00:00 2001 From: Atidot3 Date: Thu, 25 Jul 2024 23:22:10 +0200 Subject: [PATCH 28/61] fix log --- src/strategy/actions/SuggestWhatToDoAction.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/strategy/actions/SuggestWhatToDoAction.cpp b/src/strategy/actions/SuggestWhatToDoAction.cpp index 81c5f540..95c933cd 100644 --- a/src/strategy/actions/SuggestWhatToDoAction.cpp +++ b/src/strategy/actions/SuggestWhatToDoAction.cpp @@ -350,7 +350,7 @@ void SuggestWhatToDoAction::spam(std::string msg, uint8 flags, bool worldChat, b else { chn->Say(bot->GetGUID(), msg.c_str(), LANG_UNIVERSAL); - LOG_DEBUG("playerbots", "send grind {} - {}", bot->GetName().c_str(), msg.c_str()); + LOG_INFO("playerbots", "{} - {} channel {}", bot->GetName().c_str(), msg.c_str(), chn->GetName()); } } @@ -360,7 +360,7 @@ void SuggestWhatToDoAction::spam(std::string msg, uint8 flags, bool worldChat, b if (Channel* chn = cMgr->GetChannel(randomName, bot)) { chn->Say(bot->GetGUID(), msg.c_str(), LANG_UNIVERSAL); - LOG_DEBUG("playerbots", "send grind {} - {}", bot->GetName().c_str(), msg.c_str()); + LOG_INFO("playerbots", "{} - {} channel {}", bot->GetName().c_str(), msg.c_str(), chn->GetName()); } } From 966c8e652b7ec95a8799c303aadc6b18d4a3e3d9 Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Fri, 26 Jul 2024 12:45:24 +0800 Subject: [PATCH 29/61] [Crash fix] Fix format item crash --- src/ChatHelper.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ChatHelper.cpp b/src/ChatHelper.cpp index a181ac89..630bfca9 100644 --- a/src/ChatHelper.cpp +++ b/src/ChatHelper.cpp @@ -336,11 +336,11 @@ std::string const ChatHelper::FormatItem(ItemTemplate const* proto, uint32 count char color[32]; sprintf(color, "%x", ItemQualityColors[proto->Quality]); - const std::string &name = sObjectMgr->GetItemLocale(proto->ItemId)->Name[sWorld->GetDefaultDbcLocale()]; + // const std::string &name = sObjectMgr->GetItemLocale(proto->ItemId)->Name[sWorld->GetDefaultDbcLocale()]; std::ostringstream out; out << "|c" << color << "|Hitem:" << proto->ItemId - << ":0:0:0:0:0:0:0" << "|h[" << name + << ":0:0:0:0:0:0:0" << "|h[" << proto->Name1 << "]|h|r"; if (count > 1) From b2c5885050d0c67ab196b55b6548cd772c5d625d Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Fri, 26 Jul 2024 13:07:31 +0800 Subject: [PATCH 30/61] [CI] CI cache --- .github/workflows/core_build.yml | 9 ++++----- .github/workflows/windows_build.yml | 10 ++-------- 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/.github/workflows/core_build.yml b/.github/workflows/core_build.yml index fe4802e5..b0f272f7 100644 --- a/.github/workflows/core_build.yml +++ b/.github/workflows/core_build.yml @@ -50,13 +50,12 @@ jobs: path: 'modules/mod-playerbots' - name: Cache - uses: actions/cache@v3 + uses: actions/cache@v4 with: - path: | - /var/cache/apt - /var/lib/apt - key: ccache:${{ matrix.os }}:${{ github.ref }}:${{ github.sha }} + path: ${{ github.workspace }}/var/ccache + key: ccache:${{ matrix.os }}:${{ github.ref }}:${{ matrix.c_compiler }}:${{ github.sha }} restore-keys: | + ccache:${{ matrix.os }}:${{ github.ref }}:${{ matrix.c_compiler }} ccache:${{ matrix.os }}:${{ github.ref }} ccache:${{ matrix.os }} diff --git a/.github/workflows/windows_build.yml b/.github/workflows/windows_build.yml index d6829895..48d33ba2 100644 --- a/.github/workflows/windows_build.yml +++ b/.github/workflows/windows_build.yml @@ -26,14 +26,8 @@ jobs: with: repository: 'liyunfan1223/mod-playerbots' path: 'modules/mod-playerbots' - - name: Cache - uses: actions/cache@v3 - with: - path: C:\ProgramData\chocolatey\cache - key: ccache:${{ matrix.os }}:${{ github.ref }}:${{ github.sha }} - restore-keys: | - ccache:${{ matrix.os }}:${{ github.ref }} - ccache:${{ matrix.os }} + - name: ccache + uses: hendrikmuhs/ccache-action@v1.2.13 - name: Configure OS shell: bash env: From 278a48260f7067edaa67f73e8ce59a739ce53303 Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Fri, 26 Jul 2024 15:00:37 +0800 Subject: [PATCH 31/61] [CI] core_build key order --- .github/workflows/core_build.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/core_build.yml b/.github/workflows/core_build.yml index b0f272f7..806ee7df 100644 --- a/.github/workflows/core_build.yml +++ b/.github/workflows/core_build.yml @@ -53,10 +53,10 @@ jobs: uses: actions/cache@v4 with: path: ${{ github.workspace }}/var/ccache - key: ccache:${{ matrix.os }}:${{ github.ref }}:${{ matrix.c_compiler }}:${{ github.sha }} + key: ccache:${{ matrix.os }}:${{ matrix.c_compiler }}:${{ github.ref }}:${{ github.sha }} restore-keys: | - ccache:${{ matrix.os }}:${{ github.ref }}:${{ matrix.c_compiler }} - ccache:${{ matrix.os }}:${{ github.ref }} + ccache:${{ matrix.os }}:${{ matrix.c_compiler }}:${{ github.ref }} + ccache:${{ matrix.os }}:${{ matrix.c_compiler }} ccache:${{ matrix.os }} - name: Install Requirements From d78eb72b67d142d26ba99dc46ec3e68730d7f194 Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Fri, 26 Jul 2024 17:17:05 +0800 Subject: [PATCH 32/61] [CI] ccache for linux build --- .github/workflows/core_build.yml | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/.github/workflows/core_build.yml b/.github/workflows/core_build.yml index 806ee7df..45de9b47 100644 --- a/.github/workflows/core_build.yml +++ b/.github/workflows/core_build.yml @@ -60,7 +60,25 @@ jobs: ccache:${{ matrix.os }} - name: Install Requirements - run: sudo apt-get update && sudo apt-get install git cmake make gcc g++ clang libmysqlclient-dev libssl-dev libbz2-dev libreadline-dev libncurses-dev mysql-server libboost-all-dev + run: sudo apt-get update && sudo apt-get install ccache git cmake make gcc g++ clang libmysqlclient-dev libssl-dev libbz2-dev libreadline-dev libncurses-dev mysql-server libboost-all-dev + + - name: setup ccache + shell: bash + env: + CCACHE_DIR: $GITHUB_WORKSPACE/var/ccache + run: | + cat <> $GITHUB_ENV + CCACHE_DIR=${{ env.CCACHE_DIR }} + CCACHE_MAXSIZE=1000MB + CCACHE_SLOPPINESS=pch_defines,time_macros,include_file_mtime + CCACHE_CPP2=true + CCACHE_COMPRESS=1 + CCACHE_COMPRESSLEVEL=9 + CCACHE_COMPILERCHECK=content + CCACHE_LOGFILE=$CCACHE_DIR/cache.debug + CC=${{ inputs.CC }} + CXX=${{ inputs.CXX }} + EOF - name: Configure CMake run: > @@ -68,6 +86,8 @@ jobs: -DCMAKE_CXX_COMPILER=${{ matrix.cpp_compiler }} -DCMAKE_C_COMPILER=${{ matrix.c_compiler }} -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} + -DCMAKE_CXX_COMPILER_LAUNCHER="ccache" + -DCMAKE_C_COMPILER_LAUNCHER="ccache" -S ${{ github.workspace }} - name: Build From d21d1e9b688c99c192ed8c78c5a3e594c0fb0687 Mon Sep 17 00:00:00 2001 From: Atidot3 Date: Sat, 27 Jul 2024 10:13:33 +0200 Subject: [PATCH 33/61] Suggest dungeon implementation + log action unknown to help debug --- src/AiFactory.cpp | 2 +- src/PlayerbotMgr.cpp | 3 +- src/strategy/Engine.cpp | 1 + src/strategy/actions/ActionContext.h | 2 + .../actions/SuggestWhatToDoAction.cpp | 221 +++++++++--------- src/strategy/actions/SuggestWhatToDoAction.h | 12 +- 6 files changed, 130 insertions(+), 111 deletions(-) diff --git a/src/AiFactory.cpp b/src/AiFactory.cpp index e932a111..db551d1a 100644 --- a/src/AiFactory.cpp +++ b/src/AiFactory.cpp @@ -636,7 +636,7 @@ void AiFactory::AddDefaultNonCombatStrategies(Player* player, PlayerbotAI* const // Battleground switch if (player->InBattleground() && player->GetBattleground()) { - nonCombatEngine->addStrategies("nc", "chat", "default", "buff", "food", "mount", "pvp", "dps assist", "attack tagged", nullptr); + nonCombatEngine->addStrategies("nc", "chat", "default", "buff", "food", "mount", "pvp", "dps assist", "attack tagged", "emote", nullptr); nonCombatEngine->removeStrategy("custom::say"); nonCombatEngine->removeStrategy("travel"); nonCombatEngine->removeStrategy("rpg"); diff --git a/src/PlayerbotMgr.cpp b/src/PlayerbotMgr.cpp index 2582fd5b..f2fab8c4 100644 --- a/src/PlayerbotMgr.cpp +++ b/src/PlayerbotMgr.cpp @@ -85,7 +85,8 @@ void PlayerbotHolder::HandlePlayerBotLoginCallback(PlayerbotLoginQueryHolder con 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); + // At login DBC locale should be what the server is set to use by default (as spells etc are hardcoded to ENUS this allows channels to work as intended) + WorldSession* botSession = new WorldSession(botAccountId, "", nullptr, SEC_PLAYER, EXPANSION_WRATH_OF_THE_LICH_KING, time_t(0), sWorld->GetDefaultDbcLocale(), 0, false, false, 0, true); botSession->HandlePlayerLoginFromDB(holder); // will delete lqh diff --git a/src/strategy/Engine.cpp b/src/strategy/Engine.cpp index cef411c6..dbb35c74 100644 --- a/src/strategy/Engine.cpp +++ b/src/strategy/Engine.cpp @@ -172,6 +172,7 @@ bool Engine::DoNextAction(Unit* unit, uint32 depth, bool minimal) if (!action) { + LOG_ERROR("playerbots", "Action: {} - is UNKNOWN - c:{} l:{}", actionNode->getName().c_str(), botAI->GetBot()->getClass(), botAI->GetBot()->GetLevel()); LogAction("A:%s - UNKNOWN", actionNode->getName().c_str()); } else if (action->isUseful()) diff --git a/src/strategy/actions/ActionContext.h b/src/strategy/actions/ActionContext.h index ea8b3362..e7caf4e2 100644 --- a/src/strategy/actions/ActionContext.h +++ b/src/strategy/actions/ActionContext.h @@ -123,6 +123,7 @@ class ActionContext : public NamedObjectContext creators["talk"] = &ActionContext::talk; creators["suggest what to do"] = &ActionContext::suggest_what_to_do; creators["suggest trade"] = &ActionContext::suggest_trade; + creators["suggest dungeon"] = &ActionContext::suggest_dungeon; creators["return"] = &ActionContext::_return; creators["move to loot"] = &ActionContext::move_to_loot; creators["open loot"] = &ActionContext::open_loot; @@ -280,6 +281,7 @@ class ActionContext : public NamedObjectContext static Action* talk(PlayerbotAI* botAI) { return new TalkAction(botAI); } static Action* suggest_what_to_do(PlayerbotAI* botAI) { return new SuggestWhatToDoAction(botAI); } static Action* suggest_trade(PlayerbotAI* botAI) { return new SuggestTradeAction(botAI); } + static Action* suggest_dungeon(PlayerbotAI* botAI) { return new SuggestDungeonAction(botAI); } static Action* attack_anything(PlayerbotAI* botAI) { return new AttackAnythingAction(botAI); } static Action* attack_least_hp_target(PlayerbotAI* botAI) { return new AttackLeastHpTargetAction(botAI); } static Action* attack_enemy_player(PlayerbotAI* botAI) { return new AttackEnemyPlayerAction(botAI); } diff --git a/src/strategy/actions/SuggestWhatToDoAction.cpp b/src/strategy/actions/SuggestWhatToDoAction.cpp index 95c933cd..33b17e23 100644 --- a/src/strategy/actions/SuggestWhatToDoAction.cpp +++ b/src/strategy/actions/SuggestWhatToDoAction.cpp @@ -3,6 +3,7 @@ */ #include "SuggestWhatToDoAction.h" +#include "ServerFacade.h" #include "ChannelMgr.h" #include "Event.h" #include "ItemVisitors.h" @@ -24,7 +25,7 @@ enum eTalkType LookingForGroup = ChannelFlags::CHANNEL_FLAG_LFG | ChannelFlags::CHANNEL_FLAG_GENERAL }; -std::map SuggestWhatToDoAction::instances; +std::map SuggestDungeonAction::instances; std::map SuggestWhatToDoAction::factions; SuggestWhatToDoAction::SuggestWhatToDoAction(PlayerbotAI* botAI, std::string const name) @@ -34,7 +35,6 @@ SuggestWhatToDoAction::SuggestWhatToDoAction(PlayerbotAI* botAI, std::string con suggestions.push_back(std::bind(&SuggestWhatToDoAction::specificQuest, this)); suggestions.push_back(std::bind(&SuggestWhatToDoAction::grindReputation, this)); suggestions.push_back(std::bind(&SuggestWhatToDoAction::something, this)); - suggestions.push_back(std::bind(&SuggestWhatToDoAction::instance, this)); suggestions.push_back(std::bind(&SuggestWhatToDoAction::grindMaterials, this)); } @@ -61,73 +61,6 @@ bool SuggestWhatToDoAction::Execute(Event event) return true; } -void SuggestWhatToDoAction::instance() -{ - if (instances.empty()) - { - instances["Ragefire Chasm"] = 15; - instances["Deadmines"] = 18; - instances["Wailing Caverns"] = 18; - instances["Shadowfang Keep"] = 25; - instances["Blackfathom Deeps"] = 20; - instances["Stockade"] = 20; - instances["Gnomeregan"] = 35; - instances["Razorfen Kraul"] = 35; - instances["Maraudon"] = 50; - instances["Scarlet Monestery"] = 40; - instances["Uldaman"] = 45; - instances["Dire Maul"] = 58; - instances["Scholomance"] = 59; - instances["Razorfen Downs"] = 40; - instances["Strathholme"] = 59; - instances["Zul'Farrak"] = 45; - instances["Blackrock Depths"] = 55; - instances["Temple of Atal'Hakkar"] = 55; - instances["Lower Blackrock Spire"] = 57; - - instances["Hellfire Citidel"] = 65; - instances["Coilfang Reservoir"] = 65; - instances["Auchindoun"] = 65; - instances["Cavens of Time"] = 68; - instances["Tempest Keep"] = 69; - instances["Magister's Terrace"] = 70; - - instances["Utgarde Keep"] = 75; - instances["The Nexus"] = 75; - instances["Ahn'kahet: The Old Kingdom"] = 75; - instances["Azjol-Nerub"] = 75; - instances["Drak'Tharon Keep"] = 75; - instances["Violet Hold"] = 80; - instances["Gundrak"] = 77; - instances["Halls of Stone"] = 77; - instances["Halls of Lightning"] = 77; - instances["Oculus"] = 77; - instances["Utgarde Pinnacle"] = 77; - instances["Trial of the Champion"] = 80; - instances["Forge of Souls"] = 80; - instances["Pit of Saron"] = 80; - instances["Halls of Reflection"] = 80; - } - - std::vector allowedInstances; - for (const auto& instance : instances) - { - if (bot->GetLevel() >= instance.second) - allowedInstances.push_back(instance.first); - } - if (allowedInstances.empty()) return; - - std::map placeholders; - placeholders["%role"] = ChatHelper::FormatClass(bot, AiFactory::GetPlayerSpecTab(bot)); - - std::ostringstream itemout; - //itemout << "|c00b000b0" << allowedInstances[urand(0, allowedInstances.size() - 1)] << "|r"; - itemout << allowedInstances[urand(0, allowedInstances.size() - 1)]; - placeholders["%instance"] = itemout.str(); - - spam(BOT_TEXT2("suggest_instance", placeholders), urand(0, 1) ? eTalkType::LookingForGroup : 0, urand(0, 2), urand(0, 2)); -} - std::vector SuggestWhatToDoAction::GetIncompletedQuests() { std::vector result; @@ -310,48 +243,46 @@ void SuggestWhatToDoAction::spam(std::string msg, uint8 flags, bool worldChat, b ChatChannelsEntry const* channel = sChatChannelsStore.LookupEntry(i); if (!channel) continue; - for (AreaTableEntry const* current_zone : sAreaTableStore) + AreaTableEntry const* current_zone = GetAreaEntryByAreaID(bot->GetAreaId()); + if (!current_zone) + continue; + + // combine full channel name + char channelName[100]; + Channel* chn = nullptr; + if ((channel->flags & CHANNEL_DBC_FLAG_LFG) != 0) { - if (!current_zone) - continue; + std::string chanName = channel->pattern[_dbc_locale]; + chn = cMgr->GetChannel(chanName, bot); + } + else + { + snprintf(channelName, 100, channel->pattern[_dbc_locale], current_zone->area_name[_dbc_locale]); + chn = cMgr->GetChannel(channelName, bot); + } + if (!chn) + continue; + // skip world chat here + if (chn->GetName() == "World") + continue; + if (flags != 0 && chn->GetFlags() != flags) + continue; - // combine full channel name - char channelName[100]; - Channel* chn = nullptr; - if ((channel->flags & CHANNEL_DBC_FLAG_LFG) != 0) - { - std::string chanName = channel->pattern[_dbc_locale]; - chn = cMgr->GetChannel(chanName, bot); - } - else - { - snprintf(channelName, 100, channel->pattern[_dbc_locale], current_zone->area_name[_dbc_locale]); - chn = cMgr->GetChannel(channelName, bot); - } - if (!chn) - continue; - // skip world chat here - if (chn->GetName() == "World") - continue; + // skip local defense + if (chn->GetChannelId() == 22) + continue; - if (flags != 0 && chn->GetFlags() != flags) - continue; - - // skip local defense - //if (chn->GetFlags() == 0x18) - // continue; - - // no filter, pick several options - if (flags == CHANNEL_FLAG_NONE) - { - channelNames.push_back(chn->GetName()); - } - else - { - chn->Say(bot->GetGUID(), msg.c_str(), LANG_UNIVERSAL); - LOG_INFO("playerbots", "{} - {} channel {}", bot->GetName().c_str(), msg.c_str(), chn->GetName()); - } + // no filter, pick several options + if (flags == CHANNEL_FLAG_NONE) + { + channelNames.push_back(chn->GetName()); + } + else + { + if (!bot->IsInChannel(chn)) + chn->JoinChannel(bot, ""); + chn->Say(bot->GetGUID(), msg.c_str(), LANG_UNIVERSAL); } if (!channelNames.empty()) @@ -359,8 +290,10 @@ void SuggestWhatToDoAction::spam(std::string msg, uint8 flags, bool worldChat, b std::string randomName = channelNames[urand(0, channelNames.size() - 1)]; if (Channel* chn = cMgr->GetChannel(randomName, bot)) { + if (!bot->IsInChannel(chn)) + chn->JoinChannel(bot, ""); + chn->Say(bot->GetGUID(), msg.c_str(), LANG_UNIVERSAL); - LOG_INFO("playerbots", "{} - {} channel {}", bot->GetName().c_str(), msg.c_str(), chn->GetName()); } } @@ -410,6 +343,78 @@ class FindTradeItemsVisitor : public IterateItemsVisitor uint32 quality; }; +SuggestDungeonAction::SuggestDungeonAction(PlayerbotAI* botAI) : SuggestWhatToDoAction(botAI, "suggest dungeon") +{ +} + +bool SuggestDungeonAction::Execute(Event event) +{ + if (instances.empty()) + { + instances["Ragefire Chasm"] = 15; + instances["Deadmines"] = 18; + instances["Wailing Caverns"] = 18; + instances["Shadowfang Keep"] = 25; + instances["Blackfathom Deeps"] = 20; + instances["Stockade"] = 20; + instances["Gnomeregan"] = 35; + instances["Razorfen Kraul"] = 35; + instances["Maraudon"] = 50; + instances["Scarlet Monestery"] = 40; + instances["Uldaman"] = 45; + instances["Dire Maul"] = 58; + instances["Scholomance"] = 59; + instances["Razorfen Downs"] = 40; + instances["Strathholme"] = 59; + instances["Zul'Farrak"] = 45; + instances["Blackrock Depths"] = 55; + instances["Temple of Atal'Hakkar"] = 55; + instances["Lower Blackrock Spire"] = 57; + + instances["Hellfire Citidel"] = 65; + instances["Coilfang Reservoir"] = 65; + instances["Auchindoun"] = 65; + instances["Cavens of Time"] = 68; + instances["Tempest Keep"] = 69; + instances["Magister's Terrace"] = 70; + + instances["Utgarde Keep"] = 75; + instances["The Nexus"] = 75; + instances["Ahn'kahet: The Old Kingdom"] = 75; + instances["Azjol-Nerub"] = 75; + instances["Drak'Tharon Keep"] = 75; + instances["Violet Hold"] = 80; + instances["Gundrak"] = 77; + instances["Halls of Stone"] = 77; + instances["Halls of Lightning"] = 77; + instances["Oculus"] = 77; + instances["Utgarde Pinnacle"] = 77; + instances["Trial of the Champion"] = 80; + instances["Forge of Souls"] = 80; + instances["Pit of Saron"] = 80; + instances["Halls of Reflection"] = 80; + } + + std::vector allowedInstances; + for (const auto& instance : instances) + { + if (bot->GetLevel() >= instance.second) + allowedInstances.push_back(instance.first); + } + if (allowedInstances.empty()) return false; + + std::map placeholders; + placeholders["%role"] = ChatHelper::FormatClass(bot, AiFactory::GetPlayerSpecTab(bot)); + + std::ostringstream itemout; + //itemout << "|c00b000b0" << allowedInstances[urand(0, allowedInstances.size() - 1)] << "|r"; + itemout << allowedInstances[urand(0, allowedInstances.size() - 1)]; + placeholders["%instance"] = itemout.str(); + + spam(BOT_TEXT2("suggest_instance", placeholders), urand(0, 1) ? eTalkType::LookingForGroup : 0, urand(0, 2), urand(0, 2)); + return true; +} + SuggestTradeAction::SuggestTradeAction(PlayerbotAI* botAI) : SuggestWhatToDoAction(botAI, "suggest trade") { } diff --git a/src/strategy/actions/SuggestWhatToDoAction.h b/src/strategy/actions/SuggestWhatToDoAction.h index 2a942e34..f3a57b89 100644 --- a/src/strategy/actions/SuggestWhatToDoAction.h +++ b/src/strategy/actions/SuggestWhatToDoAction.h @@ -30,7 +30,6 @@ class SuggestWhatToDoAction : public InventoryAction std::vector GetIncompletedQuests(); private: - static std::map instances; static std::map factions; const int32_t _dbc_locale; }; @@ -44,4 +43,15 @@ class SuggestTradeAction : public SuggestWhatToDoAction bool isUseful() override { return true; } }; +class SuggestDungeonAction : public SuggestWhatToDoAction +{ + public: + SuggestDungeonAction(PlayerbotAI* botAI); + + bool Execute(Event event) override; + bool isUseful() override { return true; } + private: + static std::map instances; +}; + #endif From adf9924925b2187d4566def6660257421a11e744 Mon Sep 17 00:00:00 2001 From: Atidot3 Date: Sat, 27 Jul 2024 10:15:12 +0200 Subject: [PATCH 34/61] using config to toggle chat functionnality and suggest dungeon --- conf/playerbots.conf.dist | 19 ++++++++++----- src/PlayerbotAIConfig.cpp | 2 ++ src/PlayerbotAIConfig.h | 2 ++ .../actions/SuggestWhatToDoAction.cpp | 2 ++ src/strategy/generic/EmoteStrategy.cpp | 23 +++++++++++-------- 5 files changed, 32 insertions(+), 16 deletions(-) diff --git a/conf/playerbots.conf.dist b/conf/playerbots.conf.dist index 40a44683..496ea5d7 100644 --- a/conf/playerbots.conf.dist +++ b/conf/playerbots.conf.dist @@ -1238,6 +1238,19 @@ AiPlayerbot.CommandPrefix = "" # Separator for bot chat commands AiPlayerbot.CommandSeparator = "\\\\" +# Enable playerbot talk (say / yell / general chatting / lfg) +AiPlayerbot.RandomBotTalk = 0 + +# Enable playerbot emote +AiPlayerbot.RandomBotEmote = 0 + +# Enable dungeon suggestions for random bots +AiPlayerbot.RandomBotSuggestDungeons = 1 + +# Bots greet to the players +AiPlayerbot.EnableGreet = 0 + + # # # @@ -1276,9 +1289,6 @@ AiPlayerbot.RandomBotLoginAtStartup = 1 # 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 @@ -1297,9 +1307,6 @@ 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 diff --git a/src/PlayerbotAIConfig.cpp b/src/PlayerbotAIConfig.cpp index 94e290fe..94765f34 100644 --- a/src/PlayerbotAIConfig.cpp +++ b/src/PlayerbotAIConfig.cpp @@ -140,6 +140,8 @@ bool PlayerbotAIConfig::Initialize() minRandomBotsPriceChangeInterval = sConfigMgr->GetOption("AiPlayerbot.MinRandomBotsPriceChangeInterval", 2 * HOUR); maxRandomBotsPriceChangeInterval = sConfigMgr->GetOption("AiPlayerbot.MaxRandomBotsPriceChangeInterval", 48 * HOUR); randomBotJoinLfg = sConfigMgr->GetOption("AiPlayerbot.RandomBotJoinLfg", true); + randomBotTalk = sConfigMgr->GetOption("AiPlayerbot.RandomBotTalk", false); + randomBotEmote = sConfigMgr->GetOption("AiPlayerbot.RandomBotEmote", false); randomBotSuggestDungeons = sConfigMgr->GetOption("AiPlayerbot.RandomBotSuggestDungeons", true); suggestDungeonsInLowerCaseRandomly = sConfigMgr->GetOption("AiPlayerbot.SuggestDungeonsInLowerCaseRandomly", false); randomBotJoinBG = sConfigMgr->GetOption("AiPlayerbot.RandomBotJoinBG", true); diff --git a/src/PlayerbotAIConfig.h b/src/PlayerbotAIConfig.h index 5ce7d39e..c008c051 100644 --- a/src/PlayerbotAIConfig.h +++ b/src/PlayerbotAIConfig.h @@ -95,6 +95,8 @@ class PlayerbotAIConfig uint32 randomBotsPerInterval; uint32 minRandomBotsPriceChangeInterval, maxRandomBotsPriceChangeInterval; bool randomBotJoinLfg; + bool randomBotTalk; + bool randomBotEmote; bool randomBotSuggestDungeons; bool suggestDungeonsInLowerCaseRandomly; bool randomBotJoinBG; diff --git a/src/strategy/actions/SuggestWhatToDoAction.cpp b/src/strategy/actions/SuggestWhatToDoAction.cpp index 33b17e23..428edd33 100644 --- a/src/strategy/actions/SuggestWhatToDoAction.cpp +++ b/src/strategy/actions/SuggestWhatToDoAction.cpp @@ -349,6 +349,8 @@ SuggestDungeonAction::SuggestDungeonAction(PlayerbotAI* botAI) : SuggestWhatToDo bool SuggestDungeonAction::Execute(Event event) { + // TODO: use sPlayerbotDungeonSuggestionMgr + if (instances.empty()) { instances["Ragefire Chasm"] = 15; diff --git a/src/strategy/generic/EmoteStrategy.cpp b/src/strategy/generic/EmoteStrategy.cpp index a008f48e..57f400c9 100644 --- a/src/strategy/generic/EmoteStrategy.cpp +++ b/src/strategy/generic/EmoteStrategy.cpp @@ -7,22 +7,25 @@ void EmoteStrategy::InitTriggers(std::vector& triggers) { - triggers.push_back(new TriggerNode("seldom", NextAction::array(0, new NextAction("emote", 1.0f), nullptr))); - triggers.push_back(new TriggerNode("often", NextAction::array(0, new NextAction("suggest what to do", 1.0f), nullptr))); - triggers.push_back(new TriggerNode("often", NextAction::array(0, new NextAction("suggest trade", 1.0f), nullptr))); + if (sPlayerbotAIConfig->randomBotEmote) + { + triggers.push_back(new TriggerNode("seldom", NextAction::array(0, new NextAction("emote", 1.0f), nullptr))); + triggers.push_back(new TriggerNode("receive text emote", NextAction::array(0, new NextAction("emote", 10.0f), nullptr))); + triggers.push_back(new TriggerNode("receive emote", NextAction::array(0, new NextAction("emote", 10.0f), nullptr))); + } + + if (sPlayerbotAIConfig->randomBotTalk) + { + triggers.push_back(new TriggerNode("often", NextAction::array(0, new NextAction("suggest what to do", 1.0f), nullptr))); + triggers.push_back(new TriggerNode("often", NextAction::array(0, new NextAction("suggest trade", 1.0f), nullptr))); + triggers.push_back(new TriggerNode("seldom", NextAction::array(0, new NextAction("talk", 1.0f), nullptr))); + } if (sPlayerbotAIConfig->randomBotSuggestDungeons) - { triggers.push_back(new TriggerNode("random", NextAction::array(0, new NextAction("suggest dungeon", 1.0f), nullptr))); - } if (sPlayerbotAIConfig->enableGreet) - { triggers.push_back(new TriggerNode("new player nearby", NextAction::array(0, new NextAction("greet", 1.0f), nullptr))); - } - triggers.push_back(new TriggerNode("seldom", NextAction::array(0, new NextAction("talk", 1.0f), nullptr))); - triggers.push_back(new TriggerNode("receive text emote", NextAction::array(0, new NextAction("emote", 10.0f), nullptr))); - triggers.push_back(new TriggerNode("receive emote", NextAction::array(0, new NextAction("emote", 10.0f), nullptr))); triggers.push_back(new TriggerNode("often", NextAction::array(0, new NextAction("rpg mount anim", 1.0f), nullptr))); } From 162229efe5c192bcb231a1a1a31a8f367db74e97 Mon Sep 17 00:00:00 2001 From: Atidot3 Date: Sat, 27 Jul 2024 10:20:55 +0200 Subject: [PATCH 35/61] Fix spellid value to use forced enUS locale --- src/strategy/values/SpellIdValue.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/strategy/values/SpellIdValue.cpp b/src/strategy/values/SpellIdValue.cpp index beb445f8..8cb8198f 100644 --- a/src/strategy/values/SpellIdValue.cpp +++ b/src/strategy/values/SpellIdValue.cpp @@ -190,7 +190,7 @@ uint32 VehicleSpellIdValue::Calculate() char firstSymbol = tolower(namepart[0]); int spellLength = wnamepart.length(); - int loc = bot->GetSession()->GetSessionDbcLocale(); + const int loc = LocaleConstant::LOCALE_enUS; Creature* creature = vehicleBase->ToCreature(); for (uint32 x = 0; x < MAX_CREATURE_SPELLS; ++x) From c48d69a802f46ad7320229c384e182f79d050294 Mon Sep 17 00:00:00 2001 From: Atidot3 Date: Sat, 27 Jul 2024 10:33:49 +0200 Subject: [PATCH 36/61] Fix shaman cure strategy --- src/strategy/shaman/ShamanActions.h | 30 +++---------------- src/strategy/shaman/ShamanAiObjectContext.cpp | 16 +++++----- 2 files changed, 12 insertions(+), 34 deletions(-) diff --git a/src/strategy/shaman/ShamanActions.h b/src/strategy/shaman/ShamanActions.h index 2db469fb..1b8d0101 100644 --- a/src/strategy/shaman/ShamanActions.h +++ b/src/strategy/shaman/ShamanActions.h @@ -5,9 +5,7 @@ #ifndef _PLAYERBOT_SHAMANACTIONS_H #define _PLAYERBOT_SHAMANACTIONS_H -#include "Define.h" #include "GenericSpellActions.h" -#include "Playerbots.h" #include "SharedDefines.h" class PlayerbotAI; @@ -362,31 +360,11 @@ class CastWindShearOnEnemyHealerAction : public CastSpellOnEnemyHealerAction CastWindShearOnEnemyHealerAction(PlayerbotAI* botAI) : CastSpellOnEnemyHealerAction(botAI, "wind shear") { } }; -// class CastCurePoisonAction : public CastCureSpellAction -// { -// public: -// CastCurePoisonAction(PlayerbotAI* botAI) : CastCureSpellAction(botAI, "cure poison") { } -// }; +CURE_ACTION(CastCurePoisonActionSham, "cure disease"); +CURE_PARTY_ACTION(CastCurePoisonOnPartyActionSham, "cure poison", DISPEL_POISON); -// class CastCurePoisonOnPartyAction : public CurePartyMemberAction -// { -// public: -// CastCurePoisonOnPartyAction(PlayerbotAI* botAI) : CurePartyMemberAction(botAI, "cure poison", DISPEL_POISON) { } -// }; - -// class CastCureDiseaseAction : public CastCureSpellAction -// { -// public: -// CastCureDiseaseAction(PlayerbotAI* botAI) : CastCureSpellAction(botAI, "cure disease") { } -// }; - -// class CastCureDiseaseOnPartyAction : public CurePartyMemberAction -// { -// public: -// CastCureDiseaseOnPartyAction(PlayerbotAI* botAI) : CurePartyMemberAction(botAI, "cure disease", DISPEL_DISEASE) { } - -// std::string const getName() override { return "cure disease on party"; } -// }; +CURE_ACTION(CastCureDiseaseActionSham, "cure disease"); +CURE_PARTY_ACTION(CastCureDiseaseOnPartyActionSham, "cure disease", DISPEL_DISEASE); class CastLavaBurstAction : public CastSpellAction { diff --git a/src/strategy/shaman/ShamanAiObjectContext.cpp b/src/strategy/shaman/ShamanAiObjectContext.cpp index cee208c2..f7ac2223 100644 --- a/src/strategy/shaman/ShamanAiObjectContext.cpp +++ b/src/strategy/shaman/ShamanAiObjectContext.cpp @@ -213,10 +213,10 @@ class ShamanAiObjectContextInternal : public NamedObjectContext 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; - // creators["cure poison on party"] = &ShamanAiObjectContextInternal::cure_poison_on_party; + creators["cure disease"] = &ShamanAiObjectContextInternal::cure_disease; + creators["cure disease on party"] = &ShamanAiObjectContextInternal::cure_disease_on_party; + creators["cure poison"] = &ShamanAiObjectContextInternal::cure_poison; + creators["cure poison on party"] = &ShamanAiObjectContextInternal::cure_poison_on_party; creators["lava burst"] = &ShamanAiObjectContextInternal::lava_burst; creators["earth shield on main tank"] = &ShamanAiObjectContextInternal::earth_shield_on_main_tank; creators["fire elemental totem"] = &ShamanAiObjectContextInternal::fire_elemental_totem; @@ -277,10 +277,10 @@ class ShamanAiObjectContextInternal : public NamedObjectContext static Action* lava_lash(PlayerbotAI* botAI) { return new CastLavaLashAction(botAI); } static Action* ancestral_spirit(PlayerbotAI* botAI) { return new CastAncestralSpiritAction(botAI); } static Action* wind_shear_on_enemy_healer(PlayerbotAI* botAI) { return new CastWindShearOnEnemyHealerAction(botAI); } - // static Action* cure_poison(PlayerbotAI* botAI) { return new CastCurePoisonAction(botAI); } - // static Action* cure_poison_on_party(PlayerbotAI* botAI) { return new CastCurePoisonOnPartyAction(botAI); } - // static Action* cure_disease(PlayerbotAI* botAI) { return new CastCureDiseaseAction(botAI); } - // static Action* cure_disease_on_party(PlayerbotAI* botAI) { return new CastCureDiseaseOnPartyAction(botAI); } + static Action* cure_poison(PlayerbotAI* botAI) { return new CastCurePoisonActionSham(botAI); } + static Action* cure_poison_on_party(PlayerbotAI* botAI) { return new CastCurePoisonOnPartyActionSham(botAI); } + static Action* cure_disease(PlayerbotAI* botAI) { return new CastCureDiseaseActionSham(botAI); } + static Action* cure_disease_on_party(PlayerbotAI* botAI) { return new CastCureDiseaseOnPartyActionSham(botAI); } static Action* lava_burst(PlayerbotAI* ai) { return new CastLavaBurstAction(ai); } static Action* earth_shield_on_main_tank(PlayerbotAI* ai) { return new CastEarthShieldOnMainTankAction(ai); } static Action* totem_of_wrath(PlayerbotAI* ai) { return new CastTotemOfWrathAction(ai); } From 00844985eb197933555c2447464772af9fa9d722 Mon Sep 17 00:00:00 2001 From: Atidot3 Date: Sat, 27 Jul 2024 14:39:30 +0200 Subject: [PATCH 37/61] Fix chain link broken (random) unknown + dbc local enus force in some case (spell / chathelper etc) --- src/ChatHelper.cpp | 8 ++++---- src/RandomPlayerbotMgr.cpp | 4 ++-- src/strategy/actions/LfgActions.cpp | 2 +- src/strategy/actions/MovementActions.cpp | 6 +++--- src/strategy/actions/SuggestWhatToDoAction.h | 1 - src/strategy/actions/TellLosAction.cpp | 2 +- src/strategy/generic/EmoteStrategy.cpp | 2 +- 7 files changed, 12 insertions(+), 13 deletions(-) diff --git a/src/ChatHelper.cpp b/src/ChatHelper.cpp index 630bfca9..92daa117 100644 --- a/src/ChatHelper.cpp +++ b/src/ChatHelper.cpp @@ -288,7 +288,7 @@ std::string const ChatHelper::FormatQuest(Quest const* quest) std::string const ChatHelper::FormatGameobject(GameObject* go) { std::ostringstream out; - out << "|cFFFFFF00|Hfound:" << go->GetGUID().GetRawValue() << ":" << go->GetEntry() << ":" << "|h[" << go->GetNameForLocaleIdx(sWorld->GetDefaultDbcLocale()) << "]|h|r"; + out << "|cFFFFFF00|Hfound:" << go->GetGUID().GetRawValue() << ":" << go->GetEntry() << ":" << "|h[" << go->GetNameForLocaleIdx(LOCALE_enUS) << "]|h|r"; return out.str(); } @@ -296,7 +296,7 @@ std::string const ChatHelper::FormatWorldobject(WorldObject* wo) { std::ostringstream out; out << "|cFFFFFF00|Hfound:" << wo->GetGUID().GetRawValue() << ":" << wo->GetEntry() << ":" << "|h["; - out << (wo->ToGameObject() ? ((GameObject*)wo)->GetNameForLocaleIdx(sWorld->GetDefaultDbcLocale()) : wo->GetNameForLocaleIdx(sWorld->GetDefaultDbcLocale())) << "]|h|r"; + out << (wo->ToGameObject() ? ((GameObject*)wo)->GetNameForLocaleIdx(LOCALE_enUS) : wo->GetNameForLocaleIdx(LOCALE_enUS)) << "]|h|r"; return out.str(); } @@ -327,7 +327,7 @@ std::string const ChatHelper::FormatWorldEntry(int32 entry) std::string const ChatHelper::FormatSpell(SpellInfo const* spellInfo) { std::ostringstream out; - out << "|cffffffff|Hspell:" << spellInfo->Id << "|h[" << spellInfo->SpellName[sWorld->GetDefaultDbcLocale()] << "]|h|r"; + out << "|cffffffff|Hspell:" << spellInfo->Id << "|h[" << spellInfo->SpellName[LOCALE_enUS] << "]|h|r"; return out.str(); } @@ -336,7 +336,7 @@ std::string const ChatHelper::FormatItem(ItemTemplate const* proto, uint32 count char color[32]; sprintf(color, "%x", ItemQualityColors[proto->Quality]); - // const std::string &name = sObjectMgr->GetItemLocale(proto->ItemId)->Name[sWorld->GetDefaultDbcLocale()]; + // const std::string &name = sObjectMgr->GetItemLocale(proto->ItemId)->Name[LOCALE_enUS]; std::ostringstream out; out << "|c" << color << "|Hitem:" << proto->ItemId diff --git a/src/RandomPlayerbotMgr.cpp b/src/RandomPlayerbotMgr.cpp index 5e6891e5..639acd52 100644 --- a/src/RandomPlayerbotMgr.cpp +++ b/src/RandomPlayerbotMgr.cpp @@ -1228,8 +1228,8 @@ void RandomPlayerbotMgr::RandomTeleport(Player* bot, std::vector& if (bot->GetLevel() <= 18 && (loc.GetMapId() != pInfo->mapId || dis > 10000.0f)) { continue; } - LocaleConstant locale = sWorld->GetDefaultDbcLocale(); - + + const LocaleConstant& locale = sWorld->GetDefaultDbcLocale(); LOG_INFO("playerbots", "Random teleporting bot {} (level {}) to Map: {} ({}) Zone: {} ({}) Area: {} ({}) {},{},{} ({}/{} locations)", bot->GetName().c_str(), bot->GetLevel(), map->GetId(), map->GetMapName(), diff --git a/src/strategy/actions/LfgActions.cpp b/src/strategy/actions/LfgActions.cpp index 4cb0bada..d7e7b865 100644 --- a/src/strategy/actions/LfgActions.cpp +++ b/src/strategy/actions/LfgActions.cpp @@ -105,7 +105,7 @@ bool LfgJoinAction::JoinLFG() const auto& botLevel = bot->GetLevel(); - /*LFG_TYPE_RANDOM on classic is 15-58 so bot over level 25 will never queue*/ + /*LFG_TYPE_RANDOM on classic is 15-58 so bot over level 25 will never queue*/ if (dungeon->MinLevel && (botLevel < dungeon->MinLevel || botLevel > dungeon->MaxLevel) || (botLevel > dungeon->MinLevel + 10 && dungeon->TypeID == LFG_TYPE_DUNGEON) diff --git a/src/strategy/actions/MovementActions.cpp b/src/strategy/actions/MovementActions.cpp index ed002f53..9f7799b1 100644 --- a/src/strategy/actions/MovementActions.cpp +++ b/src/strategy/actions/MovementActions.cpp @@ -1555,7 +1555,7 @@ bool AvoidAoeAction::AvoidAuraWithDynamicObj() return false; } std::ostringstream name; - name << spellInfo->SpellName[sWorld->GetDefaultDbcLocale()]; // << "] (aura)"; + name << spellInfo->SpellName[LOCALE_enUS]; // << "] (aura)"; if (FleePosition(dynOwner->GetPosition(), radius)) { if (sPlayerbotAIConfig->tellWhenAvoidAoe && lastTellTimer < time(NULL) - 10) { lastTellTimer = time(NULL); @@ -1613,7 +1613,7 @@ bool AvoidAoeAction::AvoidGameObjectWithDamage() continue; } std::ostringstream name; - name << spellInfo->SpellName[sWorld->GetDefaultDbcLocale()]; // << "] (object)"; + name << spellInfo->SpellName[LOCALE_enUS]; // << "] (object)"; if (FleePosition(go->GetPosition(), radius)) { if (sPlayerbotAIConfig->tellWhenAvoidAoe && lastTellTimer < time(NULL) - 10) { lastTellTimer = time(NULL); @@ -1662,7 +1662,7 @@ bool AvoidAoeAction::AvoidUnitWithDamageAura() break; } std::ostringstream name; - name << triggerSpellInfo->SpellName[sWorld->GetDefaultDbcLocale()]; //<< "] (unit)"; + name << triggerSpellInfo->SpellName[LOCALE_enUS]; //<< "] (unit)"; if (FleePosition(unit->GetPosition(), radius)) { if (sPlayerbotAIConfig->tellWhenAvoidAoe && lastTellTimer < time(NULL) - 10) { lastTellTimer = time(NULL); diff --git a/src/strategy/actions/SuggestWhatToDoAction.h b/src/strategy/actions/SuggestWhatToDoAction.h index f3a57b89..46391ff2 100644 --- a/src/strategy/actions/SuggestWhatToDoAction.h +++ b/src/strategy/actions/SuggestWhatToDoAction.h @@ -20,7 +20,6 @@ class SuggestWhatToDoAction : public InventoryAction protected: using Suggestion = std::function; std::vector suggestions; - void instance(); void specificQuest(); void grindReputation(); void grindMaterials(); diff --git a/src/strategy/actions/TellLosAction.cpp b/src/strategy/actions/TellLosAction.cpp index 688599ff..8917d2ed 100644 --- a/src/strategy/actions/TellLosAction.cpp +++ b/src/strategy/actions/TellLosAction.cpp @@ -138,4 +138,4 @@ bool TellExpectedDpsAction::Execute(Event event) float dps = AI_VALUE(float, "expected group dps"); botAI->TellMaster("Expected Group DPS: " + std::to_string(dps)); return true; -} \ No newline at end of file +} diff --git a/src/strategy/generic/EmoteStrategy.cpp b/src/strategy/generic/EmoteStrategy.cpp index 57f400c9..002fdc41 100644 --- a/src/strategy/generic/EmoteStrategy.cpp +++ b/src/strategy/generic/EmoteStrategy.cpp @@ -22,7 +22,7 @@ void EmoteStrategy::InitTriggers(std::vector& triggers) } if (sPlayerbotAIConfig->randomBotSuggestDungeons) - triggers.push_back(new TriggerNode("random", NextAction::array(0, new NextAction("suggest dungeon", 1.0f), nullptr))); + triggers.push_back(new TriggerNode("often", NextAction::array(0, new NextAction("suggest dungeon", 1.0f), nullptr))); if (sPlayerbotAIConfig->enableGreet) triggers.push_back(new TriggerNode("new player nearby", NextAction::array(0, new NextAction("greet", 1.0f), nullptr))); From e6a7d7cc26d0c9aa53ff8f885c03ac1d6c28ef1a Mon Sep 17 00:00:00 2001 From: Atidot3 Date: Sun, 28 Jul 2024 00:54:37 +0200 Subject: [PATCH 38/61] Allow bot to attack mobs they need to kill / loot for quests up to 5 levels above their level --- src/strategy/values/GrindTargetValue.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/strategy/values/GrindTargetValue.cpp b/src/strategy/values/GrindTargetValue.cpp index ae8fffdb..0be03904 100644 --- a/src/strategy/values/GrindTargetValue.cpp +++ b/src/strategy/values/GrindTargetValue.cpp @@ -160,7 +160,7 @@ bool GrindTargetValue::needForQuest(Unit* target) { QuestStatusData* questStatus = sTravelMgr->getQuestStatus(bot, questId); - if (questTemplate->GetQuestLevel() > bot->GetLevel()) + if (questTemplate->GetQuestLevel() > bot->GetLevel()+5) continue; for (int j = 0; j < QUEST_OBJECTIVES_COUNT; j++) From 1fbd312d58f60e3d0c33824bf1a77b748276f1b2 Mon Sep 17 00:00:00 2001 From: Atidot3 Date: Sun, 28 Jul 2024 01:02:54 +0200 Subject: [PATCH 39/61] Allow bot to talk in guild when they loot nice item, levelup, kill unique monsters --- src/strategy/actions/AutoLearnSpellAction.cpp | 17 +++++++++++++++- src/strategy/actions/LootAction.cpp | 17 ++++++++++++++++ src/strategy/actions/SayAction.cpp | 12 +++++------ src/strategy/actions/XpGainAction.cpp | 20 +++++++++++++++++++ 4 files changed, 59 insertions(+), 7 deletions(-) diff --git a/src/strategy/actions/AutoLearnSpellAction.cpp b/src/strategy/actions/AutoLearnSpellAction.cpp index 3d5230ed..f2d7688f 100644 --- a/src/strategy/actions/AutoLearnSpellAction.cpp +++ b/src/strategy/actions/AutoLearnSpellAction.cpp @@ -6,6 +6,7 @@ #include "Event.h" #include "PlayerbotFactory.h" #include "Playerbots.h" +#include "GuildMgr.h" bool AutoLearnSpellAction::Execute(Event event) { @@ -27,7 +28,6 @@ bool AutoLearnSpellAction::Execute(Event event) return true; } - void AutoLearnSpellAction::LearnSpells(std::ostringstream* out) { if (sPlayerbotAIConfig->autoLearnTrainerSpells && sRandomPlayerbotMgr->IsRandomBot(bot))// || (!botAI->GetMaster() && sRandomPlayerbotMgr->IsRandomBot(bot))) @@ -35,6 +35,21 @@ void AutoLearnSpellAction::LearnSpells(std::ostringstream* out) if (sPlayerbotAIConfig->autoLearnQuestSpells && sRandomPlayerbotMgr->IsRandomBot(bot))// || (!botAI->GetMaster() && sRandomPlayerbotMgr->IsRandomBot(bot))) LearnQuestSpells(out); + + if (sPlayerbotAIConfig->randomBotTalk) + { + Guild* guild = sGuildMgr->GetGuildById(bot->GetGuildId()); + if (guild) + { + std::map placeholders; + placeholders["%level"] = std::to_string(bot->GetLevel()); + + if (urand(0, 3)) + guild->BroadcastToGuild(bot->GetSession(), false, BOT_TEXT2("Ding!", placeholders), LANG_UNIVERSAL); + else + guild->BroadcastToGuild(bot->GetSession(), false, BOT_TEXT2("Yay level %level!", placeholders), LANG_UNIVERSAL); + } + } } void AutoLearnSpellAction::LearnTrainerSpells(std::ostringstream* out) diff --git a/src/strategy/actions/LootAction.cpp b/src/strategy/actions/LootAction.cpp index f0526328..595ff16f 100644 --- a/src/strategy/actions/LootAction.cpp +++ b/src/strategy/actions/LootAction.cpp @@ -12,6 +12,7 @@ #include "PlayerbotAIConfig.h" #include "Playerbots.h" #include "ServerFacade.h" +#include "GuildMgr.h" bool LootAction::Execute(Event event) { @@ -416,6 +417,22 @@ 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); + if (sPlayerbotAIConfig->randomBotTalk && bot->GetGuildId() && urand(0, 10) && proto->Quality >= ITEM_QUALITY_RARE) + { + Guild* guild = sGuildMgr->GetGuildById(bot->GetGuildId()); + + if (guild) + { + std::map placeholders; + placeholders["%name"] = chat->FormatItem(proto); + + if (urand(0, 3)) + guild->BroadcastToGuild(bot->GetSession(), false, BOT_TEXT2("Yay I looted %name!", placeholders), LANG_UNIVERSAL); + else + guild->BroadcastToGuild(bot->GetSession(), false, BOT_TEXT2("Guess who got a %name? Me!", placeholders), LANG_UNIVERSAL); + } + } + // std::ostringstream out; // out << "Looting " << chat->FormatItem(proto); // botAI->TellMasterNoFacing(out.str()); diff --git a/src/strategy/actions/SayAction.cpp b/src/strategy/actions/SayAction.cpp index 67395b2e..e299736d 100644 --- a/src/strategy/actions/SayAction.cpp +++ b/src/strategy/actions/SayAction.cpp @@ -130,26 +130,26 @@ void ChatReplyAction::ChatReplyDo(Player* bot, uint32 type, uint32 guid1, uint32 // if we're just commanding bots around, don't respond... // first one is for exact word matches if (noReplyMsgs.find(msg) != noReplyMsgs.end()) { - std::ostringstream out; + /*std::ostringstream out; out << "DEBUG ChatReplyDo decided to ignore exact blocklist match" << msg; - bot->Say(out.str(), LANG_UNIVERSAL); + bot->Say(out.str(), LANG_UNIVERSAL);*/ return; } // second one is for partial matches like + or - where we change strats if (std::any_of(noReplyMsgParts.begin(), noReplyMsgParts.end(), [&msg](const std::string& part) { return msg.find(part) != std::string::npos; })) { - std::ostringstream out; + /*std::ostringstream out; out << "DEBUG ChatReplyDo decided to ignore partial blocklist match" << msg; - bot->Say(out.str(), LANG_UNIVERSAL); + bot->Say(out.str(), LANG_UNIVERSAL);*/ return; } if (std::any_of(noReplyMsgStarts.begin(), noReplyMsgStarts.end(), [&msg](const std::string& start) { return msg.find(start) == 0; // Check if the start matches the beginning of msg })) { - std::ostringstream out; + /*std::ostringstream out; out << "DEBUG ChatReplyDo decided to ignore start blocklist match" << msg; - bot->Say(out.str(), LANG_UNIVERSAL); + bot->Say(out.str(), LANG_UNIVERSAL);*/ return; } diff --git a/src/strategy/actions/XpGainAction.cpp b/src/strategy/actions/XpGainAction.cpp index 6dcca4a4..155cb752 100644 --- a/src/strategy/actions/XpGainAction.cpp +++ b/src/strategy/actions/XpGainAction.cpp @@ -6,6 +6,7 @@ #include "Event.h" #include "PlayerbotAIConfig.h" #include "Playerbots.h" +#include "GuildMgr.h" bool XpGainAction::Execute(Event event) { @@ -32,6 +33,25 @@ bool XpGainAction::Execute(Event event) p >> groupBonus; // 8 group bonus } + if (sPlayerbotAIConfig->randomBotTalk && bot->GetGuildId() && urand(0, 10)) + { + Creature* creature = botAI->GetCreature(guid); + if (creature && (creature->isElite() || creature->isWorldBoss() || creature->GetLevel() > 61 || creature->GetLevel() > bot->GetLevel() + 4)) + { + Guild* guild = sGuildMgr->GetGuildById(bot->GetGuildId()); + if (guild) + { + std::map placeholders; + placeholders["%name"] = creature->GetName(); + + if (urand(0, 3)) + guild->BroadcastToGuild(bot->GetSession(), false, BOT_TEXT2("Wow I just killed %name!", placeholders), LANG_UNIVERSAL); + else + guild->BroadcastToGuild(bot->GetSession(), false, BOT_TEXT2("Awesome that %name went down quickly!", placeholders), LANG_UNIVERSAL); + } + } + } + Unit* victim = nullptr; if (guid) victim = botAI->GetUnit(guid); From 5f60ded4198a7eba57ceb59f74e0619109166820 Mon Sep 17 00:00:00 2001 From: Atidot3 Date: Sun, 28 Jul 2024 01:05:30 +0200 Subject: [PATCH 40/61] missing eTalkType enum on trade chat --- src/strategy/actions/SuggestWhatToDoAction.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/strategy/actions/SuggestWhatToDoAction.cpp b/src/strategy/actions/SuggestWhatToDoAction.cpp index 428edd33..dc9241f8 100644 --- a/src/strategy/actions/SuggestWhatToDoAction.cpp +++ b/src/strategy/actions/SuggestWhatToDoAction.cpp @@ -480,6 +480,6 @@ bool SuggestTradeAction::Execute(Event event) placeholders["%item"] = chat->FormatItem(proto, count); placeholders["%gold"] = chat->formatMoney(price); - spam(BOT_TEXT2("suggest_sell", placeholders), urand(0, 1) ? 0x3C : 0, urand(0, 1), urand(0, 5)); + spam(BOT_TEXT2("suggest_sell", placeholders), urand(0, 1) ? eTalkType::Trade : 0, urand(0, 1), urand(0, 5)); return true; } From 78832f106ee5800ab248827820bc16f5f1981d2b Mon Sep 17 00:00:00 2001 From: Revision Date: Sun, 28 Jul 2024 02:43:22 +0200 Subject: [PATCH 41/61] Add bots to transports Add bots to transports they're on so they actually move with it. --- src/strategy/actions/MovementActions.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/strategy/actions/MovementActions.cpp b/src/strategy/actions/MovementActions.cpp index ed002f53..7ae2f99f 100644 --- a/src/strategy/actions/MovementActions.cpp +++ b/src/strategy/actions/MovementActions.cpp @@ -849,6 +849,21 @@ void MovementAction::UpdateMovementState() if (bot->IsFlying()) bot->UpdateSpeed(MOVE_FLIGHT, true); + + Transport* newTransport = bot->GetMap()->GetTransportForPos(bot->GetPhaseMask(), bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ(), bot); + if (newTransport != bot->GetTransport()) + { + LOG_DEBUG("playerbots", "Bot {} is on a transport", IsMovingAllowed()); + + if (bot->GetTransport()) + bot->GetTransport()->RemovePassenger(bot, true); + + if (newTransport) + newTransport->AddPassenger(bot, true); + + bot->StopMovingOnCurrentPos(); + } + // Temporary speed increase in group //if (botAI->HasRealPlayerMaster()) //bot->SetSpeedRate(MOVE_RUN, 1.1f); From 75475e398685ef95a700d3a2084d082986df99eb Mon Sep 17 00:00:00 2001 From: Revision Date: Sun, 28 Jul 2024 02:57:46 +0200 Subject: [PATCH 42/61] Fix debug message --- src/strategy/actions/MovementActions.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/strategy/actions/MovementActions.cpp b/src/strategy/actions/MovementActions.cpp index 7ae2f99f..dae03815 100644 --- a/src/strategy/actions/MovementActions.cpp +++ b/src/strategy/actions/MovementActions.cpp @@ -853,7 +853,7 @@ void MovementAction::UpdateMovementState() Transport* newTransport = bot->GetMap()->GetTransportForPos(bot->GetPhaseMask(), bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ(), bot); if (newTransport != bot->GetTransport()) { - LOG_DEBUG("playerbots", "Bot {} is on a transport", IsMovingAllowed()); + LOG_DEBUG("playerbots", "Bot {} is on a transport", bot->GetName()); if (bot->GetTransport()) bot->GetTransport()->RemovePassenger(bot, true); From 5d64cd04dcbb78c96bdf062c420e5ab1ec3a7dd9 Mon Sep 17 00:00:00 2001 From: Revision Date: Sun, 28 Jul 2024 04:00:51 +0200 Subject: [PATCH 43/61] Fix bots looting quest objects --- src/LootObjectStack.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/LootObjectStack.cpp b/src/LootObjectStack.cpp index acda2e2f..5b792865 100644 --- a/src/LootObjectStack.cpp +++ b/src/LootObjectStack.cpp @@ -96,7 +96,7 @@ void LootObject::Refresh(Player* bot, ObjectGuid lootGUID) if (IsNeededForQuest(bot, itemId)) { - this->guid = guid; + this->guid = lootGUID; return; } isQuestItemOnly |= itemId > 0; From 318dbb9975f5c522a4b6fc0c1322f5df3d40c41c Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Sun, 28 Jul 2024 10:43:20 +0800 Subject: [PATCH 44/61] [Command] Command filter for multiple players --- src/PlayerbotAI.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/PlayerbotAI.cpp b/src/PlayerbotAI.cpp index 6a4c7b3f..fa59ff11 100644 --- a/src/PlayerbotAI.cpp +++ b/src/PlayerbotAI.cpp @@ -350,7 +350,7 @@ void PlayerbotAI::UpdateAIInternal([[maybe_unused]] uint32 elapsed, bool minimal std::string const command = holder.GetCommand(); Player* owner = holder.GetOwner(); - if (owner == master && !helper.ParseChatCommand(command, owner) && holder.GetType() == CHAT_MSG_WHISPER) + if (!helper.ParseChatCommand(command, owner) && holder.GetType() == CHAT_MSG_WHISPER) { // To prevent spam caused by WIM if (!(command.rfind("WIM", 0) == 0) && @@ -625,10 +625,15 @@ void PlayerbotAI::HandleCommand(uint32 type, std::string const text, Player* fro return; } - if (!IsAllowedCommand(filtered) && !GetSecurity()->CheckLevelFor(PLAYERBOT_SECURITY_ALLOW_ALL, type != CHAT_MSG_WHISPER, fromPlayer)) + if (!IsAllowedCommand(filtered) && + (master != fromPlayer || !GetSecurity()->CheckLevelFor(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 (!IsAllowedCommand(filtered) && master != fromPlayer) + return; + + if (type == CHAT_MSG_RAID_WARNING && filtered.find(bot->GetName()) != std::string::npos && + filtered.find("award") == std::string::npos) { ChatCommandHolder cmd("warning", fromPlayer, type); chatCommands.push(cmd); From fd74ae8af782aab0086a485cb7883b62b766ae82 Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Sun, 28 Jul 2024 11:02:16 +0800 Subject: [PATCH 45/61] [Command] Fix revive condition for summon --- src/strategy/actions/UseMeetingStoneAction.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/strategy/actions/UseMeetingStoneAction.cpp b/src/strategy/actions/UseMeetingStoneAction.cpp index 2bc87266..5380d6f9 100644 --- a/src/strategy/actions/UseMeetingStoneAction.cpp +++ b/src/strategy/actions/UseMeetingStoneAction.cpp @@ -206,7 +206,7 @@ bool SummonAction::Teleport(Player* summoner, Player* player) return false; } - bool revive = sPlayerbotAIConfig->reviveBotWhenSummoned == 2 || (sPlayerbotAIConfig->reviveBotWhenSummoned == 1 && !master->IsInCombat()); + bool revive = sPlayerbotAIConfig->reviveBotWhenSummoned == 2 || (sPlayerbotAIConfig->reviveBotWhenSummoned == 1 && !master->IsInCombat() && master->IsAlive()); if (bot->isDead() && revive) { bot->ResurrectPlayer(1.0f, false); From b75dcb67ff04eb34e45c6f4797815d6365f74e05 Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Sun, 28 Jul 2024 11:05:21 +0800 Subject: [PATCH 46/61] [CI] Fix bad CI --- .github/workflows/core_build.yml | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/.github/workflows/core_build.yml b/.github/workflows/core_build.yml index 45de9b47..4711f923 100644 --- a/.github/workflows/core_build.yml +++ b/.github/workflows/core_build.yml @@ -62,32 +62,12 @@ jobs: - name: Install Requirements run: sudo apt-get update && sudo apt-get install ccache git cmake make gcc g++ clang libmysqlclient-dev libssl-dev libbz2-dev libreadline-dev libncurses-dev mysql-server libboost-all-dev - - name: setup ccache - shell: bash - env: - CCACHE_DIR: $GITHUB_WORKSPACE/var/ccache - run: | - cat <> $GITHUB_ENV - CCACHE_DIR=${{ env.CCACHE_DIR }} - CCACHE_MAXSIZE=1000MB - CCACHE_SLOPPINESS=pch_defines,time_macros,include_file_mtime - CCACHE_CPP2=true - CCACHE_COMPRESS=1 - CCACHE_COMPRESSLEVEL=9 - CCACHE_COMPILERCHECK=content - CCACHE_LOGFILE=$CCACHE_DIR/cache.debug - CC=${{ inputs.CC }} - CXX=${{ inputs.CXX }} - EOF - - name: Configure CMake run: > cmake -B ${{ steps.strings.outputs.build-output-dir }} -DCMAKE_CXX_COMPILER=${{ matrix.cpp_compiler }} -DCMAKE_C_COMPILER=${{ matrix.c_compiler }} -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} - -DCMAKE_CXX_COMPILER_LAUNCHER="ccache" - -DCMAKE_C_COMPILER_LAUNCHER="ccache" -S ${{ github.workspace }} - name: Build From eec4776672c7b59a747f65a0b3ecc3a257111bf9 Mon Sep 17 00:00:00 2001 From: Atidot3 Date: Sun, 28 Jul 2024 10:47:33 +0200 Subject: [PATCH 47/61] removed action error log --- src/strategy/Engine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/strategy/Engine.cpp b/src/strategy/Engine.cpp index dbb35c74..c4ca7394 100644 --- a/src/strategy/Engine.cpp +++ b/src/strategy/Engine.cpp @@ -172,7 +172,7 @@ bool Engine::DoNextAction(Unit* unit, uint32 depth, bool minimal) if (!action) { - LOG_ERROR("playerbots", "Action: {} - is UNKNOWN - c:{} l:{}", actionNode->getName().c_str(), botAI->GetBot()->getClass(), botAI->GetBot()->GetLevel()); + //LOG_ERROR("playerbots", "Action: {} - is UNKNOWN - c:{} l:{}", actionNode->getName().c_str(), botAI->GetBot()->getClass(), botAI->GetBot()->GetLevel()); LogAction("A:%s - UNKNOWN", actionNode->getName().c_str()); } else if (action->isUseful()) From 029ca52dd51caeb4d7b07a27de69b72bdf70c84d Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Sun, 28 Jul 2024 15:14:08 +0800 Subject: [PATCH 48/61] teleport for randomize first --- src/RandomPlayerbotMgr.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/RandomPlayerbotMgr.cpp b/src/RandomPlayerbotMgr.cpp index 639acd52..1a424d5e 100644 --- a/src/RandomPlayerbotMgr.cpp +++ b/src/RandomPlayerbotMgr.cpp @@ -1501,7 +1501,6 @@ void RandomPlayerbotMgr::Randomize(Player* bot) else { RandomizeFirst(bot); } - RandomTeleportForLevel(bot); } void RandomPlayerbotMgr::IncreaseLevel(Player* bot) @@ -1590,6 +1589,8 @@ void RandomPlayerbotMgr::RandomizeFirst(Player* bot) if (pmo) pmo->finish(); + + RandomTeleportForLevel(bot); } void RandomPlayerbotMgr::RandomizeMin(Player* bot) From 8a8a72c97712ea000e15bc610b5b4e15345e83a5 Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Sun, 28 Jul 2024 15:14:54 +0800 Subject: [PATCH 49/61] [Initialization] Fix unique gem --- src/PlayerbotFactory.cpp | 65 +++++++++++++++++++++++++++++----------- 1 file changed, 47 insertions(+), 18 deletions(-) diff --git a/src/PlayerbotFactory.cpp b/src/PlayerbotFactory.cpp index 21409f18..e6ee1c34 100644 --- a/src/PlayerbotFactory.cpp +++ b/src/PlayerbotFactory.cpp @@ -136,6 +136,9 @@ void PlayerbotFactory::Init() continue; } ItemTemplate const* proto = sObjectMgr->GetItemTemplate(gemId); + if (proto->Flags & ITEM_FLAG_UNIQUE_EQUIPPABLE) { // unique gem + continue; + } if (!proto || !sGemPropertiesStore.LookupEntry(proto->GemProperties)) { continue; } @@ -2858,7 +2861,29 @@ void PlayerbotFactory::InitGlyphs(bool increment) if (!increment) { for (uint32 slotIndex = 0; slotIndex < MAX_GLYPH_SLOT_INDEX; ++slotIndex) { - bot->SetGlyph(slotIndex, 0, true); + uint32 glyph = bot->GetGlyph(slotIndex); + if (GlyphPropertiesEntry const* glyphEntry = sGlyphPropertiesStore.LookupEntry(glyph)) + { + bot->RemoveAurasDueToSpell(glyphEntry->SpellId); + + // Removed any triggered auras + Unit::AuraMap& ownedAuras = bot->GetOwnedAuras(); + for (Unit::AuraMap::iterator iter = ownedAuras.begin(); iter != ownedAuras.end();) + { + Aura* aura = iter->second; + if (SpellInfo const* triggeredByAuraSpellInfo = aura->GetTriggeredByAuraSpellInfo()) + { + if (triggeredByAuraSpellInfo->Id == glyphEntry->SpellId) + { + bot->RemoveOwnedAura(iter); + continue; + } + } + ++iter; + } + + bot->SetGlyph(slotIndex, 0, true); + } } } @@ -2957,6 +2982,8 @@ void PlayerbotFactory::InitGlyphs(bool increment) if (!glyph) { continue; } + GlyphPropertiesEntry const* glyphEntry = sGlyphPropertiesStore.LookupEntry(glyph); + bot->CastSpell(bot, glyphEntry->SpellId, TriggerCastFlags(TRIGGERED_FULL_MASK & ~(TRIGGERED_IGNORE_SHAPESHIFT | TRIGGERED_IGNORE_CASTER_AURASTATE))); bot->SetGlyph(realSlot, glyph, true); chosen.insert(glyph); } else { @@ -2990,7 +3017,9 @@ void PlayerbotFactory::InitGlyphs(bool increment) continue; chosen.insert(id); - + GlyphPropertiesEntry const* glyphEntry = sGlyphPropertiesStore.LookupEntry(id); + bot->CastSpell(bot, glyphEntry->SpellId, TriggerCastFlags(TRIGGERED_FULL_MASK & ~(TRIGGERED_IGNORE_SHAPESHIFT | TRIGGERED_IGNORE_CASTER_AURASTATE))); + bot->SetGlyph(realSlot, id, true); found = true; break; @@ -3847,7 +3876,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 + crit * 2 + haste * 2 + intellect; + score += agility * 2.5 + attack_power + armor_penetration * 2 + rangeDps * 5 + hit * 1.2 + crit * 2 + haste * 2 + intellect; } else if (cls == CLASS_WARLOCK || cls == CLASS_MAGE || (cls == CLASS_PRIEST && tab == 2) || // shadow @@ -3856,7 +3885,7 @@ float PlayerbotFactory::CalculateItemScore(uint32 item_id, Player* bot) ) { // SPELL DPS score += intellect * 0.5 + spirit * 0.5 + spell_power + spell_penetration - + hit * 1 + crit * 0.7 + haste * 1 + rangeDps; + + hit * 0.7 + 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 @@ -3866,33 +3895,33 @@ 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 * 1.5 + crit * 1.5 + haste * 1.5 + expertise * 2.5; + score += agility * 2 + strength + attack_power + armor_penetration * 1 + meleeDps * 5 + hit * 1 + crit * 1.5 + haste * 1.5 + expertise * 1.5; } else if ((cls == CLASS_PALADIN && tab == 2) || // retribution (cls == CLASS_WARRIOR && tab != 2) || // arm / fury (cls == CLASS_DEATH_KNIGHT && tab != 0) // ice / unholy ) { // STRENGTH mainly (AGILITY also) - score += strength * 2 + agility + attack_power + armor_penetration + meleeDps * 5 + hit * 1.5 + crit * 1.5 + haste * 1.5 + expertise * 2; + score += strength * 2 + agility + attack_power + armor_penetration + meleeDps * 5 + hit * 1 + crit * 1.5 + haste * 1.5 + expertise * 1.5; } 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 * 1.5 + crit * 1.5 + haste * 1.5 + expertise * 2; + + hit * 1 + crit * 1.5 + haste * 1.5 + expertise * 1.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 * 0.5 + crit * 0.2 + haste * 0.5 + expertise * 3; + + hit * 0.5 + crit * 0.2 + haste * 0.5 + expertise * 2; } 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 * 0.5 + crit * 0.5 + haste * 0.5 + expertise * 3.5; + + hit * 0.5 + crit * 0.5 + haste * 0.5 + expertise * 2; } else { // 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; + + hit * 1 + crit * 1 + haste * 0.5 + expertise * 2; } // penalty for different type armor if (proto->Class == ITEM_CLASS_ARMOR && proto->SubClass >= ITEM_SUBCLASS_ARMOR_CLOTH && @@ -4269,7 +4298,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 + crit * 2 + haste * 2.5 + intellect; + score += agility * 2.5 + attack_power + armor_penetration * 2 + dps * 5 + hit * 1.5 + crit * 2 + haste * 2.5 + intellect; } else if (cls == CLASS_WARLOCK || cls == CLASS_MAGE || (cls == CLASS_PRIEST && tab == 2) || // shadow @@ -4288,17 +4317,17 @@ 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 * 1.5 + crit * 1.5 + haste * 1.5 + expertise * 2.5; + score += agility * 2 + strength + attack_power + armor_penetration * 1 + dps * 5 + hit * 1.2 + 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 ) { // STRENGTH mainly (AGILITY also) - score += strength * 2 + agility + attack_power + armor_penetration + dps * 5 + hit * 1.5 + crit * 1.5 + haste * 1.5 + expertise * 2; + score += strength * 2 + agility + attack_power + armor_penetration + dps * 5 + hit * 1.2 + crit * 1.5 + haste * 1.5 + expertise * 2; } 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 * 1.5 + crit * 1.5 + haste * 1.5 + expertise * 2; + + hit * 1.2 + crit * 1.5 + haste * 1.5 + expertise * 2; } else if ((cls == CLASS_WARRIOR && tab == 2) || (cls == CLASS_PALADIN && tab == 1)) { // TANK WITH SHIELD @@ -4549,7 +4578,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 + crit * 2 + haste * 2.5 + intellect; + score += agility * 2.5 + attack_power + armor_penetration * 2 + rangeDps * 5 + hit * 1.5 + crit * 2 + haste * 2.5 + intellect; } else if (cls == CLASS_WARLOCK || cls == CLASS_MAGE || (cls == CLASS_PRIEST && tab == 2) || // shadow @@ -4568,17 +4597,17 @@ 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 * 1.5 + crit * 1.5 + haste * 1.5 + expertise * 2.5; + score += agility * 2 + strength + attack_power + armor_penetration * 1 + meleeDps * 5 + hit * 1.2 + 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 ) { // STRENGTH mainly (AGILITY also) - score += strength * 2 + agility + attack_power + armor_penetration + meleeDps * 5 + hit * 1.5 + crit * 1.5 + haste * 1.5 + expertise * 2; + score += strength * 2 + agility + attack_power + armor_penetration + meleeDps * 5 + hit * 1.2 + crit * 1.5 + haste * 1.5 + expertise * 2; } 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 * 1.5 + crit * 1.5 + haste * 1.5 + expertise * 2; + + hit * 1.2 + crit * 1.5 + haste * 1.5 + expertise * 2; } else if ((cls == CLASS_WARRIOR && tab == 2) || (cls == CLASS_PALADIN && tab == 1)) { // TANK WITH SHIELD From 7c1aff09eb52ba12acac0c15c9edde2f73e71edd Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Sun, 28 Jul 2024 15:15:03 +0800 Subject: [PATCH 50/61] [Initialization] Ammo init --- src/RandomItemMgr.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/RandomItemMgr.cpp b/src/RandomItemMgr.cpp index c3b01ef5..1e1a18ab 100644 --- a/src/RandomItemMgr.cpp +++ b/src/RandomItemMgr.cpp @@ -2211,8 +2211,8 @@ void RandomItemMgr::BuildAmmoCache() { for (uint32 subClass = ITEM_SUBCLASS_ARROW; subClass <= ITEM_SUBCLASS_BULLET; subClass++) { - QueryResult results = WorldDatabase.Query("SELECT entry, Flags FROM item_template WHERE class = {} AND subclass = {} AND RequiredLevel <= {} AND stackable = 1000 " - "ORDER BY RequiredLevel DESC", ITEM_CLASS_PROJECTILE, subClass, level); + QueryResult results = WorldDatabase.Query("SELECT entry, Flags FROM item_template WHERE class = {} AND subclass = {} AND RequiredLevel <= {} " + "ORDER BY stackable DESC, RequiredLevel DESC", ITEM_CLASS_PROJECTILE, subClass, level); if (!results) continue; do { From f32ca5472a4a8ab538c09dc2ae10e5390aef72d0 Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Sun, 28 Jul 2024 15:15:33 +0800 Subject: [PATCH 51/61] Unholy Deathknight --- src/strategy/deathknight/UnholyDKStrategy.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/strategy/deathknight/UnholyDKStrategy.cpp b/src/strategy/deathknight/UnholyDKStrategy.cpp index 5bc5f500..8edab828 100644 --- a/src/strategy/deathknight/UnholyDKStrategy.cpp +++ b/src/strategy/deathknight/UnholyDKStrategy.cpp @@ -72,12 +72,12 @@ UnholyDKStrategy::UnholyDKStrategy(PlayerbotAI* botAI) : GenericDKStrategy(botAI NextAction** UnholyDKStrategy::getDefaultActions() { return NextAction::array(0, - new NextAction("death and decay", ACTION_DEFAULT + 1.0f), - new NextAction("scourge strike", ACTION_DEFAULT + 0.8f), - new NextAction("horn of winter", ACTION_DEFAULT + 0.6f), - new NextAction("summon gargoyle", ACTION_DEFAULT + 0.4f), + new NextAction("death and decay", ACTION_DEFAULT + 0.5f), + new NextAction("horn of winter", ACTION_DEFAULT + 0.4f), + new NextAction("summon gargoyle", ACTION_DEFAULT + 0.3f), new NextAction("death coil", ACTION_DEFAULT + 0.2f), - new NextAction("melee", ACTION_DEFAULT), + new NextAction("scourge strike", ACTION_NORMAL + 0.1f), + new NextAction("melee", ACTION_DEFAULT), nullptr); } @@ -91,8 +91,8 @@ void UnholyDKStrategy::InitTriggers(std::vector& triggers) triggers.push_back(new TriggerNode("no desolation", NextAction::array(0, new NextAction("blood strike", ACTION_HIGH + 4), nullptr))); triggers.push_back(new TriggerNode("death and decay cooldown", NextAction::array(0, - new NextAction("ghoul frenzy", ACTION_DEFAULT + 5.0f), - new NextAction("scourge strike", ACTION_DEFAULT + 4.0f), + new NextAction("ghoul frenzy", ACTION_NORMAL + 5.0f), + new NextAction("scourge strike", ACTION_NORMAL + 4.0f), new NextAction("blood boil", ACTION_NORMAL + 3.0f), new NextAction("icy touch", ACTION_NORMAL + 2.0f), new NextAction("plague strike", ACTION_NORMAL + 1.0f), From 39d93e6a2f23fae933f0247fb1a6258d63f72b4d Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Sun, 28 Jul 2024 15:16:11 +0800 Subject: [PATCH 52/61] Account creation info message --- src/RandomPlayerbotFactory.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/RandomPlayerbotFactory.cpp b/src/RandomPlayerbotFactory.cpp index e1fec407..b1dfae8b 100644 --- a/src/RandomPlayerbotFactory.cpp +++ b/src/RandomPlayerbotFactory.cpp @@ -375,7 +375,7 @@ void RandomPlayerbotFactory::CreateRandomBots() LOG_INFO("playerbots", "Creating random bot accounts..."); std::vector> account_creations; - bool account_creation = false; + int account_creation = 0; for (uint32 accountNumber = 0; accountNumber < sPlayerbotAIConfig->randomBotAccountCount; ++accountNumber) { std::ostringstream out; @@ -389,7 +389,7 @@ void RandomPlayerbotFactory::CreateRandomBots() { continue; } - account_creation = true; + account_creation++; std::string password = ""; if (sPlayerbotAIConfig->randomBotRandomPassword) { @@ -408,6 +408,7 @@ void RandomPlayerbotFactory::CreateRandomBots() if (account_creation) { /* wait for async accounts create to make character create correctly, same as account delete */ + LOG_INFO("playerbots", "Waiting for {} accounts loading into database...", account_creation); std::this_thread::sleep_for(10ms * sPlayerbotAIConfig->randomBotAccountCount); } @@ -418,7 +419,7 @@ void RandomPlayerbotFactory::CreateRandomBots() std::unordered_map> names; std::vector> playerBots; std::vector sessionBots; - bool bot_creation = false; + int bot_creation = 0; for (uint32 accountNumber = 0; accountNumber < sPlayerbotAIConfig->randomBotAccountCount; ++accountNumber) { std::ostringstream out; @@ -441,7 +442,6 @@ void RandomPlayerbotFactory::CreateRandomBots() { continue; } - bot_creation = true; LOG_INFO("playerbots", "Creating random bot characters for account: [{}/{}]", accountNumber + 1, sPlayerbotAIConfig->randomBotAccountCount); RandomPlayerbotFactory factory(accountId); @@ -462,19 +462,23 @@ void RandomPlayerbotFactory::CreateRandomBots() continue; } - if (cls != 10) + if (cls != 10) { if (Player* playerBot = factory.CreateRandomBot(session, cls, names)) { playerBot->SaveToDB(true, false); sCharacterCache->AddCharacterCacheEntry(playerBot->GetGUID(), accountId, playerBot->GetName(), playerBot->getGender(), playerBot->getRace(), playerBot->getClass(), playerBot->GetLevel()); playerBot->CleanupsBeforeDelete(); delete playerBot; + bot_creation++; + } else { + LOG_ERROR("playerbots", "Fail to create character for account {}", accountId); } + } } } if (bot_creation) { - LOG_INFO("playerbots", "Waiting for {} characters loading into database...", totalCharCount); + LOG_INFO("playerbots", "Waiting for {} characters loading into database...", bot_creation); /* wait for characters load into database, or characters will fail to loggin */ std::this_thread::sleep_for(10s); } From 6b7b270b2667661b656e96ef70e93f05785a0ef5 Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Sun, 28 Jul 2024 15:16:32 +0800 Subject: [PATCH 53/61] Remove can not enter message --- src/strategy/actions/UseMeetingStoneAction.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/strategy/actions/UseMeetingStoneAction.cpp b/src/strategy/actions/UseMeetingStoneAction.cpp index 5380d6f9..3ef3b0b1 100644 --- a/src/strategy/actions/UseMeetingStoneAction.cpp +++ b/src/strategy/actions/UseMeetingStoneAction.cpp @@ -164,15 +164,15 @@ bool SummonAction::SummonUsingNpcs(Player* summoner, Player* player) bool SummonAction::Teleport(Player* summoner, Player* player) { Player* master = GetMaster(); - if (master->GetMap() && master->GetMap()->IsDungeon()) { - InstanceMap* map = master->GetMap()->ToInstanceMap(); - if (map) { - if (map->CannotEnter(player) == Map::CANNOT_ENTER_MAX_PLAYERS) { - botAI->TellError("I can not enter this dungeon"); - return false; - } - } - } + // if (master->GetMap() && master->GetMap()->IsDungeon()) { + // InstanceMap* map = master->GetMap()->ToInstanceMap(); + // if (map) { + // if (map->CannotEnter(player, true) == Map::CANNOT_ENTER_MAX_PLAYERS) { + // botAI->TellError("I can not enter this dungeon"); + // return false; + // } + // } + // } if (!summoner->IsBeingTeleported() && !player->IsBeingTeleported()) { float followAngle = GetFollowAngle(); From 90aa76e3c341dc4db653446fbb92e464a5e23762 Mon Sep 17 00:00:00 2001 From: Atidot3 Date: Sun, 28 Jul 2024 13:50:50 +0200 Subject: [PATCH 54/61] Polish bot chatting --- src/strategy/actions/SuggestWhatToDoAction.cpp | 9 +++++---- src/strategy/generic/EmoteStrategy.cpp | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/strategy/actions/SuggestWhatToDoAction.cpp b/src/strategy/actions/SuggestWhatToDoAction.cpp index dc9241f8..6ebf6802 100644 --- a/src/strategy/actions/SuggestWhatToDoAction.cpp +++ b/src/strategy/actions/SuggestWhatToDoAction.cpp @@ -93,7 +93,7 @@ void SuggestWhatToDoAction::specificQuest() placeholders["%role"] = chat->FormatClass(bot, AiFactory::GetPlayerSpecTab(bot)); placeholders["%quest"] = chat->FormatQuest(quest); - spam(BOT_TEXT2("suggest_quest", placeholders), urand(0, 1) ? eTalkType::General : 0, urand(0, 2), urand(0, 2)); + spam(BOT_TEXT2("suggest_quest", placeholders), urand(0, 1) ? eTalkType::General : eTalkType::LookingForGroup, urand(0, 2), urand(0, 2)); } void SuggestWhatToDoAction::grindMaterials() @@ -225,7 +225,7 @@ void SuggestWhatToDoAction::something() out << entry->area_name[_dbc_locale]; placeholders["%zone"] = out.str(); - spam(BOT_TEXT2("suggest_something", placeholders), urand(0, 1) ? eTalkType::General : 0, urand(0, 2), urand(0, 2)); + spam(BOT_TEXT2("suggest_something", placeholders), eTalkType::General, !urand(0, 2), !urand(0, 3)); } void SuggestWhatToDoAction::spam(std::string msg, uint8 flags, bool worldChat, bool guild) @@ -413,7 +413,7 @@ bool SuggestDungeonAction::Execute(Event event) itemout << allowedInstances[urand(0, allowedInstances.size() - 1)]; placeholders["%instance"] = itemout.str(); - spam(BOT_TEXT2("suggest_instance", placeholders), urand(0, 1) ? eTalkType::LookingForGroup : 0, urand(0, 2), urand(0, 2)); + spam(BOT_TEXT2("suggest_instance", placeholders), urand(0, 1) ? eTalkType::LookingForGroup : eTalkType::General, urand(0, 2), urand(0, 2)); return true; } @@ -480,6 +480,7 @@ bool SuggestTradeAction::Execute(Event event) placeholders["%item"] = chat->FormatItem(proto, count); placeholders["%gold"] = chat->formatMoney(price); - spam(BOT_TEXT2("suggest_sell", placeholders), urand(0, 1) ? eTalkType::Trade : 0, urand(0, 1), urand(0, 5)); + + spam(BOT_TEXT2("suggest_sell", placeholders), urand(0, 1) ? eTalkType::Trade : eTalkType::General, !urand(0, 2), urand(0, 5)); return true; } diff --git a/src/strategy/generic/EmoteStrategy.cpp b/src/strategy/generic/EmoteStrategy.cpp index 002fdc41..6f8a35d9 100644 --- a/src/strategy/generic/EmoteStrategy.cpp +++ b/src/strategy/generic/EmoteStrategy.cpp @@ -9,7 +9,7 @@ void EmoteStrategy::InitTriggers(std::vector& triggers) { if (sPlayerbotAIConfig->randomBotEmote) { - triggers.push_back(new TriggerNode("seldom", NextAction::array(0, new NextAction("emote", 1.0f), nullptr))); + triggers.push_back(new TriggerNode("seldom", NextAction::array(0, new NextAction("emote", 10.0f), nullptr))); triggers.push_back(new TriggerNode("receive text emote", NextAction::array(0, new NextAction("emote", 10.0f), nullptr))); triggers.push_back(new TriggerNode("receive emote", NextAction::array(0, new NextAction("emote", 10.0f), nullptr))); } From f6056e0ec6b8b7407834f0f1bf7846e4cfbe2f40 Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Mon, 29 Jul 2024 00:12:18 +0800 Subject: [PATCH 55/61] [Initialization] Mount for nightelf (remove Swift Zulian Tiger) --- src/PlayerbotFactory.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PlayerbotFactory.cpp b/src/PlayerbotFactory.cpp index e6ee1c34..d66b8d3c 100644 --- a/src/PlayerbotFactory.cpp +++ b/src/PlayerbotFactory.cpp @@ -2574,7 +2574,7 @@ void PlayerbotFactory::InitMounts() break; case RACE_NIGHTELF: slow = { 10789, 8394, 10793 }; - fast = { 24252, 63637, 22723 }; + fast = { 23219, 23220, 63637 }; break; case RACE_UNDEAD_PLAYER: slow = { 17463, 17464, 17462 }; From 64c62b4ddb4470e03576a2a0e61b8d0bf5509787 Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Mon, 29 Jul 2024 00:27:32 +0800 Subject: [PATCH 56/61] Revert stats weight calculation --- src/PlayerbotFactory.cpp | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/PlayerbotFactory.cpp b/src/PlayerbotFactory.cpp index d66b8d3c..e8360991 100644 --- a/src/PlayerbotFactory.cpp +++ b/src/PlayerbotFactory.cpp @@ -3876,7 +3876,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 * 1.2 + crit * 2 + haste * 2 + 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 @@ -3885,7 +3885,7 @@ float PlayerbotFactory::CalculateItemScore(uint32 item_id, Player* bot) ) { // SPELL DPS score += intellect * 0.5 + spirit * 0.5 + spell_power + spell_penetration - + hit * 0.7 + 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 @@ -3895,33 +3895,33 @@ 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 * 1 + crit * 1.5 + haste * 1.5 + expertise * 1.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 ) { // STRENGTH mainly (AGILITY also) - score += strength * 2 + agility + attack_power + armor_penetration + meleeDps * 5 + hit * 1 + crit * 1.5 + haste * 1.5 + expertise * 1.5; + score += strength * 2 + agility + attack_power + armor_penetration + meleeDps * 5 + hit * 1.5 + crit * 1.5 + haste * 1.5 + expertise * 2; } 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 * 1 + crit * 1.5 + haste * 1.5 + expertise * 1.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 * 0.5 + crit * 0.2 + haste * 0.5 + expertise * 2; + + 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 * 0.5 + crit * 0.5 + haste * 0.5 + expertise * 2; + + hit * 0.5 + crit * 0.5 + haste * 0.5 + expertise * 3.5; } else { // 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 * 2; + + hit * 1 + crit * 1 + haste * 0.5 + expertise * 3; } // penalty for different type armor if (proto->Class == ITEM_CLASS_ARMOR && proto->SubClass >= ITEM_SUBCLASS_ARMOR_CLOTH && @@ -4298,7 +4298,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 * 1.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 @@ -4317,17 +4317,17 @@ 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 * 1.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 ) { // STRENGTH mainly (AGILITY also) - score += strength * 2 + agility + attack_power + armor_penetration + dps * 5 + hit * 1.2 + crit * 1.5 + haste * 1.5 + expertise * 2; + score += strength * 2 + agility + attack_power + armor_penetration + dps * 5 + hit * 1.5 + crit * 1.5 + haste * 1.5 + expertise * 2; } 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 * 1.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 @@ -4578,7 +4578,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 * 1.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 @@ -4597,17 +4597,17 @@ 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 * 1.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 ) { // STRENGTH mainly (AGILITY also) - score += strength * 2 + agility + attack_power + armor_penetration + meleeDps * 5 + hit * 1.2 + crit * 1.5 + haste * 1.5 + expertise * 2; + score += strength * 2 + agility + attack_power + armor_penetration + meleeDps * 5 + hit * 1.5 + crit * 1.5 + haste * 1.5 + expertise * 2; } 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 * 1.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 From 06a63aa730ca63f391c94f2e8b58564d167af146 Mon Sep 17 00:00:00 2001 From: Atidot3 Date: Sun, 28 Jul 2024 18:42:51 +0200 Subject: [PATCH 57/61] fix current_zone_name incorrect values + refactoring guild broadcast simplier + refactoring randomTalk to actually use area / zone general etc --- src/PlayerbotMgr.cpp | 2 +- src/strategy/actions/AutoLearnSpellAction.cpp | 9 ++-- src/strategy/actions/LootAction.cpp | 9 ++-- .../actions/SuggestWhatToDoAction.cpp | 41 ++++++++++--------- src/strategy/actions/XpGainAction.cpp | 9 ++-- src/strategy/generic/EmoteStrategy.cpp | 13 +++--- 6 files changed, 43 insertions(+), 40 deletions(-) diff --git a/src/PlayerbotMgr.cpp b/src/PlayerbotMgr.cpp index f2fab8c4..1774b93e 100644 --- a/src/PlayerbotMgr.cpp +++ b/src/PlayerbotMgr.cpp @@ -526,7 +526,7 @@ void PlayerbotHolder::OnBotLogin(Player* const bot) // join standard channels AreaTableEntry const* current_zone = sAreaTableStore.LookupEntry(bot->GetAreaId()); ChannelMgr* cMgr = ChannelMgr::forTeam(bot->GetTeamId()); - std::string current_zone_name = current_zone ? current_zone->area_name[0] : ""; + std::string current_zone_name = current_zone ? current_zone->area_name[sWorld->GetDefaultDbcLocale()] : ""; if (current_zone && cMgr) { diff --git a/src/strategy/actions/AutoLearnSpellAction.cpp b/src/strategy/actions/AutoLearnSpellAction.cpp index f2d7688f..4ef4f1e8 100644 --- a/src/strategy/actions/AutoLearnSpellAction.cpp +++ b/src/strategy/actions/AutoLearnSpellAction.cpp @@ -41,13 +41,14 @@ void AutoLearnSpellAction::LearnSpells(std::ostringstream* out) Guild* guild = sGuildMgr->GetGuildById(bot->GetGuildId()); if (guild) { - std::map placeholders; - placeholders["%level"] = std::to_string(bot->GetLevel()); + std::string toSay = ""; if (urand(0, 3)) - guild->BroadcastToGuild(bot->GetSession(), false, BOT_TEXT2("Ding!", placeholders), LANG_UNIVERSAL); + toSay = "Ding !"; else - guild->BroadcastToGuild(bot->GetSession(), false, BOT_TEXT2("Yay level %level!", placeholders), LANG_UNIVERSAL); + toSay = "Yay level " + std::to_string(bot->GetLevel()) + " !"; + + guild->BroadcastToGuild(bot->GetSession(), false, toSay, LANG_UNIVERSAL); } } } diff --git a/src/strategy/actions/LootAction.cpp b/src/strategy/actions/LootAction.cpp index 595ff16f..ff383ef7 100644 --- a/src/strategy/actions/LootAction.cpp +++ b/src/strategy/actions/LootAction.cpp @@ -423,13 +423,14 @@ bool StoreLootAction::Execute(Event event) if (guild) { - std::map placeholders; - placeholders["%name"] = chat->FormatItem(proto); + std::string toSay = ""; if (urand(0, 3)) - guild->BroadcastToGuild(bot->GetSession(), false, BOT_TEXT2("Yay I looted %name!", placeholders), LANG_UNIVERSAL); + toSay = "Yay I looted " + chat->FormatItem(proto) + " !"; else - guild->BroadcastToGuild(bot->GetSession(), false, BOT_TEXT2("Guess who got a %name? Me!", placeholders), LANG_UNIVERSAL); + toSay = "Guess who got a " + chat->FormatItem(proto) + " ? Me !"; + + guild->BroadcastToGuild(bot->GetSession(), false, toSay, LANG_UNIVERSAL); } } diff --git a/src/strategy/actions/SuggestWhatToDoAction.cpp b/src/strategy/actions/SuggestWhatToDoAction.cpp index 6ebf6802..e9006fc6 100644 --- a/src/strategy/actions/SuggestWhatToDoAction.cpp +++ b/src/strategy/actions/SuggestWhatToDoAction.cpp @@ -18,11 +18,11 @@ enum eTalkType { - General = ChannelFlags::CHANNEL_FLAG_GENERAL | ChannelFlags::CHANNEL_FLAG_NOT_LFG, - Trade = ChannelFlags::CHANNEL_FLAG_CITY | ChannelFlags::CHANNEL_FLAG_GENERAL | ChannelFlags::CHANNEL_FLAG_NOT_LFG | ChannelFlags::CHANNEL_FLAG_TRADE, - LocalDefence = ChannelFlags::CHANNEL_FLAG_GENERAL | ChannelFlags::CHANNEL_FLAG_NOT_LFG, - GuildRecruitment = ChannelFlags::CHANNEL_FLAG_CITY | ChannelFlags::CHANNEL_FLAG_GENERAL | ChannelFlags::CHANNEL_FLAG_NOT_LFG, - LookingForGroup = ChannelFlags::CHANNEL_FLAG_LFG | ChannelFlags::CHANNEL_FLAG_GENERAL + /*0x18*/ General = ChannelFlags::CHANNEL_FLAG_GENERAL | ChannelFlags::CHANNEL_FLAG_NOT_LFG, + /*0x3C*/ Trade = ChannelFlags::CHANNEL_FLAG_CITY | ChannelFlags::CHANNEL_FLAG_GENERAL | ChannelFlags::CHANNEL_FLAG_NOT_LFG | ChannelFlags::CHANNEL_FLAG_TRADE, + /*0x18*/ LocalDefence = ChannelFlags::CHANNEL_FLAG_GENERAL | ChannelFlags::CHANNEL_FLAG_NOT_LFG, + /*x038*/ GuildRecruitment = ChannelFlags::CHANNEL_FLAG_CITY | ChannelFlags::CHANNEL_FLAG_GENERAL | ChannelFlags::CHANNEL_FLAG_NOT_LFG, + /*0x50*/ LookingForGroup = ChannelFlags::CHANNEL_FLAG_LFG | ChannelFlags::CHANNEL_FLAG_GENERAL }; std::map SuggestDungeonAction::instances; @@ -93,7 +93,7 @@ void SuggestWhatToDoAction::specificQuest() placeholders["%role"] = chat->FormatClass(bot, AiFactory::GetPlayerSpecTab(bot)); placeholders["%quest"] = chat->FormatQuest(quest); - spam(BOT_TEXT2("suggest_quest", placeholders), urand(0, 1) ? eTalkType::General : eTalkType::LookingForGroup, urand(0, 2), urand(0, 2)); + spam(BOT_TEXT2("suggest_quest", placeholders), urand(0, 1) ? eTalkType::General : 0, !urand(0, 2), !urand(0, 3)); } void SuggestWhatToDoAction::grindMaterials() @@ -225,7 +225,7 @@ void SuggestWhatToDoAction::something() out << entry->area_name[_dbc_locale]; placeholders["%zone"] = out.str(); - spam(BOT_TEXT2("suggest_something", placeholders), eTalkType::General, !urand(0, 2), !urand(0, 3)); + spam(BOT_TEXT2("suggest_something", placeholders), urand(0, 1) ? eTalkType::General : 0, !urand(0, 2), !urand(0, 3)); } void SuggestWhatToDoAction::spam(std::string msg, uint8 flags, bool worldChat, bool guild) @@ -238,30 +238,34 @@ void SuggestWhatToDoAction::spam(std::string msg, uint8 flags, bool worldChat, b if (!cMgr) return; + AreaTableEntry const* zone = sAreaTableStore.LookupEntry(bot->GetMap()->GetZoneId(bot->GetPhaseMask(), bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ())); + if (!zone) return; + /*AreaTableEntry const* area = sAreaTableStore.LookupEntry(bot->GetMap()->GetAreaId(bot->GetPhaseMask(), bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ())); + if (!area) return;*/ + + std::string areaname = zone->area_name[_dbc_locale]; + for (uint32 i = 0; i < sChatChannelsStore.GetNumRows(); ++i) { ChatChannelsEntry const* channel = sChatChannelsStore.LookupEntry(i); if (!channel) continue; - AreaTableEntry const* current_zone = GetAreaEntryByAreaID(bot->GetAreaId()); - if (!current_zone) - continue; - // combine full channel name char channelName[100]; Channel* chn = nullptr; - if ((channel->flags & CHANNEL_DBC_FLAG_LFG) != 0) + if (channel->ChannelID == 24 || (channel->flags & CHANNEL_DBC_FLAG_LFG) != 0) { std::string chanName = channel->pattern[_dbc_locale]; chn = cMgr->GetChannel(chanName, bot); } else { - snprintf(channelName, 100, channel->pattern[_dbc_locale], current_zone->area_name[_dbc_locale]); + snprintf(channelName, 100, channel->pattern[_dbc_locale], areaname); chn = cMgr->GetChannel(channelName, bot); } if (!chn) continue; + // skip world chat here if (chn->GetName() == "World") continue; @@ -269,8 +273,8 @@ void SuggestWhatToDoAction::spam(std::string msg, uint8 flags, bool worldChat, b if (flags != 0 && chn->GetFlags() != flags) continue; - // skip local defense - if (chn->GetChannelId() == 22) + // skip local defense and universal defense + if (chn->GetChannelId() == 22 || chn->GetChannelId() == 23) continue; // no filter, pick several options @@ -413,7 +417,7 @@ bool SuggestDungeonAction::Execute(Event event) itemout << allowedInstances[urand(0, allowedInstances.size() - 1)]; placeholders["%instance"] = itemout.str(); - spam(BOT_TEXT2("suggest_instance", placeholders), urand(0, 1) ? eTalkType::LookingForGroup : eTalkType::General, urand(0, 2), urand(0, 2)); + spam(BOT_TEXT2("suggest_instance", placeholders), urand(0, 1) ? eTalkType::LookingForGroup : 0, !urand(0, 2), !urand(0, 3)); return true; } @@ -423,9 +427,6 @@ SuggestTradeAction::SuggestTradeAction(PlayerbotAI* botAI) : SuggestWhatToDoActi bool SuggestTradeAction::Execute(Event event) { - if (!sRandomPlayerbotMgr->IsRandomBot(bot) || bot->GetGroup() || bot->GetInstanceId()) - return false; - uint32 quality = urand(0, 100); if (quality > 95) quality = ITEM_QUALITY_LEGENDARY; @@ -481,6 +482,6 @@ bool SuggestTradeAction::Execute(Event event) placeholders["%gold"] = chat->formatMoney(price); - spam(BOT_TEXT2("suggest_sell", placeholders), urand(0, 1) ? eTalkType::Trade : eTalkType::General, !urand(0, 2), urand(0, 5)); + spam(BOT_TEXT2("suggest_sell", placeholders), urand(0, 1) ? eTalkType::Trade : 0, !urand(0, 2), urand(0, 5)); return true; } diff --git a/src/strategy/actions/XpGainAction.cpp b/src/strategy/actions/XpGainAction.cpp index 155cb752..39ff7d4f 100644 --- a/src/strategy/actions/XpGainAction.cpp +++ b/src/strategy/actions/XpGainAction.cpp @@ -41,13 +41,14 @@ bool XpGainAction::Execute(Event event) Guild* guild = sGuildMgr->GetGuildById(bot->GetGuildId()); if (guild) { - std::map placeholders; - placeholders["%name"] = creature->GetName(); + std::string toSay = ""; if (urand(0, 3)) - guild->BroadcastToGuild(bot->GetSession(), false, BOT_TEXT2("Wow I just killed %name!", placeholders), LANG_UNIVERSAL); + toSay = "Wow I just killed " + creature->GetName() + " !"; else - guild->BroadcastToGuild(bot->GetSession(), false, BOT_TEXT2("Awesome that %name went down quickly!", placeholders), LANG_UNIVERSAL); + toSay = "Awesome that " + creature->GetName() + " went down quickly !"; + + guild->BroadcastToGuild(bot->GetSession(), false, toSay, LANG_UNIVERSAL); } } } diff --git a/src/strategy/generic/EmoteStrategy.cpp b/src/strategy/generic/EmoteStrategy.cpp index 6f8a35d9..d4a053bc 100644 --- a/src/strategy/generic/EmoteStrategy.cpp +++ b/src/strategy/generic/EmoteStrategy.cpp @@ -9,21 +9,20 @@ void EmoteStrategy::InitTriggers(std::vector& triggers) { if (sPlayerbotAIConfig->randomBotEmote) { - triggers.push_back(new TriggerNode("seldom", NextAction::array(0, new NextAction("emote", 10.0f), nullptr))); + triggers.push_back(new TriggerNode("seldom", NextAction::array(0, new NextAction("emote", 1.0f), nullptr))); triggers.push_back(new TriggerNode("receive text emote", NextAction::array(0, new NextAction("emote", 10.0f), nullptr))); triggers.push_back(new TriggerNode("receive emote", NextAction::array(0, new NextAction("emote", 10.0f), nullptr))); } if (sPlayerbotAIConfig->randomBotTalk) { - triggers.push_back(new TriggerNode("often", NextAction::array(0, new NextAction("suggest what to do", 1.0f), nullptr))); - triggers.push_back(new TriggerNode("often", NextAction::array(0, new NextAction("suggest trade", 1.0f), nullptr))); - triggers.push_back(new TriggerNode("seldom", NextAction::array(0, new NextAction("talk", 1.0f), nullptr))); + triggers.push_back(new TriggerNode("often", NextAction::array(0, new NextAction("suggest what to do", 35.0f), + new NextAction("suggest dungeon", 50.0f), + new NextAction("suggest trade", 65.0f), + new NextAction("talk", 10.0f), + nullptr))); } - if (sPlayerbotAIConfig->randomBotSuggestDungeons) - triggers.push_back(new TriggerNode("often", NextAction::array(0, new NextAction("suggest dungeon", 1.0f), nullptr))); - if (sPlayerbotAIConfig->enableGreet) triggers.push_back(new TriggerNode("new player nearby", NextAction::array(0, new NextAction("greet", 1.0f), nullptr))); From 1128e0280acb6e8ac7c82e1cd97d1b8405e80f6d Mon Sep 17 00:00:00 2001 From: Atidot3 Date: Sun, 28 Jul 2024 18:44:56 +0200 Subject: [PATCH 58/61] reduce spam --- src/strategy/generic/EmoteStrategy.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/strategy/generic/EmoteStrategy.cpp b/src/strategy/generic/EmoteStrategy.cpp index d4a053bc..d3b72fa3 100644 --- a/src/strategy/generic/EmoteStrategy.cpp +++ b/src/strategy/generic/EmoteStrategy.cpp @@ -16,10 +16,10 @@ void EmoteStrategy::InitTriggers(std::vector& triggers) if (sPlayerbotAIConfig->randomBotTalk) { - triggers.push_back(new TriggerNode("often", NextAction::array(0, new NextAction("suggest what to do", 35.0f), - new NextAction("suggest dungeon", 50.0f), - new NextAction("suggest trade", 65.0f), - new NextAction("talk", 10.0f), + triggers.push_back(new TriggerNode("often", NextAction::array(0, new NextAction("suggest what to do", 10.0f), + new NextAction("suggest dungeon", 3.0f), + new NextAction("suggest trade", 3.0f), + new NextAction("talk", 1.0f), nullptr))); } From cf9dca6b16ec153e03a609dcdf1323d3acba76bf Mon Sep 17 00:00:00 2001 From: Atidot3 Date: Sun, 28 Jul 2024 20:43:17 +0200 Subject: [PATCH 59/61] Add parameters to allow bot to talk in guild + fix multi guild same message + bot in group wont ask for dungeon --- src/PlayerbotAIConfig.cpp | 1 + src/PlayerbotAIConfig.h | 1 + src/strategy/actions/AutoLearnSpellAction.cpp | 2 +- src/strategy/actions/LootAction.cpp | 2 +- src/strategy/actions/SayAction.cpp | 2 +- src/strategy/actions/SuggestWhatToDoAction.cpp | 14 ++++++++------ src/strategy/actions/XpGainAction.cpp | 2 +- 7 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/PlayerbotAIConfig.cpp b/src/PlayerbotAIConfig.cpp index 94765f34..a859c9dd 100644 --- a/src/PlayerbotAIConfig.cpp +++ b/src/PlayerbotAIConfig.cpp @@ -143,6 +143,7 @@ bool PlayerbotAIConfig::Initialize() randomBotTalk = sConfigMgr->GetOption("AiPlayerbot.RandomBotTalk", false); randomBotEmote = sConfigMgr->GetOption("AiPlayerbot.RandomBotEmote", false); randomBotSuggestDungeons = sConfigMgr->GetOption("AiPlayerbot.RandomBotSuggestDungeons", true); + randomBotGuildTalk = sConfigMgr->GetOption("AiPlayerbot.RandomBotGuildTalk", false); suggestDungeonsInLowerCaseRandomly = sConfigMgr->GetOption("AiPlayerbot.SuggestDungeonsInLowerCaseRandomly", false); randomBotJoinBG = sConfigMgr->GetOption("AiPlayerbot.RandomBotJoinBG", true); randomBotAutoJoinBG = sConfigMgr->GetOption("AiPlayerbot.RandomBotAutoJoinBG", false); diff --git a/src/PlayerbotAIConfig.h b/src/PlayerbotAIConfig.h index c008c051..129daee3 100644 --- a/src/PlayerbotAIConfig.h +++ b/src/PlayerbotAIConfig.h @@ -98,6 +98,7 @@ class PlayerbotAIConfig bool randomBotTalk; bool randomBotEmote; bool randomBotSuggestDungeons; + bool randomBotGuildTalk; bool suggestDungeonsInLowerCaseRandomly; bool randomBotJoinBG; bool randomBotAutoJoinBG; diff --git a/src/strategy/actions/AutoLearnSpellAction.cpp b/src/strategy/actions/AutoLearnSpellAction.cpp index 4ef4f1e8..24205a64 100644 --- a/src/strategy/actions/AutoLearnSpellAction.cpp +++ b/src/strategy/actions/AutoLearnSpellAction.cpp @@ -36,7 +36,7 @@ void AutoLearnSpellAction::LearnSpells(std::ostringstream* out) if (sPlayerbotAIConfig->autoLearnQuestSpells && sRandomPlayerbotMgr->IsRandomBot(bot))// || (!botAI->GetMaster() && sRandomPlayerbotMgr->IsRandomBot(bot))) LearnQuestSpells(out); - if (sPlayerbotAIConfig->randomBotTalk) + if (sPlayerbotAIConfig->randomBotGuildTalk) { Guild* guild = sGuildMgr->GetGuildById(bot->GetGuildId()); if (guild) diff --git a/src/strategy/actions/LootAction.cpp b/src/strategy/actions/LootAction.cpp index ff383ef7..10ae1ccc 100644 --- a/src/strategy/actions/LootAction.cpp +++ b/src/strategy/actions/LootAction.cpp @@ -417,7 +417,7 @@ 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); - if (sPlayerbotAIConfig->randomBotTalk && bot->GetGuildId() && urand(0, 10) && proto->Quality >= ITEM_QUALITY_RARE) + if (sPlayerbotAIConfig->randomBotGuildTalk && bot->GetGuildId() && urand(0, 10) && proto->Quality >= ITEM_QUALITY_RARE) { Guild* guild = sGuildMgr->GetGuildById(bot->GetGuildId()); diff --git a/src/strategy/actions/SayAction.cpp b/src/strategy/actions/SayAction.cpp index e299736d..2bcca877 100644 --- a/src/strategy/actions/SayAction.cpp +++ b/src/strategy/actions/SayAction.cpp @@ -674,7 +674,7 @@ void ChatReplyAction::ChatReplyDo(Player* bot, uint32 type, uint32 guid1, uint32 else if (type == CHAT_MSG_GUILD) { - if (!bot->GetGuildId()) + if (!bot->GetGuildId() || !sPlayerbotAIConfig->randomBotGuildTalk) return; Guild* guild = sGuildMgr->GetGuildById(bot->GetGuildId()); diff --git a/src/strategy/actions/SuggestWhatToDoAction.cpp b/src/strategy/actions/SuggestWhatToDoAction.cpp index e9006fc6..776c1ac9 100644 --- a/src/strategy/actions/SuggestWhatToDoAction.cpp +++ b/src/strategy/actions/SuggestWhatToDoAction.cpp @@ -306,13 +306,13 @@ void SuggestWhatToDoAction::spam(std::string msg, uint8 flags, bool worldChat, b if (Channel* worldChannel = cMgr->GetChannel("World", bot)) worldChannel->Say(bot->GetGUID(), msg.c_str(), LANG_UNIVERSAL); } + } - if (guild && bot->GetGuildId()) - { - Guild* guild = sGuildMgr->GetGuildById(bot->GetGuildId()); - if (guild) - guild->BroadcastToGuild(bot->GetSession(), false, msg.c_str(), LANG_UNIVERSAL); - } + if (sPlayerbotAIConfig->randomBotGuildTalk && guild && bot->GetGuildId()) + { + Guild* guild = sGuildMgr->GetGuildById(bot->GetGuildId()); + if (guild) + guild->BroadcastToGuild(bot->GetSession(), false, msg.c_str(), LANG_UNIVERSAL); } } @@ -355,6 +355,8 @@ bool SuggestDungeonAction::Execute(Event event) { // TODO: use sPlayerbotDungeonSuggestionMgr + if (!sPlayerbotAIConfig->randomBotSuggestDungeons || bot->GetGroup()) return false; + if (instances.empty()) { instances["Ragefire Chasm"] = 15; diff --git a/src/strategy/actions/XpGainAction.cpp b/src/strategy/actions/XpGainAction.cpp index 39ff7d4f..8dc98ca6 100644 --- a/src/strategy/actions/XpGainAction.cpp +++ b/src/strategy/actions/XpGainAction.cpp @@ -33,7 +33,7 @@ bool XpGainAction::Execute(Event event) p >> groupBonus; // 8 group bonus } - if (sPlayerbotAIConfig->randomBotTalk && bot->GetGuildId() && urand(0, 10)) + if (sPlayerbotAIConfig->randomBotGuildTalk && bot->GetGuildId() && urand(0, 10)) { Creature* creature = botAI->GetCreature(guid); if (creature && (creature->isElite() || creature->isWorldBoss() || creature->GetLevel() > 61 || creature->GetLevel() > bot->GetLevel() + 4)) From 7d13192517d9b8b2b55964ed150d17c95ba17a0d Mon Sep 17 00:00:00 2001 From: Atidot3 Date: Sun, 28 Jul 2024 21:12:06 +0200 Subject: [PATCH 60/61] removed useless string --- src/strategy/actions/SuggestWhatToDoAction.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/strategy/actions/SuggestWhatToDoAction.cpp b/src/strategy/actions/SuggestWhatToDoAction.cpp index 776c1ac9..391978f1 100644 --- a/src/strategy/actions/SuggestWhatToDoAction.cpp +++ b/src/strategy/actions/SuggestWhatToDoAction.cpp @@ -243,8 +243,6 @@ void SuggestWhatToDoAction::spam(std::string msg, uint8 flags, bool worldChat, b /*AreaTableEntry const* area = sAreaTableStore.LookupEntry(bot->GetMap()->GetAreaId(bot->GetPhaseMask(), bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ())); if (!area) return;*/ - std::string areaname = zone->area_name[_dbc_locale]; - for (uint32 i = 0; i < sChatChannelsStore.GetNumRows(); ++i) { ChatChannelsEntry const* channel = sChatChannelsStore.LookupEntry(i); @@ -260,7 +258,7 @@ void SuggestWhatToDoAction::spam(std::string msg, uint8 flags, bool worldChat, b } else { - snprintf(channelName, 100, channel->pattern[_dbc_locale], areaname); + snprintf(channelName, 100, channel->pattern[_dbc_locale], zone->area_name[_dbc_locale]); chn = cMgr->GetChannel(channelName, bot); } if (!chn) From 74658389ecb2a4843a60fc68d45800da2cfd02e1 Mon Sep 17 00:00:00 2001 From: Revision Date: Mon, 29 Jul 2024 00:51:43 +0200 Subject: [PATCH 61/61] Fix compile errors related to sSpellMgr --- src/Playerbots.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Playerbots.h b/src/Playerbots.h index 7e678af3..2b467366 100644 --- a/src/Playerbots.h +++ b/src/Playerbots.h @@ -14,6 +14,7 @@ #include "RandomPlayerbotMgr.h" #include "SharedValueContext.h" #include "Spell.h" +#include "SpellMgr.h" #include "TravelNode.h" std::vector split(std::string const s, char delim);