mirror of
https://github.com/mod-playerbots/mod-playerbots
synced 2025-11-29 15:58:20 +08:00
Rewrite bot texts
This commit is contained in:
@@ -518,7 +518,7 @@ std::string const ChatHelper::FormatClass(Player* player, int8 spec)
|
||||
out << (c1 ? "|h|cff00ff00" : "") << c1 << "|h|cffffffff/";
|
||||
out << (c2 ? "|h|cff00ff00" : "") << c2 << "|h|cffffffff";
|
||||
|
||||
out << ") " << classes[cls];
|
||||
out << ")|r " << classes[cls];
|
||||
return out.str();
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "UpdateTime.h"
|
||||
#include "Vehicle.h"
|
||||
#include "GuildMgr.h"
|
||||
#include "SayAction.h"
|
||||
|
||||
std::vector<std::string>& split(std::string const s, char delim, std::vector<std::string>& elems);
|
||||
std::vector<std::string> split(std::string const s, char delim);
|
||||
@@ -295,6 +296,27 @@ void PlayerbotAI::UpdateAIInternal([[maybe_unused]] uint32 elapsed, bool minimal
|
||||
chatCommands.push(*i);
|
||||
}
|
||||
|
||||
// chat replies
|
||||
std::list<ChatQueuedReply> delayedResponses;
|
||||
while (!chatReplies.empty())
|
||||
{
|
||||
ChatQueuedReply holder = chatReplies.front();
|
||||
time_t checkTime = holder.m_time;
|
||||
if (checkTime && time(0) < checkTime)
|
||||
{
|
||||
delayedResponses.push_back(holder);
|
||||
chatReplies.pop();
|
||||
continue;
|
||||
}
|
||||
ChatReplyAction::ChatReplyDo(bot, holder.m_type, holder.m_guid1, holder.m_guid2, holder.m_msg, holder.m_chanName, holder.m_name);
|
||||
chatReplies.pop();
|
||||
}
|
||||
|
||||
for (std::list<ChatQueuedReply>::iterator i = delayedResponses.begin(); i != delayedResponses.end(); ++i)
|
||||
{
|
||||
chatReplies.push(*i);
|
||||
}
|
||||
|
||||
// logout if logout timer is ready or if instant logout is possible
|
||||
if (bot->GetSession()->isLogingOut())
|
||||
{
|
||||
@@ -464,6 +486,9 @@ void PlayerbotAI::HandleCommand(uint32 type, std::string const text, Player* fro
|
||||
if (type == CHAT_MSG_ADDON)
|
||||
return;
|
||||
|
||||
if (type == CHAT_MSG_SYSTEM)
|
||||
return;
|
||||
|
||||
if (text.find(sPlayerbotAIConfig->commandSeparator) != std::string::npos)
|
||||
{
|
||||
std::vector<std::string> commands;
|
||||
@@ -593,6 +618,9 @@ void PlayerbotAI::HandleCommand(uint32 type, std::string const text, Player* fro
|
||||
|
||||
void PlayerbotAI::HandleBotOutgoingPacket(WorldPacket const& packet)
|
||||
{
|
||||
if (packet.empty())
|
||||
return;
|
||||
|
||||
switch (packet.GetOpcode())
|
||||
{
|
||||
case SMSG_SPELL_FAILURE:
|
||||
@@ -631,13 +659,75 @@ void PlayerbotAI::HandleBotOutgoingPacket(WorldPacket const& packet)
|
||||
uint32 emoteId;
|
||||
p.rpos(0);
|
||||
p >> emoteId >> source;
|
||||
if (!source.IsPlayer())
|
||||
return;
|
||||
else
|
||||
if (source.IsPlayer())
|
||||
botOutgoingPacketHandlers.AddPacket(packet);
|
||||
|
||||
return;
|
||||
}
|
||||
case SMSG_MESSAGECHAT: // do not react to self or if not ready to reply
|
||||
{
|
||||
if (!AllowActivity())
|
||||
return;
|
||||
|
||||
WorldPacket p(packet);
|
||||
if (!p.empty() && (p.GetOpcode() == SMSG_MESSAGECHAT || p.GetOpcode() == SMSG_GM_MESSAGECHAT))
|
||||
{
|
||||
p.rpos(0);
|
||||
uint8 msgtype, chatTag;
|
||||
uint32 lang, textLen, nameLen, unused;
|
||||
ObjectGuid guid1, guid2;
|
||||
std::string name, chanName, message;
|
||||
p >> msgtype >> lang;
|
||||
p >> guid1 >> unused;
|
||||
if (guid1.IsEmpty() || p.size() > p.DEFAULT_SIZE)
|
||||
return;
|
||||
switch (msgtype)
|
||||
{
|
||||
case CHAT_MSG_CHANNEL:
|
||||
p >> chanName;
|
||||
[[fallthrough]];
|
||||
case CHAT_MSG_SAY:
|
||||
case CHAT_MSG_PARTY:
|
||||
case CHAT_MSG_YELL:
|
||||
case CHAT_MSG_WHISPER:
|
||||
case CHAT_MSG_GUILD:
|
||||
p >> guid2;
|
||||
p >> textLen >> message >> chatTag;
|
||||
|
||||
if (guid1 != bot->GetGUID()) // do not reply to self
|
||||
{
|
||||
// try to always reply to real player
|
||||
time_t lastChat = GetAiObjectContext()->GetValue<time_t>("last said", "chat")->Get();
|
||||
bool isPaused = time(0) < lastChat;
|
||||
bool shouldReply = false;
|
||||
bool isRandomBot = false;
|
||||
sCharacterCache->GetCharacterNameByGuid(guid1, name);
|
||||
uint32 accountId = sCharacterCache->GetCharacterAccountIdByGuid(guid1);
|
||||
isRandomBot = sPlayerbotAIConfig->IsInRandomAccountList(accountId);
|
||||
bool isMentioned = message.find(bot->GetName()) != std::string::npos;
|
||||
|
||||
// random bot speaks, chat CD
|
||||
if (isRandomBot && isPaused)
|
||||
return;
|
||||
// BG: react only if mentioned or if not channel and real player spoke
|
||||
if (bot->InBattleground() && bot->GetBattleground() && !(isMentioned || (msgtype != CHAT_MSG_CHANNEL && !isRandomBot)))
|
||||
return;
|
||||
|
||||
if ((isRandomBot && !isPaused && (!urand(0, 20) || (!urand(0, 10) && message.find(bot->GetName()) != std::string::npos))) || (!isRandomBot && (isMentioned || msgtype != CHAT_MSG_CHANNEL || !urand(0, 4))))
|
||||
{
|
||||
QueueChatResponse(msgtype, guid1, ObjectGuid(), message, chanName, name);
|
||||
GetAiObjectContext()->GetValue<time_t>("last said", "chat")->Set(time(0) + urand(5, 25));
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
case SMSG_MOVE_KNOCK_BACK: // handle knockbacks
|
||||
{
|
||||
// Peiru: Disable Knockback handling for now until spline crash can be resolved
|
||||
@@ -1357,7 +1447,7 @@ bool PlayerbotAI::TellMasterNoFacing(std::string const text, PlayerbotSecurityLe
|
||||
bool PlayerbotAI::TellError(std::string const text, PlayerbotSecurityLevel securityLevel)
|
||||
{
|
||||
Player* master = GetMaster();
|
||||
if (!IsTellAllowed(securityLevel) || GET_PLAYERBOT_AI(master))
|
||||
if (!IsTellAllowed(securityLevel) || !master || GET_PLAYERBOT_AI(master))
|
||||
return false;
|
||||
|
||||
if (PlayerbotMgr* mgr = GET_PLAYERBOT_MGR(master))
|
||||
@@ -1736,9 +1826,9 @@ bool PlayerbotAI::CastSpell(uint32 spellId, Unit* target, Item* itemTarget)
|
||||
if (pet && pet->HasSpell(spellId))
|
||||
{
|
||||
bool autocast = false;
|
||||
for(AutoSpellList::iterator i = pet->m_autospells.begin(); i != pet->m_autospells.end(); ++i)
|
||||
for(unsigned int & m_autospell : pet->m_autospells)
|
||||
{
|
||||
if (*i == spellId)
|
||||
if (m_autospell == spellId)
|
||||
{
|
||||
autocast = true;
|
||||
break;
|
||||
@@ -1893,9 +1983,9 @@ bool PlayerbotAI::CastSpell(uint32 spellId, float x, float y, float z, Item* ite
|
||||
if (pet && pet->HasSpell(spellId))
|
||||
{
|
||||
bool autocast = false;
|
||||
for (AutoSpellList::iterator i = pet->m_autospells.begin(); i != pet->m_autospells.end(); ++i)
|
||||
for (unsigned int & m_autospell : pet->m_autospells)
|
||||
{
|
||||
if (*i == spellId)
|
||||
if (m_autospell == spellId)
|
||||
{
|
||||
autocast = true;
|
||||
break;
|
||||
@@ -3526,4 +3616,9 @@ bool PlayerbotAI::IsInRealGuild()
|
||||
return false;
|
||||
|
||||
return !(sPlayerbotAIConfig->IsInRandomAccountList(leaderAccount));
|
||||
}
|
||||
|
||||
void PlayerbotAI::QueueChatResponse(uint8 msgtype, ObjectGuid guid1, ObjectGuid guid2, std::string message, std::string chanName, std::string name)
|
||||
{
|
||||
chatReplies.push(ChatQueuedReply(msgtype, guid1.GetCounter(), guid2.GetCounter(), message, chanName, name, time(0) + urand(inCombat ? 10 : 5, inCombat ? 25 : 15)));
|
||||
}
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "PlayerbotAIConfig.h"
|
||||
#include "PlayerbotSecurity.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "PlayerbotTextMgr.h"
|
||||
|
||||
#include <stack>
|
||||
#include <queue>
|
||||
@@ -249,6 +250,7 @@ class PlayerbotAI : public PlayerbotAIBase
|
||||
|
||||
std::string const HandleRemoteCommand(std::string const command);
|
||||
void HandleCommand(uint32 type, std::string const text, Player* fromPlayer);
|
||||
void QueueChatResponse(uint8 msgtype, ObjectGuid guid1, ObjectGuid guid2, std::string message, std::string chanName, std::string name);
|
||||
void HandleBotOutgoingPacket(WorldPacket const& packet);
|
||||
void HandleMasterIncomingPacket(WorldPacket const& packet);
|
||||
void HandleMasterOutgoingPacket(WorldPacket const& packet);
|
||||
@@ -382,6 +384,7 @@ class PlayerbotAI : public PlayerbotAIBase
|
||||
BotState currentState;
|
||||
ChatHelper chatHelper;
|
||||
std::queue<ChatCommandHolder> chatCommands;
|
||||
std::queue<ChatQueuedReply> chatReplies;
|
||||
PacketHandlingHelper botOutgoingPacketHandlers;
|
||||
PacketHandlingHelper masterIncomingPacketHandlers;
|
||||
PacketHandlingHelper masterOutgoingPacketHandlers;
|
||||
|
||||
@@ -140,8 +140,8 @@ bool PlayerbotAIConfig::Initialize()
|
||||
|
||||
randomChangeMultiplier = sConfigMgr->GetOption<float>("AiPlayerbot.RandomChangeMultiplier", 1.0);
|
||||
|
||||
randomBotCombatStrategies = sConfigMgr->GetOption<std::string>("AiPlayerbot.RandomBotCombatStrategies", "-threat");
|
||||
randomBotNonCombatStrategies = sConfigMgr->GetOption<std::string>("AiPlayerbot.RandomBotNonCombatStrategies", "");
|
||||
randomBotCombatStrategies = sConfigMgr->GetOption<std::string>("AiPlayerbot.RandomBotCombatStrategies", "-threat,+custom::say");
|
||||
randomBotNonCombatStrategies = sConfigMgr->GetOption<std::string>("AiPlayerbot.RandomBotNonCombatStrategies", "+custom::say");
|
||||
combatStrategies = sConfigMgr->GetOption<std::string>("AiPlayerbot.CombatStrategies", "+custom::say");
|
||||
nonCombatStrategies = sConfigMgr->GetOption<std::string>("AiPlayerbot.NonCombatStrategies", "+custom::say,+return");
|
||||
|
||||
@@ -308,6 +308,8 @@ bool PlayerbotAIConfig::Initialize()
|
||||
PlayerbotFactory::Init();
|
||||
sRandomItemMgr->Init();
|
||||
sRandomItemMgr->InitAfterAhBot();
|
||||
sPlayerbotTextMgr->LoadBotTexts();
|
||||
sPlayerbotTextMgr->LoadBotTextChance();
|
||||
|
||||
if (!sPlayerbotAIConfig->autoDoQuests)
|
||||
{
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "PlayerbotDbStore.h"
|
||||
#include "PlayerbotFactory.h"
|
||||
#include "WorldSession.h"
|
||||
#include "ChannelMgr.h"
|
||||
|
||||
PlayerbotHolder::PlayerbotHolder() : PlayerbotAIBase(false)
|
||||
{
|
||||
@@ -415,6 +416,53 @@ void PlayerbotHolder::OnBotLogin(Player* const bot)
|
||||
botAI->SetNextCheckDelay(urand(2000, 4000));
|
||||
|
||||
botAI->TellMaster("Hello!");
|
||||
|
||||
// bots join World chat if not solo oriented
|
||||
if (bot->getLevel() >= 10 && sRandomPlayerbotMgr->IsRandomBot(bot) && GET_PLAYERBOT_AI(bot) && GET_PLAYERBOT_AI(bot)->GetGrouperType() != GrouperType::SOLO)
|
||||
{
|
||||
// TODO make action/config
|
||||
// Make the bot join the world channel for chat
|
||||
WorldPacket pkt(CMSG_JOIN_CHANNEL);
|
||||
pkt << uint32(0) << uint8(0) << uint8(0);
|
||||
pkt << std::string("World");
|
||||
pkt << ""; // Pass
|
||||
bot->GetSession()->HandleJoinChannel(pkt);
|
||||
}
|
||||
// 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] : "";
|
||||
|
||||
if (current_zone && cMgr)
|
||||
{
|
||||
for (uint32 i = 0; i < sChatChannelsStore.GetNumRows(); ++i)
|
||||
{
|
||||
ChatChannelsEntry const* channel = sChatChannelsStore.LookupEntry(i);
|
||||
if (!channel) continue;
|
||||
|
||||
bool isLfg = (channel->flags & CHANNEL_DBC_FLAG_LFG) != 0;
|
||||
|
||||
// skip non built-in channels or global channel without zone name in pattern
|
||||
if (!isLfg && (!channel || (channel->flags & 4) == 4))
|
||||
continue;
|
||||
|
||||
// new channel
|
||||
Channel* new_channel = nullptr;
|
||||
if (isLfg)
|
||||
{
|
||||
std::string lfgChannelName = channel->pattern[0];
|
||||
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());
|
||||
new_channel = cMgr->GetJoinChannel(new_channel_name_buf, channel->ChannelID);
|
||||
}
|
||||
if (new_channel && new_channel->GetName().length() > 0)
|
||||
new_channel->JoinChannel(bot, "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string const PlayerbotHolder::ProcessBotCommand(std::string const cmd, ObjectGuid guid, ObjectGuid masterguid, bool admin, uint32 masterAccountId, uint32 masterGuildId)
|
||||
@@ -951,6 +999,9 @@ void PlayerbotMgr::OnBotLoginInternal(Player * const bot)
|
||||
|
||||
void PlayerbotMgr::OnPlayerLogin(Player* player)
|
||||
{
|
||||
// set locale priority for bot texts
|
||||
sPlayerbotTextMgr->AddLocalePriority(player->GetSession()->GetSessionDbcLocale());
|
||||
|
||||
if (sPlayerbotAIConfig->selfBotLevel > 2)
|
||||
HandlePlayerbotCommand("self", player);
|
||||
|
||||
|
||||
@@ -5,9 +5,17 @@
|
||||
#include "PlayerbotTextMgr.h"
|
||||
#include "Playerbots.h"
|
||||
|
||||
void replaceAll(std::string& str, std::string const from, std::string const to);
|
||||
void PlayerbotTextMgr::replaceAll(std::string & str, const std::string & from, const std::string & to) {
|
||||
if (from.empty())
|
||||
return;
|
||||
size_t start_pos = 0;
|
||||
while ((start_pos = str.find(from, start_pos)) != std::string::npos) {
|
||||
str.replace(start_pos, from.length(), to);
|
||||
start_pos += to.length(); // In case 'to' contains 'from', like replacing 'x' with 'yx'
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerbotTextMgr::LoadTemplates()
|
||||
void PlayerbotTextMgr::LoadBotTexts()
|
||||
{
|
||||
LOG_INFO("playerbots", "Loading playerbots texts...");
|
||||
|
||||
@@ -16,10 +24,17 @@ void PlayerbotTextMgr::LoadTemplates()
|
||||
{
|
||||
do
|
||||
{
|
||||
std::map<uint32, std::string> text;
|
||||
Field* fields = result->Fetch();
|
||||
std::string const key = fields[0].Get<std::string>();
|
||||
std::string const text = fields[1].Get<std::string>();
|
||||
templates[key].push_back(text);
|
||||
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>();
|
||||
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;
|
||||
}
|
||||
while (result->NextRow());
|
||||
@@ -28,22 +43,158 @@ void PlayerbotTextMgr::LoadTemplates()
|
||||
LOG_INFO("playerbots", "{} playerbots texts loaded", count);
|
||||
}
|
||||
|
||||
std::string const PlayerbotTextMgr::Format(std::string const key, std::map<std::string, std::string> placeholders)
|
||||
void PlayerbotTextMgr::LoadBotTextChance()
|
||||
{
|
||||
if (templates.empty())
|
||||
LoadTemplates();
|
||||
|
||||
std::vector<std::string>& list = templates[key];
|
||||
if (list.empty())
|
||||
if (botTextChance.empty())
|
||||
{
|
||||
std::ostringstream out;
|
||||
out << "Unknown text: " << key;
|
||||
return out.str();
|
||||
QueryResult results = PlayerbotsDatabase.Query("SELECT name, probability FROM ai_playerbot_texts_chance");
|
||||
if (results)
|
||||
{
|
||||
do
|
||||
{
|
||||
Field* fields = results->Fetch();
|
||||
std::string name = fields[0].Get<std::string>();
|
||||
uint32 probability = fields[1].Get<uint32>();
|
||||
|
||||
botTextChance[name] = probability;
|
||||
} while (results->NextRow());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// general texts
|
||||
|
||||
std::string PlayerbotTextMgr::GetBotText(std::string name)
|
||||
{
|
||||
if (botTexts.empty())
|
||||
{
|
||||
LOG_ERROR("playerbots", "Can't get bot text {}! No bots texts loaded!", name);
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string str = list[urand(0, list.size() - 1)];
|
||||
for (std::map<std::string, std::string>::iterator i = placeholders.begin(); i != placeholders.end(); ++i)
|
||||
replaceAll(str, i->first, i->second);
|
||||
if (botTexts[name].empty())
|
||||
{
|
||||
LOG_ERROR("playerbots", "Can't get bot text {}! No bots texts for this name!", name);
|
||||
return "";
|
||||
}
|
||||
|
||||
return str;
|
||||
std::vector<BotTextEntry>& list = botTexts[name];
|
||||
BotTextEntry textEntry = list[urand(0, list.size() - 1)];
|
||||
return !textEntry.m_text[GetLocalePriority()].empty() ? textEntry.m_text[GetLocalePriority()] : textEntry.m_text[0];
|
||||
}
|
||||
|
||||
std::string PlayerbotTextMgr::GetBotText(std::string name, std::map<std::string, std::string> placeholders)
|
||||
{
|
||||
std::string botText = GetBotText(name);
|
||||
if (botText.empty())
|
||||
return "";
|
||||
|
||||
for (std::map<std::string, std::string>::iterator i = placeholders.begin(); i != placeholders.end(); ++i)
|
||||
replaceAll(botText, i->first, i->second);
|
||||
|
||||
return botText;
|
||||
}
|
||||
|
||||
// chat replies
|
||||
|
||||
std::string PlayerbotTextMgr::GetBotText(ChatReplyType replyType, std::map<std::string, std::string> placeholders)
|
||||
{
|
||||
if (botTexts.empty())
|
||||
{
|
||||
LOG_ERROR("playerbots", "Can't get bot text reply {}! No bots texts loaded!", replyType);
|
||||
return "";
|
||||
}
|
||||
if (botTexts["reply"].empty())
|
||||
{
|
||||
LOG_ERROR("playerbots", "Can't get bot text reply {}! No bots texts replies!", replyType);
|
||||
return "";
|
||||
}
|
||||
|
||||
std::vector<BotTextEntry>& list = botTexts["reply"];
|
||||
std::vector<BotTextEntry> proper_list;
|
||||
for (auto text : list)
|
||||
{
|
||||
if (text.m_replyType == replyType)
|
||||
proper_list.push_back(text);
|
||||
}
|
||||
|
||||
BotTextEntry textEntry = proper_list[urand(0, proper_list.size() - 1)];
|
||||
std::string botText = !textEntry.m_text[GetLocalePriority()].empty() ? textEntry.m_text[GetLocalePriority()] : textEntry.m_text[0];
|
||||
for (auto & placeholder : placeholders)
|
||||
replaceAll(botText, placeholder.first, placeholder.second);
|
||||
|
||||
return botText;
|
||||
}
|
||||
|
||||
|
||||
std::string PlayerbotTextMgr::GetBotText(ChatReplyType replyType, std::string name)
|
||||
{
|
||||
std::map<std::string, std::string> placeholders;
|
||||
placeholders["%s"] = name;
|
||||
|
||||
return GetBotText(replyType, placeholders);
|
||||
}
|
||||
|
||||
// probabilities
|
||||
|
||||
bool PlayerbotTextMgr::rollTextChance(std::string name)
|
||||
{
|
||||
if (!botTextChance[name])
|
||||
return true;
|
||||
|
||||
return urand(0, 100) < botTextChance[name];
|
||||
}
|
||||
|
||||
bool PlayerbotTextMgr::GetBotText(std::string name, std::string &text)
|
||||
{
|
||||
if (!rollTextChance(name))
|
||||
return false;
|
||||
|
||||
text = GetBotText(name);
|
||||
return !text.empty();
|
||||
}
|
||||
|
||||
bool PlayerbotTextMgr::GetBotText(std::string name, std::string& text, std::map<std::string, std::string> placeholders)
|
||||
{
|
||||
if (!rollTextChance(name))
|
||||
return false;
|
||||
|
||||
text = GetBotText(name, placeholders);
|
||||
return !text.empty();
|
||||
}
|
||||
|
||||
|
||||
void PlayerbotTextMgr::AddLocalePriority(uint32 locale)
|
||||
{
|
||||
if (!locale)
|
||||
return;
|
||||
|
||||
botTextLocalePriority[locale]++;
|
||||
}
|
||||
|
||||
uint32 PlayerbotTextMgr::GetLocalePriority()
|
||||
{
|
||||
uint32 topLocale = 0;
|
||||
|
||||
// if no real players online, reset top locale
|
||||
if (!sWorld->GetActiveSessionCount())
|
||||
{
|
||||
ResetLocalePriority();
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (uint8 i = 0; i < MAX_LOCALES; ++i)
|
||||
{
|
||||
if (botTextLocalePriority[i] > topLocale)
|
||||
topLocale = i;
|
||||
}
|
||||
return topLocale;
|
||||
}
|
||||
|
||||
void PlayerbotTextMgr::ResetLocalePriority()
|
||||
{
|
||||
for (uint8 i = 0; i < MAX_LOCALES; ++i)
|
||||
{
|
||||
botTextLocalePriority[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,10 +10,57 @@
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#define BOT_TEXT1(name) sPlayerbotTextMgr->GetBotText(name)
|
||||
#define BOT_TEXT2(name, replace) sPlayerbotTextMgr->GetBotText(name, replace)
|
||||
|
||||
struct BotTextEntry
|
||||
{
|
||||
BotTextEntry(std::string name, std::map<uint32, std::string> text, uint32 say_type, uint32 reply_type) : m_name(name), m_text(text), m_sayType(say_type), m_replyType(reply_type) {}
|
||||
std::string m_name;
|
||||
std::map<uint32, std::string> m_text;
|
||||
uint32 m_sayType;
|
||||
uint32 m_replyType;
|
||||
};
|
||||
|
||||
struct ChatReplyData
|
||||
{
|
||||
ChatReplyData(uint32 guid, uint32 type, std::string chat) : m_guid(guid), m_type(type), m_chat(chat) {}
|
||||
uint32 m_type, m_guid = 0;
|
||||
std::string m_chat = "";
|
||||
};
|
||||
|
||||
struct ChatQueuedReply
|
||||
{
|
||||
ChatQueuedReply(uint32 type, uint32 guid1, uint32 guid2, std::string msg, std::string chanName, std::string name, time_t time) : m_type(type), m_guid1(guid1), m_guid2(guid2), m_msg(msg), m_chanName(chanName), m_name(name), m_time(time) {}
|
||||
uint32 m_type;
|
||||
uint32 m_guid1;
|
||||
uint32 m_guid2;
|
||||
std::string m_msg;
|
||||
std::string m_chanName;
|
||||
std::string m_name;
|
||||
time_t m_time;
|
||||
};
|
||||
|
||||
enum ChatReplyType
|
||||
{
|
||||
REPLY_NOT_UNDERSTAND,
|
||||
REPLY_GRUDGE,
|
||||
REPLY_VICTIM,
|
||||
REPLY_ATTACKER,
|
||||
REPLY_HELLO,
|
||||
REPLY_NAME,
|
||||
REPLY_ADMIN_ABUSE
|
||||
};
|
||||
|
||||
class PlayerbotTextMgr
|
||||
{
|
||||
public:
|
||||
PlayerbotTextMgr() { };
|
||||
PlayerbotTextMgr() {
|
||||
for (uint8 i = 0; i < MAX_LOCALES; ++i)
|
||||
{
|
||||
botTextLocalePriority[i] = 0;
|
||||
}
|
||||
};
|
||||
virtual ~PlayerbotTextMgr() { };
|
||||
static PlayerbotTextMgr* instance()
|
||||
{
|
||||
@@ -21,12 +68,25 @@ class PlayerbotTextMgr
|
||||
return &instance;
|
||||
}
|
||||
|
||||
std::string const Format(std::string const key, std::map<std::string, std::string> placeholders);
|
||||
std::string GetBotText(std::string name, std::map<std::string, std::string> placeholders);
|
||||
std::string GetBotText(std::string name);
|
||||
std::string GetBotText(ChatReplyType replyType, std::map<std::string, std::string> placeholders);
|
||||
std::string GetBotText(ChatReplyType replyType, std::string name);
|
||||
bool GetBotText(std::string name, std::string& text);
|
||||
bool GetBotText(std::string name, std::string& text, std::map<std::string, std::string> placeholders);
|
||||
void LoadBotTexts();
|
||||
void LoadBotTextChance();
|
||||
static void replaceAll(std::string& str, const std::string& from, const std::string& to);
|
||||
bool rollTextChance(std::string text);
|
||||
|
||||
uint32 GetLocalePriority();
|
||||
void AddLocalePriority(uint32 locale);
|
||||
void ResetLocalePriority();
|
||||
|
||||
private:
|
||||
void LoadTemplates();
|
||||
|
||||
std::map<std::string, std::vector<std::string>> templates;
|
||||
std::map<std::string, std::vector<BotTextEntry>> botTexts;
|
||||
std::map<std::string, uint32 > botTextChance;
|
||||
uint32 botTextLocalePriority[MAX_LOCALES];
|
||||
};
|
||||
|
||||
#define sPlayerbotTextMgr PlayerbotTextMgr::instance()
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "PlayerbotCommandServer.h"
|
||||
#include "PlayerbotFactory.h"
|
||||
#include "ServerFacade.h"
|
||||
#include "ChannelMgr.h"
|
||||
|
||||
#include <iomanip>
|
||||
#include <boost/thread/thread.hpp>
|
||||
@@ -1693,11 +1694,24 @@ bool RandomPlayerbotMgr::HandlePlayerbotConsoleCommand(ChatHandler* handler, cha
|
||||
return true;
|
||||
}
|
||||
|
||||
void RandomPlayerbotMgr::HandleCommand(uint32 type, std::string const text, Player* fromPlayer)
|
||||
void RandomPlayerbotMgr::HandleCommand(uint32 type, std::string const text, Player* fromPlayer, std::string channelName)
|
||||
{
|
||||
for (PlayerBotMap::const_iterator it = GetPlayerBotsBegin(); it != GetPlayerBotsEnd(); ++it)
|
||||
{
|
||||
Player* const bot = it->second;
|
||||
if (!bot)
|
||||
continue;
|
||||
|
||||
if (!channelName.empty())
|
||||
{
|
||||
if (ChannelMgr* cMgr = ChannelMgr::forTeam(bot->GetTeamId()))
|
||||
{
|
||||
Channel* chn = cMgr->GetChannel(channelName, bot);
|
||||
if (!chn)
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
GET_PLAYERBOT_AI(bot)->HandleCommand(type, text, fromPlayer);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ class RandomPlayerbotMgr : public PlayerbotHolder
|
||||
void IncreaseLevel(Player* bot);
|
||||
void ScheduleTeleport(uint32 bot, uint32 time = 0);
|
||||
void ScheduleChangeStrategy(uint32 bot, uint32 time = 0);
|
||||
void HandleCommand(uint32 type, std::string const text, Player* fromPlayer);
|
||||
void HandleCommand(uint32 type, std::string const text, Player* fromPlayer, std::string channelName = "");
|
||||
std::string const HandleRemoteCommand(std::string const request);
|
||||
void OnPlayerLogout(Player* player);
|
||||
void OnPlayerLogin(Player* player);
|
||||
|
||||
@@ -53,7 +53,6 @@
|
||||
#include "SayAction.h"
|
||||
#include "StayActions.h"
|
||||
#include "SuggestWhatToDoAction.h"
|
||||
#include "SuggestDungeonAction.h"
|
||||
#include "TravelAction.h"
|
||||
#include "XpGainAction.h"
|
||||
#include "VehicleActions.h"
|
||||
@@ -76,7 +75,6 @@ class ActionContext : public NamedObjectContext<Action>
|
||||
creators["choose travel target"] = &ActionContext::choose_travel_target;
|
||||
creators["move to travel target"] = &ActionContext::move_to_travel_target;
|
||||
creators["move out of collision"] = &ActionContext::move_out_of_collision;
|
||||
creators["move out of collision"] = &ActionContext::move_out_of_collision;
|
||||
creators["move random"] = &ActionContext::move_random;
|
||||
creators["attack"] = &ActionContext::melee;
|
||||
creators["melee"] = &ActionContext::melee;
|
||||
@@ -118,7 +116,6 @@ class ActionContext : public NamedObjectContext<Action>
|
||||
creators["emote"] = &ActionContext::emote;
|
||||
creators["talk"] = &ActionContext::talk;
|
||||
creators["suggest what to do"] = &ActionContext::suggest_what_to_do;
|
||||
creators["suggest dungeon"] = &ActionContext::suggest_dungeon;
|
||||
creators["suggest trade"] = &ActionContext::suggest_trade;
|
||||
creators["return"] = &ActionContext::_return;
|
||||
creators["move to loot"] = &ActionContext::move_to_loot;
|
||||
@@ -138,12 +135,12 @@ class ActionContext : public NamedObjectContext<Action>
|
||||
creators["greet"] = &ActionContext::greet;
|
||||
creators["check values"] = &ActionContext::check_values;
|
||||
creators["ra"] = &ActionContext::ra;
|
||||
creators["give food"] = &ActionContext::give_food;
|
||||
creators["give water"] = &ActionContext::give_water;
|
||||
creators["apply poison"] = &ActionContext::apply_poison;
|
||||
creators["apply stone"] = &ActionContext::apply_stone;
|
||||
creators["apply oil"] = &ActionContext::apply_oil;
|
||||
creators["try emergency"] = &ActionContext::try_emergency;
|
||||
creators["give food"] = &ActionContext::give_food;
|
||||
creators["give water"] = &ActionContext::give_water;
|
||||
creators["mount"] = &ActionContext::mount;
|
||||
creators["war stomp"] = &ActionContext::war_stomp;
|
||||
creators["auto talents"] = &ActionContext::auto_talents;
|
||||
@@ -266,7 +263,6 @@ class ActionContext : public NamedObjectContext<Action>
|
||||
static Action* emote(PlayerbotAI* botAI) { return new EmoteAction(botAI); }
|
||||
static Action* talk(PlayerbotAI* botAI) { return new TalkAction(botAI); }
|
||||
static Action* suggest_what_to_do(PlayerbotAI* botAI) { return new SuggestWhatToDoAction(botAI); }
|
||||
static Action* suggest_dungeon(PlayerbotAI* botAI) { return new SuggestDungeonAction(botAI); }
|
||||
static Action* suggest_trade(PlayerbotAI* botAI) { return new SuggestTradeAction(botAI); }
|
||||
static Action* attack_anything(PlayerbotAI* botAI) { return new AttackAnythingAction(botAI); }
|
||||
static Action* attack_least_hp_target(PlayerbotAI* botAI) { return new AttackLeastHpTargetAction(botAI); }
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "Event.h"
|
||||
#include "Playerbots.h"
|
||||
#include "ServerFacade.h"
|
||||
#include "PlayerbotTextMgr.h"
|
||||
|
||||
std::map<std::string, uint32> EmoteActionBase::emotes;
|
||||
std::map<std::string, uint32> EmoteActionBase::textEmotes;
|
||||
@@ -778,7 +779,7 @@ bool EmoteAction::isUseful()
|
||||
return false;
|
||||
|
||||
time_t lastEmote = AI_VALUE2(time_t, "last emote", qualifier);
|
||||
return (time(nullptr) - lastEmote) >= sPlayerbotAIConfig->repeatDelay / 1000;
|
||||
return time(nullptr) >= lastEmote;
|
||||
}
|
||||
|
||||
bool TalkAction::Execute(Event event)
|
||||
|
||||
@@ -5,125 +5,26 @@
|
||||
#include "SayAction.h"
|
||||
#include "Event.h"
|
||||
#include "Playerbots.h"
|
||||
|
||||
std::map<std::string, std::vector<std::string>> SayAction::stringTable;
|
||||
std::map<std::string, uint32> SayAction::probabilityTable;
|
||||
#include "PlayerbotTextMgr.h"
|
||||
#include "ChannelMgr.h"
|
||||
#include "GuildMgr.h"
|
||||
#include <regex>
|
||||
|
||||
SayAction::SayAction(PlayerbotAI* botAI) : Action(botAI, "say"), Qualified()
|
||||
{
|
||||
}
|
||||
|
||||
void replaceAll(std::string& str, std::string const from, std::string const to)
|
||||
{
|
||||
if (from.empty())
|
||||
return;
|
||||
|
||||
size_t start_pos = 0;
|
||||
while((start_pos = str.find(from, start_pos)) != std::string::npos)
|
||||
{
|
||||
str.replace(start_pos, from.length(), to);
|
||||
start_pos += to.length(); // In case 'to' contains 'from', like replacing 'x' with 'yx'
|
||||
}
|
||||
}
|
||||
|
||||
bool SayAction::Execute(Event event)
|
||||
{
|
||||
if (stringTable.empty())
|
||||
{
|
||||
if (PreparedQueryResult result = PlayerbotsDatabase.Query(PlayerbotsDatabase.GetPreparedStatement(PLAYERBOTS_SEL_SPEECH)))
|
||||
{
|
||||
do
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
std::string const name = fields[0].Get<std::string>();
|
||||
std::string text = fields[1].Get<std::string>();
|
||||
std::string const type = fields[2].Get<std::string>();
|
||||
|
||||
if (type == "yell")
|
||||
text = "/y " + text;
|
||||
|
||||
if (!text.empty() && text != "")
|
||||
stringTable[name].push_back(std::move(text));
|
||||
}
|
||||
while (result->NextRow());
|
||||
}
|
||||
}
|
||||
|
||||
if (probabilityTable.empty())
|
||||
{
|
||||
if (PreparedQueryResult result = PlayerbotsDatabase.Query(PlayerbotsDatabase.GetPreparedStatement(PLAYERBOTS_SEL_SPEECH_PROBABILITY)))
|
||||
{
|
||||
do
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
std::string const name = fields[0].Get<std::string>();
|
||||
uint32 probability = fields[1].Get<uint32>();
|
||||
|
||||
probabilityTable[name] = probability;
|
||||
}
|
||||
while (result->NextRow());
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::string>& strings = stringTable[qualifier];
|
||||
if (strings.empty())
|
||||
return false;
|
||||
|
||||
time_t lastSaid = AI_VALUE2(time_t, "last said", qualifier);
|
||||
uint32 nextTime = time(nullptr) + urand(1, 30);
|
||||
botAI->GetAiObjectContext()->GetValue<time_t>("last said", qualifier)->Set(nextTime);
|
||||
|
||||
if (Group* group = bot->GetGroup())
|
||||
{
|
||||
std::vector<Player*> members;
|
||||
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
||||
{
|
||||
Player* member = ref->GetSource();
|
||||
if (PlayerbotAI* memberAi = GET_PLAYERBOT_AI(member))
|
||||
members.push_back(member);
|
||||
}
|
||||
|
||||
uint32 count = members.size();
|
||||
if (count > 1)
|
||||
{
|
||||
for (uint32 i = 0; i < count * 5; i++)
|
||||
{
|
||||
uint32 i1 = urand(0, count - 1);
|
||||
uint32 i2 = urand(0, count - 1);
|
||||
|
||||
Player* item = members[i1];
|
||||
members[i1] = members[i2];
|
||||
members[i2] = item;
|
||||
}
|
||||
}
|
||||
|
||||
uint32 index = 0;
|
||||
for (Player* player : members)
|
||||
{
|
||||
PlayerbotAI* memberAi = GET_PLAYERBOT_AI(player);
|
||||
memberAi->GetAiObjectContext()->GetValue<time_t>("last said", qualifier)->Set(nextTime + (20 * ++index) + urand(1, 15));
|
||||
}
|
||||
}
|
||||
|
||||
uint32 probability = probabilityTable[qualifier];
|
||||
if (!probability)
|
||||
probability = 100;
|
||||
|
||||
if (urand(0, 100) >= probability)
|
||||
return false;
|
||||
|
||||
uint32 idx = urand(0, strings.size() - 1);
|
||||
std::string text = strings[idx];
|
||||
|
||||
std::string text = "";
|
||||
std::map<std::string, std::string> placeholders;
|
||||
Unit* target = AI_VALUE(Unit*, "tank target");
|
||||
if (!target)
|
||||
target = AI_VALUE(Unit*, "current target");
|
||||
|
||||
if (target)
|
||||
replaceAll(text, "<target>", target->GetName());
|
||||
|
||||
replaceAll(text, "<randomfaction>", IsAlliance(bot->getRace()) ? "Alliance" : "Horde");
|
||||
|
||||
// set replace strings
|
||||
if (target) placeholders["<target>"] = target->GetName();
|
||||
placeholders["<randomfaction>"] = IsAlliance(bot->getRace()) ? "Alliance" : "Horde";
|
||||
if (qualifier == "low ammo" || qualifier == "no ammo")
|
||||
{
|
||||
if (Item* const pItem = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_RANGED))
|
||||
@@ -131,11 +32,11 @@ bool SayAction::Execute(Event event)
|
||||
switch (pItem->GetTemplate()->SubClass)
|
||||
{
|
||||
case ITEM_SUBCLASS_WEAPON_GUN:
|
||||
replaceAll(text, "<ammo>", "bullets");
|
||||
placeholders["<ammo>"] = "bullets";
|
||||
break;
|
||||
case ITEM_SUBCLASS_WEAPON_BOW:
|
||||
case ITEM_SUBCLASS_WEAPON_CROSSBOW:
|
||||
replaceAll(text, "<ammo>", "arrows");
|
||||
placeholders["<ammo>"] = "arrows";
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -144,9 +45,53 @@ bool SayAction::Execute(Event event)
|
||||
if (bot->GetMap())
|
||||
{
|
||||
if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(bot->GetAreaId()))
|
||||
replaceAll(text, "<subzone>", area->area_name[0]);
|
||||
placeholders["<subzone>"] = area->area_name[0];
|
||||
}
|
||||
|
||||
|
||||
// set delay before next say
|
||||
time_t lastSaid = AI_VALUE2(time_t, "last said", qualifier);
|
||||
uint32 nextTime = time(nullptr) + urand(1, 30);
|
||||
botAI->GetAiObjectContext()->GetValue<time_t>("last said", qualifier)->Set(nextTime);
|
||||
|
||||
Group* group = bot->GetGroup();
|
||||
if (group)
|
||||
{
|
||||
std::vector<Player*> members;
|
||||
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
||||
{
|
||||
Player* member = ref->GetSource();
|
||||
PlayerbotAI* memberAi = GET_PLAYERBOT_AI(member);
|
||||
if (memberAi) members.push_back(member);
|
||||
}
|
||||
|
||||
uint32 count = members.size();
|
||||
if (count > 1)
|
||||
{
|
||||
for (uint32 i = 0; i < count * 5; i++)
|
||||
{
|
||||
int i1 = urand(0, count - 1);
|
||||
int i2 = urand(0, count - 1);
|
||||
|
||||
Player* item = members[i1];
|
||||
members[i1] = members[i2];
|
||||
members[i2] = item;
|
||||
}
|
||||
}
|
||||
|
||||
int index = 0;
|
||||
for (auto & member : members)
|
||||
{
|
||||
PlayerbotAI* memberAi = GET_PLAYERBOT_AI(member);
|
||||
if (memberAi)
|
||||
memberAi->GetAiObjectContext()->GetValue<time_t>("last said", qualifier)->Set(nextTime + (20 * ++index) + urand(1, 15));
|
||||
}
|
||||
}
|
||||
|
||||
// load text based on chance
|
||||
if (!sPlayerbotTextMgr->GetBotText(qualifier, text, placeholders))
|
||||
return false;
|
||||
|
||||
if (text.find("/y ") == 0)
|
||||
bot->Yell(text.substr(3), (bot->GetTeamId() == TEAM_ALLIANCE ? LANG_COMMON : LANG_ORCISH));
|
||||
else
|
||||
@@ -163,3 +108,540 @@ bool SayAction::isUseful()
|
||||
time_t lastSaid = AI_VALUE2(time_t, "last said", qualifier);
|
||||
return (time(nullptr) - lastSaid) > 30;
|
||||
}
|
||||
|
||||
void ChatReplyAction::ChatReplyDo(Player* bot, uint32 type, uint32 guid1, uint32 guid2, std::string msg, std::string chanName, std::string name)
|
||||
{
|
||||
ChatReplyType replyType = REPLY_NOT_UNDERSTAND; // default not understand
|
||||
std::string respondsText = "";
|
||||
|
||||
// Chat Logic
|
||||
int32 verb_pos = -1;
|
||||
int32 verb_type = -1;
|
||||
int32 is_quest = 0;
|
||||
bool found = false;
|
||||
std::stringstream text(msg);
|
||||
std::string segment;
|
||||
std::vector<std::string> word;
|
||||
while (std::getline(text, segment, ' '))
|
||||
{
|
||||
word.push_back(segment);
|
||||
}
|
||||
|
||||
for (uint32 i = 0; i < 15; i++)
|
||||
{
|
||||
if (word.size() < i)
|
||||
word.push_back("");
|
||||
}
|
||||
|
||||
if (msg.find("?") != std::string::npos)
|
||||
is_quest = 1;
|
||||
if (word[0].find("what") != std::string::npos)
|
||||
is_quest = 2;
|
||||
else if (word[0].find("who") != std::string::npos)
|
||||
is_quest = 3;
|
||||
else if (word[0] == "when")
|
||||
is_quest = 4;
|
||||
else if (word[0] == "where")
|
||||
is_quest = 5;
|
||||
else if (word[0] == "why")
|
||||
is_quest = 6;
|
||||
|
||||
// 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")
|
||||
{
|
||||
replyType = REPLY_HELLO;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (verb_type < 4)
|
||||
{
|
||||
if (word[i] == "am" || word[i] == "are" || word[i] == "is")
|
||||
{
|
||||
verb_pos = i;
|
||||
verb_type = 2; // present
|
||||
}
|
||||
else if (word[i] == "will")
|
||||
{
|
||||
verb_pos = i;
|
||||
verb_type = 3; // future
|
||||
}
|
||||
else if (word[i] == "was" || word[i] == "were")
|
||||
{
|
||||
verb_pos = i;
|
||||
verb_type = 1; // past
|
||||
}
|
||||
else if (word[i] == "shut" || word[i] == "noob")
|
||||
{
|
||||
if (msg.find(bot->GetName()) == std::string::npos)
|
||||
{
|
||||
continue; // not react
|
||||
uint32 rnd = urand(0, 2);
|
||||
std::string msg = "";
|
||||
if (rnd == 0)
|
||||
msg = "sorry %s, ill shut up now";
|
||||
if (rnd == 1)
|
||||
msg = "ok ok %s";
|
||||
if (rnd == 2)
|
||||
msg = "fine, i wont talk to you anymore %s";
|
||||
|
||||
msg = std::regex_replace(msg, std::regex("%s"), name);
|
||||
respondsText = msg;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
replyType = REPLY_GRUDGE;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (verb_type < 4 && is_quest && !found)
|
||||
{
|
||||
switch (is_quest)
|
||||
{
|
||||
case 2:
|
||||
{
|
||||
uint32 rnd = urand(0, 3);
|
||||
std::string msg = "";
|
||||
|
||||
switch (rnd)
|
||||
{
|
||||
case 0:
|
||||
msg = "i dont know what";
|
||||
break;
|
||||
case 1:
|
||||
msg = "i dont know %s";
|
||||
break;
|
||||
case 2:
|
||||
msg = "who cares";
|
||||
break;
|
||||
case 3:
|
||||
msg = "afraid that was before i was around or paying attention";
|
||||
break;
|
||||
}
|
||||
|
||||
msg = std::regex_replace(msg, std::regex("%s"), name);
|
||||
respondsText = msg;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
uint32 rnd = urand(0, 4);
|
||||
std::string msg = "";
|
||||
|
||||
switch (rnd)
|
||||
{
|
||||
case 0:
|
||||
msg = "nobody";
|
||||
break;
|
||||
case 1:
|
||||
msg = "we all do";
|
||||
break;
|
||||
case 2:
|
||||
msg = "perhaps its you, %s";
|
||||
break;
|
||||
case 3:
|
||||
msg = "dunno %s";
|
||||
break;
|
||||
case 4:
|
||||
msg = "is it me?";
|
||||
break;
|
||||
}
|
||||
|
||||
msg = std::regex_replace(msg, std::regex("%s"), name);
|
||||
respondsText = msg;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
case 4:
|
||||
{
|
||||
uint32 rnd = urand(0, 6);
|
||||
std::string msg = "";
|
||||
|
||||
switch (rnd)
|
||||
{
|
||||
case 0:
|
||||
msg = "soon perhaps %s";
|
||||
break;
|
||||
case 1:
|
||||
msg = "probably later";
|
||||
break;
|
||||
case 2:
|
||||
msg = "never";
|
||||
break;
|
||||
case 3:
|
||||
msg = "what do i look like, a psychic?";
|
||||
break;
|
||||
case 4:
|
||||
msg = "a few minutes, maybe an hour ... years?";
|
||||
break;
|
||||
case 5:
|
||||
msg = "when? good question %s";
|
||||
break;
|
||||
case 6:
|
||||
msg = "dunno %s";
|
||||
break;
|
||||
}
|
||||
|
||||
msg = std::regex_replace(msg, std::regex("%s"), name);
|
||||
respondsText = msg;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
case 5:
|
||||
{
|
||||
uint32 rnd = urand(0, 6);
|
||||
std::string msg = "";
|
||||
|
||||
switch (rnd)
|
||||
{
|
||||
case 0:
|
||||
msg = "really want me to answer that?";
|
||||
break;
|
||||
case 1:
|
||||
msg = "on the map?";
|
||||
break;
|
||||
case 2:
|
||||
msg = "who cares";
|
||||
break;
|
||||
case 3:
|
||||
msg = "afk?";
|
||||
break;
|
||||
case 4:
|
||||
msg = "none of your buisiness where";
|
||||
break;
|
||||
case 5:
|
||||
msg = "yeah, where?";
|
||||
break;
|
||||
case 6:
|
||||
msg = "dunno %s";
|
||||
break;
|
||||
}
|
||||
|
||||
msg = std::regex_replace(msg, std::regex("%s"), name);
|
||||
respondsText = msg;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
case 6:
|
||||
{
|
||||
uint32 rnd = urand(0, 6);
|
||||
std::string msg = "";
|
||||
|
||||
switch (rnd)
|
||||
{
|
||||
case 0:
|
||||
msg = "dunno %s";
|
||||
break;
|
||||
case 1:
|
||||
msg = "why? just because %s";
|
||||
break;
|
||||
case 2:
|
||||
msg = "why is the sky blue?";
|
||||
break;
|
||||
case 3:
|
||||
msg = "dont ask me %s, im just a bot";
|
||||
break;
|
||||
case 4:
|
||||
msg = "your asking the wrong person";
|
||||
break;
|
||||
case 5:
|
||||
msg = "who knows?";
|
||||
break;
|
||||
case 6:
|
||||
msg = "dunno %s";
|
||||
break;
|
||||
}
|
||||
msg = std::regex_replace(msg, std::regex("%s"), name);
|
||||
respondsText = msg;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
switch (verb_type)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
uint32 rnd = urand(0, 3);
|
||||
std::string msg = "";
|
||||
|
||||
switch (rnd)
|
||||
{
|
||||
case 0:
|
||||
msg = "its true, " + word[verb_pos + 1] + " " + word[verb_pos] + " " + word[verb_pos + 2] + " " + word[verb_pos + 3] + " " + word[verb_pos + 4] + " " + word[verb_pos + 4];
|
||||
break;
|
||||
case 1:
|
||||
msg = "ya %s but thats in the past";
|
||||
break;
|
||||
case 2:
|
||||
msg = "nah, but " + word[verb_pos + 1] + " will " + word[verb_pos + 3] + " again though %s";
|
||||
break;
|
||||
case 3:
|
||||
msg = "afraid that was before i was around or paying attention";
|
||||
break;
|
||||
}
|
||||
msg = std::regex_replace(msg, std::regex("%s"), name);
|
||||
respondsText = msg;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
uint32 rnd = urand(0, 6);
|
||||
std::string msg = "";
|
||||
|
||||
switch (rnd)
|
||||
{
|
||||
case 0:
|
||||
msg = "its true, " + word[verb_pos + 1] + " " + word[verb_pos] + " " + word[verb_pos + 2] + " " + word[verb_pos + 3] + " " + word[verb_pos + 4] + " " + word[verb_pos + 5];
|
||||
break;
|
||||
case 1:
|
||||
msg = "ya %s thats true";
|
||||
break;
|
||||
case 2:
|
||||
msg = "maybe " + word[verb_pos + 1] + " " + word[verb_pos] + " " + word[verb_pos + 2] + " " + word[verb_pos + 3] + " " + word[verb_pos + 4] + " " + word[verb_pos + 5];
|
||||
break;
|
||||
case 3:
|
||||
msg = "dunno %s";
|
||||
break;
|
||||
case 4:
|
||||
msg = "i dont think so %s";
|
||||
break;
|
||||
case 5:
|
||||
msg = "yes";
|
||||
break;
|
||||
case 6:
|
||||
msg = "no";
|
||||
break;
|
||||
}
|
||||
msg = std::regex_replace(msg, std::regex("%s"), name);
|
||||
respondsText = msg;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
uint32 rnd = urand(0, 8);
|
||||
std::string msg = "";
|
||||
|
||||
switch (rnd)
|
||||
{
|
||||
case 0:
|
||||
msg = "dunno %s";
|
||||
break;
|
||||
case 1:
|
||||
msg = "beats me %s";
|
||||
break;
|
||||
case 2:
|
||||
msg = "how should i know %s";
|
||||
break;
|
||||
case 3:
|
||||
msg = "dont ask me %s, im just a bot";
|
||||
break;
|
||||
case 4:
|
||||
msg = "your asking the wrong person";
|
||||
break;
|
||||
case 5:
|
||||
msg = "what do i look like, a psychic?";
|
||||
break;
|
||||
case 6:
|
||||
msg = "sure %s";
|
||||
break;
|
||||
case 7:
|
||||
msg = "i dont think so %s";
|
||||
break;
|
||||
case 8:
|
||||
msg = "maybe";
|
||||
break;
|
||||
}
|
||||
msg = std::regex_replace(msg, std::regex("%s"), name);
|
||||
respondsText = msg;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!found)
|
||||
{
|
||||
switch (verb_type)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
uint32 rnd = urand(0, 2);
|
||||
std::string msg = "";
|
||||
|
||||
switch (rnd)
|
||||
{
|
||||
case 0:
|
||||
msg = "yeah %s, the key word being " + word[verb_pos] + " " + word[verb_pos + 1];
|
||||
break;
|
||||
case 1:
|
||||
msg = "ya %s but thats in the past";
|
||||
break;
|
||||
case 2:
|
||||
msg = word[verb_pos - 1] + " will " + word[verb_pos + 1] + " again though %s";
|
||||
break;
|
||||
}
|
||||
msg = std::regex_replace(msg, std::regex("%s"), name);
|
||||
respondsText = msg;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
uint32 rnd = urand(0, 2);
|
||||
std::string msg = "";
|
||||
|
||||
switch (rnd)
|
||||
{
|
||||
case 0:
|
||||
msg = "%s, what do you mean " + word[verb_pos + 1] + "?";
|
||||
break;
|
||||
case 1:
|
||||
msg = "%s, what is a " + word[verb_pos + 1] + "?";
|
||||
break;
|
||||
case 2:
|
||||
msg = "yeah i know " + word[verb_pos - 1] + " is a " + word[verb_pos + 1];
|
||||
break;
|
||||
}
|
||||
msg = std::regex_replace(msg, std::regex("%s"), name);
|
||||
respondsText = msg;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
uint32 rnd = urand(0, 1);
|
||||
std::string msg = "";
|
||||
|
||||
switch (rnd)
|
||||
{
|
||||
case 0:
|
||||
msg = "are you sure thats going to happen %s?";
|
||||
break;
|
||||
case 1:
|
||||
msg = "%s, what will happen %s?";
|
||||
break;
|
||||
case 2:
|
||||
msg = "are you saying " + word[verb_pos - 1] + " will " + word[verb_pos + 1] + " " + word[verb_pos + 2] + " %s?";
|
||||
break;
|
||||
}
|
||||
msg = std::regex_replace(msg, std::regex("%s"), name);
|
||||
respondsText = msg;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
{
|
||||
// Name Responds
|
||||
if (msg.find(bot->GetName()) != std::string::npos)
|
||||
{
|
||||
replyType = REPLY_NAME;
|
||||
found = true;
|
||||
}
|
||||
else // Does not understand
|
||||
{
|
||||
replyType = REPLY_NOT_UNDERSTAND;
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
// send responds
|
||||
//
|
||||
if (found)
|
||||
{
|
||||
// load text if needed
|
||||
if (respondsText.empty())
|
||||
{
|
||||
respondsText = BOT_TEXT2(replyType, name);
|
||||
}
|
||||
const char* c = respondsText.c_str();
|
||||
if (strlen(c) > 255)
|
||||
return;
|
||||
|
||||
if (chanName == "World")
|
||||
{
|
||||
if (ChannelMgr* cMgr = ChannelMgr::forTeam(bot->GetTeamId()))
|
||||
{
|
||||
std::string worldChan = "World";
|
||||
if (Channel* chn = cMgr->GetJoinChannel(worldChan.c_str(), 0))
|
||||
if (bot->GetTeamId() == TEAM_ALLIANCE)
|
||||
chn->Say(bot->GetGUID(), c, LANG_COMMON);
|
||||
else
|
||||
chn->Say(bot->GetGUID(), c, LANG_ORCISH);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (type == CHAT_MSG_WHISPER)
|
||||
{
|
||||
ObjectGuid receiver = sCharacterCache->GetCharacterGuidByName(name);
|
||||
if (!receiver.IsPlayer())
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (bot->GetTeamId() == TEAM_ALLIANCE)
|
||||
{
|
||||
bot->Whisper(c, LANG_COMMON, ObjectAccessor::FindPlayer(receiver));
|
||||
}
|
||||
else
|
||||
{
|
||||
bot->Whisper(c, LANG_ORCISH, ObjectAccessor::FindPlayer(receiver));
|
||||
}
|
||||
}
|
||||
|
||||
if (type == CHAT_MSG_SAY)
|
||||
{
|
||||
if (bot->GetTeamId() == TEAM_ALLIANCE)
|
||||
bot->Say(respondsText, LANG_COMMON);
|
||||
else
|
||||
bot->Say(respondsText, LANG_ORCISH);
|
||||
}
|
||||
|
||||
if (type == CHAT_MSG_YELL)
|
||||
{
|
||||
if (bot->GetTeamId() == TEAM_ALLIANCE)
|
||||
bot->Yell(respondsText, LANG_COMMON);
|
||||
else
|
||||
bot->Yell(respondsText, LANG_ORCISH);
|
||||
}
|
||||
|
||||
if (type == CHAT_MSG_GUILD)
|
||||
{
|
||||
if (!bot->GetGuildId())
|
||||
return;
|
||||
|
||||
Guild* guild = sGuildMgr->GetGuildById(bot->GetGuildId());
|
||||
if (!guild)
|
||||
return;
|
||||
|
||||
guild->BroadcastToGuild(bot->GetSession(), false, respondsText, LANG_UNIVERSAL);
|
||||
}
|
||||
}
|
||||
GET_PLAYERBOT_AI(bot)->GetAiObjectContext()->GetValue<time_t>("last said", "chat")->Set(time(nullptr) + urand(5, 25));
|
||||
}
|
||||
}
|
||||
@@ -24,4 +24,13 @@ class SayAction : public Action, public Qualified
|
||||
static std::map<std::string, uint32> probabilityTable;
|
||||
};
|
||||
|
||||
|
||||
class ChatReplyAction : public Action
|
||||
{
|
||||
public:
|
||||
ChatReplyAction(PlayerbotAI* ai) : Action(ai, "chat message") {}
|
||||
virtual bool Execute(Event event) { return true; }
|
||||
bool isUseful() { return true; }
|
||||
static void ChatReplyDo(Player* bot, uint32 type, uint32 guid1, uint32 guid2, std::string msg, std::string chanName, std::string name);
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -1,95 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "SuggestDungeonAction.h"
|
||||
#include "AiFactory.h"
|
||||
#include "Player.h"
|
||||
#include "Playerbots.h"
|
||||
#include "PlayerbotTextMgr.h"
|
||||
#include "PlayerbotDungeonSuggestionMgr.h"
|
||||
|
||||
DungeonSuggestions SuggestDungeonAction::m_dungeonSuggestions;
|
||||
|
||||
SuggestDungeonAction::SuggestDungeonAction(PlayerbotAI* botAI) :
|
||||
SuggestWhatToDoAction(botAI, "suggest instance")
|
||||
{
|
||||
if (m_dungeonSuggestions.empty())
|
||||
{
|
||||
m_dungeonSuggestions = sPlayerbotDungeonSuggestionMgr->GetDungeonSuggestions();
|
||||
}
|
||||
}
|
||||
|
||||
bool SuggestDungeonAction::Execute(Event event)
|
||||
{
|
||||
bool const isRealPlayer = !sRandomPlayerbotMgr->IsRandomBot(bot);
|
||||
bool const isInGroup = bot->GetGroup();
|
||||
bool const isInInstance = bot->GetInstanceId();
|
||||
if (isRealPlayer || isInGroup || isInInstance)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
DungeonSuggestions const dungeonSuggestions = GetDungeonSuggestionsEligibleFor(bot);
|
||||
if (dungeonSuggestions.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32 const randomDungeonIndex = urand(0, dungeonSuggestions.size() - 1);
|
||||
DungeonSuggestion const* dungeonSuggestion = &dungeonSuggestions[randomDungeonIndex];
|
||||
PlaceholderMap const placeholders = MapPlaceholders(bot, dungeonSuggestion);
|
||||
std::string playerbotsTextKey = PlayerbotsTextKeyByMapKey(placeholders);
|
||||
std::string message = sPlayerbotTextMgr->Format(playerbotsTextKey, placeholders);
|
||||
bool isRandomlyLowerCase = sPlayerbotAIConfig->suggestDungeonsInLowerCaseRandomly
|
||||
? urand(0, 1)
|
||||
: false;
|
||||
spam(message, 1, isRandomlyLowerCase);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
DungeonSuggestions const SuggestDungeonAction::GetDungeonSuggestionsEligibleFor(Player* bot)
|
||||
{
|
||||
DungeonSuggestions dungeonSuggestionsEligibleFor;
|
||||
for (DungeonSuggestions::const_iterator i = m_dungeonSuggestions.begin();
|
||||
i != m_dungeonSuggestions.end(); ++i)
|
||||
{
|
||||
uint8 const level = bot->getLevel();
|
||||
bool const isEligible = level >= i->min_level && level <= i->max_level;
|
||||
if (isEligible)
|
||||
{
|
||||
dungeonSuggestionsEligibleFor.push_back(*i);
|
||||
}
|
||||
}
|
||||
|
||||
return dungeonSuggestionsEligibleFor;
|
||||
}
|
||||
|
||||
PlaceholderMap SuggestDungeonAction::MapPlaceholders(
|
||||
Player* bot,
|
||||
DungeonSuggestion const* dungeonSuggestion
|
||||
)
|
||||
{
|
||||
PlaceholderMap placeholders;
|
||||
bool const isRandomlyMappingRole = urand(0, 1);
|
||||
if (isRandomlyMappingRole)
|
||||
{
|
||||
PlaceholderHelper::MapRole(placeholders, bot);
|
||||
}
|
||||
PlaceholderHelper::MapDungeon(placeholders, dungeonSuggestion, bot);
|
||||
|
||||
return placeholders;
|
||||
}
|
||||
|
||||
std::string SuggestDungeonAction::PlayerbotsTextKeyByMapKey(PlaceholderMap const& placeholders)
|
||||
{
|
||||
bool const isRoleMapped = placeholders.find("%role") != placeholders.end();
|
||||
std::string playerbotsTextKey = "suggest_dungeon";
|
||||
if (isRoleMapped)
|
||||
{
|
||||
playerbotsTextKey = "suggest_dungeon_role";
|
||||
}
|
||||
|
||||
return playerbotsTextKey;
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#ifndef _PLAYERBOT_SUGGESTINSTANCEACTION_H
|
||||
#define _PLAYERBOT_SUGGESTINSTANCEACTION_H
|
||||
|
||||
#include "SuggestWhatToDoAction.h"
|
||||
#include "PlayerbotDungeonSuggestionMgr.h"
|
||||
#include "PlaceholderHelper.h"
|
||||
|
||||
typedef std::vector<DungeonSuggestion> DungeonSuggestions;
|
||||
|
||||
class SuggestDungeonAction : public SuggestWhatToDoAction
|
||||
{
|
||||
public:
|
||||
SuggestDungeonAction(PlayerbotAI* botAI);
|
||||
|
||||
bool Execute(Event event) override;
|
||||
bool isUseful() override { return true; }
|
||||
|
||||
private:
|
||||
static DungeonSuggestions m_dungeonSuggestions;
|
||||
|
||||
DungeonSuggestions const GetDungeonSuggestionsEligibleFor(Player* bot);
|
||||
PlaceholderMap MapPlaceholders(
|
||||
Player* bot,
|
||||
DungeonSuggestion const* dungeonSuggestion
|
||||
);
|
||||
std::string PlayerbotsTextKeyByMapKey(PlaceholderMap const& placeholders);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -10,7 +10,9 @@
|
||||
#include "ChatHelper.h"
|
||||
#include "Playerbots.h"
|
||||
#include "PlayerbotTextMgr.h"
|
||||
#include "GuildMgr.h"
|
||||
|
||||
std::map<std::string, uint8> SuggestWhatToDoAction::instances;
|
||||
std::map<std::string, uint8> SuggestWhatToDoAction::factions;
|
||||
|
||||
SuggestWhatToDoAction::SuggestWhatToDoAction(PlayerbotAI* botAI, std::string const name) : InventoryAction(botAI, name)
|
||||
@@ -35,6 +37,73 @@ 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;
|
||||
@@ -67,7 +136,7 @@ void SuggestWhatToDoAction::specificQuest()
|
||||
placeholders["%role"] = chat->FormatClass(bot, AiFactory::GetPlayerSpecTab(bot));
|
||||
placeholders["%quest"] = chat->FormatQuest(quest);
|
||||
|
||||
spam(sPlayerbotTextMgr->Format("suggest_quest", placeholders));
|
||||
spam(BOT_TEXT2("suggest_quest", placeholders), urand(0, 1) ? 0x18 : 0, urand(0, 2), urand(0, 2));
|
||||
}
|
||||
|
||||
void SuggestWhatToDoAction::grindReputation()
|
||||
@@ -134,10 +203,11 @@ void SuggestWhatToDoAction::grindReputation()
|
||||
placeholders["%rndK"] = rnd.str();
|
||||
|
||||
std::ostringstream itemout;
|
||||
itemout << "|c004040b0" << allowedFactions[urand(0, allowedFactions.size() - 1)] << "|r";
|
||||
// itemout << "|c004040b0" << allowedFactions[urand(0, allowedFactions.size() - 1)] << "|r";
|
||||
itemout << allowedFactions[urand(0, allowedFactions.size() - 1)];
|
||||
placeholders["%faction"] = itemout.str();
|
||||
|
||||
spam(sPlayerbotTextMgr->Format("suggest_faction", placeholders));
|
||||
spam(BOT_TEXT2("suggest_faction", placeholders), 0x18, true);
|
||||
}
|
||||
|
||||
void SuggestWhatToDoAction::something()
|
||||
@@ -150,48 +220,88 @@ void SuggestWhatToDoAction::something()
|
||||
return;
|
||||
|
||||
std::ostringstream out;
|
||||
out << "|cffb04040" << entry->area_name[0] << "|r";
|
||||
// out << "|cffb04040" << entry->area_name[0] << "|r";
|
||||
out << entry->area_name[0];
|
||||
placeholders["%zone"] = out.str();
|
||||
|
||||
spam(sPlayerbotTextMgr->Format("suggest_something", placeholders));
|
||||
spam(BOT_TEXT2("suggest_something", placeholders), urand(0, 1) ? 0x18 : 0, urand(0, 2), urand(0, 2));
|
||||
}
|
||||
|
||||
void SuggestWhatToDoAction::spam(
|
||||
std::string msg,
|
||||
uint32 channelId,
|
||||
bool const isLowerCase
|
||||
)
|
||||
void SuggestWhatToDoAction::spam(std::string msg, uint8 flags, bool worldChat, bool guild)
|
||||
{
|
||||
std::set<std::string> said;
|
||||
if (msg.empty())
|
||||
return;
|
||||
|
||||
std::vector<std::string> channelNames;
|
||||
ChannelMgr* cMgr = ChannelMgr::forTeam(bot->GetTeamId());
|
||||
if (!cMgr)
|
||||
return;
|
||||
|
||||
|
||||
for (uint32 i = 0; i < sChatChannelsStore.GetNumRows(); ++i)
|
||||
{
|
||||
ChatChannelsEntry const* channel = sChatChannelsStore.LookupEntry(i);
|
||||
if (!channel || channel->ChannelID != channelId) continue;
|
||||
if (!channel) continue;
|
||||
|
||||
for (AreaTableEntry const* area : sAreaTableStore)
|
||||
for (AreaTableEntry const* current_zone : sAreaTableStore)
|
||||
{
|
||||
char channelName[255];
|
||||
snprintf(channelName, 255, channel->pattern[0], area->area_name[0]);
|
||||
if (said.find(channelName) != said.end())
|
||||
if (!current_zone)
|
||||
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;
|
||||
|
||||
said.insert(channelName);
|
||||
if (flags != 0 && chn->GetFlags() != flags)
|
||||
continue;
|
||||
|
||||
if (ChannelMgr* cMgr = ChannelMgr::forTeam(bot->GetTeamId()))
|
||||
// skip local defense
|
||||
//if (chn->GetFlags() == 0x18)
|
||||
// continue;
|
||||
|
||||
// no filter, pick several options
|
||||
if (flags == CHANNEL_FLAG_NONE)
|
||||
{
|
||||
if (Channel* chn = cMgr->GetJoinChannel(channelName, channel->ChannelID))
|
||||
{
|
||||
chn->JoinChannel(bot, "");
|
||||
if (isLowerCase)
|
||||
{
|
||||
strToLower(msg);
|
||||
}
|
||||
if (chn->GetName().length() > 0)
|
||||
{
|
||||
chn->Say(bot->GetGUID(), msg.c_str(), LANG_UNIVERSAL);
|
||||
}
|
||||
}
|
||||
channelNames.push_back(chn->GetName());
|
||||
}
|
||||
else
|
||||
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))
|
||||
chn->Say(bot->GetGUID(), msg.c_str(), LANG_UNIVERSAL);
|
||||
}
|
||||
|
||||
if (worldChat)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -290,7 +400,7 @@ bool SuggestTradeAction::Execute(Event event)
|
||||
placeholders["%item"] = chat->FormatItem(proto, count);
|
||||
placeholders["%gold"] = chat->formatMoney(price);
|
||||
|
||||
spam(sPlayerbotTextMgr->Format("suggest_sell", placeholders));
|
||||
spam(BOT_TEXT2("suggest_sell", placeholders), urand(0, 1) ? 0x3C : 0, urand(0, 1), urand(0, 5));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,14 +20,11 @@ class SuggestWhatToDoAction : public InventoryAction
|
||||
protected:
|
||||
typedef void (SuggestWhatToDoAction::*Suggestion)();
|
||||
std::vector<Suggestion> suggestions;
|
||||
void instance();
|
||||
void specificQuest();
|
||||
void grindReputation();
|
||||
void something();
|
||||
void spam(
|
||||
std::string msg,
|
||||
uint32 channelId = 1,
|
||||
bool const isLowerCase = false
|
||||
);
|
||||
void spam(std::string msg, uint8 flags = 0, bool worldChat = false, bool guild = false);
|
||||
|
||||
std::vector<uint32> GetIncompletedQuests();
|
||||
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
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("seldom", NextAction::array(0, new NextAction("suggest what to do", 1.0f), nullptr)));
|
||||
triggers.push_back(new TriggerNode("seldom", NextAction::array(0, new NextAction("suggest trade", 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->randomBotSuggestDungeons)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user