mirror of
https://github.com/mod-playerbots/mod-playerbots
synced 2025-11-29 15:58:20 +08:00
Merge pull request #386 from atidot3/locale_fix
Playerbot functionnality to use (channels / emote / say / yell / guild) chat
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -140,6 +140,8 @@ bool PlayerbotAIConfig::Initialize()
|
||||
minRandomBotsPriceChangeInterval = sConfigMgr->GetOption<int32>("AiPlayerbot.MinRandomBotsPriceChangeInterval", 2 * HOUR);
|
||||
maxRandomBotsPriceChangeInterval = sConfigMgr->GetOption<int32>("AiPlayerbot.MaxRandomBotsPriceChangeInterval", 48 * HOUR);
|
||||
randomBotJoinLfg = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotJoinLfg", true);
|
||||
randomBotTalk = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotTalk", false);
|
||||
randomBotEmote = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotEmote", false);
|
||||
randomBotSuggestDungeons = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotSuggestDungeons", true);
|
||||
suggestDungeonsInLowerCaseRandomly = sConfigMgr->GetOption<bool>("AiPlayerbot.SuggestDungeonsInLowerCaseRandomly", false);
|
||||
randomBotJoinBG = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotJoinBG", true);
|
||||
|
||||
@@ -95,6 +95,8 @@ class PlayerbotAIConfig
|
||||
uint32 randomBotsPerInterval;
|
||||
uint32 minRandomBotsPriceChangeInterval, maxRandomBotsPriceChangeInterval;
|
||||
bool randomBotJoinLfg;
|
||||
bool randomBotTalk;
|
||||
bool randomBotEmote;
|
||||
bool randomBotSuggestDungeons;
|
||||
bool suggestDungeonsInLowerCaseRandomly;
|
||||
bool randomBotJoinBG;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -28,12 +28,13 @@ void PlayerbotTextMgr::LoadBotTexts()
|
||||
Field* fields = result->Fetch();
|
||||
std::string name = fields[0].Get<std::string>();
|
||||
text[0] = fields[1].Get<std::string>();
|
||||
uint32 sayType = fields[2].Get<uint32>();
|
||||
uint32 replyType = fields[3].Get<uint32>();
|
||||
uint8 sayType = fields[2].Get<uint8>();
|
||||
uint8 replyType = fields[3].Get<uint8>();
|
||||
for (uint8 i = 1; i < MAX_LOCALES; ++i)
|
||||
{
|
||||
text[i] = fields[i + 3].Get<std::string>();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -1228,8 +1228,8 @@ void RandomPlayerbotMgr::RandomTeleport(Player* bot, std::vector<WorldLocation>&
|
||||
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(),
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -123,6 +123,7 @@ class ActionContext : public NamedObjectContext<Action>
|
||||
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<Action>
|
||||
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); }
|
||||
|
||||
@@ -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<std::string, std::string> 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)
|
||||
|
||||
@@ -671,9 +671,9 @@ bool EmoteAction::Execute(Event event)
|
||||
if (pSource && (pSource->GetGUID() != bot->GetGUID()) && ((urand(0, 1) && bot->HasInArc(static_cast<float>(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<float>(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<uint32> types;
|
||||
for (int32 i = sEmotesTextStore.GetNumRows(); i >= 0; --i)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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<std::string, std::string> 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());
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -10,6 +10,16 @@
|
||||
#include "GuildMgr.h"
|
||||
#include <regex>
|
||||
|
||||
static const std::unordered_set<std::string> 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<std::string> noReplyMsgParts = { "+", "-","@" , "follow target", "focus heal", "cast ", "accept [", "e [", "destroy [", "go zone" };
|
||||
static const std::unordered_set<std::string> 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<time_t>("last said", "chat")->Set(time(nullptr) + urand(5, 25));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<std::string, uint8> SuggestWhatToDoAction::instances;
|
||||
#include <functional>
|
||||
|
||||
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<std::string, uint8> SuggestDungeonAction::instances;
|
||||
std::map<std::string, uint8> 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<std::string> allowedInstances;
|
||||
for (auto & instance : instances)
|
||||
{
|
||||
if (bot->GetLevel() >= instance.second) allowedInstances.push_back(instance.first);
|
||||
}
|
||||
|
||||
if (allowedInstances.empty()) return;
|
||||
|
||||
std::map<std::string, std::string> 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<uint32> SuggestWhatToDoAction::GetIncompletedQuests()
|
||||
{
|
||||
std::vector<uint32> 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<std::string, double> categories;
|
||||
do
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
categories[fields[0].Get<std::string>()] = fields[1].Get<float>();
|
||||
} while (result->NextRow());
|
||||
|
||||
for (std::map<std::string, double>::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<std::string, std::string> 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<std::string> allowedFactions;
|
||||
for (std::map<std::string, uint8>::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<std::string> allowedInstances;
|
||||
for (const auto& instance : instances)
|
||||
{
|
||||
if (bot->GetLevel() >= instance.second)
|
||||
allowedInstances.push_back(instance.first);
|
||||
}
|
||||
if (allowedInstances.empty()) return false;
|
||||
|
||||
std::map<std::string, std::string> 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;
|
||||
}
|
||||
|
||||
@@ -18,19 +18,19 @@ class SuggestWhatToDoAction : public InventoryAction
|
||||
bool isUseful() override;
|
||||
|
||||
protected:
|
||||
typedef void (SuggestWhatToDoAction::*Suggestion)();
|
||||
using Suggestion = std::function<void()>;
|
||||
std::vector<Suggestion> 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<uint32> GetIncompletedQuests();
|
||||
|
||||
private:
|
||||
static std::map<std::string, uint8> instances;
|
||||
static std::map<std::string, uint8> 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<std::string, uint8> instances;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<std::string, std::string> 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);
|
||||
|
||||
@@ -7,22 +7,25 @@
|
||||
|
||||
void EmoteStrategy::InitTriggers(std::vector<TriggerNode*>& 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)));
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user