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/AiFactory.cpp b/src/AiFactory.cpp index 2eb4453e..db551d1a 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"); @@ -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/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/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/PlayerbotMgr.cpp b/src/PlayerbotMgr.cpp index 088901bf..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 @@ -544,13 +545,13 @@ void PlayerbotHolder::OnBotLogin(Player* const bot) Channel* new_channel = nullptr; if (isLfg) { - std::string lfgChannelName = channel->pattern[0]; + std::string lfgChannelName = channel->pattern[sWorld->GetDefaultDbcLocale()]; new_channel = cMgr->GetJoinChannel("LookingForGroup", 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..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; } @@ -191,6 +192,7 @@ uint32 PlayerbotTextMgr::GetLocalePriority() if (botTextLocalePriority[i] > topLocale) topLocale = i; } + return topLocale; } 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/Engine.cpp b/src/strategy/Engine.cpp index cef411c6..c4ca7394 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/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/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/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/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/MovementActions.cpp b/src/strategy/actions/MovementActions.cpp index dae03815..f6fd86cd 100644 --- a/src/strategy/actions/MovementActions.cpp +++ b/src/strategy/actions/MovementActions.cpp @@ -1570,7 +1570,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); @@ -1628,7 +1628,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); @@ -1677,7 +1677,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/SayAction.cpp b/src/strategy/actions/SayAction.cpp index 02f03499..e299736d 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() { } @@ -105,6 +115,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; } @@ -114,6 +127,35 @@ void ChatReplyAction::ChatReplyDo(Player* bot, uint32 type, uint32 guid1, uint32 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; @@ -149,18 +191,16 @@ 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; -// } -// } -// - if (word[i] == "hi" || word[i] == "hey" || word[i] == "hello" || word[i] == "wazzup") + // 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") { replyType = REPLY_HELLO; found = true; @@ -169,22 +209,25 @@ 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] == "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") + 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) { @@ -600,22 +643,20 @@ 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)); - } - else - { - bot->Whisper(c, LANG_ORCISH, ObjectAccessor::FindPlayer(receiver)); + if (bot->GetTeamId() == TEAM_ALLIANCE) + { + bot->Whisper(c, LANG_COMMON, plr); + } + else + { + bot->Whisper(c, LANG_ORCISH, plr); + } } } - if (type == CHAT_MSG_SAY) + else if (type == CHAT_MSG_SAY) { if (bot->GetTeamId() == TEAM_ALLIANCE) bot->Say(respondsText, LANG_COMMON); @@ -623,7 +664,7 @@ void ChatReplyAction::ChatReplyDo(Player* bot, uint32 type, uint32 guid1, uint32 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); @@ -631,7 +672,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; @@ -645,4 +686,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 3c797193..dc9241f8 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" @@ -11,24 +12,47 @@ #include "Playerbots.h" #include "PlayerbotTextMgr.h" #include "GuildMgr.h" +#include "Config.h" -std::map SuggestWhatToDoAction::instances; +#include + +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 SuggestDungeonAction::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(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::grindMaterials, this)); } -bool SuggestWhatToDoAction::Execute(Event event) +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) +{ 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); @@ -37,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 (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) ? 0x50 : 0, urand(0, 2), urand(0, 2)); -} - std::vector SuggestWhatToDoAction::GetIncompletedQuests() { std::vector result; @@ -136,7 +93,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() @@ -185,12 +187,11 @@ void SuggestWhatToDoAction::grindReputation() levels.push_back("exalted"); std::vector allowedFactions; - for (std::map::iterator i = factions.begin(); i != factions.end(); ++i) + 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 +208,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 +222,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,58 +238,63 @@ 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; - 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[0]; - chn = cMgr->GetChannel(chanName, bot); - } - else - { - snprintf(channelName, 100, channel->pattern[0], current_zone->area_name[0]); - 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); + // 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()) { 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); + } } if (worldChat) @@ -337,6 +343,80 @@ class FindTradeItemsVisitor : public IterateItemsVisitor uint32 quality; }; +SuggestDungeonAction::SuggestDungeonAction(PlayerbotAI* botAI) : SuggestWhatToDoAction(botAI, "suggest dungeon") +{ +} + +bool SuggestDungeonAction::Execute(Event event) +{ + // TODO: use sPlayerbotDungeonSuggestionMgr + + 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") { } @@ -400,13 +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; } - -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..46391ff2 100644 --- a/src/strategy/actions/SuggestWhatToDoAction.h +++ b/src/strategy/actions/SuggestWhatToDoAction.h @@ -18,19 +18,19 @@ class SuggestWhatToDoAction : public InventoryAction bool isUseful() override; protected: - typedef void (SuggestWhatToDoAction::*Suggestion)(); + using Suggestion = std::function; std::vector suggestions; - void instance(); void specificQuest(); void grindReputation(); + void grindMaterials(); void something(); void spam(std::string msg, uint8 flags = 0, bool worldChat = false, bool guild = false); std::vector GetIncompletedQuests(); private: - static std::map instances; static std::map factions; + const int32_t _dbc_locale; }; class SuggestTradeAction : public SuggestWhatToDoAction @@ -42,4 +42,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 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/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); diff --git a/src/strategy/generic/EmoteStrategy.cpp b/src/strategy/generic/EmoteStrategy.cpp index a008f48e..002fdc41 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))); - } + 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))); - } - 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))); } 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)