mirror of
https://github.com/mod-playerbots/mod-playerbots
synced 2025-11-29 15:58:20 +08:00
Merge branch 'master' into eots-fixes
This commit is contained in:
@@ -264,7 +264,7 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa
|
||||
|
||||
if (!player->InBattleground())
|
||||
{
|
||||
engine->addStrategies("racials", "chat", "default", "cast time", "duel", "boost", nullptr);
|
||||
engine->addStrategies("racials", "chat", "default", "cast time", "duel", "boost", "emote", nullptr);
|
||||
}
|
||||
if (sPlayerbotAIConfig->autoSaveMana)
|
||||
{
|
||||
@@ -548,12 +548,12 @@ void AiFactory::AddDefaultNonCombatStrategies(Player* player, PlayerbotAI* const
|
||||
if (!player->InBattleground())
|
||||
{
|
||||
nonCombatEngine->addStrategies("nc", "food", "chat", "follow",
|
||||
"default", "quest", "loot", "gather", "duel", "buff", "mount", nullptr);
|
||||
"default", "quest", "loot", "gather", "duel", "buff", "mount", "emote", nullptr);
|
||||
}
|
||||
if (sPlayerbotAIConfig->autoSaveMana) {
|
||||
nonCombatEngine->addStrategy("auto save mana");
|
||||
}
|
||||
if ((facade->IsRealPlayer() || sRandomPlayerbotMgr->IsRandomBot(player)) && !player->InBattleground())
|
||||
if ((sRandomPlayerbotMgr->IsRandomBot(player)) && !player->InBattleground())
|
||||
{
|
||||
Player* master = facade->GetMaster();
|
||||
|
||||
@@ -636,7 +636,7 @@ void AiFactory::AddDefaultNonCombatStrategies(Player* player, PlayerbotAI* const
|
||||
// Battleground switch
|
||||
if (player->InBattleground() && player->GetBattleground())
|
||||
{
|
||||
nonCombatEngine->addStrategies("nc", "chat", "default", "buff", "food", "mount", "pvp", "dps assist", "attack tagged", nullptr);
|
||||
nonCombatEngine->addStrategies("nc", "chat", "default", "buff", "food", "mount", "pvp", "dps assist", "attack tagged", "emote", nullptr);
|
||||
nonCombatEngine->removeStrategy("custom::say");
|
||||
nonCombatEngine->removeStrategy("travel");
|
||||
nonCombatEngine->removeStrategy("rpg");
|
||||
|
||||
@@ -288,7 +288,7 @@ std::string const ChatHelper::FormatQuest(Quest const* quest)
|
||||
std::string const ChatHelper::FormatGameobject(GameObject* go)
|
||||
{
|
||||
std::ostringstream out;
|
||||
out << "|cFFFFFF00|Hfound:" << go->GetGUID().GetRawValue() << ":" << go->GetEntry() << ":" << "|h[" << go->GetGOInfo()->name << "]|h|r";
|
||||
out << "|cFFFFFF00|Hfound:" << go->GetGUID().GetRawValue() << ":" << go->GetEntry() << ":" << "|h[" << go->GetNameForLocaleIdx(LOCALE_enUS) << "]|h|r";
|
||||
return out.str();
|
||||
}
|
||||
|
||||
@@ -296,7 +296,7 @@ std::string const ChatHelper::FormatWorldobject(WorldObject* wo)
|
||||
{
|
||||
std::ostringstream out;
|
||||
out << "|cFFFFFF00|Hfound:" << wo->GetGUID().GetRawValue() << ":" << wo->GetEntry() << ":" << "|h[";
|
||||
out << (wo->ToGameObject() ? ((GameObject*)wo)->GetGOInfo()->name : wo->GetName()) << "]|h|r";
|
||||
out << (wo->ToGameObject() ? ((GameObject*)wo)->GetNameForLocaleIdx(LOCALE_enUS) : wo->GetNameForLocaleIdx(LOCALE_enUS)) << "]|h|r";
|
||||
return out.str();
|
||||
}
|
||||
|
||||
@@ -336,6 +336,8 @@ std::string const ChatHelper::FormatItem(ItemTemplate const* proto, uint32 count
|
||||
char color[32];
|
||||
sprintf(color, "%x", ItemQualityColors[proto->Quality]);
|
||||
|
||||
// const std::string &name = sObjectMgr->GetItemLocale(proto->ItemId)->Name[LOCALE_enUS];
|
||||
|
||||
std::ostringstream out;
|
||||
out << "|c" << color << "|Hitem:" << proto->ItemId
|
||||
<< ":0:0:0:0:0:0:0" << "|h[" << proto->Name1
|
||||
|
||||
@@ -96,7 +96,7 @@ void LootObject::Refresh(Player* bot, ObjectGuid lootGUID)
|
||||
|
||||
if (IsNeededForQuest(bot, itemId))
|
||||
{
|
||||
this->guid = guid;
|
||||
this->guid = lootGUID;
|
||||
return;
|
||||
}
|
||||
isQuestItemOnly |= itemId > 0;
|
||||
|
||||
@@ -191,7 +191,7 @@ PlayerbotAI::~PlayerbotAI()
|
||||
delete aiObjectContext;
|
||||
|
||||
if (bot)
|
||||
sPlayerbotsMgr->RemovePlayerBotData(bot->GetGUID());
|
||||
sPlayerbotsMgr->RemovePlayerBotData(bot->GetGUID(), true);
|
||||
}
|
||||
|
||||
void PlayerbotAI::UpdateAI(uint32 elapsed, bool minimal)
|
||||
@@ -625,10 +625,15 @@ void PlayerbotAI::HandleCommand(uint32 type, std::string const text, Player* fro
|
||||
return;
|
||||
}
|
||||
|
||||
if (!IsAllowedCommand(filtered) && !GetSecurity()->CheckLevelFor(PLAYERBOT_SECURITY_ALLOW_ALL, type != CHAT_MSG_WHISPER, fromPlayer))
|
||||
if (!IsAllowedCommand(filtered) &&
|
||||
(master != fromPlayer || !GetSecurity()->CheckLevelFor(PLAYERBOT_SECURITY_ALLOW_ALL, type != CHAT_MSG_WHISPER, fromPlayer)))
|
||||
return;
|
||||
|
||||
if (type == CHAT_MSG_RAID_WARNING && filtered.find(bot->GetName()) != std::string::npos && filtered.find("award") == std::string::npos)
|
||||
if (!IsAllowedCommand(filtered) && master != fromPlayer)
|
||||
return;
|
||||
|
||||
if (type == CHAT_MSG_RAID_WARNING && filtered.find(bot->GetName()) != std::string::npos &&
|
||||
filtered.find("award") == std::string::npos)
|
||||
{
|
||||
ChatCommandHolder cmd("warning", fromPlayer, type);
|
||||
chatCommands.push(cmd);
|
||||
|
||||
@@ -140,7 +140,10 @@ bool PlayerbotAIConfig::Initialize()
|
||||
minRandomBotsPriceChangeInterval = sConfigMgr->GetOption<int32>("AiPlayerbot.MinRandomBotsPriceChangeInterval", 2 * HOUR);
|
||||
maxRandomBotsPriceChangeInterval = sConfigMgr->GetOption<int32>("AiPlayerbot.MaxRandomBotsPriceChangeInterval", 48 * HOUR);
|
||||
randomBotJoinLfg = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotJoinLfg", true);
|
||||
randomBotTalk = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotTalk", false);
|
||||
randomBotEmote = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotEmote", false);
|
||||
randomBotSuggestDungeons = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotSuggestDungeons", true);
|
||||
randomBotGuildTalk = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotGuildTalk", false);
|
||||
suggestDungeonsInLowerCaseRandomly = sConfigMgr->GetOption<bool>("AiPlayerbot.SuggestDungeonsInLowerCaseRandomly", false);
|
||||
randomBotJoinBG = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotJoinBG", true);
|
||||
randomBotAutoJoinBG = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotAutoJoinBG", false);
|
||||
@@ -279,7 +282,7 @@ bool PlayerbotAIConfig::Initialize()
|
||||
allowSummonInCombat = sConfigMgr->GetOption<bool>("AiPlayerbot.AllowSummonInCombat", true);
|
||||
allowSummonWhenMasterIsDead = sConfigMgr->GetOption<bool>("AiPlayerbot.AllowSummonWhenMasterIsDead", true);
|
||||
allowSummonWhenBotIsDead = sConfigMgr->GetOption<bool>("AiPlayerbot.AllowSummonWhenBotIsDead", true);
|
||||
reviveBotWhenSummoned = sConfigMgr->GetOption<bool>("AiPlayerbot.ReviveBotWhenSummoned", true);
|
||||
reviveBotWhenSummoned = sConfigMgr->GetOption<int32>("AiPlayerbot.ReviveBotWhenSummoned", 1);
|
||||
botRepairWhenSummon = sConfigMgr->GetOption<bool>("AiPlayerbot.BotRepairWhenSummon", true);
|
||||
autoInitOnly = sConfigMgr->GetOption<bool>("AiPlayerbot.AutoInitOnly", false);
|
||||
autoInitEquipLevelLimitRatio = sConfigMgr->GetOption<float>("AiPlayerbot.AutoInitEquipLevelLimitRatio", 1.0);
|
||||
|
||||
@@ -95,7 +95,10 @@ class PlayerbotAIConfig
|
||||
uint32 randomBotsPerInterval;
|
||||
uint32 minRandomBotsPriceChangeInterval, maxRandomBotsPriceChangeInterval;
|
||||
bool randomBotJoinLfg;
|
||||
bool randomBotTalk;
|
||||
bool randomBotEmote;
|
||||
bool randomBotSuggestDungeons;
|
||||
bool randomBotGuildTalk;
|
||||
bool suggestDungeonsInLowerCaseRandomly;
|
||||
bool randomBotJoinBG;
|
||||
bool randomBotAutoJoinBG;
|
||||
@@ -220,7 +223,7 @@ class PlayerbotAIConfig
|
||||
bool allowSummonInCombat;
|
||||
bool allowSummonWhenMasterIsDead;
|
||||
bool allowSummonWhenBotIsDead;
|
||||
bool reviveBotWhenSummoned;
|
||||
int reviveBotWhenSummoned;
|
||||
bool botRepairWhenSummon;
|
||||
bool autoInitOnly;
|
||||
float autoInitEquipLevelLimitRatio;
|
||||
|
||||
@@ -136,6 +136,9 @@ void PlayerbotFactory::Init()
|
||||
continue;
|
||||
}
|
||||
ItemTemplate const* proto = sObjectMgr->GetItemTemplate(gemId);
|
||||
if (proto->Flags & ITEM_FLAG_UNIQUE_EQUIPPABLE) { // unique gem
|
||||
continue;
|
||||
}
|
||||
if (!proto || !sGemPropertiesStore.LookupEntry(proto->GemProperties)) {
|
||||
continue;
|
||||
}
|
||||
@@ -644,6 +647,7 @@ void PlayerbotFactory::InitPetTalents()
|
||||
spells_row.erase(spells_row.begin() + index);
|
||||
}
|
||||
}
|
||||
bot->SendTalentsInfoData(true);
|
||||
}
|
||||
|
||||
void PlayerbotFactory::InitPet()
|
||||
@@ -870,6 +874,7 @@ void PlayerbotFactory::InitTalentsTree(bool increment/*false*/, bool use_templat
|
||||
if (bot->GetFreeTalentPoints())
|
||||
InitTalents((specTab + 1) % 3);
|
||||
}
|
||||
bot->SendTalentsInfoData(false);
|
||||
}
|
||||
|
||||
void PlayerbotFactory::InitTalentsBySpecNo(Player* bot, int specNo, bool reset)
|
||||
@@ -933,6 +938,7 @@ void PlayerbotFactory::InitTalentsBySpecNo(Player* bot, int specNo, bool reset)
|
||||
break;
|
||||
}
|
||||
}
|
||||
bot->SendTalentsInfoData(false);
|
||||
}
|
||||
|
||||
void PlayerbotFactory::InitTalentsByParsedSpecLink(Player* bot, std::vector<std::vector<uint32>> parsedSpecLink, bool reset)
|
||||
@@ -983,6 +989,7 @@ void PlayerbotFactory::InitTalentsByParsedSpecLink(Player* bot, std::vector<std:
|
||||
break;
|
||||
}
|
||||
}
|
||||
bot->SendTalentsInfoData(false);
|
||||
}
|
||||
|
||||
class DestroyItemsVisitor : public IterateItemsVisitor
|
||||
@@ -1734,7 +1741,7 @@ void PlayerbotFactory::InitBags(bool destroyOld)
|
||||
bot->DestroyItem(INVENTORY_SLOT_BAG_0, slot, true);
|
||||
}
|
||||
if (old_bag) {
|
||||
return;
|
||||
continue;
|
||||
}
|
||||
Item* newItem = bot->EquipNewItem(dest, newItemId, true);
|
||||
if (newItem)
|
||||
@@ -2567,7 +2574,7 @@ void PlayerbotFactory::InitMounts()
|
||||
break;
|
||||
case RACE_NIGHTELF:
|
||||
slow = { 10789, 8394, 10793 };
|
||||
fast = { 24252, 63637, 22723 };
|
||||
fast = { 23219, 23220, 63637 };
|
||||
break;
|
||||
case RACE_UNDEAD_PLAYER:
|
||||
slow = { 17463, 17464, 17462 };
|
||||
@@ -2616,6 +2623,16 @@ void PlayerbotFactory::InitMounts()
|
||||
|
||||
for (uint32 type = 0; type < 4; type++)
|
||||
{
|
||||
bool hasMount = false;
|
||||
for (uint32 &spell : mounts[bot->getRace()][type]) {
|
||||
if (bot->HasSpell(spell)) {
|
||||
hasMount = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (hasMount)
|
||||
continue;
|
||||
|
||||
if (bot->GetLevel() < secondmount && type == 1)
|
||||
continue;
|
||||
|
||||
@@ -2844,7 +2861,29 @@ void PlayerbotFactory::InitGlyphs(bool increment)
|
||||
if (!increment) {
|
||||
for (uint32 slotIndex = 0; slotIndex < MAX_GLYPH_SLOT_INDEX; ++slotIndex)
|
||||
{
|
||||
bot->SetGlyph(slotIndex, 0, true);
|
||||
uint32 glyph = bot->GetGlyph(slotIndex);
|
||||
if (GlyphPropertiesEntry const* glyphEntry = sGlyphPropertiesStore.LookupEntry(glyph))
|
||||
{
|
||||
bot->RemoveAurasDueToSpell(glyphEntry->SpellId);
|
||||
|
||||
// Removed any triggered auras
|
||||
Unit::AuraMap& ownedAuras = bot->GetOwnedAuras();
|
||||
for (Unit::AuraMap::iterator iter = ownedAuras.begin(); iter != ownedAuras.end();)
|
||||
{
|
||||
Aura* aura = iter->second;
|
||||
if (SpellInfo const* triggeredByAuraSpellInfo = aura->GetTriggeredByAuraSpellInfo())
|
||||
{
|
||||
if (triggeredByAuraSpellInfo->Id == glyphEntry->SpellId)
|
||||
{
|
||||
bot->RemoveOwnedAura(iter);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
++iter;
|
||||
}
|
||||
|
||||
bot->SetGlyph(slotIndex, 0, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2943,6 +2982,8 @@ void PlayerbotFactory::InitGlyphs(bool increment)
|
||||
if (!glyph) {
|
||||
continue;
|
||||
}
|
||||
GlyphPropertiesEntry const* glyphEntry = sGlyphPropertiesStore.LookupEntry(glyph);
|
||||
bot->CastSpell(bot, glyphEntry->SpellId, TriggerCastFlags(TRIGGERED_FULL_MASK & ~(TRIGGERED_IGNORE_SHAPESHIFT | TRIGGERED_IGNORE_CASTER_AURASTATE)));
|
||||
bot->SetGlyph(realSlot, glyph, true);
|
||||
chosen.insert(glyph);
|
||||
} else {
|
||||
@@ -2976,13 +3017,16 @@ void PlayerbotFactory::InitGlyphs(bool increment)
|
||||
continue;
|
||||
|
||||
chosen.insert(id);
|
||||
|
||||
GlyphPropertiesEntry const* glyphEntry = sGlyphPropertiesStore.LookupEntry(id);
|
||||
bot->CastSpell(bot, glyphEntry->SpellId, TriggerCastFlags(TRIGGERED_FULL_MASK & ~(TRIGGERED_IGNORE_SHAPESHIFT | TRIGGERED_IGNORE_CASTER_AURASTATE)));
|
||||
|
||||
bot->SetGlyph(realSlot, id, true);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
bot->SendTalentsInfoData(false);
|
||||
}
|
||||
|
||||
void PlayerbotFactory::CancelAuras()
|
||||
|
||||
@@ -85,7 +85,8 @@ void PlayerbotHolder::HandlePlayerBotLoginCallback(PlayerbotLoginQueryHolder con
|
||||
|
||||
uint32 botAccountId = holder.GetAccountId();
|
||||
|
||||
WorldSession* botSession = new WorldSession(botAccountId, "", nullptr, SEC_PLAYER, EXPANSION_WRATH_OF_THE_LICH_KING, time_t(0), LOCALE_enUS, 0, false, false, 0, true);
|
||||
// At login DBC locale should be what the server is set to use by default (as spells etc are hardcoded to ENUS this allows channels to work as intended)
|
||||
WorldSession* botSession = new WorldSession(botAccountId, "", nullptr, SEC_PLAYER, EXPANSION_WRATH_OF_THE_LICH_KING, time_t(0), sWorld->GetDefaultDbcLocale(), 0, false, false, 0, true);
|
||||
|
||||
botSession->HandlePlayerLoginFromDB(holder); // will delete lqh
|
||||
|
||||
@@ -525,7 +526,7 @@ void PlayerbotHolder::OnBotLogin(Player* const bot)
|
||||
// join standard channels
|
||||
AreaTableEntry const* current_zone = sAreaTableStore.LookupEntry(bot->GetAreaId());
|
||||
ChannelMgr* cMgr = ChannelMgr::forTeam(bot->GetTeamId());
|
||||
std::string current_zone_name = current_zone ? current_zone->area_name[0] : "";
|
||||
std::string current_zone_name = current_zone ? current_zone->area_name[sWorld->GetDefaultDbcLocale()] : "";
|
||||
|
||||
if (current_zone && cMgr)
|
||||
{
|
||||
@@ -544,13 +545,13 @@ void PlayerbotHolder::OnBotLogin(Player* const bot)
|
||||
Channel* new_channel = nullptr;
|
||||
if (isLfg)
|
||||
{
|
||||
std::string lfgChannelName = channel->pattern[0];
|
||||
std::string lfgChannelName = channel->pattern[sWorld->GetDefaultDbcLocale()];
|
||||
new_channel = cMgr->GetJoinChannel("LookingForGroup", channel->ChannelID);
|
||||
}
|
||||
else
|
||||
{
|
||||
char new_channel_name_buf[100];
|
||||
snprintf(new_channel_name_buf, 100, channel->pattern[0], current_zone_name.c_str());
|
||||
snprintf(new_channel_name_buf, 100, channel->pattern[sWorld->GetDefaultDbcLocale()], current_zone_name.c_str());
|
||||
new_channel = cMgr->GetJoinChannel(new_channel_name_buf, channel->ChannelID);
|
||||
}
|
||||
if (new_channel && new_channel->GetName().length() > 0)
|
||||
@@ -736,7 +737,7 @@ bool PlayerbotMgr::HandlePlayerbotMgrCommand(ChatHandler* handler, char const* a
|
||||
|
||||
for (std::vector<std::string>::iterator i = messages.begin(); i != messages.end(); ++i)
|
||||
{
|
||||
handler->PSendSysMessage("%s", i->c_str());
|
||||
handler->PSendSysMessage("{}", i->c_str());
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -748,8 +749,8 @@ std::vector<std::string> PlayerbotHolder::HandlePlayerbotCommand(char const* arg
|
||||
|
||||
if (!*args)
|
||||
{
|
||||
messages.push_back("usage: list/reload/tweak/self or add/init/remove PLAYERNAME");
|
||||
messages.push_back(" addclass CLASSNAME");
|
||||
messages.push_back("usage: list/reload/tweak/self or add/init/remove PLAYERNAME\n");
|
||||
messages.push_back("usage: addclass CLASSNAME");
|
||||
return messages;
|
||||
}
|
||||
|
||||
@@ -842,7 +843,7 @@ std::vector<std::string> PlayerbotHolder::HandlePlayerbotCommand(char const* arg
|
||||
if (GET_PLAYERBOT_AI(master))
|
||||
{
|
||||
messages.push_back("Disable player botAI");
|
||||
DisablePlayerBot(master->GetGUID());
|
||||
delete GET_PLAYERBOT_AI(master);
|
||||
}
|
||||
else if (sPlayerbotAIConfig->selfBotLevel == 0)
|
||||
messages.push_back("Self-bot is disabled");
|
||||
@@ -851,7 +852,8 @@ std::vector<std::string> PlayerbotHolder::HandlePlayerbotCommand(char const* arg
|
||||
else
|
||||
{
|
||||
messages.push_back("Enable player botAI");
|
||||
OnBotLogin(master);
|
||||
sPlayerbotsMgr->AddPlayerbotData(master, true);
|
||||
GET_PLAYERBOT_AI(master)->SetMaster(master);
|
||||
}
|
||||
|
||||
return messages;
|
||||
@@ -938,20 +940,22 @@ std::vector<std::string> PlayerbotHolder::HandlePlayerbotCommand(char const* arg
|
||||
race_limit = "2, 5, 6, 8, 10";
|
||||
break;
|
||||
}
|
||||
uint32 maxAccountId = sPlayerbotAIConfig->randomBotAccounts.back();
|
||||
// find a bot fit conditions and not in any guild
|
||||
QueryResult results = CharacterDatabase.Query("SELECT guid FROM characters "
|
||||
"WHERE name IN (SELECT name FROM playerbots_names) AND class = '{}' AND online = 0 AND race IN ({}) AND guid NOT IN ( SELECT guid FROM guild_member ) "
|
||||
"ORDER BY account DESC LIMIT 1", claz, race_limit);
|
||||
"AND account <= {} "
|
||||
"ORDER BY account DESC LIMIT 1", claz, race_limit, maxAccountId);
|
||||
if (results)
|
||||
{
|
||||
Field* fields = results->Fetch();
|
||||
ObjectGuid guid = ObjectGuid(HighGuid::Player, fields[0].Get<uint32>());
|
||||
AddPlayerBot(guid, master->GetSession()->GetAccountId());
|
||||
|
||||
messages.push_back("addclass " + std::string(charname) + " ok");
|
||||
messages.push_back("Add class " + std::string(charname));
|
||||
return messages;
|
||||
}
|
||||
messages.push_back("addclass failed.");
|
||||
messages.push_back("Add class failed.");
|
||||
return messages;
|
||||
}
|
||||
|
||||
@@ -1214,7 +1218,7 @@ PlayerbotMgr::PlayerbotMgr(Player* const master) : PlayerbotHolder(), master(ma
|
||||
PlayerbotMgr::~PlayerbotMgr()
|
||||
{
|
||||
if (master)
|
||||
sPlayerbotsMgr->RemovePlayerBotData(master->GetGUID());
|
||||
sPlayerbotsMgr->RemovePlayerBotData(master->GetGUID(), false);
|
||||
}
|
||||
|
||||
void PlayerbotMgr::UpdateAIInternal(uint32 elapsed, bool /*minimal*/)
|
||||
@@ -1427,31 +1431,45 @@ void PlayerbotsMgr::AddPlayerbotData(Player* player, bool isBotAI)
|
||||
return;
|
||||
}
|
||||
// If the guid already exists in the map, remove it
|
||||
std::unordered_map<ObjectGuid, PlayerbotAIBase*>::iterator itr = _playerbotsMap.find(player->GetGUID());
|
||||
if (itr != _playerbotsMap.end())
|
||||
{
|
||||
_playerbotsMap.erase(itr);
|
||||
}
|
||||
|
||||
if (!isBotAI)
|
||||
{
|
||||
std::unordered_map<ObjectGuid, PlayerbotAIBase*>::iterator itr = _playerbotsMgrMap.find(player->GetGUID());
|
||||
if (itr != _playerbotsMgrMap.end())
|
||||
{
|
||||
_playerbotsMgrMap.erase(itr);
|
||||
}
|
||||
PlayerbotMgr* playerbotMgr = new PlayerbotMgr(player);
|
||||
ASSERT(_playerbotsMap.emplace(player->GetGUID(), playerbotMgr).second);
|
||||
ASSERT(_playerbotsMgrMap.emplace(player->GetGUID(), playerbotMgr).second);
|
||||
|
||||
playerbotMgr->OnPlayerLogin(player);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::unordered_map<ObjectGuid, PlayerbotAIBase*>::iterator itr = _playerbotsAIMap.find(player->GetGUID());
|
||||
if (itr != _playerbotsAIMap.end())
|
||||
{
|
||||
_playerbotsAIMap.erase(itr);
|
||||
}
|
||||
PlayerbotAI* botAI = new PlayerbotAI(player);
|
||||
ASSERT(_playerbotsMap.emplace(player->GetGUID(), botAI).second);
|
||||
ASSERT(_playerbotsAIMap.emplace(player->GetGUID(), botAI).second);
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerbotsMgr::RemovePlayerBotData(ObjectGuid const& guid)
|
||||
void PlayerbotsMgr::RemovePlayerBotData(ObjectGuid const& guid, bool is_AI)
|
||||
{
|
||||
std::unordered_map<ObjectGuid, PlayerbotAIBase*>::iterator itr = _playerbotsMap.find(guid);
|
||||
if (itr != _playerbotsMap.end())
|
||||
{
|
||||
_playerbotsMap.erase(itr);
|
||||
if (is_AI) {
|
||||
std::unordered_map<ObjectGuid, PlayerbotAIBase*>::iterator itr = _playerbotsAIMap.find(guid);
|
||||
if (itr != _playerbotsAIMap.end())
|
||||
{
|
||||
_playerbotsAIMap.erase(itr);
|
||||
}
|
||||
} else {
|
||||
std::unordered_map<ObjectGuid, PlayerbotAIBase*>::iterator itr = _playerbotsMgrMap.find(guid);
|
||||
if (itr != _playerbotsMgrMap.end())
|
||||
{
|
||||
_playerbotsMgrMap.erase(itr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1464,8 +1482,8 @@ PlayerbotAI* PlayerbotsMgr::GetPlayerbotAI(Player* player)
|
||||
// if (player->GetSession()->isLogingOut() || player->IsDuringRemoveFromWorld()) {
|
||||
// return nullptr;
|
||||
// }
|
||||
auto itr = _playerbotsMap.find(player->GetGUID());
|
||||
if (itr != _playerbotsMap.end())
|
||||
auto itr = _playerbotsAIMap.find(player->GetGUID());
|
||||
if (itr != _playerbotsAIMap.end())
|
||||
{
|
||||
if (itr->second->IsBotAI())
|
||||
return reinterpret_cast<PlayerbotAI*>(itr->second);
|
||||
@@ -1480,8 +1498,8 @@ PlayerbotMgr* PlayerbotsMgr::GetPlayerbotMgr(Player* player)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
auto itr = _playerbotsMap.find(player->GetGUID());
|
||||
if (itr != _playerbotsMap.end())
|
||||
auto itr = _playerbotsMgrMap.find(player->GetGUID());
|
||||
if (itr != _playerbotsMgrMap.end())
|
||||
{
|
||||
if (!itr->second->IsBotAI())
|
||||
return reinterpret_cast<PlayerbotMgr*>(itr->second);
|
||||
|
||||
@@ -99,13 +99,14 @@ class PlayerbotsMgr
|
||||
}
|
||||
|
||||
void AddPlayerbotData(Player* player, bool isBotAI);
|
||||
void RemovePlayerBotData(ObjectGuid const& guid);
|
||||
void RemovePlayerBotData(ObjectGuid const& guid, bool is_AI);
|
||||
|
||||
PlayerbotAI* GetPlayerbotAI(Player* player);
|
||||
PlayerbotMgr* GetPlayerbotMgr(Player* player);
|
||||
|
||||
private:
|
||||
std::unordered_map<ObjectGuid, PlayerbotAIBase*> _playerbotsMap;
|
||||
std::unordered_map<ObjectGuid, PlayerbotAIBase*> _playerbotsAIMap;
|
||||
std::unordered_map<ObjectGuid, PlayerbotAIBase*> _playerbotsMgrMap;
|
||||
};
|
||||
|
||||
#define sPlayerbotsMgr PlayerbotsMgr::instance()
|
||||
|
||||
@@ -28,12 +28,13 @@ void PlayerbotTextMgr::LoadBotTexts()
|
||||
Field* fields = result->Fetch();
|
||||
std::string name = fields[0].Get<std::string>();
|
||||
text[0] = fields[1].Get<std::string>();
|
||||
uint32 sayType = fields[2].Get<uint32>();
|
||||
uint32 replyType = fields[3].Get<uint32>();
|
||||
uint8 sayType = fields[2].Get<uint8>();
|
||||
uint8 replyType = fields[3].Get<uint8>();
|
||||
for (uint8 i = 1; i < MAX_LOCALES; ++i)
|
||||
{
|
||||
text[i] = fields[i + 3].Get<std::string>();
|
||||
}
|
||||
|
||||
botTexts[name].push_back(BotTextEntry(name, text, sayType, replyType));
|
||||
++count;
|
||||
}
|
||||
@@ -191,6 +192,7 @@ uint32 PlayerbotTextMgr::GetLocalePriority()
|
||||
if (botTextLocalePriority[i] > topLocale)
|
||||
topLocale = i;
|
||||
}
|
||||
|
||||
return topLocale;
|
||||
}
|
||||
|
||||
|
||||
@@ -299,7 +299,7 @@ class PlayerbotsScript : public PlayerbotScript
|
||||
{
|
||||
botAI->HandleBotOutgoingPacket(*packet);
|
||||
}
|
||||
else if (PlayerbotMgr* playerbotMgr = GET_PLAYERBOT_MGR(player))
|
||||
if (PlayerbotMgr* playerbotMgr = GET_PLAYERBOT_MGR(player))
|
||||
{
|
||||
playerbotMgr->HandleMasterOutgoingPacket(*packet);
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "RandomPlayerbotMgr.h"
|
||||
#include "SharedValueContext.h"
|
||||
#include "Spell.h"
|
||||
#include "SpellMgr.h"
|
||||
#include "TravelNode.h"
|
||||
|
||||
std::vector<std::string> split(std::string const s, char delim);
|
||||
|
||||
@@ -2211,8 +2211,8 @@ void RandomItemMgr::BuildAmmoCache()
|
||||
{
|
||||
for (uint32 subClass = ITEM_SUBCLASS_ARROW; subClass <= ITEM_SUBCLASS_BULLET; subClass++)
|
||||
{
|
||||
QueryResult results = WorldDatabase.Query("SELECT entry, Flags FROM item_template WHERE class = {} AND subclass = {} AND RequiredLevel <= {} AND stackable = 1000 "
|
||||
"ORDER BY RequiredLevel DESC", ITEM_CLASS_PROJECTILE, subClass, level);
|
||||
QueryResult results = WorldDatabase.Query("SELECT entry, Flags FROM item_template WHERE class = {} AND subclass = {} AND RequiredLevel <= {} "
|
||||
"ORDER BY stackable DESC, RequiredLevel DESC", ITEM_CLASS_PROJECTILE, subClass, level);
|
||||
if (!results)
|
||||
continue;
|
||||
do {
|
||||
|
||||
@@ -375,7 +375,7 @@ void RandomPlayerbotFactory::CreateRandomBots()
|
||||
LOG_INFO("playerbots", "Creating random bot accounts...");
|
||||
|
||||
std::vector<std::future<void>> account_creations;
|
||||
bool account_creation = false;
|
||||
int account_creation = 0;
|
||||
for (uint32 accountNumber = 0; accountNumber < sPlayerbotAIConfig->randomBotAccountCount; ++accountNumber)
|
||||
{
|
||||
std::ostringstream out;
|
||||
@@ -389,7 +389,7 @@ void RandomPlayerbotFactory::CreateRandomBots()
|
||||
{
|
||||
continue;
|
||||
}
|
||||
account_creation = true;
|
||||
account_creation++;
|
||||
std::string password = "";
|
||||
if (sPlayerbotAIConfig->randomBotRandomPassword)
|
||||
{
|
||||
@@ -408,6 +408,7 @@ void RandomPlayerbotFactory::CreateRandomBots()
|
||||
|
||||
if (account_creation) {
|
||||
/* wait for async accounts create to make character create correctly, same as account delete */
|
||||
LOG_INFO("playerbots", "Waiting for {} accounts loading into database...", account_creation);
|
||||
std::this_thread::sleep_for(10ms * sPlayerbotAIConfig->randomBotAccountCount);
|
||||
}
|
||||
|
||||
@@ -418,7 +419,7 @@ void RandomPlayerbotFactory::CreateRandomBots()
|
||||
std::unordered_map<uint8,std::vector<std::string>> names;
|
||||
std::vector<std::pair<Player*, uint32>> playerBots;
|
||||
std::vector<WorldSession*> sessionBots;
|
||||
bool bot_creation = false;
|
||||
int bot_creation = 0;
|
||||
for (uint32 accountNumber = 0; accountNumber < sPlayerbotAIConfig->randomBotAccountCount; ++accountNumber)
|
||||
{
|
||||
std::ostringstream out;
|
||||
@@ -441,7 +442,6 @@ void RandomPlayerbotFactory::CreateRandomBots()
|
||||
{
|
||||
continue;
|
||||
}
|
||||
bot_creation = true;
|
||||
LOG_INFO("playerbots", "Creating random bot characters for account: [{}/{}]", accountNumber + 1, sPlayerbotAIConfig->randomBotAccountCount);
|
||||
RandomPlayerbotFactory factory(accountId);
|
||||
|
||||
@@ -462,19 +462,23 @@ void RandomPlayerbotFactory::CreateRandomBots()
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cls != 10)
|
||||
if (cls != 10) {
|
||||
if (Player* playerBot = factory.CreateRandomBot(session, cls, names)) {
|
||||
playerBot->SaveToDB(true, false);
|
||||
sCharacterCache->AddCharacterCacheEntry(playerBot->GetGUID(), accountId, playerBot->GetName(),
|
||||
playerBot->getGender(), playerBot->getRace(), playerBot->getClass(), playerBot->GetLevel());
|
||||
playerBot->CleanupsBeforeDelete();
|
||||
delete playerBot;
|
||||
bot_creation++;
|
||||
} else {
|
||||
LOG_ERROR("playerbots", "Fail to create character for account {}", accountId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bot_creation) {
|
||||
LOG_INFO("playerbots", "Waiting for {} characters loading into database...", totalCharCount);
|
||||
LOG_INFO("playerbots", "Waiting for {} characters loading into database...", bot_creation);
|
||||
/* wait for characters load into database, or characters will fail to loggin */
|
||||
std::this_thread::sleep_for(10s);
|
||||
}
|
||||
|
||||
@@ -1228,8 +1228,8 @@ void RandomPlayerbotMgr::RandomTeleport(Player* bot, std::vector<WorldLocation>&
|
||||
if (bot->GetLevel() <= 18 && (loc.GetMapId() != pInfo->mapId || dis > 10000.0f)) {
|
||||
continue;
|
||||
}
|
||||
LocaleConstant locale = sWorld->GetDefaultDbcLocale();
|
||||
|
||||
|
||||
const LocaleConstant& locale = sWorld->GetDefaultDbcLocale();
|
||||
LOG_INFO("playerbots", "Random teleporting bot {} (level {}) to Map: {} ({}) Zone: {} ({}) Area: {} ({}) {},{},{} ({}/{} locations)",
|
||||
bot->GetName().c_str(), bot->GetLevel(),
|
||||
map->GetId(), map->GetMapName(),
|
||||
@@ -1501,7 +1501,6 @@ void RandomPlayerbotMgr::Randomize(Player* bot)
|
||||
else {
|
||||
RandomizeFirst(bot);
|
||||
}
|
||||
RandomTeleportForLevel(bot);
|
||||
}
|
||||
|
||||
void RandomPlayerbotMgr::IncreaseLevel(Player* bot)
|
||||
@@ -1590,6 +1589,8 @@ void RandomPlayerbotMgr::RandomizeFirst(Player* bot)
|
||||
|
||||
if (pmo)
|
||||
pmo->finish();
|
||||
|
||||
RandomTeleportForLevel(bot);
|
||||
}
|
||||
|
||||
void RandomPlayerbotMgr::RandomizeMin(Player* bot)
|
||||
|
||||
@@ -172,6 +172,7 @@ bool Engine::DoNextAction(Unit* unit, uint32 depth, bool minimal)
|
||||
|
||||
if (!action)
|
||||
{
|
||||
//LOG_ERROR("playerbots", "Action: {} - is UNKNOWN - c:{} l:{}", actionNode->getName().c_str(), botAI->GetBot()->getClass(), botAI->GetBot()->GetLevel());
|
||||
LogAction("A:%s - UNKNOWN", actionNode->getName().c_str());
|
||||
}
|
||||
else if (action->isUseful())
|
||||
|
||||
@@ -4,17 +4,24 @@
|
||||
|
||||
#include "AcceptInvitationAction.h"
|
||||
#include "Event.h"
|
||||
#include "ObjectAccessor.h"
|
||||
#include "PlayerbotAIConfig.h"
|
||||
#include "Playerbots.h"
|
||||
#include "PlayerbotSecurity.h"
|
||||
#include "WorldPacket.h"
|
||||
|
||||
bool AcceptInvitationAction::Execute(Event event)
|
||||
{
|
||||
Group* grp = bot->GetGroupInvite();
|
||||
if (!grp)
|
||||
return false;
|
||||
WorldPacket packet = event.getPacket();
|
||||
uint8 flag;
|
||||
std::string name;
|
||||
packet >> flag >> name;
|
||||
|
||||
Player* inviter = ObjectAccessor::FindPlayer(grp->GetLeaderGUID());
|
||||
// Player* inviter = ObjectAccessor::FindPlayer(grp->GetLeaderGUID());
|
||||
Player* inviter = ObjectAccessor::FindPlayerByName(name, true);
|
||||
if (!inviter)
|
||||
return false;
|
||||
|
||||
|
||||
@@ -123,6 +123,7 @@ class ActionContext : public NamedObjectContext<Action>
|
||||
creators["talk"] = &ActionContext::talk;
|
||||
creators["suggest what to do"] = &ActionContext::suggest_what_to_do;
|
||||
creators["suggest trade"] = &ActionContext::suggest_trade;
|
||||
creators["suggest dungeon"] = &ActionContext::suggest_dungeon;
|
||||
creators["return"] = &ActionContext::_return;
|
||||
creators["move to loot"] = &ActionContext::move_to_loot;
|
||||
creators["open loot"] = &ActionContext::open_loot;
|
||||
@@ -280,6 +281,7 @@ class ActionContext : public NamedObjectContext<Action>
|
||||
static Action* talk(PlayerbotAI* botAI) { return new TalkAction(botAI); }
|
||||
static Action* suggest_what_to_do(PlayerbotAI* botAI) { return new SuggestWhatToDoAction(botAI); }
|
||||
static Action* suggest_trade(PlayerbotAI* botAI) { return new SuggestTradeAction(botAI); }
|
||||
static Action* suggest_dungeon(PlayerbotAI* botAI) { return new SuggestDungeonAction(botAI); }
|
||||
static Action* attack_anything(PlayerbotAI* botAI) { return new AttackAnythingAction(botAI); }
|
||||
static Action* attack_least_hp_target(PlayerbotAI* botAI) { return new AttackLeastHpTargetAction(botAI); }
|
||||
static Action* attack_enemy_player(PlayerbotAI* botAI) { return new AttackEnemyPlayerAction(botAI); }
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "Event.h"
|
||||
#include "PlayerbotFactory.h"
|
||||
#include "Playerbots.h"
|
||||
#include "GuildMgr.h"
|
||||
|
||||
bool AutoLearnSpellAction::Execute(Event event)
|
||||
{
|
||||
@@ -27,7 +28,6 @@ bool AutoLearnSpellAction::Execute(Event event)
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void AutoLearnSpellAction::LearnSpells(std::ostringstream* out)
|
||||
{
|
||||
if (sPlayerbotAIConfig->autoLearnTrainerSpells && sRandomPlayerbotMgr->IsRandomBot(bot))// || (!botAI->GetMaster() && sRandomPlayerbotMgr->IsRandomBot(bot)))
|
||||
@@ -35,6 +35,22 @@ void AutoLearnSpellAction::LearnSpells(std::ostringstream* out)
|
||||
|
||||
if (sPlayerbotAIConfig->autoLearnQuestSpells && sRandomPlayerbotMgr->IsRandomBot(bot))// || (!botAI->GetMaster() && sRandomPlayerbotMgr->IsRandomBot(bot)))
|
||||
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)
|
||||
|
||||
@@ -2386,11 +2386,11 @@ static std::pair<uint32, uint32> AV_AllianceDefendObjectives[] =
|
||||
static uint32 AB_AttackObjectives[] =
|
||||
{
|
||||
// Attack
|
||||
{ BG_AB_NODE_STABLES },
|
||||
{ BG_AB_NODE_BLACKSMITH },
|
||||
{ BG_AB_NODE_FARM },
|
||||
{ BG_AB_NODE_LUMBER_MILL },
|
||||
{ BG_AB_NODE_GOLD_MINE }
|
||||
BG_AB_NODE_STABLES,
|
||||
BG_AB_NODE_BLACKSMITH,
|
||||
BG_AB_NODE_FARM,
|
||||
BG_AB_NODE_LUMBER_MILL,
|
||||
BG_AB_NODE_GOLD_MINE
|
||||
};
|
||||
|
||||
static std::tuple<uint32, uint32, uint32> EY_AttackObjectives[] =
|
||||
|
||||
@@ -447,7 +447,7 @@ bool EmoteActionBase::ReceiveEmote(Player* source, uint32 emote, bool verbal)
|
||||
case TEXT_EMOTE_RASP:
|
||||
emoteId = EMOTE_ONESHOT_RUDE;
|
||||
textEmote = TEXT_EMOTE_RASP;
|
||||
emoteText = "Right back at you, bub!", LANG_UNIVERSAL;
|
||||
emoteText = "Right back at you, bub!"; // , LANG_UNIVERSAL;
|
||||
break;
|
||||
case TEXT_EMOTE_ROAR:
|
||||
case TEXT_EMOTE_THREATEN:
|
||||
@@ -671,9 +671,9 @@ bool EmoteAction::Execute(Event event)
|
||||
if (pSource && (pSource->GetGUID() != bot->GetGUID()) && ((urand(0, 1) && bot->HasInArc(static_cast<float>(M_PI), pSource, 10.0f)) ||
|
||||
(namlen > 1 && strstri(bot->GetName().c_str(), nam.c_str()))))
|
||||
{
|
||||
LOG_INFO("playerbots", "Bot {} {}:{} <{}> received SMSG_TEXT_EMOTE {} from player {} <{}>",
|
||||
/*LOG_INFO("playerbots", "Bot {} {}:{} <{}> received SMSG_TEXT_EMOTE {} from player {} <{}>",
|
||||
bot->GetGUID().ToString().c_str(), bot->GetTeamId() == TEAM_ALLIANCE ? "A" : "H", bot->GetLevel(),
|
||||
bot->GetName(), text_emote, pSource->GetGUID().ToString().c_str(), pSource->GetName());
|
||||
bot->GetName(), text_emote, pSource->GetGUID().ToString().c_str(), pSource->GetName());*/
|
||||
|
||||
emote = text_emote;
|
||||
}
|
||||
@@ -693,9 +693,9 @@ bool EmoteAction::Execute(Event event)
|
||||
if ((pSource->GetGUID() != bot->GetGUID()) && (pSource->GetTarget() == bot->GetGUID() ||
|
||||
(urand(0, 1) && bot->HasInArc(static_cast<float>(M_PI), pSource, 10.0f))))
|
||||
{
|
||||
LOG_INFO("playerbots", "Bot {} {}:{} <{}> received SMSG_EMOTE {} from player {} <{}>",
|
||||
/*LOG_INFO("playerbots", "Bot {} {}:{} <{}> received SMSG_EMOTE {} from player {} <{}>",
|
||||
bot->GetGUID().ToString().c_str(), bot->GetTeamId() == TEAM_ALLIANCE ? "A" : "H", bot->GetLevel(), bot->GetName(),
|
||||
emoteId, pSource->GetGUID().ToString().c_str(), pSource->GetName());
|
||||
emoteId, pSource->GetGUID().ToString().c_str(), pSource->GetName());*/
|
||||
|
||||
std::vector<uint32> types;
|
||||
for (int32 i = sEmotesTextStore.GetNumRows(); i >= 0; --i)
|
||||
|
||||
@@ -20,6 +20,7 @@ bool TogglePetSpellAutoCastAction::Execute(Event event) {
|
||||
if (!pet) {
|
||||
return false;
|
||||
}
|
||||
bool toggled = false;
|
||||
for (PetSpellMap::const_iterator itr = pet->m_spells.begin(); itr != pet->m_spells.end(); ++itr)
|
||||
{
|
||||
if(itr->second.state == PETSPELL_REMOVED)
|
||||
@@ -29,17 +30,29 @@ bool TogglePetSpellAutoCastAction::Execute(Event event) {
|
||||
const SpellInfo* spellInfo = sSpellMgr->GetSpellInfo(spellId);
|
||||
if (spellInfo->IsPassive())
|
||||
continue;
|
||||
|
||||
|
||||
bool shouldApply = true;
|
||||
// imp's spell, felhunte's intelligence, ghoul's leap, cat stealth
|
||||
if (spellId == 4511 || spellId == 1742 ||
|
||||
spellId == 54424 || spellId == 57564 || spellId == 57565 || spellId == 57566 || spellId == 57567 ||
|
||||
spellId == 47482 || spellId == 24450) {
|
||||
pet->ToggleAutocast(spellInfo, false);
|
||||
} else {
|
||||
pet->ToggleAutocast(spellInfo, true);
|
||||
shouldApply = false;
|
||||
}
|
||||
bool isAutoCast = false;
|
||||
for (unsigned int &m_autospell : pet->m_autospells)
|
||||
{
|
||||
if (m_autospell == spellId)
|
||||
{
|
||||
isAutoCast = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (shouldApply != isAutoCast) {
|
||||
pet->ToggleAutocast(spellInfo, shouldApply);
|
||||
toggled = true;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
return toggled;
|
||||
}
|
||||
|
||||
bool PetAttackAction::Execute(Event event)
|
||||
|
||||
@@ -19,7 +19,7 @@ bool InviteToGroupAction::Execute(Event event)
|
||||
|
||||
bool InviteToGroupAction::Invite(Player* player)
|
||||
{
|
||||
if (!player)
|
||||
if (!player || !player->IsInWorld())
|
||||
return false;
|
||||
|
||||
if (!GET_PLAYERBOT_AI(player) && !botAI->GetSecurity()->CheckLevelFor(PLAYERBOT_SECURITY_INVITE, true, player))
|
||||
|
||||
@@ -103,14 +103,13 @@ bool LfgJoinAction::JoinLFG()
|
||||
if (!dungeon || (dungeon->TypeID != LFG_TYPE_RANDOM && dungeon->TypeID != LFG_TYPE_DUNGEON && dungeon->TypeID != LFG_TYPE_HEROIC && dungeon->TypeID != LFG_TYPE_RAID))
|
||||
continue;
|
||||
|
||||
uint32 botLevel = bot->GetLevel();
|
||||
if (dungeon->MinLevel && botLevel < dungeon->MinLevel)
|
||||
continue;
|
||||
const auto& botLevel = bot->GetLevel();
|
||||
|
||||
if (dungeon->MinLevel && botLevel > dungeon->MinLevel + 10)
|
||||
continue;
|
||||
|
||||
if (dungeon->MaxLevel && botLevel > dungeon->MaxLevel)
|
||||
/*LFG_TYPE_RANDOM on classic is 15-58 so bot over level 25 will never queue*/
|
||||
if (dungeon->MinLevel && (botLevel < dungeon->MinLevel || botLevel > dungeon->MaxLevel)
|
||||
||
|
||||
(botLevel > dungeon->MinLevel + 10 && dungeon->TypeID == LFG_TYPE_DUNGEON)
|
||||
)
|
||||
continue;
|
||||
|
||||
selected.push_back(dungeon->ID);
|
||||
@@ -126,41 +125,8 @@ bool LfgJoinAction::JoinLFG()
|
||||
bool many = list.size() > 1;
|
||||
LFGDungeonEntry const* dungeon = sLFGDungeonStore.LookupEntry(*list.begin());
|
||||
|
||||
/*for (uint32 i = 0; i < sLFGDungeonStore.GetNumRows(); ++i)
|
||||
{
|
||||
LFGDungeonEntry const* dungeon = sLFGDungeonStore.LookupEntry(i);
|
||||
if (!dungeon || (dungeon->type != LFG_TYPE_RANDOM_DUNGEON && dungeon->type != LFG_TYPE_DUNGEON && dungeon->type != LFG_TYPE_HEROIC_DUNGEON &&
|
||||
dungeon->type != LFG_TYPE_RAID))
|
||||
continue;
|
||||
|
||||
uint32 botLevel = bot->GetLevel();
|
||||
if (dungeon->MinLevel && botLevel < dungeon->MinLevel)
|
||||
continue;
|
||||
|
||||
if (dungeon->MinLevel && botLevel > dungeon->MinLevel + 10)
|
||||
continue;
|
||||
|
||||
if (dungeon->MaxLevel && botLevel > dungeon->MaxLevel)
|
||||
continue;
|
||||
|
||||
if (heroic && !dungeon->difficulty)
|
||||
continue;
|
||||
|
||||
if (rbotAId && dungeon->type != LFG_TYPE_RAID)
|
||||
continue;
|
||||
|
||||
if (!random && !rbotAId && !heroic && dungeon->type != LFG_TYPE_DUNGEON)
|
||||
continue;
|
||||
|
||||
list.insert(dungeon);
|
||||
}
|
||||
|
||||
if (list.empty() && !random)
|
||||
return false;*/
|
||||
|
||||
// check role for console msg
|
||||
std::string _roles = "multiple roles";
|
||||
|
||||
uint32 roleMask = GetRoles();
|
||||
if (roleMask & PLAYER_ROLE_TANK)
|
||||
_roles = "TANK";
|
||||
@@ -175,70 +141,8 @@ bool LfgJoinAction::JoinLFG()
|
||||
bot->GetGUID().ToString().c_str(), bot->GetTeamId() == TEAM_ALLIANCE ? "A" : "H",
|
||||
bot->GetLevel(), bot->GetName().c_str(), _roles, many ? "several dungeons" : dungeon->Name[0]);
|
||||
|
||||
/*if (lfgState->IsSingleRole())
|
||||
{
|
||||
if (lfgState->HasRole(ROLE_TANK))
|
||||
_roles = "TANK";
|
||||
if (lfgState->HasRole(ROLE_HEALER))
|
||||
_roles = "HEAL";
|
||||
if (lfgState->HasRole(ROLE_DAMAGE))
|
||||
_roles = "DPS";
|
||||
}*/
|
||||
|
||||
/*LFGDungeonEntry const* dungeon;
|
||||
|
||||
if(!random)
|
||||
dungeon = *list.begin();
|
||||
|
||||
bool many = list.size() > 1;
|
||||
|
||||
if (random)
|
||||
{
|
||||
LFGDungeonSet randList = sLFGMgr->GetRandomDungeonsForPlayer(bot);
|
||||
for (LFGDungeonSet::const_iterator itr = randList.begin(); itr != randList.end(); ++itr)
|
||||
{
|
||||
LFGDungeonEntry const* dungeon = *itr;
|
||||
|
||||
if (!dungeon)
|
||||
continue;
|
||||
|
||||
idx.push_back(dungeon->ID);
|
||||
}
|
||||
if (idx.empty())
|
||||
return false;
|
||||
|
||||
// choose random dungeon
|
||||
dungeon = sLFGDungeonStore.LookupEntry(idx[urand(0, idx.size() - 1)]);
|
||||
list.insert(dungeon);
|
||||
|
||||
pState->SetType(LFG_TYPE_RANDOM_DUNGEON);
|
||||
LOG_INFO("playerbots", "Bot {} {}:{} <{}>: queues LFG, Random Dungeon as {} ({})",
|
||||
bot->GetGUID().ToString().c_str(), bot->GetTeamId() == TEAM_ALLIANCE ? "A" : "H", bot->GetLevel(), bot->GetName().c_str(), _roles, dungeon->Name[0]);
|
||||
return true;
|
||||
}
|
||||
else if (heroic)
|
||||
{
|
||||
pState->SetType(LFG_TYPE_HEROIC_DUNGEON);
|
||||
LOG_INFO("playerbots", "Bot {} {}:{} <{}>: queues LFG, Heroic Dungeon as {} ({})",
|
||||
bot->GetGUID().ToString().c_str(), bot->GetTeamId() == TEAM_ALLIANCE ? "A" : "H",
|
||||
bot->GetLevel(), bot->GetName().c_str(), _roles, many ? "several dungeons" : dungeon->Name[0]);
|
||||
}
|
||||
else if (rbotAId)
|
||||
{
|
||||
pState->SetType(LFG_TYPE_RAID);
|
||||
LOG_INFO("playerbots", "Bot {} {}:{} <{}>: queues LFG, RbotAId as {} ({})",
|
||||
bot->GetGUID().ToString().c_str(), bot->GetTeamId() == TEAM_ALLIANCE ? "A" : "H", bot->GetLevel(), bot->GetName().c_str(), _roles, many ? "several dungeons" : dungeon->Name[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
pState->SetType(LFG_TYPE_DUNGEON);
|
||||
LOG_INFO("playerbots", "Bot {} {}:{} <{}>: queues LFG, Dungeon as {} ({})",
|
||||
bot->GetGUID().ToString().c_str(), bot->GetTeamId() == TEAM_ALLIANCE ? "A" : "H", bot->GetLevel(), bot->GetName().c_str(), _roles, many ? "several dungeons" : dungeon->Name[0]);
|
||||
}*/
|
||||
|
||||
// Set RbotAId Browser comment
|
||||
std::string const _gs = std::to_string(botAI->GetEquipGearScore(bot, false, false));
|
||||
|
||||
sLFGMgr->JoinLfg(bot, roleMask, list, _gs);
|
||||
|
||||
return true;
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "PlayerbotAIConfig.h"
|
||||
#include "Playerbots.h"
|
||||
#include "ServerFacade.h"
|
||||
#include "GuildMgr.h"
|
||||
|
||||
bool LootAction::Execute(Event event)
|
||||
{
|
||||
@@ -416,6 +417,23 @@ 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());
|
||||
|
||||
@@ -859,6 +859,21 @@ void MovementAction::UpdateMovementState()
|
||||
|
||||
if (bot->IsFlying())
|
||||
bot->UpdateSpeed(MOVE_FLIGHT, true);
|
||||
|
||||
Transport* newTransport = bot->GetMap()->GetTransportForPos(bot->GetPhaseMask(), bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ(), bot);
|
||||
if (newTransport != bot->GetTransport())
|
||||
{
|
||||
LOG_DEBUG("playerbots", "Bot {} is on a transport", bot->GetName());
|
||||
|
||||
if (bot->GetTransport())
|
||||
bot->GetTransport()->RemovePassenger(bot, true);
|
||||
|
||||
if (newTransport)
|
||||
newTransport->AddPassenger(bot, true);
|
||||
|
||||
bot->StopMovingOnCurrentPos();
|
||||
}
|
||||
|
||||
// Temporary speed increase in group
|
||||
//if (botAI->HasRealPlayerMaster())
|
||||
//bot->SetSpeedRate(MOVE_RUN, 1.1f);
|
||||
@@ -1565,7 +1580,7 @@ bool AvoidAoeAction::AvoidAuraWithDynamicObj()
|
||||
return false;
|
||||
}
|
||||
std::ostringstream name;
|
||||
name << spellInfo->SpellName[sWorld->GetDefaultDbcLocale()]; // << "] (aura)";
|
||||
name << spellInfo->SpellName[LOCALE_enUS]; // << "] (aura)";
|
||||
if (FleePosition(dynOwner->GetPosition(), radius)) {
|
||||
if (sPlayerbotAIConfig->tellWhenAvoidAoe && lastTellTimer < time(NULL) - 10) {
|
||||
lastTellTimer = time(NULL);
|
||||
@@ -1605,7 +1620,7 @@ bool AvoidAoeAction::AvoidGameObjectWithDamage()
|
||||
continue;
|
||||
}
|
||||
const SpellInfo* spellInfo = sSpellMgr->GetSpellInfo(spellId);
|
||||
if (spellInfo->IsPositive()) {
|
||||
if (!spellInfo || spellInfo->IsPositive()) {
|
||||
continue;
|
||||
}
|
||||
float radius = (float)goInfo->trap.diameter / 2;
|
||||
@@ -1623,7 +1638,7 @@ bool AvoidAoeAction::AvoidGameObjectWithDamage()
|
||||
continue;
|
||||
}
|
||||
std::ostringstream name;
|
||||
name << spellInfo->SpellName[sWorld->GetDefaultDbcLocale()]; // << "] (object)";
|
||||
name << spellInfo->SpellName[LOCALE_enUS]; // << "] (object)";
|
||||
if (FleePosition(go->GetPosition(), radius)) {
|
||||
if (sPlayerbotAIConfig->tellWhenAvoidAoe && lastTellTimer < time(NULL) - 10) {
|
||||
lastTellTimer = time(NULL);
|
||||
@@ -1672,7 +1687,7 @@ bool AvoidAoeAction::AvoidUnitWithDamageAura()
|
||||
break;
|
||||
}
|
||||
std::ostringstream name;
|
||||
name << triggerSpellInfo->SpellName[sWorld->GetDefaultDbcLocale()]; //<< "] (unit)";
|
||||
name << triggerSpellInfo->SpellName[LOCALE_enUS]; //<< "] (unit)";
|
||||
if (FleePosition(unit->GetPosition(), radius)) {
|
||||
if (sPlayerbotAIConfig->tellWhenAvoidAoe && lastTellTimer < time(NULL) - 10) {
|
||||
lastTellTimer = time(NULL);
|
||||
|
||||
@@ -10,6 +10,16 @@
|
||||
#include "GuildMgr.h"
|
||||
#include <regex>
|
||||
|
||||
static const std::unordered_set<std::string> noReplyMsgs = {
|
||||
"join", "leave", "follow", "attack", "pull", "flee", "reset", "reset ai",
|
||||
"all ?", "talents", "talents list", "talents auto", "talk", "stay", "stats",
|
||||
"who", "items", "leave", "join", "repair", "summon", "nc ?", "co ?", "de ?",
|
||||
"dead ?", "follow", "los", "guard", "do accept invitation", "stats", "react ?",
|
||||
"reset strats", "home",
|
||||
};
|
||||
static const std::unordered_set<std::string> noReplyMsgParts = { "+", "-","@" , "follow target", "focus heal", "cast ", "accept [", "e [", "destroy [", "go zone" };
|
||||
static const std::unordered_set<std::string> noReplyMsgStarts = { "e ", "accept ", "cast ", "destroy " };
|
||||
|
||||
SayAction::SayAction(PlayerbotAI* botAI) : Action(botAI, "say"), Qualified()
|
||||
{
|
||||
}
|
||||
@@ -105,6 +115,9 @@ bool SayAction::isUseful()
|
||||
if (!botAI->AllowActivity())
|
||||
return false;
|
||||
|
||||
if (botAI->HasStrategy("silent", BotState::BOT_STATE_NON_COMBAT))
|
||||
return false;
|
||||
|
||||
time_t lastSaid = AI_VALUE2(time_t, "last said", qualifier);
|
||||
return (time(nullptr) - lastSaid) > 30;
|
||||
}
|
||||
@@ -114,6 +127,35 @@ void ChatReplyAction::ChatReplyDo(Player* bot, uint32 type, uint32 guid1, uint32
|
||||
ChatReplyType replyType = REPLY_NOT_UNDERSTAND; // default not understand
|
||||
std::string respondsText = "";
|
||||
|
||||
// if we're just commanding bots around, don't respond...
|
||||
// first one is for exact word matches
|
||||
if (noReplyMsgs.find(msg) != noReplyMsgs.end()) {
|
||||
/*std::ostringstream out;
|
||||
out << "DEBUG ChatReplyDo decided to ignore exact blocklist match" << msg;
|
||||
bot->Say(out.str(), LANG_UNIVERSAL);*/
|
||||
return;
|
||||
}
|
||||
|
||||
// second one is for partial matches like + or - where we change strats
|
||||
if (std::any_of(noReplyMsgParts.begin(), noReplyMsgParts.end(), [&msg](const std::string& part) { return msg.find(part) != std::string::npos; })) {
|
||||
/*std::ostringstream out;
|
||||
out << "DEBUG ChatReplyDo decided to ignore partial blocklist match" << msg;
|
||||
bot->Say(out.str(), LANG_UNIVERSAL);*/
|
||||
return;
|
||||
}
|
||||
|
||||
if (std::any_of(noReplyMsgStarts.begin(), noReplyMsgStarts.end(), [&msg](const std::string& start) {
|
||||
return msg.find(start) == 0; // Check if the start matches the beginning of msg
|
||||
})) {
|
||||
/*std::ostringstream out;
|
||||
out << "DEBUG ChatReplyDo decided to ignore start blocklist match" << msg;
|
||||
bot->Say(out.str(), LANG_UNIVERSAL);*/
|
||||
return;
|
||||
}
|
||||
|
||||
ObjectGuid receiver = sCharacterCache->GetCharacterGuidByName(name);
|
||||
Player* plr = ObjectAccessor::FindPlayer(receiver);
|
||||
|
||||
// Chat Logic
|
||||
int32 verb_pos = -1;
|
||||
int32 verb_type = -1;
|
||||
@@ -149,18 +191,16 @@ void ChatReplyAction::ChatReplyDo(Player* bot, uint32 type, uint32 guid1, uint32
|
||||
// Responds
|
||||
for (uint32 i = 0; i < 8; i++)
|
||||
{
|
||||
// // blame gm with chat tag
|
||||
// if (Player* plr = sObjectMgr->GetPlayer(ObjectGuid(HIGHGUID_PLAYER, guid1)))
|
||||
// {
|
||||
// if (plr->isGMChat())
|
||||
// {
|
||||
// replyType = REPLY_ADMIN_ABUSE;
|
||||
// found = true;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
if (word[i] == "hi" || word[i] == "hey" || word[i] == "hello" || word[i] == "wazzup")
|
||||
// blame gm with chat tag
|
||||
if (plr && plr->isGMChat())
|
||||
{
|
||||
replyType = REPLY_ADMIN_ABUSE;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (word[i] == "hi" || word[i] == "hey" || word[i] == "hello" || word[i] == "wazzup"
|
||||
|| word[i] == "salut" || word[i] == "plop" || word[i] == "yo")
|
||||
{
|
||||
replyType = REPLY_HELLO;
|
||||
found = true;
|
||||
@@ -169,22 +209,25 @@ void ChatReplyAction::ChatReplyDo(Player* bot, uint32 type, uint32 guid1, uint32
|
||||
|
||||
if (verb_type < 4)
|
||||
{
|
||||
if (word[i] == "am" || word[i] == "are" || word[i] == "is")
|
||||
if (word[i] == "am" || word[i] == "are" || word[i] == "is" || word[i] == "suis" || word[i] == "as" || word[i] == "est"
|
||||
|| word[i] == "dois" || word[i] == "doit")
|
||||
{
|
||||
verb_pos = i;
|
||||
verb_type = 2; // present
|
||||
if (verb_pos == 0)
|
||||
is_quest = 1;
|
||||
}
|
||||
else if (word[i] == "will")
|
||||
else if (word[i] == "will" || word[i] == "vais" || word[i] == "sera")
|
||||
{
|
||||
verb_pos = i;
|
||||
verb_type = 3; // future
|
||||
}
|
||||
else if (word[i] == "was" || word[i] == "were")
|
||||
else if (word[i] == "was" || word[i] == "were" || word[i] == "été" || word[i] == "ai" || word[i] == "eu" || word[i] == "étions" || word[i] == "etion" )
|
||||
{
|
||||
verb_pos = i;
|
||||
verb_type = 1; // past
|
||||
}
|
||||
else if (word[i] == "shut" || word[i] == "noob")
|
||||
else if (word[i] == "shut" || word[i] == "noob" || word[i] == "tg")
|
||||
{
|
||||
if (msg.find(bot->GetName()) == std::string::npos)
|
||||
{
|
||||
@@ -600,22 +643,20 @@ void ChatReplyAction::ChatReplyDo(Player* bot, uint32 type, uint32 guid1, uint32
|
||||
{
|
||||
if (type == CHAT_MSG_WHISPER)
|
||||
{
|
||||
ObjectGuid receiver = sCharacterCache->GetCharacterGuidByName(name);
|
||||
if (!receiver || !receiver.IsPlayer() || !ObjectAccessor::FindPlayer(receiver))
|
||||
if (plr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (bot->GetTeamId() == TEAM_ALLIANCE)
|
||||
{
|
||||
bot->Whisper(c, LANG_COMMON, ObjectAccessor::FindPlayer(receiver));
|
||||
}
|
||||
else
|
||||
{
|
||||
bot->Whisper(c, LANG_ORCISH, ObjectAccessor::FindPlayer(receiver));
|
||||
if (bot->GetTeamId() == TEAM_ALLIANCE)
|
||||
{
|
||||
bot->Whisper(c, LANG_COMMON, plr);
|
||||
}
|
||||
else
|
||||
{
|
||||
bot->Whisper(c, LANG_ORCISH, plr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (type == CHAT_MSG_SAY)
|
||||
else if (type == CHAT_MSG_SAY)
|
||||
{
|
||||
if (bot->GetTeamId() == TEAM_ALLIANCE)
|
||||
bot->Say(respondsText, LANG_COMMON);
|
||||
@@ -623,7 +664,7 @@ void ChatReplyAction::ChatReplyDo(Player* bot, uint32 type, uint32 guid1, uint32
|
||||
bot->Say(respondsText, LANG_ORCISH);
|
||||
}
|
||||
|
||||
if (type == CHAT_MSG_YELL)
|
||||
else if (type == CHAT_MSG_YELL)
|
||||
{
|
||||
if (bot->GetTeamId() == TEAM_ALLIANCE)
|
||||
bot->Yell(respondsText, LANG_COMMON);
|
||||
@@ -631,9 +672,9 @@ void ChatReplyAction::ChatReplyDo(Player* bot, uint32 type, uint32 guid1, uint32
|
||||
bot->Yell(respondsText, LANG_ORCISH);
|
||||
}
|
||||
|
||||
if (type == CHAT_MSG_GUILD)
|
||||
else if (type == CHAT_MSG_GUILD)
|
||||
{
|
||||
if (!bot->GetGuildId())
|
||||
if (!bot->GetGuildId() || !sPlayerbotAIConfig->randomBotGuildTalk)
|
||||
return;
|
||||
|
||||
Guild* guild = sGuildMgr->GetGuildById(bot->GetGuildId());
|
||||
@@ -645,4 +686,4 @@ void ChatReplyAction::ChatReplyDo(Player* bot, uint32 type, uint32 guid1, uint32
|
||||
}
|
||||
GET_PLAYERBOT_AI(bot)->GetAiObjectContext()->GetValue<time_t>("last said", "chat")->Set(time(nullptr) + urand(5, 25));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ bool SellAction::Execute(Event event)
|
||||
return true;
|
||||
}
|
||||
|
||||
if (text == "all")
|
||||
if (text != "")
|
||||
{
|
||||
std::vector<Item *> items = parseItems(text, ITERATE_ITEMS_IN_BAGS);
|
||||
for (Item *item : items)
|
||||
@@ -84,7 +84,7 @@ bool SellAction::Execute(Event event)
|
||||
return true;
|
||||
}
|
||||
|
||||
botAI->TellError("Usage: s gray/*/vendor/all");
|
||||
botAI->TellError("Usage: s gray/*/vendor/[item link]");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
*/
|
||||
|
||||
#include "SuggestWhatToDoAction.h"
|
||||
#include "ServerFacade.h"
|
||||
#include "ChannelMgr.h"
|
||||
#include "Event.h"
|
||||
#include "ItemVisitors.h"
|
||||
@@ -11,24 +12,47 @@
|
||||
#include "Playerbots.h"
|
||||
#include "PlayerbotTextMgr.h"
|
||||
#include "GuildMgr.h"
|
||||
#include "Config.h"
|
||||
|
||||
std::map<std::string, uint8> SuggestWhatToDoAction::instances;
|
||||
#include <functional>
|
||||
|
||||
enum eTalkType
|
||||
{
|
||||
/*0x18*/ General = ChannelFlags::CHANNEL_FLAG_GENERAL | ChannelFlags::CHANNEL_FLAG_NOT_LFG,
|
||||
/*0x3C*/ Trade = ChannelFlags::CHANNEL_FLAG_CITY | ChannelFlags::CHANNEL_FLAG_GENERAL | ChannelFlags::CHANNEL_FLAG_NOT_LFG | ChannelFlags::CHANNEL_FLAG_TRADE,
|
||||
/*0x18*/ LocalDefence = ChannelFlags::CHANNEL_FLAG_GENERAL | ChannelFlags::CHANNEL_FLAG_NOT_LFG,
|
||||
/*x038*/ GuildRecruitment = ChannelFlags::CHANNEL_FLAG_CITY | ChannelFlags::CHANNEL_FLAG_GENERAL | ChannelFlags::CHANNEL_FLAG_NOT_LFG,
|
||||
/*0x50*/ LookingForGroup = ChannelFlags::CHANNEL_FLAG_LFG | ChannelFlags::CHANNEL_FLAG_GENERAL
|
||||
};
|
||||
|
||||
std::map<std::string, uint8> SuggestDungeonAction::instances;
|
||||
std::map<std::string, uint8> SuggestWhatToDoAction::factions;
|
||||
|
||||
SuggestWhatToDoAction::SuggestWhatToDoAction(PlayerbotAI* botAI, std::string const name) : InventoryAction(botAI, name)
|
||||
SuggestWhatToDoAction::SuggestWhatToDoAction(PlayerbotAI* botAI, std::string const name)
|
||||
: InventoryAction{ botAI, name }
|
||||
, _dbc_locale{ sWorld->GetDefaultDbcLocale() }
|
||||
{
|
||||
suggestions.push_back(&SuggestWhatToDoAction::specificQuest);
|
||||
suggestions.push_back(&SuggestWhatToDoAction::grindReputation);
|
||||
suggestions.push_back(&SuggestWhatToDoAction::something);
|
||||
suggestions.push_back(std::bind(&SuggestWhatToDoAction::specificQuest, this));
|
||||
suggestions.push_back(std::bind(&SuggestWhatToDoAction::grindReputation, this));
|
||||
suggestions.push_back(std::bind(&SuggestWhatToDoAction::something, this));
|
||||
suggestions.push_back(std::bind(&SuggestWhatToDoAction::grindMaterials, this));
|
||||
}
|
||||
|
||||
bool SuggestWhatToDoAction::Execute(Event event)
|
||||
bool SuggestWhatToDoAction::isUseful()
|
||||
{
|
||||
if (!sRandomPlayerbotMgr->IsRandomBot(bot) || bot->GetGroup() || bot->GetInstanceId())
|
||||
return false;
|
||||
|
||||
std::string qualifier = "suggest what to do";
|
||||
time_t lastSaid = AI_VALUE2(time_t, "last said", qualifier);
|
||||
return (time(0) - lastSaid) > 30;
|
||||
}
|
||||
|
||||
bool SuggestWhatToDoAction::Execute(Event event)
|
||||
{
|
||||
uint32 index = rand() % suggestions.size();
|
||||
(this->*suggestions[index])();
|
||||
auto fnct_ptr = suggestions[index];
|
||||
fnct_ptr();
|
||||
|
||||
std::string const qualifier = "suggest what to do";
|
||||
time_t lastSaid = AI_VALUE2(time_t, "last said", qualifier);
|
||||
@@ -37,73 +61,6 @@ bool SuggestWhatToDoAction::Execute(Event event)
|
||||
return true;
|
||||
}
|
||||
|
||||
void SuggestWhatToDoAction::instance()
|
||||
{
|
||||
if (instances.empty())
|
||||
{
|
||||
instances["Ragefire Chasm"] = 15;
|
||||
instances["Deadmines"] = 18;
|
||||
instances["Wailing Caverns"] = 18;
|
||||
instances["Shadowfang Keep"] = 25;
|
||||
instances["Blackfathom Deeps"] = 20;
|
||||
instances["Stockade"] = 20;
|
||||
instances["Gnomeregan"] = 35;
|
||||
instances["Razorfen Kraul"] = 35;
|
||||
instances["Maraudon"] = 50;
|
||||
instances["Scarlet Monestery"] = 40;
|
||||
instances["Uldaman"] = 45;
|
||||
instances["Dire Maul"] = 58;
|
||||
instances["Scholomance"] = 59;
|
||||
instances["Razorfen Downs"] = 40;
|
||||
instances["Strathholme"] = 59;
|
||||
instances["Zul'Farrak"] = 45;
|
||||
instances["Blackrock Depths"] = 55;
|
||||
instances["Temple of Atal'Hakkar"] = 55;
|
||||
instances["Lower Blackrock Spire"] = 57;
|
||||
|
||||
instances["Hellfire Citidel"] = 65;
|
||||
instances["Coilfang Reservoir"] = 65;
|
||||
instances["Auchindoun"] = 65;
|
||||
instances["Cavens of Time"] = 68;
|
||||
instances["Tempest Keep"] = 69;
|
||||
instances["Magister's Terrace"] = 70;
|
||||
|
||||
instances["Utgarde Keep"] = 75;
|
||||
instances["The Nexus"] = 75;
|
||||
instances["Ahn'kahet: The Old Kingdom"] = 75;
|
||||
instances["Azjol-Nerub"] = 75;
|
||||
instances["Drak'Tharon Keep"] = 75;
|
||||
instances["Violet Hold"] = 80;
|
||||
instances["Gundrak"] = 77;
|
||||
instances["Halls of Stone"] = 77;
|
||||
instances["Halls of Lightning"] = 77;
|
||||
instances["Oculus"] = 77;
|
||||
instances["Utgarde Pinnacle"] = 77;
|
||||
instances["Trial of the Champion"] = 80;
|
||||
instances["Forge of Souls"] = 80;
|
||||
instances["Pit of Saron"] = 80;
|
||||
instances["Halls of Reflection"] = 80;
|
||||
}
|
||||
|
||||
std::vector<std::string> allowedInstances;
|
||||
for (auto & instance : instances)
|
||||
{
|
||||
if (bot->GetLevel() >= instance.second) allowedInstances.push_back(instance.first);
|
||||
}
|
||||
|
||||
if (allowedInstances.empty()) return;
|
||||
|
||||
std::map<std::string, std::string> placeholders;
|
||||
placeholders["%role"] = ChatHelper::FormatClass(bot, AiFactory::GetPlayerSpecTab(bot));
|
||||
|
||||
std::ostringstream itemout;
|
||||
//itemout << "|c00b000b0" << allowedInstances[urand(0, allowedInstances.size() - 1)] << "|r";
|
||||
itemout << allowedInstances[urand(0, allowedInstances.size() - 1)];
|
||||
placeholders["%instance"] = itemout.str();
|
||||
|
||||
spam(BOT_TEXT2("suggest_instance", placeholders), urand(0, 1) ? 0x50 : 0, urand(0, 2), urand(0, 2));
|
||||
}
|
||||
|
||||
std::vector<uint32> SuggestWhatToDoAction::GetIncompletedQuests()
|
||||
{
|
||||
std::vector<uint32> result;
|
||||
@@ -136,7 +93,52 @@ void SuggestWhatToDoAction::specificQuest()
|
||||
placeholders["%role"] = chat->FormatClass(bot, AiFactory::GetPlayerSpecTab(bot));
|
||||
placeholders["%quest"] = chat->FormatQuest(quest);
|
||||
|
||||
spam(BOT_TEXT2("suggest_quest", placeholders), urand(0, 1) ? 0x18 : 0, urand(0, 2), urand(0, 2));
|
||||
spam(BOT_TEXT2("suggest_quest", placeholders), urand(0, 1) ? eTalkType::General : 0, !urand(0, 2), !urand(0, 3));
|
||||
}
|
||||
|
||||
void SuggestWhatToDoAction::grindMaterials()
|
||||
{
|
||||
/*if (bot->GetLevel() <= 5)
|
||||
return;
|
||||
|
||||
auto result = CharacterDatabase.Query("SELECT distinct category, multiplier FROM ahbot_category where category not in ('other', 'quest', 'trade', 'reagent') and multiplier > 3 order by multiplier desc limit 10");
|
||||
if (!result)
|
||||
return;
|
||||
|
||||
std::map<std::string, double> categories;
|
||||
do
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
categories[fields[0].Get<std::string>()] = fields[1].Get<float>();
|
||||
} while (result->NextRow());
|
||||
|
||||
for (std::map<std::string, double>::iterator i = categories.begin(); i != categories.end(); ++i)
|
||||
{
|
||||
if (urand(0, 10) < 3) {
|
||||
std::string name = i->first;
|
||||
double multiplier = i->second;
|
||||
|
||||
for (int j = 0; j < ahbot::CategoryList::instance.size(); j++)
|
||||
{
|
||||
ahbot::Category* category = ahbot::CategoryList::instance[j];
|
||||
if (name == category->GetName())
|
||||
{
|
||||
std::string item = category->GetLabel();
|
||||
transform(item.begin(), item.end(), item.begin(), ::tolower);
|
||||
std::ostringstream itemout;
|
||||
itemout << "|c0000b000" << item << "|r";
|
||||
item = itemout.str();
|
||||
|
||||
std::map<std::string, std::string> placeholders;
|
||||
placeholders["%role"] = chat->formatClass(bot, AiFactory::GetPlayerSpecTab(bot));
|
||||
placeholders["%category"] = item;
|
||||
|
||||
spam(BOT_TEXT2("suggest_trade", placeholders), urand(0, 1) ? 0x3C : 0x18, !urand(0, 2), !urand(0, 3));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
void SuggestWhatToDoAction::grindReputation()
|
||||
@@ -185,12 +187,11 @@ void SuggestWhatToDoAction::grindReputation()
|
||||
levels.push_back("exalted");
|
||||
|
||||
std::vector<std::string> allowedFactions;
|
||||
for (std::map<std::string, uint8>::iterator i = factions.begin(); i != factions.end(); ++i)
|
||||
for (const auto& i : factions)
|
||||
{
|
||||
if (bot->GetLevel() >= i->second)
|
||||
allowedFactions.push_back(i->first);
|
||||
if (bot->GetLevel() >= i.second)
|
||||
allowedFactions.push_back(i.first);
|
||||
}
|
||||
|
||||
if (allowedFactions.empty())
|
||||
return;
|
||||
|
||||
@@ -207,7 +208,7 @@ void SuggestWhatToDoAction::grindReputation()
|
||||
itemout << allowedFactions[urand(0, allowedFactions.size() - 1)];
|
||||
placeholders["%faction"] = itemout.str();
|
||||
|
||||
spam(BOT_TEXT2("suggest_faction", placeholders), 0x18, true);
|
||||
spam(BOT_TEXT2("suggest_faction", placeholders), eTalkType::General, true);
|
||||
}
|
||||
|
||||
void SuggestWhatToDoAction::something()
|
||||
@@ -221,10 +222,10 @@ void SuggestWhatToDoAction::something()
|
||||
|
||||
std::ostringstream out;
|
||||
// out << "|cffb04040" << entry->area_name[0] << "|r";
|
||||
out << entry->area_name[0];
|
||||
out << entry->area_name[_dbc_locale];
|
||||
placeholders["%zone"] = out.str();
|
||||
|
||||
spam(BOT_TEXT2("suggest_something", placeholders), urand(0, 1) ? 0x18 : 0, urand(0, 2), urand(0, 2));
|
||||
spam(BOT_TEXT2("suggest_something", placeholders), urand(0, 1) ? eTalkType::General : 0, !urand(0, 2), !urand(0, 3));
|
||||
}
|
||||
|
||||
void SuggestWhatToDoAction::spam(std::string msg, uint8 flags, bool worldChat, bool guild)
|
||||
@@ -237,58 +238,65 @@ void SuggestWhatToDoAction::spam(std::string msg, uint8 flags, bool worldChat, b
|
||||
if (!cMgr)
|
||||
return;
|
||||
|
||||
AreaTableEntry const* zone = sAreaTableStore.LookupEntry(bot->GetMap()->GetZoneId(bot->GetPhaseMask(), bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ()));
|
||||
if (!zone) return;
|
||||
/*AreaTableEntry const* area = sAreaTableStore.LookupEntry(bot->GetMap()->GetAreaId(bot->GetPhaseMask(), bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ()));
|
||||
if (!area) return;*/
|
||||
|
||||
for (uint32 i = 0; i < sChatChannelsStore.GetNumRows(); ++i)
|
||||
{
|
||||
ChatChannelsEntry const* channel = sChatChannelsStore.LookupEntry(i);
|
||||
if (!channel) continue;
|
||||
|
||||
for (AreaTableEntry const* current_zone : sAreaTableStore)
|
||||
// combine full channel name
|
||||
char channelName[100];
|
||||
Channel* chn = nullptr;
|
||||
if (channel->ChannelID == 24 || (channel->flags & CHANNEL_DBC_FLAG_LFG) != 0)
|
||||
{
|
||||
if (!current_zone)
|
||||
continue;
|
||||
std::string chanName = channel->pattern[_dbc_locale];
|
||||
chn = cMgr->GetChannel(chanName, bot);
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(channelName, 100, channel->pattern[_dbc_locale], zone->area_name[_dbc_locale]);
|
||||
chn = cMgr->GetChannel(channelName, bot);
|
||||
}
|
||||
if (!chn)
|
||||
continue;
|
||||
|
||||
// skip world chat here
|
||||
if (chn->GetName() == "World")
|
||||
continue;
|
||||
|
||||
// combine full channel name
|
||||
char channelName[100];
|
||||
Channel* chn = nullptr;
|
||||
if ((channel->flags & CHANNEL_DBC_FLAG_LFG) != 0)
|
||||
{
|
||||
std::string chanName = channel->pattern[0];
|
||||
chn = cMgr->GetChannel(chanName, bot);
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(channelName, 100, channel->pattern[0], current_zone->area_name[0]);
|
||||
chn = cMgr->GetChannel(channelName, bot);
|
||||
}
|
||||
if (!chn)
|
||||
continue;
|
||||
// skip world chat here
|
||||
if (chn->GetName() == "World")
|
||||
continue;
|
||||
if (flags != 0 && chn->GetFlags() != flags)
|
||||
continue;
|
||||
|
||||
if (flags != 0 && chn->GetFlags() != flags)
|
||||
continue;
|
||||
// skip local defense and universal defense
|
||||
if (chn->GetChannelId() == 22 || chn->GetChannelId() == 23)
|
||||
continue;
|
||||
|
||||
// skip local defense
|
||||
//if (chn->GetFlags() == 0x18)
|
||||
// continue;
|
||||
|
||||
// no filter, pick several options
|
||||
if (flags == CHANNEL_FLAG_NONE)
|
||||
{
|
||||
channelNames.push_back(chn->GetName());
|
||||
}
|
||||
else
|
||||
chn->Say(bot->GetGUID(), msg.c_str(), LANG_UNIVERSAL);
|
||||
// no filter, pick several options
|
||||
if (flags == CHANNEL_FLAG_NONE)
|
||||
{
|
||||
channelNames.push_back(chn->GetName());
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!bot->IsInChannel(chn))
|
||||
chn->JoinChannel(bot, "");
|
||||
chn->Say(bot->GetGUID(), msg.c_str(), LANG_UNIVERSAL);
|
||||
}
|
||||
|
||||
if (!channelNames.empty())
|
||||
{
|
||||
std::string randomName = channelNames[urand(0, channelNames.size() - 1)];
|
||||
if (Channel* chn = cMgr->GetChannel(randomName, bot))
|
||||
{
|
||||
if (!bot->IsInChannel(chn))
|
||||
chn->JoinChannel(bot, "");
|
||||
|
||||
chn->Say(bot->GetGUID(), msg.c_str(), LANG_UNIVERSAL);
|
||||
}
|
||||
}
|
||||
|
||||
if (worldChat)
|
||||
@@ -296,13 +304,13 @@ void SuggestWhatToDoAction::spam(std::string msg, uint8 flags, bool worldChat, b
|
||||
if (Channel* worldChannel = cMgr->GetChannel("World", bot))
|
||||
worldChannel->Say(bot->GetGUID(), msg.c_str(), LANG_UNIVERSAL);
|
||||
}
|
||||
}
|
||||
|
||||
if (guild && bot->GetGuildId())
|
||||
{
|
||||
Guild* guild = sGuildMgr->GetGuildById(bot->GetGuildId());
|
||||
if (guild)
|
||||
guild->BroadcastToGuild(bot->GetSession(), false, msg.c_str(), LANG_UNIVERSAL);
|
||||
}
|
||||
if (sPlayerbotAIConfig->randomBotGuildTalk && guild && bot->GetGuildId())
|
||||
{
|
||||
Guild* guild = sGuildMgr->GetGuildById(bot->GetGuildId());
|
||||
if (guild)
|
||||
guild->BroadcastToGuild(bot->GetSession(), false, msg.c_str(), LANG_UNIVERSAL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -337,15 +345,88 @@ class FindTradeItemsVisitor : public IterateItemsVisitor
|
||||
uint32 quality;
|
||||
};
|
||||
|
||||
SuggestDungeonAction::SuggestDungeonAction(PlayerbotAI* botAI) : SuggestWhatToDoAction(botAI, "suggest dungeon")
|
||||
{
|
||||
}
|
||||
|
||||
bool SuggestDungeonAction::Execute(Event event)
|
||||
{
|
||||
// TODO: use sPlayerbotDungeonSuggestionMgr
|
||||
|
||||
if (!sPlayerbotAIConfig->randomBotSuggestDungeons || bot->GetGroup()) return false;
|
||||
|
||||
if (instances.empty())
|
||||
{
|
||||
instances["Ragefire Chasm"] = 15;
|
||||
instances["Deadmines"] = 18;
|
||||
instances["Wailing Caverns"] = 18;
|
||||
instances["Shadowfang Keep"] = 25;
|
||||
instances["Blackfathom Deeps"] = 20;
|
||||
instances["Stockade"] = 20;
|
||||
instances["Gnomeregan"] = 35;
|
||||
instances["Razorfen Kraul"] = 35;
|
||||
instances["Maraudon"] = 50;
|
||||
instances["Scarlet Monestery"] = 40;
|
||||
instances["Uldaman"] = 45;
|
||||
instances["Dire Maul"] = 58;
|
||||
instances["Scholomance"] = 59;
|
||||
instances["Razorfen Downs"] = 40;
|
||||
instances["Strathholme"] = 59;
|
||||
instances["Zul'Farrak"] = 45;
|
||||
instances["Blackrock Depths"] = 55;
|
||||
instances["Temple of Atal'Hakkar"] = 55;
|
||||
instances["Lower Blackrock Spire"] = 57;
|
||||
|
||||
instances["Hellfire Citidel"] = 65;
|
||||
instances["Coilfang Reservoir"] = 65;
|
||||
instances["Auchindoun"] = 65;
|
||||
instances["Cavens of Time"] = 68;
|
||||
instances["Tempest Keep"] = 69;
|
||||
instances["Magister's Terrace"] = 70;
|
||||
|
||||
instances["Utgarde Keep"] = 75;
|
||||
instances["The Nexus"] = 75;
|
||||
instances["Ahn'kahet: The Old Kingdom"] = 75;
|
||||
instances["Azjol-Nerub"] = 75;
|
||||
instances["Drak'Tharon Keep"] = 75;
|
||||
instances["Violet Hold"] = 80;
|
||||
instances["Gundrak"] = 77;
|
||||
instances["Halls of Stone"] = 77;
|
||||
instances["Halls of Lightning"] = 77;
|
||||
instances["Oculus"] = 77;
|
||||
instances["Utgarde Pinnacle"] = 77;
|
||||
instances["Trial of the Champion"] = 80;
|
||||
instances["Forge of Souls"] = 80;
|
||||
instances["Pit of Saron"] = 80;
|
||||
instances["Halls of Reflection"] = 80;
|
||||
}
|
||||
|
||||
std::vector<std::string> allowedInstances;
|
||||
for (const auto& instance : instances)
|
||||
{
|
||||
if (bot->GetLevel() >= instance.second)
|
||||
allowedInstances.push_back(instance.first);
|
||||
}
|
||||
if (allowedInstances.empty()) return false;
|
||||
|
||||
std::map<std::string, std::string> placeholders;
|
||||
placeholders["%role"] = ChatHelper::FormatClass(bot, AiFactory::GetPlayerSpecTab(bot));
|
||||
|
||||
std::ostringstream itemout;
|
||||
//itemout << "|c00b000b0" << allowedInstances[urand(0, allowedInstances.size() - 1)] << "|r";
|
||||
itemout << allowedInstances[urand(0, allowedInstances.size() - 1)];
|
||||
placeholders["%instance"] = itemout.str();
|
||||
|
||||
spam(BOT_TEXT2("suggest_instance", placeholders), urand(0, 1) ? eTalkType::LookingForGroup : 0, !urand(0, 2), !urand(0, 3));
|
||||
return true;
|
||||
}
|
||||
|
||||
SuggestTradeAction::SuggestTradeAction(PlayerbotAI* botAI) : SuggestWhatToDoAction(botAI, "suggest trade")
|
||||
{
|
||||
}
|
||||
|
||||
bool SuggestTradeAction::Execute(Event event)
|
||||
{
|
||||
if (!sRandomPlayerbotMgr->IsRandomBot(bot) || bot->GetGroup() || bot->GetInstanceId())
|
||||
return false;
|
||||
|
||||
uint32 quality = urand(0, 100);
|
||||
if (quality > 95)
|
||||
quality = ITEM_QUALITY_LEGENDARY;
|
||||
@@ -400,13 +481,7 @@ bool SuggestTradeAction::Execute(Event event)
|
||||
placeholders["%item"] = chat->FormatItem(proto, count);
|
||||
placeholders["%gold"] = chat->formatMoney(price);
|
||||
|
||||
spam(BOT_TEXT2("suggest_sell", placeholders), urand(0, 1) ? 0x3C : 0, urand(0, 1), urand(0, 5));
|
||||
|
||||
spam(BOT_TEXT2("suggest_sell", placeholders), urand(0, 1) ? eTalkType::Trade : 0, !urand(0, 2), urand(0, 5));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SuggestWhatToDoAction::isUseful()
|
||||
{
|
||||
std::string const qualifier = "suggest what to do";
|
||||
time_t lastSaid = AI_VALUE2(time_t, "last said", qualifier);
|
||||
return (time(nullptr) - lastSaid) > 30;
|
||||
}
|
||||
|
||||
@@ -18,19 +18,19 @@ class SuggestWhatToDoAction : public InventoryAction
|
||||
bool isUseful() override;
|
||||
|
||||
protected:
|
||||
typedef void (SuggestWhatToDoAction::*Suggestion)();
|
||||
using Suggestion = std::function<void()>;
|
||||
std::vector<Suggestion> suggestions;
|
||||
void instance();
|
||||
void specificQuest();
|
||||
void grindReputation();
|
||||
void grindMaterials();
|
||||
void something();
|
||||
void spam(std::string msg, uint8 flags = 0, bool worldChat = false, bool guild = false);
|
||||
|
||||
std::vector<uint32> GetIncompletedQuests();
|
||||
|
||||
private:
|
||||
static std::map<std::string, uint8> instances;
|
||||
static std::map<std::string, uint8> factions;
|
||||
const int32_t _dbc_locale;
|
||||
};
|
||||
|
||||
class SuggestTradeAction : public SuggestWhatToDoAction
|
||||
@@ -42,4 +42,15 @@ class SuggestTradeAction : public SuggestWhatToDoAction
|
||||
bool isUseful() override { return true; }
|
||||
};
|
||||
|
||||
class SuggestDungeonAction : public SuggestWhatToDoAction
|
||||
{
|
||||
public:
|
||||
SuggestDungeonAction(PlayerbotAI* botAI);
|
||||
|
||||
bool Execute(Event event) override;
|
||||
bool isUseful() override { return true; }
|
||||
private:
|
||||
static std::map<std::string, uint8> instances;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "Event.h"
|
||||
#include "ChatHelper.h"
|
||||
#include "Playerbots.h"
|
||||
#include "World.h"
|
||||
|
||||
bool TellLosAction::Execute(Event event)
|
||||
{
|
||||
@@ -52,7 +53,7 @@ void TellLosAction::ListUnits(std::string const title, GuidVector units)
|
||||
for (ObjectGuid const guid : units)
|
||||
{
|
||||
if (Unit* unit = botAI->GetUnit(guid)) {
|
||||
botAI->TellMaster(unit->GetName());
|
||||
botAI->TellMaster(unit->GetNameForLocaleIdx(sWorld->GetDefaultDbcLocale()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,4 +138,4 @@ bool TellExpectedDpsAction::Execute(Event event)
|
||||
float dps = AI_VALUE(float, "expected group dps");
|
||||
botAI->TellMaster("Expected Group DPS: " + std::to_string(dps));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -172,6 +172,7 @@ bool MaintenanceAction::Execute(Event event)
|
||||
factory.ApplyEnchantAndGemsNew();
|
||||
}
|
||||
bot->DurabilityRepairAll(false, 1.0f, false);
|
||||
bot->SendTalentsInfoData(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -181,6 +182,7 @@ bool RemoveGlyphAction::Execute(Event event)
|
||||
{
|
||||
bot->SetGlyph(slotIndex, 0, true);
|
||||
}
|
||||
bot->SendTalentsInfoData(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -164,15 +164,15 @@ bool SummonAction::SummonUsingNpcs(Player* summoner, Player* player)
|
||||
bool SummonAction::Teleport(Player* summoner, Player* player)
|
||||
{
|
||||
Player* master = GetMaster();
|
||||
if (master->GetMap() && master->GetMap()->IsDungeon()) {
|
||||
InstanceMap* map = master->GetMap()->ToInstanceMap();
|
||||
if (map) {
|
||||
if (map->CannotEnter(player) == Map::CANNOT_ENTER_MAX_PLAYERS) {
|
||||
botAI->TellError("I can not enter this dungeon");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
// if (master->GetMap() && master->GetMap()->IsDungeon()) {
|
||||
// InstanceMap* map = master->GetMap()->ToInstanceMap();
|
||||
// if (map) {
|
||||
// if (map->CannotEnter(player, true) == Map::CANNOT_ENTER_MAX_PLAYERS) {
|
||||
// botAI->TellError("I can not enter this dungeon");
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
if (!summoner->IsBeingTeleported() && !player->IsBeingTeleported())
|
||||
{
|
||||
float followAngle = GetFollowAngle();
|
||||
@@ -206,7 +206,8 @@ bool SummonAction::Teleport(Player* summoner, Player* player)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (bot->isDead() && sPlayerbotAIConfig->reviveBotWhenSummoned)
|
||||
bool revive = sPlayerbotAIConfig->reviveBotWhenSummoned == 2 || (sPlayerbotAIConfig->reviveBotWhenSummoned == 1 && !master->IsInCombat() && master->IsAlive());
|
||||
if (bot->isDead() && revive)
|
||||
{
|
||||
bot->ResurrectPlayer(1.0f, false);
|
||||
botAI->TellMasterNoFacing("I live, again!");
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "Event.h"
|
||||
#include "PlayerbotAIConfig.h"
|
||||
#include "Playerbots.h"
|
||||
#include "GuildMgr.h"
|
||||
|
||||
bool XpGainAction::Execute(Event event)
|
||||
{
|
||||
@@ -32,6 +33,26 @@ bool XpGainAction::Execute(Event event)
|
||||
p >> groupBonus; // 8 group bonus
|
||||
}
|
||||
|
||||
if (sPlayerbotAIConfig->randomBotGuildTalk && bot->GetGuildId() && urand(0, 10))
|
||||
{
|
||||
Creature* creature = botAI->GetCreature(guid);
|
||||
if (creature && (creature->isElite() || creature->isWorldBoss() || creature->GetLevel() > 61 || creature->GetLevel() > bot->GetLevel() + 4))
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Unit* victim = nullptr;
|
||||
if (guid)
|
||||
victim = botAI->GetUnit(guid);
|
||||
|
||||
@@ -72,12 +72,12 @@ UnholyDKStrategy::UnholyDKStrategy(PlayerbotAI* botAI) : GenericDKStrategy(botAI
|
||||
NextAction** UnholyDKStrategy::getDefaultActions()
|
||||
{
|
||||
return NextAction::array(0,
|
||||
new NextAction("death and decay", ACTION_DEFAULT + 1.0f),
|
||||
new NextAction("scourge strike", ACTION_DEFAULT + 0.8f),
|
||||
new NextAction("horn of winter", ACTION_DEFAULT + 0.6f),
|
||||
new NextAction("summon gargoyle", ACTION_DEFAULT + 0.4f),
|
||||
new NextAction("death and decay", ACTION_DEFAULT + 0.5f),
|
||||
new NextAction("horn of winter", ACTION_DEFAULT + 0.4f),
|
||||
new NextAction("summon gargoyle", ACTION_DEFAULT + 0.3f),
|
||||
new NextAction("death coil", ACTION_DEFAULT + 0.2f),
|
||||
new NextAction("melee", ACTION_DEFAULT),
|
||||
new NextAction("scourge strike", ACTION_NORMAL + 0.1f),
|
||||
new NextAction("melee", ACTION_DEFAULT),
|
||||
nullptr);
|
||||
}
|
||||
|
||||
@@ -91,8 +91,8 @@ void UnholyDKStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
triggers.push_back(new TriggerNode("no desolation", NextAction::array(0, new NextAction("blood strike", ACTION_HIGH + 4), nullptr)));
|
||||
triggers.push_back(new TriggerNode("death and decay cooldown",
|
||||
NextAction::array(0,
|
||||
new NextAction("ghoul frenzy", ACTION_DEFAULT + 5.0f),
|
||||
new NextAction("scourge strike", ACTION_DEFAULT + 4.0f),
|
||||
new NextAction("ghoul frenzy", ACTION_NORMAL + 5.0f),
|
||||
new NextAction("scourge strike", ACTION_NORMAL + 4.0f),
|
||||
new NextAction("blood boil", ACTION_NORMAL + 3.0f),
|
||||
new NextAction("icy touch", ACTION_NORMAL + 2.0f),
|
||||
new NextAction("plague strike", ACTION_NORMAL + 1.0f),
|
||||
|
||||
@@ -7,22 +7,24 @@
|
||||
|
||||
void EmoteStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(new TriggerNode("seldom", NextAction::array(0, new NextAction("emote", 1.0f), nullptr)));
|
||||
triggers.push_back(new TriggerNode("often", NextAction::array(0, new NextAction("suggest what to do", 1.0f), nullptr)));
|
||||
triggers.push_back(new TriggerNode("often", NextAction::array(0, new NextAction("suggest trade", 1.0f), nullptr)));
|
||||
|
||||
if (sPlayerbotAIConfig->randomBotSuggestDungeons)
|
||||
if (sPlayerbotAIConfig->randomBotEmote)
|
||||
{
|
||||
triggers.push_back(new TriggerNode("random", NextAction::array(0, new NextAction("suggest dungeon", 1.0f), nullptr)));
|
||||
triggers.push_back(new TriggerNode("seldom", NextAction::array(0, new NextAction("emote", 1.0f), nullptr)));
|
||||
triggers.push_back(new TriggerNode("receive text emote", NextAction::array(0, new NextAction("emote", 10.0f), nullptr)));
|
||||
triggers.push_back(new TriggerNode("receive emote", NextAction::array(0, new NextAction("emote", 10.0f), nullptr)));
|
||||
}
|
||||
|
||||
if (sPlayerbotAIConfig->randomBotTalk)
|
||||
{
|
||||
triggers.push_back(new TriggerNode("often", NextAction::array(0, new NextAction("suggest what to do", 10.0f),
|
||||
new NextAction("suggest dungeon", 3.0f),
|
||||
new NextAction("suggest trade", 3.0f),
|
||||
new NextAction("talk", 1.0f),
|
||||
nullptr)));
|
||||
}
|
||||
|
||||
if (sPlayerbotAIConfig->enableGreet)
|
||||
{
|
||||
triggers.push_back(new TriggerNode("new player nearby", NextAction::array(0, new NextAction("greet", 1.0f), nullptr)));
|
||||
}
|
||||
|
||||
triggers.push_back(new TriggerNode("seldom", NextAction::array(0, new NextAction("talk", 1.0f), nullptr)));
|
||||
triggers.push_back(new TriggerNode("receive text emote", NextAction::array(0, new NextAction("emote", 10.0f), nullptr)));
|
||||
triggers.push_back(new TriggerNode("receive emote", NextAction::array(0, new NextAction("emote", 10.0f), nullptr)));
|
||||
triggers.push_back(new TriggerNode("often", NextAction::array(0, new NextAction("rpg mount anim", 1.0f), nullptr)));
|
||||
}
|
||||
|
||||
@@ -88,10 +88,10 @@ class FreezingTrapTrigger : public HasCcTargetTrigger
|
||||
FreezingTrapTrigger(PlayerbotAI* botAI) : HasCcTargetTrigger(botAI, "freezing trap") { }
|
||||
};
|
||||
|
||||
class RapidFireTrigger : public BuffTrigger
|
||||
class RapidFireTrigger : public BoostTrigger
|
||||
{
|
||||
public:
|
||||
RapidFireTrigger(PlayerbotAI* botAI) : BuffTrigger(botAI, "rapid fire") { }
|
||||
RapidFireTrigger(PlayerbotAI* botAI) : BoostTrigger(botAI, "rapid fire") { }
|
||||
};
|
||||
|
||||
class TrueshotAuraTrigger : public BuffTrigger
|
||||
|
||||
@@ -180,7 +180,7 @@ void MageBoostStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
triggers.push_back(new TriggerNode("icy veins", NextAction::array(0, new NextAction("icy veins", 50.0f), nullptr)));
|
||||
triggers.push_back(new TriggerNode("presence of mind", NextAction::array(0, new NextAction("presence of mind", 42.0f), nullptr)));
|
||||
// triggers.push_back(new TriggerNode("arcane power", NextAction::array(0, new NextAction("arcane power", 41.0f), nullptr)));
|
||||
// triggers.push_back(new TriggerNode("mirror image", NextAction::array(0, new NextAction("mirror image", 41.0f), nullptr)));
|
||||
triggers.push_back(new TriggerNode("mirror image", NextAction::array(0, new NextAction("mirror image", 41.0f), nullptr)));
|
||||
}
|
||||
|
||||
void MageCcStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
|
||||
@@ -5,9 +5,7 @@
|
||||
#ifndef _PLAYERBOT_SHAMANACTIONS_H
|
||||
#define _PLAYERBOT_SHAMANACTIONS_H
|
||||
|
||||
#include "Define.h"
|
||||
#include "GenericSpellActions.h"
|
||||
#include "Playerbots.h"
|
||||
#include "SharedDefines.h"
|
||||
|
||||
class PlayerbotAI;
|
||||
@@ -362,31 +360,11 @@ class CastWindShearOnEnemyHealerAction : public CastSpellOnEnemyHealerAction
|
||||
CastWindShearOnEnemyHealerAction(PlayerbotAI* botAI) : CastSpellOnEnemyHealerAction(botAI, "wind shear") { }
|
||||
};
|
||||
|
||||
// class CastCurePoisonAction : public CastCureSpellAction
|
||||
// {
|
||||
// public:
|
||||
// CastCurePoisonAction(PlayerbotAI* botAI) : CastCureSpellAction(botAI, "cure poison") { }
|
||||
// };
|
||||
CURE_ACTION(CastCurePoisonActionSham, "cure disease");
|
||||
CURE_PARTY_ACTION(CastCurePoisonOnPartyActionSham, "cure poison", DISPEL_POISON);
|
||||
|
||||
// class CastCurePoisonOnPartyAction : public CurePartyMemberAction
|
||||
// {
|
||||
// public:
|
||||
// CastCurePoisonOnPartyAction(PlayerbotAI* botAI) : CurePartyMemberAction(botAI, "cure poison", DISPEL_POISON) { }
|
||||
// };
|
||||
|
||||
// class CastCureDiseaseAction : public CastCureSpellAction
|
||||
// {
|
||||
// public:
|
||||
// CastCureDiseaseAction(PlayerbotAI* botAI) : CastCureSpellAction(botAI, "cure disease") { }
|
||||
// };
|
||||
|
||||
// class CastCureDiseaseOnPartyAction : public CurePartyMemberAction
|
||||
// {
|
||||
// public:
|
||||
// CastCureDiseaseOnPartyAction(PlayerbotAI* botAI) : CurePartyMemberAction(botAI, "cure disease", DISPEL_DISEASE) { }
|
||||
|
||||
// std::string const getName() override { return "cure disease on party"; }
|
||||
// };
|
||||
CURE_ACTION(CastCureDiseaseActionSham, "cure disease");
|
||||
CURE_PARTY_ACTION(CastCureDiseaseOnPartyActionSham, "cure disease", DISPEL_DISEASE);
|
||||
|
||||
class CastLavaBurstAction : public CastSpellAction
|
||||
{
|
||||
|
||||
@@ -213,10 +213,10 @@ class ShamanAiObjectContextInternal : public NamedObjectContext<Action>
|
||||
creators["heroism"] = &ShamanAiObjectContextInternal::heroism;
|
||||
creators["bloodlust"] = &ShamanAiObjectContextInternal::bloodlust;
|
||||
creators["elemental mastery"] = &ShamanAiObjectContextInternal::elemental_mastery;
|
||||
// creators["cure disease"] = &ShamanAiObjectContextInternal::cure_disease;
|
||||
// creators["cure disease on party"] = &ShamanAiObjectContextInternal::cure_disease_on_party;
|
||||
// creators["cure poison"] = &ShamanAiObjectContextInternal::cure_poison;
|
||||
// creators["cure poison on party"] = &ShamanAiObjectContextInternal::cure_poison_on_party;
|
||||
creators["cure disease"] = &ShamanAiObjectContextInternal::cure_disease;
|
||||
creators["cure disease on party"] = &ShamanAiObjectContextInternal::cure_disease_on_party;
|
||||
creators["cure poison"] = &ShamanAiObjectContextInternal::cure_poison;
|
||||
creators["cure poison on party"] = &ShamanAiObjectContextInternal::cure_poison_on_party;
|
||||
creators["lava burst"] = &ShamanAiObjectContextInternal::lava_burst;
|
||||
creators["earth shield on main tank"] = &ShamanAiObjectContextInternal::earth_shield_on_main_tank;
|
||||
creators["fire elemental totem"] = &ShamanAiObjectContextInternal::fire_elemental_totem;
|
||||
@@ -277,10 +277,10 @@ class ShamanAiObjectContextInternal : public NamedObjectContext<Action>
|
||||
static Action* lava_lash(PlayerbotAI* botAI) { return new CastLavaLashAction(botAI); }
|
||||
static Action* ancestral_spirit(PlayerbotAI* botAI) { return new CastAncestralSpiritAction(botAI); }
|
||||
static Action* wind_shear_on_enemy_healer(PlayerbotAI* botAI) { return new CastWindShearOnEnemyHealerAction(botAI); }
|
||||
// static Action* cure_poison(PlayerbotAI* botAI) { return new CastCurePoisonAction(botAI); }
|
||||
// static Action* cure_poison_on_party(PlayerbotAI* botAI) { return new CastCurePoisonOnPartyAction(botAI); }
|
||||
// static Action* cure_disease(PlayerbotAI* botAI) { return new CastCureDiseaseAction(botAI); }
|
||||
// static Action* cure_disease_on_party(PlayerbotAI* botAI) { return new CastCureDiseaseOnPartyAction(botAI); }
|
||||
static Action* cure_poison(PlayerbotAI* botAI) { return new CastCurePoisonActionSham(botAI); }
|
||||
static Action* cure_poison_on_party(PlayerbotAI* botAI) { return new CastCurePoisonOnPartyActionSham(botAI); }
|
||||
static Action* cure_disease(PlayerbotAI* botAI) { return new CastCureDiseaseActionSham(botAI); }
|
||||
static Action* cure_disease_on_party(PlayerbotAI* botAI) { return new CastCureDiseaseOnPartyActionSham(botAI); }
|
||||
static Action* lava_burst(PlayerbotAI* ai) { return new CastLavaBurstAction(ai); }
|
||||
static Action* earth_shield_on_main_tank(PlayerbotAI* ai) { return new CastEarthShieldOnMainTankAction(ai); }
|
||||
static Action* totem_of_wrath(PlayerbotAI* ai) { return new CastTotemOfWrathAction(ai); }
|
||||
|
||||
@@ -160,7 +160,7 @@ bool GrindTargetValue::needForQuest(Unit* target)
|
||||
{
|
||||
QuestStatusData* questStatus = sTravelMgr->getQuestStatus(bot, questId);
|
||||
|
||||
if (questTemplate->GetQuestLevel() > bot->GetLevel())
|
||||
if (questTemplate->GetQuestLevel() > bot->GetLevel()+5)
|
||||
continue;
|
||||
|
||||
for (int j = 0; j < QUEST_OBJECTIVES_COUNT; j++)
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "ChatHelper.h"
|
||||
#include "Playerbots.h"
|
||||
#include "Vehicle.h"
|
||||
#include "World.h"
|
||||
|
||||
SpellIdValue::SpellIdValue(PlayerbotAI* botAI) : CalculatedValue<uint32>(botAI, "spell id", 20 * 1000)
|
||||
{
|
||||
@@ -34,7 +35,7 @@ uint32 SpellIdValue::Calculate()
|
||||
char firstSymbol = tolower(namepart[0]);
|
||||
int spellLength = wnamepart.length();
|
||||
|
||||
LocaleConstant loc = bot->GetSession()->GetSessionDbcLocale();
|
||||
LocaleConstant loc = LOCALE_enUS;
|
||||
|
||||
std::set<uint32> spellIds;
|
||||
for (PlayerSpellMap::iterator itr = bot->GetSpellMap().begin(); itr != bot->GetSpellMap().end(); ++itr)
|
||||
@@ -189,7 +190,7 @@ uint32 VehicleSpellIdValue::Calculate()
|
||||
char firstSymbol = tolower(namepart[0]);
|
||||
int spellLength = wnamepart.length();
|
||||
|
||||
int loc = bot->GetSession()->GetSessionDbcLocale();
|
||||
const int loc = LocaleConstant::LOCALE_enUS;
|
||||
|
||||
Creature* creature = vehicleBase->ToCreature();
|
||||
for (uint32 x = 0; x < MAX_CREATURE_SPELLS; ++x)
|
||||
|
||||
Reference in New Issue
Block a user