Chat refactor quests and generic + suggest

This commit is contained in:
antony
2024-08-01 14:13:00 +02:00
parent 79d0f3fd28
commit 142f2ad212
19 changed files with 1855 additions and 304 deletions

View File

@@ -458,9 +458,6 @@ AiPlayerbot.SyncLevelWithPlayers = 0
# Mark many quests <= Bot level as complete (slows down bot creation)
AiPlayerbot.PreQuests = 0
# Bots without a master will say their lines
AiPlayerbot.RandomBotSayWithoutMaster = 0
# Enable LFG for random bots
AiPlayerbot.RandomBotJoinLfg = 1
@@ -1263,27 +1260,107 @@ AiPlayerbot.CommandPrefix = ""
# Separator for bot chat commands
AiPlayerbot.CommandSeparator = "\\\\"
# Enable playerbot to talk in guild
AiPlayerbot.RandomBotGuildTalk = 1
# 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
# Chance to reply to toxic links with toxic links (0-100)
AiPlayerbot.ToxicLinksRepliesChance = 30
# Chance to reply to thunderfury with thunderfury (0-100)
AiPlayerbot.ThunderfuryRepliesChance = 40
# Bots will chat in guild about certain events (int) (0-100)
AiPlayerbot.GuildRepliesRate = 100 # Reply someone saying something.
# Bots will chat in guild about certain events
AIPlayerbot.GuildFeedback = 1
# Bots without a master will say their lines
AiPlayerbot.RandomBotSayWithoutMaster = 0
#
#
#
####################################################################################################
####################################################################################################
#
# Broadcast rates
#
# 1 - to enable broadcasts globally, 0 - to disable (default 1)
# AiPlayerbot.EnableBroadcasts = 1
#
# all broadcast chances should be in range 0-30000
#
# value of 0 will disable this particular broadcast
# setting value to 30000 does not guarantee the broadcast, as there are some internal randoms as well
#
# setting channel broadcast chance to 0, will re-route most broadcasts to other available channels
# setting all channel broadcasts to 0 will disable most broadcasts
# AiPlayerbot.BroadcastToGuildGlobalChance = 30000
# AiPlayerbot.BroadcastToWorldGlobalChance = 30000
# AiPlayerbot.BroadcastToGeneralGlobalChance = 30000
# AiPlayerbot.BroadcastToTradeGlobalChance = 30000
# AiPlayerbot.BroadcastToLFGGlobalChance = 30000
# AiPlayerbot.BroadcastToLocalDefenseGlobalChance = 30000
# AiPlayerbot.BroadcastToWorldDefenseGlobalChance = 30000
# AiPlayerbot.BroadcastToGuildRecruitmentGlobalChance = 30000
#
# individual settings
# setting one of these to 0 will disable the particular broadcast
# AiPlayerbot.BroadcastChanceLootingItemPoor = 30
# AiPlayerbot.BroadcastChanceLootingItemNormal = 150
# AiPlayerbot.BroadcastChanceLootingItemUncommon = 10000
# AiPlayerbot.BroadcastChanceLootingItemRare = 20000
# AiPlayerbot.BroadcastChanceLootingItemEpic = 30000
# AiPlayerbot.BroadcastChanceLootingItemLegendary = 30000
# AiPlayerbot.BroadcastChanceLootingItemArtifact = 30000
#
# AiPlayerbot.BroadcastChanceQuestAccepted = 6000
# AiPlayerbot.BroadcastChanceQuestUpdateObjectiveCompleted = 300
# AiPlayerbot.BroadcastChanceQuestUpdateObjectiveProgress = 300
# AiPlayerbot.BroadcastChanceQuestUpdateFailedTimer = 300
# AiPlayerbot.BroadcastChanceQuestUpdateComplete = 1000
# AiPlayerbot.BroadcastChanceQuestTurnedIn = 10000
#
# AiPlayerbot.BroadcastChanceKillNormal = 30
# AiPlayerbot.BroadcastChanceKillElite = 300
# AiPlayerbot.BroadcastChanceKillRareelite = 3000
# AiPlayerbot.BroadcastChanceKillWorldboss = 20000
# AiPlayerbot.BroadcastChanceKillRare = 10000
# AiPlayerbot.BroadcastChanceKillUnknown = 100
# AiPlayerbot.BroadcastChanceKillPet = 10
# AiPlayerbot.BroadcastChanceKillPlayer = 30
#
# AiPlayerbot.BroadcastChanceLevelupGeneric = 20000
# AiPlayerbot.BroadcastChanceLevelupTenX = 30000
# AiPlayerbot.BroadcastChanceLevelupMaxLevel = 30000
#
# AiPlayerbot.BroadcastChanceSuggestInstance = 5000
# AiPlayerbot.BroadcastChanceSuggestQuest = 10000
# AiPlayerbot.BroadcastChanceSuggestGrindMaterials = 5000
# AiPlayerbot.BroadcastChanceSuggestGrindReputation = 5000
# AiPlayerbot.BroadcastChanceSuggestSell = 300
# AiPlayerbot.BroadcastChanceSuggestSomething = 30000
#
# Very rude speeches
# AiPlayerbot.BroadcastChanceSuggestSomethingToxic = 0
#
# Specifically for "<word> [item link]"
# AiPlayerbot.BroadcastChanceSuggestToxicLinks = 0
#
# prefix is used as a word in "<word> [item link]"
# AiPlayerbot.ToxicLinksPrefix = gnomes
#
# chance to suggest thunderfury
# AiPlayerbot.BroadcastChanceSuggestThunderfury = 1
#
# does not depend on global chance
# AiPlayerbot.BroadcastChanceGuildManagement = 30000
#
####################################################################################################
####################################################################################################
# LOGS
#

919
src/BroadcastHelper.cpp Normal file
View File

@@ -0,0 +1,919 @@
#include "Playerbots.h"
#include "BroadcastHelper.h"
#include "ServerFacade.h"
#include "Channel.h"
BroadcastHelper::BroadcastHelper() {}
uint8 BroadcastHelper::GetLocale()
{
uint8 locale = sWorld->GetDefaultDbcLocale();
// -- In case we're using auto detect on config file^M
if (locale >= MAX_LOCALES)
locale = LocaleConstant::LOCALE_enUS;
return locale;
}
bool BroadcastHelper::BroadcastTest(PlayerbotAI* ai, Player* bot)
{
//return something to ignore the logic
return false;
std::map<std::string, std::string> placeholders;
placeholders["%rand1"] = std::to_string(urand(0, 1));
placeholders["%rand2"] = std::to_string(urand(0, 1));
placeholders["%rand3"] = std::to_string(urand(0, 1));
int32 rand = urand(0, 1);
if (rand == 1 && ai->SayToChannel(BOT_TEXT2("Posted to trade, %rand1, %rand2, %rand3", placeholders), ChatChannelId::TRADE))
return true;
else if (ai->SayToChannel(BOT_TEXT2("Posted to GuildRecruitment, %rand1, %rand2, %rand3", placeholders), ChatChannelId::GUILD_RECRUITMENT))
return true;
return ai->SayToChannel(BOT_TEXT2("Posted to trade, %rand1, %rand2, %rand3", placeholders), ChatChannelId::TRADE);
//int32 rand = urand(1, 8);
if (rand == 1 && ai->SayToGuild(BOT_TEXT2("Posted to guild, %rand1, %rand2, %rand3", placeholders)))
return true;
else if (rand == 2 && ai->SayToWorld(BOT_TEXT2("Posted to world, %rand1, %rand2, %rand3", placeholders)))
return true;
else if (rand == 3 && ai->SayToChannel(BOT_TEXT2("Posted to general, %rand1, %rand2, %rand3", placeholders), ChatChannelId::GENERAL))
return true;
else if (rand == 4 && ai->SayToChannel(BOT_TEXT2("Posted to trade, %rand1, %rand2, %rand3", placeholders), ChatChannelId::TRADE))
return true;
else if (rand == 5 && ai->SayToChannel(BOT_TEXT2("Posted to LFG, %rand1, %rand2, %rand3", placeholders), ChatChannelId::LOOKING_FOR_GROUP))
return true;
else if (rand == 6 && ai->SayToChannel(BOT_TEXT2("Posted to LocalDefense, %rand1, %rand2, %rand3", placeholders), ChatChannelId::LOCAL_DEFENSE))
return true;
else if (rand == 7 && ai->SayToChannel(BOT_TEXT2("Posted to WorldDefense, %rand1, %rand2, %rand3", placeholders), ChatChannelId::WORLD_DEFENSE))
return true;
else if (rand == 8 && ai->SayToChannel(BOT_TEXT2("Posted to GuildRecruitment, %rand1, %rand2, %rand3", placeholders), ChatChannelId::GUILD_RECRUITMENT))
return true;
return false;
}
/**
@param toChannels - map of (ToChannel, chance), where chance is in range 0-100 as uint32 (unless global chance is not 100%)
@return true if said to the channel, false otherwise
*/
bool BroadcastHelper::BroadcastToChannelWithGlobalChance(PlayerbotAI* ai, std::string message, std::list<std::pair<ToChannel, uint32>> toChannels)
{
if (message.empty())
{
return false;
}
for (const auto& pair : toChannels)
{
uint32 roll = urand(1, 100);
uint32 chance = pair.second;
uint32 broadcastRoll = urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue);
switch (pair.first)
{
case TO_GUILD:
{
if (roll <= chance
&& broadcastRoll <= sPlayerbotAIConfig->broadcastToGuildGlobalChance
&& ai->SayToGuild(message))
{
return true;
}
break;
}
case TO_WORLD:
{
if (roll <= chance
&& broadcastRoll <= sPlayerbotAIConfig->broadcastToWorldGlobalChance
&& ai->SayToWorld(message))
{
return true;
}
break;
}
case TO_GENERAL:
{
if (roll <= chance
&& broadcastRoll <= sPlayerbotAIConfig->broadcastToGeneralGlobalChance
&& ai->SayToChannel(message, ChatChannelId::GENERAL))
{
return true;
}
break;
}
case TO_TRADE:
{
if (roll <= chance
&& broadcastRoll <= sPlayerbotAIConfig->broadcastToTradeGlobalChance
&& ai->SayToChannel(message, ChatChannelId::TRADE))
{
return true;
}
break;
}
case TO_LOOKING_FOR_GROUP:
{
if (roll <= chance
&& broadcastRoll <= sPlayerbotAIConfig->broadcastToLFGGlobalChance
&& ai->SayToChannel(message, ChatChannelId::LOOKING_FOR_GROUP))
{
return true;
}
break;
}
case TO_LOCAL_DEFENSE:
{
if (roll <= chance
&& broadcastRoll <= sPlayerbotAIConfig->broadcastToLocalDefenseGlobalChance
&& ai->SayToChannel(message, ChatChannelId::LOCAL_DEFENSE))
{
return true;
}
break;
}
case TO_WORLD_DEFENSE:
{
if (roll <= chance
&& broadcastRoll <= sPlayerbotAIConfig->broadcastToWorldDefenseGlobalChance
&& ai->SayToChannel(message, ChatChannelId::WORLD_DEFENSE))
{
return true;
}
break;
}
case TO_GUILD_RECRUITMENT:
{
if (roll <= chance
&& broadcastRoll <= sPlayerbotAIConfig->broadcastToGuildRecruitmentGlobalChance
&& ai->SayToChannel(message, ChatChannelId::GUILD_RECRUITMENT))
{
return true;
}
break;
}
default:
break;
}
}
return false;
}
bool BroadcastHelper::BroadcastLootingItem(PlayerbotAI* ai, Player* bot, const ItemTemplate *proto)
{
std::map<std::string, std::string> placeholders;
placeholders["%item_link"] = ai->GetChatHelper()->FormatItem(proto);
AreaTableEntry const* current_area = ai->GetCurrentArea();
AreaTableEntry const* current_zone = ai->GetCurrentZone();
placeholders["%area_name"] = current_area ? ai->GetLocalizedAreaName(current_area) : BOT_TEXT1("string_unknown_area");
placeholders["%zone_name"] = current_zone ? ai->GetLocalizedAreaName(current_zone) : BOT_TEXT1("string_unknown_area");
placeholders["%my_class"] = ai->GetChatHelper()->FormatClass(bot->getClass());
placeholders["%my_race"] = ai->GetChatHelper()->FormatRace(bot->getRace());
placeholders["%my_level"] = std::to_string(bot->GetLevel());
switch (proto->Quality)
{
case ITEM_QUALITY_POOR:
if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceLootingItemPoor)
{
return BroadcastToChannelWithGlobalChance(
ai,
BOT_TEXT2("broadcast_looting_item_poor", placeholders),
{ {TO_GUILD, 50}, {TO_WORLD, 50}, {TO_GENERAL, 100} }
);
}
break;
case ITEM_QUALITY_NORMAL:
if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceLootingItemNormal)
{
return BroadcastToChannelWithGlobalChance(
ai,
BOT_TEXT2("broadcast_looting_item_normal", placeholders),
{ {TO_GUILD, 50}, {TO_WORLD, 50}, {TO_GENERAL, 100} }
);
}
break;
case ITEM_QUALITY_UNCOMMON:
if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceLootingItemUncommon)
{
return BroadcastToChannelWithGlobalChance(
ai,
BOT_TEXT2("broadcast_looting_item_uncommon", placeholders),
{ {TO_GUILD, 50}, {TO_WORLD, 50}, {TO_GENERAL, 100} }
);
}
break;
case ITEM_QUALITY_RARE:
if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceLootingItemRare)
{
return BroadcastToChannelWithGlobalChance(
ai,
BOT_TEXT2("broadcast_looting_item_rare", placeholders),
{ {TO_GUILD, 50}, {TO_WORLD, 50}, {TO_GENERAL, 100} }
);
}
break;
case ITEM_QUALITY_EPIC:
if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceLootingItemEpic)
{
return BroadcastToChannelWithGlobalChance(
ai,
BOT_TEXT2("broadcast_looting_item_epic", placeholders),
{ {TO_GUILD, 50}, {TO_WORLD, 50}, {TO_GENERAL, 100} }
);
}
break;
case ITEM_QUALITY_LEGENDARY:
if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceLootingItemLegendary)
{
return BroadcastToChannelWithGlobalChance(
ai,
BOT_TEXT2("broadcast_looting_item_legendary", placeholders),
{ {TO_GUILD, 50}, {TO_WORLD, 50}, {TO_GENERAL, 100} }
);
}
break;
case ITEM_QUALITY_ARTIFACT:
if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceLootingItemArtifact)
{
return BroadcastToChannelWithGlobalChance(
ai,
BOT_TEXT2("broadcast_looting_item_artifact", placeholders),
{ {TO_GUILD, 50}, {TO_WORLD, 50}, {TO_GENERAL, 100} }
);
}
break;
default:
break;
}
return false;
}
bool BroadcastHelper::BroadcastQuestAccepted(PlayerbotAI* ai, Player* bot, const Quest* quest)
{
if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceQuestAccepted)
{
std::map<std::string, std::string> placeholders;
placeholders["%quest_link"] = ai->GetChatHelper()->FormatQuest(quest);
AreaTableEntry const* current_area = ai->GetCurrentArea();
AreaTableEntry const* current_zone = ai->GetCurrentZone();
placeholders["%area_name"] = current_area ? ai->GetLocalizedAreaName(current_area) : BOT_TEXT1("string_unknown_area");
placeholders["%zone_name"] = current_zone ? ai->GetLocalizedAreaName(current_zone) : BOT_TEXT1("string_unknown_area");
placeholders["%my_class"] = ai->GetChatHelper()->FormatClass(bot->getClass());
placeholders["%my_race"] = ai->GetChatHelper()->FormatRace(bot->getRace());
placeholders["%my_level"] = std::to_string(bot->GetLevel());
return BroadcastToChannelWithGlobalChance(
ai,
BOT_TEXT2("broadcast_quest_accepted_generic", placeholders),
{ {TO_GUILD, 50}, {TO_WORLD, 50}, {TO_GENERAL, 100} }
);
}
return false;
}
bool BroadcastHelper::BroadcastQuestUpdateAddKill(PlayerbotAI* ai, Player* bot, Quest const* quest, uint32 availableCount, uint32 requiredCount, std::string obectiveName)
{
std::map<std::string, std::string> placeholders;
AreaTableEntry const* current_area = ai->GetCurrentArea();
AreaTableEntry const* current_zone = ai->GetCurrentZone();
placeholders["%area_name"] = current_area ? ai->GetLocalizedAreaName(current_area) : BOT_TEXT1("string_unknown_area");
placeholders["%zone_name"] = current_zone ? ai->GetLocalizedAreaName(current_zone) : BOT_TEXT1("string_unknown_area");
placeholders["%quest_link"] = ai->GetChatHelper()->FormatQuest(quest);
placeholders["%quest_obj_name"] = obectiveName;
placeholders["%my_class"] = ai->GetChatHelper()->FormatClass(bot->getClass());
placeholders["%my_race"] = ai->GetChatHelper()->FormatRace(bot->getRace());
placeholders["%my_level"] = std::to_string(bot->GetLevel());
placeholders["%quest_obj_available"] = std::to_string(availableCount);
placeholders["%quest_obj_required"] = std::to_string(requiredCount);
placeholders["%quest_obj_missing"] = std::to_string(requiredCount - std::min(availableCount, requiredCount));
placeholders["%quest_obj_full_formatted"] = ai->GetChatHelper()->FormatQuestObjective(obectiveName, availableCount, requiredCount);
if (availableCount < requiredCount
&& urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceQuestUpdateObjectiveProgress)
{
return BroadcastToChannelWithGlobalChance(
ai,
BOT_TEXT2("broadcast_quest_update_add_kill_objective_progress", placeholders),
{ {TO_GUILD, 50}, {TO_WORLD, 50}, {TO_GENERAL, 100} }
);
}
else if (availableCount == requiredCount
&& urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceQuestUpdateObjectiveCompleted)
{
return BroadcastToChannelWithGlobalChance(
ai,
BOT_TEXT2("broadcast_quest_update_add_kill_objective_completed", placeholders),
{ {TO_GUILD, 50}, {TO_WORLD, 50}, {TO_GENERAL, 100} }
);
}
return false;
}
bool BroadcastHelper::BroadcastQuestUpdateAddItem(PlayerbotAI* ai, Player* bot, Quest const* quest, uint32 availableCount, uint32 requiredCount, const ItemTemplate* proto)
{
std::map<std::string, std::string> placeholders;
AreaTableEntry const* current_area = ai->GetCurrentArea();
AreaTableEntry const* current_zone = ai->GetCurrentZone();
placeholders["%area_name"] = current_area ? ai->GetLocalizedAreaName(current_area) : BOT_TEXT1("string_unknown_area");
placeholders["%zone_name"] = current_zone ? ai->GetLocalizedAreaName(current_zone) : BOT_TEXT1("string_unknown_area");
placeholders["%quest_link"] = ai->GetChatHelper()->FormatQuest(quest);
std::string itemLinkFormatted = ai->GetChatHelper()->FormatItem(proto);
placeholders["%item_link"] = itemLinkFormatted;
placeholders["%my_class"] = ai->GetChatHelper()->FormatClass(bot->getClass());
placeholders["%my_race"] = ai->GetChatHelper()->FormatRace(bot->getRace());
placeholders["%my_level"] = std::to_string(bot->GetLevel());
placeholders["%quest_obj_available"] = std::to_string(availableCount);
placeholders["%quest_obj_required"] = std::to_string(requiredCount);
placeholders["%quest_obj_missing"] = std::to_string(requiredCount - std::min(availableCount, requiredCount));
placeholders["%quest_obj_full_formatted"] = ai->GetChatHelper()->FormatQuestObjective(itemLinkFormatted, availableCount, requiredCount);
if (availableCount < requiredCount
&& urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceQuestUpdateObjectiveProgress)
{
return BroadcastToChannelWithGlobalChance(
ai,
BOT_TEXT2("broadcast_quest_update_add_item_objective_progress", placeholders),
{ {TO_GUILD, 50}, {TO_WORLD, 50}, {TO_GENERAL, 100} }
);
}
else if (availableCount == requiredCount
&& urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceQuestUpdateObjectiveCompleted)
{
return BroadcastToChannelWithGlobalChance(
ai,
BOT_TEXT2("broadcast_quest_update_add_item_objective_completed", placeholders),
{ {TO_GUILD, 50}, {TO_WORLD, 50}, {TO_GENERAL, 100} }
);
}
return false;
}
bool BroadcastHelper::BroadcastQuestUpdateFailedTimer(PlayerbotAI* ai, Player* bot, Quest const* quest)
{
if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceQuestUpdateFailedTimer)
{
std::map<std::string, std::string> placeholders;
placeholders["%quest_link"] = ai->GetChatHelper()->FormatQuest(quest);
AreaTableEntry const* current_area = ai->GetCurrentArea();
AreaTableEntry const* current_zone = ai->GetCurrentZone();
placeholders["%area_name"] = current_area ? ai->GetLocalizedAreaName(current_area) : BOT_TEXT1("string_unknown_area");
placeholders["%zone_name"] = current_zone ? ai->GetLocalizedAreaName(current_zone) : BOT_TEXT1("string_unknown_area");
placeholders["%my_class"] = ai->GetChatHelper()->FormatClass(bot->getClass());
placeholders["%my_race"] = ai->GetChatHelper()->FormatRace(bot->getRace());
placeholders["%my_level"] = std::to_string(bot->GetLevel());
return BroadcastToChannelWithGlobalChance(
ai,
BOT_TEXT2("broadcast_quest_update_failed_timer", placeholders),
{ {TO_GUILD, 50}, {TO_WORLD, 50}, {TO_GENERAL, 100} }
);
}
return false;
}
bool BroadcastHelper::BroadcastQuestUpdateComplete(PlayerbotAI* ai, Player* bot, Quest const* quest)
{
if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceQuestUpdateComplete)
{
std::map<std::string, std::string> placeholders;
placeholders["%quest_link"] = ai->GetChatHelper()->FormatQuest(quest);
AreaTableEntry const* current_area = ai->GetCurrentArea();
AreaTableEntry const* current_zone = ai->GetCurrentZone();
placeholders["%area_name"] = current_area ? ai->GetLocalizedAreaName(current_area) : BOT_TEXT1("string_unknown_area");
placeholders["%zone_name"] = current_zone ? ai->GetLocalizedAreaName(current_zone) : BOT_TEXT1("string_unknown_area");
placeholders["%my_class"] = ai->GetChatHelper()->FormatClass(bot->getClass());
placeholders["%my_race"] = ai->GetChatHelper()->FormatRace(bot->getRace());
placeholders["%my_level"] = std::to_string(bot->GetLevel());
return BroadcastToChannelWithGlobalChance(
ai,
BOT_TEXT2("broadcast_quest_update_complete", placeholders),
{ {TO_GUILD, 50}, {TO_WORLD, 50}, {TO_GENERAL, 100} }
);
}
return false;
}
bool BroadcastHelper::BroadcastQuestTurnedIn(PlayerbotAI* ai, Player* bot, Quest const* quest)
{
if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceQuestTurnedIn)
{
std::map<std::string, std::string> placeholders;
placeholders["%quest_link"] = ai->GetChatHelper()->FormatQuest(quest);
AreaTableEntry const* current_area = ai->GetCurrentArea();
AreaTableEntry const* current_zone = ai->GetCurrentZone();
placeholders["%area_name"] = current_area ? ai->GetLocalizedAreaName(current_area) : BOT_TEXT1("string_unknown_area");
placeholders["%zone_name"] = current_zone ? ai->GetLocalizedAreaName(current_zone) : BOT_TEXT1("string_unknown_area");
placeholders["%my_class"] = ai->GetChatHelper()->FormatClass(bot->getClass());
placeholders["%my_race"] = ai->GetChatHelper()->FormatRace(bot->getRace());
placeholders["%my_level"] = std::to_string(bot->GetLevel());
return BroadcastToChannelWithGlobalChance(
ai,
BOT_TEXT2("broadcast_quest_turned_in", placeholders),
{ {TO_GUILD, 50}, {TO_WORLD, 50}, {TO_GENERAL, 100} }
);
}
return false;
}
bool BroadcastHelper::BroadcastKill(PlayerbotAI* ai, Player* bot, Creature *creature)
{
std::map<std::string, std::string> placeholders;
placeholders["%victim_name"] = creature->GetName();
AreaTableEntry const* current_area = ai->GetCurrentArea();
AreaTableEntry const* current_zone = ai->GetCurrentZone();
placeholders["%area_name"] = current_area ? ai->GetLocalizedAreaName(current_area) : BOT_TEXT1("string_unknown_area");
placeholders["%zone_name"] = current_zone ? ai->GetLocalizedAreaName(current_zone) : BOT_TEXT1("string_unknown_area");
placeholders["%victim_level"] = creature->GetLevel();
placeholders["%my_class"] = ai->GetChatHelper()->FormatClass(bot->getClass());
placeholders["%my_race"] = ai->GetChatHelper()->FormatRace(bot->getRace());
placeholders["%my_level"] = std::to_string(bot->GetLevel());
//if ((creature->IsElite() && !creature->GetMap()->IsDungeon())
//if creature->IsWorldBoss()
//if creature->GetLevel() > DEFAULT_MAX_LEVEL + 1
//if creature->GetLevel() > bot->GetLevel() + 4
if (creature->IsPet())
{
if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceKillPet)
{
return BroadcastToChannelWithGlobalChance(
ai,
BOT_TEXT2("broadcast_killed_pet", placeholders),
{ {TO_GUILD, 50}, {TO_WORLD, 50}, {TO_GENERAL, 100} }
);
}
}
else if (creature->IsPlayer())
{
if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceKillPlayer)
{
placeholders["%victim_class"] = ai->GetChatHelper()->FormatClass(creature->getClass());
return BroadcastToChannelWithGlobalChance(
ai,
BOT_TEXT2("broadcast_killed_player", placeholders),
{ {TO_WORLD_DEFENSE, 50}, {TO_LOCAL_DEFENSE, 50}, {TO_GUILD, 50}, {TO_WORLD, 50}, {TO_GENERAL, 100} }
);
}
}
else
{
switch (creature->GetCreatureTemplate()->rank)
{
case CREATURE_ELITE_NORMAL:
if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceKillNormal)
{
return BroadcastToChannelWithGlobalChance(
ai,
BOT_TEXT2("broadcast_killed_normal", placeholders),
{ {TO_GUILD, 50}, {TO_WORLD, 50}, {TO_GENERAL, 100} }
);
}
break;
case CREATURE_ELITE_ELITE:
if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceKillElite)
{
return BroadcastToChannelWithGlobalChance(
ai,
BOT_TEXT2("broadcast_killed_elite", placeholders),
{ {TO_GUILD, 50}, {TO_WORLD, 50}, {TO_GENERAL, 100} }
);
}
break;
case CREATURE_ELITE_RAREELITE:
if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceKillRareelite)
{
return BroadcastToChannelWithGlobalChance(
ai,
BOT_TEXT2("broadcast_killed_rareelite", placeholders),
{ {TO_GUILD, 50}, {TO_WORLD, 50}, {TO_GENERAL, 100} }
);
}
break;
case CREATURE_ELITE_WORLDBOSS:
if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceKillWorldboss)
{
return BroadcastToChannelWithGlobalChance(
ai,
BOT_TEXT2("broadcast_killed_worldboss", placeholders),
{ {TO_GUILD, 50}, {TO_WORLD, 50}, {TO_GENERAL, 100} }
);
}
break;
case CREATURE_ELITE_RARE:
if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceKillRare)
{
return BroadcastToChannelWithGlobalChance(
ai,
BOT_TEXT2("broadcast_killed_rare", placeholders),
{ {TO_GUILD, 50}, {TO_WORLD, 50}, {TO_GENERAL, 100} }
);
}
break;
case CREATURE_UNKNOWN:
if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceKillUnknown)
{
return BroadcastToChannelWithGlobalChance(
ai,
BOT_TEXT2("broadcast_killed_unknown", placeholders),
{ {TO_GUILD, 50}, {TO_WORLD, 50}, {TO_GENERAL, 100} }
);
}
break;
default:
break;
}
}
return false;
}
bool BroadcastHelper::BroadcastLevelup(PlayerbotAI* ai, Player* bot)
{
uint32 level = bot->GetLevel();
std::map<std::string, std::string> placeholders;
AreaTableEntry const* current_area = ai->GetCurrentArea();
AreaTableEntry const* current_zone = ai->GetCurrentZone();
placeholders["%area_name"] = current_area ? ai->GetLocalizedAreaName(current_area) : BOT_TEXT1("string_unknown_area");
placeholders["%zone_name"] = current_zone ? ai->GetLocalizedAreaName(current_zone) : BOT_TEXT1("string_unknown_area");
placeholders["%my_class"] = ai->GetChatHelper()->FormatClass(bot->getClass());
placeholders["%my_race"] = ai->GetChatHelper()->FormatRace(bot->getRace());
placeholders["%my_level"] = std::to_string(level);
if (level == sPlayerbotAIConfig->randomBotMaxLevel
&& urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceLevelupMaxLevel)
{
return BroadcastToChannelWithGlobalChance(
ai,
BOT_TEXT2("broadcast_levelup_max_level", placeholders),
{ {TO_GUILD, 30}, {TO_WORLD, 90}, {TO_GENERAL, 100} }
);
}
// It's divisible by 10
else if (level % 10 == 0
&& urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceLevelupTenX)
{
return BroadcastToChannelWithGlobalChance(
ai,
BOT_TEXT2("broadcast_levelup_10x", placeholders),
{ {TO_GUILD, 50}, {TO_WORLD, 90}, {TO_GENERAL, 100} }
);
}
else if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceLevelupGeneric)
{
return BroadcastToChannelWithGlobalChance(
ai,
BOT_TEXT2("broadcast_levelup_generic", placeholders),
{ {TO_GUILD, 90}, {TO_WORLD, 90}, {TO_GENERAL, 100} }
);
}
return false;
}
bool BroadcastHelper::BroadcastGuildMemberPromotion(PlayerbotAI* ai, Player* bot, Player* player)
{
if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceGuildManagement)
{
std::map<std::string, std::string> placeholders;
placeholders["%other_name"] = player->GetName();
placeholders["%other_class"] = ai->GetChatHelper()->FormatClass(player->getClass());
placeholders["%other_race"] = ai->GetChatHelper()->FormatRace(player->getRace());
placeholders["%other_level"] = std::to_string(player->GetLevel());
return ai->SayToGuild(BOT_TEXT2("broadcast_guild_promotion", placeholders));
}
return false;
}
bool BroadcastHelper::BroadcastGuildMemberDemotion(PlayerbotAI* ai, Player* bot, Player* player)
{
if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceGuildManagement)
{
std::map<std::string, std::string> placeholders;
placeholders["%other_name"] = player->GetName();
placeholders["%other_class"] = ai->GetChatHelper()->FormatClass(player->getClass());
placeholders["%other_race"] = ai->GetChatHelper()->FormatRace(player->getRace());
placeholders["%other_level"] = std::to_string(player->GetLevel());
return ai->SayToGuild(BOT_TEXT2("broadcast_guild_demotion", placeholders));
}
return false;
}
bool BroadcastHelper::BroadcastGuildGroupOrRaidInvite(PlayerbotAI* ai, Player* bot, Player* player, Group* group)
{
std::map<std::string, std::string> placeholders;
placeholders["%name"] = player->GetName();
AreaTableEntry const* current_area = ai->GetCurrentArea();
AreaTableEntry const* current_zone = ai->GetCurrentZone();
placeholders["%area_name"] = current_area ? ai->GetLocalizedAreaName(current_area) : BOT_TEXT1("string_unknown_area");
placeholders["%zone_name"] = current_zone ? ai->GetLocalizedAreaName(current_zone) : BOT_TEXT1("string_unknown_area");
//TODO move texts to sql!
if (group && group->isRaidGroup())
{
if (urand(0, 3))
{
return ai->SayToGuild(BOT_TEXT2("Hey anyone want to raid in %zone_name", placeholders));
}
else
{
return ai->SayToGuild(BOT_TEXT2("Hey %name I'm raiding in %zone_name do you wan to join me?", placeholders));
}
}
else
{
//(bot->GetTeam() == ALLIANCE ? LANG_COMMON : LANG_ORCISH)
if (urand(0, 3))
{
return ai->SayToGuild(BOT_TEXT2("Hey anyone wanna group up in %zone_name?", placeholders));
}
else
{
return ai->SayToGuild(BOT_TEXT2("Hey %name do you want join my group? I'm heading for %zone_name", placeholders));
}
}
return false;
}
bool BroadcastHelper::BroadcastSuggestInstance(PlayerbotAI* ai, std::vector<std::string>& allowedInstances, Player* bot)
{
if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceSuggestInstance)
{
std::map<std::string, std::string> placeholders;
placeholders["%my_role"] = ai->GetChatHelper()->FormatClass(bot->GetSpec());
std::ostringstream itemout;
//itemout << "|c00b000b0" << allowedInstances[urand(0, allowedInstances.size() - 1)] << "|r";
itemout << allowedInstances[urand(0, allowedInstances.size() - 1)];
placeholders["%instance_name"] = itemout.str();
placeholders["%my_class"] = ai->GetChatHelper()->FormatClass(bot->getClass());
placeholders["%my_race"] = ai->GetChatHelper()->FormatRace(bot->getRace());
placeholders["%my_level"] = std::to_string(bot->GetLevel());
return BroadcastToChannelWithGlobalChance(
ai,
BOT_TEXT2("suggest_instance", placeholders),
{ {TO_LOOKING_FOR_GROUP, 50}, {TO_GUILD, 50}, {TO_WORLD, 50}, {TO_GENERAL, 100} }
);
}
return false;
}
bool BroadcastHelper::BroadcastSuggestQuest(PlayerbotAI* ai, std::vector<uint32>& quests, Player* bot)
{
if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceSuggestQuest)
{
int index = rand() % quests.size();
Quest const* quest = sObjectMgr->GetQuestTemplate(quests[index]);
std::map<std::string, std::string> placeholders;
placeholders["%my_role"] = ai->GetChatHelper()->FormatClass(bot->GetSpec());
placeholders["%quest_link"] = ai->GetChatHelper()->FormatQuest(quest);
placeholders["%quest_level"] = std::to_string(quest->GetQuestLevel());
placeholders["%my_class"] = ai->GetChatHelper()->FormatClass(bot->getClass());
placeholders["%my_race"] = ai->GetChatHelper()->FormatRace(bot->getRace());
placeholders["%my_level"] = std::to_string(bot->GetLevel());
return BroadcastToChannelWithGlobalChance(
ai,
BOT_TEXT2("suggest_quest", placeholders),
{ {TO_LOOKING_FOR_GROUP, 50}, {TO_GUILD, 50}, {TO_WORLD, 50}, {TO_GENERAL, 100} }
);
}
return false;
}
bool BroadcastHelper::BroadcastSuggestGrindMaterials(PlayerbotAI* ai, std::string item, Player* bot)
{
if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceSuggestGrindMaterials)
{
std::map<std::string, std::string> placeholders;
placeholders["%my_role"] = ai->GetChatHelper()->FormatClass(bot->GetSpec());
placeholders["%category"] = item;
placeholders["%my_class"] = ai->GetChatHelper()->FormatClass(bot->getClass());
placeholders["%my_race"] = ai->GetChatHelper()->FormatRace(bot->getRace());
placeholders["%my_level"] = std::to_string(bot->GetLevel());
return BroadcastToChannelWithGlobalChance(
ai,
BOT_TEXT2("suggest_trade", placeholders),
{ {TO_TRADE, 50}, {TO_LOOKING_FOR_GROUP, 50}, {TO_GUILD, 50}, {TO_WORLD, 50}, {TO_GENERAL, 100} }
);
}
return false;
}
bool BroadcastHelper::BroadcastSuggestGrindReputation(PlayerbotAI* ai, std::vector<std::string> levels, std::vector<std::string> allowedFactions, Player* bot)
{
if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceSuggestGrindReputation)
{
std::map<std::string, std::string> placeholders;
placeholders["%my_role"] = ai->GetChatHelper()->FormatClass(bot->GetSpec());
placeholders["%rep_level"] = levels[urand(0, 2)];
std::ostringstream rnd; rnd << urand(1, 5) << "K";
placeholders["%rndK"] = rnd.str();
std::ostringstream itemout;
//itemout << "|c004040b0" << allowedFactions[urand(0, allowedFactions.size() - 1)] << "|r";
itemout << allowedFactions[urand(0, allowedFactions.size() - 1)];
placeholders["%faction"] = itemout.str();
placeholders["%my_class"] = ai->GetChatHelper()->FormatClass(bot->getClass());
placeholders["%my_race"] = ai->GetChatHelper()->FormatRace(bot->getRace());
placeholders["%my_level"] = std::to_string(bot->GetLevel());
return BroadcastToChannelWithGlobalChance(
ai,
BOT_TEXT2("suggest_faction", placeholders),
{ {TO_LOOKING_FOR_GROUP, 50}, {TO_GUILD, 50}, {TO_WORLD, 50}, {TO_GENERAL, 100} }
);
}
return false;
}
bool BroadcastHelper::BroadcastSuggestSell(PlayerbotAI* ai, const ItemTemplate* proto, uint32 count, uint32 price, Player* bot)
{
if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceSuggestSell)
{
std::map<std::string, std::string> placeholders;
placeholders["%item_link"] = ai->GetChatHelper()->FormatItem(proto, 0);
placeholders["%item_formatted_link"] = ai->GetChatHelper()->FormatItem(proto, count);
placeholders["%item_count"] = std::to_string(count);
placeholders["%cost_gold"] = ai->GetChatHelper()->formatMoney(price);
placeholders["%my_class"] = ai->GetChatHelper()->FormatClass(bot->getClass());
placeholders["%my_race"] = ai->GetChatHelper()->FormatRace(bot->getRace());
placeholders["%my_level"] = std::to_string(bot->GetLevel());
return BroadcastToChannelWithGlobalChance(
ai,
BOT_TEXT2("suggest_sell", placeholders),
{ {TO_TRADE, 90}, {TO_GENERAL, 100} }
);
}
return false;
}
bool BroadcastHelper::BroadcastSuggestSomething(PlayerbotAI* ai, Player* bot)
{
if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceSuggestSomething)
{
std::map<std::string, std::string> placeholders;
placeholders["%my_role"] = ai->GetChatHelper()->FormatClass(bot->GetSpec());
AreaTableEntry const* current_area = ai->GetCurrentArea();
AreaTableEntry const* current_zone = ai->GetCurrentZone();
placeholders["%area_name"] = current_area ? ai->GetLocalizedAreaName(current_area) : BOT_TEXT1("string_unknown_area");
placeholders["%zone_name"] = current_zone ? ai->GetLocalizedAreaName(current_zone) : BOT_TEXT1("string_unknown_area");
placeholders["%my_class"] = ai->GetChatHelper()->FormatClass(bot->getClass());
placeholders["%my_race"] = ai->GetChatHelper()->FormatRace(bot->getRace());
placeholders["%my_level"] = std::to_string(bot->GetLevel());
return BroadcastToChannelWithGlobalChance(
ai,
BOT_TEXT2("suggest_something", placeholders),
{ {TO_GUILD, 10}, {TO_WORLD, 70}, {TO_GENERAL, 100} }
);
}
return false;
}
bool BroadcastHelper::BroadcastSuggestSomethingToxic(PlayerbotAI* ai, Player* bot)
{
if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceSuggestSomethingToxic)
{
//items
std::vector<Item*> botItems = ai->GetInventoryAndEquippedItems();
std::map<std::string, std::string> placeholders;
placeholders["%random_inventory_item_link"] = botItems.size() > 0 ? ai->GetChatHelper()->FormatItem(botItems[rand() % botItems.size()]->GetTemplate()) : BOT_TEXT1("string_empty_link");
placeholders["%my_role"] = ai->GetChatHelper()->FormatClass(bot->GetSpec());
AreaTableEntry const* current_area = ai->GetCurrentArea();
AreaTableEntry const* current_zone = ai->GetCurrentZone();
placeholders["%area_name"] = current_area ? ai->GetLocalizedAreaName(current_area) : BOT_TEXT1("string_unknown_area");
placeholders["%zone_name"] = current_zone ? ai->GetLocalizedAreaName(current_zone) : BOT_TEXT1("string_unknown_area");
placeholders["%my_class"] = ai->GetChatHelper()->FormatClass(bot->getClass());
placeholders["%my_race"] = ai->GetChatHelper()->FormatRace(bot->getRace());
placeholders["%my_level"] = std::to_string(bot->GetLevel());
return BroadcastToChannelWithGlobalChance(
ai,
BOT_TEXT2("suggest_something_toxic", placeholders),
{ {TO_GUILD, 10}, {TO_WORLD, 70}, {TO_GENERAL, 100} }
);
}
return false;
}
bool BroadcastHelper::BroadcastSuggestToxicLinks(PlayerbotAI* ai, Player* bot)
{
if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceSuggestToxicLinks)
{
//quests
std::vector<uint32> incompleteQuests;
for (uint16 slot = 0; slot < MAX_QUEST_LOG_SIZE; ++slot)
{
uint32 questId = bot->GetQuestSlotQuestId(slot);
if (!questId)
continue;
QuestStatus status = bot->GetQuestStatus(questId);
if (status == QUEST_STATUS_INCOMPLETE || status == QUEST_STATUS_NONE)
incompleteQuests.push_back(questId);
}
//items
std::vector<Item*> botItems = ai->GetInventoryAndEquippedItems();
//spells
//?
std::map<std::string, std::string> placeholders;
placeholders["%random_inventory_item_link"] = botItems.size() > 0 ? ai->GetChatHelper()->FormatItem(botItems[rand() % botItems.size()]->GetTemplate()) : BOT_TEXT1("string_empty_link");
placeholders["%prefix"] = sPlayerbotAIConfig->toxicLinksPrefix;
if (incompleteQuests.size() > 0)
{
Quest const* quest = sObjectMgr->GetQuestTemplate(incompleteQuests[rand() % incompleteQuests.size()]);
placeholders["%random_taken_quest_or_item_link"] = ai->GetChatHelper()->FormatQuest(quest);
}
else
{
placeholders["%random_taken_quest_or_item_link"] = placeholders["%random_inventory_item_link"];
}
placeholders["%my_role"] = ai->GetChatHelper()->FormatClass(bot->GetSpec());
AreaTableEntry const* current_area = ai->GetCurrentArea();
AreaTableEntry const* current_zone = ai->GetCurrentZone();
placeholders["%area_name"] = current_area ? ai->GetLocalizedAreaName(current_area) : BOT_TEXT1("string_unknown_area");
placeholders["%zone_name"] = current_zone ? ai->GetLocalizedAreaName(current_zone) : BOT_TEXT1("string_unknown_area");
placeholders["%my_class"] = ai->GetChatHelper()->FormatClass(bot->getClass());
placeholders["%my_race"] = ai->GetChatHelper()->FormatRace(bot->getRace());
placeholders["%my_level"] = std::to_string(bot->GetLevel());
return BroadcastToChannelWithGlobalChance(
ai,
BOT_TEXT2("suggest_toxic_links", placeholders),
{ {TO_GUILD, 10}, {TO_WORLD, 70}, {TO_GENERAL, 100} }
);
}
return false;
}
bool BroadcastHelper::BroadcastSuggestThunderfury(PlayerbotAI* ai, Player* bot)
{
if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceSuggestThunderfury)
{
std::map<std::string, std::string> placeholders;
ItemTemplate const* thunderfuryProto = sObjectMgr->GetItemTemplate(19019);
placeholders["%thunderfury_link"] = GET_PLAYERBOT_AI(bot)->GetChatHelper()->FormatItem(thunderfuryProto);
return BroadcastToChannelWithGlobalChance(
ai,
BOT_TEXT2("thunderfury_spam", placeholders),
{ {TO_WORLD, 70}, {TO_GENERAL, 100} }
);
}
return false;
}

148
src/BroadcastHelper.h Normal file
View File

@@ -0,0 +1,148 @@
#pragma once
class PlayerbotAI;
class Player;
class ItemTemplate;
class Quest;
class Creature;
class Group;
class BroadcastHelper
{
public:
BroadcastHelper();
public:
enum ToChannel
{
TO_GUILD = 1,
TO_WORLD = 2,
TO_GENERAL = 3,
TO_TRADE = 4,
TO_LOOKING_FOR_GROUP = 5,
TO_LOCAL_DEFENSE = 6,
TO_WORLD_DEFENSE = 7,
TO_GUILD_RECRUITMENT = 8
};
static uint8_t GetLocale();
static bool BroadcastTest(
PlayerbotAI* ai,
Player* bot
);
static bool BroadcastToChannelWithGlobalChance(
PlayerbotAI* ai,
std::string message,
std::list<std::pair<ToChannel, uint32_t>> toChannels
);
static bool BroadcastLootingItem(
PlayerbotAI* ai,
Player* bot,
const ItemTemplate* proto
);
static bool BroadcastQuestAccepted(
PlayerbotAI* ai,
Player* bot,
const Quest* quest
);
static bool BroadcastQuestUpdateAddKill(
PlayerbotAI* ai,
Player* bot,
Quest const* quest,
uint32_t availableCount,
uint32_t requiredCount,
std::string obectiveName
);
static bool BroadcastQuestUpdateAddItem(
PlayerbotAI* ai,
Player* bot,
Quest const* quest,
uint32_t availableCount,
uint32_t requiredCount,
const ItemTemplate* proto
);
static bool BroadcastQuestUpdateFailedTimer(
PlayerbotAI* ai,
Player* bot,
Quest const* quest
);
static bool BroadcastQuestUpdateComplete(
PlayerbotAI* ai,
Player* bot,
Quest const* quest
);
static bool BroadcastQuestTurnedIn(
PlayerbotAI* ai,
Player* bot,
Quest const* quest
);
static bool BroadcastKill(
PlayerbotAI* ai,
Player* bot,
Creature* creature
);
static bool BroadcastLevelup(
PlayerbotAI* ai,
Player* bot
);
static bool BroadcastGuildMemberPromotion(
PlayerbotAI* ai,
Player* bot,
Player* player
);
static bool BroadcastGuildMemberDemotion(
PlayerbotAI* ai,
Player* bot,
Player* player
);
static bool BroadcastGuildGroupOrRaidInvite(
PlayerbotAI* ai,
Player* bot,
Player* player,
Group* group
);
static bool BroadcastSuggestInstance(
PlayerbotAI* ai,
std::vector<std::string>& allowedInstances,
Player* bot
);
static bool BroadcastSuggestQuest(
PlayerbotAI* ai,
std::vector<uint32>& quests,
Player* bot
);
static bool BroadcastSuggestGrindMaterials(
PlayerbotAI* ai,
std::string item,
Player* bot
);
static bool BroadcastSuggestGrindReputation(
PlayerbotAI* ai,
std::vector<std::string> levels,
std::vector<std::string> allowedFactions,
Player* bot
);
static bool BroadcastSuggestSell(
PlayerbotAI* ai,
const ItemTemplate* proto,
uint32_t count,
uint32_t price,
Player* bot
);
static bool BroadcastSuggestSomething(
PlayerbotAI* ai,
Player* bot
);
static bool BroadcastSuggestSomethingToxic(
PlayerbotAI* ai,
Player* bot
);
static bool BroadcastSuggestToxicLinks(
PlayerbotAI* ai,
Player* bot
);
static bool BroadcastSuggestThunderfury(
PlayerbotAI* ai,
Player* bot
);
};

View File

@@ -344,11 +344,11 @@ void PlayerbotAI::UpdateAIInternal([[maybe_unused]] uint32 elapsed, bool minimal
std::list<ChatQueuedReply> delayedResponses;
while (!chatReplies.empty())
{
ChatQueuedReply holder = chatReplies.front();
ChatQueuedReply& holder = chatReplies.front();
time_t checkTime = holder.m_time;
if (checkTime && time(0) < checkTime)
{
delayedResponses.push_back(holder);
delayedResponses.push_back(std::move(holder));
chatReplies.pop();
continue;
}
@@ -420,11 +420,11 @@ void PlayerbotAI::HandleCommands()
std::list<ChatCommandHolder> delayed;
while (!chatCommands.empty())
{
ChatCommandHolder holder = chatCommands.front();
ChatCommandHolder& holder = chatCommands.front();
time_t checkTime = holder.GetTime();
if (checkTime && time(0) < checkTime)
{
delayed.push_back(holder);
delayed.push_back(std::move(holder));
chatCommands.pop();
continue;
}
@@ -940,6 +940,11 @@ void PlayerbotAI::HandleBotOutgoingPacket(WorldPacket const& packet)
p >> guid1 >> unused;
if (guid1.IsEmpty() || p.size() > p.DEFAULT_SIZE)
return;
if (p.GetOpcode() == SMSG_GM_MESSAGECHAT)
{
p >> textLen;
p >> name;
}
switch (msgtype)
{
@@ -965,6 +970,7 @@ void PlayerbotAI::HandleBotOutgoingPacket(WorldPacket const& packet)
bool isPaused = time(0) < lastChat;
bool shouldReply = false;
bool isFromFreeBot = false;
if (!sCharacterCache->GetCharacterNameByGuid(guid1, name)) {/*sould return or ?*/}
uint32 accountId = sCharacterCache->GetCharacterAccountIdByGuid(guid1);
isFromFreeBot = sPlayerbotAIConfig->IsInRandomAccountList(accountId);
bool isMentioned = message.find(bot->GetName()) != std::string::npos;
@@ -984,14 +990,24 @@ void PlayerbotAI::HandleBotOutgoingPacket(WorldPacket const& packet)
if (lang == LANG_ADDON)
return;
// several talk config option later
/*
TODO:
toxic link
legendary grind / thunderfury etc
*/
if (message.starts_with(sPlayerbotAIConfig->toxicLinksPrefix)
&& (GetChatHelper()->ExtractAllItemIds(message).size() > 0 || GetChatHelper()->ExtractAllQuestIds(message).size() > 0)
&& sPlayerbotAIConfig->toxicLinksRepliesChance)
{
if (urand(0, 50) > 0 || urand(1, 100) > sPlayerbotAIConfig->toxicLinksRepliesChance)
{
return;
}
}
else if ((GetChatHelper()->ExtractAllItemIds(message).count(19019) && sPlayerbotAIConfig->thunderfuryRepliesChance))
{
if (urand(0, 60) > 0 || urand(1, 100) > sPlayerbotAIConfig->thunderfuryRepliesChance)
{
return;
}
}
else
{
if (isFromFreeBot && urand(0, 20))
return;
@@ -1008,10 +1024,9 @@ void PlayerbotAI::HandleBotOutgoingPacket(WorldPacket const& packet)
if (urand(0, 20 + 10 * isMentioned))
return;
}
}
QueueChatResponse(msgtype, guid1, ObjectGuid(), message, chanName, name);
GetAiObjectContext()->GetValue<time_t>("last said", "chat")->Set(time(0) + urand(5, 25));
return;
}
}
@@ -4653,6 +4668,209 @@ Item* PlayerbotAI::FindOilFor(Item* weapon) const
return oil;
}
std::vector<Item*> PlayerbotAI::GetInventoryAndEquippedItems()
{
std::vector<Item*> items;
for (int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; ++i)
{
if (Bag* pBag = (Bag*)bot->GetItemByPos(INVENTORY_SLOT_BAG_0, i))
{
for (uint32 j = 0; j < pBag->GetBagSize(); ++j)
{
if (Item* pItem = pBag->GetItemByPos(j))
{
items.push_back(pItem);
}
}
}
}
for (int i = INVENTORY_SLOT_ITEM_START; i < INVENTORY_SLOT_ITEM_END; ++i)
{
if (Item* pItem = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, i))
{
items.push_back(pItem);
}
}
for (int i = KEYRING_SLOT_START; i < KEYRING_SLOT_END; ++i)
{
if (Item* pItem = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, i))
{
items.push_back(pItem);
}
}
for (uint8 slot = EQUIPMENT_SLOT_START; slot < EQUIPMENT_SLOT_END; slot++)
{
if (Item* pItem = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, slot))
{
items.push_back(pItem);
}
}
return items;
}
std::vector<Item*> PlayerbotAI::GetInventoryItems()
{
std::vector<Item*> items;
for (int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; ++i)
{
if (Bag* pBag = (Bag*)bot->GetItemByPos(INVENTORY_SLOT_BAG_0, i))
{
for (uint32 j = 0; j < pBag->GetBagSize(); ++j)
{
if (Item* pItem = pBag->GetItemByPos(j))
{
items.push_back(pItem);
}
}
}
}
for (int i = INVENTORY_SLOT_ITEM_START; i < INVENTORY_SLOT_ITEM_END; ++i)
{
if (Item* pItem = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, i))
{
items.push_back(pItem);
}
}
for (int i = KEYRING_SLOT_START; i < KEYRING_SLOT_END; ++i)
{
if (Item* pItem = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, i))
{
items.push_back(pItem);
}
}
return items;
}
uint32 PlayerbotAI::GetInventoryItemsCountWithId(uint32 itemId)
{
uint32 count = 0;
for (int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; ++i)
{
if (Bag* pBag = (Bag*)bot->GetItemByPos(INVENTORY_SLOT_BAG_0, i))
{
for (uint32 j = 0; j < pBag->GetBagSize(); ++j)
{
if (Item* pItem = pBag->GetItemByPos(j))
{
if (pItem->GetTemplate()->ItemId == itemId)
{
count += pItem->GetCount();
}
}
}
}
}
for (int i = INVENTORY_SLOT_ITEM_START; i < INVENTORY_SLOT_ITEM_END; ++i)
{
if (Item* pItem = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, i))
{
if (pItem->GetTemplate()->ItemId == itemId)
{
count += pItem->GetCount();
}
}
}
for (int i = KEYRING_SLOT_START; i < KEYRING_SLOT_END; ++i)
{
if (Item* pItem = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, i))
{
if (pItem->GetTemplate()->ItemId == itemId)
{
count += pItem->GetCount();
}
}
}
return count;
}
bool PlayerbotAI::HasItemInInventory(uint32 itemId)
{
for (int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; ++i)
{
if (Bag* pBag = (Bag*)bot->GetItemByPos(INVENTORY_SLOT_BAG_0, i))
{
for (uint32 j = 0; j < pBag->GetBagSize(); ++j)
{
if (Item* pItem = pBag->GetItemByPos(j))
{
if (pItem->GetTemplate()->ItemId == itemId)
{
return true;
}
}
}
}
}
for (int i = INVENTORY_SLOT_ITEM_START; i < INVENTORY_SLOT_ITEM_END; ++i)
{
if (Item* pItem = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, i))
{
if (pItem->GetTemplate()->ItemId == itemId)
{
return true;
}
}
}
for (int i = KEYRING_SLOT_START; i < KEYRING_SLOT_END; ++i)
{
if (Item* pItem = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, i))
{
if (pItem->GetTemplate()->ItemId == itemId)
{
return true;
}
}
}
return false;
}
std::vector<std::pair<const Quest*, uint32>> PlayerbotAI::GetCurrentQuestsRequiringItemId(uint32 itemId)
{
std::vector<std::pair<const Quest*, uint32>> result;
if (!itemId)
{
return result;
}
for (uint16 slot = 0; slot < MAX_QUEST_LOG_SIZE; ++slot)
{
uint32 questId = bot->GetQuestSlotQuestId(slot);
if (!questId)
continue;
QuestStatus status = bot->GetQuestStatus(questId);
const Quest* quest = sObjectMgr->GetQuestTemplate(questId);
for (uint8 i = 0; i < std::size(quest->RequiredItemId); ++i)
{
if (quest->RequiredItemId[i] == itemId)
{
result.push_back(std::pair(quest, quest->RequiredItemId[i]));
break;
}
}
}
return result;
}
// on self
void PlayerbotAI::ImbueItem(Item* item)
{
@@ -4807,9 +5025,9 @@ bool PlayerbotAI::IsInRealGuild()
return !(sPlayerbotAIConfig->IsInRandomAccountList(leaderAccount));
}
void PlayerbotAI::QueueChatResponse(uint8 msgtype, ObjectGuid guid1, ObjectGuid guid2, std::string message, std::string chanName, std::string name)
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(nullptr) + urand(inCombat ? 10 : 5, inCombat ? 25 : 15)));
chatReplies.push({ msgtype, guid1.GetCounter(), guid2.GetCounter(), message, chanName, name, time(nullptr) + urand(inCombat ? 10 : 5, inCombat ? 25 : 15) });
}
bool PlayerbotAI::EqualLowercaseName(std::string s1, std::string s2)

View File

@@ -364,7 +364,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 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);
@@ -525,6 +525,11 @@ class PlayerbotAI : public PlayerbotAIBase
bool EqualLowercaseName(std::string s1, std::string s2);
InventoryResult CanEquipItem(uint8 slot, uint16& dest, Item* pItem, bool swap, bool not_loading = true) const;
uint8 FindEquipSlot(ItemTemplate const* proto, uint32 slot, bool swap) const;
std::vector<Item*> GetInventoryAndEquippedItems();
std::vector<Item*> GetInventoryItems();
uint32 GetInventoryItemsCountWithId(uint32 itemId);
bool HasItemInInventory(uint32 itemId);
std::vector<std::pair<const Quest*, uint32>> GetCurrentQuestsRequiringItemId(uint32 itemId);
std::vector<const Quest*> GetAllCurrentQuests();
std::vector<const Quest*> GetCurrentIncompleteQuests();

View File

@@ -140,11 +140,85 @@ 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);
//////////////////////////// CHAT
enableBroadcasts = sConfigMgr->GetOption<bool>("AiPlayerbot.EnableBroadcasts", true);
randomBotTalk = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotTalk", false);
randomBotEmote = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotEmote", false);
randomBotSuggestDungeons = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotSuggestDungeons", true);
randomBotGuildTalk = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotGuildTalk", false);
randomBotSayWithoutMaster = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotSayWithoutMaster", false);
//broadcastChanceMaxValue is used in urand(1, broadcastChanceMaxValue) for broadcasts,
//lowering it will increase the chance, setting it to 0 will disable broadcasts
//for internal use, not intended to be change by the user
broadcastChanceMaxValue = enableBroadcasts ? 30000 : 0;
//all broadcast chances should be in range 1-broadcastChanceMaxValue, value of 0 will disable this particular broadcast
//setting value to max does not guarantee the broadcast, as there are some internal randoms as well
broadcastToGuildGlobalChance = sConfigMgr->GetOption<int32>("AiPlayerbot.BroadcastToGuildGlobalChance", 30000);
broadcastToWorldGlobalChance = sConfigMgr->GetOption<int32>("AiPlayerbot.BroadcastToWorldGlobalChance", 30000);
broadcastToGeneralGlobalChance = sConfigMgr->GetOption<int32>("AiPlayerbot.BroadcastToGeneralGlobalChance", 30000);
broadcastToTradeGlobalChance = sConfigMgr->GetOption<int32>("AiPlayerbot.BroadcastToTradeGlobalChance", 30000);
broadcastToLFGGlobalChance = sConfigMgr->GetOption<int32>("AiPlayerbot.BroadcastToLFGGlobalChance", 30000);
broadcastToLocalDefenseGlobalChance = sConfigMgr->GetOption<int32>("AiPlayerbot.BroadcastToLocalDefenseGlobalChance", 30000);
broadcastToWorldDefenseGlobalChance = sConfigMgr->GetOption<int32>("AiPlayerbot.BroadcastToWorldDefenseGlobalChance", 30000);
broadcastToGuildRecruitmentGlobalChance = sConfigMgr->GetOption<int32>("AiPlayerbot.BroadcastToGuildRecruitmentGlobalChance", 30000);
broadcastChanceLootingItemPoor = sConfigMgr->GetOption<int32>("AiPlayerbot.BroadcastChanceLootingItemPoor", 30);
broadcastChanceLootingItemNormal = sConfigMgr->GetOption<int32>("AiPlayerbot.BroadcastChanceLootingItemNormal", 300);
broadcastChanceLootingItemUncommon = sConfigMgr->GetOption<int32>("AiPlayerbot.BroadcastChanceLootingItemUncommon", 10000);
broadcastChanceLootingItemRare = sConfigMgr->GetOption<int32>("AiPlayerbot.BroadcastChanceLootingItemRare", 20000);
broadcastChanceLootingItemEpic = sConfigMgr->GetOption<int32>("AiPlayerbot.BroadcastChanceLootingItemEpic", 30000);
broadcastChanceLootingItemLegendary = sConfigMgr->GetOption<int32>("AiPlayerbot.BroadcastChanceLootingItemLegendary", 30000);
broadcastChanceLootingItemArtifact = sConfigMgr->GetOption<int32>("AiPlayerbot.BroadcastChanceLootingItemArtifact", 30000);
broadcastChanceQuestAccepted = sConfigMgr->GetOption<int32>("AiPlayerbot.BroadcastChanceQuestAccepted", 6000);
broadcastChanceQuestUpdateObjectiveCompleted = sConfigMgr->GetOption<int32>("AiPlayerbot.BroadcastChanceQuestUpdateObjectiveCompleted", 300);
broadcastChanceQuestUpdateObjectiveProgress = sConfigMgr->GetOption<int32>("AiPlayerbot.BroadcastChanceQuestUpdateObjectiveProgress", 300);
broadcastChanceQuestUpdateFailedTimer = sConfigMgr->GetOption<int32>("AiPlayerbot.BroadcastChanceQuestUpdateFailedTimer", 300);
broadcastChanceQuestUpdateComplete = sConfigMgr->GetOption<int32>("AiPlayerbot.BroadcastChanceQuestUpdateComplete", 1000);
broadcastChanceQuestTurnedIn = sConfigMgr->GetOption<int32>("AiPlayerbot.BroadcastChanceQuestTurnedIn", 10000);
broadcastChanceKillNormal = sConfigMgr->GetOption<int32>("AiPlayerbot.BroadcastChanceKillNormal", 30);
broadcastChanceKillElite = sConfigMgr->GetOption<int32>("AiPlayerbot.BroadcastChanceKillElite", 300);
broadcastChanceKillRareelite = sConfigMgr->GetOption<int32>("AiPlayerbot.BroadcastChanceKillRareelite", 3000);
broadcastChanceKillWorldboss = sConfigMgr->GetOption<int32>("AiPlayerbot.BroadcastChanceKillWorldboss", 20000);
broadcastChanceKillRare = sConfigMgr->GetOption<int32>("AiPlayerbot.BroadcastChanceKillRare", 10000);
broadcastChanceKillUnknown = sConfigMgr->GetOption<int32>("AiPlayerbot.BroadcastChanceKillUnknown", 100);
broadcastChanceKillPet = sConfigMgr->GetOption<int32>("AiPlayerbot.BroadcastChanceKillPet", 10);
broadcastChanceKillPlayer = sConfigMgr->GetOption<int32>("AiPlayerbot.BroadcastChanceKillPlayer", 30);
broadcastChanceLevelupGeneric = sConfigMgr->GetOption<int32>("AiPlayerbot.BroadcastChanceLevelupGeneric", 20000);
broadcastChanceLevelupTenX = sConfigMgr->GetOption<int32>("AiPlayerbot.BroadcastChanceLevelupTenX", 30000);
broadcastChanceLevelupMaxLevel = sConfigMgr->GetOption<int32>("AiPlayerbot.BroadcastChanceLevelupMaxLevel", 30000);
broadcastChanceSuggestInstance = sConfigMgr->GetOption<int32>("AiPlayerbot.BroadcastChanceSuggestInstance", 5000);
broadcastChanceSuggestQuest = sConfigMgr->GetOption<int32>("AiPlayerbot.BroadcastChanceSuggestQuest", 10000);
broadcastChanceSuggestGrindMaterials = sConfigMgr->GetOption<int32>("AiPlayerbot.BroadcastChanceSuggestGrindMaterials", 5000);
broadcastChanceSuggestGrindReputation = sConfigMgr->GetOption<int32>("AiPlayerbot.BroadcastChanceSuggestGrindReputation", 5000);
broadcastChanceSuggestSell = sConfigMgr->GetOption<int32>("AiPlayerbot.BroadcastChanceSuggestSell", 300);
broadcastChanceSuggestSomething = sConfigMgr->GetOption<int32>("AiPlayerbot.BroadcastChanceSuggestSomething", 30000);
broadcastChanceSuggestSomethingToxic = sConfigMgr->GetOption<int32>("AiPlayerbot.BroadcastChanceSuggestSomethingToxic", 0);
broadcastChanceSuggestToxicLinks = sConfigMgr->GetOption<int32>("AiPlayerbot.BroadcastChanceSuggestToxicLinks", 0);
toxicLinksPrefix = sConfigMgr->GetOption<std::string>("AiPlayerbot.ToxicLinksPrefix", "gnomes");
broadcastChanceSuggestThunderfury = sConfigMgr->GetOption<int32>("AiPlayerbot.BroadcastChanceSuggestThunderfury", 1);
//does not depend on global chance
broadcastChanceGuildManagement = sConfigMgr->GetOption<int32>("AiPlayerbot.BroadcastChanceGuildManagement", 30000);
////////////////////////////
toxicLinksRepliesChance = sConfigMgr->GetOption<int32>("AiPlayerbot.ToxicLinksRepliesChance", 30); //0-100
thunderfuryRepliesChance = sConfigMgr->GetOption<int32>("AiPlayerbot.ThunderfuryRepliesChance", 40); //0-100
guildRepliesRate = sConfigMgr->GetOption<int32>("AiPlayerbot.GuildRepliesRate", 100); //0-100
suggestDungeonsInLowerCaseRandomly = sConfigMgr->GetOption<bool>("AiPlayerbot.SuggestDungeonsInLowerCaseRandomly", false);
////////////////////////// !CHAT
randomBotJoinBG = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotJoinBG", true);
randomBotAutoJoinBG = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotAutoJoinBG", false);
randomBotAutoJoinWarsongBracket = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotAutoJoinWarsongBracket", 14);
@@ -337,8 +411,6 @@ bool PlayerbotAIConfig::Initialize()
autoDoQuests = sConfigMgr->GetOption<bool>("AiPlayerbot.AutoDoQuests", false);
syncLevelWithPlayers = sConfigMgr->GetOption<bool>("AiPlayerbot.SyncLevelWithPlayers", false);
freeFood = sConfigMgr->GetOption<bool>("AiPlayerbot.FreeFood", true);
randomBotSayWithoutMaster = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotSayWithoutMaster", false);
sayWhenCollectingItems = sConfigMgr->GetOption<bool>("AiPlayerbot.SayWhenCollectingItems", true);
randomBotGroupNearby = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotGroupNearby", true);
// arena

View File

@@ -95,11 +95,78 @@ class PlayerbotAIConfig
uint32 randomBotsPerInterval;
uint32 minRandomBotsPriceChangeInterval, maxRandomBotsPriceChangeInterval;
bool randomBotJoinLfg;
// chat
bool randomBotTalk;
bool randomBotEmote;
bool randomBotSuggestDungeons;
bool randomBotGuildTalk;
bool enableBroadcasts;
bool enableGreet;
bool randomBotSayWithoutMaster;
uint32 broadcastChanceMaxValue;
uint32 broadcastToGuildGlobalChance;
uint32 broadcastToWorldGlobalChance;
uint32 broadcastToGeneralGlobalChance;
uint32 broadcastToTradeGlobalChance;
uint32 broadcastToLFGGlobalChance;
uint32 broadcastToLocalDefenseGlobalChance;
uint32 broadcastToWorldDefenseGlobalChance;
uint32 broadcastToGuildRecruitmentGlobalChance;
uint32 broadcastChanceLootingItemPoor;
uint32 broadcastChanceLootingItemNormal;
uint32 broadcastChanceLootingItemUncommon;
uint32 broadcastChanceLootingItemRare;
uint32 broadcastChanceLootingItemEpic;
uint32 broadcastChanceLootingItemLegendary;
uint32 broadcastChanceLootingItemArtifact;
uint32 broadcastChanceQuestAccepted;
uint32 broadcastChanceQuestUpdateObjectiveCompleted;
uint32 broadcastChanceQuestUpdateObjectiveProgress;
uint32 broadcastChanceQuestUpdateFailedTimer;
uint32 broadcastChanceQuestUpdateComplete;
uint32 broadcastChanceQuestTurnedIn;
uint32 broadcastChanceKillNormal;
uint32 broadcastChanceKillElite;
uint32 broadcastChanceKillRareelite;
uint32 broadcastChanceKillWorldboss;
uint32 broadcastChanceKillRare;
uint32 broadcastChanceKillUnknown;
uint32 broadcastChanceKillPet;
uint32 broadcastChanceKillPlayer;
uint32 broadcastChanceLevelupGeneric;
uint32 broadcastChanceLevelupTenX;
uint32 broadcastChanceLevelupMaxLevel;
uint32 broadcastChanceSuggestInstance;
uint32 broadcastChanceSuggestQuest;
uint32 broadcastChanceSuggestGrindMaterials;
uint32 broadcastChanceSuggestGrindReputation;
uint32 broadcastChanceSuggestSell;
uint32 broadcastChanceSuggestSomething;
uint32 broadcastChanceSuggestSomethingToxic;
uint32 broadcastChanceSuggestToxicLinks;
std::string toxicLinksPrefix;
uint32 toxicLinksRepliesChance;
uint32 broadcastChanceSuggestThunderfury;
uint32 thunderfuryRepliesChance;
uint32 broadcastChanceGuildManagement;
uint32 guildRepliesRate;
bool suggestDungeonsInLowerCaseRandomly;
// --
bool randomBotJoinBG;
bool randomBotAutoJoinBG;
uint32 randomBotAutoJoinWarsongBracket;
@@ -181,8 +248,6 @@ class PlayerbotAIConfig
uint32 commandServerPort;
bool perfMonEnabled;
bool enableGreet;
bool summonWhenGroup;
bool randomBotShowHelmet;
bool randomBotShowCloak;
@@ -212,8 +277,6 @@ class PlayerbotAIConfig
bool freeFood;
bool autoLearnQuestSpells;
bool autoTeleportForLevel;
bool randomBotSayWithoutMaster;
bool sayWhenCollectingItems;
bool randomBotGroupNearby;
uint32 tweakValue; //Debugging config

View File

@@ -6,7 +6,7 @@
#include "Event.h"
#include "PlayerbotFactory.h"
#include "Playerbots.h"
#include "GuildMgr.h"
#include "BroadcastHelper.h"
bool AutoLearnSpellAction::Execute(Event event)
{
@@ -30,18 +30,12 @@ bool AutoLearnSpellAction::Execute(Event event)
void AutoLearnSpellAction::LearnSpells(std::ostringstream* out)
{
BroadcastHelper::BroadcastLevelup(botAI, bot);
if (sPlayerbotAIConfig->autoLearnTrainerSpells)
LearnTrainerSpells(out);
if (sPlayerbotAIConfig->autoLearnQuestSpells)
LearnQuestSpells(out);
if (sPlayerbotAIConfig->randomBotGuildTalk)
{
std::map<std::string, std::string> args;
args["%my_level"] = std::to_string(bot->GetLevel());
botAI->SayToGuild(BOT_TEXT2("broadcast_levelup_generic", args));
}
}
void AutoLearnSpellAction::LearnTrainerSpells(std::ostringstream* out)

View File

@@ -7,6 +7,7 @@
#include "GuildPackets.h"
#include "Playerbots.h"
#include "ServerFacade.h"
#include "BroadcastHelper.h"
Player* GuidManageAction::GetPlayer(Event event)
{
@@ -167,6 +168,7 @@ bool GuildManageNearbyAction::Execute(Event event)
{
if (!urand(0, 10))
{
BroadcastHelper::BroadcastGuildMemberPromotion(botAI, bot, player);
botAI->DoSpecificAction("guild promote", Event("guild management", guid), true);
continue;

View File

@@ -7,6 +7,7 @@
#include "GuildMgr.h"
#include "Playerbots.h"
#include "ServerFacade.h"
#include "BroadcastHelper.h"
bool InviteToGroupAction::Execute(Event event)
{
@@ -76,6 +77,26 @@ bool InviteNearbyToGroupAction::Execute(Event event)
if (sServerFacade->GetDistance2d(bot, player) > sPlayerbotAIConfig->sightDistance)
continue;
Group* group = bot->GetGroup();
Guild* guild = sGuildMgr->GetGuildById(bot->GetGuildId());
if (!botAI->HasActivePlayerMaster())
{
if (guild && bot->GetGuildId() == player->GetGuildId())
{
BroadcastHelper::BroadcastGuildGroupOrRaidInvite(botAI, bot, player, group);
}
else
{
std::map<std::string, std::string> placeholders;
placeholders["%player"] = player->GetName();
if (group && group->isRaidGroup())
bot->Say(BOT_TEXT2("join_raid", placeholders), (bot->GetTeamId() == TEAM_ALLIANCE ? LANG_COMMON : LANG_ORCISH));
else
bot->Say(BOT_TEXT2("join_group", placeholders), (bot->GetTeamId() == TEAM_ALLIANCE ? LANG_COMMON : LANG_ORCISH));
}
}
return Invite(player);
}
@@ -125,6 +146,8 @@ std::vector<Player*> InviteGuildToGroupAction::getGuildMembers()
bool InviteGuildToGroupAction::Execute(Event event)
{
Guild* guild = sGuildMgr->GetGuildById(bot->GetGuildId());
for (auto& member : getGuildMembers())
{
Player* player = member;
@@ -165,6 +188,8 @@ bool InviteGuildToGroupAction::Execute(Event event)
if (!botAI && sServerFacade->GetDistance2d(bot, player) > sPlayerbotAIConfig->sightDistance)
continue;
Group* group = bot->GetGroup();
BroadcastHelper::BroadcastGuildGroupOrRaidInvite(botAI, bot, player, group);
return Invite(player);
}

View File

@@ -13,6 +13,7 @@
#include "Playerbots.h"
#include "ServerFacade.h"
#include "GuildMgr.h"
#include "BroadcastHelper.h"
bool LootAction::Execute(Event event)
{
@@ -417,19 +418,7 @@ bool StoreLootAction::Execute(Event event)
if (proto->Quality >= ITEM_QUALITY_RARE && !urand(0, 1) && botAI->HasStrategy("emote", BOT_STATE_NON_COMBAT))
botAI->PlayEmote(TEXT_EMOTE_CHEER);
if (sPlayerbotAIConfig->randomBotGuildTalk && urand(0, 10) && proto->Quality >= ITEM_QUALITY_RARE)
{
std::map<std::string, std::string> args;
args["%item"] = chat->FormatItem(proto);
botAI->SayToGuild(BOT_TEXT2("loot_command", args));
}
// std::ostringstream out;
// out << "Looting " << chat->FormatItem(proto);
// botAI->TellMasterNoFacing(out.str());
//ItemUsage usage = AI_VALUE2(ItemUsage, "item usage", proto->ItemId);
//LOG_ERROR("playerbots", "Bot {} is looting {} {} for usage {}.", bot->GetName().c_str(), itemcount, proto->Name1.c_str(), usage);
BroadcastHelper::BroadcastLootingItem(botAI, bot, proto);
}
AI_VALUE(LootObjectStack*, "available loot")->Remove(guid);

View File

@@ -10,64 +10,6 @@
bool QueryItemUsageAction::Execute(Event event)
{
if (!GetMaster() && !sPlayerbotAIConfig->randomBotSayWithoutMaster)
return false;
if (!sPlayerbotAIConfig->sayWhenCollectingItems)
return false;
WorldPacket& data = event.getPacket();
if (!data.empty())
{
data.rpos(0);
ObjectGuid guid;
data >> guid;
if (guid != bot->GetGUID())
return false;
uint32 received;
uint32 created;
uint32 isShowChatMessage;
uint32 notUsed;
uint32 itemId;
uint32 suffixFactor;
uint32 itemRandomPropertyId;
uint32 count;
uint32 invCount;
uint8 bagSlot;
data >> received; // 0=looted, 1=from npc
data >> created; // 0=received, 1=created
data >> isShowChatMessage; // IsShowChatMessage
data >> bagSlot; // item slot, but when added to stack: 0xFFFFFFFF
data >> notUsed;
data >> itemId;
data >> suffixFactor;
data >> itemRandomPropertyId;
data >> count;
// data >> invCount; // [-ZERO] count of items in inventory
ItemTemplate const* item = sObjectMgr->GetItemTemplate(itemId);
if (!item)
return false;
bot->Say(QueryItem(item, count, GetCount(item)), LANG_UNIVERSAL);
return true;
}
std::string const text = event.getParam();
ItemIds items = chat->parseItems(text);
for (uint32 itemId : items)
{
ItemTemplate const* item = sObjectMgr->GetItemTemplate(itemId);
if (!item)
continue;
botAI->TellMaster(QueryItem(item, 0, GetCount(item)));
}
return true;
}

View File

@@ -8,6 +8,7 @@
#include "Playerbots.h"
#include "ReputationMgr.h"
#include "ServerFacade.h"
#include "BroadcastHelper.h"
bool QuestAction::Execute(Event event)
{
@@ -226,6 +227,7 @@ bool QuestAction::AcceptQuest(Quest const* quest, ObjectGuid questGiver)
if (bot->GetQuestStatus(questId) != QUEST_STATUS_NONE && bot->GetQuestStatus(questId) != QUEST_STATUS_REWARDED)
{
BroadcastHelper::BroadcastQuestAccepted(botAI, bot, quest);
out << "Accepted " << chat->FormatQuest(quest);
botAI->TellMaster(out);
return true;
@@ -253,13 +255,17 @@ bool QuestUpdateCompleteAction::Execute(Event event)
Quest const* qInfo = sObjectMgr->GetQuestTemplate(questId);
if (qInfo)
{
const std::string text_quest = ChatHelper::FormatQuest(qInfo);
std::map<std::string, std::string> placeholders;
const auto format = ChatHelper::FormatQuest(qInfo);
placeholders["%quest_link"] = format;
if (botAI->HasStrategy("debug quest", BotState::BOT_STATE_NON_COMBAT) || botAI->HasStrategy("debug rpg", BotState::BOT_STATE_COMBAT))
{
LOG_INFO("playerbots", "{} => Quest [ {} ] completed", bot->GetName(), qInfo->GetTitle());
bot->Say("Quest [ " + text_quest + " ] completed", LANG_UNIVERSAL);
bot->Say("Quest [ " + format + " ] completed", LANG_UNIVERSAL);
}
botAI->TellMasterNoFacing("Quest completed " + text_quest);
botAI->TellMasterNoFacing("Quest completed " + format);
BroadcastHelper::BroadcastQuestUpdateComplete(botAI, bot, qInfo);
}
return true;
@@ -276,9 +282,38 @@ bool QuestUpdateAddKillAction::Execute(Event event)
uint32 entry, questId, available, required;
p >> questId >> entry >> available >> required;
std::stringstream ss;
ss << "Update progression kill questid {" << std::to_string(questId) << "} {" << std::to_string(available) << "} / {" << std::to_string(required) << "}";
botAI->TellMasterNoFacing(ss.str());
const Quest* qInfo = sObjectMgr->GetQuestTemplate(questId);
if (qInfo && (entry & 0x80000000))
{
entry &= 0x7FFFFFFF;
const GameObjectTemplate* info = sObjectMgr->GetGameObjectTemplate(entry);
if (info)
BroadcastHelper::BroadcastQuestUpdateAddKill(botAI, bot, qInfo, available, required, info->name);
}
else if (qInfo)
{
CreatureTemplate const* info = sObjectMgr->GetCreatureTemplate(entry);
if (info)
{
BroadcastHelper::BroadcastQuestUpdateAddKill(botAI, bot, qInfo, available, required, info->Name);
}
}
else
{
std::map<std::string, std::string> placeholders;
placeholders["%quest_id"] = questId;
placeholders["%available"] = available;
placeholders["%required"] = required;
if (botAI->HasStrategy("debug quest", BotState::BOT_STATE_COMBAT) || botAI->HasStrategy("debug quest", BotState::BOT_STATE_NON_COMBAT))
{
LOG_INFO("playerbots", "{} => {}", bot->GetName(), BOT_TEXT2("%available/%required for questId: %quest_id", placeholders));
botAI->Say(BOT_TEXT2("%available/%required for questId: %quest_id", placeholders));
}
botAI->TellMasterNoFacing(BOT_TEXT2("%available/%required for questId: %quest_id", placeholders));
}
return false;
}
@@ -292,10 +327,28 @@ bool QuestUpdateAddItemAction::Execute(Event event)
Player* requester = event.getOwner() ? event.getOwner() : GetMaster();
auto const* itemPrototype = sObjectMgr->GetItemTemplate(itemId);
if (itemPrototype)
{
std::map<std::string, std::string> placeholders;
placeholders["%item_link"] = botAI->GetChatHelper()->FormatItem(itemPrototype);
uint32 availableItemsCount = botAI->GetInventoryItemsCountWithId(itemId);
placeholders["%quest_obj_available"] = std::to_string(availableItemsCount);
std::stringstream ss;
ss << "Update progression itemid {" << std::to_string(itemId) << "} count: {" << std::to_string(count) << "}";
botAI->TellMasterNoFacing(ss.str());
for (const auto& pair : botAI->GetCurrentQuestsRequiringItemId(itemId))
{
placeholders["%quest_link"] = chat->FormatQuest(pair.first);
uint32 requiredItemsCount = pair.second;
placeholders["%quest_obj_required"] = std::to_string(requiredItemsCount);
if (botAI->HasStrategy("debug quest", BotState::BOT_STATE_COMBAT) || botAI->HasStrategy("debug quest", BotState::BOT_STATE_NON_COMBAT))
{
const auto text = BOT_TEXT2("%quest_link - %item_link %quest_obj_available/%quest_obj_required", placeholders);
botAI->Say(text);
LOG_INFO("playerbots", "{} => {}", bot->GetName(), text);
}
BroadcastHelper::BroadcastQuestUpdateAddItem(botAI, bot, pair.first, availableItemsCount, requiredItemsCount, itemPrototype);
}
}
return false;
}
@@ -320,7 +373,10 @@ bool QuestUpdateFailedTimerAction::Execute(Event event)
if (qInfo)
{
botAI->TellMaster("Failed timer for " + botAI->GetChatHelper()->FormatQuest(qInfo) +", abandoning");
std::map<std::string, std::string> placeholders;
placeholders["%quest_link"] = botAI->GetChatHelper()->FormatQuest(qInfo);
botAI->TellMaster(BOT_TEXT2("Failed timer for %quest_link, abandoning", placeholders));
BroadcastHelper::BroadcastQuestUpdateFailedTimer(botAI, bot, qInfo);
}
else
{

View File

@@ -122,7 +122,7 @@ bool SayAction::isUseful()
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)
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 = "";
@@ -165,7 +165,7 @@ void ChatReplyAction::ChatReplyDo(Player* bot, uint32 type, uint32 guid1, uint32
}
//toxic links
if (msg.starts_with("gnomes")
if (msg.starts_with(sPlayerbotAIConfig->toxicLinksPrefix)
&& (GET_PLAYERBOT_AI(bot)->GetChatHelper()->ExtractAllItemIds(msg).size() > 0 || GET_PLAYERBOT_AI(bot)->GetChatHelper()->ExtractAllQuestIds(msg).size() > 0))
{
HandleToxicLinksReply(bot, chatChannelSource, msg, name);
@@ -179,10 +179,11 @@ void ChatReplyAction::ChatReplyDo(Player* bot, uint32 type, uint32 guid1, uint32
return;
}
SendGeneralResponse(bot, chatChannelSource, GenerateReplyMessage(bot, msg, guid1, name), name);
auto messageRepy = GenerateReplyMessage(bot, msg, guid1, name);
SendGeneralResponse(bot, chatChannelSource, messageRepy, name);
}
bool ChatReplyAction::HandleThunderfuryReply(Player* bot, ChatChannelSource chatChannelSource, std::string msg, std::string name)
bool ChatReplyAction::HandleThunderfuryReply(Player* bot, ChatChannelSource chatChannelSource, std::string& msg, std::string& name)
{
std::map<std::string, std::string> placeholders;
const auto thunderfury = sObjectMgr->GetItemTemplate(19019);
@@ -208,17 +209,164 @@ bool ChatReplyAction::HandleThunderfuryReply(Player* bot, ChatChannelSource chat
return true;
}
bool ChatReplyAction::HandleToxicLinksReply(Player* bot, ChatChannelSource chatChannelSource, std::string msg, std::string name)
bool ChatReplyAction::HandleToxicLinksReply(Player* bot, ChatChannelSource chatChannelSource, std::string& msg, std::string& name)
{
//quests
std::vector<uint32> incompleteQuests;
for (uint16 slot = 0; slot < MAX_QUEST_LOG_SIZE; ++slot)
{
uint32 questId = bot->GetQuestSlotQuestId(slot);
if (!questId)
continue;
QuestStatus status = bot->GetQuestStatus(questId);
if (status == QUEST_STATUS_INCOMPLETE || status == QUEST_STATUS_NONE)
incompleteQuests.push_back(questId);
}
//items
std::vector<Item*> botItems = GET_PLAYERBOT_AI(bot)->GetInventoryAndEquippedItems();
std::map<std::string, std::string> placeholders;
placeholders["%random_inventory_item_link"] = botItems.size() > 0 ? GET_PLAYERBOT_AI(bot)->GetChatHelper()->FormatItem(botItems[rand() % botItems.size()]->GetTemplate()) : BOT_TEXT1("string_empty_link");
placeholders["%prefix"] = sPlayerbotAIConfig->toxicLinksPrefix;
if (incompleteQuests.size() > 0)
{
Quest const* quest = sObjectMgr->GetQuestTemplate(incompleteQuests[rand() % incompleteQuests.size()]);
placeholders["%random_taken_quest_or_item_link"] = GET_PLAYERBOT_AI(bot)->GetChatHelper()->FormatQuest(quest);
}
else
{
placeholders["%random_taken_quest_or_item_link"] = placeholders["%random_inventory_item_link"];
}
placeholders["%my_role"] = GET_PLAYERBOT_AI(bot)->GetChatHelper()->FormatClass(bot->getClass());
AreaTableEntry const* current_area = GET_PLAYERBOT_AI(bot)->GetCurrentArea();
AreaTableEntry const* current_zone = GET_PLAYERBOT_AI(bot)->GetCurrentZone();
placeholders["%area_name"] = current_area ? GET_PLAYERBOT_AI(bot)->GetLocalizedAreaName(current_area) : BOT_TEXT1("string_unknown_area");
placeholders["%zone_name"] = current_zone ? GET_PLAYERBOT_AI(bot)->GetLocalizedAreaName(current_zone) : BOT_TEXT1("string_unknown_area");
placeholders["%my_class"] = GET_PLAYERBOT_AI(bot)->GetChatHelper()->FormatClass(bot->getClass());
placeholders["%my_race"] = GET_PLAYERBOT_AI(bot)->GetChatHelper()->FormatRace(bot->getRace());
placeholders["%my_level"] = std::to_string(bot->GetLevel());
switch (chatChannelSource)
{
case ChatChannelSource::SRC_WORLD:
{
GET_PLAYERBOT_AI(bot)->SayToWorld(BOT_TEXT2("suggest_toxic_links", placeholders));
break;
}
case ChatChannelSource::SRC_GENERAL:
{
GET_PLAYERBOT_AI(bot)->SayToChannel(BOT_TEXT2("suggest_toxic_links", placeholders), ChatChannelId::GENERAL);
break;
}
case ChatChannelSource::SRC_GUILD:
{
GET_PLAYERBOT_AI(bot)->SayToGuild(BOT_TEXT2("suggest_toxic_links", placeholders));
break;
}
}
GET_PLAYERBOT_AI(bot)->GetAiObjectContext()->GetValue<time_t>("last said", "chat")->Set(time(0) + urand(5, 60));
return true;
}
bool ChatReplyAction::HandleWTBItemsReply(Player* bot, ChatChannelSource chatChannelSource, std::string msg, std::string name)
bool ChatReplyAction::HandleWTBItemsReply(Player* bot, ChatChannelSource chatChannelSource, std::string& msg, std::string& name)
{
auto messageItemIds = GET_PLAYERBOT_AI(bot)->GetChatHelper()->ExtractAllItemIds(msg);
if (messageItemIds.empty())
{
return false;
}
std::set<uint32> matchingItemIds;
for (auto messageItemId : messageItemIds)
{
if (GET_PLAYERBOT_AI(bot)->HasItemInInventory(messageItemId))
{
matchingItemIds.insert(messageItemId);
}
}
if (!matchingItemIds.empty())
{
std::map<std::string, std::string> placeholders;
placeholders["%other_name"] = name;
AreaTableEntry const* current_area = GET_PLAYERBOT_AI(bot)->GetCurrentArea();
AreaTableEntry const* current_zone = GET_PLAYERBOT_AI(bot)->GetCurrentZone();
placeholders["%area_name"] = current_area ? GET_PLAYERBOT_AI(bot)->GetLocalizedAreaName(current_area) : BOT_TEXT1("string_unknown_area");
placeholders["%zone_name"] = current_zone ? GET_PLAYERBOT_AI(bot)->GetLocalizedAreaName(current_zone) : BOT_TEXT1("string_unknown_area");
placeholders["%my_class"] = GET_PLAYERBOT_AI(bot)->GetChatHelper()->FormatClass(bot->getClass());
placeholders["%my_race"] = GET_PLAYERBOT_AI(bot)->GetChatHelper()->FormatRace(bot->getRace());
placeholders["%my_level"] = std::to_string(bot->GetLevel());
placeholders["%my_role"] = GET_PLAYERBOT_AI(bot)->GetChatHelper()->FormatClass(bot->GetSpec());
placeholders["%formatted_item_links"] = "";
for (auto matchingItemId : matchingItemIds)
{
ItemTemplate const* proto = sObjectMgr->GetItemTemplate(matchingItemId);
placeholders["%formatted_item_links"] += GET_PLAYERBOT_AI(bot)->GetChatHelper()->FormatItem(proto, GET_PLAYERBOT_AI(bot)->GetInventoryItemsCountWithId(matchingItemId));
placeholders["%formatted_item_links"] += " ";
}
switch (chatChannelSource)
{
case ChatChannelSource::SRC_WORLD:
{
//may reply to the same channel or whisper
if (urand(0, 1))
{
std::string responseMessage = BOT_TEXT2("response_wtb_items_channel", placeholders);
GET_PLAYERBOT_AI(bot)->SayToWorld(responseMessage);
}
else
{
std::string responseMessage = BOT_TEXT2("response_wtb_items_whisper", placeholders);
GET_PLAYERBOT_AI(bot)->Whisper(responseMessage, name);
}
break;
}
case ChatChannelSource::SRC_GENERAL:
{
//may reply to the same channel or whisper
if (urand(0, 1))
{
std::string responseMessage = BOT_TEXT2("response_wtb_items_channel", placeholders);
GET_PLAYERBOT_AI(bot)->SayToChannel(responseMessage, ChatChannelId::GENERAL);
}
else
{
std::string responseMessage = BOT_TEXT2("response_wtb_items_whisper", placeholders);
GET_PLAYERBOT_AI(bot)->Whisper(responseMessage, name);
}
break;
}
case ChatChannelSource::SRC_TRADE:
{
//may reply to the same channel or whisper
if (urand(0, 1))
{
std::string responseMessage = BOT_TEXT2("response_wtb_items_channel", placeholders);
GET_PLAYERBOT_AI(bot)->SayToChannel(responseMessage, ChatChannelId::TRADE);
}
else
{
std::string responseMessage = BOT_TEXT2("response_wtb_items_whisper", placeholders);
GET_PLAYERBOT_AI(bot)->Whisper(responseMessage, name);
}
break;
}
}
GET_PLAYERBOT_AI(bot)->GetAiObjectContext()->GetValue<time_t>("last said", "chat")->Set(time(0) + urand(5, 60));
}
return true;
}
bool ChatReplyAction::HandleLFGQuestsReply(Player* bot, ChatChannelSource chatChannelSource, std::string msg, std::string name)
bool ChatReplyAction::HandleLFGQuestsReply(Player* bot, ChatChannelSource chatChannelSource, std::string& msg, std::string& name)
{
auto messageQuestIds = GET_PLAYERBOT_AI(bot)->GetChatHelper()->ExtractAllQuestIds(msg);
@@ -303,7 +451,7 @@ bool ChatReplyAction::HandleLFGQuestsReply(Player* bot, ChatChannelSource chatCh
return true;
}
bool ChatReplyAction::SendGeneralResponse(Player* bot, ChatChannelSource chatChannelSource, std::string responseMessage, std::string name)
bool ChatReplyAction::SendGeneralResponse(Player* bot, ChatChannelSource chatChannelSource, std::string& responseMessage, std::string& name)
{
// send responds
switch (chatChannelSource)
@@ -341,13 +489,11 @@ bool ChatReplyAction::SendGeneralResponse(Player* bot, ChatChannelSource chatCha
case ChatChannelSource::SRC_LOOKING_FOR_GROUP:
{
//do not reply to the chat
//may whisper
break;
}
case ChatChannelSource::SRC_GUILD_RECRUITMENT:
{
//do not reply to the chat
//may whisper
break;
}
case ChatChannelSource::SRC_WHISPER:
@@ -378,7 +524,7 @@ bool ChatReplyAction::SendGeneralResponse(Player* bot, ChatChannelSource chatCha
return true;
}
std::string ChatReplyAction::GenerateReplyMessage(Player* bot, std::string incomingMessage, uint32 guid1, std::string name)
std::string ChatReplyAction::GenerateReplyMessage(Player* bot, std::string& incomingMessage, uint32& guid1, std::string& name)
{
ChatReplyType replyType = REPLY_NOT_UNDERSTAND; // default not understand

View File

@@ -32,12 +32,12 @@ public:
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);
static bool HandleThunderfuryReply(Player* bot, ChatChannelSource chatChannelSource, std::string msg, std::string name);
static bool HandleToxicLinksReply(Player* bot, ChatChannelSource chatChannelSource, std::string msg, std::string name);
static bool HandleWTBItemsReply(Player* bot, ChatChannelSource chatChannelSource, std::string msg, std::string name);
static bool HandleLFGQuestsReply(Player* bot, ChatChannelSource chatChannelSource, std::string msg, std::string name);
static bool SendGeneralResponse(Player* bot, ChatChannelSource chatChannelSource, std::string responseMessage, std::string name);
static std::string GenerateReplyMessage(Player* bot, std::string incomingMessage, uint32 guid1, std::string name);
static void ChatReplyDo(Player* bot, uint32& type, uint32& guid1, uint32& guid2, std::string& msg, std::string& chanName, std::string& name);
static bool HandleThunderfuryReply(Player* bot, ChatChannelSource chatChannelSource, std::string& msg, std::string& name);
static bool HandleToxicLinksReply(Player* bot, ChatChannelSource chatChannelSource, std::string& msg, std::string& name);
static bool HandleWTBItemsReply(Player* bot, ChatChannelSource chatChannelSource, std::string& msg, std::string& name);
static bool HandleLFGQuestsReply(Player* bot, ChatChannelSource chatChannelSource, std::string& msg, std::string& name);
static bool SendGeneralResponse(Player* bot, ChatChannelSource chatChannelSource, std::string& responseMessage, std::string& name);
static std::string GenerateReplyMessage(Player* bot, std::string& incomingMessage, uint32& guid1, std::string& name);
};
#endif

View File

@@ -11,8 +11,8 @@
#include "ChatHelper.h"
#include "Playerbots.h"
#include "PlayerbotTextMgr.h"
#include "GuildMgr.h"
#include "Config.h"
#include "BroadcastHelper.h"
#include <functional>
@@ -36,6 +36,8 @@ SuggestWhatToDoAction::SuggestWhatToDoAction(PlayerbotAI* botAI, std::string con
suggestions.push_back(std::bind(&SuggestWhatToDoAction::grindReputation, this));
suggestions.push_back(std::bind(&SuggestWhatToDoAction::something, this));
suggestions.push_back(std::bind(&SuggestWhatToDoAction::grindMaterials, this));
suggestions.push_back(std::bind(&SuggestWhatToDoAction::somethingToxic, this));
suggestions.push_back(std::bind(&SuggestWhatToDoAction::toxicLinks, this));
}
bool SuggestWhatToDoAction::isUseful()
@@ -85,15 +87,7 @@ void SuggestWhatToDoAction::specificQuest()
if (quests.empty())
return;
uint32 index = rand() % quests.size();
Quest const* quest = sObjectMgr->GetQuestTemplate(quests[index]);
std::map<std::string, std::string> placeholders;
placeholders["%role"] = chat->FormatClass(bot, AiFactory::GetPlayerSpecTab(bot));
placeholders["%quest"] = chat->FormatQuest(quest);
spam(BOT_TEXT2("suggest_quest", placeholders), urand(0, 1) ? eTalkType::General : 0, !urand(0, 2), !urand(0, 3));
BroadcastHelper::BroadcastSuggestQuest(botAI, quests, bot);
}
void SuggestWhatToDoAction::grindMaterials()
@@ -187,123 +181,34 @@ void SuggestWhatToDoAction::grindReputation()
levels.push_back("exalted");
std::vector<std::string> allowedFactions;
for (const auto& i : factions)
for (auto it : factions)
{
if (bot->GetLevel() >= i.second)
allowedFactions.push_back(i.first);
if ((int)bot->GetLevel() >= it.second) allowedFactions.push_back(it.first);
}
if (allowedFactions.empty())
return;
std::map<std::string, std::string> placeholders;
placeholders["%role"] = chat->FormatClass(bot, AiFactory::GetPlayerSpecTab(bot));
placeholders["%level"] = levels[urand(0, 2)];
if (allowedFactions.empty()) return;
std::ostringstream rnd;
rnd << urand(1, 5) << "K";
placeholders["%rndK"] = rnd.str();
std::ostringstream itemout;
// itemout << "|c004040b0" << allowedFactions[urand(0, allowedFactions.size() - 1)] << "|r";
itemout << allowedFactions[urand(0, allowedFactions.size() - 1)];
placeholders["%faction"] = itemout.str();
spam(BOT_TEXT2("suggest_faction", placeholders), eTalkType::General, true);
BroadcastHelper::BroadcastSuggestGrindReputation(botAI, levels, allowedFactions, bot);
}
void SuggestWhatToDoAction::something()
{
std::map<std::string, std::string> placeholders;
placeholders["%role"] = chat->FormatClass(bot, AiFactory::GetPlayerSpecTab(bot));
AreaTableEntry const* zone = sAreaTableStore.LookupEntry(bot->GetMap()->GetZoneId(bot->GetPhaseMask(), bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ()));
if (!zone) return;
std::ostringstream out;
// out << "|cffb04040" << entry->area_name[0] << "|r";
out << zone->area_name[_dbc_locale];
placeholders["%zone"] = out.str();
spam(BOT_TEXT2("suggest_something", placeholders), urand(0, 1) ? eTalkType::General : 0, !urand(0, 2), !urand(0, 3));
BroadcastHelper::BroadcastSuggestSomething(botAI, bot);
}
void SuggestWhatToDoAction::spam(std::string msg, uint8 flags, bool worldChat, bool guild)
void SuggestWhatToDoAction::somethingToxic()
{
if (msg.empty())
return;
std::vector<std::string> channelNames;
ChannelMgr* cMgr = ChannelMgr::forTeam(bot->GetTeamId());
if (!cMgr)
return;
AreaTableEntry const* zone = sAreaTableStore.LookupEntry(bot->GetMap()->GetZoneId(bot->GetPhaseMask(), bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ()));
if (!zone) return;
/*AreaTableEntry const* area = sAreaTableStore.LookupEntry(bot->GetMap()->GetAreaId(bot->GetPhaseMask(), bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ()));
if (!area) return;*/
for (uint32 i = 0; i < sChatChannelsStore.GetNumRows(); ++i)
{
ChatChannelsEntry const* channel = sChatChannelsStore.LookupEntry(i);
if (!channel) continue;
// combine full channel name
char channelName[100];
Channel* chn = nullptr;
if (channel->ChannelID == 24 || (channel->flags & CHANNEL_DBC_FLAG_LFG) != 0)
{
std::string chanName = channel->pattern[_dbc_locale];
chn = cMgr->GetChannel(chanName, bot);
}
else
{
snprintf(channelName, 100, channel->pattern[_dbc_locale], 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;
// skip local defense and universal defense
if (chn->GetChannelId() == 22 || chn->GetChannelId() == 23)
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);
BroadcastHelper::BroadcastSuggestSomethingToxic(botAI, bot);
}
if (!channelNames.empty())
void SuggestWhatToDoAction::toxicLinks()
{
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);
}
BroadcastHelper::BroadcastSuggestToxicLinks(botAI, bot);
}
if (worldChat)
void SuggestWhatToDoAction::thunderfury()
{
if (Channel* worldChannel = cMgr->GetChannel("World", bot))
worldChannel->Say(bot->GetGUID(), msg.c_str(), LANG_UNIVERSAL);
}
}
if (sPlayerbotAIConfig->randomBotGuildTalk)
{
botAI->SayToGuild(msg);
}
BroadcastHelper::BroadcastSuggestThunderfury(botAI, bot);
}
class FindTradeItemsVisitor : public IterateItemsVisitor
@@ -394,22 +299,14 @@ bool SuggestDungeonAction::Execute(Event event)
}
std::vector<std::string> allowedInstances;
for (const auto& instance : instances)
for (auto it : instances)
{
if (bot->GetLevel() >= instance.second)
allowedInstances.push_back(instance.first);
if (bot->GetLevel() >= it.second) allowedInstances.push_back(it.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, 3));
BroadcastHelper::BroadcastSuggestInstance(botAI, allowedInstances, bot);
return true;
}
@@ -469,11 +366,6 @@ bool SuggestTradeAction::Execute(Event event)
if (!price)
return false;
std::map<std::string, std::string> placeholders;
placeholders["%item"] = chat->FormatItem(proto, count);
placeholders["%gold"] = chat->formatMoney(price);
spam(BOT_TEXT2("suggest_sell", placeholders), urand(0, 1) ? eTalkType::Trade : 0, !urand(0, 2), urand(0, 5));
BroadcastHelper::BroadcastSuggestSell(botAI, proto, count, price, bot);
return true;
}

View File

@@ -24,7 +24,9 @@ class SuggestWhatToDoAction : public InventoryAction
void grindReputation();
void grindMaterials();
void something();
void spam(std::string msg, uint8 flags = 0, bool worldChat = false, bool guild = false);
void toxicLinks();
void somethingToxic();
void thunderfury();
std::vector<uint32> GetIncompletedQuests();

View File

@@ -10,6 +10,7 @@
#include "Playerbots.h"
#include "QuestDef.h"
#include "WorldPacket.h"
#include "BroadcastHelper.h"
bool TalkToQuestGiverAction::ProcessQuest(Quest const* quest, Object* questGiver)
{
@@ -96,14 +97,19 @@ bool TalkToQuestGiverAction::TurnInQuest(Quest const* quest, Object* questGiver,
void TalkToQuestGiverAction::RewardNoItem(Quest const* quest, Object* questGiver, std::ostringstream& out)
{
std::map<std::string, std::string> args;
args["%quest"] = chat->FormatQuest(quest);
if (bot->CanRewardQuest(quest, false))
{
out << BOT_TEXT2("quest_status_completed", args);
BroadcastHelper::BroadcastQuestTurnedIn(botAI, bot, quest);
bot->RewardQuest(quest, 0, questGiver, false);
out << "Completed";
}
else
{
out << "|cffff0000Unable to turn in|r";
out << BOT_TEXT2("quest_status_unable_to_complete", args);
}
}
@@ -111,15 +117,19 @@ void TalkToQuestGiverAction::RewardSingleItem(Quest const* quest, Object* questG
{
int index = 0;
ItemTemplate const* item = sObjectMgr->GetItemTemplate(quest->RewardChoiceItemId[index]);
std::map<std::string, std::string> args;
args["%quest"] = chat->FormatQuest(quest);
args["%item"] = chat->FormatItem(item);
if (bot->CanRewardQuest(quest, index, false))
{
out << BOT_TEXT2("quest_status_complete_single_reward", args);
BroadcastHelper::BroadcastQuestTurnedIn(botAI, bot, quest);
bot->RewardQuest(quest, index, questGiver, true);
out << "Rewarded " << chat->FormatItem(item);
}
else
{
out << "|cffff0000Unable to turn in:|r, reward: " << chat->FormatItem(item);
out << BOT_TEXT2("quest_status_unable_to_complete", args);
}
}

View File

@@ -6,7 +6,7 @@
#include "Event.h"
#include "PlayerbotAIConfig.h"
#include "Playerbots.h"
#include "GuildMgr.h"
#include "BroadcastHelper.h"
bool XpGainAction::Execute(Event event)
{
@@ -33,19 +33,10 @@ bool XpGainAction::Execute(Event event)
p >> groupBonus; // 8 group bonus
}
if (sPlayerbotAIConfig->randomBotGuildTalk && bot->GetGuildId() && urand(0, 10))
{
Creature* creature = botAI->GetCreature(guid);
if (creature && (creature->isElite() || creature->isWorldBoss() || creature->GetLevel() > 61 || creature->GetLevel() > bot->GetLevel() + 4))
if (creature && !creature->GetMap()->IsDungeon())
{
Guild* guild = sGuildMgr->GetGuildById(bot->GetGuildId());
if (guild)
{
std::map<std::string, std::string> args;
args["%victim_name"] = creature->GetName();
botAI->SayToGuild(BOT_TEXT2("broadcast_killed_rare", args));
}
}
BroadcastHelper::BroadcastKill(botAI, bot, creature);
}
Unit* victim = nullptr;