боты русифицированы

This commit is contained in:
2026-07-30 19:06:57 +04:00
parent 6f075133f7
commit 85adbe19da
26 changed files with 11211 additions and 28 deletions
@@ -12,6 +12,7 @@
#include "Event.h"
#include "PlayerbotTextMgr.h"
#include "Playerbots.h"
#include "Util.h"
static const std::unordered_set<std::string> noReplyMsgs = {
"join",
@@ -52,6 +53,18 @@ 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 "};
static std::string Utf8Lowercase(std::string const& value)
{
std::wstring wide;
if (!Utf8toWStr(value, wide))
return value;
wstrToLower(wide);
std::string lowered;
WStrToUtf8(wide, lowered);
return lowered;
}
SayAction::SayAction(PlayerbotAI* botAI) : Action(botAI, "say"), Qualified() {}
bool SayAction::Execute(Event /*event*/)
@@ -578,6 +591,40 @@ std::string ChatReplyAction::GenerateReplyMessage(Player* bot, std::string& inco
std::string respondsText = "";
// The legacy free-chat parser below is English-specific and constructs
// several responses directly in English. For ruRU, classify the small
// static reply set locally and let PlayerbotTextMgr select text_loc8.
if (PlayerbotTextMgr::instance().GetLocalePriority() == LOCALE_ruRU)
{
std::string const message = Utf8Lowercase(incomingMessage);
std::string const botName = Utf8Lowercase(bot->GetName());
if (Player* player = ObjectAccessor::FindPlayer(ObjectGuid(HighGuid::Player, guid1));
player && player->isGMChat())
{
replyType = REPLY_ADMIN_ABUSE;
}
else if (message.find("привет") != std::string::npos || message.find("здравств") != std::string::npos ||
message.find("добрый день") != std::string::npos || message.find("добрый вечер") != std::string::npos)
{
replyType = REPLY_HELLO;
}
else if (message.find("нуб") != std::string::npos || message.find("дурак") != std::string::npos ||
message.find("идиот") != std::string::npos || message.find("заткнись") != std::string::npos)
{
replyType = REPLY_GRUDGE;
}
else if (message.find(botName) != std::string::npos)
{
replyType = REPLY_NAME;
}
respondsText = PlayerbotTextMgr::instance().GetBotText(replyType, name);
if (respondsText.size() > 255)
respondsText.resize(255);
return respondsText;
}
// Chat Logic
int32 verb_pos = -1;
int32 verb_type = -1;
@@ -175,16 +175,17 @@ Player* RandomPlayerbotFactory::CreateRandomBot(WorldSession* session, uint8 cls
std::string const RandomPlayerbotFactory::CreateRandomBotName(NameRaceAndGender raceAndGender)
{
std::string botName = "";
char const* namesTable = sPlayerbotAIConfig.useRussianNames ? "playerbots_names_ru" : "playerbots_names";
int tries = 3;
while (--tries)
{
QueryResult result = CharacterDatabase.Query(
"SELECT n.name "
"FROM playerbots_names n "
"FROM {} n "
"LEFT OUTER JOIN characters c ON c.name = n.name "
"WHERE c.guid IS NULL and n.gender = '{}' "
"ORDER BY RAND() LIMIT 1",
static_cast<uint8>(raceAndGender));
namesTable, static_cast<uint8>(raceAndGender));
if (!result)
{
break;
@@ -668,7 +669,8 @@ void RandomPlayerbotFactory::CreateRandomBots()
{
nameCached = true;
LOG_INFO("playerbots", "Creating cache for names per gender and race...");
QueryResult result = CharacterDatabase.Query("SELECT name, gender FROM playerbots_names");
char const* namesTable = sPlayerbotAIConfig.useRussianNames ? "playerbots_names_ru" : "playerbots_names";
QueryResult result = CharacterDatabase.Query("SELECT name, gender FROM {}", namesTable);
if (!result)
{
LOG_ERROR("playerbots", "No more unused names left");
@@ -753,8 +755,10 @@ void RandomPlayerbotFactory::CreateRandomBots()
std::string const RandomPlayerbotFactory::CreateRandomGuildName()
{
std::string guildName = "";
char const* guildNamesTable =
sPlayerbotAIConfig.useRussianNames ? "playerbots_guild_names_ru" : "playerbots_guild_names";
QueryResult result = CharacterDatabase.Query("SELECT MAX(name_id) FROM playerbots_guild_names");
QueryResult result = CharacterDatabase.Query("SELECT MAX(name_id) FROM {}", guildNamesTable);
if (!result)
{
LOG_ERROR("playerbots", "No more names left for random guilds");
@@ -766,9 +770,9 @@ std::string const RandomPlayerbotFactory::CreateRandomGuildName()
uint32 id = urand(0, maxId);
result = CharacterDatabase.Query(
"SELECT n.name FROM playerbots_guild_names n "
"SELECT n.name FROM {} n "
"LEFT OUTER JOIN guild e ON e.name = n.name WHERE e.guildid IS NULL AND n.name_id >= {} LIMIT 1",
id);
guildNamesTable, id);
if (!result)
{
LOG_ERROR("playerbots", "No more names left for random guilds");
@@ -1652,7 +1652,7 @@ void PlayerbotMgr::OnPlayerLogin(Player* player)
// For bot texts (DB-driven), prefer the database locale with a safe fallback.
LocaleConstant usedLocale = databaseLocale;
if (usedLocale >= MAX_LOCALES)
if (usedLocale >= TOTAL_LOCALES)
usedLocale = LOCALE_enUS; // fallback
// set locale priority for bot texts
@@ -161,13 +161,15 @@ void PlayerbotGuildMgr::ResetGuildCache()
void PlayerbotGuildMgr::LoadGuildNames()
{
LOG_INFO("playerbots", "Loading guild names from playerbots_guild_names...");
char const* guildNamesTable =
sPlayerbotAIConfig.useRussianNames ? "playerbots_guild_names_ru" : "playerbots_guild_names";
LOG_INFO("playerbots", "Loading guild names from {}...", guildNamesTable);
QueryResult result = CharacterDatabase.Query("SELECT name_id, name FROM playerbots_guild_names");
QueryResult result = CharacterDatabase.Query("SELECT name_id, name FROM {}", guildNamesTable);
if (!result)
{
LOG_ERROR("playerbots", "No entries found in playerbots_guild_names. List is empty.");
LOG_ERROR("playerbots", "No entries found in {}. List is empty.", guildNamesTable);
return;
}
@@ -184,7 +186,7 @@ void PlayerbotGuildMgr::LoadGuildNames()
std::mt19937 g(rd());
std::shuffle(_shuffled_guild_keys.begin(), _shuffled_guild_keys.end(), g);
LOG_INFO("playerbots", "Loaded {} guild entries from playerbots_guild_names table.", _guildNames.size());
LOG_INFO("playerbots", "Loaded {} guild entries from {} table.", _guildNames.size(), guildNamesTable);
}
void PlayerbotGuildMgr::ValidateGuildCache()
@@ -38,7 +38,7 @@ void PlayerbotTextMgr::LoadBotTexts()
text[0] = fields[1].Get<std::string>();
uint8 sayType = fields[2].Get<uint8>();
uint8 replyType = fields[3].Get<uint8>();
for (uint8 i = 1; i < MAX_LOCALES; ++i)
for (uint8 i = 1; i < TOTAL_LOCALES; ++i)
{
text[i] = fields[i + 3].Get<std::string>();
}
@@ -192,9 +192,10 @@ bool PlayerbotTextMgr::GetBotText(std::string name, std::string& text, std::map<
void PlayerbotTextMgr::AddLocalePriority(uint32 locale)
{
if (locale >= MAX_LOCALES)
if (locale >= TOTAL_LOCALES)
{
LOG_WARN("playerbots", "Ignoring locale {} for bot texts because it exceeds MAX_LOCALES ({})", locale, MAX_LOCALES - 1);
LOG_WARN("playerbots", "Ignoring locale {} for bot texts because it exceeds TOTAL_LOCALES ({})", locale,
TOTAL_LOCALES - 1);
return;
}
@@ -212,7 +213,7 @@ uint32 PlayerbotTextMgr::GetLocalePriority()
}
uint32 topLocale = 0;
for (uint8 i = 0; i < MAX_LOCALES; ++i)
for (uint8 i = 0; i < TOTAL_LOCALES; ++i)
{
if (botTextLocalePriority[i] > botTextLocalePriority[topLocale])
topLocale = i;
@@ -223,7 +224,7 @@ uint32 PlayerbotTextMgr::GetLocalePriority()
void PlayerbotTextMgr::ResetLocalePriority()
{
for (uint8 i = 0; i < MAX_LOCALES; ++i)
for (uint8 i = 0; i < TOTAL_LOCALES; ++i)
{
botTextLocalePriority[i] = 0;
}
@@ -87,7 +87,7 @@ public:
private:
PlayerbotTextMgr()
{
for (uint8 i = 0; i < MAX_LOCALES; ++i)
for (uint8 i = 0; i < TOTAL_LOCALES; ++i)
{
botTextLocalePriority[i] = 0;
}
@@ -102,7 +102,7 @@ private:
std::map<std::string, std::vector<BotTextEntry>> botTexts;
std::map<std::string, uint32> botTextChance;
uint32 botTextLocalePriority[MAX_LOCALES];
uint32 botTextLocalePriority[TOTAL_LOCALES];
};
#endif
@@ -67,6 +67,8 @@ bool PlayerbotAIConfig::Initialize()
return false;
}
useRussianNames = sConfigMgr->GetOption<bool>("AiPlayerbot.UseRussianNames", false);
globalCoolDown = sConfigMgr->GetOption<int32>("AiPlayerbot.GlobalCooldown", 500);
maxWaitForMove = sConfigMgr->GetOption<int32>("AiPlayerbot.MaxWaitForMove", 5000);
disableMoveSplinePath = sConfigMgr->GetOption<int32>("AiPlayerbot.DisableMoveSplinePath", 0);
@@ -79,6 +79,7 @@ public:
bool IsInPvpProhibitedArea(uint32 id);
bool enabled;
bool useRussianNames;
bool disabledWithoutRealPlayer;
bool EnableICCBuffs;
bool allowAccountBots, allowGuildBots, allowTrustedAccountBots;