mirror of
https://github.com/mod-playerbots/mod-playerbots
synced 2025-11-29 15:58:20 +08:00
@@ -128,6 +128,15 @@ AiPlayerbot.AllowPlayerBots = 0
|
||||
# Allow/deny bots from your guild
|
||||
AiPlayerbot.AllowGuildBots = 1
|
||||
|
||||
# Randombots will invite nearby bots to guilds
|
||||
AiPlayerbot.RandomBotGuildNearby = 0
|
||||
|
||||
# Randombots will invite players to groups/raids/guilds.
|
||||
AiPlayerbot.RandomBotInvitePlayer = 0
|
||||
|
||||
# Bots will chat in say/guild when they invite other bots to groups/raids/guilds
|
||||
AiPlayerbot.InviteChat = 0
|
||||
|
||||
# Bots will be summoned to player when accept group invitation
|
||||
AiPlayerbot.SummonWhenGroup = 1
|
||||
|
||||
@@ -458,9 +467,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
|
||||
|
||||
@@ -1266,27 +1272,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
|
||||
# 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
|
||||
#
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
1475
sql/playerbots/updates/db_playerbots/2024_08_07_00.sql
Normal file
1475
sql/playerbots/updates/db_playerbots/2024_08_07_00.sql
Normal file
File diff suppressed because it is too large
Load Diff
@@ -276,7 +276,7 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa
|
||||
|
||||
if (!player->InBattleground())
|
||||
{
|
||||
engine->addStrategies("racials", "chat", "default", "cast time", "duel", "boost", "emote", nullptr);
|
||||
engine->addStrategies("racials", "chat", "default", "cast time", "duel", "boost", nullptr);
|
||||
}
|
||||
if (sPlayerbotAIConfig->autoSaveMana)
|
||||
{
|
||||
@@ -596,6 +596,7 @@ void AiFactory::AddDefaultNonCombatStrategies(Player* player, PlayerbotAI* const
|
||||
nonCombatEngine->addStrategies("nc", "food", "chat", "follow", "default", "quest", "loot", "gather", "duel",
|
||||
"buff", "mount", "emote", nullptr);
|
||||
}
|
||||
|
||||
if (sPlayerbotAIConfig->autoSaveMana)
|
||||
{
|
||||
nonCombatEngine->addStrategy("auto save mana");
|
||||
|
||||
920
src/BroadcastHelper.cpp
Normal file
920
src/BroadcastHelper.cpp
Normal file
@@ -0,0 +1,920 @@
|
||||
|
||||
#include "Playerbots.h"
|
||||
#include "BroadcastHelper.h"
|
||||
#include "ServerFacade.h"
|
||||
#include "Channel.h"
|
||||
#include "AiFactory.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"] = 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_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"] = ChatHelper::FormatClass(bot, AiFactory::GetPlayerSpecTab(bot));
|
||||
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"] = ChatHelper::FormatClass(bot, AiFactory::GetPlayerSpecTab(bot));
|
||||
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"] = ChatHelper::FormatClass(bot, AiFactory::GetPlayerSpecTab(bot));
|
||||
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"] = ChatHelper::FormatClass(bot, AiFactory::GetPlayerSpecTab(bot));
|
||||
|
||||
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"] = ChatHelper::FormatClass(bot, AiFactory::GetPlayerSpecTab(bot));
|
||||
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"] = ChatHelper::FormatClass(bot, AiFactory::GetPlayerSpecTab(bot));
|
||||
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
148
src/BroadcastHelper.h
Normal 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
|
||||
);
|
||||
};
|
||||
@@ -9,6 +9,8 @@
|
||||
#include "Playerbots.h"
|
||||
#include "SpellInfo.h"
|
||||
|
||||
#include <regex>
|
||||
|
||||
std::map<std::string, uint32> ChatHelper::consumableSubClasses;
|
||||
std::map<std::string, uint32> ChatHelper::tradeSubClasses;
|
||||
std::map<std::string, uint32> ChatHelper::itemQualities;
|
||||
@@ -219,6 +221,26 @@ std::string const ChatHelper::formatMoney(uint32 copper)
|
||||
return out.str();
|
||||
}
|
||||
|
||||
std::string ChatHelper::parseValue(const std::string& type, const std::string& text)
|
||||
{
|
||||
std::string retString;
|
||||
|
||||
std::string pattern = "Hvalue:" + type + ":";
|
||||
|
||||
int pos = text.find(pattern, 0);
|
||||
if (pos == -1)
|
||||
return retString;
|
||||
|
||||
pos += pattern.size();
|
||||
|
||||
int endPos = text.find('|', pos);
|
||||
if (endPos == -1)
|
||||
return retString;
|
||||
|
||||
retString = text.substr(pos, endPos - pos);
|
||||
return retString;
|
||||
}
|
||||
|
||||
uint32 ChatHelper::parseMoney(std::string const text)
|
||||
{
|
||||
// if user specified money in ##g##s##c format
|
||||
@@ -570,3 +592,35 @@ void ChatHelper::eraseAllSubStr(std::string& mainStr, std::string const toErase)
|
||||
mainStr.erase(pos, toErase.length());
|
||||
}
|
||||
}
|
||||
|
||||
std::set<uint32> ChatHelper::ExtractAllQuestIds(const std::string& text)
|
||||
{
|
||||
std::set<uint32> ids;
|
||||
|
||||
std::regex rgx("Hquest:[0-9]+");
|
||||
auto begin = std::sregex_iterator(text.begin(), text.end(), rgx);
|
||||
auto end = std::sregex_iterator();
|
||||
for (std::sregex_iterator i = begin; i != end; ++i)
|
||||
{
|
||||
std::smatch match = *i;
|
||||
ids.insert(std::stoi(match.str().erase(0, 7)));
|
||||
}
|
||||
|
||||
return ids;
|
||||
}
|
||||
|
||||
std::set<uint32> ChatHelper::ExtractAllItemIds(const std::string& text)
|
||||
{
|
||||
std::set<uint32> ids;
|
||||
|
||||
std::regex rgx("Hitem:[0-9]+");
|
||||
auto begin = std::sregex_iterator(text.begin(), text.end(), rgx);
|
||||
auto end = std::sregex_iterator();
|
||||
for (std::sregex_iterator i = begin; i != end; ++i)
|
||||
{
|
||||
std::smatch match = *i;
|
||||
ids.insert(std::stoi(match.str().erase(0, 6)));
|
||||
}
|
||||
|
||||
return ids;
|
||||
}
|
||||
|
||||
@@ -34,6 +34,8 @@ public:
|
||||
static uint32 parseMoney(std::string const text);
|
||||
static ItemIds parseItems(std::string const text);
|
||||
uint32 parseSpell(std::string const text);
|
||||
static std::string parseValue(const std::string& type, const std::string& text);
|
||||
|
||||
static std::string const FormatQuest(Quest const* quest);
|
||||
static std::string const FormatItem(ItemTemplate const* proto, uint32 count = 0, uint32 total = 0);
|
||||
static std::string const FormatQItem(uint32 itemId);
|
||||
@@ -62,6 +64,9 @@ public:
|
||||
|
||||
void eraseAllSubStr(std::string& mainStr, std::string const toErase);
|
||||
|
||||
static std::set<uint32> ExtractAllQuestIds(const std::string& text);
|
||||
static std::set<uint32> ExtractAllItemIds(const std::string& text);
|
||||
|
||||
private:
|
||||
static std::map<std::string, uint32> consumableSubClasses;
|
||||
static std::map<std::string, uint32> tradeSubClasses;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -106,6 +106,58 @@ public:
|
||||
void* param;
|
||||
float minValue;
|
||||
};
|
||||
enum ChatChannelSource
|
||||
{
|
||||
SRC_GUILD,
|
||||
SRC_WORLD,
|
||||
SRC_GENERAL,
|
||||
SRC_TRADE,
|
||||
SRC_LOOKING_FOR_GROUP,
|
||||
SRC_LOCAL_DEFENSE,
|
||||
SRC_WORLD_DEFENSE,
|
||||
SRC_GUILD_RECRUITMENT,
|
||||
|
||||
SRC_SAY,
|
||||
SRC_WHISPER,
|
||||
SRC_EMOTE,
|
||||
SRC_TEXT_EMOTE,
|
||||
SRC_YELL,
|
||||
|
||||
SRC_PARTY,
|
||||
SRC_RAID,
|
||||
|
||||
SRC_UNDEFINED
|
||||
};
|
||||
static std::map<ChatChannelSource, std::string> ChatChannelSourceStr = {
|
||||
{ SRC_GUILD, "SRC_GUILD"},
|
||||
{ SRC_WORLD, "SRC_WORLD"},
|
||||
{ SRC_GENERAL, "SRC_GENERAL"},
|
||||
{ SRC_TRADE, "SRC_TRADE"},
|
||||
{ SRC_LOOKING_FOR_GROUP, "SRC_LOOKING_FOR_GROUP"},
|
||||
{ SRC_LOCAL_DEFENSE, "SRC_LOCAL_DEFENSE"},
|
||||
{ SRC_WORLD_DEFENSE, "SRC_WORLD_DEFENSE"},
|
||||
{ SRC_GUILD_RECRUITMENT, "SRC_GUILD_RECRUITMENT"},
|
||||
|
||||
{ SRC_SAY, "SRC_SAY"},
|
||||
{ SRC_WHISPER, "SRC_WHISPER"},
|
||||
{ SRC_EMOTE, "SRC_EMOTE"},
|
||||
{ SRC_TEXT_EMOTE, "SRC_TEXT_EMOTE"},
|
||||
{ SRC_YELL, "SRC_YELL"},
|
||||
|
||||
{ SRC_PARTY, "SRC_PARTY"},
|
||||
{ SRC_RAID, "SRC_RAID"},
|
||||
|
||||
{ SRC_UNDEFINED, "SRC_UNDEFINED"}
|
||||
};
|
||||
enum ChatChannelId
|
||||
{
|
||||
GENERAL = 1,
|
||||
TRADE = 2,
|
||||
LOCAL_DEFENSE = 22,
|
||||
WORLD_DEFENSE = 23,
|
||||
LOOKING_FOR_GROUP = 26,
|
||||
GUILD_RECRUITMENT = 25,
|
||||
};
|
||||
|
||||
enum RoguePoisonDisplayId
|
||||
{
|
||||
@@ -307,10 +359,10 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
std::string const GetCommand() { return command; }
|
||||
const std::string& GetCommand() { return command; }
|
||||
Player* GetOwner() { return owner; }
|
||||
uint32 GetType() { return type; }
|
||||
time_t GetTime() { return time; }
|
||||
uint32& GetType() { return type; }
|
||||
time_t& GetTime() { return time; }
|
||||
|
||||
private:
|
||||
std::string const command;
|
||||
@@ -331,16 +383,14 @@ public:
|
||||
|
||||
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 QueueChatResponse(const ChatQueuedReply reply);
|
||||
void HandleBotOutgoingPacket(WorldPacket const& packet);
|
||||
void HandleMasterIncomingPacket(WorldPacket const& packet);
|
||||
void HandleMasterOutgoingPacket(WorldPacket const& packet);
|
||||
void HandleTeleportAck();
|
||||
void ChangeEngine(BotState type);
|
||||
void DoNextAction(bool minimal = false);
|
||||
virtual bool DoSpecificAction(std::string const name, Event event = Event(), bool silent = false,
|
||||
std::string const qualifier = "");
|
||||
virtual bool DoSpecificAction(std::string const name, Event event = Event(), bool silent = false, std::string const qualifier = "");
|
||||
void ChangeStrategy(std::string const name, BotState type);
|
||||
void ClearStrategies(BotState type);
|
||||
std::vector<std::string> GetStrategies(BotState type);
|
||||
@@ -377,13 +427,25 @@ public:
|
||||
GameObject* GetGameObject(ObjectGuid guid);
|
||||
// static GameObject* GetGameObject(GameObjectData const* gameObjectData);
|
||||
WorldObject* GetWorldObject(ObjectGuid guid);
|
||||
std::vector<Player*> GetPlayersInGroup();
|
||||
const AreaTableEntry* GetCurrentArea();
|
||||
const AreaTableEntry* GetCurrentZone();
|
||||
std::string GetLocalizedAreaName(const AreaTableEntry* entry);
|
||||
|
||||
bool TellMaster(std::ostringstream& stream, PlayerbotSecurityLevel securityLevel = PLAYERBOT_SECURITY_ALLOW_ALL);
|
||||
bool TellMaster(std::string const text, PlayerbotSecurityLevel securityLevel = PLAYERBOT_SECURITY_ALLOW_ALL);
|
||||
bool TellMasterNoFacing(std::ostringstream& stream,
|
||||
PlayerbotSecurityLevel securityLevel = PLAYERBOT_SECURITY_ALLOW_ALL);
|
||||
bool TellMasterNoFacing(std::string const text,
|
||||
PlayerbotSecurityLevel securityLevel = PLAYERBOT_SECURITY_ALLOW_ALL);
|
||||
bool TellMasterNoFacing(std::ostringstream& stream, PlayerbotSecurityLevel securityLevel = PLAYERBOT_SECURITY_ALLOW_ALL);
|
||||
bool TellMasterNoFacing(std::string const text, PlayerbotSecurityLevel securityLevel = PLAYERBOT_SECURITY_ALLOW_ALL);
|
||||
bool TellError(std::string const text, PlayerbotSecurityLevel securityLevel = PLAYERBOT_SECURITY_ALLOW_ALL);
|
||||
bool SayToGuild(const std::string& msg);
|
||||
bool SayToWorld(const std::string& msg);
|
||||
bool SayToChannel(const std::string& msg, const ChatChannelId& chanId);
|
||||
bool SayToParty(const std::string& msg);
|
||||
bool SayToRaid(const std::string& msg);
|
||||
bool Yell(const std::string& msg);
|
||||
bool Say(const std::string& msg);
|
||||
bool Whisper(const std::string& msg, const std::string& receiverName);
|
||||
|
||||
void SpellInterrupted(uint32 spellid);
|
||||
int32 CalculateGlobalCooldown(uint32 spellid);
|
||||
void InterruptSpell();
|
||||
@@ -461,11 +523,12 @@ public:
|
||||
bool AllowActive(ActivityType activityType);
|
||||
bool AllowActivity(ActivityType activityType = ALL_ACTIVITY, bool checkNow = false);
|
||||
|
||||
bool HasCheat(BotCheatMask mask)
|
||||
{
|
||||
return ((uint32)mask & (uint32)cheatMask) != 0 ||
|
||||
((uint32)mask & (uint32)sPlayerbotAIConfig->botCheatMask) != 0;
|
||||
}
|
||||
//Check if player is safe to use.
|
||||
bool IsSafe(Player* player);
|
||||
bool IsSafe(WorldObject* obj);
|
||||
ChatChannelSource GetChatChannelSource(Player* bot, uint32 type, std::string channelName);
|
||||
|
||||
bool HasCheat(BotCheatMask mask) { return ((uint32)mask & (uint32)cheatMask) != 0 || ((uint32)mask & (uint32)sPlayerbotAIConfig->botCheatMask) != 0; }
|
||||
BotCheatMask GetCheat() { return cheatMask; }
|
||||
void SetCheat(BotCheatMask mask) { cheatMask = mask; }
|
||||
|
||||
@@ -486,23 +549,34 @@ public:
|
||||
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();
|
||||
std::set<uint32> GetAllCurrentQuestIds();
|
||||
std::set<uint32> GetCurrentIncompleteQuestIds();
|
||||
private:
|
||||
static void _fillGearScoreData(Player* player, Item* item, std::vector<uint32>* gearScore, uint32& twoHandScore,
|
||||
bool mixed = false);
|
||||
static void _fillGearScoreData(Player* player, Item* item, std::vector<uint32>* gearScore, uint32& twoHandScore, bool mixed = false);
|
||||
bool IsTellAllowed(PlayerbotSecurityLevel securityLevel = PLAYERBOT_SECURITY_ALLOW_ALL);
|
||||
|
||||
void HandleCommands();
|
||||
void HandleCommand(uint32 type, const std::string& text, Player& fromPlayer, const uint32 lang = LANG_UNIVERSAL);
|
||||
|
||||
protected:
|
||||
Player* bot;
|
||||
Player* master;
|
||||
uint32 accountId;
|
||||
Player* master;
|
||||
uint32 accountId;
|
||||
AiObjectContext* aiObjectContext;
|
||||
Engine* currentEngine;
|
||||
Engine* engines[BOT_STATE_MAX];
|
||||
BotState currentState;
|
||||
ChatHelper chatHelper;
|
||||
std::queue<ChatCommandHolder> chatCommands;
|
||||
std::queue<ChatQueuedReply> chatReplies;
|
||||
std::list<ChatCommandHolder> chatCommands;
|
||||
std::list<ChatQueuedReply> chatReplies;
|
||||
PacketHandlingHelper botOutgoingPacketHandlers;
|
||||
PacketHandlingHelper masterIncomingPacketHandlers;
|
||||
PacketHandlingHelper masterOutgoingPacketHandlers;
|
||||
|
||||
@@ -107,6 +107,9 @@ bool PlayerbotAIConfig::Initialize()
|
||||
iterationsPerTick = sConfigMgr->GetOption<int32>("AiPlayerbot.IterationsPerTick", 100);
|
||||
|
||||
allowGuildBots = sConfigMgr->GetOption<bool>("AiPlayerbot.AllowGuildBots", true);
|
||||
randomBotGuildNearby = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotGuildNearby", false);
|
||||
randomBotInvitePlayer = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotInvitePlayer", false);
|
||||
inviteChat = sConfigMgr->GetOption<bool>("AiPlayerbot.InviteChat", false);
|
||||
allowPlayerBots = sConfigMgr->GetOption<bool>("AiPlayerbot.AllowPlayerBots", false);
|
||||
|
||||
randomBotMapsAsString = sConfigMgr->GetOption<std::string>("AiPlayerbot.RandomBotMaps", "0,1,530,571");
|
||||
@@ -160,12 +163,100 @@ bool PlayerbotAIConfig::Initialize()
|
||||
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);
|
||||
@@ -368,8 +459,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
|
||||
|
||||
@@ -55,6 +55,7 @@ public:
|
||||
|
||||
bool enabled;
|
||||
bool allowGuildBots, allowPlayerBots;
|
||||
bool randomBotGuildNearby, randomBotInvitePlayer, inviteChat;
|
||||
uint32 globalCoolDown, reactDelay, maxWaitForMove, disableMoveSplinePath, maxMovementSearchTime, expireActionTime,
|
||||
dispelAuraDuration, passiveDelay, repeatDelay, errorDelay, rpgDelay, sitDelay, returnDelay, lootDelay;
|
||||
float sightDistance, spellDistance, reactDistance, grindDistance, lootDistance, shootDistance, fleeDistance,
|
||||
@@ -95,11 +96,78 @@ public:
|
||||
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 +249,6 @@ public:
|
||||
|
||||
uint32 commandServerPort;
|
||||
bool perfMonEnabled;
|
||||
|
||||
bool enableGreet;
|
||||
bool summonWhenGroup;
|
||||
bool randomBotShowHelmet;
|
||||
bool randomBotShowCloak;
|
||||
@@ -212,8 +278,6 @@ public:
|
||||
bool freeFood;
|
||||
bool autoLearnQuestSpells;
|
||||
bool autoTeleportForLevel;
|
||||
bool randomBotSayWithoutMaster;
|
||||
bool sayWhenCollectingItems;
|
||||
bool randomBotGroupNearby;
|
||||
uint32 tweakValue; // Debugging config
|
||||
|
||||
|
||||
@@ -26,9 +26,10 @@
|
||||
#include "Playerbots.h"
|
||||
#include "SharedDefines.h"
|
||||
#include "WorldSession.h"
|
||||
#include "ChannelMgr.h"
|
||||
#include "BroadcastHelper.h"
|
||||
|
||||
PlayerbotHolder::PlayerbotHolder() : PlayerbotAIBase(false) {}
|
||||
|
||||
class PlayerbotLoginQueryHolder : public LoginQueryHolder
|
||||
{
|
||||
private:
|
||||
@@ -562,10 +563,12 @@ void PlayerbotHolder::OnBotLogin(Player* const bot)
|
||||
pkt << ""; // Pass
|
||||
bot->GetSession()->HandleJoinChannel(pkt);
|
||||
}
|
||||
|
||||
// join standard channels
|
||||
AreaTableEntry const* current_zone = sAreaTableStore.LookupEntry(bot->GetAreaId());
|
||||
uint8 locale = BroadcastHelper::GetLocale();
|
||||
AreaTableEntry const* current_zone = GET_PLAYERBOT_AI(bot)->GetCurrentZone();
|
||||
ChannelMgr* cMgr = ChannelMgr::forTeam(bot->GetTeamId());
|
||||
std::string current_zone_name = current_zone ? current_zone->area_name[sWorld->GetDefaultDbcLocale()] : "";
|
||||
std::string current_zone_name = current_zone ? GET_PLAYERBOT_AI(bot)->GetLocalizedAreaName(current_zone) : "";
|
||||
|
||||
if (current_zone && cMgr)
|
||||
{
|
||||
@@ -575,27 +578,40 @@ void PlayerbotHolder::OnBotLogin(Player* const bot)
|
||||
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)
|
||||
switch (channel->ChannelID)
|
||||
{
|
||||
std::string lfgChannelName = channel->pattern[sWorld->GetDefaultDbcLocale()];
|
||||
new_channel = cMgr->GetJoinChannel("LookingForGroup", channel->ChannelID);
|
||||
case ChatChannelId::GENERAL:
|
||||
case ChatChannelId::LOCAL_DEFENSE:
|
||||
{
|
||||
char new_channel_name_buf[100];
|
||||
snprintf(new_channel_name_buf, 100, channel->pattern[locale], current_zone_name.c_str());
|
||||
new_channel = cMgr->GetJoinChannel(new_channel_name_buf, channel->ChannelID);
|
||||
break;
|
||||
}
|
||||
case ChatChannelId::TRADE:
|
||||
case ChatChannelId::GUILD_RECRUITMENT:
|
||||
{
|
||||
char new_channel_name_buf[100];
|
||||
//3459 is ID for a zone named "City" (only exists for the sake of using its name)
|
||||
//Currently in magons TBC, if you switch zones, then you join "Trade - <zone>" and "GuildRecruitment - <zone>"
|
||||
//which is a core bug, should be "Trade - City" and "GuildRecruitment - City" in both 1.12 and TBC
|
||||
//but if you (actual player) logout in a city and log back in - you join "City" versions
|
||||
snprintf(new_channel_name_buf, 100, channel->pattern[locale], GET_PLAYERBOT_AI(bot)->GetLocalizedAreaName(GetAreaEntryByAreaID(3459)).c_str());
|
||||
new_channel = cMgr->GetJoinChannel(new_channel_name_buf, channel->ChannelID);
|
||||
break;
|
||||
}
|
||||
case ChatChannelId::LOOKING_FOR_GROUP:
|
||||
case ChatChannelId::WORLD_DEFENSE:
|
||||
{
|
||||
new_channel = cMgr->GetJoinChannel(channel->pattern[locale], channel->ChannelID);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
char new_channel_name_buf[100];
|
||||
snprintf(new_channel_name_buf, 100, channel->pattern[sWorld->GetDefaultDbcLocale()],
|
||||
current_zone_name.c_str());
|
||||
new_channel = cMgr->GetJoinChannel(new_channel_name_buf, channel->ChannelID);
|
||||
}
|
||||
if (new_channel && new_channel->GetName().length() > 0)
|
||||
|
||||
if (new_channel)
|
||||
new_channel->JoinChannel(bot, "");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,3 +68,8 @@ Unit* ServerFacade::GetChaseTarget(Unit* target)
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void ServerFacade::SendPacket(Player *player, WorldPacket *packet)
|
||||
{
|
||||
return player->GetSession()->SendPacket(packet);
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
class Player;
|
||||
class Unit;
|
||||
class WorldObject;
|
||||
class WorldPacket;
|
||||
|
||||
class ServerFacade
|
||||
{
|
||||
@@ -32,8 +33,9 @@ public:
|
||||
bool IsDistanceLessOrEqualThan(float dist1, float dist2);
|
||||
|
||||
void SetFacingTo(Player* bot, WorldObject* wo, bool force = false);
|
||||
|
||||
Unit* GetChaseTarget(Unit* target);
|
||||
|
||||
void SendPacket(Player *player, WorldPacket* packet);
|
||||
};
|
||||
|
||||
#define sServerFacade ServerFacade::instance()
|
||||
|
||||
@@ -121,7 +121,20 @@ WorldPosition::WorldPosition(uint32 mapid, mGridCoord grid)
|
||||
|
||||
void WorldPosition::set(const WorldLocation& pos) { WorldRelocate(pos); }
|
||||
|
||||
void WorldPosition::setMapId(uint32 id) { m_mapId = id; }
|
||||
void WorldPosition::set(const WorldPosition& pos)
|
||||
{
|
||||
WorldRelocate(pos.m_mapId, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation());
|
||||
}
|
||||
|
||||
void WorldPosition::set(const WorldObject* pos)
|
||||
{
|
||||
WorldRelocate(pos->GetMapId(), pos->GetPositionX(), pos->GetPositionY(), pos->GetPositionZ(), pos->GetOrientation());
|
||||
}
|
||||
|
||||
void WorldPosition::setMapId(uint32 id)
|
||||
{
|
||||
m_mapId = id;
|
||||
}
|
||||
|
||||
void WorldPosition::setX(float x) { m_positionX = x; }
|
||||
|
||||
@@ -1045,30 +1058,42 @@ std::string const QuestTravelDestination::getTitle() { return ChatHelper::Format
|
||||
|
||||
bool QuestRelationTravelDestination::isActive(Player* bot)
|
||||
{
|
||||
PlayerbotAI* botAI = GET_PLAYERBOT_AI(bot);
|
||||
AiObjectContext* context = botAI->GetAiObjectContext();
|
||||
|
||||
if (botAI && !botAI->HasStrategy("rpg quest", BOT_STATE_NON_COMBAT))
|
||||
return false;
|
||||
|
||||
if (relation == 0)
|
||||
{
|
||||
if (questTemplate->GetQuestLevel() >= bot->GetLevel() + 5)
|
||||
if ((int32)questTemplate->GetQuestLevel() >= (int32)bot->GetLevel() + (int32)5)
|
||||
return false;
|
||||
|
||||
// if (questTemplate->XPValue(bot) == 0)
|
||||
// return false;
|
||||
// skip for now this quest
|
||||
if (getPoints().front()->GetMapId() != bot->GetMapId())
|
||||
return false;
|
||||
|
||||
if (!bot->GetMap()->GetEntry()->IsWorldMap() || !bot->CanTakeQuest(questTemplate, false))
|
||||
return false;
|
||||
|
||||
PlayerbotAI* botAI = GET_PLAYERBOT_AI(bot);
|
||||
AiObjectContext* context = botAI->GetAiObjectContext();
|
||||
|
||||
uint32 dialogStatus = sTravelMgr->getDialogStatus(bot, entry, questTemplate);
|
||||
|
||||
if (AI_VALUE(bool, "can fight equal"))
|
||||
{
|
||||
if (dialogStatus != DIALOG_STATUS_AVAILABLE)
|
||||
if (AI_VALUE(uint8, "free quest log slots") < 5)
|
||||
return false;
|
||||
|
||||
//None has yellow exclamation mark.
|
||||
if (!AI_VALUE2(bool, "group or", "following party,near leader,can accept quest npc::" + std::to_string(entry)))
|
||||
if (!AI_VALUE2(bool, "group or", "following party,near leader,can accept quest low level npc::" + std::to_string(entry) + "need quest objective::" + std::to_string(questId))) //Noone can do this quest for a usefull reward.
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dialogStatus != DIALOG_STATUS_LOW_LEVEL_AVAILABLE)
|
||||
if (!AI_VALUE2(bool, "group or", "following party,near leader,can accept quest low level npc::" + std::to_string(entry))) //Noone can pick up this quest for money.
|
||||
return false;
|
||||
|
||||
if (AI_VALUE(uint8, "free quest log slots") < 10)
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1079,27 +1104,14 @@ bool QuestRelationTravelDestination::isActive(Player* bot)
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!bot->IsActiveQuest(questId))
|
||||
if (!AI_VALUE2(bool, "group or", "following party,near leader,can turn in quest npc::" + std::to_string(entry)))
|
||||
return false;
|
||||
|
||||
if (!bot->CanRewardQuest(questTemplate, false))
|
||||
return false;
|
||||
|
||||
uint32 dialogStatus = sTravelMgr->getDialogStatus(bot, entry, questTemplate);
|
||||
|
||||
if (dialogStatus != DIALOG_STATUS_REWARD2 && dialogStatus != DIALOG_STATUS_REWARD &&
|
||||
dialogStatus != DIALOG_STATUS_REWARD_REP)
|
||||
return false;
|
||||
|
||||
PlayerbotAI* botAI = GET_PLAYERBOT_AI(bot);
|
||||
AiObjectContext* context = botAI->GetAiObjectContext();
|
||||
|
||||
// Do not try to hand-in dungeon/elite quests in instances without a group.
|
||||
if ((questTemplate->GetType() == QUEST_TYPE_ELITE || questTemplate->GetType() == QUEST_TYPE_DUNGEON) &&
|
||||
!AI_VALUE(bool, "can fight boss"))
|
||||
//Do not try to hand-in dungeon/elite quests in instances without a group.
|
||||
if ((questTemplate->GetType() == QUEST_TYPE_ELITE || questTemplate->GetType() == QUEST_TYPE_DUNGEON) && !AI_VALUE(bool, "can fight boss"))
|
||||
{
|
||||
WorldPosition pos(bot);
|
||||
if (!this->nearestPoint(const_cast<WorldPosition*>(&pos))->isOverworld())
|
||||
if (!this->nearestPoint(&pos)->isOverworld())
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1233,7 +1245,8 @@ std::string const RpgTravelDestination::getTitle()
|
||||
{
|
||||
std::ostringstream out;
|
||||
|
||||
out << "rpg npc ";
|
||||
if(entry > 0)
|
||||
out << "rpg npc ";
|
||||
|
||||
out << " " << ChatHelper::FormatWorldEntry(entry);
|
||||
|
||||
@@ -3880,7 +3893,45 @@ std::vector<TravelDestination*> TravelMgr::getQuestTravelDestinations(Player* bo
|
||||
|
||||
std::vector<TravelDestination*> retTravelLocations;
|
||||
|
||||
if (questId == -1)
|
||||
if (!questId)
|
||||
{
|
||||
for (auto& dest : questGivers)
|
||||
{
|
||||
if (!ignoreInactive && !dest->isActive(bot))
|
||||
continue;
|
||||
|
||||
if (maxDistance > 0 && dest->distanceTo(&botLocation) > maxDistance)
|
||||
continue;
|
||||
|
||||
retTravelLocations.push_back(dest);
|
||||
}
|
||||
for (auto& quest : quests)
|
||||
{
|
||||
for (auto& dest : quest.second->questTakers)
|
||||
{
|
||||
if (!ignoreInactive && !dest->isActive(bot))
|
||||
continue;
|
||||
|
||||
if (maxDistance > 0 && dest->distanceTo(&botLocation) > maxDistance)
|
||||
continue;
|
||||
|
||||
retTravelLocations.push_back(dest);
|
||||
}
|
||||
|
||||
if (!ignoreObjectives)
|
||||
for (auto& dest : quest.second->questObjectives)
|
||||
{
|
||||
if (!ignoreInactive && !dest->isActive(bot))
|
||||
continue;
|
||||
|
||||
if (maxDistance > 0 && dest->distanceTo(&botLocation) > maxDistance)
|
||||
continue;
|
||||
|
||||
retTravelLocations.push_back(dest);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (questId == -1)
|
||||
{
|
||||
for (auto& dest : questGivers)
|
||||
{
|
||||
|
||||
@@ -97,8 +97,10 @@ public:
|
||||
WorldPosition(uint32 mapid, CellCoord cell);
|
||||
WorldPosition(uint32 mapid, mGridCoord grid);
|
||||
|
||||
// Setters
|
||||
//Setters
|
||||
void set(const WorldLocation& pos);
|
||||
void set(const WorldObject* wo);
|
||||
void set(const WorldPosition& pos);
|
||||
void setMapId(uint32 id);
|
||||
void setX(float x);
|
||||
void setY(float y);
|
||||
@@ -404,11 +406,10 @@ private:
|
||||
class GuidPosition : public ObjectGuid, public WorldPosition
|
||||
{
|
||||
public:
|
||||
GuidPosition() : ObjectGuid(), WorldPosition(), loadedFromDB(false) {}
|
||||
GuidPosition() : ObjectGuid(), WorldPosition(), loadedFromDB(false) { }
|
||||
GuidPosition(WorldObject* wo);
|
||||
GuidPosition(CreatureData const& creData);
|
||||
GuidPosition(GameObjectData const& goData);
|
||||
|
||||
CreatureTemplate const* GetCreatureTemplate();
|
||||
GameObjectTemplate const* GetGameObjectTemplate();
|
||||
|
||||
|
||||
@@ -14,13 +14,30 @@ void Qualified::Qualify(int qual)
|
||||
qualifier = out.str();
|
||||
}
|
||||
|
||||
std::string const Qualified::MultiQualify(std::vector<std::string> qualifiers)
|
||||
std::string const Qualified::MultiQualify(std::vector<std::string> qualifiers, const std::string& separator, const std::string_view brackets)
|
||||
{
|
||||
std::ostringstream out;
|
||||
for (auto& qualifier : qualifiers)
|
||||
out << qualifier << (&qualifier != &qualifiers.back() ? " " : "");
|
||||
std::stringstream out;
|
||||
for (uint8 i = 0; i < qualifiers.size(); i++)
|
||||
{
|
||||
const std::string& qualifier = qualifiers[i];
|
||||
if (i == qualifiers.size() - 1)
|
||||
{
|
||||
out << qualifier;
|
||||
}
|
||||
else
|
||||
{
|
||||
out << qualifier << separator;
|
||||
}
|
||||
}
|
||||
|
||||
return out.str();
|
||||
if (brackets.empty())
|
||||
{
|
||||
return out.str();
|
||||
}
|
||||
else
|
||||
{
|
||||
return brackets[0] + out.str() + brackets[1];
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::string> Qualified::getMultiQualifiers(std::string const qualifier1)
|
||||
|
||||
@@ -29,7 +29,7 @@ public:
|
||||
|
||||
std::string const getQualifier() { return qualifier; }
|
||||
|
||||
static std::string const MultiQualify(std::vector<std::string> qualifiers);
|
||||
static std::string const MultiQualify(std::vector<std::string> qualifiers, const std::string& separator, const std::string_view brackets = "{}");
|
||||
static std::vector<std::string> getMultiQualifiers(std::string const qualifier1);
|
||||
static int32 getMultiQualifier(std::string const qualifier1, uint32 pos);
|
||||
|
||||
|
||||
@@ -107,6 +107,7 @@ public:
|
||||
creators["debug move"] = &StrategyContext::debug_move;
|
||||
creators["debug rpg"] = &StrategyContext::debug_rpg;
|
||||
creators["debug spell"] = &StrategyContext::debug_spell;
|
||||
creators["debug quest"] = &StrategyContext::debug_quest;
|
||||
creators["maintenance"] = &StrategyContext::maintenance;
|
||||
creators["group"] = &StrategyContext::group;
|
||||
creators["guild"] = &StrategyContext::guild;
|
||||
@@ -170,9 +171,10 @@ private:
|
||||
static Strategy* debug_move(PlayerbotAI* botAI) { return new DebugMoveStrategy(botAI); }
|
||||
static Strategy* debug_rpg(PlayerbotAI* botAI) { return new DebugRpgStrategy(botAI); }
|
||||
static Strategy* debug_spell(PlayerbotAI* botAI) { return new DebugSpellStrategy(botAI); }
|
||||
static Strategy* debug_quest(PlayerbotAI* botAI) { return new DebugQuestStrategy(botAI); }
|
||||
static Strategy* maintenance(PlayerbotAI* botAI) { return new MaintenanceStrategy(botAI); }
|
||||
static Strategy* group(PlayerbotAI* botAI) { return new GroupStrategy(botAI); }
|
||||
static Strategy* guild(PlayerbotAI* botAI) { return new GuildStrategy(botAI); }
|
||||
static Strategy* guild (PlayerbotAI* botAI) { return new GuildStrategy(botAI); }
|
||||
static Strategy* grind(PlayerbotAI* botAI) { return new GrindingStrategy(botAI); }
|
||||
static Strategy* avoid_aoe(PlayerbotAI* botAI) { return new AvoidAoeStrategy(botAI); }
|
||||
static Strategy* move_random(PlayerbotAI* ai) { return new MoveRandomStrategy(ai); }
|
||||
|
||||
@@ -8,54 +8,63 @@
|
||||
#include "Event.h"
|
||||
#include "Playerbots.h"
|
||||
|
||||
void AcceptAllQuestsAction::ProcessQuest(Quest const* quest, Object* questGiver)
|
||||
bool AcceptAllQuestsAction::ProcessQuest(Quest const* quest, Object* questGiver)
|
||||
{
|
||||
AcceptQuest(quest, questGiver->GetGUID());
|
||||
if (!AcceptQuest(quest, questGiver->GetGUID())) return false;
|
||||
|
||||
auto text_quest = ChatHelper::FormatQuest(quest);
|
||||
bot->PlayDistanceSound(620);
|
||||
|
||||
if (botAI->HasStrategy("debug quest", BotState::BOT_STATE_NON_COMBAT) || botAI->HasStrategy("debug rpg", BotState::BOT_STATE_COMBAT))
|
||||
{
|
||||
LOG_INFO("playerbots", "{} => Quest [ {} ] accepted", bot->GetName(), quest->GetTitle());
|
||||
bot->Say("Quest [ " + text_quest + " ] accepted", LANG_UNIVERSAL);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AcceptQuestAction::Execute(Event event)
|
||||
{
|
||||
Player* master = GetMaster();
|
||||
if (!master)
|
||||
Player* requester = event.getOwner() ? event.getOwner() : GetMaster();
|
||||
if (!requester)
|
||||
return false;
|
||||
|
||||
Player* bot = botAI->GetBot();
|
||||
ObjectGuid guid;
|
||||
uint64_t guid;
|
||||
uint32 quest = 0;
|
||||
|
||||
std::string const text = event.getParam();
|
||||
PlayerbotChatHandler ch(master);
|
||||
PlayerbotChatHandler ch(requester);
|
||||
quest = ch.extractQuestId(text);
|
||||
|
||||
bool hasAccept = false;
|
||||
|
||||
if (event.getPacket().empty())
|
||||
{
|
||||
GuidVector npcs = AI_VALUE(GuidVector, "nearest npcs");
|
||||
for (GuidVector::iterator i = npcs.begin(); i != npcs.end(); i++)
|
||||
for (auto i = npcs.begin(); i != npcs.end(); i++)
|
||||
{
|
||||
Unit* unit = botAI->GetUnit(*i);
|
||||
if (unit && quest && unit->hasQuest(quest))
|
||||
{
|
||||
guid = unit->GetGUID();
|
||||
guid = unit->GetGUID().GetRawValue();
|
||||
break;
|
||||
}
|
||||
|
||||
if (unit && text == "*" && bot->GetDistance(unit) <= INTERACTION_DISTANCE)
|
||||
QuestAction::ProcessQuests(unit);
|
||||
if (unit && text == "*" && sqrt(bot->GetDistance(unit)) <= INTERACTION_DISTANCE)
|
||||
hasAccept |= QuestAction::ProcessQuests(unit);
|
||||
}
|
||||
|
||||
GuidVector gos = AI_VALUE(GuidVector, "nearest game objects");
|
||||
for (GuidVector::iterator i = gos.begin(); i != gos.end(); i++)
|
||||
GuidVector gos = AI_VALUE(GuidVector, "nearest game objects no los");
|
||||
for (auto i = gos.begin(); i != gos.end(); i++)
|
||||
{
|
||||
GameObject* go = botAI->GetGameObject(*i);
|
||||
if (go && quest && go->hasQuest(quest))
|
||||
{
|
||||
guid = go->GetGUID();
|
||||
guid = go->GetGUID().GetRawValue();
|
||||
break;
|
||||
}
|
||||
|
||||
if (go && text == "*" && bot->GetDistance(go) <= INTERACTION_DISTANCE)
|
||||
QuestAction::ProcessQuests(go);
|
||||
if (go && text == "*" && sqrt(bot->GetDistance(go)) <= INTERACTION_DISTANCE)
|
||||
hasAccept |= QuestAction::ProcessQuests(go);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -72,7 +81,17 @@ bool AcceptQuestAction::Execute(Event event)
|
||||
if (!qInfo)
|
||||
return false;
|
||||
|
||||
return AcceptQuest(qInfo, guid);
|
||||
hasAccept |= AcceptQuest(qInfo, ObjectGuid(guid));
|
||||
|
||||
if (hasAccept)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "AcceptQuestAction {" << qInfo->GetTitle() << "} - {" << std::to_string(qInfo->GetQuestId()) << "}";
|
||||
LOG_INFO("playerbots", "{}", ss.str().c_str());
|
||||
botAI->TellMaster(ss.str());
|
||||
}
|
||||
|
||||
return hasAccept;
|
||||
}
|
||||
|
||||
bool AcceptQuestShareAction::Execute(Event event)
|
||||
@@ -136,3 +155,41 @@ bool AcceptQuestShareAction::Execute(Event event)
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ConfirmQuestAction::Execute(Event event)
|
||||
{
|
||||
Player* bot = botAI->GetBot();
|
||||
Player* requester = event.getOwner() ? event.getOwner() : GetMaster();
|
||||
|
||||
WorldPacket& p = event.getPacket();
|
||||
p.rpos(0);
|
||||
uint32 quest;
|
||||
p >> quest;
|
||||
Quest const* qInfo = sObjectMgr->GetQuestTemplate(quest);
|
||||
|
||||
quest = qInfo->GetQuestId();
|
||||
if (!bot->CanTakeQuest(qInfo, false))
|
||||
{
|
||||
// can't take quest
|
||||
botAI->TellError("quest_cant_take");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (bot->CanAddQuest(qInfo, false))
|
||||
{
|
||||
bot->AddQuest(qInfo, requester);
|
||||
|
||||
if (bot->CanCompleteQuest(quest))
|
||||
bot->CompleteQuest(quest);
|
||||
|
||||
if (qInfo->GetSrcSpell() > 0)
|
||||
{
|
||||
bot->CastSpell(bot, qInfo->GetSrcSpell(), true);
|
||||
}
|
||||
|
||||
botAI->TellMaster("quest_accept");
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ public:
|
||||
}
|
||||
|
||||
protected:
|
||||
void ProcessQuest(Quest const* quest, Object* questGiver) override;
|
||||
bool ProcessQuest(Quest const* quest, Object* questGiver) override;
|
||||
};
|
||||
|
||||
class AcceptQuestAction : public AcceptAllQuestsAction
|
||||
@@ -37,4 +37,10 @@ public:
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class ConfirmQuestAction : public Action {
|
||||
public:
|
||||
ConfirmQuestAction(PlayerbotAI* ai) : Action(ai, "confirm quest") {}
|
||||
bool Execute(Event event);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
#include "AddLootAction.h"
|
||||
#include "AttackAction.h"
|
||||
#include "AutoLearnSpellAction.h"
|
||||
#include "ShareQuestAction.h"
|
||||
#include "BattleGroundTactics.h"
|
||||
#include "AutoTeleportForLevelAction.h"
|
||||
#include "BattleGroundJoinAction.h"
|
||||
#include "BattleGroundTactics.h"
|
||||
@@ -43,6 +45,7 @@
|
||||
#include "NonCombatActions.h"
|
||||
#include "OutfitAction.h"
|
||||
#include "PositionAction.h"
|
||||
#include "DropQuestAction.h"
|
||||
#include "RaidNaxxActions.h"
|
||||
#include "RandomBotUpdateAction.h"
|
||||
#include "ReachTargetActions.h"
|
||||
@@ -153,6 +156,7 @@ public:
|
||||
creators["war stomp"] = &ActionContext::war_stomp;
|
||||
creators["auto talents"] = &ActionContext::auto_talents;
|
||||
creators["auto learn spell"] = &ActionContext::auto_learn_spell;
|
||||
creators["auto share quest"] = &ActionContext::auto_share_quest;
|
||||
creators["auto teleport for level"] = &ActionContext::auto_teleport_for_level;
|
||||
creators["auto upgrade equip"] = &ActionContext::auto_upgrade_equip;
|
||||
creators["xp gain"] = &ActionContext::xp_gain;
|
||||
@@ -179,6 +183,7 @@ public:
|
||||
creators["turn in petition"] = &ActionContext::turn_in_petition;
|
||||
creators["buy tabard"] = &ActionContext::buy_tabard;
|
||||
creators["guild manage nearby"] = &ActionContext::guild_manage_nearby;
|
||||
creators["clean quest log"] = &ActionContext::clean_quest_log;
|
||||
|
||||
// BG Tactics
|
||||
creators["bg tactics"] = &ActionContext::bg_tactics;
|
||||
@@ -206,7 +211,7 @@ public:
|
||||
creators["blade salvo"] = &ActionContext::blade_salvo;
|
||||
creators["glaive throw"] = &ActionContext::glaive_throw;
|
||||
|
||||
// Rpg
|
||||
//Rpg
|
||||
creators["rpg stay"] = &ActionContext::rpg_stay;
|
||||
creators["rpg work"] = &ActionContext::rpg_work;
|
||||
creators["rpg emote"] = &ActionContext::rpg_emote;
|
||||
@@ -231,7 +236,7 @@ public:
|
||||
creators["rpg mount anim"] = &ActionContext::rpg_mount_anim;
|
||||
|
||||
creators["toggle pet spell"] = &ActionContext::toggle_pet_spell;
|
||||
creators["pet attack"] = &ActionContext::pet_attack;
|
||||
creators["pet attack"] = &ActionContext::pet_attack;
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -265,10 +270,7 @@ private:
|
||||
static Action* ReachSpell(PlayerbotAI* botAI) { return new ReachSpellAction(botAI); }
|
||||
static Action* ReachMelee(PlayerbotAI* botAI) { return new ReachMeleeAction(botAI); }
|
||||
static Action* reach_party_member_to_heal(PlayerbotAI* botAI) { return new ReachPartyMemberToHealAction(botAI); }
|
||||
static Action* reach_party_member_to_resurrect(PlayerbotAI* botAI)
|
||||
{
|
||||
return new ReachPartyMemberToResurrectAction(botAI);
|
||||
}
|
||||
static Action* reach_party_member_to_resurrect(PlayerbotAI* botAI) { return new ReachPartyMemberToResurrectAction(botAI); }
|
||||
static Action* flee(PlayerbotAI* botAI) { return new FleeAction(botAI); }
|
||||
static Action* flee_with_pet(PlayerbotAI* botAI) { return new FleeWithPetAction(botAI); }
|
||||
static Action* avoid_aoe(PlayerbotAI* botAI) { return new AvoidAoeAction(botAI); }
|
||||
@@ -324,6 +326,7 @@ private:
|
||||
static Action* war_stomp(PlayerbotAI* botAI) { return new CastWarStompAction(botAI); }
|
||||
static Action* auto_talents(PlayerbotAI* botAI) { return new AutoSetTalentsAction(botAI); }
|
||||
static Action* auto_learn_spell(PlayerbotAI* botAI) { return new AutoLearnSpellAction(botAI); }
|
||||
static Action* auto_share_quest(PlayerbotAI* ai) { return new AutoShareQuestAction(ai); }
|
||||
static Action* auto_teleport_for_level(PlayerbotAI* botAI) { return new AutoTeleportForLevelAction(botAI); }
|
||||
static Action* auto_upgrade_equip(PlayerbotAI* botAI) { return new AutoUpgradeEquipAction(botAI); }
|
||||
static Action* xp_gain(PlayerbotAI* botAI) { return new XpGainAction(botAI); }
|
||||
@@ -351,6 +354,7 @@ private:
|
||||
static Action* turn_in_petition(PlayerbotAI* botAI) { return new PetitionTurnInAction(botAI); }
|
||||
static Action* buy_tabard(PlayerbotAI* botAI) { return new BuyTabardAction(botAI); }
|
||||
static Action* guild_manage_nearby(PlayerbotAI* botAI) { return new GuildManageNearbyAction(botAI); }
|
||||
static Action* clean_quest_log(PlayerbotAI* botAI) { return new CleanQuestLogAction(botAI); }
|
||||
|
||||
// BG Tactics
|
||||
static Action* bg_tactics(PlayerbotAI* botAI) { return new BGTactics(botAI); }
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "GuildMgr.h"
|
||||
#include "PlayerbotFactory.h"
|
||||
#include "Playerbots.h"
|
||||
#include "BroadcastHelper.h"
|
||||
|
||||
bool AutoLearnSpellAction::Execute(Event event)
|
||||
{
|
||||
@@ -32,29 +33,12 @@ bool AutoLearnSpellAction::Execute(Event event)
|
||||
|
||||
void AutoLearnSpellAction::LearnSpells(std::ostringstream* out)
|
||||
{
|
||||
if (sPlayerbotAIConfig->autoLearnTrainerSpells &&
|
||||
sRandomPlayerbotMgr->IsRandomBot(bot)) // || (!botAI->GetMaster() && sRandomPlayerbotMgr->IsRandomBot(bot)))
|
||||
BroadcastHelper::BroadcastLevelup(botAI, bot);
|
||||
if (sPlayerbotAIConfig->autoLearnTrainerSpells)
|
||||
LearnTrainerSpells(out);
|
||||
|
||||
if (sPlayerbotAIConfig->autoLearnQuestSpells &&
|
||||
sRandomPlayerbotMgr->IsRandomBot(bot)) // || (!botAI->GetMaster() && sRandomPlayerbotMgr->IsRandomBot(bot)))
|
||||
if (sPlayerbotAIConfig->autoLearnQuestSpells)
|
||||
LearnQuestSpells(out);
|
||||
|
||||
if (sPlayerbotAIConfig->randomBotGuildTalk)
|
||||
{
|
||||
Guild* guild = sGuildMgr->GetGuildById(bot->GetGuildId());
|
||||
if (guild)
|
||||
{
|
||||
std::string toSay = "";
|
||||
|
||||
if (urand(0, 3))
|
||||
toSay = "Ding !";
|
||||
else
|
||||
toSay = "Yay level " + std::to_string(bot->GetLevel()) + " !";
|
||||
|
||||
guild->BroadcastToGuild(bot->GetSession(), false, toSay, LANG_UNIVERSAL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AutoLearnSpellAction::LearnTrainerSpells(std::ostringstream* out)
|
||||
|
||||
@@ -172,6 +172,7 @@ public:
|
||||
creators["naxx chat shortcut"] = &ChatActionContext::naxx_chat_shortcut;
|
||||
creators["bwl chat shortcut"] = &ChatActionContext::bwl_chat_shortcut;
|
||||
creators["tell expected dps"] = &ChatActionContext::tell_expected_dps;
|
||||
creators["join"] = &ChatActionContext::join;
|
||||
creators["calc"] = &ChatActionContext::calc;
|
||||
}
|
||||
|
||||
@@ -269,6 +270,7 @@ private:
|
||||
static Action* naxx_chat_shortcut(PlayerbotAI* ai) { return new NaxxChatShortcutAction(ai); }
|
||||
static Action* bwl_chat_shortcut(PlayerbotAI* ai) { return new BwlChatShortcutAction(ai); }
|
||||
static Action* tell_expected_dps(PlayerbotAI* ai) { return new TellExpectedDpsAction(ai); }
|
||||
static Action* join(PlayerbotAI* ai) { return new JoinGroupAction(ai); }
|
||||
static Action* calc(PlayerbotAI* ai) { return new TellCalculateItemAction(ai); }
|
||||
};
|
||||
|
||||
|
||||
@@ -3,10 +3,9 @@
|
||||
* and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "ChooseRpgTargetAction.h"
|
||||
|
||||
#include <random>
|
||||
|
||||
#include "ChooseRpgTargetAction.h"
|
||||
#include "BattlegroundMgr.h"
|
||||
#include "BudgetValues.h"
|
||||
#include "ChatHelper.h"
|
||||
@@ -14,6 +13,9 @@
|
||||
#include "Formations.h"
|
||||
#include "GuildCreateActions.h"
|
||||
#include "Playerbots.h"
|
||||
#include "RpgSubActions.h"
|
||||
#include "Util.h"
|
||||
#include "ServerFacade.h"
|
||||
#include "PossibleRpgTargetsValue.h"
|
||||
|
||||
bool ChooseRpgTargetAction::HasSameTarget(ObjectGuid guid, uint32 max, GuidVector const& nearGuids)
|
||||
@@ -52,52 +54,94 @@ float ChooseRpgTargetAction::getMaxRelevance(GuidPosition guidP)
|
||||
GuidPosition currentRpgTarget = AI_VALUE(GuidPosition, "rpg target");
|
||||
SET_AI_VALUE(GuidPosition, "rpg target", guidP);
|
||||
|
||||
Strategy* rpgStrategy = botAI->GetAiObjectContext()->GetStrategy("rpg");
|
||||
Strategy* rpgStrategy;
|
||||
|
||||
std::vector<TriggerNode*> triggerNodes;
|
||||
rpgStrategy->InitTriggers(triggerNodes);
|
||||
|
||||
float maxRelevance = 0.0f;
|
||||
|
||||
for (auto& triggerNode : triggerNodes)
|
||||
for (auto& strategy : botAI->GetAiObjectContext()->GetSupportedStrategies())
|
||||
{
|
||||
Trigger* trigger = context->GetTrigger(triggerNode->getName());
|
||||
if (trigger)
|
||||
if (strategy.find("rpg") == std::string::npos)
|
||||
continue;
|
||||
|
||||
if (!botAI->HasStrategy(strategy, BotState::BOT_STATE_NON_COMBAT))
|
||||
continue;
|
||||
|
||||
rpgStrategy = botAI->GetAiObjectContext()->GetStrategy(strategy);
|
||||
|
||||
rpgStrategy->InitTriggers(triggerNodes);
|
||||
|
||||
for (auto triggerNode : triggerNodes)
|
||||
{
|
||||
triggerNode->setTrigger(trigger);
|
||||
Trigger* trigger = context->GetTrigger(triggerNode->getName());
|
||||
|
||||
if (triggerNode->getFirstRelevance() < maxRelevance || triggerNode->getFirstRelevance() > 2.0f)
|
||||
continue;
|
||||
if (trigger)
|
||||
{
|
||||
triggerNode->setTrigger(trigger);
|
||||
|
||||
trigger = triggerNode->getTrigger();
|
||||
if (!trigger->IsActive())
|
||||
continue;
|
||||
if (triggerNode->getFirstRelevance() < maxRelevance || triggerNode->getFirstRelevance() > 2.0f)
|
||||
continue;
|
||||
|
||||
maxRelevance = triggerNode->getFirstRelevance();
|
||||
Trigger* trigger = triggerNode->getTrigger();
|
||||
|
||||
if (!trigger->IsActive())
|
||||
continue;
|
||||
|
||||
NextAction** nextActions = triggerNode->getHandlers();
|
||||
|
||||
bool isRpg = false;
|
||||
|
||||
for (int32 i = 0; i < NextAction::size(nextActions); i++)
|
||||
{
|
||||
NextAction* nextAction = nextActions[i];
|
||||
|
||||
Action* action = botAI->GetAiObjectContext()->GetAction(nextAction->getName());
|
||||
|
||||
if (dynamic_cast<RpgEnabled*>(action))
|
||||
isRpg = true;
|
||||
}
|
||||
NextAction::destroy(nextActions);
|
||||
|
||||
if (isRpg)
|
||||
{
|
||||
maxRelevance = triggerNode->getFirstRelevance();
|
||||
rgpActionReason[guidP] = triggerNode->getName();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (auto trigger : triggerNodes)
|
||||
{
|
||||
delete trigger;
|
||||
}
|
||||
|
||||
triggerNodes.clear();
|
||||
}
|
||||
|
||||
SET_AI_VALUE(GuidPosition, "rpg target", currentRpgTarget);
|
||||
|
||||
for (std::vector<TriggerNode*>::iterator i = triggerNodes.begin(); i != triggerNodes.end(); i++)
|
||||
{
|
||||
TriggerNode* trigger = *i;
|
||||
delete trigger;
|
||||
}
|
||||
if (!maxRelevance)
|
||||
return 0.0;
|
||||
|
||||
triggerNodes.clear();
|
||||
|
||||
return (maxRelevance - 1.0) * 1000.0f;
|
||||
return floor((maxRelevance - 1.0) * 1000.0f);
|
||||
}
|
||||
|
||||
bool ChooseRpgTargetAction::Execute(Event event)
|
||||
{
|
||||
TravelTarget* travelTarget = AI_VALUE(TravelTarget*, "travel target");
|
||||
|
||||
uint32 num = 0;
|
||||
Player* master = botAI->GetMaster();
|
||||
GuidPosition masterRpgTarget;
|
||||
if (master && master != bot && GET_PLAYERBOT_AI(master) && master->GetMapId() == bot->GetMapId() && !master->IsBeingTeleported())
|
||||
{
|
||||
Player* player = botAI->GetMaster();
|
||||
GuidPosition masterRpgTarget = PAI_VALUE(GuidPosition, "rpg target");
|
||||
}
|
||||
else
|
||||
master = nullptr;
|
||||
|
||||
std::unordered_map<ObjectGuid, uint32> targets;
|
||||
|
||||
uint32 num = 0;
|
||||
GuidVector possibleTargets = AI_VALUE(GuidVector, "possible rpg targets");
|
||||
GuidVector possibleObjects = AI_VALUE(GuidVector, "nearest game objects no los");
|
||||
GuidVector possiblePlayers = AI_VALUE(GuidVector, "nearest friendly players");
|
||||
@@ -180,18 +224,22 @@ bool ChooseRpgTargetAction::Execute(Event event)
|
||||
|
||||
for (auto it = begin(targets); it != end(targets);)
|
||||
{
|
||||
if (it->second == 0 || (hasGoodRelevance && it->second <= 1.0))
|
||||
{
|
||||
//Remove empty targets.
|
||||
if (it->second == 0)
|
||||
it = targets.erase(it);
|
||||
//Remove useless targets if there's any good ones
|
||||
else if (hasGoodRelevance && it->second <= 1.0)
|
||||
it = targets.erase(it);
|
||||
//Remove useless targets if it's not masters target.
|
||||
else if (!hasGoodRelevance && master && (!masterRpgTarget || it->first != masterRpgTarget))
|
||||
it = targets.erase(it);
|
||||
}
|
||||
else
|
||||
++it;
|
||||
}
|
||||
|
||||
if (targets.empty())
|
||||
{
|
||||
LOG_DEBUG("playerbots", "{} can't choose RPG target: all {} are not available", bot->GetName().c_str(),
|
||||
possibleTargets.size());
|
||||
LOG_DEBUG("playerbots", "{} can't choose RPG target: all {} targets are not available", bot->GetName().c_str(), possibleTargets.size());
|
||||
RESET_AI_VALUE(GuidSet&, "ignore rpg target");
|
||||
RESET_AI_VALUE(GuidPosition, "rpg target");
|
||||
return false;
|
||||
@@ -244,17 +292,20 @@ bool ChooseRpgTargetAction::isUseful()
|
||||
if (!botAI->AllowActivity(RPG_ACTIVITY))
|
||||
return false;
|
||||
|
||||
if (AI_VALUE(GuidPosition, "rpg target"))
|
||||
GuidPosition guidP = AI_VALUE(GuidPosition, "rpg target");
|
||||
|
||||
if (guidP && guidP.distance(bot) < sPlayerbotAIConfig->reactDistance * 2)
|
||||
return false;
|
||||
|
||||
TravelTarget* travelTarget = AI_VALUE(TravelTarget*, "travel target");
|
||||
|
||||
if (travelTarget->isTraveling() && isFollowValid(bot, *travelTarget->getPosition()))
|
||||
return false;
|
||||
//if (travelTarget->isTraveling() && AI_VALUE2(bool, "can free move to", *travelTarget->getPosition()))
|
||||
//return false;
|
||||
|
||||
if (AI_VALUE(GuidVector, "possible rpg targets").empty())
|
||||
return false;
|
||||
|
||||
//Not stay, not guard, not combat, not trading and group ready.
|
||||
if (!AI_VALUE(bool, "can move around"))
|
||||
return false;
|
||||
|
||||
|
||||
@@ -28,7 +28,9 @@ public:
|
||||
|
||||
private:
|
||||
float getMaxRelevance(GuidPosition guidP);
|
||||
bool HasSameTarget(ObjectGuid guid, uint32 max, GuidVector const& nearGuids);
|
||||
bool HasSameTarget(ObjectGuid guid, uint32 max, GuidVector const& nearGuids);
|
||||
|
||||
std::unordered_map <ObjectGuid, std::string> rgpActionReason;
|
||||
};
|
||||
|
||||
class ClearRpgTargetAction : public ChooseRpgTargetAction
|
||||
|
||||
@@ -11,19 +11,26 @@
|
||||
|
||||
bool ChooseTravelTargetAction::Execute(Event event)
|
||||
{
|
||||
// Get the current travel target. This target is no longer active.
|
||||
Player* requester = event.getOwner() ? event.getOwner() : GetMaster();
|
||||
|
||||
//Get the current travel target. This target is no longer active.
|
||||
TravelTarget* oldTarget = context->GetValue<TravelTarget*>("travel target")->Get();
|
||||
|
||||
// Select a new target to travel to.
|
||||
//Select a new target to travel to.
|
||||
TravelTarget newTarget = TravelTarget(botAI);
|
||||
getNewTarget(&newTarget, oldTarget);
|
||||
|
||||
// If the new target is not active we failed.
|
||||
if (!newTarget.isActive())
|
||||
if (!oldTarget) return false;
|
||||
|
||||
if (!oldTarget->isForced() || oldTarget->getStatus() == TravelStatus::TRAVEL_STATUS_EXPIRED)
|
||||
getNewTarget(&newTarget, oldTarget);
|
||||
else
|
||||
newTarget.copyTarget(oldTarget);
|
||||
|
||||
//If the new target is not active we failed.
|
||||
if (!newTarget.isActive() && !newTarget.isForced())
|
||||
return false;
|
||||
|
||||
setNewTarget(&newTarget, oldTarget);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -34,64 +41,141 @@ bool ChooseTravelTargetAction::Execute(Event event)
|
||||
// Eventually we want to rewrite this to be more intelligent.
|
||||
void ChooseTravelTargetAction::getNewTarget(TravelTarget* newTarget, TravelTarget* oldTarget)
|
||||
{
|
||||
bool foundTarget = false;
|
||||
// Join groups members
|
||||
bool foundTarget = foundTarget = SetGroupTarget(newTarget);
|
||||
|
||||
foundTarget = SetGroupTarget(newTarget); // Join groups members
|
||||
|
||||
// Enpty bags/repair
|
||||
if (!foundTarget && urand(1, 100) > 10) // 90% chance
|
||||
if (AI_VALUE2(bool, "group or", "should sell,can sell,following party,near leader") ||
|
||||
AI_VALUE2(bool, "group or", "should repair,can repair,following party,near leader"))
|
||||
foundTarget = SetRpgTarget(newTarget); // Go to town to sell items or repair
|
||||
|
||||
// Rpg in city
|
||||
if (!foundTarget && urand(1, 100) > 90) // 10% chance
|
||||
foundTarget =
|
||||
SetNpcFlagTarget(newTarget, {UNIT_NPC_FLAG_BANKER, UNIT_NPC_FLAG_BATTLEMASTER, UNIT_NPC_FLAG_AUCTIONEER});
|
||||
|
||||
// Grind for money
|
||||
if (!foundTarget && AI_VALUE(bool, "should get money"))
|
||||
//Empty bags/repair
|
||||
if (!foundTarget && urand(1, 100) > 10 && bot->GetLevel() > 5) //90% chance
|
||||
{
|
||||
if (urand(1, 100) > 66)
|
||||
if (AI_VALUE2(bool, "group or", "should sell,can sell,following party,near leader") ||
|
||||
AI_VALUE2(bool, "group or", "should repair,can repair,following party,near leader")
|
||||
)
|
||||
{
|
||||
foundTarget = SetQuestTarget(newTarget, true); // Turn in quests for money.
|
||||
|
||||
if (!foundTarget)
|
||||
foundTarget = SetQuestTarget(newTarget); // Do low level quests
|
||||
}
|
||||
else if (urand(1, 100) > 50)
|
||||
{
|
||||
foundTarget = SetGrindTarget(newTarget); // Go grind mobs for money
|
||||
}
|
||||
else
|
||||
{
|
||||
foundTarget = SetNewQuestTarget(newTarget); // Find a low level quest to do
|
||||
foundTarget = SetRpgTarget(newTarget); //Go to town to sell items or repair
|
||||
}
|
||||
}
|
||||
|
||||
// Continue
|
||||
if (!foundTarget && urand(1, 100) > 10) // 90% chance
|
||||
foundTarget = SetCurrentTarget(newTarget, oldTarget); // Extend current target.
|
||||
//Rpg in city
|
||||
if (!foundTarget && urand(1, 100) > 90 && bot->GetLevel() > 5) //10% chance
|
||||
{
|
||||
foundTarget = SetNpcFlagTarget(newTarget, { UNIT_NPC_FLAG_BANKER,UNIT_NPC_FLAG_BATTLEMASTER,UNIT_NPC_FLAG_AUCTIONEER });
|
||||
}
|
||||
|
||||
// Dungeon in group
|
||||
if (!foundTarget && urand(1, 100) > 50) // 50% chance
|
||||
// PvP activities
|
||||
bool pvpActivate = false;
|
||||
if (pvpActivate && !foundTarget && urand(0, 4) && bot->GetLevel() > 50)
|
||||
{
|
||||
WorldPosition pos = WorldPosition(bot);
|
||||
WorldPosition* botPos = &pos;
|
||||
TravelTarget* target = context->GetValue<TravelTarget*>("travel target")->Get();
|
||||
|
||||
TravelDestination* dest = ChooseTravelTargetAction::FindDestination(bot, "Tarren Mill");
|
||||
if (dest)
|
||||
{
|
||||
std::vector<WorldPosition*> points = dest->nextPoint(botPos, true);
|
||||
if (!points.empty())
|
||||
{
|
||||
target->setTarget(dest, points.front());
|
||||
target->setForced(true);
|
||||
|
||||
std::ostringstream out; out << "Traveling to " << dest->getTitle();
|
||||
botAI->TellMasterNoFacing(out.str());
|
||||
foundTarget = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Grind for money
|
||||
if (!foundTarget && AI_VALUE(bool, "should get money"))
|
||||
{
|
||||
//Empty mail for money
|
||||
//if (AI_VALUE(bool, "can get mail"))
|
||||
//{
|
||||
// foundTarget = SetGOTypeTarget(requester, newTarget, GAMEOBJECT_TYPE_MAILBOX, "", false); //Find a mailbox
|
||||
//}
|
||||
|
||||
if (!foundTarget)
|
||||
{
|
||||
// 50% Focus on active quests for money.
|
||||
if (urand(1, 100) > 50)
|
||||
{
|
||||
// 50% Focus on active quests for money.
|
||||
if (urand(1, 100) > 50)
|
||||
{
|
||||
// Turn in quests for money.
|
||||
foundTarget = SetQuestTarget(newTarget, true, false, true, true);
|
||||
}
|
||||
|
||||
if (!foundTarget)
|
||||
{
|
||||
// Find new (low) level quests
|
||||
foundTarget = SetQuestTarget(newTarget, false, true, false, false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Go grind mobs for money
|
||||
foundTarget = SetGrindTarget(newTarget);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//Continue current target. 90% chance
|
||||
if (!foundTarget && urand(1, 100) > 10)
|
||||
{
|
||||
// Extend current target.
|
||||
foundTarget = SetCurrentTarget(newTarget, oldTarget);
|
||||
}
|
||||
|
||||
//Get mail 30% chance
|
||||
//if (!foundTarget && urand(1, 100) > 70)
|
||||
//{
|
||||
// if (AI_VALUE(bool, "can get mail"))
|
||||
// {
|
||||
// foundTarget = SetGOTypeTarget(requester, newTarget, GAMEOBJECT_TYPE_MAILBOX, "", false); //Find a mailbox
|
||||
// }
|
||||
//}
|
||||
|
||||
//Dungeon in group. 50% chance
|
||||
if (!foundTarget && urand(1, 100) > 50)
|
||||
{
|
||||
if (AI_VALUE(bool, "can fight boss"))
|
||||
foundTarget = SetBossTarget(newTarget); // Go fight a (dungeon boss)
|
||||
|
||||
if (!foundTarget && urand(1, 100) > 5) // 95% chance
|
||||
foundTarget = SetQuestTarget(newTarget); // Do a target of an active quest.
|
||||
|
||||
{
|
||||
// Go fight a (dungeon boss)
|
||||
foundTarget = SetBossTarget(newTarget);
|
||||
}
|
||||
}
|
||||
|
||||
//Do quests (start, do, end) 95% chance
|
||||
if (!foundTarget && urand(1, 100) > 5)
|
||||
foundTarget = SetNewQuestTarget(newTarget); // Find a new quest to do.
|
||||
{
|
||||
// Do any nearby
|
||||
foundTarget = SetQuestTarget(newTarget, false, true, true, true);
|
||||
}
|
||||
|
||||
if (!foundTarget && botAI->HasStrategy("explore", BOT_STATE_NON_COMBAT)) // Explore a unexplored sub-zone.
|
||||
//Explore a nearby unexplored area.
|
||||
if (!foundTarget && botAI->HasStrategy("explore", BotState::BOT_STATE_NON_COMBAT) && urand(1, 100) > 90) //10% chance Explore a unexplored sub-zone.
|
||||
{
|
||||
foundTarget = SetExploreTarget(newTarget);
|
||||
}
|
||||
|
||||
// if (!foundTarget)
|
||||
// foundTarget = SetRpgTarget(target);
|
||||
//Just hang with an npc 50% chance
|
||||
if (!foundTarget && urand(1, 100) > 50)
|
||||
{
|
||||
foundTarget = SetRpgTarget(newTarget);
|
||||
if (foundTarget)
|
||||
newTarget->setForced(true);
|
||||
}
|
||||
|
||||
if (!foundTarget)
|
||||
SetNullTarget(newTarget); // Idle a bit.
|
||||
{
|
||||
foundTarget = SetGrindTarget(newTarget);
|
||||
}
|
||||
|
||||
// Idle a bit.
|
||||
if (!foundTarget)
|
||||
SetNullTarget(newTarget);
|
||||
}
|
||||
|
||||
void ChooseTravelTargetAction::setNewTarget(TravelTarget* newTarget, TravelTarget* oldTarget)
|
||||
@@ -395,45 +479,57 @@ bool ChooseTravelTargetAction::SetCurrentTarget(TravelTarget* target, TravelTarg
|
||||
return target->isActive();
|
||||
}
|
||||
|
||||
bool ChooseTravelTargetAction::SetQuestTarget(TravelTarget* target, bool onlyCompleted)
|
||||
bool ChooseTravelTargetAction::SetQuestTarget(TravelTarget* target, bool onlyCompleted, bool newQuests, bool activeQuests, bool completedQuests)
|
||||
{
|
||||
std::vector<TravelDestination*> activeDestinations;
|
||||
std::vector<WorldPosition*> activePoints;
|
||||
|
||||
QuestStatusMap& questMap = bot->getQuestStatusMap();
|
||||
|
||||
WorldPosition botLocation(bot);
|
||||
bool onlyClassQuest = !urand(0, 10);
|
||||
|
||||
// Find destinations related to the active quests.
|
||||
for (auto& quest : questMap)
|
||||
if (newQuests)
|
||||
{
|
||||
if (bot->IsQuestRewarded(quest.first))
|
||||
continue;
|
||||
|
||||
uint32 questId = quest.first;
|
||||
QuestStatusData* questStatus = &quest.second;
|
||||
|
||||
if (onlyCompleted && sObjectMgr->GetQuestTemplate(questId) &&
|
||||
!bot->CanRewardQuest(sObjectMgr->GetQuestTemplate(questId), false))
|
||||
continue;
|
||||
|
||||
std::vector<TravelDestination*> questDestinations =
|
||||
sTravelMgr->getQuestTravelDestinations(bot, questId, botAI->HasRealPlayerMaster(), false, 5000);
|
||||
std::vector<WorldPosition*> questPoints;
|
||||
|
||||
for (auto& questDestination : questDestinations)
|
||||
// Prefer new quests near the player at lower levels.
|
||||
activeDestinations = sTravelMgr->getQuestTravelDestinations(bot, -1, true, false, 400 + bot->GetLevel() * 10);
|
||||
}
|
||||
if (activeQuests || completedQuests)
|
||||
{
|
||||
QuestStatusMap& questMap = bot->getQuestStatusMap();
|
||||
//Find destinations related to the active quests.
|
||||
for (auto& quest : questMap)
|
||||
{
|
||||
std::vector<WorldPosition*> destinationPoints = questDestination->getPoints();
|
||||
if (!destinationPoints.empty())
|
||||
questPoints.insert(questPoints.end(), destinationPoints.begin(), destinationPoints.end());
|
||||
}
|
||||
if (bot->IsQuestRewarded(quest.first))
|
||||
continue;
|
||||
|
||||
if (getBestDestination(&questDestinations, &questPoints))
|
||||
{
|
||||
activeDestinations.push_back(questDestinations.front());
|
||||
activePoints.push_back(questPoints.front());
|
||||
uint32 questId = quest.first;
|
||||
QuestStatusData* questStatus = &quest.second;
|
||||
const auto questTemplate = sObjectMgr->GetQuestTemplate(questId);
|
||||
|
||||
if (!activeQuests && !bot->CanRewardQuest(questTemplate, false))
|
||||
continue;
|
||||
|
||||
if (!completedQuests && bot->CanRewardQuest(questTemplate, false))
|
||||
continue;
|
||||
|
||||
//Find quest takers or objectives
|
||||
std::vector<TravelDestination*> questDestinations = sTravelMgr->getQuestTravelDestinations(bot, questId, true, false, 0);
|
||||
|
||||
if (onlyClassQuest && activeDestinations.size() && questDestinations.size()) //Only do class quests if we have any.
|
||||
{
|
||||
if (activeDestinations.front()->GetQuestTemplate()->GetRequiredClasses() && !questTemplate->GetRequiredClasses())
|
||||
continue;
|
||||
|
||||
if (!activeDestinations.front()->GetQuestTemplate()->GetRequiredClasses() && questTemplate->GetRequiredClasses())
|
||||
activeDestinations.clear();
|
||||
}
|
||||
|
||||
activeDestinations.insert(activeDestinations.end(), questDestinations.begin(), questDestinations.end());
|
||||
}
|
||||
}
|
||||
if (newQuests && activeDestinations.empty())
|
||||
activeDestinations = sTravelMgr->getQuestTravelDestinations(bot, -1, true, false); //If we really don't find any new quests look futher away.
|
||||
|
||||
if (botAI->HasStrategy("debug travel", BotState::BOT_STATE_NON_COMBAT))
|
||||
botAI->TellMasterNoFacing(std::to_string(activeDestinations.size()) + " quest destinations found.");
|
||||
|
||||
if (!getBestDestination(&activeDestinations, &activePoints))
|
||||
return false;
|
||||
@@ -726,7 +822,7 @@ bool ChooseTravelTargetAction::SetNullTarget(TravelTarget* target)
|
||||
std::vector<std::string> split(std::string const s, char delim);
|
||||
char* strstri(char const* haystack, char const* needle);
|
||||
|
||||
TravelDestination* ChooseTravelTargetAction::FindDestination(Player* bot, std::string const name)
|
||||
TravelDestination* ChooseTravelTargetAction::FindDestination(Player* bot, std::string const name, bool zones, bool npcs, bool quests, bool mobs, bool bosses)
|
||||
{
|
||||
PlayerbotAI* botAI = GET_PLAYERBOT_AI(bot);
|
||||
|
||||
@@ -734,32 +830,54 @@ TravelDestination* ChooseTravelTargetAction::FindDestination(Player* bot, std::s
|
||||
|
||||
std::vector<TravelDestination*> dests;
|
||||
|
||||
// Zones
|
||||
for (auto& d : sTravelMgr->getExploreTravelDestinations(bot, true, true))
|
||||
//Quests
|
||||
if (quests)
|
||||
{
|
||||
if (strstri(d->getTitle().c_str(), name.c_str()))
|
||||
dests.push_back(d);
|
||||
for (auto& d : sTravelMgr->getQuestTravelDestinations(bot, 0, true, true))
|
||||
{
|
||||
if (strstri(d->getTitle().c_str(), name.c_str()))
|
||||
dests.push_back(d);
|
||||
}
|
||||
}
|
||||
|
||||
// Npcs
|
||||
for (auto& d : sTravelMgr->getRpgTravelDestinations(bot, true, true))
|
||||
//Zones
|
||||
if (zones)
|
||||
{
|
||||
if (strstri(d->getTitle().c_str(), name.c_str()))
|
||||
dests.push_back(d);
|
||||
for (auto& d : sTravelMgr->getExploreTravelDestinations(bot, true, true))
|
||||
{
|
||||
if (strstri(d->getTitle().c_str(), name.c_str()))
|
||||
dests.push_back(d);
|
||||
}
|
||||
}
|
||||
|
||||
// Mobs
|
||||
for (auto& d : sTravelMgr->getGrindTravelDestinations(bot, true, true))
|
||||
//Npcs
|
||||
if (npcs)
|
||||
{
|
||||
if (strstri(d->getTitle().c_str(), name.c_str()))
|
||||
dests.push_back(d);
|
||||
for (auto& d : sTravelMgr->getRpgTravelDestinations(bot, true, true))
|
||||
{
|
||||
if (strstri(d->getTitle().c_str(), name.c_str()))
|
||||
dests.push_back(d);
|
||||
}
|
||||
}
|
||||
|
||||
// Bosses
|
||||
for (auto& d : sTravelMgr->getBossTravelDestinations(bot, true, true))
|
||||
//Mobs
|
||||
if (mobs)
|
||||
{
|
||||
if (strstri(d->getTitle().c_str(), name.c_str()))
|
||||
dests.push_back(d);
|
||||
for (auto& d : sTravelMgr->getGrindTravelDestinations(bot, true, true, 5000.0f))
|
||||
{
|
||||
if (strstri(d->getTitle().c_str(), name.c_str()))
|
||||
dests.push_back(d);
|
||||
}
|
||||
}
|
||||
|
||||
//Bosses
|
||||
if (bosses)
|
||||
{
|
||||
for (auto& d : sTravelMgr->getBossTravelDestinations(bot, true, true))
|
||||
{
|
||||
if (strstri(d->getTitle().c_str(), name.c_str()))
|
||||
dests.push_back(d);
|
||||
}
|
||||
}
|
||||
|
||||
WorldPosition botPos(bot);
|
||||
@@ -767,13 +885,11 @@ TravelDestination* ChooseTravelTargetAction::FindDestination(Player* bot, std::s
|
||||
if (dests.empty())
|
||||
return nullptr;
|
||||
|
||||
TravelDestination* dest = *std::min_element(dests.begin(), dests.end(),
|
||||
[botPos](TravelDestination* i, TravelDestination* j) {
|
||||
return i->distanceTo(const_cast<WorldPosition*>(&botPos)) <
|
||||
j->distanceTo(const_cast<WorldPosition*>(&botPos));
|
||||
});
|
||||
|
||||
return dest;
|
||||
return *std::min_element(dests.begin(), dests.end(),
|
||||
[botPos](TravelDestination* i, TravelDestination* j)
|
||||
{
|
||||
return i->distanceTo(const_cast<WorldPosition*>(&botPos)) < j->distanceTo(const_cast<WorldPosition*>(&botPos));
|
||||
});
|
||||
};
|
||||
|
||||
bool ChooseTravelTargetAction::isUseful()
|
||||
|
||||
@@ -26,26 +26,23 @@ public:
|
||||
bool Execute(Event event) override;
|
||||
bool isUseful() override;
|
||||
|
||||
static TravelDestination* FindDestination(Player* bot, std::string const name);
|
||||
static TravelDestination* FindDestination(Player* bot, std::string const name, bool zones = true, bool npcs = true, bool quests = true, bool mobs = true, bool bosses = true);
|
||||
|
||||
protected:
|
||||
void getNewTarget(TravelTarget* newTarget, TravelTarget* oldTarget);
|
||||
void setNewTarget(TravelTarget* newTarget, TravelTarget* oldTarget);
|
||||
void ReportTravelTarget(TravelTarget* newTarget, TravelTarget* oldTarget);
|
||||
|
||||
bool getBestDestination(std::vector<TravelDestination*>* activeDestinations,
|
||||
std::vector<WorldPosition*>* activePoints);
|
||||
|
||||
bool getBestDestination(std::vector<TravelDestination*>* activeDestinations, std::vector<WorldPosition*>* activePoints);
|
||||
bool SetGroupTarget(TravelTarget* target);
|
||||
bool SetCurrentTarget(TravelTarget* target, TravelTarget* oldTarget);
|
||||
bool SetQuestTarget(TravelTarget* target, bool onlyCompleted = false);
|
||||
bool SetQuestTarget(TravelTarget* target, bool onlyCompleted = false, bool newQuests = true, bool activeQuests = true, bool completedQuests = true);
|
||||
bool SetNewQuestTarget(TravelTarget* target);
|
||||
bool SetRpgTarget(TravelTarget* target);
|
||||
bool SetGrindTarget(TravelTarget* target);
|
||||
bool SetBossTarget(TravelTarget* target);
|
||||
bool SetExploreTarget(TravelTarget* target);
|
||||
bool SetNpcFlagTarget(TravelTarget* target, std::vector<NPCFlags> flags, std::string const name = "",
|
||||
std::vector<uint32> items = {});
|
||||
bool SetNpcFlagTarget(TravelTarget* target, std::vector<NPCFlags> flags, std::string const name = "", std::vector<uint32> items = { });
|
||||
bool SetNullTarget(TravelTarget* target);
|
||||
|
||||
private:
|
||||
|
||||
@@ -46,28 +46,44 @@ bool DropQuestAction::Execute(Event event)
|
||||
bot->RemoveRewardedQuest(entry);
|
||||
bot->RemoveActiveQuest(entry, false);
|
||||
|
||||
if (botAI->HasStrategy("debug quest", BotState::BOT_STATE_NON_COMBAT) || botAI->HasStrategy("debug rpg", BotState::BOT_STATE_COMBAT))
|
||||
{
|
||||
const Quest* pQuest = sObjectMgr->GetQuestTemplate(entry);
|
||||
const std::string text_quest = ChatHelper::FormatQuest(pQuest);
|
||||
LOG_INFO("playerbots", "{} => Quest [ {} ] removed", bot->GetName(), pQuest->GetTitle());
|
||||
bot->Say("Quest [ " + text_quest + " ] removed", LANG_UNIVERSAL);
|
||||
}
|
||||
|
||||
botAI->TellMaster("Quest removed");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CleanQuestLogAction::Execute(Event event)
|
||||
{
|
||||
std::string const link = event.getParam();
|
||||
if (botAI->HasActivePlayerMaster())
|
||||
Player* requester = event.getOwner() ? event.getOwner() : GetMaster();
|
||||
std::string link = event.getParam();
|
||||
if (botAI->HasActivePlayerMaster() || !sRandomPlayerbotMgr->IsRandomBot(bot))
|
||||
return false;
|
||||
|
||||
uint8 totalQuests = 0;
|
||||
|
||||
DropQuestType(totalQuests); // Count the total quests
|
||||
|
||||
// Count the total quests
|
||||
DropQuestType(totalQuests);
|
||||
if (MAX_QUEST_LOG_SIZE - totalQuests > 6)
|
||||
return true;
|
||||
|
||||
if (AI_VALUE(bool, "can fight equal")) // Only drop gray quests when able to fight proper lvl quests.
|
||||
{
|
||||
DropQuestType(totalQuests, MAX_QUEST_LOG_SIZE - 6); // Drop gray/red quests.
|
||||
DropQuestType(totalQuests, MAX_QUEST_LOG_SIZE - 6, false, true); // Drop gray/red quests with progress.
|
||||
DropQuestType(totalQuests, MAX_QUEST_LOG_SIZE - 6, false, true, true); // Drop gray/red completed quests.
|
||||
// Drop failed quests
|
||||
DropQuestType(totalQuests, MAX_QUEST_LOG_SIZE, true, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Only drop gray quests when able to fight proper lvl quests.
|
||||
if (AI_VALUE(bool, "can fight equal"))
|
||||
{
|
||||
// Drop gray/red quests.
|
||||
DropQuestType(totalQuests, MAX_QUEST_LOG_SIZE - 6);
|
||||
// Drop gray/red quests with progress.
|
||||
DropQuestType(totalQuests, MAX_QUEST_LOG_SIZE - 6, false, true);
|
||||
// Drop gray/red completed quests.
|
||||
DropQuestType(totalQuests, MAX_QUEST_LOG_SIZE - 6, false, true, true);
|
||||
}
|
||||
|
||||
if (MAX_QUEST_LOG_SIZE - totalQuests > 4)
|
||||
@@ -93,7 +109,19 @@ bool CleanQuestLogAction::Execute(Event event)
|
||||
|
||||
void CleanQuestLogAction::DropQuestType(uint8& numQuest, uint8 wantNum, bool isGreen, bool hasProgress, bool isComplete)
|
||||
{
|
||||
std::vector<uint8> slots;
|
||||
for (uint8 slot = 0; slot < MAX_QUEST_LOG_SIZE; ++slot)
|
||||
slots.push_back(slot);
|
||||
|
||||
if (wantNum < 100)
|
||||
{
|
||||
std::random_device rd;
|
||||
std::mt19937 g(rd());
|
||||
|
||||
std::shuffle(slots.begin(), slots.end(), g);
|
||||
}
|
||||
|
||||
for (uint8 slot : slots)
|
||||
{
|
||||
uint32 questId = bot->GetQuestSlotQuestId(slot);
|
||||
if (!questId)
|
||||
@@ -103,12 +131,8 @@ void CleanQuestLogAction::DropQuestType(uint8& numQuest, uint8 wantNum, bool isG
|
||||
if (!quest)
|
||||
continue;
|
||||
|
||||
if (quest->GetRequiredClasses() &&
|
||||
(quest->GetRewSpellCast() || quest->GetRewSpell())) // Do not drop class specific quests that learn spells.
|
||||
continue;
|
||||
|
||||
if (quest->GetRequiredClasses() &&
|
||||
(quest->GetRewSpellCast() || quest->GetRewSpell())) // Do not drop class specific quests that learn spells.
|
||||
// Do not drop class quest, may be not rewarding gold but important spells
|
||||
if (quest->GetRequiredClasses())
|
||||
continue;
|
||||
|
||||
if (wantNum == 100)
|
||||
@@ -128,13 +152,14 @@ void CleanQuestLogAction::DropQuestType(uint8& numQuest, uint8 wantNum, bool isG
|
||||
continue;
|
||||
}
|
||||
|
||||
if (HasProgress(bot, quest) && !hasProgress)
|
||||
if (HasProgress(bot, quest) && !hasProgress && bot->GetQuestStatus(questId) != QUEST_STATUS_FAILED)
|
||||
continue;
|
||||
|
||||
if (bot->GetQuestStatus(questId) == QUEST_STATUS_COMPLETE && !isComplete)
|
||||
continue;
|
||||
|
||||
if (numQuest <= wantNum && bot->GetQuestStatus(questId) != QUEST_STATUS_FAILED) // Always drop failed quests
|
||||
// Always drop failed quests
|
||||
if (numQuest <= wantNum && bot->GetQuestStatus(questId) != QUEST_STATUS_FAILED)
|
||||
continue;
|
||||
|
||||
// Drop quest.
|
||||
@@ -148,6 +173,12 @@ void CleanQuestLogAction::DropQuestType(uint8& numQuest, uint8 wantNum, bool isG
|
||||
|
||||
numQuest--;
|
||||
|
||||
if (botAI->HasStrategy("debug quest", BotState::BOT_STATE_NON_COMBAT) || botAI->HasStrategy("debug rpg", BotState::BOT_STATE_COMBAT))
|
||||
{
|
||||
const std::string text_quest = ChatHelper::FormatQuest(quest);
|
||||
LOG_INFO("playerbots", "{} => Quest [ {} ] removed", bot->GetName(), quest->GetTitle());
|
||||
bot->Say("Quest [ " + text_quest + " ] removed", LANG_UNIVERSAL);
|
||||
}
|
||||
botAI->TellMaster("Quest removed" + chat->FormatQuest(quest));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
#include "MovementActions.h"
|
||||
|
||||
class PlayerbotAI;
|
||||
class TravelDestination;
|
||||
class WorldPosition;
|
||||
|
||||
class GoAction : public MovementAction
|
||||
{
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "GuildPackets.h"
|
||||
#include "Playerbots.h"
|
||||
#include "ServerFacade.h"
|
||||
#include "BroadcastHelper.h"
|
||||
|
||||
Player* GuidManageAction::GetPlayer(Event event)
|
||||
{
|
||||
@@ -154,62 +155,141 @@ bool GuildManageNearbyAction::Execute(Event event)
|
||||
if (!player || bot == player)
|
||||
continue;
|
||||
|
||||
if (player->GetGuildId()) // Promote or demote nearby members based on chance.
|
||||
if (player->isDND())
|
||||
continue;
|
||||
|
||||
// Promote or demote nearby members based on chance.
|
||||
if (player->GetGuildId() && player->GetGuildId() == bot->GetGuildId())
|
||||
{
|
||||
Guild::Member* member = guild->GetMember(player->GetGUID());
|
||||
uint32 dCount = AI_VALUE(uint32, "death count");
|
||||
|
||||
if ((dCount < 2 || !urand(0, 10)) && guild->GetRankRights(botMember->GetRankId() & GR_RIGHT_PROMOTE))
|
||||
if (!urand(0, 30) && dCount < 2 && guild->GetRankRights(botMember->GetRankId()) & GR_RIGHT_PROMOTE)
|
||||
{
|
||||
if (!urand(0, 10))
|
||||
{
|
||||
botAI->DoSpecificAction("guild promote", Event("guild management", guid), true);
|
||||
BroadcastHelper::BroadcastGuildMemberPromotion(botAI, bot, player);
|
||||
|
||||
continue;
|
||||
}
|
||||
botAI->DoSpecificAction("guild promote", Event("guild management", guid), true);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((dCount > 3 || !urand(0, 10)) && guild->GetRankRights(botMember->GetRankId() & GR_RIGHT_DEMOTE))
|
||||
if (!urand(0, 30) && dCount > 2 && guild->GetRankRights(botMember->GetRankId()) & GR_RIGHT_DEMOTE)
|
||||
{
|
||||
if (!urand(0, 10))
|
||||
{
|
||||
botAI->DoSpecificAction("guild demote", Event("guild management", guid), true);
|
||||
BroadcastHelper::BroadcastGuildMemberDemotion(botAI, bot, player);
|
||||
|
||||
continue;
|
||||
}
|
||||
botAI->DoSpecificAction("guild demote", Event("guild management", guid), true);
|
||||
continue;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(guild->GetRankRights(botMember->GetRankId()) & GR_RIGHT_INVITE))
|
||||
if (!sPlayerbotAIConfig->randomBotGuildNearby)
|
||||
return false;
|
||||
|
||||
if (guild->GetMemberSize() > 1000)
|
||||
return false;
|
||||
|
||||
if ( (guild->GetRankRights(botMember->GetRankId()) & GR_RIGHT_INVITE) == 0)
|
||||
continue;
|
||||
|
||||
if (player->GetGuildIdInvited())
|
||||
continue;
|
||||
|
||||
PlayerbotAI* botAI = GET_PLAYERBOT_AI(player);
|
||||
PlayerbotAI* botAi = GET_PLAYERBOT_AI(player);
|
||||
|
||||
if (botAI)
|
||||
{
|
||||
if (botAI->GetGuilderType() == GuilderType::SOLO &&
|
||||
!botAI->HasRealPlayerMaster()) // Do not invite solo players.
|
||||
continue;
|
||||
|
||||
if (botAI->HasActivePlayerMaster()) // Do not invite alts of active players.
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!sPlayerbotAIConfig->randomBotGroupNearby)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (sServerFacade->GetDistance2d(bot, player) > sPlayerbotAIConfig->sightDistance)
|
||||
if (!sPlayerbotAIConfig->randomBotInvitePlayer && botAi && botAi->IsRealPlayer())
|
||||
continue;
|
||||
|
||||
if (botAI && botAI->DoSpecificAction("ginvite", Event("guild management", guid)))
|
||||
if (botAi)
|
||||
{
|
||||
if (botAi->GetGuilderType() == GuilderType::SOLO && !botAi->HasRealPlayerMaster()) //Do not invite solo players.
|
||||
continue;
|
||||
|
||||
if (botAi->HasActivePlayerMaster() && !sRandomPlayerbotMgr->IsRandomBot(player)) //Do not invite alts of active players.
|
||||
continue;
|
||||
}
|
||||
|
||||
bool sameGroup = bot->GetGroup() && bot->GetGroup()->IsMember(player->GetGUID());
|
||||
|
||||
if (!sameGroup && sServerFacade->GetDistance2d(bot, player) > sPlayerbotAIConfig->spellDistance)
|
||||
continue;
|
||||
|
||||
if (sPlayerbotAIConfig->inviteChat && (sRandomPlayerbotMgr->IsRandomBot(bot) || !botAI->HasActivePlayerMaster()))
|
||||
{
|
||||
/* std::map<std::string, std::string> placeholders;
|
||||
placeholders["%name"] = player->GetName();
|
||||
placeholders["%members"] = std::to_string(guild->GetMemberSize());
|
||||
placeholders["%guildname"] = guild->GetName();
|
||||
AreaTableEntry const* current_area = botAI->GetCurrentArea();
|
||||
AreaTableEntry const* current_zone = botAI->GetCurrentZone();
|
||||
placeholders["%area_name"] = current_area ? current_area->area_name[BroadcastHelper::GetLocale()] : BOT_TEXT1("string_unknown_area");
|
||||
placeholders["%zone_name"] = current_zone ? current_zone->area_name[BroadcastHelper::GetLocale()] : BOT_TEXT1("string_unknown_area");
|
||||
|
||||
std::vector<std::string> lines;
|
||||
|
||||
//TODO - Move these hardcoded texts to sql!
|
||||
switch ((urand(0, 10) * urand(0, 10)) / 10)
|
||||
{
|
||||
case 0:
|
||||
lines.push_back(BOT_TEXT2("Hey %name do you want to join my guild?", placeholders));
|
||||
break;
|
||||
case 1:
|
||||
lines.push_back(BOT_TEXT2("Hey man you wanna join my guild %name?", placeholders));
|
||||
break;
|
||||
case 2:
|
||||
lines.push_back(BOT_TEXT2("I think you would be a good contribution to %guildname. Would you like to join %name?", placeholders));
|
||||
break;
|
||||
case 3:
|
||||
lines.push_back(BOT_TEXT2("My guild %guildname has %members quality members. Would you like to make it 1 more %name?", placeholders));
|
||||
break;
|
||||
case 4:
|
||||
lines.push_back(BOT_TEXT2("Hey %name do you want to join %guildname? We have %members members and looking to become number 1 of the server.", placeholders));
|
||||
break;
|
||||
case 5:
|
||||
lines.push_back(BOT_TEXT2("I'm not really good at smalltalk. Do you wanna join my guild %name/r?", placeholders));
|
||||
break;
|
||||
case 6:
|
||||
lines.push_back(BOT_TEXT2("Welcome to %zone_name.... do you want to join my guild %name?", placeholders));
|
||||
break;
|
||||
case 7:
|
||||
lines.push_back(BOT_TEXT2("%name, you should join my guild!", placeholders));
|
||||
break;
|
||||
case 8:
|
||||
lines.push_back(BOT_TEXT2("%name, I got this guild....", placeholders));
|
||||
break;
|
||||
case 9:
|
||||
lines.push_back(BOT_TEXT2("You are actually going to join my guild %name?", placeholders));
|
||||
lines.push_back(BOT_TEXT2("Haha.. you are the man! We are going to raid Molten...", placeholders));
|
||||
break;
|
||||
case 10:
|
||||
lines.push_back(BOT_TEXT2("Hey Hey! do you guys wanna join my gild????", placeholders));
|
||||
lines.push_back(BOT_TEXT2("We've got a bunch of high levels and we are really super friendly..", placeholders));
|
||||
lines.push_back(BOT_TEXT2("..and watch your dog and do your homework...", placeholders));
|
||||
lines.push_back(BOT_TEXT2("..and we raid once a week and are working on MC raids...", placeholders));
|
||||
lines.push_back(BOT_TEXT2("..and we have more members than just me...", placeholders));
|
||||
lines.push_back(BOT_TEXT2("..and please stop I'm lonenly and we can get a ride the whole time...", placeholders));
|
||||
lines.push_back(BOT_TEXT2("..and it's really beautifull and I feel like crying...", placeholders));
|
||||
lines.push_back(BOT_TEXT2("So what do you guys say are you going to join are you going to join?", placeholders));
|
||||
break;
|
||||
}
|
||||
|
||||
for (auto line : lines)
|
||||
if (sameGroup)
|
||||
{
|
||||
WorldPacket data;
|
||||
ChatHandler::BuildChatPacket(data, bot->GetGroup()->isRaidGroup() ? CHAT_MSG_RAID : CHAT_MSG_PARTY, line.c_str(), LANG_UNIVERSAL, CHAT_TAG_NONE, bot->GetGUID(), bot->GetName());
|
||||
bot->GetGroup()->BroadcastPacket(&data, true);
|
||||
}
|
||||
else
|
||||
bot->Say(line, (bot->GetTeamId() == TEAM_ALLIANCE ? LANG_COMMON : LANG_ORCISH));*/
|
||||
}
|
||||
|
||||
if (botAI->DoSpecificAction("guild invite", Event("guild management", guid), true))
|
||||
{
|
||||
if (sPlayerbotAIConfig->inviteChat)
|
||||
return true;
|
||||
found++;
|
||||
}
|
||||
}
|
||||
|
||||
return found > 0;
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "GuildMgr.h"
|
||||
#include "Playerbots.h"
|
||||
#include "ServerFacade.h"
|
||||
#include "BroadcastHelper.h"
|
||||
|
||||
bool InviteToGroupAction::Execute(Event event)
|
||||
{
|
||||
@@ -24,9 +25,16 @@ bool InviteToGroupAction::Invite(Player* player)
|
||||
if (!player || !player->IsInWorld())
|
||||
return false;
|
||||
|
||||
if (bot == player)
|
||||
return false;
|
||||
|
||||
if (!GET_PLAYERBOT_AI(player) && !botAI->GetSecurity()->CheckLevelFor(PLAYERBOT_SECURITY_INVITE, true, player))
|
||||
return false;
|
||||
|
||||
if (Group* group = player->GetGroup())
|
||||
if (!group->isRaidGroup() && group->GetMembersCount() > 4)
|
||||
group->ConvertToRaid();
|
||||
|
||||
WorldPacket p;
|
||||
uint32 roles_mask = 0;
|
||||
p << player->GetName();
|
||||
@@ -48,6 +56,9 @@ bool InviteNearbyToGroupAction::Execute(Event event)
|
||||
if (player->GetGroup())
|
||||
continue;
|
||||
|
||||
if (player == bot)
|
||||
continue;
|
||||
|
||||
if (botAI)
|
||||
{
|
||||
if (botAI->GetGrouperType() == GrouperType::SOLO &&
|
||||
@@ -69,6 +80,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);
|
||||
}
|
||||
|
||||
@@ -118,6 +149,8 @@ std::vector<Player*> InviteGuildToGroupAction::getGuildMembers()
|
||||
|
||||
bool InviteGuildToGroupAction::Execute(Event event)
|
||||
{
|
||||
Guild* guild = sGuildMgr->GetGuildById(bot->GetGuildId());
|
||||
|
||||
for (auto& member : getGuildMembers())
|
||||
{
|
||||
Player* player = member;
|
||||
@@ -160,10 +193,30 @@ 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);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool InviteGuildToGroupAction::isUseful() { return bot->GetGuildId() && InviteNearbyToGroupAction::isUseful(); };
|
||||
bool InviteGuildToGroupAction::isUseful()
|
||||
{
|
||||
return bot->GetGuildId() && InviteNearbyToGroupAction::isUseful();
|
||||
};
|
||||
|
||||
bool JoinGroupAction::Execute(Event event)
|
||||
{
|
||||
Player* master = event.getOwner();
|
||||
Group* group = master->GetGroup();
|
||||
|
||||
if (group && (group->IsFull() || bot->GetGroup() == group))
|
||||
return false;
|
||||
|
||||
if (bot->GetGroup())
|
||||
if (!botAI->DoSpecificAction("leave", event, true))
|
||||
return false;
|
||||
|
||||
return Invite(bot);
|
||||
}
|
||||
|
||||
@@ -21,6 +21,14 @@ public:
|
||||
virtual bool Invite(Player* player);
|
||||
};
|
||||
|
||||
class JoinGroupAction : public InviteToGroupAction
|
||||
{
|
||||
public:
|
||||
JoinGroupAction(PlayerbotAI* ai, std::string name = "join") : InviteToGroupAction(ai, name) {}
|
||||
bool Execute(Event event) override;
|
||||
bool isUseful() override { return !bot->IsBeingTeleported(); }
|
||||
};
|
||||
|
||||
class InviteNearbyToGroupAction : public InviteToGroupAction
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -98,13 +98,14 @@ bool LeaveGroupAction::Leave(Player* player)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LeaveFarAwayAction::Execute(Event event) { return Leave(nullptr); }
|
||||
bool LeaveFarAwayAction::Execute(Event event)
|
||||
{
|
||||
// allow bot to leave party when they want
|
||||
return Leave(botAI->GetGroupMaster());
|
||||
}
|
||||
|
||||
bool LeaveFarAwayAction::isUseful()
|
||||
{
|
||||
if (!sPlayerbotAIConfig->randomBotGroupNearby)
|
||||
return false;
|
||||
|
||||
if (bot->InBattleground())
|
||||
return false;
|
||||
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
#include "PlayerbotAIConfig.h"
|
||||
#include "Playerbots.h"
|
||||
#include "ServerFacade.h"
|
||||
#include "GuildMgr.h"
|
||||
#include "BroadcastHelper.h"
|
||||
|
||||
bool LootAction::Execute(Event event)
|
||||
{
|
||||
@@ -423,31 +425,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 && bot->GetGuildId() && urand(0, 10) &&
|
||||
proto->Quality >= ITEM_QUALITY_RARE)
|
||||
{
|
||||
Guild* guild = sGuildMgr->GetGuildById(bot->GetGuildId());
|
||||
|
||||
if (guild)
|
||||
{
|
||||
std::string toSay = "";
|
||||
|
||||
if (urand(0, 3))
|
||||
toSay = "Yay I looted " + chat->FormatItem(proto) + " !";
|
||||
else
|
||||
toSay = "Guess who got a " + chat->FormatItem(proto) + " ? Me !";
|
||||
|
||||
guild->BroadcastToGuild(bot->GetSession(), false, toSay, LANG_UNIVERSAL);
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
@@ -12,64 +12,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;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,8 +16,10 @@ void QueryQuestAction::TellObjective(std::string const name, uint32 available, u
|
||||
|
||||
bool QueryQuestAction::Execute(Event event)
|
||||
{
|
||||
Player* requester = event.getOwner() ? event.getOwner() : GetMaster();
|
||||
Player* bot = botAI->GetBot();
|
||||
WorldPosition botPos(bot);
|
||||
WorldPosition* ptr_botpos = &botPos;
|
||||
std::string text = event.getParam();
|
||||
bool travel = false;
|
||||
|
||||
@@ -30,7 +32,22 @@ bool QueryQuestAction::Execute(Event event)
|
||||
PlayerbotChatHandler ch(bot);
|
||||
uint32 questId = ch.extractQuestId(text);
|
||||
if (!questId)
|
||||
return false;
|
||||
{
|
||||
for (uint8 slot = 0; slot < MAX_QUEST_LOG_SIZE; ++slot)
|
||||
{
|
||||
uint32 logQuest = bot->GetQuestSlotQuestId(slot);
|
||||
|
||||
Quest const* quest = sObjectMgr->GetQuestTemplate(logQuest);
|
||||
if (!quest)
|
||||
continue;
|
||||
|
||||
if (text.find(quest->GetTitle()) != std::string::npos)
|
||||
{
|
||||
questId = quest->GetQuestId();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (uint16 slot = 0; slot < MAX_QUEST_LOG_SIZE; ++slot)
|
||||
{
|
||||
@@ -58,12 +75,7 @@ bool QueryQuestAction::Execute(Event event)
|
||||
std::vector<TravelDestination*> allDestinations =
|
||||
sTravelMgr->getQuestTravelDestinations(bot, questId, true, true, -1);
|
||||
|
||||
std::sort(allDestinations.begin(), allDestinations.end(),
|
||||
[botPos](TravelDestination* i, TravelDestination* j) {
|
||||
return i->distanceTo(const_cast<WorldPosition*>(&botPos)) <
|
||||
j->distanceTo(const_cast<WorldPosition*>(&botPos));
|
||||
});
|
||||
|
||||
std::sort(allDestinations.begin(), allDestinations.end(), [ptr_botpos](TravelDestination* i, TravelDestination* j) {return i->distanceTo(ptr_botpos) < j->distanceTo(ptr_botpos); });
|
||||
for (auto dest : allDestinations)
|
||||
{
|
||||
if (limit > 50)
|
||||
@@ -74,7 +86,7 @@ bool QueryQuestAction::Execute(Event event)
|
||||
uint32 tpoints = dest->getPoints(true).size();
|
||||
uint32 apoints = dest->getPoints().size();
|
||||
|
||||
out << round(dest->distanceTo(const_cast<WorldPosition*>(&botPos)));
|
||||
out << round(dest->distanceTo(&botPos));
|
||||
out << " to " << dest->getTitle();
|
||||
out << " " << apoints;
|
||||
|
||||
@@ -86,12 +98,6 @@ bool QueryQuestAction::Execute(Event event)
|
||||
if (!dest->isActive(bot))
|
||||
out << " not active";
|
||||
|
||||
if (dest->isFull(bot))
|
||||
out << " crowded";
|
||||
|
||||
if (dest->isFull(bot))
|
||||
out << " crowded";
|
||||
|
||||
botAI->TellMaster(out);
|
||||
|
||||
limit++;
|
||||
|
||||
@@ -9,27 +9,49 @@
|
||||
#include "Event.h"
|
||||
#include "Playerbots.h"
|
||||
#include "ReputationMgr.h"
|
||||
#include "ServerFacade.h"
|
||||
#include "BroadcastHelper.h"
|
||||
|
||||
bool QuestAction::Execute(Event event)
|
||||
{
|
||||
ObjectGuid guid = event.getObject();
|
||||
|
||||
Player* master = GetMaster();
|
||||
if (!master)
|
||||
{
|
||||
if (!guid)
|
||||
guid = bot->GetTarget();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!guid)
|
||||
guid = master->GetTarget();
|
||||
}
|
||||
|
||||
if (!guid)
|
||||
return false;
|
||||
{
|
||||
if (!master)
|
||||
{
|
||||
guid = bot->GetTarget();
|
||||
}
|
||||
else
|
||||
{
|
||||
guid = master->GetTarget();
|
||||
}
|
||||
}
|
||||
|
||||
return ProcessQuests(guid);
|
||||
if (guid)
|
||||
{
|
||||
return ProcessQuests(guid);
|
||||
}
|
||||
|
||||
bool result = false;
|
||||
GuidVector npcs = AI_VALUE(GuidVector, "nearest npcs");
|
||||
for (const auto npc : npcs)
|
||||
{
|
||||
Unit* unit = botAI->GetUnit(npc);
|
||||
if (unit && bot->GetDistance(unit) <= INTERACTION_DISTANCE)
|
||||
result |= ProcessQuests(unit);
|
||||
}
|
||||
std::list<ObjectGuid> gos = AI_VALUE(std::list<ObjectGuid>, "nearest game objects");
|
||||
for (const auto go : gos)
|
||||
{
|
||||
GameObject* gameobj = botAI->GetGameObject(go);
|
||||
if (gameobj && bot->GetDistance(gameobj) <= INTERACTION_DISTANCE)
|
||||
result |= ProcessQuests(gameobj);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool QuestAction::CompleteQuest(Player* player, uint32 entry)
|
||||
@@ -69,7 +91,15 @@ bool QuestAction::CompleteQuest(Player* player, uint32 entry)
|
||||
int32 creature = pQuest->RequiredNpcOrGo[i];
|
||||
uint32 creaturecount = pQuest->RequiredNpcOrGoCount[i];
|
||||
|
||||
if (creature > 0)
|
||||
// TODO check if we need a REQSPELL condition, this methods and sql entry dosent seem implemented ?
|
||||
/*if (uint32 spell_id = pQuest->GetReqSpell[i])
|
||||
{
|
||||
for (uint16 z = 0; z < creaturecount; ++z)
|
||||
{
|
||||
player->CastedCreatureOrGO(creature, ObjectGuid(), spell_id);
|
||||
}
|
||||
}*/
|
||||
/*else*/ if (creature > 0)
|
||||
{
|
||||
if (CreatureTemplate const* cInfo = sObjectMgr->GetCreatureTemplate(creature))
|
||||
for (uint16 z = 0; z < creaturecount; ++z)
|
||||
@@ -105,6 +135,14 @@ bool QuestAction::CompleteQuest(Player* player, uint32 entry)
|
||||
player->ModifyMoney(-ReqOrRewMoney);
|
||||
}
|
||||
|
||||
const std::string text_quest = ChatHelper::FormatQuest(pQuest);
|
||||
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(), pQuest->GetTitle());
|
||||
bot->Say("Quest [ " + text_quest + " ] completed", LANG_UNIVERSAL);
|
||||
}
|
||||
botAI->TellMasterNoFacing("Quest completed " + text_quest);
|
||||
|
||||
player->CompleteQuest(entry);
|
||||
|
||||
return true;
|
||||
@@ -129,6 +167,8 @@ bool QuestAction::ProcessQuests(WorldObject* questGiver)
|
||||
|
||||
if (bot->GetDistance(questGiver) > INTERACTION_DISTANCE && !sPlayerbotAIConfig->syncQuestWithPlayer)
|
||||
{
|
||||
//if (botAI->HasStrategy("debug", BotState::BOT_STATE_COMBAT) || botAI->HasStrategy("debug", BotState::BOT_STATE_NON_COMBAT))
|
||||
|
||||
botAI->TellError("Cannot talk to quest giver");
|
||||
return false;
|
||||
}
|
||||
@@ -190,6 +230,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;
|
||||
@@ -199,29 +240,154 @@ bool QuestAction::AcceptQuest(Quest const* quest, ObjectGuid questGiver)
|
||||
|
||||
out << " " << chat->FormatQuest(quest);
|
||||
botAI->TellMaster(out);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool QuestObjectiveCompletedAction::Execute(Event event)
|
||||
bool QuestUpdateCompleteAction::Execute(Event event)
|
||||
{
|
||||
WorldPacket p(event.getPacket());
|
||||
p.rpos(0);
|
||||
|
||||
uint32 questId = 0;
|
||||
p >> questId;
|
||||
|
||||
p.print_storage();
|
||||
LOG_INFO("playerbots", "Packet: empty{} questId{}", p.empty(), questId);
|
||||
|
||||
Quest const* qInfo = sObjectMgr->GetQuestTemplate(questId);
|
||||
if (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 [ " + format + " ] completed", LANG_UNIVERSAL);
|
||||
}
|
||||
botAI->TellMasterNoFacing("Quest completed " + format);
|
||||
BroadcastHelper::BroadcastQuestUpdateComplete(botAI, bot, qInfo);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* For creature or gameobject
|
||||
*/
|
||||
bool QuestUpdateAddKillAction::Execute(Event event)
|
||||
{
|
||||
WorldPacket p(event.getPacket());
|
||||
p.rpos(0);
|
||||
|
||||
uint32 entry, questId, available, required;
|
||||
ObjectGuid guid;
|
||||
p >> questId >> entry >> available >> required >> guid;
|
||||
p >> questId >> entry >> available >> required;
|
||||
|
||||
if (entry & 0x80000000)
|
||||
const Quest* qInfo = sObjectMgr->GetQuestTemplate(questId);
|
||||
if (qInfo && (entry & 0x80000000))
|
||||
{
|
||||
entry &= 0x7FFFFFFF;
|
||||
if (GameObjectTemplate const* info = sObjectMgr->GetGameObjectTemplate(entry))
|
||||
botAI->TellMaster(chat->FormatQuestObjective(info->name, available, required));
|
||||
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
|
||||
{
|
||||
if (CreatureTemplate const* info = sObjectMgr->GetCreatureTemplate(entry))
|
||||
botAI->TellMaster(chat->FormatQuestObjective(info->Name, available, required));
|
||||
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;
|
||||
}
|
||||
|
||||
bool QuestUpdateAddItemAction::Execute(Event event)
|
||||
{
|
||||
WorldPacket p(event.getPacket());
|
||||
p.rpos(0);
|
||||
|
||||
uint32 itemId, count;
|
||||
p >> itemId >> count;
|
||||
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
bool QuestUpdateFailedAction::Execute(Event event)
|
||||
{
|
||||
//opcode SMSG_QUESTUPDATE_FAILED is never sent...(yet?)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool QuestUpdateFailedTimerAction::Execute(Event event)
|
||||
{
|
||||
WorldPacket p(event.getPacket());
|
||||
p.rpos(0);
|
||||
|
||||
uint32 questId;
|
||||
p >> questId;
|
||||
|
||||
Player* requester = event.getOwner() ? event.getOwner() : GetMaster();
|
||||
|
||||
Quest const* qInfo = sObjectMgr->GetQuestTemplate(questId);
|
||||
|
||||
if (qInfo)
|
||||
{
|
||||
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
|
||||
{
|
||||
botAI->TellMaster("Failed timer for " + std::to_string(questId));
|
||||
}
|
||||
|
||||
return true;
|
||||
//drop quest
|
||||
bot->AbandonQuest(questId);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include "Action.h"
|
||||
#include "Object.h"
|
||||
#include "QuestDef.h"
|
||||
|
||||
class ObjectGuid;
|
||||
class Quest;
|
||||
@@ -19,23 +20,49 @@ class Object;
|
||||
class QuestAction : public Action
|
||||
{
|
||||
public:
|
||||
QuestAction(PlayerbotAI* botAI, std::string const name) : Action(botAI, name) {}
|
||||
|
||||
QuestAction(PlayerbotAI* botAI, std::string const name) : Action(botAI, name) { }
|
||||
bool Execute(Event event) override;
|
||||
|
||||
protected:
|
||||
bool CompleteQuest(Player* player, uint32 entry);
|
||||
virtual void ProcessQuest(Quest const* quest, Object* questGiver) = 0;
|
||||
virtual bool ProcessQuest(Quest const* quest, Object* questGiver) = 0;
|
||||
bool AcceptQuest(Quest const* quest, ObjectGuid questGiver);
|
||||
bool ProcessQuests(ObjectGuid questGiver);
|
||||
bool ProcessQuests(WorldObject* questGiver);
|
||||
};
|
||||
|
||||
class QuestObjectiveCompletedAction : public Action
|
||||
class QuestUpdateCompleteAction : public Action
|
||||
{
|
||||
public:
|
||||
QuestObjectiveCompletedAction(PlayerbotAI* botAI) : Action(botAI, "quest objective completed") {}
|
||||
QuestUpdateCompleteAction(PlayerbotAI* ai) : Action(ai, "quest update complete") {}
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class QuestUpdateAddKillAction : public Action
|
||||
{
|
||||
public:
|
||||
QuestUpdateAddKillAction(PlayerbotAI* ai) : Action(ai, "quest update add kill") {}
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class QuestUpdateAddItemAction : public Action
|
||||
{
|
||||
public:
|
||||
QuestUpdateAddItemAction(PlayerbotAI* ai) : Action(ai, "quest update add item") {}
|
||||
bool Execute(Event event) override;;
|
||||
};
|
||||
|
||||
class QuestUpdateFailedAction : public Action
|
||||
{
|
||||
public:
|
||||
QuestUpdateFailedAction(PlayerbotAI* ai) : Action(ai, "quest update failed") {}
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class QuestUpdateFailedTimerAction : public Action
|
||||
{
|
||||
public:
|
||||
QuestUpdateFailedTimerAction(PlayerbotAI* ai) : Action(ai, "quest update failed timer") {}
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "Formations.h"
|
||||
#include "Playerbots.h"
|
||||
#include "ServerFacade.h"
|
||||
#include "RpgSubActions.h"
|
||||
|
||||
bool RpgAction::Execute(Event event)
|
||||
{
|
||||
@@ -44,65 +45,109 @@ bool RpgAction::isUseful() { return AI_VALUE(GuidPosition, "rpg target"); }
|
||||
|
||||
bool RpgAction::SetNextRpgAction()
|
||||
{
|
||||
Strategy* rpgStrategy = botAI->GetAiObjectContext()->GetStrategy("rpg");
|
||||
|
||||
Strategy* rpgStrategy;
|
||||
std::vector<Action*> actions;
|
||||
std::vector<uint32> relevances;
|
||||
std::vector<TriggerNode*> triggerNodes;
|
||||
rpgStrategy->InitTriggers(triggerNodes);
|
||||
|
||||
for (auto& triggerNode : triggerNodes)
|
||||
|
||||
for (auto& strategy : botAI->GetAiObjectContext()->GetSupportedStrategies())
|
||||
{
|
||||
Trigger* trigger = context->GetTrigger(triggerNode->getName());
|
||||
if (trigger)
|
||||
if (strategy.find("rpg") == std::string::npos)
|
||||
continue;
|
||||
|
||||
rpgStrategy = botAI->GetAiObjectContext()->GetStrategy(strategy);
|
||||
|
||||
rpgStrategy->InitTriggers(triggerNodes);
|
||||
|
||||
for (auto& triggerNode : triggerNodes)
|
||||
{
|
||||
triggerNode->setTrigger(trigger);
|
||||
Trigger* trigger = context->GetTrigger(triggerNode->getName());
|
||||
|
||||
NextAction** nextActions = triggerNode->getHandlers();
|
||||
|
||||
trigger = triggerNode->getTrigger();
|
||||
|
||||
bool isChecked = false;
|
||||
for (int32 i = 0; i < NextAction::size(nextActions); i++)
|
||||
if (trigger)
|
||||
{
|
||||
NextAction* nextAction = nextActions[i];
|
||||
|
||||
if (nextAction->getRelevance() > 2.0f)
|
||||
continue;
|
||||
triggerNode->setTrigger(trigger);
|
||||
|
||||
if (!isChecked && !trigger->IsActive())
|
||||
break;
|
||||
NextAction** nextActions = triggerNode->getHandlers();
|
||||
|
||||
isChecked = true;
|
||||
Trigger* trigger = triggerNode->getTrigger();
|
||||
|
||||
Action* action = botAI->GetAiObjectContext()->GetAction(nextAction->getName());
|
||||
bool isChecked = false;
|
||||
|
||||
if (!action->isPossible() || !action->isUseful())
|
||||
continue;
|
||||
for (int32 i = 0; i < NextAction::size(nextActions); i++)
|
||||
{
|
||||
NextAction* nextAction = nextActions[i];
|
||||
|
||||
actions.push_back(action);
|
||||
relevances.push_back((nextAction->getRelevance() - 1) * 1000);
|
||||
if (nextAction->getRelevance() > 2.0f)
|
||||
continue;
|
||||
|
||||
if (!isChecked && !trigger->IsActive())
|
||||
break;
|
||||
|
||||
isChecked = true;
|
||||
|
||||
Action* action = botAI->GetAiObjectContext()->GetAction(nextAction->getName());
|
||||
if (!dynamic_cast<RpgEnabled*>(action) || !action->isPossible() || !action->isUseful())
|
||||
continue;
|
||||
|
||||
actions.push_back(action);
|
||||
relevances.push_back((nextAction->getRelevance() - 1) * 1000);
|
||||
}
|
||||
NextAction::destroy(nextActions);
|
||||
}
|
||||
|
||||
NextAction::destroy(nextActions);
|
||||
}
|
||||
|
||||
for (const auto i : triggerNodes)
|
||||
{
|
||||
delete i;
|
||||
}
|
||||
triggerNodes.clear();
|
||||
}
|
||||
|
||||
if (actions.empty())
|
||||
return false;
|
||||
|
||||
if (botAI->HasStrategy("debug rpg", BotState::BOT_STATE_NON_COMBAT))
|
||||
{
|
||||
std::vector<std::pair<Action*, uint32>> sortedActions;
|
||||
|
||||
for (int i = 0; i < actions.size(); i++)
|
||||
sortedActions.push_back(std::make_pair(actions[i], relevances[i]));
|
||||
|
||||
std::sort(sortedActions.begin(), sortedActions.end(), [](std::pair<Action*, uint32>i, std::pair<Action*, uint32> j) {return i.second > j.second; });
|
||||
|
||||
std::stringstream ss;
|
||||
ss << "------" << chat->FormatWorldobject(AI_VALUE(GuidPosition, "rpg target").GetWorldObject()) << "------";
|
||||
bot->Say(ss.str(), LANG_UNIVERSAL);
|
||||
botAI->TellMasterNoFacing(ss.str());
|
||||
|
||||
for (auto action : sortedActions)
|
||||
{
|
||||
std::ostringstream out;
|
||||
|
||||
out << " " << action.first->getName() << " " << action.second;
|
||||
|
||||
botAI->TellMasterNoFacing(out);
|
||||
}
|
||||
}
|
||||
|
||||
std::mt19937 gen(time(0));
|
||||
|
||||
sTravelMgr->weighted_shuffle(actions.begin(), actions.end(), relevances.begin(), relevances.end(), gen);
|
||||
|
||||
Action* action = actions.front();
|
||||
|
||||
for (std::vector<TriggerNode*>::iterator i = triggerNodes.begin(); i != triggerNodes.end(); i++)
|
||||
if ((botAI->HasStrategy("debug", BotState::BOT_STATE_NON_COMBAT) || botAI->HasStrategy("debug rpg", BotState::BOT_STATE_NON_COMBAT)))
|
||||
{
|
||||
TriggerNode* trigger = *i;
|
||||
delete trigger;
|
||||
}
|
||||
std::ostringstream out;
|
||||
out << "do: ";
|
||||
out << chat->FormatWorldobject(AI_VALUE(GuidPosition, "rpg target").GetWorldObject());
|
||||
|
||||
triggerNodes.clear();
|
||||
out << " " << action->getName();
|
||||
|
||||
botAI->TellMasterNoFacing(out);
|
||||
}
|
||||
|
||||
SET_AI_VALUE(std::string, "next rpg action", action->getName());
|
||||
|
||||
|
||||
@@ -15,16 +15,13 @@ class Unit;
|
||||
class RpgAction : public MovementAction
|
||||
{
|
||||
public:
|
||||
RpgAction(PlayerbotAI* botAI, std::string const name = "rpg") : MovementAction(botAI, name) {}
|
||||
|
||||
RpgAction(PlayerbotAI* botAI, std::string const name = "rpg") : MovementAction(botAI, name) { }
|
||||
bool Execute(Event event) override;
|
||||
bool isUseful() override;
|
||||
|
||||
protected:
|
||||
virtual bool SetNextRpgAction();
|
||||
|
||||
typedef void (RpgAction::*RpgElement)(ObjectGuid guid);
|
||||
|
||||
bool AddIgnore(ObjectGuid guid);
|
||||
bool RemIgnore(ObjectGuid guid);
|
||||
bool HasIgnore(ObjectGuid guid);
|
||||
@@ -33,8 +30,7 @@ protected:
|
||||
class CRpgAction : public RpgAction
|
||||
{
|
||||
public:
|
||||
CRpgAction(PlayerbotAI* botAI) : RpgAction(botAI, "crpg") {}
|
||||
|
||||
CRpgAction(PlayerbotAI* botAI) : RpgAction(botAI, "crpg") { }
|
||||
bool isUseful() override;
|
||||
};
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -7,10 +7,10 @@
|
||||
#define _PLAYERBOT_SAYACTION_H
|
||||
|
||||
#include "Action.h"
|
||||
#include "PlayerbotAI.h"
|
||||
#include "NamedObjectContext.h"
|
||||
|
||||
class PlayerbotAI;
|
||||
|
||||
class SayAction : public Action, public Qualified
|
||||
{
|
||||
public:
|
||||
@@ -31,7 +31,13 @@ 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);
|
||||
|
||||
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
|
||||
|
||||
@@ -39,3 +39,74 @@ bool ShareQuestAction::Execute(Event event)
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AutoShareQuestAction::Execute(Event event)
|
||||
{
|
||||
Player* requester = event.getOwner() ? event.getOwner() : GetMaster();
|
||||
bool shared = false;
|
||||
|
||||
for (uint8 slot = 0; slot < MAX_QUEST_LOG_SIZE; ++slot)
|
||||
{
|
||||
uint32 logQuest = bot->GetQuestSlotQuestId(slot);
|
||||
Quest const* quest = sObjectMgr->GetQuestTemplate(logQuest);
|
||||
|
||||
if (!quest)
|
||||
continue;
|
||||
|
||||
bool partyNeedsQuest = false;
|
||||
|
||||
for (GroupReference* itr = bot->GetGroup()->GetFirstMember(); itr != nullptr; itr = itr->next())
|
||||
{
|
||||
Player* player = itr->GetSource();
|
||||
|
||||
if (!player || player == bot || !player->IsInWorld() || !botAI->IsSafe(player)) // skip self
|
||||
continue;
|
||||
|
||||
if (bot->GetDistance(player) > 10)
|
||||
continue;
|
||||
|
||||
if (!player->SatisfyQuestStatus(quest, false))
|
||||
continue;
|
||||
|
||||
if (player->GetQuestStatus(logQuest) == QUEST_STATUS_COMPLETE)
|
||||
continue;
|
||||
|
||||
if (!player->CanTakeQuest(quest, false))
|
||||
continue;
|
||||
|
||||
if (!player->SatisfyQuestLog(false))
|
||||
continue;
|
||||
|
||||
if (player->GetDivider())
|
||||
continue;
|
||||
|
||||
if (auto ai = GET_PLAYERBOT_AI(player))
|
||||
{
|
||||
if (PAI_VALUE(uint8, "free quest log slots") < 15 || !urand(0,5))
|
||||
{
|
||||
WorldPacket packet(CMSG_PUSHQUESTTOPARTY, 20);
|
||||
packet << logQuest;
|
||||
ai->HandleMasterIncomingPacket(packet);
|
||||
}
|
||||
}
|
||||
else
|
||||
partyNeedsQuest = true;
|
||||
}
|
||||
|
||||
if (!partyNeedsQuest)
|
||||
continue;
|
||||
|
||||
WorldPacket p;
|
||||
p << logQuest;
|
||||
bot->GetSession()->HandlePushQuestToParty(p);
|
||||
botAI->TellMaster("Quest shared");
|
||||
shared = true;
|
||||
}
|
||||
|
||||
return shared;
|
||||
}
|
||||
|
||||
bool AutoShareQuestAction::isUseful()
|
||||
{
|
||||
return bot->GetGroup() && !botAI->HasActivePlayerMaster();
|
||||
}
|
||||
@@ -13,9 +13,17 @@ class PlayerbotAI;
|
||||
class ShareQuestAction : public Action
|
||||
{
|
||||
public:
|
||||
ShareQuestAction(PlayerbotAI* botAI) : Action(botAI, "share quest") {}
|
||||
|
||||
ShareQuestAction(PlayerbotAI* botAI, std::string name = "share quest") : Action(botAI, name) { }
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class AutoShareQuestAction : public ShareQuestAction
|
||||
{
|
||||
public:
|
||||
AutoShareQuestAction(PlayerbotAI* ai) : ShareQuestAction(botAI, "auto share quest") {}
|
||||
bool Execute(Event event) override;
|
||||
|
||||
bool isUseful() override;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -3,10 +3,19 @@
|
||||
* and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "SuggestWhatToDoAction.h"
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include "SuggestWhatToDoAction.h"
|
||||
#include "ServerFacade.h"
|
||||
#include "ChannelMgr.h"
|
||||
#include "Event.h"
|
||||
#include "ItemVisitors.h"
|
||||
#include "AiFactory.h"
|
||||
#include "ChatHelper.h"
|
||||
#include "Playerbots.h"
|
||||
#include "PlayerbotTextMgr.h"
|
||||
#include "Config.h"
|
||||
#include "BroadcastHelper.h"
|
||||
#include "AiFactory.h"
|
||||
#include "ChannelMgr.h"
|
||||
#include "ChatHelper.h"
|
||||
@@ -39,11 +48,13 @@ 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()
|
||||
{
|
||||
if (!sRandomPlayerbotMgr->IsRandomBot(bot) || bot->GetGroup() || bot->GetInstanceId())
|
||||
if (!sRandomPlayerbotMgr->IsRandomBot(bot) || bot->GetGroup() || bot->GetInstanceId() || bot->GetBattleground())
|
||||
return false;
|
||||
|
||||
std::string qualifier = "suggest what to do";
|
||||
@@ -88,15 +99,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()
|
||||
@@ -190,135 +193,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* entry = sAreaTableStore.LookupEntry(bot->GetAreaId());
|
||||
if (!entry)
|
||||
return;
|
||||
|
||||
std::ostringstream out;
|
||||
// out << "|cffb04040" << entry->area_name[0] << "|r";
|
||||
out << entry->area_name[_dbc_locale];
|
||||
placeholders["%zone"] = out.str();
|
||||
|
||||
spam(BOT_TEXT2("suggest_something", placeholders), urand(0, 1) ? eTalkType::General : 0, !urand(0, 2),
|
||||
!urand(0, 3));
|
||||
BroadcastHelper::BroadcastSuggestSomething(botAI, bot);
|
||||
}
|
||||
|
||||
void SuggestWhatToDoAction::spam(std::string msg, uint8 flags, bool worldChat, bool guild)
|
||||
void SuggestWhatToDoAction::somethingToxic()
|
||||
{
|
||||
if (msg.empty())
|
||||
return;
|
||||
BroadcastHelper::BroadcastSuggestSomethingToxic(botAI, bot);
|
||||
}
|
||||
|
||||
std::vector<std::string> channelNames;
|
||||
ChannelMgr* cMgr = ChannelMgr::forTeam(bot->GetTeamId());
|
||||
if (!cMgr)
|
||||
return;
|
||||
void SuggestWhatToDoAction::toxicLinks()
|
||||
{
|
||||
BroadcastHelper::BroadcastSuggestToxicLinks(botAI, bot);
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
if (!bot->IsInChannel(chn))
|
||||
chn->JoinChannel(bot, "");
|
||||
chn->Say(bot->GetGUID(), msg.c_str(), LANG_UNIVERSAL);
|
||||
}
|
||||
|
||||
if (!channelNames.empty())
|
||||
{
|
||||
std::string randomName = channelNames[urand(0, channelNames.size() - 1)];
|
||||
if (Channel* chn = cMgr->GetChannel(randomName, bot))
|
||||
{
|
||||
if (!bot->IsInChannel(chn))
|
||||
chn->JoinChannel(bot, "");
|
||||
|
||||
chn->Say(bot->GetGUID(), msg.c_str(), LANG_UNIVERSAL);
|
||||
}
|
||||
}
|
||||
|
||||
if (worldChat)
|
||||
{
|
||||
if (Channel* worldChannel = cMgr->GetChannel("World", bot))
|
||||
worldChannel->Say(bot->GetGUID(), msg.c_str(), LANG_UNIVERSAL);
|
||||
}
|
||||
}
|
||||
|
||||
if (sPlayerbotAIConfig->randomBotGuildTalk && guild && bot->GetGuildId())
|
||||
{
|
||||
Guild* guild = sGuildMgr->GetGuildById(bot->GetGuildId());
|
||||
if (guild)
|
||||
guild->BroadcastToGuild(bot->GetSession(), false, msg.c_str(), LANG_UNIVERSAL);
|
||||
}
|
||||
void SuggestWhatToDoAction::thunderfury()
|
||||
{
|
||||
BroadcastHelper::BroadcastSuggestThunderfury(botAI, bot);
|
||||
}
|
||||
|
||||
class FindTradeItemsVisitor : public IterateItemsVisitor
|
||||
@@ -409,24 +311,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));
|
||||
if (allowedInstances.empty()) return false;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -484,10 +376,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;
|
||||
}
|
||||
|
||||
@@ -25,8 +25,10 @@ protected:
|
||||
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();
|
||||
|
||||
private:
|
||||
@@ -38,9 +40,7 @@ class SuggestTradeAction : public SuggestWhatToDoAction
|
||||
{
|
||||
public:
|
||||
SuggestTradeAction(PlayerbotAI* botAI);
|
||||
|
||||
bool Execute(Event event) override;
|
||||
bool isUseful() override { return true; }
|
||||
};
|
||||
|
||||
class SuggestDungeonAction : public SuggestWhatToDoAction
|
||||
@@ -49,8 +49,6 @@ public:
|
||||
SuggestDungeonAction(PlayerbotAI* botAI);
|
||||
|
||||
bool Execute(Event event) override;
|
||||
bool isUseful() override { return true; }
|
||||
|
||||
private:
|
||||
static std::map<std::string, uint8> instances;
|
||||
};
|
||||
|
||||
@@ -12,9 +12,11 @@
|
||||
#include "Playerbots.h"
|
||||
#include "QuestDef.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "BroadcastHelper.h"
|
||||
|
||||
void TalkToQuestGiverAction::ProcessQuest(Quest const* quest, Object* questGiver)
|
||||
bool TalkToQuestGiverAction::ProcessQuest(Quest const* quest, Object* questGiver)
|
||||
{
|
||||
bool isCompleted = false;
|
||||
std::ostringstream out;
|
||||
out << "Quest ";
|
||||
|
||||
@@ -28,7 +30,7 @@ void TalkToQuestGiverAction::ProcessQuest(Quest const* quest, Object* questGiver
|
||||
{
|
||||
QuestStatus masterStatus = master->GetQuestStatus(quest->GetQuestId());
|
||||
if (masterStatus == QUEST_STATUS_INCOMPLETE || masterStatus == QUEST_STATUS_FAILED)
|
||||
CompleteQuest(master, quest->GetQuestId());
|
||||
isCompleted |= CompleteQuest(master, quest->GetQuestId());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,39 +39,42 @@ void TalkToQuestGiverAction::ProcessQuest(Quest const* quest, Object* questGiver
|
||||
if (master && master->GetQuestStatus(quest->GetQuestId()) == QUEST_STATUS_COMPLETE &&
|
||||
(status == QUEST_STATUS_INCOMPLETE || status == QUEST_STATUS_FAILED))
|
||||
{
|
||||
CompleteQuest(bot, quest->GetQuestId());
|
||||
isCompleted |= CompleteQuest(bot, quest->GetQuestId());
|
||||
status = bot->GetQuestStatus(quest->GetQuestId());
|
||||
}
|
||||
}
|
||||
|
||||
switch (status)
|
||||
{
|
||||
case QUEST_STATUS_COMPLETE:
|
||||
TurnInQuest(quest, questGiver, out);
|
||||
break;
|
||||
case QUEST_STATUS_INCOMPLETE:
|
||||
out << "|cffff0000Incompleted|r";
|
||||
break;
|
||||
case QUEST_STATUS_NONE:
|
||||
out << "|cff00ff00Available|r";
|
||||
break;
|
||||
case QUEST_STATUS_FAILED:
|
||||
out << "|cffff0000Failed|r";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
case QUEST_STATUS_COMPLETE:
|
||||
isCompleted |= TurnInQuest(quest, questGiver, out);
|
||||
break;
|
||||
case QUEST_STATUS_INCOMPLETE:
|
||||
out << "|cffff0000Incompleted|r";
|
||||
break;
|
||||
case QUEST_STATUS_NONE:
|
||||
AcceptQuest(quest, questGiver->GetGUID());
|
||||
out << "|cff00ff00Available|r";
|
||||
break;
|
||||
case QUEST_STATUS_FAILED:
|
||||
out << "|cffff0000Failed|r";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
out << ": " << chat->FormatQuest(quest);
|
||||
botAI->TellMaster(out);
|
||||
|
||||
return isCompleted;
|
||||
}
|
||||
|
||||
void TalkToQuestGiverAction::TurnInQuest(Quest const* quest, Object* questGiver, std::ostringstream& out)
|
||||
bool TalkToQuestGiverAction::TurnInQuest(Quest const* quest, Object* questGiver, std::ostringstream& out)
|
||||
{
|
||||
uint32 questID = quest->GetQuestId();
|
||||
|
||||
if (bot->GetQuestRewardStatus(questID))
|
||||
return;
|
||||
return false;
|
||||
|
||||
bot->PlayDistanceSound(621);
|
||||
|
||||
@@ -81,18 +86,33 @@ void TalkToQuestGiverAction::TurnInQuest(Quest const* quest, Object* questGiver,
|
||||
{
|
||||
RewardMultipleItem(quest, questGiver, out);
|
||||
}
|
||||
|
||||
if (botAI->HasStrategy("debug quest", BotState::BOT_STATE_NON_COMBAT) || botAI->HasStrategy("debug rpg", BotState::BOT_STATE_COMBAT))
|
||||
{
|
||||
const Quest* pQuest = sObjectMgr->GetQuestTemplate(questID);
|
||||
const std::string text_quest = ChatHelper::FormatQuest(pQuest);
|
||||
LOG_INFO("playerbots", "{} => Quest [ {} ] completed", bot->GetName(), pQuest->GetTitle());
|
||||
bot->Say("Quest [ " + text_quest + " ] completed", LANG_UNIVERSAL);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,15 +120,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -247,26 +271,27 @@ bool TurnInQueryQuestAction::Execute(Event event)
|
||||
out << "Quest ";
|
||||
switch (status)
|
||||
{
|
||||
case QUEST_STATUS_COMPLETE:
|
||||
TurnInQuest(quest, object, out);
|
||||
break;
|
||||
case QUEST_STATUS_INCOMPLETE:
|
||||
out << "|cffff0000Incompleted|r";
|
||||
break;
|
||||
case QUEST_STATUS_NONE:
|
||||
out << "|cff00ff00Available|r";
|
||||
break;
|
||||
case QUEST_STATUS_FAILED:
|
||||
out << "|cffff0000Failed|r";
|
||||
break;
|
||||
case QUEST_STATUS_REWARDED:
|
||||
out << "|cffff0000Rewarded|r";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
case QUEST_STATUS_COMPLETE:
|
||||
TurnInQuest(quest, object, out);
|
||||
break;
|
||||
case QUEST_STATUS_INCOMPLETE:
|
||||
out << "|cffff0000Incompleted|r";
|
||||
break;
|
||||
case QUEST_STATUS_NONE:
|
||||
AcceptQuest(quest, object->GetGUID());
|
||||
out << "|cff00ff00Available|r";
|
||||
break;
|
||||
case QUEST_STATUS_FAILED:
|
||||
out << "|cffff0000Failed|r";
|
||||
break;
|
||||
case QUEST_STATUS_REWARDED:
|
||||
out << "|cffff0000Rewarded|r";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
out << ": " << chat->FormatQuest(quest);
|
||||
botAI->TellMaster(out);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,11 +15,11 @@ class WorldObject;
|
||||
class TalkToQuestGiverAction : public QuestAction
|
||||
{
|
||||
public:
|
||||
TalkToQuestGiverAction(PlayerbotAI* botAI, std::string name = "talk to quest giver") : QuestAction(botAI, name) {}
|
||||
TalkToQuestGiverAction(PlayerbotAI* botAI, std::string name = "talk to quest giver") : QuestAction(botAI, name) { }
|
||||
|
||||
protected:
|
||||
void ProcessQuest(Quest const* quest, Object* questGiver) override;
|
||||
void TurnInQuest(Quest const* quest, Object* questGiver, std::ostringstream& out);
|
||||
bool ProcessQuest(Quest const* quest, Object* questGiver) override;
|
||||
bool TurnInQuest(Quest const* quest, Object* questGiver, std::ostringstream& out);
|
||||
|
||||
private:
|
||||
void RewardNoItem(Quest const* quest, Object* questGiver, std::ostringstream& out);
|
||||
|
||||
@@ -438,13 +438,10 @@ bool UseRandomQuestItem::Execute(Event event)
|
||||
ObjectGuid goTarget;
|
||||
|
||||
std::vector<Item*> questItems = AI_VALUE2(std::vector<Item*>, "inventory items", "quest");
|
||||
|
||||
Item* item = nullptr;
|
||||
uint32 delay = 0;
|
||||
|
||||
if (questItems.empty())
|
||||
return false;
|
||||
|
||||
Item* item = nullptr;
|
||||
for (uint8 i = 0; i < 5; i++)
|
||||
{
|
||||
auto itr = questItems.begin();
|
||||
@@ -452,7 +449,6 @@ bool UseRandomQuestItem::Execute(Event event)
|
||||
Item* questItem = *itr;
|
||||
|
||||
ItemTemplate const* proto = questItem->GetTemplate();
|
||||
|
||||
if (proto->StartQuest)
|
||||
{
|
||||
Quest const* qInfo = sObjectMgr->GetQuestTemplate(proto->StartQuest);
|
||||
@@ -463,61 +459,14 @@ bool UseRandomQuestItem::Execute(Event event)
|
||||
}
|
||||
}
|
||||
|
||||
uint32 spellId = proto->Spells[0].SpellId;
|
||||
if (spellId)
|
||||
{
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
|
||||
|
||||
GuidVector npcs = AI_VALUE(GuidVector, ("nearest npcs"));
|
||||
for (auto& npc : npcs)
|
||||
{
|
||||
Unit* unit = botAI->GetUnit(npc);
|
||||
if (botAI->CanCastSpell(spellId, unit, false))
|
||||
{
|
||||
item = questItem;
|
||||
unitTarget = unit;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
GuidVector gos = AI_VALUE(GuidVector, ("nearest game objects"));
|
||||
for (auto& go : gos)
|
||||
{
|
||||
GameObject* gameObject = botAI->GetGameObject(go);
|
||||
GameObjectTemplate const* goInfo = gameObject->GetGOInfo();
|
||||
if (!goInfo->GetLockId())
|
||||
continue;
|
||||
|
||||
LockEntry const* lock = sLockStore.LookupEntry(goInfo->GetLockId());
|
||||
for (uint8 i = 0; i < MAX_LOCK_CASE; ++i)
|
||||
{
|
||||
if (!lock->Type[i])
|
||||
continue;
|
||||
if (lock->Type[i] != LOCK_KEY_ITEM)
|
||||
continue;
|
||||
|
||||
if (lock->Index[i] == proto->ItemId)
|
||||
{
|
||||
item = questItem;
|
||||
goTarget = go;
|
||||
unitTarget = nullptr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!item)
|
||||
return false;
|
||||
|
||||
if (!goTarget && !unitTarget)
|
||||
return false;
|
||||
|
||||
bool used = UseItem(item, goTarget, nullptr, unitTarget);
|
||||
|
||||
if (used)
|
||||
botAI->SetNextCheckDelay(delay);
|
||||
botAI->SetNextCheckDelay(sPlayerbotAIConfig->globalCoolDown);
|
||||
|
||||
return used;
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
#include "TellMasterAction.h"
|
||||
#include "TradeStatusAction.h"
|
||||
#include "UseMeetingStoneAction.h"
|
||||
#include "NamedObjectContext.h"
|
||||
|
||||
class PlayerbotAI;
|
||||
|
||||
@@ -52,10 +53,6 @@ public:
|
||||
creators["tell not enough money"] = &WorldPacketActionContext::tell_not_enough_money;
|
||||
creators["tell not enough reputation"] = &WorldPacketActionContext::tell_not_enough_reputation;
|
||||
creators["tell cannot equip"] = &WorldPacketActionContext::tell_cannot_equip;
|
||||
creators["talk to quest giver"] = &WorldPacketActionContext::turn_in_quest;
|
||||
creators["accept quest"] = &WorldPacketActionContext::accept_quest;
|
||||
creators["accept all quests"] = &WorldPacketActionContext::accept_all_quests;
|
||||
creators["accept quest share"] = &WorldPacketActionContext::accept_quest_share;
|
||||
creators["loot roll"] = &WorldPacketActionContext::loot_roll;
|
||||
creators["master loot roll"] = &WorldPacketActionContext::master_loot_roll;
|
||||
creators["revive from corpse"] = &WorldPacketActionContext::revive_from_corpse;
|
||||
@@ -69,7 +66,20 @@ public:
|
||||
creators["remember taxi"] = &WorldPacketActionContext::remember_taxi;
|
||||
creators["accept trade"] = &WorldPacketActionContext::accept_trade;
|
||||
creators["store loot"] = &WorldPacketActionContext::store_loot;
|
||||
creators["quest objective completed"] = &WorldPacketActionContext::quest_objective_completed;
|
||||
|
||||
// quest
|
||||
creators["talk to quest giver"] = &WorldPacketActionContext::turn_in_quest;
|
||||
creators["accept quest"] = &WorldPacketActionContext::accept_quest;
|
||||
creators["confirm quest"] = &WorldPacketActionContext::confirm_quest;
|
||||
creators["accept all quests"] = &WorldPacketActionContext::accept_all_quests;
|
||||
creators["accept quest share"] = &WorldPacketActionContext::accept_quest_share;
|
||||
creators["quest update add kill"] = &WorldPacketActionContext::quest_update_add_kill;
|
||||
creators["quest update add item"] = &WorldPacketActionContext::quest_update_add_item;
|
||||
creators["quest update failed"] = &WorldPacketActionContext::quest_update_failed;
|
||||
creators["quest update failed timer"] = &WorldPacketActionContext::quest_update_failed_timer;
|
||||
creators["quest update complete"] = &WorldPacketActionContext::quest_update_complete;
|
||||
creators["turn in query quest"] = &WorldPacketActionContext::turn_in_query_quest;
|
||||
|
||||
creators["party command"] = &WorldPacketActionContext::party_command;
|
||||
creators["tell cast failed"] = &WorldPacketActionContext::tell_cast_failed;
|
||||
creators["accept duel"] = &WorldPacketActionContext::accept_duel;
|
||||
@@ -93,8 +103,6 @@ public:
|
||||
creators["lfg teleport"] = &WorldPacketActionContext::lfg_teleport;
|
||||
creators["see spell"] = &WorldPacketActionContext::see_spell;
|
||||
creators["arena team accept"] = &WorldPacketActionContext::arena_team_accept;
|
||||
creators["turn in query quest"] = &WorldPacketActionContext::turn_in_query_quest;
|
||||
creators["quest confirm accept"] = &WorldPacketActionContext::quest_confirm_accept;
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -107,7 +115,6 @@ private:
|
||||
static Action* accept_duel(PlayerbotAI* botAI) { return new AcceptDuelAction(botAI); }
|
||||
static Action* tell_cast_failed(PlayerbotAI* botAI) { return new TellCastFailedAction(botAI); }
|
||||
static Action* party_command(PlayerbotAI* botAI) { return new PartyCommandAction(botAI); }
|
||||
static Action* quest_objective_completed(PlayerbotAI* botAI) { return new QuestObjectiveCompletedAction(botAI); }
|
||||
static Action* store_loot(PlayerbotAI* botAI) { return new StoreLootAction(botAI); }
|
||||
static Action* accept_trade(PlayerbotAI* botAI) { return new TradeStatusAction(botAI); }
|
||||
static Action* remember_taxi(PlayerbotAI* botAI) { return new RememberTaxiAction(botAI); }
|
||||
@@ -120,21 +127,27 @@ private:
|
||||
static Action* auto_release(PlayerbotAI* botAI) { return new AutoReleaseSpiritAction(botAI); }
|
||||
static Action* revive_from_corpse(PlayerbotAI* botAI) { return new ReviveFromCorpseAction(botAI); }
|
||||
static Action* accept_invitation(PlayerbotAI* botAI) { return new AcceptInvitationAction(botAI); }
|
||||
static Action* give_leader_in_dungeon(PlayerbotAI* botAI)
|
||||
{
|
||||
return new GiveLeaderAction(botAI, "I don't know this dungeon, lead the way!");
|
||||
}
|
||||
static Action* give_leader_in_dungeon(PlayerbotAI* botAI) { return new GiveLeaderAction(botAI, "I don't know this dungeon, lead the way!"); }
|
||||
static Action* pass_leadership_to_master(PlayerbotAI* botAI) { return new PassLeadershipToMasterAction(botAI); }
|
||||
static Action* tell_not_enough_money(PlayerbotAI* botAI) { return new TellMasterAction(botAI, "Not enough money"); }
|
||||
static Action* tell_not_enough_reputation(PlayerbotAI* botAI)
|
||||
{
|
||||
return new TellMasterAction(botAI, "Not enough reputation");
|
||||
}
|
||||
static Action* tell_not_enough_reputation(PlayerbotAI* botAI) { return new TellMasterAction(botAI, "Not enough reputation"); }
|
||||
static Action* tell_cannot_equip(PlayerbotAI* botAI) { return new InventoryChangeFailureAction(botAI); }
|
||||
|
||||
// quest
|
||||
static Action* quest_update_add_kill(PlayerbotAI* ai) { return new QuestUpdateAddKillAction(ai); }
|
||||
static Action* quest_update_add_item(PlayerbotAI* ai) { return new QuestUpdateAddItemAction(ai); }
|
||||
static Action* quest_update_failed(PlayerbotAI* ai) { return new QuestUpdateFailedAction(ai); }
|
||||
static Action* quest_update_failed_timer(PlayerbotAI* ai) { return new QuestUpdateFailedTimerAction(ai); }
|
||||
static Action* quest_update_complete(PlayerbotAI* botAI) { return new QuestUpdateCompleteAction(botAI); }
|
||||
|
||||
static Action* turn_in_quest(PlayerbotAI* botAI) { return new TalkToQuestGiverAction(botAI); }
|
||||
static Action* accept_quest(PlayerbotAI* botAI) { return new AcceptQuestAction(botAI); }
|
||||
static Action* confirm_quest(PlayerbotAI* ai) { return new ConfirmQuestAction(ai); }
|
||||
static Action* accept_all_quests(PlayerbotAI* botAI) { return new AcceptAllQuestsAction(botAI); }
|
||||
static Action* accept_quest_share(PlayerbotAI* botAI) { return new AcceptQuestShareAction(botAI); }
|
||||
static Action* turn_in_query_quest(PlayerbotAI* botAI) { return new TurnInQueryQuestAction(botAI); }
|
||||
//static Action* quest_confirm_accept(PlayerbotAI* botAI) { return new QuestConfirmAcceptAction(botAI); }
|
||||
|
||||
static Action* loot_roll(PlayerbotAI* botAI) { return new LootRollAction(botAI); }
|
||||
static Action* master_loot_roll(PlayerbotAI* botAI) { return new MasterLootRollAction(botAI); }
|
||||
static Action* bg_join(PlayerbotAI* botAI) { return new BGJoinAction(botAI); }
|
||||
@@ -151,8 +164,6 @@ private:
|
||||
static Action* lfg_join(PlayerbotAI* botAI) { return new LfgJoinAction(botAI); }
|
||||
static Action* see_spell(PlayerbotAI* botAI) { return new SeeSpellAction(botAI); }
|
||||
static Action* arena_team_accept(PlayerbotAI* botAI) { return new ArenaTeamAcceptAction(botAI); }
|
||||
static Action* turn_in_query_quest(PlayerbotAI* botAI) { return new TurnInQueryQuestAction(botAI); }
|
||||
static Action* quest_confirm_accept(PlayerbotAI* botAI) { return new QuestConfirmAcceptAction(botAI); }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "GuildMgr.h"
|
||||
#include "PlayerbotAIConfig.h"
|
||||
#include "Playerbots.h"
|
||||
#include "BroadcastHelper.h"
|
||||
|
||||
bool XpGainAction::Execute(Event event)
|
||||
{
|
||||
@@ -35,25 +36,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->GetMap()->IsDungeon())
|
||||
{
|
||||
Creature* creature = botAI->GetCreature(guid);
|
||||
if (creature && (creature->isElite() || creature->isWorldBoss() || creature->GetLevel() > 61 ||
|
||||
creature->GetLevel() > bot->GetLevel() + 4))
|
||||
{
|
||||
Guild* guild = sGuildMgr->GetGuildById(bot->GetGuildId());
|
||||
if (guild)
|
||||
{
|
||||
std::string toSay = "";
|
||||
|
||||
if (urand(0, 3))
|
||||
toSay = "Wow I just killed " + creature->GetName() + " !";
|
||||
else
|
||||
toSay = "Awesome that " + creature->GetName() + " went down quickly !";
|
||||
|
||||
guild->BroadcastToGuild(bot->GetSession(), false, toSay, LANG_UNIVERSAL);
|
||||
}
|
||||
}
|
||||
BroadcastHelper::BroadcastKill(botAI, bot, creature);
|
||||
}
|
||||
|
||||
Unit* victim = nullptr;
|
||||
|
||||
@@ -44,4 +44,13 @@ public:
|
||||
std::string const getName() override { return "debug spell"; }
|
||||
};
|
||||
|
||||
class DebugQuestStrategy : public Strategy
|
||||
{
|
||||
public:
|
||||
DebugQuestStrategy(PlayerbotAI* botAI) : Strategy(botAI) { }
|
||||
|
||||
uint32 GetType() const override { return STRATEGY_TYPE_NONCOMBAT | STRATEGY_TYPE_COMBAT; }
|
||||
std::string const getName() override { return "debug quest"; }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -11,19 +11,13 @@ NextAction** MaintenanceStrategy::getDefaultActions() { return nullptr; }
|
||||
|
||||
void MaintenanceStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(
|
||||
new TriggerNode("random", NextAction::array(0, new NextAction("clean quest log", 6.0f), nullptr)));
|
||||
triggers.push_back(
|
||||
new TriggerNode("random", NextAction::array(0, new NextAction("use random recipe", 1.0f), nullptr)));
|
||||
triggers.push_back(
|
||||
new TriggerNode("often", NextAction::array(0, new NextAction("use random quest item", 10.0f), nullptr)));
|
||||
triggers.push_back(
|
||||
new TriggerNode("random", NextAction::array(0, new NextAction("disenchant random item", 1.0f), nullptr)));
|
||||
triggers.push_back(
|
||||
new TriggerNode("random", NextAction::array(0, new NextAction("enchant random item", 1.0f), nullptr)));
|
||||
triggers.push_back(
|
||||
new TriggerNode("random", NextAction::array(0, new NextAction("smart destroy item", 1.0f), nullptr)));
|
||||
triggers.push_back(new TriggerNode("random", NextAction::array(0, new NextAction("clean quest log", 6.0f), nullptr)));
|
||||
triggers.push_back(new TriggerNode("random", NextAction::array(0, new NextAction("use random recipe", 1.0f), nullptr)));
|
||||
triggers.push_back(new TriggerNode("random", NextAction::array(0, new NextAction("disenchant random item", 1.0f), nullptr)));
|
||||
triggers.push_back(new TriggerNode("random", NextAction::array(0, new NextAction("enchant random item", 1.0f), nullptr)));
|
||||
triggers.push_back(new TriggerNode("random", NextAction::array(0, new NextAction("smart destroy item", 1.0f), nullptr)));
|
||||
triggers.push_back(new TriggerNode("move stuck", NextAction::array(0, new NextAction("reset", 1.0f), nullptr)));
|
||||
// triggers.push_back(new TriggerNode("move long stuck", NextAction::array(0, new NextAction("hearthstone", 0.9f),
|
||||
// new NextAction("repop", 0.8f), nullptr)));
|
||||
// triggers.push_back(new TriggerNode("move long stuck", NextAction::array(0, new NextAction("hearthstone", 0.9f), new NextAction("repop", 0.8f), nullptr)));
|
||||
triggers.push_back(new TriggerNode("random", NextAction::array(0, new NextAction("use random quest item", 0.9f), nullptr)));
|
||||
triggers.push_back(new TriggerNode("random", NextAction::array(0, new NextAction("auto share quest", 0.9f), nullptr)));
|
||||
}
|
||||
|
||||
@@ -9,16 +9,15 @@
|
||||
|
||||
void NonCombatStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(new TriggerNode("timer", NextAction::array(0, new NextAction("check mount state", 1.0f),
|
||||
// new NextAction("check values", 1.0f),
|
||||
nullptr)));
|
||||
// triggers.push_back(new TriggerNode("near dark portal", NextAction::array(0, new NextAction("move to dark
|
||||
// portal", 1.0f), nullptr))); triggers.push_back(new TriggerNode("at dark portal azeroth", NextAction::array(0, new
|
||||
// NextAction("use dark portal azeroth", 1.0f), nullptr))); triggers.push_back(new TriggerNode("at dark portal
|
||||
// outland", NextAction::array(0, new NextAction("move from dark portal", 1.0f), nullptr))); triggers.push_back(new
|
||||
// TriggerNode("need world buff", NextAction::array(0, new NextAction("world buff", 1.0f), nullptr)));
|
||||
// triggers.push_back(new TriggerNode("vehicle near", NextAction::array(0, new NextAction("enter vehicle", 10.0f),
|
||||
// nullptr)));
|
||||
triggers.push_back(new TriggerNode("random", NextAction::array(0, new NextAction("clean quest log", 1.0f), nullptr)));
|
||||
triggers.push_back(new TriggerNode("timer", NextAction::array(0, new NextAction("check mount state", 1.0f),
|
||||
// new NextAction("check values", 1.0f),
|
||||
nullptr)));
|
||||
// triggers.push_back(new TriggerNode("near dark portal", NextAction::array(0, new NextAction("move to dark portal", 1.0f), nullptr)));
|
||||
// triggers.push_back(new TriggerNode("at dark portal azeroth", NextAction::array(0, new NextAction("use dark portal azeroth", 1.0f), nullptr)));
|
||||
// triggers.push_back(new TriggerNode("at dark portal outland", NextAction::array(0, new NextAction("move from dark portal", 1.0f), nullptr)));
|
||||
// triggers.push_back(new TriggerNode("need world buff", NextAction::array(0, new NextAction("world buff", 1.0f), nullptr)));
|
||||
// triggers.push_back(new TriggerNode("vehicle near", NextAction::array(0, new NextAction("enter vehicle", 10.0f), nullptr)));
|
||||
}
|
||||
|
||||
void CollisionStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
|
||||
@@ -34,66 +34,44 @@ void WorldPacketHandlerStrategy::InitTriggers(std::vector<TriggerNode*>& trigger
|
||||
triggers.push_back(new TriggerNode("activate taxi", NextAction::array(0, new NextAction("remember taxi", relevance),
|
||||
new NextAction("taxi", relevance), nullptr)));
|
||||
triggers.push_back(new TriggerNode("taxi done", NextAction::array(0, new NextAction("taxi", relevance), nullptr)));
|
||||
triggers.push_back(
|
||||
new TriggerNode("trade status", NextAction::array(0, new NextAction("accept trade", relevance),
|
||||
new NextAction("equip upgrades", relevance), nullptr)));
|
||||
triggers.push_back(new TriggerNode("area trigger",
|
||||
NextAction::array(0, new NextAction("reach area trigger", relevance), nullptr)));
|
||||
triggers.push_back(new TriggerNode("within area trigger",
|
||||
NextAction::array(0, new NextAction("area trigger", relevance), nullptr)));
|
||||
triggers.push_back(
|
||||
new TriggerNode("loot response", NextAction::array(0, new NextAction("store loot", relevance), nullptr)));
|
||||
triggers.push_back(
|
||||
new TriggerNode("item push result", NextAction::array(0, new NextAction("query item usage", relevance),
|
||||
new NextAction("equip upgrades", relevance), nullptr)));
|
||||
triggers.push_back(new TriggerNode("ready check finished",
|
||||
NextAction::array(0, new NextAction("finish ready check", relevance), nullptr)));
|
||||
// triggers.push_back(new TriggerNode("often", NextAction::array(0, new NextAction("security check", relevance), new
|
||||
// NextAction("check mail", relevance), nullptr)));
|
||||
triggers.push_back(
|
||||
new TriggerNode("guild invite", NextAction::array(0, new NextAction("guild accept", relevance), nullptr)));
|
||||
triggers.push_back(
|
||||
new TriggerNode("petition offer", NextAction::array(0, new NextAction("petition sign", relevance), nullptr)));
|
||||
triggers.push_back(
|
||||
new TriggerNode("lfg proposal", NextAction::array(0, new NextAction("lfg accept", relevance), nullptr)));
|
||||
triggers.push_back(
|
||||
new TriggerNode("lfg proposal active", NextAction::array(0, new NextAction("lfg accept", relevance), nullptr)));
|
||||
triggers.push_back(new TriggerNode("arena team invite",
|
||||
NextAction::array(0, new NextAction("arena team accept", relevance), nullptr)));
|
||||
triggers.push_back(new TriggerNode(
|
||||
"quest confirm accept", NextAction::array(0, new NextAction("quest confirm accept", relevance), nullptr)));
|
||||
// triggers.push_back(new TriggerNode("no non bot players around", NextAction::array(0, new NextAction("delay",
|
||||
// relevance), nullptr)));
|
||||
triggers.push_back(
|
||||
new TriggerNode("bg status", NextAction::array(0, new NextAction("bg status", relevance), nullptr)));
|
||||
triggers.push_back(new TriggerNode("trade status", NextAction::array(0, new NextAction("accept trade", relevance), new NextAction("equip upgrades", relevance), nullptr)));
|
||||
triggers.push_back(new TriggerNode("area trigger", NextAction::array(0, new NextAction("reach area trigger", relevance), nullptr)));
|
||||
triggers.push_back(new TriggerNode("within area trigger", NextAction::array(0, new NextAction("area trigger", relevance), nullptr)));
|
||||
triggers.push_back(new TriggerNode("loot response", NextAction::array(0, new NextAction("store loot", relevance), nullptr)));
|
||||
triggers.push_back(new TriggerNode("item push result", NextAction::array(0, new NextAction("query item usage", relevance), new NextAction("equip upgrades", relevance), nullptr)));
|
||||
triggers.push_back(new TriggerNode("ready check finished", NextAction::array(0, new NextAction("finish ready check", relevance), nullptr)));
|
||||
// triggers.push_back(new TriggerNode("often", NextAction::array(0, new NextAction("security check", relevance), new NextAction("check mail", relevance), nullptr)));
|
||||
triggers.push_back(new TriggerNode("guild invite", NextAction::array(0, new NextAction("guild accept", relevance), nullptr)));
|
||||
triggers.push_back(new TriggerNode("petition offer", NextAction::array(0, new NextAction("petition sign", relevance), nullptr)));
|
||||
triggers.push_back(new TriggerNode("lfg proposal", NextAction::array(0, new NextAction("lfg accept", relevance), nullptr)));
|
||||
triggers.push_back(new TriggerNode("lfg proposal active", NextAction::array(0, new NextAction("lfg accept", relevance), nullptr)));
|
||||
triggers.push_back(new TriggerNode("arena team invite", NextAction::array(0, new NextAction("arena team accept", relevance), nullptr)));
|
||||
//triggers.push_back(new TriggerNode("no non bot players around", NextAction::array(0, new NextAction("delay", relevance), nullptr)));
|
||||
triggers.push_back(new TriggerNode("bg status", NextAction::array(0, new NextAction("bg status", relevance), nullptr)));
|
||||
triggers.push_back(new TriggerNode("xpgain", NextAction::array(0, new NextAction("xp gain", relevance), nullptr)));
|
||||
triggers.push_back(
|
||||
new TriggerNode("levelup", NextAction::array(0, new NextAction("auto teleport for level", relevance + 3),
|
||||
new NextAction("auto talents", relevance + 2),
|
||||
new NextAction("auto learn spell", relevance + 1),
|
||||
new NextAction("auto upgrade equip", relevance), nullptr)));
|
||||
// triggers.push_back(new TriggerNode("group destroyed", NextAction::array(0, new NextAction("reset botAI",
|
||||
// relevance), nullptr)));
|
||||
triggers.push_back(new TriggerNode(
|
||||
"questgiver quest details", NextAction::array(0, new NextAction("turn in query quest", relevance), nullptr)));
|
||||
triggers.push_back(new TriggerNode("levelup", NextAction::array(0,
|
||||
new NextAction("auto teleport for level", relevance + 3),
|
||||
new NextAction("auto talents", relevance + 2),
|
||||
new NextAction("auto learn spell", relevance + 1),
|
||||
new NextAction("auto upgrade equip", relevance),
|
||||
nullptr)));
|
||||
// triggers.push_back(new TriggerNode("group destroyed", NextAction::array(0, new NextAction("reset botAI", relevance), nullptr)));
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode("group list", NextAction::array(0, new NextAction("reset botAI", relevance), nullptr)));
|
||||
triggers.push_back(
|
||||
new TriggerNode("see spell", NextAction::array(0, new NextAction("see spell", relevance), nullptr)));
|
||||
triggers.push_back(
|
||||
new TriggerNode("release spirit", NextAction::array(0, new NextAction("release", relevance), nullptr)));
|
||||
triggers.push_back(new TriggerNode("revive from corpse",
|
||||
NextAction::array(0, new NextAction("revive from corpse", relevance), nullptr)));
|
||||
triggers.push_back(new TriggerNode("master loot roll",
|
||||
NextAction::array(0, new NextAction("master loot roll", relevance), nullptr)));
|
||||
triggers.push_back(new TriggerNode("group list", NextAction::array(0, new NextAction("reset botAI", relevance), nullptr)));
|
||||
triggers.push_back(new TriggerNode("see spell", NextAction::array(0, new NextAction("see spell", relevance), nullptr)));
|
||||
triggers.push_back(new TriggerNode("release spirit", NextAction::array(0, new NextAction("release", relevance), nullptr)));
|
||||
triggers.push_back(new TriggerNode("revive from corpse", NextAction::array(0, new NextAction("revive from corpse", relevance), nullptr)));
|
||||
triggers.push_back(new TriggerNode("master loot roll", NextAction::array(0, new NextAction("master loot roll", relevance), nullptr)));
|
||||
|
||||
// quest ?
|
||||
//triggers.push_back(new TriggerNode("quest confirm", NextAction::array(0, new NextAction("quest confirm", relevance), nullptr)));
|
||||
triggers.push_back(new TriggerNode("questgiver quest details", NextAction::array(0, new NextAction("turn in query quest", relevance), nullptr)));
|
||||
}
|
||||
|
||||
WorldPacketHandlerStrategy::WorldPacketHandlerStrategy(PlayerbotAI* botAI) : PassTroughStrategy(botAI)
|
||||
{
|
||||
supported.push_back("loot roll");
|
||||
supported.push_back("check mount state");
|
||||
supported.push_back("quest objective completed");
|
||||
supported.push_back("party command");
|
||||
supported.push_back("ready check");
|
||||
supported.push_back("uninvite");
|
||||
@@ -102,6 +80,14 @@ WorldPacketHandlerStrategy::WorldPacketHandlerStrategy(PlayerbotAI* botAI) : Pas
|
||||
supported.push_back("random bot update");
|
||||
supported.push_back("inventory change failure");
|
||||
supported.push_back("bg status");
|
||||
|
||||
// quests
|
||||
supported.push_back("quest update add kill");
|
||||
supported.push_back("quest update add item");
|
||||
supported.push_back("quest update failed");
|
||||
supported.push_back("quest update failed timer");
|
||||
supported.push_back("quest update complete");
|
||||
supported.push_back("confirm quest");
|
||||
}
|
||||
|
||||
void ReadyCheckStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
|
||||
@@ -22,7 +22,7 @@ public:
|
||||
class ReadyCheckStrategy : public PassTroughStrategy
|
||||
{
|
||||
public:
|
||||
ReadyCheckStrategy(PlayerbotAI* botAI) : PassTroughStrategy(botAI) {}
|
||||
ReadyCheckStrategy(PlayerbotAI* botAI) : PassTroughStrategy(botAI) { }
|
||||
|
||||
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
|
||||
std::string const getName() override { return "ready check"; }
|
||||
|
||||
@@ -107,6 +107,12 @@ bool RpgEndQuestTrigger::IsActive()
|
||||
if (AI_VALUE2(bool, "can turn in quest npc", guidP.GetEntry()))
|
||||
return true;
|
||||
|
||||
if (!AI_VALUE2(bool, "can accept quest low level npc", guidP.GetEntry()))
|
||||
return false;
|
||||
|
||||
if (guidP.GetEntry() == AI_VALUE(TravelTarget*, "travel target")->getEntry())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -292,6 +298,10 @@ bool RpgQueueBGTrigger::IsActive()
|
||||
|
||||
if (!guidP.IsCreature())
|
||||
return false;
|
||||
|
||||
// if bot is not leader disallow tag bg
|
||||
if (bot->GetGroup() && !bot->GetGroup()->IsLeader(bot->GetGUID()))
|
||||
return false;
|
||||
|
||||
if (AI_VALUE(BattlegroundTypeId, "rpg bg type") == BATTLEGROUND_TYPE_NONE)
|
||||
return false;
|
||||
|
||||
@@ -22,9 +22,6 @@ public:
|
||||
creators["not enough reputation"] = &WorldPacketTriggerContext::no_reputation;
|
||||
creators["cannot equip"] = &WorldPacketTriggerContext::cannot_equip;
|
||||
creators["use game object"] = &WorldPacketTriggerContext::use_game_object;
|
||||
creators["complete quest"] = &WorldPacketTriggerContext::complete_quest;
|
||||
creators["accept quest"] = &WorldPacketTriggerContext::accept_quest;
|
||||
creators["quest share"] = &WorldPacketTriggerContext::quest_share;
|
||||
creators["loot roll"] = &WorldPacketTriggerContext::loot_roll;
|
||||
creators["resurrect request"] = &WorldPacketTriggerContext::resurrect_request;
|
||||
creators["area trigger"] = &WorldPacketTriggerContext::area_trigger;
|
||||
@@ -34,7 +31,20 @@ public:
|
||||
creators["trade status"] = &WorldPacketTriggerContext::trade_status;
|
||||
creators["loot response"] = &WorldPacketTriggerContext::loot_response;
|
||||
creators["out of react range"] = &WorldPacketTriggerContext::out_of_react_range;
|
||||
creators["quest objective completed"] = &WorldPacketTriggerContext::quest_objective_completed;
|
||||
|
||||
// quest
|
||||
creators["complete quest"] = &WorldPacketTriggerContext::complete_quest;
|
||||
creators["accept quest"] = &WorldPacketTriggerContext::accept_quest;
|
||||
creators["confirm quest"] = &WorldPacketTriggerContext::quest_confirm_accept;
|
||||
creators["quest share"] = &WorldPacketTriggerContext::quest_share;
|
||||
creators["quest update add kill"] = &WorldPacketTriggerContext::quest_update_add_kill;
|
||||
creators["quest update add item"] = &WorldPacketTriggerContext::quest_update_add_item;
|
||||
creators["quest update failed"] = &WorldPacketTriggerContext::quest_update_failed;
|
||||
creators["quest update failed timer"] = &WorldPacketTriggerContext::quest_update_failed_timer;
|
||||
creators["quest update complete"] = &WorldPacketTriggerContext::quest_update_complete;
|
||||
creators["questgiver quest details"] = &WorldPacketTriggerContext::questgiver_quest_details;
|
||||
|
||||
|
||||
creators["item push result"] = &WorldPacketTriggerContext::item_push_result;
|
||||
creators["party command"] = &WorldPacketTriggerContext::party_command;
|
||||
creators["taxi done"] = &WorldPacketTriggerContext::taxi_done;
|
||||
@@ -61,17 +71,12 @@ public:
|
||||
creators["receive emote"] = &WorldPacketTriggerContext::receive_emote;
|
||||
creators["receive text emote"] = &WorldPacketTriggerContext::receive_text_emote;
|
||||
creators["arena team invite"] = &WorldPacketTriggerContext::arena_team_invite;
|
||||
creators["quest confirm accept"] = &WorldPacketTriggerContext::quest_confirm_accept;
|
||||
creators["group destroyed"] = &WorldPacketTriggerContext::group_destroyed;
|
||||
creators["group list"] = &WorldPacketTriggerContext::group_list;
|
||||
creators["questgiver quest details"] = &WorldPacketTriggerContext::questgiver_quest_details;
|
||||
}
|
||||
|
||||
private:
|
||||
static Trigger* inventory_change_failure(PlayerbotAI* botAI)
|
||||
{
|
||||
return new WorldPacketTrigger(botAI, "inventory change failure");
|
||||
}
|
||||
static Trigger* inventory_change_failure(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "inventory change failure"); }
|
||||
static Trigger* guild_invite(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "guild invite"); }
|
||||
static Trigger* lfg_teleport(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "lfg teleport"); }
|
||||
static Trigger* lfg_leave(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "lfg leave"); }
|
||||
@@ -80,20 +85,26 @@ private:
|
||||
static Trigger* lfg_update(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "lfg join"); }
|
||||
static Trigger* uninvite(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "uninvite"); }
|
||||
static Trigger* uninvite_guid(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "uninvite guid"); }
|
||||
static Trigger* ready_check_finished(PlayerbotAI* botAI)
|
||||
{
|
||||
return new WorldPacketTrigger(botAI, "ready check finished");
|
||||
}
|
||||
static Trigger* ready_check_finished(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "ready check finished"); }
|
||||
static Trigger* ready_check(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "ready check"); }
|
||||
static Trigger* duel_requested(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "duel requested"); }
|
||||
static Trigger* cast_failed(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "cast failed"); }
|
||||
static Trigger* taxi_done(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "taxi done"); }
|
||||
static Trigger* party_command(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "party command"); }
|
||||
static Trigger* item_push_result(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "item push result"); }
|
||||
static Trigger* quest_objective_completed(PlayerbotAI* botAI)
|
||||
{
|
||||
return new WorldPacketTrigger(botAI, "quest objective completed");
|
||||
}
|
||||
|
||||
// quest
|
||||
static Trigger* quest_update_add_kill(PlayerbotAI* ai) { return new WorldPacketTrigger(ai, "quest update add kill"); }
|
||||
static Trigger* quest_update_add_item(PlayerbotAI* ai) { return new WorldPacketTrigger(ai, "quest update add item"); }
|
||||
static Trigger* quest_update_failed(PlayerbotAI* ai) { return new WorldPacketTrigger(ai, "quest update failed"); }
|
||||
static Trigger* quest_update_failed_timer(PlayerbotAI* ai) { return new WorldPacketTrigger(ai, "quest update failed timer"); }
|
||||
static Trigger* quest_update_complete(PlayerbotAI* ai) { return new WorldPacketTrigger(ai, "quest update complete"); }
|
||||
static Trigger* complete_quest(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "complete quest"); }
|
||||
static Trigger* accept_quest(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "accept quest"); }
|
||||
static Trigger* quest_confirm_accept(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "confirm quest"); }
|
||||
static Trigger* quest_share(PlayerbotAI* ai) { return new WorldPacketTrigger(ai, "quest share"); }
|
||||
static Trigger* questgiver_quest_details(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "questgiver quest details"); }
|
||||
|
||||
static Trigger* out_of_react_range(PlayerbotAI* botAI) { return new OutOfReactRangeTrigger(botAI); }
|
||||
static Trigger* loot_response(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "loot response"); }
|
||||
static Trigger* trade_status(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "trade status"); }
|
||||
@@ -108,9 +119,6 @@ private:
|
||||
static Trigger* no_money(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "not enough money"); }
|
||||
static Trigger* no_reputation(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "not enough reputation"); }
|
||||
static Trigger* use_game_object(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "use game object"); }
|
||||
static Trigger* complete_quest(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "complete quest"); }
|
||||
static Trigger* accept_quest(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "accept quest"); }
|
||||
static Trigger* quest_share(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "quest share"); }
|
||||
static Trigger* loot_roll(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "loot roll"); }
|
||||
static Trigger* taxi(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "activate taxi"); }
|
||||
static Trigger* bg_status(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "bg status"); }
|
||||
@@ -119,26 +127,12 @@ private:
|
||||
static Trigger* petition_offer(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "petition offer"); }
|
||||
static Trigger* seespell(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "see spell"); }
|
||||
static Trigger* release_spirit(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "release spirit"); }
|
||||
static Trigger* revive_from_corpse(PlayerbotAI* botAI)
|
||||
{
|
||||
return new WorldPacketTrigger(botAI, "revive from corpse");
|
||||
}
|
||||
static Trigger* revive_from_corpse(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "revive from corpse"); }
|
||||
static Trigger* receive_emote(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "receive emote"); }
|
||||
static Trigger* receive_text_emote(PlayerbotAI* botAI)
|
||||
{
|
||||
return new WorldPacketTrigger(botAI, "receive text emote");
|
||||
}
|
||||
static Trigger* receive_text_emote(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "receive text emote"); }
|
||||
static Trigger* arena_team_invite(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "arena team invite"); }
|
||||
static Trigger* quest_confirm_accept(PlayerbotAI* botAI)
|
||||
{
|
||||
return new WorldPacketTrigger(botAI, "quest confirm accept");
|
||||
}
|
||||
static Trigger* group_destroyed(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "group destroyed"); }
|
||||
static Trigger* group_list(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "group list"); }
|
||||
static Trigger* questgiver_quest_details(PlayerbotAI* botAI)
|
||||
{
|
||||
return new WorldPacketTrigger(botAI, "questgiver quest details");
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "Playerbots.h"
|
||||
#include "ReputationMgr.h"
|
||||
#include "SharedDefines.h"
|
||||
#include "ServerFacade.h"
|
||||
|
||||
Unit* GrindTargetValue::Calculate()
|
||||
{
|
||||
@@ -32,6 +33,9 @@ Unit* GrindTargetValue::FindTargetForGrinding(uint32 assistCount)
|
||||
Group* group = bot->GetGroup();
|
||||
Player* master = GetMaster();
|
||||
|
||||
if (master && (master == bot || master->GetMapId() != bot->GetMapId() || master->IsBeingTeleported() || !GET_PLAYERBOT_AI(master)))
|
||||
master = nullptr;
|
||||
|
||||
GuidVector attackers = context->GetValue<GuidVector>("attackers")->Get();
|
||||
for (ObjectGuid const guid : attackers)
|
||||
{
|
||||
@@ -48,8 +52,7 @@ Unit* GrindTargetValue::FindTargetForGrinding(uint32 assistCount)
|
||||
|
||||
float distance = 0;
|
||||
Unit* result = nullptr;
|
||||
|
||||
// std::unordered_map<uint32, bool> needForQuestMap;
|
||||
std::unordered_map<uint32, bool> needForQuestMap;
|
||||
|
||||
for (ObjectGuid const guid : targets)
|
||||
{
|
||||
@@ -84,19 +87,30 @@ Unit* GrindTargetValue::FindTargetForGrinding(uint32 assistCount)
|
||||
// if (!bot->InBattleground() && master && master->GetDistance(unit) >= sPlayerbotAIConfig->grindDistance &&
|
||||
// !sRandomPlayerbotMgr->IsRandomBot(bot)) continue;
|
||||
|
||||
if (!bot->InBattleground() && (int)unit->GetLevel() - (int)bot->GetLevel() > 4 && !unit->GetGUID().IsPlayer())
|
||||
// Bots in bot-groups no have a more limited range to look for grind target
|
||||
if (!bot->InBattleground() && master && botAI->HasStrategy("follow", BotState::BOT_STATE_NON_COMBAT)
|
||||
&& sServerFacade->GetDistance2d(master, unit) > sPlayerbotAIConfig->lootDistance)
|
||||
{
|
||||
if (botAI->HasStrategy("debug grind", BotState::BOT_STATE_NON_COMBAT))
|
||||
botAI->TellMaster(chat->FormatWorldobject(unit) + " ignored (far from master).");
|
||||
continue;
|
||||
}
|
||||
|
||||
// if (needForQuestMap.find(unit->GetEntry()) == needForQuestMap.end())
|
||||
// needForQuestMap[unit->GetEntry()] = needForQuest(unit);
|
||||
if (!bot->InBattleground() && (int)unit->GetLevel() - (int)bot->GetLevel() > 4 && !unit->GetGUID().IsPlayer())
|
||||
continue;
|
||||
|
||||
// if (!needForQuestMap[unit->GetEntry()])
|
||||
// if ((urand(0, 100) < 75 || (context->GetValue<TravelTarget*>("travel target")->Get()->isWorking() &&
|
||||
// context->GetValue<TravelTarget*>("travel target")->Get()->getDestination()->getName() !=
|
||||
// "GrindTravelDestination"))) continue;
|
||||
if (needForQuestMap.find(unit->GetEntry()) == needForQuestMap.end())
|
||||
needForQuestMap[unit->GetEntry()] = needForQuest(unit);
|
||||
|
||||
// if (bot->InBattleground() && bot->GetDistance(unit) > 40.0f)
|
||||
// continue;
|
||||
if (!needForQuestMap[unit->GetEntry()])
|
||||
{
|
||||
Creature* creature = dynamic_cast<Creature*>(unit);
|
||||
if ((urand(0, 100) < 60 || (context->GetValue<TravelTarget*>("travel target")->Get()->isWorking() &&
|
||||
context->GetValue<TravelTarget*>("travel target")->Get()->getDestination()->getName() != "GrindTravelDestination")))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (Creature* creature = unit->ToCreature())
|
||||
if (CreatureTemplate const* CreatureTemplate = creature->GetCreatureTemplate())
|
||||
|
||||
Reference in New Issue
Block a user