боты, русификация, подключение ИИ

This commit is contained in:
2026-07-31 19:45:21 +04:00
parent 85adbe19da
commit b5c0a8a27a
118 changed files with 2928 additions and 482 deletions
+36
View File
@@ -65,6 +65,42 @@ AC_RATE_XP_KILL=1
# Legacy alias для docker override. Держим синхронно с ACORE_PLAYERBOTS_RANDOM_BOT_AUTOLOGIN. # Legacy alias для docker override. Держим синхронно с ACORE_PLAYERBOTS_RANDOM_BOT_AUTOLOGIN.
AC_AI_PLAYERBOT_RANDOM_BOT_AUTOLOGIN=0 AC_AI_PLAYERBOT_RANDOM_BOT_AUTOLOGIN=0
# ------------------------------------------------------------------------------
# Playerbots AI / Yandex AI Studio
# ------------------------------------------------------------------------------
# Включайте после заполнения YANDEX_AI_API_KEY и YANDEX_AI_FOLDER_ID.
ACORE_PLAYERBOTS_AI_ENABLED=0
# Секретный API-ключ сервисного аккаунта Yandex AI Studio.
# Не коммитьте заполненное значение.
YANDEX_AI_API_KEY=
# Идентификатор каталога Yandex Cloud.
YANDEX_AI_FOLDER_ID=
# Пусто = gpt://<YANDEX_AI_FOLDER_ID>/aliceai-llm-flash
YANDEX_AI_MODEL_URI=
YANDEX_AI_BASE_URL=https://ai.api.cloud.yandex.net/v1
# Параметры генерации и игрового rate limit.
PLAYERBOTS_AI_REQUEST_TIMEOUT=12
PLAYERBOTS_AI_TEMPERATURE=0.4
PLAYERBOTS_AI_MAX_TOKENS=120
PLAYERBOTS_AI_HISTORY_MESSAGES=6
PLAYERBOTS_AI_LOG_API_RESPONSES=1
# Постоянный кэш классификации команд. 604800 секунд = 7 дней.
PLAYERBOTS_AI_CLASSIFIER_CACHE_ENABLED=1
PLAYERBOTS_AI_CLASSIFIER_CACHE_TTL_SECONDS=604800
PLAYERBOTS_AI_CLASSIFIER_CACHE_MAX_ENTRIES=10000
ACORE_PLAYERBOTS_AI_COMMANDS_ENABLED=1
# 1 = доступно всем; 0 = недоступно никому до реализации подписки.
ACORE_PLAYERBOTS_AI_AVAILABLE_FOR_ALL=1
ACORE_PLAYERBOTS_AI_PLAYER_COOLDOWN_SECONDS=8
ACORE_PLAYERBOTS_AI_MAX_QUEUED_REQUESTS=32
ACORE_PLAYERBOTS_AI_MAX_REPLY_CHARACTERS=240
ACORE_PLAYERBOTS_AI_DEBUG=0
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Значения по умолчанию для ./create-account.sh # Значения по умолчанию для ./create-account.sh
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
+42
View File
@@ -1,4 +1,43 @@
services: services:
playerbots-ai:
container_name: playerbots-ai
image: moonwell/playerbots-ai:local
build:
context: ./services/playerbots-ai
dockerfile: Dockerfile
networks:
- ac-network
restart: unless-stopped
environment:
PLAYERBOTS_AI_PORT: "8080"
PLAYERBOTS_AI_REQUEST_TIMEOUT: "${PLAYERBOTS_AI_REQUEST_TIMEOUT:-12}"
PLAYERBOTS_AI_TEMPERATURE: "${PLAYERBOTS_AI_TEMPERATURE:-0.4}"
PLAYERBOTS_AI_MAX_TOKENS: "${PLAYERBOTS_AI_MAX_TOKENS:-120}"
PLAYERBOTS_AI_MAX_REPLY_CHARACTERS: "${ACORE_PLAYERBOTS_AI_MAX_REPLY_CHARACTERS:-240}"
PLAYERBOTS_AI_HISTORY_MESSAGES: "${PLAYERBOTS_AI_HISTORY_MESSAGES:-6}"
PLAYERBOTS_AI_COMMANDS_ENABLED: "${ACORE_PLAYERBOTS_AI_COMMANDS_ENABLED:-1}"
PLAYERBOTS_AI_LOG_API_RESPONSES: "${PLAYERBOTS_AI_LOG_API_RESPONSES:-1}"
PLAYERBOTS_AI_CLASSIFIER_CACHE_ENABLED: "${PLAYERBOTS_AI_CLASSIFIER_CACHE_ENABLED:-1}"
PLAYERBOTS_AI_CLASSIFIER_CACHE_DB: "/data/classifier-cache.sqlite3"
PLAYERBOTS_AI_CLASSIFIER_CACHE_TTL_SECONDS: "${PLAYERBOTS_AI_CLASSIFIER_CACHE_TTL_SECONDS:-604800}"
PLAYERBOTS_AI_CLASSIFIER_CACHE_MAX_ENTRIES: "${PLAYERBOTS_AI_CLASSIFIER_CACHE_MAX_ENTRIES:-10000}"
PLAYERBOTS_AI_SYSTEM_PROMPT: "${PLAYERBOTS_AI_SYSTEM_PROMPT:-}"
YANDEX_AI_API_KEY: "${YANDEX_AI_API_KEY:-}"
YANDEX_AI_FOLDER_ID: "${YANDEX_AI_FOLDER_ID:-}"
YANDEX_AI_MODEL_URI: "${YANDEX_AI_MODEL_URI:-}"
YANDEX_AI_BASE_URL: "${YANDEX_AI_BASE_URL:-https://ai.api.cloud.yandex.net/v1}"
volumes:
- playerbots-ai-cache:/data
healthcheck:
test:
- CMD
- python
- -c
- "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8080/health', timeout=2)"
interval: 5s
timeout: 3s
retries: 12
ac-worldserver: ac-worldserver:
stdin_open: true stdin_open: true
tty: true tty: true
@@ -9,3 +48,6 @@ services:
- ./modules:/azerothcore/modules:ro - ./modules:/azerothcore/modules:ro
- ./lua_scripts:/azerothcore/lua_scripts - ./lua_scripts:/azerothcore/lua_scripts
- ./client_patch/enUS/DBFilesClient/LFGDungeons.dbc:/azerothcore/env/dist/data/dbc/LFGDungeons.dbc:ro - ./client_patch/enUS/DBFilesClient/LFGDungeons.dbc:/azerothcore/env/dist/data/dbc/LFGDungeons.dbc:ro
volumes:
playerbots-ai-cache:
+12
View File
@@ -1,4 +1,16 @@
services: services:
playerbots-ai:
deploy:
resources:
limits:
cpus: '0.5'
memory: 128M
logging:
driver: "json-file"
options:
max-size: "20m"
max-file: "3"
ac-database: ac-database:
command: > command: >
--innodb_buffer_pool_size=4G --innodb_buffer_pool_size=4G
+114
View File
@@ -0,0 +1,114 @@
# MoonWell Playerbots AI
This module sends a local `/say` or public-channel message to the LLM only when
a real player mentions the complete name of an online bot. A channel bot must
be a channel member; a `/say` bot must be within the server's normal listening
range. HTTP work runs outside the AzerothCore world thread.
Alice AI LLM Flash can classify direct natural-language requests into a small
allowlisted set of native playerbots commands. The server validates the command
again and executes it only against the addressed bot; existing playerbots
ownership and group security checks still apply.
The routing prompt covers party movement and combat, LFG, combat/non-combat
strategies, spells, RTI/RTSC, focus healing, loot lists, inventory operations,
quests, pets, talents, glyphs, maintenance, and information commands documented
in the upstream Playerbot Commands wiki. Administrative, console, account,
debug/cheat, and destructive `destroy`/`drop`/mail commands are intentionally
not executable through the LLM.
Common Russian movement/combat phrases use a deterministic fast path. Other
requests first pass through a command-only classifier; ordinary conversation is
then sent separately to the roleplay prompt. While AI routing is enabled, the
legacy public-channel parser is bypassed and `setup-modules.sh` also forces
`AiPlayerbot.RandomBotTalk = 0`. RandomBotTalk consumes incoming chat packets
inside each bot, so bypassing only the parser does not prevent its delayed
stock replies. Whisper, party, raid, and guild command hooks remain unchanged.
Recognized commands produce a gender-aware local-chat acknowledgement
(`Понял команду.` or `Поняла команду.`) before they are handed to the native
playerbots command handler. Bot and player gender are also included in the LLM
context for pronoun, past-tense verb, and adjective agreement. Russian requests
to show bags or inventory use the native `inv` command; `open items` is reserved
for actually opening container items.
Trade and quest requests have deterministic link-preserving routes before the
LLM classifier:
- `дай/передай [item]` -> `t [item]`; `начни обмен` -> `t`
- `покажи задания` -> `quests all`; completed/incomplete filters are supported
- `покажи прогресс [quest]` -> `q [quest]`
- `прими [quest]` / `прими все задания` -> `accept [quest]` / `accept *`
- `поделись [quest]` -> `share [quest]`
- `выбери [item] в награду` -> `r [item]`
- `сдай готовое задание` -> `talk`
- `откажись от [quest]` -> `drop [quest]` only with an explicit quest link
These routes preserve the original WoW hyperlink byte-for-byte. The local
playerbots trade action continues processing after it creates the trade, so one
`t [item]` command both initiates the exchange and places the requested item in
the trade window.
The bundled `playerbots-ai` bridge uses the Yandex AI Studio OpenAI-compatible
Chat Completions API and defaults to Alice AI LLM Flash.
## Configuration
Set these values in the repository `.env`:
```dotenv
ACORE_PLAYERBOTS_AI_ENABLED=1
ACORE_PLAYERBOTS_AI_COMMANDS_ENABLED=1
YANDEX_AI_API_KEY=<service-account API key>
YANDEX_AI_FOLDER_ID=<Yandex Cloud folder ID>
```
Until the subscription system exists, public access is controlled by one
explicit switch:
```dotenv
ACORE_PLAYERBOTS_AI_AVAILABLE_FOR_ALL=1
```
`1` allows every player to reach the bridge. `0` denies LLM access to everyone
without spending tokens. When subscriptions are implemented, their entitlement
check will be added to the disabled branch instead of using a temporary manual
account list.
The command classifier has a persistent SQLite cache in the
`playerbots-ai-cache` Docker volume. The key excludes the addressed bot name,
so repeated phrases such as “покажи инвентарь” are shared across players and
bots. Both commands and “ordinary chat, not a command” decisions are cached.
The cache does not store roleplay responses or conversation history.
Obvious social phrases such as greetings, “как дела?” and “расскажи о себе”
skip the command classifier entirely: they still receive an Alice roleplay
reply, but do not pay the roughly 800-token command-catalog prompt first.
```dotenv
PLAYERBOTS_AI_CLASSIFIER_CACHE_ENABLED=1
PLAYERBOTS_AI_CLASSIFIER_CACHE_TTL_SECONDS=604800
PLAYERBOTS_AI_CLASSIFIER_CACHE_MAX_ENTRIES=10000
```
Changing the classifier prompt automatically creates a new cache namespace.
Old rows expire normally, and the oldest rows are removed at the size limit.
The default model URI is:
```text
gpt://<YANDEX_AI_FOLDER_ID>/aliceai-llm-flash
```
Run `./start-server.sh` or `scripts/prod-deploy.sh`. The deployment wrapper
builds and starts the bridge before `ac-worldserver`.
Never commit a populated API key.
Full Yandex response JSON is logged by default by the bridge:
```dotenv
PLAYERBOTS_AI_LOG_API_RESPONSES=1
```
Use `docker compose logs -f playerbots-ai` to follow classifier and chat
responses. Authentication headers and the API key are never logged.
@@ -0,0 +1,29 @@
#
# MoonWell Playerbots AI
#
# Enables LLM replies in public channels.
PlayerbotsAI.Enabled = 0
# Enables natural-language commands through an allowlisted playerbots command set.
PlayerbotsAI.CommandsEnabled = 1
# Temporary public-access switch. A future subscription check will be inserted
# when this is disabled; until that system exists, 0 denies access to everyone.
PlayerbotsAI.AvailableForAll = 1
# Internal HTTP bridge. The Yandex API key is kept in the bridge container.
PlayerbotsAI.BridgeHost = playerbots-ai
PlayerbotsAI.BridgePort = 8080
PlayerbotsAI.BridgePath = /v1/chat
# Per-player request cooldown and bounded worker queue.
PlayerbotsAI.PlayerCooldownSeconds = 8
PlayerbotsAI.MaxQueuedRequests = 32
# Maximum UTF-8 characters sent back to an in-game channel.
PlayerbotsAI.MaxReplyCharacters = 240
# Extra request/response logging. Prompts and API keys are never logged.
PlayerbotsAI.Debug = 0
п
+3
View File
@@ -0,0 +1,3 @@
#!/usr/bin/env bash
# This module uses AzerothCore's standard source and loader discovery.
@@ -0,0 +1,808 @@
#include "Channel.h"
#include "ChannelMgr.h"
#include "Config.h"
#include "Language.h"
#include "Log.h"
#include "ObjectAccessor.h"
#include "Player.h"
#include "PlayerbotAI.h"
#include "PlayerbotMgr.h"
#include "RandomPlayerbotMgr.h"
#include "ScriptMgr.h"
#include "World.h"
#include <boost/asio/connect.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/read.hpp>
#include <boost/asio/read_until.hpp>
#include <boost/asio/streambuf.hpp>
#include <boost/asio/write.hpp>
#include <algorithm>
#include <atomic>
#include <chrono>
#include <condition_variable>
#include <cstdint>
#include <deque>
#include <iomanip>
#include <map>
#include <mutex>
#include <optional>
#include <set>
#include <sstream>
#include <stdexcept>
#include <string>
#include <thread>
#include <utility>
#include <vector>
namespace
{
struct AiRequest
{
ObjectGuid botGuid;
ObjectGuid playerGuid;
TeamId teamId;
std::string channelName;
std::string host;
std::string port;
std::string path;
std::string body;
};
struct AiResponse
{
ObjectGuid botGuid;
ObjectGuid playerGuid;
TeamId teamId;
std::string channelName;
std::string command;
std::string text;
};
struct BridgeResponse
{
std::string command;
std::string text;
};
std::string JsonEscape(std::string const& value)
{
std::ostringstream output;
for (unsigned char character : value)
{
switch (character)
{
case '"': output << "\\\""; break;
case '\\': output << "\\\\"; break;
case '\b': output << "\\b"; break;
case '\f': output << "\\f"; break;
case '\n': output << "\\n"; break;
case '\r': output << "\\r"; break;
case '\t': output << "\\t"; break;
default:
if (character < 0x20)
{
output << "\\u" << std::hex << std::setw(4) << std::setfill('0')
<< static_cast<uint32>(character) << std::dec;
}
else
{
output << static_cast<char>(character);
}
break;
}
}
return output.str();
}
std::vector<uint32> DecodeAndCaseFold(std::string const& text)
{
std::vector<uint32> result;
result.reserve(text.size());
for (std::size_t index = 0; index < text.size();)
{
unsigned char first = static_cast<unsigned char>(text[index]);
uint32 codepoint = 0xFFFD;
std::size_t length = 1;
if (first < 0x80)
{
codepoint = first;
}
else if ((first & 0xE0) == 0xC0 && index + 1 < text.size())
{
codepoint = ((first & 0x1F) << 6)
| (static_cast<unsigned char>(text[index + 1]) & 0x3F);
length = 2;
}
else if ((first & 0xF0) == 0xE0 && index + 2 < text.size())
{
codepoint = ((first & 0x0F) << 12)
| ((static_cast<unsigned char>(text[index + 1]) & 0x3F) << 6)
| (static_cast<unsigned char>(text[index + 2]) & 0x3F);
length = 3;
}
else if ((first & 0xF8) == 0xF0 && index + 3 < text.size())
{
codepoint = ((first & 0x07) << 18)
| ((static_cast<unsigned char>(text[index + 1]) & 0x3F) << 12)
| ((static_cast<unsigned char>(text[index + 2]) & 0x3F) << 6)
| (static_cast<unsigned char>(text[index + 3]) & 0x3F);
length = 4;
}
if (codepoint >= 'A' && codepoint <= 'Z')
codepoint += 'a' - 'A';
else if (codepoint >= 0x0410 && codepoint <= 0x042F)
codepoint += 0x20;
else if (codepoint == 0x0401)
codepoint = 0x0451;
result.push_back(codepoint);
index += length;
}
return result;
}
bool IsWordCodepoint(uint32 codepoint)
{
return (codepoint >= '0' && codepoint <= '9')
|| (codepoint >= 'a' && codepoint <= 'z')
|| (codepoint >= 0x0430 && codepoint <= 0x044F)
|| codepoint == 0x0451;
}
std::optional<std::size_t> FindCompleteName(
std::vector<uint32> const& message,
std::vector<uint32> const& name)
{
if (name.empty() || name.size() > message.size())
return std::nullopt;
for (std::size_t position = 0; position + name.size() <= message.size(); ++position)
{
if (!std::equal(name.begin(), name.end(), message.begin() + position))
continue;
bool leftBoundary = position == 0 || !IsWordCodepoint(message[position - 1]);
std::size_t end = position + name.size();
bool rightBoundary = end == message.size() || !IsWordCodepoint(message[end]);
if (leftBoundary && rightBoundary)
return position;
}
return std::nullopt;
}
std::string NormalizeReply(std::string text, uint32 maxCharacters)
{
std::replace(text.begin(), text.end(), '\r', ' ');
std::replace(text.begin(), text.end(), '\n', ' ');
std::string compact;
compact.reserve(text.size());
bool previousSpace = false;
for (unsigned char character : text)
{
bool isSpace = character == ' ' || character == '\t';
if (isSpace && previousSpace)
continue;
compact.push_back(isSpace ? ' ' : static_cast<char>(character));
previousSpace = isSpace;
}
std::size_t first = compact.find_first_not_of(' ');
if (first == std::string::npos)
return {};
compact.erase(0, first);
std::size_t last = compact.find_last_not_of(' ');
compact.erase(last + 1);
if (!maxCharacters)
return compact;
std::size_t byteIndex = 0;
uint32 characters = 0;
while (byteIndex < compact.size() && characters < maxCharacters)
{
unsigned char firstByte = static_cast<unsigned char>(compact[byteIndex]);
std::size_t length = firstByte < 0x80 ? 1
: (firstByte & 0xE0) == 0xC0 ? 2
: (firstByte & 0xF0) == 0xE0 ? 3
: (firstByte & 0xF8) == 0xF0 ? 4
: 1;
byteIndex = std::min(compact.size(), byteIndex + length);
++characters;
}
if (byteIndex < compact.size())
{
compact.resize(byteIndex);
compact += "…";
}
return compact;
}
BridgeResponse ParseBridgeResponse(std::string response)
{
static std::string const commandPrefix = "PB-COMMAND:";
if (response.rfind(commandPrefix, 0) != 0)
return {"", std::move(response)};
std::size_t newline = response.find('\n');
if (newline == std::string::npos)
return {"", ""};
return {
response.substr(commandPrefix.size(), newline - commandPrefix.size()),
response.substr(newline + 1)
};
}
bool IsAllowedPlayerbotCommand(std::string const& command)
{
if (command.empty() || command.size() > 300 || command.find('\\') != std::string::npos)
return false;
if (std::any_of(command.begin(), command.end(), [](unsigned char character)
{
return character < 0x20;
}))
{
return false;
}
static std::set<std::string> const allowedCommands = {
"accept",
"accept *",
"add all loot",
"attack",
"attack rti target",
"autogear",
"buff",
"disperse disable",
"flee",
"focus heal ?",
"focus heal clear",
"focus heal none",
"focus heal unset",
"follow",
"give leader",
"glyphs",
"grind",
"help",
"home",
"inv",
"invite",
"items",
"leave",
"lfg",
"ll all",
"ll gray",
"ll normal",
"ll quest",
"ll skill",
"los",
"maintenance",
"open items",
"outfit ?",
"pet aggressive",
"pet attack",
"pet defensive",
"pet follow",
"pet passive",
"pet stance",
"pet stay",
"quests",
"quests all",
"quests completed",
"quests incompleted",
"ready",
"release",
"reset",
"reset botAI",
"revive",
"roll",
"rti",
"rtsc",
"rtsc cancel",
"rtsc go save",
"rtsc toggle",
"runaway",
"spells",
"ss reset",
"stay",
"stats",
"summon",
"t",
"talents",
"talents spec list",
"talk",
"tame",
"tame family",
"tank attack",
"trainer",
"trainer learn",
"who"
};
if (allowedCommands.find(command) != allowedCommands.end())
return true;
static std::vector<std::string> const allowedPrefixes = {
"accept ",
"b ",
"bank ",
"cast ",
"co ",
"disperse set ",
"e ",
"focus heal ",
"gb ",
"glyph equip ",
"lfg ",
"ll ",
"nc ",
"outfit ",
"pet ",
"q ",
"r ",
"roll ",
"rti ",
"rtsc ",
"s ",
"ss ",
"share ",
"talents apply ",
"talents spec ",
"tame ",
"t ",
"drop ",
"u ",
"ue ",
"who "
};
return std::any_of(
allowedPrefixes.begin(),
allowedPrefixes.end(),
[&command](std::string const& prefix)
{
return command.size() > prefix.size() && command.rfind(prefix, 0) == 0;
});
}
std::string ReadHttpBody(
std::string const& host,
std::string const& port,
std::string const& path,
std::string const& body)
{
using boost::asio::ip::tcp;
boost::asio::io_context ioContext;
tcp::resolver resolver(ioContext);
tcp::socket socket(ioContext);
boost::asio::connect(socket, resolver.resolve(host, port));
std::ostringstream request;
request << "POST " << path << " HTTP/1.1\r\n"
<< "Host: " << host << ':' << port << "\r\n"
<< "User-Agent: MoonWell-playerbots-ai/1.0\r\n"
<< "Content-Type: application/json; charset=utf-8\r\n"
<< "Accept: text/plain\r\n"
<< "Connection: close\r\n"
<< "Content-Length: " << body.size() << "\r\n\r\n"
<< body;
boost::asio::write(socket, boost::asio::buffer(request.str()));
boost::asio::streambuf response;
boost::asio::read_until(socket, response, "\r\n\r\n");
std::istream responseStream(&response);
std::string httpVersion;
unsigned int statusCode = 0;
std::string statusMessage;
responseStream >> httpVersion >> statusCode;
std::getline(responseStream, statusMessage);
if (!responseStream || httpVersion.rfind("HTTP/", 0) != 0)
throw std::runtime_error("invalid HTTP response");
std::string header;
while (std::getline(responseStream, header) && header != "\r")
{
}
std::ostringstream responseBody;
if (response.size())
responseBody << &response;
boost::system::error_code error;
while (boost::asio::read(socket, response, boost::asio::transfer_at_least(1), error))
responseBody << &response;
if (error != boost::asio::error::eof)
throw boost::system::system_error(error);
if (response.size())
responseBody << &response;
if (statusCode < 200 || statusCode >= 300)
{
throw std::runtime_error(
"bridge returned HTTP " + std::to_string(statusCode) + ": " + responseBody.str());
}
return responseBody.str();
}
class PlayerbotsAiBridge
{
public:
static PlayerbotsAiBridge& Instance()
{
static PlayerbotsAiBridge instance;
return instance;
}
void Start()
{
bool expected = false;
if (!_running.compare_exchange_strong(expected, true))
return;
_stopping = false;
_worker = std::thread([this] { Run(); });
LOG_INFO("server.loading", "[PlayerbotsAI] Async bridge worker started");
}
void Stop()
{
if (!_running.exchange(false))
return;
{
std::lock_guard<std::mutex> lock(_requestMutex);
_stopping = true;
}
_requestReady.notify_all();
if (_worker.joinable())
_worker.join();
std::lock_guard<std::mutex> requestLock(_requestMutex);
_requests.clear();
LOG_INFO("server.loading", "[PlayerbotsAI] Async bridge worker stopped");
}
bool Submit(AiRequest request, uint32 maxQueuedRequests)
{
if (!_running)
return false;
std::lock_guard<std::mutex> lock(_requestMutex);
if (_stopping || _requests.size() >= maxQueuedRequests)
return false;
_requests.push_back(std::move(request));
_requestReady.notify_one();
return true;
}
std::deque<AiResponse> TakeResponses()
{
std::lock_guard<std::mutex> lock(_responseMutex);
std::deque<AiResponse> responses;
responses.swap(_responses);
return responses;
}
private:
PlayerbotsAiBridge() = default;
~PlayerbotsAiBridge()
{
Stop();
}
void Run()
{
while (true)
{
AiRequest request;
{
std::unique_lock<std::mutex> lock(_requestMutex);
_requestReady.wait(lock, [this] { return _stopping || !_requests.empty(); });
if (_stopping && _requests.empty())
break;
request = std::move(_requests.front());
_requests.pop_front();
}
try
{
BridgeResponse response = ParseBridgeResponse(ReadHttpBody(
request.host, request.port, request.path, request.body));
std::lock_guard<std::mutex> lock(_responseMutex);
_responses.push_back({
request.botGuid,
request.playerGuid,
request.teamId,
std::move(request.channelName),
std::move(response.command),
std::move(response.text)
});
}
catch (std::exception const& error)
{
LOG_ERROR("server.loading", "[PlayerbotsAI] Bridge request failed: {}", error.what());
}
}
}
std::atomic<bool> _running{false};
bool _stopping{false};
std::thread _worker;
std::mutex _requestMutex;
std::condition_variable _requestReady;
std::deque<AiRequest> _requests;
std::mutex _responseMutex;
std::deque<AiResponse> _responses;
};
bool IsEnabled()
{
return sConfigMgr->GetOption<bool>("PlayerbotsAI.Enabled", false);
}
bool IsAvailableForAll()
{
return sConfigMgr->GetOption<bool>("PlayerbotsAI.AvailableForAll", true);
}
AiRequest BuildRequest(
Player* bot,
Player* player,
std::string channelName,
std::string const& message)
{
std::ostringstream body;
body << '{'
<< "\"bot_guid\":\"" << bot->GetGUID().GetCounter() << "\","
<< "\"player_guid\":\"" << player->GetGUID().GetCounter() << "\","
<< "\"bot_name\":\"" << JsonEscape(bot->GetName()) << "\","
<< "\"player_name\":\"" << JsonEscape(player->GetName()) << "\","
<< "\"message\":\"" << JsonEscape(message) << "\","
<< "\"bot_gender\":" << static_cast<uint32>(bot->getGender()) << ','
<< "\"player_gender\":" << static_cast<uint32>(player->getGender()) << ','
<< "\"bot_class\":" << static_cast<uint32>(bot->getClass()) << ','
<< "\"bot_race\":" << static_cast<uint32>(bot->getRace()) << ','
<< "\"bot_level\":" << static_cast<uint32>(bot->GetLevel()) << ','
<< "\"zone_id\":" << bot->GetZoneId()
<< '}';
return {
bot->GetGUID(),
player->GetGUID(),
bot->GetTeamId(),
std::move(channelName),
sConfigMgr->GetOption<std::string>("PlayerbotsAI.BridgeHost", "playerbots-ai"),
std::to_string(sConfigMgr->GetOption<uint32>("PlayerbotsAI.BridgePort", 8080)),
sConfigMgr->GetOption<std::string>("PlayerbotsAI.BridgePath", "/v1/chat"),
body.str()
};
}
class PlayerbotsAiPlayerScript : public PlayerScript
{
public:
PlayerbotsAiPlayerScript()
: PlayerScript(
"PlayerbotsAiPlayerScript",
{
PLAYERHOOK_ON_BEFORE_SEND_CHAT_MESSAGE,
PLAYERHOOK_CAN_PLAYER_USE_CHANNEL_CHAT
})
{
}
void OnPlayerBeforeSendChatMessage(
Player* player,
uint32& type,
uint32& /*language*/,
std::string& message) override
{
if (type == CHAT_MSG_SAY)
HandleAddressedMessage(player, message, nullptr);
}
bool OnPlayerCanUseChat(
Player* player,
uint32 type,
uint32 /*language*/,
std::string& message,
Channel* channel) override
{
if (type == CHAT_MSG_CHANNEL)
HandleAddressedMessage(player, message, channel);
return true;
}
private:
void HandleAddressedMessage(Player* player, std::string const& message, Channel* channel)
{
if (!IsEnabled() || !player || message.empty())
return;
if (PlayerbotsMgr::instance().GetPlayerbotAI(player))
return;
std::vector<uint32> foldedMessage = DecodeAndCaseFold(message);
Player* selectedBot = nullptr;
std::size_t selectedPosition = foldedMessage.size();
PlayerBotMap bots = sRandomPlayerbotMgr.GetAllBots();
if (PlayerbotMgr* playerbotMgr = PlayerbotsMgr::instance().GetPlayerbotMgr(player))
{
for (auto iterator = playerbotMgr->GetPlayerBotsBegin();
iterator != playerbotMgr->GetPlayerBotsEnd();
++iterator)
{
bots.emplace(iterator->first, iterator->second);
}
}
for (auto const& [guid, bot] : bots)
{
if (!bot || !bot->IsInWorld())
continue;
if (channel)
{
if (!channel->HasMember(guid))
continue;
}
else if (!bot->IsWithinDistInMap(
player, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_SAY)))
{
continue;
}
std::optional<std::size_t> position =
FindCompleteName(foldedMessage, DecodeAndCaseFold(bot->GetName()));
if (position && *position < selectedPosition)
{
selectedBot = bot;
selectedPosition = *position;
}
}
if (!selectedBot)
return;
if (!IsAvailableForAll())
{
std::string const deniedReply = "Разговоры со мной через ИИ сейчас недоступны.";
if (channel)
channel->Say(selectedBot->GetGUID(), deniedReply, LANG_UNIVERSAL);
else
selectedBot->Say(deniedReply, LANG_UNIVERSAL);
return;
}
auto now = std::chrono::steady_clock::now();
uint32 cooldownSeconds =
sConfigMgr->GetOption<uint32>("PlayerbotsAI.PlayerCooldownSeconds", 8);
auto cooldown = std::chrono::seconds(cooldownSeconds);
auto found = _lastRequest.find(player->GetGUID());
if (found != _lastRequest.end() && now - found->second < cooldown)
return;
uint32 maxQueuedRequests =
std::max<uint32>(1, sConfigMgr->GetOption<uint32>("PlayerbotsAI.MaxQueuedRequests", 32));
if (!PlayerbotsAiBridge::Instance().Submit(
BuildRequest(
selectedBot,
player,
channel ? channel->GetName() : std::string(),
message),
maxQueuedRequests))
{
LOG_WARN("server.loading", "[PlayerbotsAI] Request queue is unavailable or full");
return;
}
_lastRequest[player->GetGUID()] = now;
if (sConfigMgr->GetOption<bool>("PlayerbotsAI.Debug", false))
{
LOG_INFO(
"server.loading",
"[PlayerbotsAI] {} addressed bot {} in {}",
player->GetName(),
selectedBot->GetName(),
channel ? channel->GetName() : "/say");
}
}
std::map<ObjectGuid, std::chrono::steady_clock::time_point> _lastRequest;
};
class PlayerbotsAiWorldScript : public WorldScript
{
public:
PlayerbotsAiWorldScript()
: WorldScript(
"PlayerbotsAiWorldScript",
{WORLDHOOK_ON_STARTUP, WORLDHOOK_ON_UPDATE, WORLDHOOK_ON_SHUTDOWN})
{
}
void OnStartup() override
{
if (IsEnabled())
PlayerbotsAiBridge::Instance().Start();
}
void OnUpdate(uint32 /*diff*/) override
{
if (!IsEnabled())
return;
uint32 maxCharacters =
sConfigMgr->GetOption<uint32>("PlayerbotsAI.MaxReplyCharacters", 240);
for (AiResponse& response : PlayerbotsAiBridge::Instance().TakeResponses())
{
Player* bot = ObjectAccessor::FindPlayer(response.botGuid);
if (!bot || !bot->IsInWorld() || !PlayerbotsMgr::instance().GetPlayerbotAI(bot))
continue;
Player* player = ObjectAccessor::FindPlayer(response.playerGuid);
if (!player || !player->IsInWorld())
continue;
Channel* channel = nullptr;
if (response.channelName.empty())
{
if (!bot->IsWithinDistInMap(
player, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_SAY)))
{
continue;
}
}
else
{
ChannelMgr* channelManager = ChannelMgr::forTeam(response.teamId);
channel = channelManager
? channelManager->GetChannel(response.channelName, bot, false)
: nullptr;
if (!channel || !channel->HasMember(bot->GetGUID()))
continue;
}
if (sConfigMgr->GetOption<bool>("PlayerbotsAI.CommandsEnabled", true)
&& IsAllowedPlayerbotCommand(response.command))
{
PlayerbotAI* botAi = PlayerbotsMgr::instance().GetPlayerbotAI(bot);
botAi->HandleCommand(CHAT_MSG_WHISPER, response.command, player);
}
std::string reply = NormalizeReply(std::move(response.text), maxCharacters);
if (!reply.empty())
{
if (channel)
channel->Say(bot->GetGUID(), reply, LANG_UNIVERSAL);
else
bot->Say(reply, LANG_UNIVERSAL);
}
}
}
void OnShutdown() override
{
PlayerbotsAiBridge::Instance().Stop();
}
};
}
void AddSC_mod_playerbots_ai()
{
new PlayerbotsAiPlayerScript();
new PlayerbotsAiWorldScript();
}
@@ -0,0 +1,6 @@
void AddSC_mod_playerbots_ai();
void Addmod_playerbots_aiScripts()
{
AddSC_mod_playerbots_ai();
}
@@ -55,7 +55,7 @@ bool AcceptInvitationAction::Execute(Event event)
botAI->ChangeStrategy("+follow,-lfg,-bg", BOT_STATE_NON_COMBAT); botAI->ChangeStrategy("+follow,-lfg,-bg", BOT_STATE_NON_COMBAT);
botAI->Reset(); botAI->Reset();
botAI->TellMaster("Hello"); botAI->TellMaster("Здравствуйте.");
if (sPlayerbotAIConfig.summonWhenGroup && bot->GetDistance(inviter) > sPlayerbotAIConfig.sightDistance) if (sPlayerbotAIConfig.summonWhenGroup && bot->GetDistance(inviter) > sPlayerbotAIConfig.sightDistance)
{ {
@@ -18,7 +18,7 @@ bool AcceptAllQuestsAction::ProcessQuest(Quest const* quest, Object* questGiver)
if (botAI->HasStrategy("debug quest", BotState::BOT_STATE_NON_COMBAT) || botAI->HasStrategy("debug rpg", BotState::BOT_STATE_COMBAT)) if (botAI->HasStrategy("debug quest", BotState::BOT_STATE_NON_COMBAT) || botAI->HasStrategy("debug rpg", BotState::BOT_STATE_COMBAT))
{ {
LOG_INFO("playerbots", "{} => Quest [{}] accepted", bot->GetName(), quest->GetTitle()); LOG_INFO("playerbots", "{} => Quest [{}] accepted", bot->GetName(), quest->GetTitle());
bot->Say("Quest [" + text_quest + "] accepted", LANG_UNIVERSAL); bot->Say("Задание [" + text_quest + "] accepted", LANG_UNIVERSAL);
} }
return true; return true;
@@ -113,7 +113,7 @@ bool AcceptQuestShareAction::Execute(Event event)
if (bot->HasQuest(quest)) if (bot->HasQuest(quest))
{ {
bot->SetDivider(ObjectGuid::Empty); bot->SetDivider(ObjectGuid::Empty);
botAI->TellError("I have this quest"); botAI->TellError("У меня уже есть это задание");
return false; return false;
} }
@@ -121,7 +121,7 @@ bool AcceptQuestShareAction::Execute(Event event)
{ {
// can't take quest // can't take quest
bot->SetDivider(ObjectGuid::Empty); bot->SetDivider(ObjectGuid::Empty);
botAI->TellError("I can't take this quest"); botAI->TellError("Я не могу взять это задание");
return false; return false;
} }
@@ -149,7 +149,7 @@ bool AcceptQuestShareAction::Execute(Event event)
bot->CastSpell(bot, qInfo->GetSrcSpell(), true); bot->CastSpell(bot, qInfo->GetSrcSpell(), true);
} }
botAI->TellMaster("Quest accepted"); botAI->TellMaster("Задание принято.");
return true; return true;
} }
@@ -36,7 +36,7 @@ bool ReachAreaTriggerAction::Execute(Event event)
if (bot->GetMapId() != at->map) if (bot->GetMapId() != at->map)
{ {
botAI->TellError("I won't follow: too far away"); botAI->TellError("Я не последую за вами: вы слишком далеко");
return true; return true;
} }
@@ -51,7 +51,7 @@ bool ReachAreaTriggerAction::Execute(Event event)
float distance = bot->GetDistance(at->x, at->y, at->z); float distance = bot->GetDistance(at->x, at->y, at->z);
float delay = 1000.0f * distance / bot->GetSpeed(MOVE_RUN) + sPlayerbotAIConfig.reactDelay; float delay = 1000.0f * distance / bot->GetSpeed(MOVE_RUN) + sPlayerbotAIConfig.reactDelay;
botAI->TellError("Wait for me"); botAI->TellError("Подождите меня");
botAI->SetNextCheckDelay(delay); botAI->SetNextCheckDelay(delay);
context->GetValue<LastMovement&>("last area trigger")->Get().lastAreaTrigger = triggerId; context->GetValue<LastMovement&>("last area trigger")->Get().lastAreaTrigger = triggerId;
@@ -76,6 +76,6 @@ bool AreaTriggerAction::Execute(Event /*event*/)
p.rpos(0); p.rpos(0);
bot->GetSession()->HandleAreaTriggerOpcode(p); bot->GetSession()->HandleAreaTriggerOpcode(p);
botAI->TellMaster("Hello"); botAI->TellMaster("Здравствуйте.");
return true; return true;
} }
@@ -31,7 +31,7 @@ bool ArenaTeamAcceptAction::Execute(Event event)
if (bot->GetArenaTeamId(at->GetSlot())) if (bot->GetArenaTeamId(at->GetSlot()))
{ {
// bot is already in an arena team // bot is already in an arena team
bot->Say("Sorry, I am already in such team", LANG_UNIVERSAL); bot->Say("У меня уже есть такая команда", LANG_UNIVERSAL);
accept = false; accept = false;
} }
@@ -39,7 +39,7 @@ bool ArenaTeamAcceptAction::Execute(Event event)
{ {
WorldPacket data(CMSG_ARENA_TEAM_ACCEPT); WorldPacket data(CMSG_ARENA_TEAM_ACCEPT);
bot->GetSession()->HandleArenaTeamAcceptOpcode(data); bot->GetSession()->HandleArenaTeamAcceptOpcode(data);
bot->Say("Thanks for the invite!", LANG_UNIVERSAL); bot->Say("Спасибо за приглашение!", LANG_UNIVERSAL);
LOG_INFO("playerbots", "Bot {} <{}> accepts Arena Team invite", bot->GetGUID().ToString().c_str(), LOG_INFO("playerbots", "Bot {} <{}> accepts Arena Team invite", bot->GetGUID().ToString().c_str(),
bot->GetName().c_str()); bot->GetName().c_str());
return true; return true;
@@ -37,7 +37,7 @@ bool AttackMyTargetAction::Execute(Event /*event*/)
if (!guid) if (!guid)
{ {
if (verbose) if (verbose)
botAI->TellError("You have no target"); botAI->TellError("У вас нет цели");
return false; return false;
} }
@@ -63,7 +63,7 @@ bool AttackAction::Attack(Unit* target, bool /*with_pet*/ /*true*/)
bot->HasUnitState(UNIT_STATE_IN_FLIGHT)) bot->HasUnitState(UNIT_STATE_IN_FLIGHT))
{ {
if (verbose) if (verbose)
botAI->TellError("I cannot attack in flight"); botAI->TellError("Я не могу атаковать в полёте");
return false; return false;
} }
@@ -71,7 +71,7 @@ bool AttackAction::Attack(Unit* target, bool /*with_pet*/ /*true*/)
if (!target) if (!target)
{ {
if (verbose) if (verbose)
botAI->TellError("I have no target"); botAI->TellError("У меня нет цели");
return false; return false;
} }
@@ -91,7 +91,7 @@ bool AttackAction::Attack(Unit* target, bool /*with_pet*/ /*true*/)
sPlayerbotAIConfig.IsPvpProhibited(target->GetZoneId(), target->GetAreaId()))) sPlayerbotAIConfig.IsPvpProhibited(target->GetZoneId(), target->GetAreaId())))
{ {
if (verbose) if (verbose)
botAI->TellError("I cannot attack other players in PvP prohibited areas."); botAI->TellError("Я не могу атаковать игроков в зонах, где запрещено PvP.");
return false; return false;
} }
@@ -123,7 +123,7 @@ bool AttackAction::Attack(Unit* target, bool /*with_pet*/ /*true*/)
if (sameTarget && inCombat && sameAttackMode) if (sameTarget && inCombat && sameAttackMode)
{ {
if (verbose) if (verbose)
botAI->TellError("I am already attacking " + std::string(target->GetName()) + "."); botAI->TellError("Я уже атакую: " + std::string(target->GetName()) + ".");
return false; return false;
} }
@@ -131,7 +131,7 @@ bool AttackAction::Attack(Unit* target, bool /*with_pet*/ /*true*/)
if (!bot->IsValidAttackTarget(target)) if (!bot->IsValidAttackTarget(target))
{ {
if (verbose) if (verbose)
botAI->TellError("I cannot attack an invalid target."); botAI->TellError("Я не могу атаковать недопустимую цель.");
return false; return false;
} }
@@ -54,7 +54,7 @@ void AutoMaintenanceOnLevelupAction::AutoLearnSpell()
{ {
std::string const temp = out.str(); std::string const temp = out.str();
out.seekp(0); out.seekp(0);
out << "Learned spells: "; out << "Изученные заклинания: ";
out << temp; out << temp;
out.seekp(-2, out.cur); out.seekp(-2, out.cur);
out << "."; out << ".";
@@ -23,7 +23,7 @@ bool BankAction::Execute(Event event)
return ExecuteBank(text, npc); return ExecuteBank(text, npc);
} }
botAI->TellError("Cannot find banker nearby"); botAI->TellError("Поблизости нет банкира");
return false; return false;
} }
@@ -82,7 +82,7 @@ bool BankAction::Withdraw(uint32 itemid)
bot->StoreItem(dest, pItem, true); bot->StoreItem(dest, pItem, true);
std::ostringstream out; std::ostringstream out;
out << "got " << chat->FormatItem(pItem->GetTemplate(), pItem->GetCount()) << " from bank"; out << "получено: " << chat->FormatItem(pItem->GetTemplate(), pItem->GetCount()) << " из банка";
botAI->TellMaster(out.str()); botAI->TellMaster(out.str());
return true; return true;
} }
@@ -102,14 +102,14 @@ bool BankAction::Deposit(Item* pItem)
bot->RemoveItem(pItem->GetBagSlot(), pItem->GetSlot(), true); bot->RemoveItem(pItem->GetBagSlot(), pItem->GetSlot(), true);
bot->BankItem(dest, pItem, true); bot->BankItem(dest, pItem, true);
out << "put " << chat->FormatItem(pItem->GetTemplate(), pItem->GetCount()) << " to bank"; out << "помещено: " << chat->FormatItem(pItem->GetTemplate(), pItem->GetCount()) << " в банк";
botAI->TellMaster(out.str()); botAI->TellMaster(out.str());
return true; return true;
} }
void BankAction::ListItems() void BankAction::ListItems()
{ {
botAI->TellMaster("=== Bank ==="); botAI->TellMaster("=== Банк ===");
std::map<uint32, uint32> items; std::map<uint32, uint32> items;
std::map<uint32, bool> soulbound; std::map<uint32, bool> soulbound;
@@ -1278,13 +1278,13 @@ bool BGTactics::HandleConsoleCommand(ChatHandler* handler, char const* args)
{ {
if (!sPlayerbotAIConfig.enabled) if (!sPlayerbotAIConfig.enabled)
{ {
handler->PSendSysMessage("|cffff0000Playerbot system is currently disabled!"); handler->PSendSysMessage("|cffff0000Система Playerbot сейчас отключена!");
return true; return true;
} }
WorldSession* session = handler->GetSession(); WorldSession* session = handler->GetSession();
if (!session) if (!session)
{ {
handler->PSendSysMessage("Command can only be used from an active session"); handler->PSendSysMessage("Команду можно использовать только из активной игровой сессии");
return true; return true;
} }
std::string const commandOutput = HandleConsoleCommandPrivate(session, args); std::string const commandOutput = HandleConsoleCommandPrivate(session, args);
@@ -4304,7 +4304,7 @@ bool ArenaTactics::Execute(Event /*event*/)
float x, y, z; float x, y, z;
target->GetPosition(x, y, z); target->GetPosition(x, y, z);
botAI->TellMasterNoFacing("Repositioning to exit the LoS target!"); botAI->TellMasterNoFacing("Меняю позицию, чтобы выйти из поля зрения цели!");
return MoveTo(target->GetMapId(), x + frand(-1, +1), y + frand(-1, +1), z, false, true); return MoveTo(target->GetMapId(), x + frand(-1, +1), y + frand(-1, +1), z, false, true);
} }
} }
@@ -64,19 +64,19 @@ void BuffAction::TellHeader(uint32 subClass)
switch (subClass) switch (subClass)
{ {
case ITEM_SUBCLASS_ELIXIR: case ITEM_SUBCLASS_ELIXIR:
botAI->TellMaster("--- Elixir ---"); botAI->TellMaster("--- Эликсиры ---");
return; return;
case ITEM_SUBCLASS_FLASK: case ITEM_SUBCLASS_FLASK:
botAI->TellMaster("--- Flask ---"); botAI->TellMaster("--- Настои ---");
return; return;
case ITEM_SUBCLASS_SCROLL: case ITEM_SUBCLASS_SCROLL:
botAI->TellMaster("--- Scroll ---"); botAI->TellMaster("--- Свитки ---");
return; return;
case ITEM_SUBCLASS_FOOD: case ITEM_SUBCLASS_FOOD:
botAI->TellMaster("--- Food ---"); botAI->TellMaster("--- Еда ---");
return; return;
case ITEM_SUBCLASS_ITEM_ENHANCEMENT: case ITEM_SUBCLASS_ITEM_ENHANCEMENT:
botAI->TellMaster("--- Enchant ---"); botAI->TellMaster("--- Чары ---");
return; return;
} }
} }
@@ -197,7 +197,7 @@ bool BuyAction::Execute(Event event)
if (!result) if (!result)
{ {
std::ostringstream out; std::ostringstream out;
out << "Nobody sells " << ChatHelper::FormatItem(proto) << " nearby"; out << "Никто не продаёт: " << ChatHelper::FormatItem(proto) << " поблизости";
botAI->TellMaster(out.str()); botAI->TellMaster(out.str());
continue; continue;
} }
@@ -215,7 +215,7 @@ bool BuyAction::Execute(Event event)
if (!vendored) if (!vendored)
{ {
botAI->TellError("There are no vendors nearby"); botAI->TellError("Поблизости нет торговцев");
return false; return false;
} }
@@ -248,7 +248,7 @@ bool BuyAction::BuyItem(VendorItemData const* tItems, ObjectGuid vendorguid, Ite
if (newCount > oldCount) if (newCount > oldCount)
{ {
std::ostringstream out; std::ostringstream out;
out << "Buying " << ChatHelper::FormatItem(proto); out << "Покупаю: " << ChatHelper::FormatItem(proto);
botAI->TellMaster(out.str()); botAI->TellMaster(out.str());
return true; return true;
} }
@@ -117,7 +117,7 @@ bool CastCustomSpellAction::Execute(Event event)
std::ostringstream msg; std::ostringstream msg;
if (!spell) if (!spell)
{ {
msg << "Unknown spell " << text; msg << "Неизвестное заклинание: " << text;
botAI->TellError(msg.str()); botAI->TellError(msg.str());
return false; return false;
} }
@@ -125,7 +125,7 @@ bool CastCustomSpellAction::Execute(Event event)
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spell); SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spell);
if (!spellInfo) if (!spellInfo)
{ {
msg << "Unknown spell " << text; msg << "Неизвестное заклинание: " << text;
botAI->TellError(msg.str()); botAI->TellError(msg.str());
return false; return false;
} }
@@ -154,7 +154,7 @@ bool CastCustomSpellAction::Execute(Event event)
if (!bot->GetTrader() && !botAI->CanCastSpell(spell, target, true, itemTarget)) if (!bot->GetTrader() && !botAI->CanCastSpell(spell, target, true, itemTarget))
{ {
msg << "Cannot cast " << spellName.str(); msg << "Не удалось применить: " << spellName.str();
botAI->TellError(msg.str()); botAI->TellError(msg.str());
return false; return false;
} }
@@ -162,7 +162,7 @@ bool CastCustomSpellAction::Execute(Event event)
bool result = spell ? botAI->CastSpell(spell, target, itemTarget) : botAI->CastSpell(text, target, itemTarget); bool result = spell ? botAI->CastSpell(spell, target, itemTarget) : botAI->CastSpell(text, target, itemTarget);
if (result) if (result)
{ {
msg << "Casting " << spellName.str(); msg << "Применяю: " << spellName.str();
if (castCount > 1) if (castCount > 1)
{ {
@@ -176,7 +176,7 @@ bool CastCustomSpellAction::Execute(Event event)
} }
else else
{ {
msg << "Cast " << spellName.str() << " is failed"; msg << "Применение " << spellName.str() << " завершилось ошибкой";
botAI->TellError(msg.str()); botAI->TellError(msg.str());
} }
@@ -15,7 +15,7 @@ bool ChangeChatAction::Execute(Event event)
if (parsed == CHAT_MSG_SYSTEM) if (parsed == CHAT_MSG_SYSTEM)
{ {
std::ostringstream out; std::ostringstream out;
out << "Current chat is " << chat->FormatChat(*context->GetValue<ChatMsg>("chat")); out << "Текущий канал чата: " << chat->FormatChat(*context->GetValue<ChatMsg>("chat"));
botAI->TellMaster(out); botAI->TellMaster(out);
} }
else else
@@ -23,7 +23,7 @@ bool ChangeChatAction::Execute(Event event)
context->GetValue<ChatMsg>("chat")->Set(parsed); context->GetValue<ChatMsg>("chat")->Set(parsed);
std::ostringstream out; std::ostringstream out;
out << "Chat set to " << chat->FormatChat(parsed); out << "Канал чата установлен: " << chat->FormatChat(parsed);
botAI->TellMaster(out); botAI->TellMaster(out);
} }
@@ -45,7 +45,7 @@ bool ChangeNonCombatStrategyAction::Execute(Event event)
{ {
if (text.find("loot") != std::string::npos || text.find("gather") != std::string::npos) if (text.find("loot") != std::string::npos || text.find("gather") != std::string::npos)
{ {
botAI->TellError("You can change any strategy except loot and gather"); botAI->TellError("Можно изменять любую стратегию, кроме loot и gather");
return false; return false;
} }
} }
@@ -38,7 +38,7 @@ bool ChangeTalentsAction::Execute(Event event)
if (param.find("switch 1") != std::string::npos) if (param.find("switch 1") != std::string::npos)
{ {
bot->ActivateSpec(0); bot->ActivateSpec(0);
out << "Active first talent"; out << "Активирован первый набор талантов";
botAI->ResetStrategies(); botAI->ResetStrategies();
} }
else if (param.find("switch 2") != std::string::npos) else if (param.find("switch 2") != std::string::npos)
@@ -49,7 +49,7 @@ bool ChangeTalentsAction::Execute(Event event)
bot->CastSpell(bot, 63624, true, nullptr, nullptr, bot->GetGUID()); bot->CastSpell(bot, 63624, true, nullptr, nullptr, bot->GetGUID());
} }
bot->ActivateSpec(1); bot->ActivateSpec(1);
out << "Active second talent"; out << "Активирован второй набор талантов";
botAI->ResetStrategies(); botAI->ResetStrategies();
} }
} }
@@ -57,7 +57,7 @@ bool ChangeTalentsAction::Execute(Event event)
{ {
PlayerbotFactory factory(bot, bot->GetLevel()); PlayerbotFactory factory(bot, bot->GetLevel());
factory.InitTalentsTree(true); factory.InitTalentsTree(true);
out << "Auto pick talents"; out << "Автоматический выбор талантов включён";
botAI->ResetStrategies(); botAI->ResetStrategies();
} }
else if (param.find("spec list") != std::string::npos) else if (param.find("spec list") != std::string::npos)
@@ -78,13 +78,13 @@ bool ChangeTalentsAction::Execute(Event event)
} }
else else
{ {
out << "Unknown command."; out << "Неизвестная команда.";
} }
} }
else else
{ {
uint32 tab = AiFactory::GetPlayerSpecTab(bot); uint32 tab = AiFactory::GetPlayerSpecTab(bot);
out << "My current talent spec is: " out << "Моя текущая специализация: "
<< "|h|cffffffff"; << "|h|cffffffff";
out << chat->FormatClass(bot, tab) << "\n"; out << chat->FormatClass(bot, tab) << "\n";
out << TalentsHelp(); out << TalentsHelp();
@@ -98,7 +98,7 @@ bool ChangeTalentsAction::Execute(Event event)
std::string ChangeTalentsAction::TalentsHelp() std::string ChangeTalentsAction::TalentsHelp()
{ {
std::ostringstream out; std::ostringstream out;
out << "Talents usage: talents switch <1/2>, talents autopick, talents spec list, " out << "Команды талантов: talents switch <1/2>, talents autopick, talents spec list, "
"talents spec <specName>, talents apply <link>."; "talents spec <specName>, talents apply <link>.";
return out.str(); return out.str();
} }
@@ -127,7 +127,7 @@ std::string ChangeTalentsAction::SpecList()
out << tabCount[0] << "-" << tabCount[1] << "-" << tabCount[2] << ")"; out << tabCount[0] << "-" << tabCount[1] << "-" << tabCount[2] << ")";
botAI->TellMasterNoFacing(out.str()); botAI->TellMasterNoFacing(out.str());
} }
out << "Total " << specFound << " specs found"; out << "Найдено: " << specFound << " специализаций";
return out.str(); return out.str();
} }
@@ -149,12 +149,12 @@ std::string ChangeTalentsAction::SpecPick(std::string param)
factory.InitGlyphs(false); factory.InitGlyphs(false);
std::ostringstream out; std::ostringstream out;
out << "Picking " << sPlayerbotAIConfig.premadeSpecName[cls][specNo]; out << "Выбираю: " << sPlayerbotAIConfig.premadeSpecName[cls][specNo];
return out.str(); return out.str();
} }
} }
std::ostringstream out; std::ostringstream out;
out << "Spec " << param << " not found"; out << "Специализация " << param << " не найдена";
return out.str(); return out.str();
} }
@@ -165,11 +165,11 @@ std::string ChangeTalentsAction::SpecApply(std::string param)
std::vector<std::vector<uint32>> parsedSpecLink = PlayerbotAIConfig::ParseTempTalentsOrder(cls, param); std::vector<std::vector<uint32>> parsedSpecLink = PlayerbotAIConfig::ParseTempTalentsOrder(cls, param);
if (parsedSpecLink.size() == 0) if (parsedSpecLink.size() == 0)
{ {
out << "Invalid link " << param; out << "Неверная ссылка: " << param;
return out.str(); return out.str();
} }
PlayerbotFactory::InitTalentsByParsedSpecLink(bot, parsedSpecLink, true); PlayerbotFactory::InitTalentsByParsedSpecLink(bot, parsedSpecLink, true);
out << "Applying " << param; out << "Применяю: " << param;
return out.str(); return out.str();
} }
@@ -89,7 +89,7 @@ bool FollowChatShortcutAction::Execute(Event /*event*/)
if (moved) if (moved)
{ {
botAI->TellMaster("Following"); botAI->TellMaster("Следую за целью.");
return true; return true;
} }
} }
@@ -101,10 +101,10 @@ bool FollowChatShortcutAction::Execute(Event /*event*/)
if (bot->isDead()) if (bot->isDead())
{ {
bot->ResurrectPlayer(1.0f, false); bot->ResurrectPlayer(1.0f, false);
botAI->TellMasterNoFacing("Back from the grave!"); botAI->TellMasterNoFacing("Возвращение из могилы!");
} }
else else
botAI->TellMaster("You are too far away from me! I will there soon."); botAI->TellMaster("Вы слишком далеко! Я скоро подойду.");
bot->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_TELEPORTED | AURA_INTERRUPT_FLAG_CHANGE_MAP); bot->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_TELEPORTED | AURA_INTERRUPT_FLAG_CHANGE_MAP);
bot->TeleportTo(master->GetMapId(), master->GetPositionX(), master->GetPositionY(), master->GetPositionZ(), bot->TeleportTo(master->GetMapId(), master->GetPositionX(), master->GetPositionY(), master->GetPositionZ(),
@@ -112,7 +112,7 @@ bool FollowChatShortcutAction::Execute(Event /*event*/)
} }
*/ */
botAI->TellMaster("Following"); botAI->TellMaster("Следую за целью.");
return true; return true;
} }
@@ -129,7 +129,7 @@ bool StayChatShortcutAction::Execute(Event /*event*/)
SetReturnPosition(bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ()); SetReturnPosition(bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ());
SetStayPosition(bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ()); SetStayPosition(bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ());
botAI->TellMaster("Staying"); botAI->TellMaster("Остаюсь на месте.");
return true; return true;
} }
@@ -144,7 +144,7 @@ bool MoveFromGroupChatShortcutAction::Execute(Event /*event*/)
botAI->ChangeStrategy("+move from group", BOT_STATE_NON_COMBAT); botAI->ChangeStrategy("+move from group", BOT_STATE_NON_COMBAT);
botAI->ChangeStrategy("+move from group", BOT_STATE_COMBAT); botAI->ChangeStrategy("+move from group", BOT_STATE_COMBAT);
botAI->TellMaster("Moving away from group"); botAI->TellMaster("Отхожу от группы");
return true; return true;
} }
@@ -163,11 +163,11 @@ bool FleeChatShortcutAction::Execute(Event /*event*/)
if (bot->GetMapId() != master->GetMapId() || bot->GetDistance(master) > sPlayerbotAIConfig.sightDistance) if (bot->GetMapId() != master->GetMapId() || bot->GetDistance(master) > sPlayerbotAIConfig.sightDistance)
{ {
botAI->TellError("I will not flee with you - too far away"); botAI->TellError("Я не могу отступать вместе с вами — вы слишком далеко");
return true; return true;
} }
botAI->TellMaster("Fleeing"); botAI->TellMaster("Отступаю.");
return true; return true;
} }
@@ -184,7 +184,7 @@ bool GoawayChatShortcutAction::Execute(Event /*event*/)
ResetReturnPosition(); ResetReturnPosition();
ResetStayPosition(); ResetStayPosition();
botAI->TellMaster("Running away"); botAI->TellMaster("Отступаю");
return true; return true;
} }
@@ -200,7 +200,7 @@ bool GrindChatShortcutAction::Execute(Event /*event*/)
ResetReturnPosition(); ResetReturnPosition();
ResetStayPosition(); ResetStayPosition();
botAI->TellMaster("Grinding"); botAI->TellMaster("Фармлю.");
return true; return true;
} }
@@ -220,7 +220,7 @@ bool TankAttackChatShortcutAction::Execute(Event /*event*/)
ResetReturnPosition(); ResetReturnPosition();
ResetStayPosition(); ResetStayPosition();
botAI->TellMaster("Attacking"); botAI->TellMaster("Атакую.");
return true; return true;
} }
@@ -236,7 +236,7 @@ bool MaxDpsChatShortcutAction::Execute(Event /*event*/)
botAI->Reset(); botAI->Reset();
botAI->ChangeStrategy("-threat,-conserve mana,-cast time,+dps debuff,+boost", BOT_STATE_COMBAT); botAI->ChangeStrategy("-threat,-conserve mana,-cast time,+dps debuff,+boost", BOT_STATE_COMBAT);
botAI->TellMaster("Max DPS!"); botAI->TellMaster("Максимальный урон!");
return true; return true;
} }
@@ -250,6 +250,6 @@ bool BwlChatShortcutAction::Execute(Event /*event*/)
botAI->Reset(); botAI->Reset();
botAI->ChangeStrategy("+bwl", BOT_STATE_NON_COMBAT); botAI->ChangeStrategy("+bwl", BOT_STATE_NON_COMBAT);
botAI->ChangeStrategy("+bwl", BOT_STATE_COMBAT); botAI->ChangeStrategy("+bwl", BOT_STATE_COMBAT);
botAI->TellMasterNoFacing("Add Bwl Strategies!"); botAI->TellMasterNoFacing("Стратегии Логова Крыла Тьмы включены!");
return true; return true;
} }
@@ -258,7 +258,7 @@ bool ChooseRpgTargetAction::Execute(Event /*event*/)
if (botAI->HasStrategy("debug", BOT_STATE_NON_COMBAT) && guidP.GetWorldObject()) if (botAI->HasStrategy("debug", BOT_STATE_NON_COMBAT) && guidP.GetWorldObject())
{ {
std::ostringstream out; std::ostringstream out;
out << "found: "; out << "найдено: ";
out << chat->FormatWorldobject(guidP.GetWorldObject()); out << chat->FormatWorldobject(guidP.GetWorldObject());
out << " " << relevances.front(); out << " " << relevances.front();
@@ -169,7 +169,7 @@ bool AttackRtiTargetAction::Execute(Event /*event*/)
} }
} }
else else
botAI->TellError("I dont see my rti attack target"); botAI->TellError("Я не вижу назначенную групповую цель для атаки");
return false; return false;
} }
@@ -244,15 +244,15 @@ void ChooseTravelTargetAction::ReportTravelTarget(TravelTarget* newTarget, Trave
std::string Sub; std::string Sub;
if (newTarget->isGroupCopy()) if (newTarget->isGroupCopy())
out << "Following group "; out << "Следую за группой: ";
else if (oldDestination && oldDestination == destination) else if (oldDestination && oldDestination == destination)
out << "Continuing "; out << "Продолжаю: ";
else else
out << "Traveling "; out << "Путешествую: ";
out << round(newTarget->getDestination()->distanceTo(&botLocation)) << "y"; out << round(newTarget->getDestination()->distanceTo(&botLocation)) << "y";
out << " for " << chat->FormatQuest(quest); out << " за " << chat->FormatQuest(quest);
out << " to " << QuestDestination->getTitle(); out << " to " << QuestDestination->getTitle();
@@ -265,20 +265,20 @@ void ChooseTravelTargetAction::ReportTravelTarget(TravelTarget* newTarget, Trave
WorldPosition botLocation(bot); WorldPosition botLocation(bot);
if (newTarget->isGroupCopy()) if (newTarget->isGroupCopy())
out << "Following group "; out << "Следую за группой: ";
else if (oldDestination && oldDestination == destination) else if (oldDestination && oldDestination == destination)
out << "Continuing "; out << "Продолжаю: ";
else else
out << "Traveling "; out << "Путешествую: ";
out << round(newTarget->getDestination()->distanceTo(&botLocation)) << "y"; out << round(newTarget->getDestination()->distanceTo(&botLocation)) << "y";
out << " for "; out << " за ";
if (AI_VALUE2(bool, "group or", "should sell,can sell")) if (AI_VALUE2(bool, "group or", "should sell,can sell"))
out << "selling items"; out << "продаю предметы";
else if (AI_VALUE2(bool, "group or", "should repair,can repair")) else if (AI_VALUE2(bool, "group or", "should repair,can repair"))
out << "repairing"; out << "ремонтируюсь";
else else
out << "rpg"; out << "rpg";
@@ -293,11 +293,11 @@ void ChooseTravelTargetAction::ReportTravelTarget(TravelTarget* newTarget, Trave
WorldPosition botLocation(bot); WorldPosition botLocation(bot);
if (newTarget->isGroupCopy()) if (newTarget->isGroupCopy())
out << "Following group "; out << "Следую за группой: ";
else if (oldDestination && oldDestination == destination) else if (oldDestination && oldDestination == destination)
out << "Continuing "; out << "Продолжаю: ";
else else
out << "Traveling "; out << "Путешествую: ";
out << round(newTarget->getDestination()->distanceTo(&botLocation)) << "y"; out << round(newTarget->getDestination()->distanceTo(&botLocation)) << "y";
@@ -314,11 +314,11 @@ void ChooseTravelTargetAction::ReportTravelTarget(TravelTarget* newTarget, Trave
WorldPosition botLocation(bot); WorldPosition botLocation(bot);
if (newTarget->isGroupCopy()) if (newTarget->isGroupCopy())
out << "Following group "; out << "Следую за группой: ";
else if (oldDestination && oldDestination == destination) else if (oldDestination && oldDestination == destination)
out << "Continuing "; out << "Продолжаю: ";
else else
out << "Traveling "; out << "Путешествую: ";
out << round(newTarget->getDestination()->distanceTo(&botLocation)) << "y"; out << round(newTarget->getDestination()->distanceTo(&botLocation)) << "y";
@@ -335,11 +335,11 @@ void ChooseTravelTargetAction::ReportTravelTarget(TravelTarget* newTarget, Trave
WorldPosition botLocation(bot); WorldPosition botLocation(bot);
if (newTarget->isGroupCopy()) if (newTarget->isGroupCopy())
out << "Following group "; out << "Следую за группой: ";
else if (oldDestination && oldDestination == destination) else if (oldDestination && oldDestination == destination)
out << "Continuing "; out << "Продолжаю: ";
else else
out << "Traveling "; out << "Путешествую: ";
out << round(newTarget->getDestination()->distanceTo(&botLocation)) << "y"; out << round(newTarget->getDestination()->distanceTo(&botLocation)) << "y";
@@ -353,7 +353,7 @@ void ChooseTravelTargetAction::ReportTravelTarget(TravelTarget* newTarget, Trave
{ {
if (!oldTarget->getDestination() || oldTarget->getDestination()->getName() != "NullTravelDestination") if (!oldTarget->getDestination() || oldTarget->getDestination()->getName() != "NullTravelDestination")
{ {
botAI->TellMaster("No where to travel. Idling a bit."); botAI->TellMaster("Некуда идти. Немного подожду.");
} }
} }
} }
@@ -31,7 +31,7 @@ bool CustomStrategyEditAction::Execute(Event event)
bool CustomStrategyEditAction::PrintHelp() bool CustomStrategyEditAction::PrintHelp()
{ {
botAI->TellMaster("=== Custom strategies ==="); botAI->TellMaster("=== Пользовательские стратегии ===");
uint32 owner = botAI->GetBot()->GetGUID().GetCounter(); uint32 owner = botAI->GetBot()->GetGUID().GetCounter();
@@ -48,7 +48,7 @@ bool CustomStrategyEditAction::PrintHelp()
} while (result->NextRow()); } while (result->NextRow());
} }
botAI->TellMaster("Usage: cs <name> <idx> <command>"); botAI->TellMaster("Использование: cs <имя> <индекс> <команда>");
return false; return false;
} }
@@ -79,7 +79,7 @@ bool DebugAction::Execute(Event event)
TravelNodeRoute route = TravelNodeMap::instance().getRoute(botPos, *points.front(), beginPath, bot); TravelNodeRoute route = TravelNodeMap::instance().getRoute(botPos, *points.front(), beginPath, bot);
std::ostringstream out; std::ostringstream out;
out << "Traveling to " << dest->getTitle() << ": "; out << "Направляюсь к: " << dest->getTitle() << ": ";
for (auto node : route.getNodes()) for (auto node : route.getNodes())
{ {
@@ -92,7 +92,7 @@ bool DebugAction::Execute(Event event)
} }
else else
{ {
botAI->TellMasterNoFacing("Destination " + destination + " not found."); botAI->TellMasterNoFacing("Точка назначения " + destination + " not found.");
return true; return true;
} }
} }
@@ -104,7 +104,7 @@ bool DebugAction::Execute(Event event)
if (!quest) if (!quest)
{ {
botAI->TellMasterNoFacing("Quest " + text.substr(6) + " not found."); botAI->TellMasterNoFacing("Задание " + text.substr(6) + " not found.");
return false; return false;
} }
@@ -164,7 +164,7 @@ bool DebugAction::Execute(Event event)
else if (text.find("bquest") != std::string::npos) else if (text.find("bquest") != std::string::npos)
{ {
std::ostringstream out; std::ostringstream out;
out << "bad quests:"; out << "ошибочные задания:";
// uint32 noT = 0, noG = 0, noO = 0; //not used, line marked for removal. // uint32 noT = 0, noG = 0, noO = 0; //not used, line marked for removal.
@@ -205,7 +205,7 @@ bool DebugAction::Execute(Event event)
endNode->setLinked(false); endNode->setLinked(false);
} }
botAI->TellMasterNoFacing("Node " + name + " created."); botAI->TellMasterNoFacing("Узел " + name + " created.");
TravelNodeMap::instance().setHasToGen(); TravelNodeMap::instance().setHasToGen();
@@ -222,12 +222,12 @@ bool DebugAction::Execute(Event event)
if (startNode->isImportant()) if (startNode->isImportant())
{ {
botAI->TellMasterNoFacing("Node can not be removed."); botAI->TellMasterNoFacing("Не удалось удалить узел.");
} }
TravelNodeMap::instance().m_nMapMtx.lock(); TravelNodeMap::instance().m_nMapMtx.lock();
TravelNodeMap::instance().removeNode(startNode); TravelNodeMap::instance().removeNode(startNode);
botAI->TellMasterNoFacing("Node removed."); botAI->TellMasterNoFacing("Узел удалён.");
TravelNodeMap::instance().m_nMapMtx.unlock(); TravelNodeMap::instance().m_nMapMtx.unlock();
TravelNodeMap::instance().setHasToGen(); TravelNodeMap::instance().setHasToGen();
@@ -51,10 +51,10 @@ bool DropQuestAction::Execute(Event event)
const Quest* pQuest = sObjectMgr->GetQuestTemplate(entry); const Quest* pQuest = sObjectMgr->GetQuestTemplate(entry);
const std::string text_quest = ChatHelper::FormatQuest(pQuest); const std::string text_quest = ChatHelper::FormatQuest(pQuest);
LOG_INFO("playerbots", "{} => Quest [ {} ] removed", bot->GetName(), pQuest->GetTitle()); LOG_INFO("playerbots", "{} => Quest [ {} ] removed", bot->GetName(), pQuest->GetTitle());
bot->Say("Quest [ " + text_quest + " ] removed", LANG_UNIVERSAL); bot->Say("Задание [ " + text_quest + " ] removed", LANG_UNIVERSAL);
} }
botAI->TellMaster("Quest removed"); botAI->TellMaster("Задание удалено.");
return true; return true;
} }
@@ -63,7 +63,7 @@ bool CleanQuestLogAction::Execute(Event event)
Player* requester = event.getOwner() ? event.getOwner() : GetMaster(); Player* requester = event.getOwner() ? event.getOwner() : GetMaster();
if (!requester) if (!requester)
{ {
botAI->TellMaster("No event owner detected"); botAI->TellMaster("Не удалось определить владельца события");
return false; return false;
} }
@@ -75,7 +75,7 @@ bool CleanQuestLogAction::Execute(Event event)
// Only output this message if "debug rpg" strategy is enabled // Only output this message if "debug rpg" strategy is enabled
if (botAI->HasStrategy("debug rpg", BotState::BOT_STATE_COMBAT)) if (botAI->HasStrategy("debug rpg", BotState::BOT_STATE_COMBAT))
{ {
botAI->TellMaster("Clean Quest Log command received, removing grey/trivial quests..."); botAI->TellMaster("Получена команда очистки журнала: удаляю серые и незначительные задания...");
} }
uint8 botLevel = bot->GetLevel(); // Get bot's level uint8 botLevel = bot->GetLevel(); // Get bot's level
@@ -127,7 +127,7 @@ bool CleanQuestLogAction::Execute(Event event)
// Output only if "debug rpg" strategy is enabled // Output only if "debug rpg" strategy is enabled
if (botAI->HasStrategy("debug rpg", BotState::BOT_STATE_COMBAT)) if (botAI->HasStrategy("debug rpg", BotState::BOT_STATE_COMBAT))
{ {
botAI->TellMaster("Quest [ " + quest->GetTitle() + " ] will be removed because it is trivial (grey)."); botAI->TellMaster("Задание [ " + quest->GetTitle() + " ] will be removed because it is trivial (grey).");
} }
// Remove quest // Remove quest
@@ -143,12 +143,12 @@ bool CleanQuestLogAction::Execute(Event event)
{ {
const std::string text_quest = ChatHelper::FormatQuest(quest); const std::string text_quest = ChatHelper::FormatQuest(quest);
LOG_INFO("playerbots", "{} => Quest [ {} ] removed", bot->GetName(), quest->GetTitle()); LOG_INFO("playerbots", "{} => Quest [ {} ] removed", bot->GetName(), quest->GetTitle());
bot->Say("Quest [ " + text_quest + " ] removed", LANG_UNIVERSAL); bot->Say("Задание [ " + text_quest + " ] removed", LANG_UNIVERSAL);
} }
if (botAI->HasStrategy("debug rpg", BotState::BOT_STATE_COMBAT)) if (botAI->HasStrategy("debug rpg", BotState::BOT_STATE_COMBAT))
{ {
botAI->TellMaster("Quest [ " + quest->GetTitle() + " ] has been removed."); botAI->TellMaster("Задание [ " + quest->GetTitle() + " ] has been removed.");
} }
} }
else else
@@ -156,7 +156,7 @@ bool CleanQuestLogAction::Execute(Event event)
// Only output if "debug rpg" strategy is enabled // Only output if "debug rpg" strategy is enabled
if (botAI->HasStrategy("debug rpg", BotState::BOT_STATE_COMBAT)) if (botAI->HasStrategy("debug rpg", BotState::BOT_STATE_COMBAT))
{ {
botAI->TellMaster("Quest [ " + quest->GetTitle() + " ] is not trivial and will be kept."); botAI->TellMaster("Задание [ " + quest->GetTitle() + " ] is not trivial and will be kept.");
} }
} }
} }
@@ -234,9 +234,9 @@ void CleanQuestLogAction::DropQuestType(uint8& numQuest, uint8 wantNum, bool isG
{ {
const std::string text_quest = ChatHelper::FormatQuest(quest); const std::string text_quest = ChatHelper::FormatQuest(quest);
LOG_INFO("playerbots", "{} => Quest [ {} ] removed", bot->GetName(), quest->GetTitle()); LOG_INFO("playerbots", "{} => Quest [ {} ] removed", bot->GetName(), quest->GetTitle());
bot->Say("Quest [ " + text_quest + " ] removed", LANG_UNIVERSAL); bot->Say("Задание [ " + text_quest + " ] removed", LANG_UNIVERSAL);
} }
botAI->TellMaster("Quest removed" + chat->FormatQuest(quest)); botAI->TellMaster("Задание удалено." + chat->FormatQuest(quest));
} }
} }
@@ -163,7 +163,7 @@ bool EmoteActionBase::ReceiveEmote(Player* source, uint32 emote, bool verbal)
if (botAI->GetMaster() == source) if (botAI->GetMaster() == source)
{ {
botAI->ChangeStrategy("-follow,+stay", BOT_STATE_NON_COMBAT); botAI->ChangeStrategy("-follow,+stay", BOT_STATE_NON_COMBAT);
botAI->TellMasterNoFacing("Fine.. I'll stay right here.."); botAI->TellMasterNoFacing("Хорошо... Останусь здесь...");
} }
break; break;
case TEXT_EMOTE_BECKON: case TEXT_EMOTE_BECKON:
@@ -171,7 +171,7 @@ bool EmoteActionBase::ReceiveEmote(Player* source, uint32 emote, bool verbal)
if (botAI->GetMaster() == source) if (botAI->GetMaster() == source)
{ {
botAI->ChangeStrategy("+follow", BOT_STATE_NON_COMBAT); botAI->ChangeStrategy("+follow", BOT_STATE_NON_COMBAT);
botAI->TellMasterNoFacing("Wherever you go, I'll follow.."); botAI->TellMasterNoFacing("Куда бы вы ни пошли, я последую за вами...");
} }
break; break;
case TEXT_EMOTE_WAVE: case TEXT_EMOTE_WAVE:
@@ -579,36 +579,36 @@ bool EmoteActionBase::ReceiveEmote(Player* source, uint32 emote, bool verbal)
break; break;
/*case TEXT_EMOTE_BADFEELING: /*case TEXT_EMOTE_BADFEELING:
bot->HandleEmoteCommand(EMOTE_ONESHOT_QUESTION); bot->HandleEmoteCommand(EMOTE_ONESHOT_QUESTION);
bot->Say("I'm just waiting for the ominous music now...", LANG_UNIVERSAL); bot->Say("Теперь осталось дождаться зловещей музыки...", LANG_UNIVERSAL);
break; break;
case TEXT_EMOTE_MAP: case TEXT_EMOTE_MAP:
bot->HandleEmoteCommand(EMOTE_ONESHOT_NO); bot->HandleEmoteCommand(EMOTE_ONESHOT_NO);
bot->Say("Noooooooo.. you just couldn't ask for directions, huh?", LANG_UNIVERSAL); bot->Say("Неееет... Нельзя было просто спросить дорогу?", LANG_UNIVERSAL);
break; break;
case TEXT_EMOTE_IDEA: case TEXT_EMOTE_IDEA:
case TEXT_EMOTE_THINK: case TEXT_EMOTE_THINK:
bot->HandleEmoteCommand(EMOTE_ONESHOT_NO); bot->HandleEmoteCommand(EMOTE_ONESHOT_NO);
bot->Say("Oh boy.. another genius idea...", LANG_UNIVERSAL); bot->Say("Ох... Ещё одна гениальная идея...", LANG_UNIVERSAL);
break; break;
case TEXT_EMOTE_OFFER: case TEXT_EMOTE_OFFER:
bot->HandleEmoteCommand(EMOTE_ONESHOT_NO); bot->HandleEmoteCommand(EMOTE_ONESHOT_NO);
bot->Say("No thanks.. I had some back at the last village", LANG_UNIVERSAL); bot->Say("Нет, спасибо... В прошлой деревне уже хватило", LANG_UNIVERSAL);
break; break;
case TEXT_EMOTE_PET: case TEXT_EMOTE_PET:
bot->HandleEmoteCommand(EMOTE_ONESHOT_ROAR); bot->HandleEmoteCommand(EMOTE_ONESHOT_ROAR);
bot->Say("Do I look like a dog to you?!", LANG_UNIVERSAL); bot->Say("Я похож на собаку?!", LANG_UNIVERSAL);
break; break;
case TEXT_EMOTE_ROLLEYES: case TEXT_EMOTE_ROLLEYES:
bot->HandleEmoteCommand(EMOTE_ONESHOT_POINT); bot->HandleEmoteCommand(EMOTE_ONESHOT_POINT);
bot->Say("Keep doing that and I'll roll those eyes right out of your head..", LANG_UNIVERSAL); bot->Say("Продолжайте — и глаза скоро закатятся навсегда...", LANG_UNIVERSAL);
break; break;
case TEXT_EMOTE_SING: case TEXT_EMOTE_SING:
bot->HandleEmoteCommand(EMOTE_ONESHOT_APPLAUD); bot->HandleEmoteCommand(EMOTE_ONESHOT_APPLAUD);
bot->Say("Lovely... just lovely..", LANG_UNIVERSAL); bot->Say("Прекрасно... Просто прекрасно...", LANG_UNIVERSAL);
break; break;
case TEXT_EMOTE_COVEREARS: case TEXT_EMOTE_COVEREARS:
bot->HandleEmoteCommand(EMOTE_ONESHOT_EXCLAMATION); bot->HandleEmoteCommand(EMOTE_ONESHOT_EXCLAMATION);
bot->Yell("You think that's going to help you?!", LANG_UNIVERSAL); bot->Yell("Думаете, это вам поможет?!", LANG_UNIVERSAL);
break;*/ break;*/
default: default:
// return false; // return false;
@@ -75,7 +75,7 @@ void EquipAction::EquipItem(Item* item)
{ {
bot->SetAmmo(itemId); bot->SetAmmo(itemId);
std::ostringstream out; std::ostringstream out;
out << "equipping " << chat->FormatItem(itemProto); out << "Надеваю: " << chat->FormatItem(itemProto);
botAI->TellMaster(out); botAI->TellMaster(out);
return; return;
} }
@@ -112,7 +112,7 @@ void EquipAction::EquipItem(Item* item)
bot->GetSession()->HandleAutoEquipItemSlotOpcode(nicePacket); bot->GetSession()->HandleAutoEquipItemSlotOpcode(nicePacket);
std::ostringstream out; std::ostringstream out;
out << "Equipping " << chat->FormatItem(itemProto) << " in ranged slot"; out << "Надеваю: " << chat->FormatItem(itemProto) << " в ячейку оружия дальнего боя";
botAI->TellMaster(out); botAI->TellMaster(out);
return; return;
} }
@@ -227,7 +227,7 @@ void EquipAction::EquipItem(Item* item)
} }
std::ostringstream out; std::ostringstream out;
out << "Equipping " << chat->FormatItem(itemProto) << " in main hand"; out << "Надеваю: " << chat->FormatItem(itemProto) << " в правую руку";
botAI->TellMaster(out); botAI->TellMaster(out);
return; return;
} }
@@ -244,7 +244,7 @@ void EquipAction::EquipItem(Item* item)
bot->GetSession()->HandleAutoEquipItemSlotOpcode(nicePacket); bot->GetSession()->HandleAutoEquipItemSlotOpcode(nicePacket);
std::ostringstream out; std::ostringstream out;
out << "Equipping " << chat->FormatItem(itemProto) << " in offhand"; out << "Надеваю: " << chat->FormatItem(itemProto) << " в левую руку";
botAI->TellMaster(out); botAI->TellMaster(out);
return; return;
} }
@@ -324,7 +324,7 @@ void EquipAction::EquipItem(Item* item)
} }
std::ostringstream out; std::ostringstream out;
out << "Equipping " << chat->FormatItem(itemProto); out << "Надеваю: " << chat->FormatItem(itemProto);
botAI->TellMaster(out); botAI->TellMaster(out);
} }
@@ -106,7 +106,7 @@ bool EquipGlyphsAction::Execute(Event event)
std::vector<GlyphInfo const*> glyphs; std::vector<GlyphInfo const*> glyphs;
if (!CollectGlyphs(itemIds, glyphs)) if (!CollectGlyphs(itemIds, glyphs))
{ {
botAI->TellMaster("Usage: glyph equip <6 glyph item IDs> (3 major, 3 minor)."); botAI->TellMaster("Использование: glyph equip <6 ID символов> (3 больших и 3 малых).");
return false; return false;
} }
@@ -144,12 +144,12 @@ bool EquipGlyphsAction::Execute(Event event)
if (!placed) if (!placed)
{ {
botAI->TellMaster("Not enought empty sockets for all glyphs."); botAI->TellMaster("Недостаточно свободных ячеек для всех символов.");
return false; return false;
} }
} }
botAI->TellMaster("Glyphs updated."); botAI->TellMaster("Символы обновлены.");
// Flag for custom glyphs // Flag for custom glyphs
botAI->GetAiObjectContext()->GetValue<bool>("custom_glyphs")->Set(true); botAI->GetAiObjectContext()->GetValue<bool>("custom_glyphs")->Set(true);
@@ -10,7 +10,7 @@
bool FlagAction::TellUsage() bool FlagAction::TellUsage()
{ {
botAI->TellError("Usage: flag cloak/helm/pvp on/set/off/clear/toggle/?"); botAI->TellError("Использование: flag cloak/helm/pvp on/set/off/clear/toggle/?");
return false; return false;
} }
@@ -130,15 +130,15 @@ bool FleeToGroupLeaderAction::Execute(Event /*event*/)
if (distance < sPlayerbotAIConfig.reactDistance * 3) if (distance < sPlayerbotAIConfig.reactDistance * 3)
{ {
if (!urand(0, 3)) if (!urand(0, 3))
botAI->TellMaster("I am close, wait for me!"); botAI->TellMaster("Я рядом, подождите меня!");
} }
else if (distance < 1000) else if (distance < 1000)
{ {
if (!urand(0, 10)) if (!urand(0, 10))
botAI->TellMaster("I heading to your position."); botAI->TellMaster("Я направляюсь к вам.");
} }
else if (!urand(0, 20)) else if (!urand(0, 20))
botAI->TellMaster("I am traveling to your position."); botAI->TellMaster("Я иду к вам.");
botAI->SetNextCheckDelay(3000); botAI->SetNextCheckDelay(3000);
@@ -112,7 +112,7 @@ bool TogglePetSpellAutoCastAction::Execute(Event /*event*/)
// Debug message if pet spells have been toggled and debug is enabled // Debug message if pet spells have been toggled and debug is enabled
if (toggled && sPlayerbotAIConfig.petChatCommandDebug == 1) if (toggled && sPlayerbotAIConfig.petChatCommandDebug == 1)
botAI->TellMaster("Pet autocast spells have been toggled."); botAI->TellMaster("Автоматическое применение способностей питомца переключено.");
return toggled; return toggled;
} }
@@ -178,7 +178,7 @@ bool SetPetStanceAction::Execute(Event /*event*/)
// If there are no controlled pets or guardians, notify the player and exit // If there are no controlled pets or guardians, notify the player and exit
if (targets.empty()) if (targets.empty())
{ {
botAI->TellError("You have no pet or guardian pet."); botAI->TellError("У вас нет питомца или стража.");
return false; return false;
} }
@@ -220,7 +220,7 @@ bool SetPetStanceAction::Execute(Event /*event*/)
// If debug is enabled in config, inform the master of the new stance // If debug is enabled in config, inform the master of the new stance
if (sPlayerbotAIConfig.petChatCommandDebug == 1) if (sPlayerbotAIConfig.petChatCommandDebug == 1)
botAI->TellMaster("Pet stance set to " + stanceText + " (applied to all pets/guardians)."); botAI->TellMaster("Режим питомца: " + stanceText + " (applied to all pets/guardians).");
return true; return true;
} }
@@ -45,13 +45,13 @@ bool GiveItemAction::Execute(Event /*event*/)
moved = true; moved = true;
std::ostringstream out; std::ostringstream out;
out << "Got " << chat->FormatItem(item->GetTemplate(), item->GetCount()) << " from " << bot->GetName(); out << "Получено: " << chat->FormatItem(item->GetTemplate(), item->GetCount()) << " от " << bot->GetName();
receiverAi->TellMasterNoFacing(out.str()); receiverAi->TellMasterNoFacing(out.str());
} }
else else
{ {
std::ostringstream out; std::ostringstream out;
out << "Cannot get " << chat->FormatItem(item->GetTemplate(), item->GetCount()) << " from " out << "Не удалось получить: " << chat->FormatItem(item->GetTemplate(), item->GetCount()) << " от "
<< bot->GetName() << "- my bags are full"; << bot->GetName() << "- my bags are full";
receiverAi->TellError(out.str()); receiverAi->TellError(out.str());
} }
@@ -30,7 +30,7 @@ bool GoAction::Execute(Event event)
Map2ZoneCoordinates(x, y, bot->GetZoneId()); Map2ZoneCoordinates(x, y, bot->GetZoneId());
std::ostringstream out; std::ostringstream out;
out << "I am at " << x << "," << y; out << "Я нахожусь в точке " << x << "," << y;
botAI->TellMaster(out.str()); botAI->TellMaster(out.str());
return true; return true;
} }
@@ -53,14 +53,14 @@ bool GoAction::Execute(Event event)
target->setForced(true); target->setForced(true);
std::ostringstream out; std::ostringstream out;
out << "Traveling to " << dest->getTitle(); out << "Направляюсь к: " << dest->getTitle();
botAI->TellMasterNoFacing(out.str()); botAI->TellMasterNoFacing(out.str());
return true; return true;
} }
else else
{ {
botAI->TellMasterNoFacing("Clearing travel target"); botAI->TellMasterNoFacing("Цель путешествия сброшена");
target->setTarget(TravelMgr::instance().nullTravelDestination, TravelMgr::instance().nullWorldPosition); target->setTarget(TravelMgr::instance().nullTravelDestination, TravelMgr::instance().nullWorldPosition);
target->setForced(false); target->setForced(false);
return true; return true;
@@ -78,12 +78,12 @@ bool GoAction::Execute(Event event)
if (ServerFacade::instance().IsDistanceGreaterThan(ServerFacade::instance().GetDistance2d(bot, go), if (ServerFacade::instance().IsDistanceGreaterThan(ServerFacade::instance().GetDistance2d(bot, go),
sPlayerbotAIConfig.reactDistance)) sPlayerbotAIConfig.reactDistance))
{ {
botAI->TellError("It is too far away"); botAI->TellError("Слишком далеко.");
return false; return false;
} }
std::ostringstream out; std::ostringstream out;
out << "Moving to " << ChatHelper::FormatGameobject(go); out << "Двигаюсь к: " << ChatHelper::FormatGameobject(go);
botAI->TellMasterNoFacing(out.str()); botAI->TellMasterNoFacing(out.str());
return MoveNear(bot->GetMapId(), go->GetPositionX(), go->GetPositionY(), go->GetPositionZ() + 0.5f, return MoveNear(bot->GetMapId(), go->GetPositionX(), go->GetPositionY(), go->GetPositionZ() + 0.5f,
sPlayerbotAIConfig.followDistance); sPlayerbotAIConfig.followDistance);
@@ -103,7 +103,7 @@ bool GoAction::Execute(Event event)
if (strstri(unit->GetName().c_str(), param.c_str())) if (strstri(unit->GetName().c_str(), param.c_str()))
{ {
std::ostringstream out; std::ostringstream out;
out << "Moving to " << unit->GetName(); out << "Двигаюсь к: " << unit->GetName();
botAI->TellMasterNoFacing(out.str()); botAI->TellMasterNoFacing(out.str());
return MoveNear(bot->GetMapId(), unit->GetPositionX(), unit->GetPositionY(), return MoveNear(bot->GetMapId(), unit->GetPositionX(), unit->GetPositionY(),
unit->GetPositionZ() + 0.5f, sPlayerbotAIConfig.followDistance); unit->GetPositionZ() + 0.5f, sPlayerbotAIConfig.followDistance);
@@ -137,7 +137,7 @@ bool GoAction::Execute(Event event)
out << x << ";" << y << ";" << z << " ="; out << x << ";" << y << ";" << z << " =";
out << "path is: "; out << "путь: ";
out << type; out << type;
@@ -179,20 +179,20 @@ bool GoAction::Execute(Event event)
if (ServerFacade::instance().IsDistanceGreaterThan(ServerFacade::instance().GetDistance2d(bot, x, y), if (ServerFacade::instance().IsDistanceGreaterThan(ServerFacade::instance().GetDistance2d(bot, x, y),
sPlayerbotAIConfig.reactDistance)) sPlayerbotAIConfig.reactDistance))
{ {
botAI->TellMaster("It is too far away"); botAI->TellMaster("Слишком далеко.");
return false; return false;
} }
if (map->IsInWater(bot->GetPhaseMask(), x, y, z, bot->GetCollisionHeight())) if (map->IsInWater(bot->GetPhaseMask(), x, y, z, bot->GetCollisionHeight()))
{ {
botAI->TellError("It is in water"); botAI->TellError("Цель находится в воде");
return false; return false;
} }
float ground = map->GetHeight(x, y, z + 0.5f); float ground = map->GetHeight(x, y, z + 0.5f);
if (ground <= INVALID_HEIGHT) if (ground <= INVALID_HEIGHT)
{ {
botAI->TellError("I can't go there"); botAI->TellError("Я не могу туда пройти");
return false; return false;
} }
@@ -200,7 +200,7 @@ bool GoAction::Execute(Event event)
Map2ZoneCoordinates(x1, y1, bot->GetZoneId()); Map2ZoneCoordinates(x1, y1, bot->GetZoneId());
std::ostringstream out; std::ostringstream out;
out << "Moving to " << x1 << "," << y1; out << "Двигаюсь к: " << x1 << "," << y1;
botAI->TellMasterNoFacing(out.str()); botAI->TellMasterNoFacing(out.str());
return MoveNear(bot->GetMapId(), x, y, z + 0.5f, sPlayerbotAIConfig.followDistance); return MoveNear(bot->GetMapId(), x, y, z + 0.5f, sPlayerbotAIConfig.followDistance);
@@ -212,16 +212,16 @@ bool GoAction::Execute(Event event)
if (ServerFacade::instance().IsDistanceGreaterThan(ServerFacade::instance().GetDistance2d(bot, pos.x, pos.y), if (ServerFacade::instance().IsDistanceGreaterThan(ServerFacade::instance().GetDistance2d(bot, pos.x, pos.y),
sPlayerbotAIConfig.reactDistance)) sPlayerbotAIConfig.reactDistance))
{ {
botAI->TellError("It is too far away"); botAI->TellError("Слишком далеко.");
return false; return false;
} }
std::ostringstream out; std::ostringstream out;
out << "Moving to position " << param; out << "Двигаюсь к позиции: " << param;
botAI->TellMasterNoFacing(out.str()); botAI->TellMasterNoFacing(out.str());
return MoveNear(bot->GetMapId(), pos.x, pos.y, pos.z + 0.5f, sPlayerbotAIConfig.followDistance); return MoveNear(bot->GetMapId(), pos.x, pos.y, pos.z + 0.5f, sPlayerbotAIConfig.followDistance);
} }
botAI->TellMaster("Whisper 'go x,y', 'go [game object]', 'go unit' or 'go position' and I will go there"); botAI->TellMaster("Напишите «go x,y», «go [объект]», «go unit» или «go position», и я отправлюсь туда");
return false; return false;
} }
@@ -83,7 +83,7 @@ bool GossipHelloAction::ProcessGossip(int32 menuToSelect, bool silent)
if (menuToSelect != -1 && !menu.GetItem(menuToSelect)) if (menuToSelect != -1 && !menu.GetItem(menuToSelect))
{ {
if (!silent) if (!silent)
botAI->TellError("Unknown gossip option"); botAI->TellError("Неизвестный вариант диалога");
return false; return false;
} }
@@ -138,7 +138,7 @@ bool GossipHelloAction::Execute(ObjectGuid guid, int32 menuToSelect, bool silent
else if (!bot->PlayerTalkClass) else if (!bot->PlayerTalkClass)
{ {
if (!silent) if (!silent)
botAI->TellError("I need to talk first"); botAI->TellError("Сначала нужно поговорить");
return false; return false;
} }
else else
@@ -28,17 +28,17 @@ bool GuildAcceptAction::Execute(Event event)
uint32 guildId = inviter->GetGuildId(); uint32 guildId = inviter->GetGuildId();
if (!guildId) if (!guildId)
{ {
botAI->TellError("You are not in a guild!"); botAI->TellError("Вы не состоите в гильдии!");
accept = false; accept = false;
} }
else if (bot->GetGuildId()) else if (bot->GetGuildId())
{ {
botAI->TellError("Sorry, I am in a guild already"); botAI->TellError("Я уже состою в гильдии");
accept = false; accept = false;
} }
else if (!botAI->GetSecurity()->CheckLevelFor(PLAYERBOT_SECURITY_INVITE, false, inviter, true)) else if (!botAI->GetSecurity()->CheckLevelFor(PLAYERBOT_SECURITY_INVITE, false, inviter, true))
{ {
botAI->TellError("Sorry, I don't want to join your guild :("); botAI->TellError("Я не хочу вступать в вашу гильдию :(");
accept = false; accept = false;
} }
@@ -17,7 +17,7 @@ bool GuildBankAction::Execute(Event event)
if (!bot->GetGuildId() || (GetMaster() && GetMaster()->GetGuildId() != bot->GetGuildId())) if (!bot->GetGuildId() || (GetMaster() && GetMaster()->GetGuildId() != bot->GetGuildId()))
{ {
botAI->TellMaster("I'm not in your guild!"); botAI->TellMaster("Я не состою в вашей гильдии!");
return false; return false;
} }
@@ -31,7 +31,7 @@ bool GuildBankAction::Execute(Event event)
return Execute(text, go); return Execute(text, go);
} }
botAI->TellMaster("Cannot find the guild bank nearby"); botAI->TellMaster("Поблизости нет банка гильдии");
return false; return false;
} }
@@ -65,11 +65,11 @@ bool GuildBankAction::MoveFromCharToBank(Item* item, GameObject* bank)
// check source pos rights (item moved to bank) // check source pos rights (item moved to bank)
if (!guild->MemberHasTabRights(bot->GetGUID(), 0, GUILD_BANK_RIGHT_DEPOSIT_ITEM)) if (!guild->MemberHasTabRights(bot->GetGUID(), 0, GUILD_BANK_RIGHT_DEPOSIT_ITEM))
out << "I can't put " << chat->FormatItem(item->GetTemplate()) out << "Я не могу положить: " << chat->FormatItem(item->GetTemplate())
<< " to guild bank. I have no rights to put items in the first guild bank tab"; << " to guild bank. I have no rights to put items in the first guild bank tab";
else else
{ {
out << chat->FormatItem(item->GetTemplate()) << " put to guild bank"; out << chat->FormatItem(item->GetTemplate()) << " положено в банк гильдии";
guild->SwapItemsWithInventory(bot, false, 0, 255, playerBag, playerSlot, 0); guild->SwapItemsWithInventory(bot, false, 0, 255, playerBag, playerSlot, 0);
} }
@@ -298,7 +298,7 @@ bool GuildLeaveAction::Execute(Event event)
Player* owner = event.getOwner(); Player* owner = event.getOwner();
if (owner && !botAI->GetSecurity()->CheckLevelFor(PLAYERBOT_SECURITY_INVITE, false, owner, true)) if (owner && !botAI->GetSecurity()->CheckLevelFor(PLAYERBOT_SECURITY_INVITE, false, owner, true))
{ {
botAI->TellError("Sorry, I am happy in my guild :)"); botAI->TellError("Меня устраивает моя гильдия :)");
return false; return false;
} }
@@ -23,7 +23,7 @@ bool HelpAction::Execute(Event /*event*/)
void HelpAction::TellChatCommands() void HelpAction::TellChatCommands()
{ {
std::ostringstream out; std::ostringstream out;
out << "Whisper any of: "; out << "Напишите одну из команд: ";
out << CombineSupported(chatContext->supports()); out << CombineSupported(chatContext->supports());
out << ", [item], [quest] or [object] link"; out << ", [item], [quest] or [object] link";
botAI->TellError(out.str()); botAI->TellError(out.str());
@@ -32,7 +32,7 @@ void HelpAction::TellChatCommands()
void HelpAction::TellStrategies() void HelpAction::TellStrategies()
{ {
std::ostringstream out; std::ostringstream out;
out << "Possible strategies (co/nc/dead commands): "; out << "Доступные стратегии (команды co/nc/dead): ";
out << CombineSupported(botAI->GetAiObjectContext()->GetSupportedStrategies()); out << CombineSupported(botAI->GetAiObjectContext()->GetSupportedStrategies());
botAI->TellError(out.str()); botAI->TellError(out.str());
} }
@@ -30,13 +30,13 @@ bool HireAction::Execute(Event /*event*/)
if (charCount >= 10) if (charCount >= 10)
{ {
botAI->TellMaster("You already have the maximum number of characters"); botAI->TellMaster("У вас уже максимальное количество персонажей");
return false; return false;
} }
if (bot->GetLevel() > master->GetLevel()) if (bot->GetLevel() > master->GetLevel())
{ {
botAI->TellMaster("You cannot hire higher level characters than you"); botAI->TellMaster("Нельзя нанять персонажа выше вашего уровня");
return false; return false;
} }
@@ -46,13 +46,13 @@ bool HireAction::Execute(Event /*event*/)
if (discount < moneyReq) if (discount < moneyReq)
{ {
std::ostringstream out; std::ostringstream out;
out << "You cannot hire me - I barely know you. Make sure you have at least " << chat->formatMoney(moneyReq) out << "Вы не можете меня нанять: мы почти не знакомы. Требуется не менее " << chat->formatMoney(moneyReq)
<< " as a trade discount"; << " as a trade discount";
botAI->TellMaster(out.str()); botAI->TellMaster(out.str());
return false; return false;
} }
botAI->TellMaster("I will join you at your next relogin"); botAI->TellMaster("Я присоединюсь после вашего следующего входа в игру");
bot->SetMoney(moneyReq); bot->SetMoney(moneyReq);
RandomPlayerbotMgr::instance().Remove(bot); RandomPlayerbotMgr::instance().Remove(bot);
@@ -130,40 +130,40 @@ void InventoryAction::TellItems(std::map<uint32, uint32> itemMap, std::map<uint3
switch (proto->Class) switch (proto->Class)
{ {
case ITEM_CLASS_CONSUMABLE: case ITEM_CLASS_CONSUMABLE:
botAI->TellMaster("--- consumable ---"); botAI->TellMaster("--- Расходуемые предметы ---");
break; break;
case ITEM_CLASS_CONTAINER: case ITEM_CLASS_CONTAINER:
botAI->TellMaster("--- container ---"); botAI->TellMaster("--- Сумки ---");
break; break;
case ITEM_CLASS_WEAPON: case ITEM_CLASS_WEAPON:
botAI->TellMaster("--- weapon ---"); botAI->TellMaster("--- Оружие ---");
break; break;
case ITEM_CLASS_ARMOR: case ITEM_CLASS_ARMOR:
botAI->TellMaster("--- armor ---"); botAI->TellMaster("--- Доспехи ---");
break; break;
case ITEM_CLASS_REAGENT: case ITEM_CLASS_REAGENT:
botAI->TellMaster("--- reagent ---"); botAI->TellMaster("--- Реагенты ---");
break; break;
case ITEM_CLASS_PROJECTILE: case ITEM_CLASS_PROJECTILE:
botAI->TellMaster("--- projectile ---"); botAI->TellMaster("--- Боеприпасы ---");
break; break;
case ITEM_CLASS_TRADE_GOODS: case ITEM_CLASS_TRADE_GOODS:
botAI->TellMaster("--- trade goods ---"); botAI->TellMaster("--- Хозяйственные товары ---");
break; break;
case ITEM_CLASS_RECIPE: case ITEM_CLASS_RECIPE:
botAI->TellMaster("--- recipe ---"); botAI->TellMaster("--- Рецепты ---");
break; break;
case ITEM_CLASS_QUIVER: case ITEM_CLASS_QUIVER:
botAI->TellMaster("--- quiver ---"); botAI->TellMaster("--- Колчаны ---");
break; break;
case ITEM_CLASS_QUEST: case ITEM_CLASS_QUEST:
botAI->TellMaster("--- quest items ---"); botAI->TellMaster("--- Предметы заданий ---");
break; break;
case ITEM_CLASS_KEY: case ITEM_CLASS_KEY:
botAI->TellMaster("--- keys ---"); botAI->TellMaster("--- Ключи ---");
break; break;
case ITEM_CLASS_MISC: case ITEM_CLASS_MISC:
botAI->TellMaster("--- other ---"); botAI->TellMaster("--- Прочее ---");
break; break;
} }
} }
@@ -438,7 +438,7 @@ bool LfgAction::Execute(Event event)
std::ostringstream out; std::ostringstream out;
if (allowedRoles[role] > 1) if (allowedRoles[role] > 1)
{ {
out << "Joining as " << placeholders["%role"] << ", " << placeholders["%spotsleft"] << " " out << "Присоединяюсь в роли: " << placeholders["%role"] << ", " << placeholders["%spotsleft"] << " "
<< placeholders["%role"] << " spots left."; << placeholders["%role"] << " spots left.";
botAI->TellMasterNoFacing(out.str()); botAI->TellMasterNoFacing(out.str());
@@ -447,7 +447,7 @@ bool LfgAction::Execute(Event event)
} }
else else
{ {
out << "Joining as " << placeholders["%role"] << "."; out << "Присоединяюсь в роли: " << placeholders["%role"] << ".";
botAI->TellMasterNoFacing(out.str()); botAI->TellMasterNoFacing(out.str());
//botAI->DoSpecificAction("autogear"); //botAI->DoSpecificAction("autogear");
@@ -86,7 +86,7 @@ bool LeaveGroupAction::Leave()
Player* master = botAI -> GetMaster(); Player* master = botAI -> GetMaster();
if (master) if (master)
botAI->TellMaster("Goodbye!", PLAYERBOT_SECURITY_TALK); botAI->TellMaster("До свидания!", PLAYERBOT_SECURITY_TALK);
botAI->LeaveOrDisbandGroup(); botAI->LeaveOrDisbandGroup();
return true; return true;
@@ -44,19 +44,19 @@ void ListQuestsAction::ListQuests(QuestListFilter filter, QuestTravelDetail trav
bool showCompleted = filter & QUEST_LIST_FILTER_COMPLETED; bool showCompleted = filter & QUEST_LIST_FILTER_COMPLETED;
if (showIncompleted) if (showIncompleted)
botAI->TellMaster("--- Incompleted quests ---"); botAI->TellMaster("--- Невыполненные задания ---");
uint32 incompleteCount = ListQuests(false, !showIncompleted, travelDetail); uint32 incompleteCount = ListQuests(false, !showIncompleted, travelDetail);
if (showCompleted) if (showCompleted)
botAI->TellMaster("--- Completed quests ---"); botAI->TellMaster("--- Выполненные задания ---");
uint32 completeCount = ListQuests(true, !showCompleted, travelDetail); uint32 completeCount = ListQuests(true, !showCompleted, travelDetail);
botAI->TellMaster("--- Summary ---"); botAI->TellMaster("--- Итого ---");
std::ostringstream out; std::ostringstream out;
out << "Total: " << (completeCount + incompleteCount) << " / 25 (incompleted: " << incompleteCount out << "Всего: " << (completeCount + incompleteCount) << " / 25 (невыполнено: " << incompleteCount
<< ", completed: " << completeCount << ")"; << ", completed: " << completeCount << ")";
botAI->TellMaster(out); botAI->TellMaster(out);
} }
@@ -284,11 +284,11 @@ bool ListSpellsAction::Execute(Event event)
if (spells.empty()) if (spells.empty())
{ {
// CHANGE: Give early feedback when no spells match the filter. // CHANGE: Give early feedback when no spells match the filter.
botAI->TellMaster("No spells found."); botAI->TellMaster("Заклинания не найдены.");
return true; return true;
} }
botAI->TellMaster("=== Spells ==="); botAI->TellMaster("=== Заклинания ===");
std::sort(spells.begin(), spells.end(), CompareSpells); std::sort(spells.begin(), spells.end(), CompareSpells);
@@ -17,11 +17,11 @@ bool LogLevelAction::Execute(Event event)
if (param != "?") if (param != "?")
{ {
value->Set(string2logLevel(param)); value->Set(string2logLevel(param));
out << "My log level set to " << logLevel2string(value->Get()); out << "Уровень журнала установлен: " << logLevel2string(value->Get());
} }
else else
{ {
out << "My log level is " << logLevel2string(value->Get()); out << "Текущий уровень журнала: " << logLevel2string(value->Get());
} }
botAI->TellMaster(out); botAI->TellMaster(out);
@@ -24,14 +24,14 @@ bool LootStrategyAction::Execute(Event event)
{ {
{ {
std::ostringstream out; std::ostringstream out;
out << "Loot strategy: "; out << "Стратегия добычи: ";
out << lootStrategy->Get()->GetName(); out << lootStrategy->Get()->GetName();
botAI->TellMaster(out); botAI->TellMaster(out);
} }
{ {
std::ostringstream out; std::ostringstream out;
out << "Always loot items: "; out << "Всегда собирать: ";
for (uint32 itemId : alwaysLootItems) for (uint32 itemId : alwaysLootItems)
{ {
@@ -54,7 +54,7 @@ bool LootStrategyAction::Execute(Event event)
lootStrategy->Set(LootStrategyValue::instance(strategy)); lootStrategy->Set(LootStrategyValue::instance(strategy));
std::ostringstream out; std::ostringstream out;
out << "Loot strategy set to " << lootStrategy->Get()->GetName(); out << "Установлена стратегия добычи: " << lootStrategy->Get()->GetName();
botAI->TellMaster(out); botAI->TellMaster(out);
return true; return true;
} }
@@ -80,12 +80,12 @@ bool LootStrategyAction::Execute(Event event)
if (j != alwaysLootItems.end()) if (j != alwaysLootItems.end())
alwaysLootItems.erase(j); alwaysLootItems.erase(j);
botAI->TellMaster("Item(s) removed from always loot list"); botAI->TellMaster("Предметы удалены из списка обязательного сбора");
} }
else else
{ {
alwaysLootItems.insert(itemid); alwaysLootItems.insert(itemid);
botAI->TellMaster("Item(s) added to always loot list"); botAI->TellMaster("Предметы добавлены в список обязательного сбора");
} }
} }
} }
@@ -17,7 +17,7 @@ class TellMailProcessor : public MailProcessor
public: public:
bool Before(PlayerbotAI* botAI) override bool Before(PlayerbotAI* botAI) override
{ {
botAI->TellMaster("=== Mailbox ==="); botAI->TellMaster("=== Почта ===");
tells.clear(); tells.clear();
return true; return true;
} }
@@ -83,7 +83,7 @@ public:
Player* bot = botAI->GetBot(); Player* bot = botAI->GetBot();
if (!CheckBagSpace(bot)) if (!CheckBagSpace(bot))
{ {
botAI->TellError("Not enough bag space"); botAI->TellError("В сумках недостаточно места");
return false; return false;
} }
@@ -256,7 +256,7 @@ bool MailAction::Execute(Event event)
if (!MailProcessor::FindMailbox(botAI)) if (!MailProcessor::FindMailbox(botAI))
{ {
botAI->TellError("There is no mailbox nearby"); botAI->TellError("Поблизости нет почтового ящика");
return false; return false;
} }
@@ -33,7 +33,7 @@ bool MoveToRpgTargetAction::Execute(Event /*event*/)
if (botAI->HasStrategy("debug rpg", BOT_STATE_NON_COMBAT) && guidP.GetWorldObject()) if (botAI->HasStrategy("debug rpg", BOT_STATE_NON_COMBAT) && guidP.GetWorldObject())
{ {
std::ostringstream out; std::ostringstream out;
out << "Heading to: "; out << "Направляюсь к цели: ";
out << chat->FormatWorldobject(guidP.GetWorldObject()); out << chat->FormatWorldobject(guidP.GetWorldObject());
botAI->TellMasterNoFacing(out); botAI->TellMasterNoFacing(out);
} }
@@ -55,9 +55,9 @@ bool MoveToTravelTargetAction::Execute(Event /*event*/)
{ {
std::ostringstream out; std::ostringstream out;
if (botAI->GetMaster() && !bot->GetGroup()->IsMember(botAI->GetMaster()->GetGUID())) if (botAI->GetMaster() && !bot->GetGroup()->IsMember(botAI->GetMaster()->GetGUID()))
out << "Waiting a bit for "; out << "Немного подожду: ";
else else
out << "Please hurry up "; out << "Пожалуйста, поторопитесь: ";
out << member->GetName(); out << member->GetName();
@@ -164,7 +164,7 @@ bool MovementAction::MoveToLOS(WorldObject* target, bool ranged)
if (dest.isSet()) if (dest.isSet())
return MoveTo(dest.mapId, dest.x, dest.y, dest.z); return MoveTo(dest.mapId, dest.x, dest.y, dest.z);
else else
botAI->TellError("All paths not in LOS"); botAI->TellError("Ни один путь не находится в поле зрения");
return false; return false;
} }
@@ -1160,13 +1160,13 @@ bool MovementAction::Follow(Unit* target, float distance, float angle)
if (bot->isDead() && botAI->GetMaster()->IsAlive()) if (bot->isDead() && botAI->GetMaster()->IsAlive())
{ {
bot->ResurrectPlayer(1.0f, false); bot->ResurrectPlayer(1.0f, false);
botAI->TellMasterNoFacing("I live, again!"); botAI->TellMasterNoFacing("Я снова жив!");
} }
else else
botAI->TellError("I am stuck while following"); botAI->TellError("Я застрял во время следования");
bot->CombatStop(true); bot->CombatStop(true);
botAI->TellMasterNoFacing("I will there soon."); botAI->TellMasterNoFacing("Я скоро буду там.");
bot->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_TELEPORTED | AURA_INTERRUPT_FLAG_CHANGE_MAP); bot->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_TELEPORTED | AURA_INTERRUPT_FLAG_CHANGE_MAP);
bot->TeleportTo(target->GetMapId(), target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), bot->TeleportTo(target->GetMapId(), target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(),
target->GetOrientation()); return false; target->GetOrientation()); return false;
@@ -1379,7 +1379,7 @@ bool MovementAction::Flee(Unit* target)
if (!IsMovingAllowed()) if (!IsMovingAllowed())
{ {
botAI->TellError("I am stuck while fleeing"); botAI->TellError("Я застрял при отступлении");
return false; return false;
} }
@@ -1535,7 +1535,7 @@ bool MovementAction::Flee(Unit* target)
float rx, ry, rz; float rx, ry, rz;
if (!manager.CalculateDestination(&rx, &ry, &rz)) if (!manager.CalculateDestination(&rx, &ry, &rz))
{ {
botAI->TellError("Nowhere to flee"); botAI->TellError("Некуда отступать");
return false; return false;
} }
@@ -1940,7 +1940,7 @@ bool AvoidAoeAction::AvoidAuraWithDynamicObj()
lastTellTimer = time(NULL); lastTellTimer = time(NULL);
lastMoveTimer = getMSTime(); lastMoveTimer = getMSTime();
std::ostringstream out; std::ostringstream out;
out << "I'm avoiding " << name.str() << " (" << spellInfo->Id << ")" << " Radius " << radius << " - [Aura]"; out << "Избегаю: " << name.str() << " (" << spellInfo->Id << ")" << "; радиус " << radius << " — [аура]";
bot->Say(out.str(), LANG_UNIVERSAL); bot->Say(out.str(), LANG_UNIVERSAL);
} }
return true; return true;
@@ -2008,7 +2008,7 @@ bool AvoidAoeAction::AvoidGameObjectWithDamage()
lastTellTimer = time(NULL); lastTellTimer = time(NULL);
lastMoveTimer = getMSTime(); lastMoveTimer = getMSTime();
std::ostringstream out; std::ostringstream out;
out << "I'm avoiding " << name.str() << " (" << spellInfo->Id << ")" << " Radius " << radius out << "Избегаю: " << name.str() << " (" << spellInfo->Id << ")" << "; радиус " << radius
<< " - [Trap]"; << " - [Trap]";
bot->Say(out.str(), LANG_UNIVERSAL); bot->Say(out.str(), LANG_UNIVERSAL);
} }
@@ -2075,7 +2075,7 @@ bool AvoidAoeAction::AvoidUnitWithDamageAura()
lastTellTimer = time(NULL); lastTellTimer = time(NULL);
lastMoveTimer = getMSTime(); lastMoveTimer = getMSTime();
std::ostringstream out; std::ostringstream out;
out << "I'm avoiding " << name.str() << " (" << triggerSpellInfo->Id << ")" out << "Избегаю: " << name.str() << " (" << triggerSpellInfo->Id << ")"
<< " Radius " << radius << " - [Unit Trigger]"; << " Radius " << radius << " - [Unit Trigger]";
bot->Say(out.str(), LANG_UNIVERSAL); bot->Say(out.str(), LANG_UNIVERSAL);
} }
@@ -2554,7 +2554,7 @@ bool DisperseSetAction::Execute(Event event)
if (text == "disable") if (text == "disable")
{ {
RESET_AI_VALUE(float, "disperse distance"); RESET_AI_VALUE(float, "disperse distance");
botAI->TellMasterNoFacing("Disable disperse"); botAI->TellMasterNoFacing("Рассредоточение отключено");
return true; return true;
} }
if (text == "enable" || text == "reset") if (text == "enable" || text == "reset")
@@ -2569,7 +2569,7 @@ bool DisperseSetAction::Execute(Event event)
} }
float dis = AI_VALUE(float, "disperse distance"); float dis = AI_VALUE(float, "disperse distance");
std::ostringstream out; std::ostringstream out;
out << "Enable disperse distance " << std::setprecision(2) << dis; out << "Включено рассредоточение с дистанцией " << std::setprecision(2) << dis;
botAI->TellMasterNoFacing(out.str()); botAI->TellMasterNoFacing(out.str());
return true; return true;
} }
@@ -2579,13 +2579,13 @@ bool DisperseSetAction::Execute(Event event)
std::ostringstream out; std::ostringstream out;
if (dis <= 0.0f) if (dis <= 0.0f)
{ {
out << "Enable disperse first"; out << "Сначала включите рассредоточение";
botAI->TellMasterNoFacing(out.str()); botAI->TellMasterNoFacing(out.str());
return true; return true;
} }
dis += 1.0f; dis += 1.0f;
SET_AI_VALUE(float, "disperse distance", dis); SET_AI_VALUE(float, "disperse distance", dis);
out << "Increase disperse distance to " << std::setprecision(2) << dis; out << "Дистанция рассредоточения увеличена до " << std::setprecision(2) << dis;
botAI->TellMasterNoFacing(out.str()); botAI->TellMasterNoFacing(out.str());
return true; return true;
} }
@@ -2599,7 +2599,7 @@ bool DisperseSetAction::Execute(Event event)
} }
SET_AI_VALUE(float, "disperse distance", dis); SET_AI_VALUE(float, "disperse distance", dis);
std::ostringstream out; std::ostringstream out;
out << "Increase disperse distance to " << std::setprecision(2) << dis; out << "Дистанция рассредоточения увеличена до " << std::setprecision(2) << dis;
botAI->TellMasterNoFacing(out.str()); botAI->TellMasterNoFacing(out.str());
return true; return true;
} }
@@ -2611,18 +2611,18 @@ bool DisperseSetAction::Execute(Event event)
std::ostringstream out; std::ostringstream out;
if (dis < 0 || dis > 100.0f) if (dis < 0 || dis > 100.0f)
{ {
out << "Invalid disperse distance " << std::setprecision(2) << dis; out << "Недопустимая дистанция рассредоточения: " << std::setprecision(2) << dis;
} }
else else
{ {
SET_AI_VALUE(float, "disperse distance", dis); SET_AI_VALUE(float, "disperse distance", dis);
out << "Set disperse distance to " << std::setprecision(2) << dis; out << "Дистанция рассредоточения установлена: " << std::setprecision(2) << dis;
} }
botAI->TellMasterNoFacing(out.str()); botAI->TellMasterNoFacing(out.str());
return true; return true;
} }
std::ostringstream out; std::ostringstream out;
out << "Usage: disperse [enable | disable | increase | decrease | set {distance}]"; out << "Использование: disperse [enable | disable | increase | decrease | set {дистанция}]";
float dis = AI_VALUE(float, "disperse distance"); float dis = AI_VALUE(float, "disperse distance");
if (dis > 0.0f) if (dis > 0.0f)
{ {
@@ -36,6 +36,6 @@ void OpenItemAction::OpenItem(Item* item, uint8 bag, uint8 slot)
botAI->GetAiObjectContext()->GetValue<LootObject>("loot target")->Set(lootObject); botAI->GetAiObjectContext()->GetValue<LootObject>("loot target")->Set(lootObject);
std::ostringstream out; std::ostringstream out;
out << "Opened item: " << item->GetTemplate()->Name1; out << "Открыт предмет: " << item->GetTemplate()->Name1;
botAI->TellMaster(out.str()); botAI->TellMaster(out.str());
} }
@@ -17,9 +17,9 @@ bool OutfitAction::Execute(Event event)
if (param == "?") if (param == "?")
{ {
List(); List();
botAI->TellMaster("outfit <name> +[item] to add items"); botAI->TellMaster("outfit <имя> +[предмет] — добавить предметы");
botAI->TellMaster("outfit <name> -[item] to remove items"); botAI->TellMaster("outfit <имя> -[предмет] — удалить предметы");
botAI->TellMaster("outfit <name> equip/replace to equip items"); botAI->TellMaster("outfit <имя> equip/replace — надеть предметы");
} }
else else
{ {
@@ -30,7 +30,7 @@ bool OutfitAction::Execute(Event event)
Save(name, items); Save(name, items);
std::ostringstream out; std::ostringstream out;
out << "Setting outfit " << name << " as " << param; out << "Настраиваю комплект: " << name << " как " << param;
botAI->TellMaster(out); botAI->TellMaster(out);
return true; return true;
} }
@@ -48,7 +48,7 @@ bool OutfitAction::Execute(Event event)
if (command == "equip") if (command == "equip")
{ {
std::ostringstream out; std::ostringstream out;
out << "Equipping outfit " << name; out << "Надеваю комплект: " << name;
botAI->TellMaster(out); botAI->TellMaster(out);
EquipItems(outfit); EquipItems(outfit);
@@ -57,7 +57,7 @@ bool OutfitAction::Execute(Event event)
else if (command == "replace") else if (command == "replace")
{ {
std::ostringstream out; std::ostringstream out;
out << "Replacing current equip with outfit " << name; out << "Заменяю текущую экипировку комплектом: " << name;
botAI->TellMaster(out); botAI->TellMaster(out);
for (uint8 slot = EQUIPMENT_SLOT_START; slot < EQUIPMENT_SLOT_END; slot++) for (uint8 slot = EQUIPMENT_SLOT_START; slot < EQUIPMENT_SLOT_END; slot++)
@@ -82,7 +82,7 @@ bool OutfitAction::Execute(Event event)
else if (command == "reset") else if (command == "reset")
{ {
std::ostringstream out; std::ostringstream out;
out << "Resetting outfit " << name; out << "Сбрасываю комплект: " << name;
botAI->TellMaster(out); botAI->TellMaster(out);
Save(name, ItemIds()); Save(name, ItemIds());
@@ -91,7 +91,7 @@ bool OutfitAction::Execute(Event event)
else if (command == "update") else if (command == "update")
{ {
std::ostringstream out; std::ostringstream out;
out << "Updating with current items outfit " << name; out << "Обновляю комплект текущими предметами: " << name;
botAI->TellMaster(out); botAI->TellMaster(out);
Update(name); Update(name);
@@ -38,7 +38,7 @@ bool PetitionSignAction::Execute(Event event)
if (bot->GetArenaTeamId(slot)) if (bot->GetArenaTeamId(slot))
{ {
// player is already in an arena team // player is already in an arena team
botAI->TellError("Sorry, I am already in such team"); botAI->TellError("У меня уже есть такая команда");
accept = false; accept = false;
} }
} }
@@ -46,13 +46,13 @@ bool PetitionSignAction::Execute(Event event)
{ {
if (bot->GetGuildId()) if (bot->GetGuildId())
{ {
botAI->TellError("Sorry, I am in a guild already"); botAI->TellError("Я уже состою в гильдии");
accept = false; accept = false;
} }
if (bot->GetGuildIdInvited()) if (bot->GetGuildIdInvited())
{ {
botAI->TellError("Sorry, I am invited to a guild already"); botAI->TellError("Меня уже пригласили в гильдию");
accept = false; accept = false;
} }
@@ -60,7 +60,7 @@ bool PetitionSignAction::Execute(Event event)
/*if (QueryResult* result = CharacterDatabase.Query("SELECT playerguid FROM petition_sign WHERE player_account = /*if (QueryResult* result = CharacterDatabase.Query("SELECT playerguid FROM petition_sign WHERE player_account =
{} AND petitionguid = {}'", bot->GetSession()->GetAccountId(), petitionGuid.GetCounter())) {} AND petitionguid = {}'", bot->GetSession()->GetAccountId(), petitionGuid.GetCounter()))
{ {
botAI->TellError("Sorry, I already signed this pettition"); botAI->TellError("Я уже подписал эту хартию");
accept = false; accept = false;
} }
*/ */
@@ -88,7 +88,7 @@ bool PetitionSignAction::Execute(Event event)
WorldPacket data(CMSG_PETITION_SIGN, 20); WorldPacket data(CMSG_PETITION_SIGN, 20);
data << petitionGuid << unk; data << petitionGuid << unk;
bot->GetSession()->HandlePetitionSignOpcode(data); bot->GetSession()->HandlePetitionSignOpcode(data);
bot->Say("Thanks for the invite!", LANG_UNIVERSAL); bot->Say("Спасибо за приглашение!", LANG_UNIVERSAL);
LOG_INFO("playerbots", "Bot {} <{}> accepts {} invite", bot->GetGUID().ToString().c_str(), LOG_INFO("playerbots", "Bot {} <{}> accepts {} invite", bot->GetGUID().ToString().c_str(),
bot->GetName().c_str(), isArena ? "Arena" : "Guild"); bot->GetName().c_str(), isArena ? "Arena" : "Guild");
return true; return true;
@@ -12,7 +12,7 @@
void TellPosition(PlayerbotAI* botAI, std::string const name, PositionInfo pos) void TellPosition(PlayerbotAI* botAI, std::string const name, PositionInfo pos)
{ {
std::ostringstream out; std::ostringstream out;
out << "Position " << name; out << "Позиция " << name;
if (pos.isSet()) if (pos.isSet())
{ {
@@ -22,7 +22,7 @@ void TellPosition(PlayerbotAI* botAI, std::string const name, PositionInfo pos)
out << " is set to " << x << "," << y; out << " is set to " << x << "," << y;
} }
else else
out << " is not set"; out << " не установлена";
botAI->TellMaster(out); botAI->TellMaster(out);
} }
@@ -52,7 +52,7 @@ bool PositionAction::Execute(Event event)
std::vector<std::string> params = split(param, ' '); std::vector<std::string> params = split(param, ' ');
if (params.size() != 2) if (params.size() != 2)
{ {
botAI->TellMaster("Whisper position <name> ?/set/reset"); botAI->TellMaster("Напишите: position <имя> ?/set/reset");
return false; return false;
} }
@@ -72,7 +72,7 @@ bool PositionAction::Execute(Event event)
posMap[name] = pos; posMap[name] = pos;
std::ostringstream out; std::ostringstream out;
out << "Position " << name << " is set"; out << "Позиция " << name << " установлена";
botAI->TellMaster(out); botAI->TellMaster(out);
return true; return true;
} }
@@ -83,7 +83,7 @@ bool PositionAction::Execute(Event event)
posMap[name] = pos; posMap[name] = pos;
std::ostringstream out; std::ostringstream out;
out << "Position " << name << " is set"; out << "Позиция " << name << " установлена";
botAI->TellMaster(out); botAI->TellMaster(out);
return true; return true;
} }
@@ -94,7 +94,7 @@ bool PositionAction::Execute(Event event)
posMap[name] = pos; posMap[name] = pos;
std::ostringstream out; std::ostringstream out;
out << "Position " << name << " is reset"; out << "Позиция " << name << " сброшена";
botAI->TellMaster(out); botAI->TellMaster(out);
return true; return true;
} }
@@ -108,7 +108,7 @@ bool MoveToPositionAction::Execute(Event /*event*/)
if (!pos.isSet()) if (!pos.isSet())
{ {
std::ostringstream out; std::ostringstream out;
out << "Position " << qualifier << " is not set"; out << "Позиция " << qualifier << " не установлена";
botAI->TellMaster(out); botAI->TellMaster(out);
return false; return false;
} }
@@ -169,7 +169,7 @@ bool ReturnToStayPositionAction::isPossible()
const float distance = bot->GetDistance(stayPosition.x, stayPosition.y, stayPosition.z); const float distance = bot->GetDistance(stayPosition.x, stayPosition.y, stayPosition.z);
if (distance > sPlayerbotAIConfig.reactDistance) if (distance > sPlayerbotAIConfig.reactDistance)
{ {
botAI->TellMaster("The stay position is too far to return. I am going to stay where I am now"); botAI->TellMaster("Заданная точка слишком далеко. Останусь на текущем месте");
// Set the stay position to current position // Set the stay position to current position
stayPosition.Set(bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ(), bot->GetMapId()); stayPosition.Set(bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ(), bot->GetMapId());
@@ -139,7 +139,7 @@ std::string const QueryItemUsageAction::QueryItemPrice(ItemTemplate const* item)
} }
} }
if (sellPrice) if (sellPrice)
msg << "Sell: " << chat->formatMoney(sellPrice); msg << "Продажа: " << chat->formatMoney(sellPrice);
std::ostringstream out; std::ostringstream out;
out << item->ItemId; out << item->ItemId;
@@ -153,7 +153,7 @@ std::string const QueryItemUsageAction::QueryItemPrice(ItemTemplate const* item)
if (sellPrice) if (sellPrice)
msg << " "; msg << " ";
msg << "Buy: " << chat->formatMoney(buyPrice); msg << "Покупка: " << chat->formatMoney(buyPrice);
} }
return msg.str(); return msg.str();
@@ -117,7 +117,7 @@ void QueryQuestAction::TellObjectives(uint32 questId)
// Checks if the questTemplate is valid // Checks if the questTemplate is valid
if (!questTemplate) if (!questTemplate)
{ {
botAI->TellMaster("Quest template not found."); botAI->TellMaster("Шаблон задания не найден.");
return; return;
} }
@@ -158,9 +158,9 @@ bool QuestAction::CompleteQuest(Player* player, uint32 entry)
if (botAI->HasStrategy("debug quest", BotState::BOT_STATE_NON_COMBAT) || botAI->HasStrategy("debug rpg", BotState::BOT_STATE_COMBAT)) if (botAI->HasStrategy("debug quest", BotState::BOT_STATE_NON_COMBAT) || botAI->HasStrategy("debug rpg", BotState::BOT_STATE_COMBAT))
{ {
LOG_INFO("playerbots", "{} => Quest [ {} ] completed", bot->GetName(), pQuest->GetTitle()); LOG_INFO("playerbots", "{} => Quest [ {} ] completed", bot->GetName(), pQuest->GetTitle());
bot->Say("Quest [ " + text_quest + " ] completed", LANG_UNIVERSAL); bot->Say("Задание [ " + text_quest + " ] completed", LANG_UNIVERSAL);
} }
botAI->TellMasterNoFacing("Quest completed " + text_quest); botAI->TellMasterNoFacing("Задание выполнено: " + text_quest);
player->CompleteQuest(entry); player->CompleteQuest(entry);
@@ -188,7 +188,7 @@ bool QuestAction::ProcessQuests(WorldObject* questGiver)
{ {
//if (botAI->HasStrategy("debug", BotState::BOT_STATE_COMBAT) || botAI->HasStrategy("debug", BotState::BOT_STATE_NON_COMBAT)) //if (botAI->HasStrategy("debug", BotState::BOT_STATE_COMBAT) || botAI->HasStrategy("debug", BotState::BOT_STATE_NON_COMBAT))
botAI->TellError("Cannot talk to quest giver"); botAI->TellError("Не удалось поговорить с персонажем, выдающим задание");
return false; return false;
} }
@@ -220,18 +220,18 @@ bool QuestAction::AcceptQuest(Quest const* quest, ObjectGuid questGiver)
uint32 questId = quest->GetQuestId(); uint32 questId = quest->GetQuestId();
if (bot->GetQuestStatus(questId) == QUEST_STATUS_COMPLETE) if (bot->GetQuestStatus(questId) == QUEST_STATUS_COMPLETE)
out << "Already completed"; out << "Уже выполнено";
else if (!bot->CanTakeQuest(quest, false)) else if (!bot->CanTakeQuest(quest, false))
{ {
if (!bot->SatisfyQuestStatus(quest, false)) if (!bot->SatisfyQuestStatus(quest, false))
out << "Already on"; out << "Уже выполняется";
else else
out << "Can't take"; out << "Невозможно взять";
} }
else if (!bot->SatisfyQuestLog(false)) else if (!bot->SatisfyQuestLog(false))
out << "Quest log is full"; out << "Журнал заданий заполнен";
else if (!bot->CanAddQuest(quest, false)) else if (!bot->CanAddQuest(quest, false))
out << "Bags are full"; out << "Сумки заполнены";
else else
{ {
WorldPacket p(CMSG_QUESTGIVER_ACCEPT_QUEST); WorldPacket p(CMSG_QUESTGIVER_ACCEPT_QUEST);
@@ -250,11 +250,11 @@ bool QuestAction::AcceptQuest(Quest const* quest, ObjectGuid questGiver)
if (bot->GetQuestStatus(questId) != QUEST_STATUS_NONE && bot->GetQuestStatus(questId) != QUEST_STATUS_REWARDED) if (bot->GetQuestStatus(questId) != QUEST_STATUS_NONE && bot->GetQuestStatus(questId) != QUEST_STATUS_REWARDED)
{ {
BroadcastHelper::BroadcastQuestAccepted(botAI, bot, quest); BroadcastHelper::BroadcastQuestAccepted(botAI, bot, quest);
out << "Accepted " << chat->FormatQuest(quest); out << "Принято: " << chat->FormatQuest(quest);
botAI->TellMaster(out); botAI->TellMaster(out);
return true; return true;
} }
out << "Cannot accept"; out << "Невозможно принять";
} }
out << " " << chat->FormatQuest(quest); out << " " << chat->FormatQuest(quest);
@@ -288,7 +288,7 @@ bool QuestUpdateCompleteAction::Execute(Event event)
// } // }
const auto format = ChatHelper::FormatQuest(qInfo); const auto format = ChatHelper::FormatQuest(qInfo);
if (botAI->GetMaster()) if (botAI->GetMaster())
botAI->TellMasterNoFacing("Quest completed " + format); botAI->TellMasterNoFacing("Задание выполнено: " + format);
BroadcastHelper::BroadcastQuestUpdateComplete(botAI, bot, qInfo); BroadcastHelper::BroadcastQuestUpdateComplete(botAI, bot, qInfo);
botAI->rpgStatistic.questCompleted++; botAI->rpgStatistic.questCompleted++;
// LOG_DEBUG("playerbots", "[New rpg] {} complete quest {}", bot->GetName(), qInfo->GetQuestId()); // LOG_DEBUG("playerbots", "[New rpg] {} complete quest {}", bot->GetName(), qInfo->GetQuestId());
@@ -461,7 +461,7 @@ bool QuestUpdateFailedTimerAction::Execute(Event event)
} }
else else
{ {
botAI->TellMaster("Failed timer for " + std::to_string(questId)); botAI->TellMaster("Не удалось запустить таймер задания: " + std::to_string(questId));
} }
//drop quest //drop quest
@@ -16,7 +16,7 @@ bool QuestConfirmAcceptAction::Execute(Event event)
return false; return false;
} }
std::ostringstream out; std::ostringstream out;
out << "Quest: " << chat->FormatQuest(quest) << " confirm accept"; out << "Задание: " << chat->FormatQuest(quest) << " — подтвердите принятие";
botAI->TellMaster(out); botAI->TellMaster(out);
bot->GetSession()->HandleQuestConfirmAccept(sendPacket); bot->GetSession()->HandleQuestConfirmAccept(sendPacket);
return true; return true;
@@ -97,19 +97,19 @@ public:
{ {
if (!bot->GetUInt32Value(PLAYER_AMMO_ID)) if (!bot->GetUInt32Value(PLAYER_AMMO_ID))
{ {
botAI->TellError("Out of ammo!"); botAI->TellError("Закончились боеприпасы!");
return false; return false;
} }
if (!bot->GetPet()) if (!bot->GetPet())
{ {
botAI->TellError("No pet!"); botAI->TellError("Нет питомца!");
return false; return false;
} }
if (bot->GetPet()->GetHappinessState() == UNHAPPY) if (bot->GetPet()->GetHappinessState() == UNHAPPY)
{ {
botAI->TellError("Pet is unhappy!"); botAI->TellError("Питомец недоволен!");
return false; return false;
} }
} }
@@ -22,7 +22,7 @@ bool ReleaseSpiritAction::Execute(Event event)
{ {
if (!bot->InBattleground()) if (!bot->InBattleground())
{ {
botAI->TellMasterNoFacing("I am not dead, will wait here"); botAI->TellMasterNoFacing("Мне не требуется воскрешение, подожду здесь");
// -follow in bg is overwriten each tick with +follow // -follow in bg is overwriten each tick with +follow
// +stay in bg causes stuttering effect as bot is cycled between +stay and +follow each tick // +stay in bg causes stuttering effect as bot is cycled between +stay and +follow each tick
botAI->ChangeStrategy("-follow,+stay", BOT_STATE_NON_COMBAT); botAI->ChangeStrategy("-follow,+stay", BOT_STATE_NON_COMBAT);
@@ -33,7 +33,7 @@ bool ReleaseSpiritAction::Execute(Event event)
if (bot->GetCorpse() && bot->HasPlayerFlag(PLAYER_FLAGS_GHOST)) if (bot->GetCorpse() && bot->HasPlayerFlag(PLAYER_FLAGS_GHOST))
{ {
botAI->TellMasterNoFacing("I am already a spirit"); botAI->TellMasterNoFacing("Я уже дух");
return false; return false;
} }
@@ -45,7 +45,7 @@ bool RepairAllAction::Execute(Event /*event*/)
if (totalCost > 0) if (totalCost > 0)
{ {
std::ostringstream out; std::ostringstream out;
out << "Repair: " << chat->formatMoney(totalCost) << " (" << unit->GetName() << ")"; out << "Ремонт: " << chat->formatMoney(totalCost) << " (" << unit->GetName() << ")";
botAI->TellMasterNoFacing(out.str()); botAI->TellMasterNoFacing(out.str());
bot->PlayDistanceSound(1116); bot->PlayDistanceSound(1116);
@@ -56,6 +56,6 @@ bool RepairAllAction::Execute(Event /*event*/)
return true; return true;
} }
botAI->TellError("Cannot find any npc to repair at"); botAI->TellError("Не удалось найти персонажа для ремонта");
return false; return false;
} }
@@ -46,6 +46,6 @@ bool ResetAiAction::Execute(Event event)
} }
PlayerbotRepository::instance().Reset(botAI); PlayerbotRepository::instance().Reset(botAI);
botAI->ResetStrategies(false); botAI->ResetStrategies(false);
botAI->TellMaster("AI was reset to defaults"); botAI->TellMaster("Настройки ИИ сброшены");
return true; return true;
} }
@@ -62,18 +62,18 @@ bool RevealGatheringItemAction::Execute(Event /*event*/)
return false; return false;
std::ostringstream msg; std::ostringstream msg;
msg << "I see a " << ChatHelper::FormatGameobject(go) << ". "; msg << "Вижу: " << ChatHelper::FormatGameobject(go) << ". ";
switch (go->GetGoType()) switch (go->GetGoType())
{ {
case GAMEOBJECT_TYPE_CHEST: case GAMEOBJECT_TYPE_CHEST:
msg << "Let's look at it."; msg << "Давайте посмотрим.";
break; break;
case GAMEOBJECT_TYPE_FISHINGNODE: case GAMEOBJECT_TYPE_FISHINGNODE:
msg << "Let's fish a bit."; msg << "Давайте немного порыбачим.";
break; break;
default: default:
msg << "Should we go nearer?"; msg << "Подойти ближе?";
} }
// everything is fine, do it // everything is fine, do it
@@ -28,7 +28,7 @@ bool ReviveFromCorpseAction::Execute(Event event)
{ {
if (!botAI->HasStrategy("follow", BOT_STATE_NON_COMBAT)) if (!botAI->HasStrategy("follow", BOT_STATE_NON_COMBAT))
{ {
botAI->TellMasterNoFacing("Welcome back!"); botAI->TellMasterNoFacing("С возвращением!");
botAI->ChangeStrategy("+follow,-stay", BOT_STATE_NON_COMBAT); botAI->ChangeStrategy("+follow,-stay", BOT_STATE_NON_COMBAT);
return true; return true;
} }
@@ -297,7 +297,7 @@ bool SpiritHealerAction::Execute(Event /*event*/)
Corpse* corpse = bot->GetCorpse(); Corpse* corpse = bot->GetCorpse();
if (!corpse) if (!corpse)
{ {
botAI->TellError("I am not a spirit"); botAI->TellError("Я не дух");
return false; return false;
} }
@@ -322,7 +322,7 @@ bool SpiritHealerAction::Execute(Event /*event*/)
bot->SpawnCorpseBones(); bot->SpawnCorpseBones();
context->GetValue<Unit*>("current target")->Set(nullptr); context->GetValue<Unit*>("current target")->Set(nullptr);
bot->SetTarget(); bot->SetTarget();
botAI->TellMaster("Hello"); botAI->TellMaster("Здравствуйте.");
if (dCount > 20) if (dCount > 20)
context->GetValue<uint32>("death count")->Set(0); context->GetValue<uint32>("death count")->Set(0);
@@ -39,7 +39,7 @@ bool RewardAction::Execute(Event event)
if (groupLeaderUnit && Reward(itemId, groupLeaderUnit)) if (groupLeaderUnit && Reward(itemId, groupLeaderUnit))
return true; return true;
botAI->TellError("Cannot talk to quest giver"); botAI->TellError("Не удалось поговорить с персонажем, выдающим задание");
return false; return false;
} }
@@ -374,7 +374,7 @@ bool RpgTradeUsefulAction::Execute(Event /*event*/)
"You can use this " + chat->FormatItem(item->GetTemplate()) + " better than me, " + "You can use this " + chat->FormatItem(item->GetTemplate()) + " better than me, " +
guidP.GetPlayer()->GetName() /*chat->FormatWorldobject(guidP.GetPlayer())*/ + "."); guidP.GetPlayer()->GetName() /*chat->FormatWorldobject(guidP.GetPlayer())*/ + ".");
else else
bot->Say("You can use this " + chat->FormatItem(item->GetTemplate()) + " better than me, " + bot->Say("Можно использовать: " + chat->FormatItem(item->GetTemplate()) + " better than me, " +
player->GetName() /*chat->FormatWorldobject(player)*/ + ".", player->GetName() /*chat->FormatWorldobject(player)*/ + ".",
(bot->GetTeamId() == TEAM_ALLIANCE ? LANG_COMMON : LANG_ORCISH)); (bot->GetTeamId() == TEAM_ALLIANCE ? LANG_COMMON : LANG_ORCISH));
@@ -389,7 +389,7 @@ bool RpgTradeUsefulAction::Execute(Event /*event*/)
} }
} }
else else
bot->Say("Start trade with" + chat->FormatWorldobject(player), bot->Say("Начинаю обмен с" + chat->FormatWorldobject(player),
(bot->GetTeamId() == TEAM_ALLIANCE ? LANG_COMMON : LANG_ORCISH)); (bot->GetTeamId() == TEAM_ALLIANCE ? LANG_COMMON : LANG_ORCISH));
botAI->SetNextCheckDelay(sPlayerbotAIConfig.rpgDelay); botAI->SetNextCheckDelay(sPlayerbotAIConfig.rpgDelay);
@@ -20,15 +20,15 @@ bool RTSCAction::Execute(Event event)
if (command != "reset" && !master->HasSpell(RTSC_MOVE_SPELL)) if (command != "reset" && !master->HasSpell(RTSC_MOVE_SPELL))
{ {
master->learnSpell(RTSC_MOVE_SPELL, false); master->learnSpell(RTSC_MOVE_SPELL, false);
botAI->TellMasterNoFacing("RTS control enabled."); botAI->TellMasterNoFacing("Управление RTS включено.");
botAI->TellMasterNoFacing("Aedm (Awesome energetic do move) spell trained."); botAI->TellMasterNoFacing("Заклинание Aedm для управления перемещением изучено.");
} }
else if (command == "reset") else if (command == "reset")
{ {
if (master->HasSpell(RTSC_MOVE_SPELL)) if (master->HasSpell(RTSC_MOVE_SPELL))
{ {
master->removeSpell(RTSC_MOVE_SPELL, SPEC_MASK_ALL, false); master->removeSpell(RTSC_MOVE_SPELL, SPEC_MASK_ALL, false);
botAI->TellMasterNoFacing("RTS control spell removed."); botAI->TellMasterNoFacing("Заклинание управления RTS удалено.");
} }
RESET_AI_VALUE(bool, "RTSC selected"); RESET_AI_VALUE(bool, "RTSC selected");
@@ -123,7 +123,7 @@ bool RTSCAction::Execute(Event event)
if (command.find("show") != std::string::npos) if (command.find("show") != std::string::npos)
{ {
std::ostringstream out; std::ostringstream out;
out << "saved: "; out << "сохранено: ";
for (auto value : botAI->GetAiObjectContext()->GetValues()) for (auto value : botAI->GetAiObjectContext()->GetValues())
if (value.find("RTSC saved location::") != std::string::npos) if (value.find("RTSC saved location::") != std::string::npos)
@@ -16,7 +16,7 @@ bool SaveManaAction::Execute(Event event)
if (text == "?") if (text == "?")
{ {
std::ostringstream out; std::ostringstream out;
out << "Mana save level: " << Format(value); out << "Уровень экономии маны: " << Format(value);
botAI->TellMaster(out); botAI->TellMaster(out);
return true; return true;
} }
@@ -55,7 +55,7 @@ bool SaveManaAction::Execute(Event event)
botAI->GetAiObjectContext()->GetValue<double>("mana save level")->Set(value); botAI->GetAiObjectContext()->GetValue<double>("mana save level")->Set(value);
std::ostringstream out; std::ostringstream out;
out << "Mana save level set: " << Format(value); out << "Уровень экономии маны установлен: " << Format(value);
botAI->TellMaster(out); botAI->TellMaster(out);
return true; return true;
@@ -25,7 +25,7 @@ bool SecurityCheckAction::Execute(Event /*event*/)
if ((botAI->GetGroupLeader()->GetSession()->GetSecurity() == SEC_PLAYER) && if ((botAI->GetGroupLeader()->GetSession()->GetSecurity() == SEC_PLAYER) &&
(!bot->GetGuildId() || bot->GetGuildId() != botAI->GetGroupLeader()->GetGuildId())) (!bot->GetGuildId() || bot->GetGuildId() != botAI->GetGroupLeader()->GetGuildId()))
{ {
botAI->TellError("I will play with this loot type only if I'm in your guild :/"); botAI->TellError("Я буду использовать этот тип добычи, только если состою в вашей гильдии :/");
botAI->ChangeStrategy("+passive,+stay", BOT_STATE_NON_COMBAT); botAI->ChangeStrategy("+passive,+stay", BOT_STATE_NON_COMBAT);
botAI->ChangeStrategy("+passive,+stay", BOT_STATE_COMBAT); botAI->ChangeStrategy("+passive,+stay", BOT_STATE_COMBAT);
} }
@@ -84,7 +84,7 @@ bool SellAction::Execute(Event event)
return true; return true;
} }
botAI->TellError("Usage: s gray/*/vendor/[item link]"); botAI->TellError("Использование: s gray/*/vendor/[ссылка на предмет]");
return false; return false;
} }
@@ -127,7 +127,7 @@ void SellAction::Sell(Item* item)
bot->SetMoney(botMoney); bot->SetMoney(botMoney);
} }
out << "Selling " << chat->FormatItem(item->GetTemplate()); out << "Продаю: " << chat->FormatItem(item->GetTemplate());
botAI->TellMaster(out); botAI->TellMaster(out);
bot->PlayDistanceSound(120); bot->PlayDistanceSound(120);
@@ -53,14 +53,14 @@ bool SendMailAction::Execute(Event event)
if (!mailboxFound && !randomBot) if (!mailboxFound && !randomBot)
{ {
bot->Whisper("There is no mailbox nearby", LANG_UNIVERSAL, tellTo); bot->Whisper("Поблизости нет почтового ящика", LANG_UNIVERSAL, tellTo);
return false; return false;
} }
ItemIds ids = chat->parseItems(text); ItemIds ids = chat->parseItems(text);
if (ids.size() > 1) if (ids.size() > 1)
{ {
bot->Whisper("You can not request more than one item", LANG_UNIVERSAL, tellTo); bot->Whisper("Можно запросить только один предмет", LANG_UNIVERSAL, tellTo);
return false; return false;
} }
@@ -72,13 +72,13 @@ bool SendMailAction::Execute(Event event)
if (randomBot) if (randomBot)
{ {
bot->Whisper("I cannot send money", LANG_UNIVERSAL, tellTo); bot->Whisper("Я не могу отправить деньги", LANG_UNIVERSAL, tellTo);
return false; return false;
} }
if (bot->GetMoney() < money) if (bot->GetMoney() < money)
{ {
botAI->TellError("I don't have enough money"); botAI->TellError("У меня недостаточно денег");
return false; return false;
} }
@@ -100,7 +100,7 @@ bool SendMailAction::Execute(Event event)
CharacterDatabase.CommitTransaction(trans); CharacterDatabase.CommitTransaction(trans);
std::ostringstream out; std::ostringstream out;
out << "Sending mail to " << receiver->GetName(); out << "Отправляю письмо: " << receiver->GetName();
botAI->TellMaster(out.str()); botAI->TellMaster(out.str());
return true; return true;
} }
@@ -125,7 +125,7 @@ bool SendMailAction::Execute(Event event)
if (item->IsSoulBound() || item->IsConjuredConsumable()) if (item->IsSoulBound() || item->IsConjuredConsumable())
{ {
std::ostringstream out; std::ostringstream out;
out << "Cannot send " << ChatHelper::FormatItem(item->GetTemplate()); out << "Не удалось отправить: " << ChatHelper::FormatItem(item->GetTemplate());
bot->Whisper(out.str(), LANG_UNIVERSAL, tellTo); bot->Whisper(out.str(), LANG_UNIVERSAL, tellTo);
continue; continue;
} }
@@ -160,7 +160,7 @@ bool SendMailAction::Execute(Event event)
CharacterDatabase.CommitTransaction(trans); CharacterDatabase.CommitTransaction(trans);
std::ostringstream out; std::ostringstream out;
out << "Sent mail to " << receiver->GetName(); out << "Письмо отправлено: " << receiver->GetName();
bot->Whisper(out.str(), LANG_UNIVERSAL, tellTo); bot->Whisper(out.str(), LANG_UNIVERSAL, tellTo);
return true; return true;
} }
@@ -24,7 +24,7 @@ bool SetCraftAction::Execute(Event event)
if (link == "reset") if (link == "reset")
{ {
data.Reset(); data.Reset();
botAI->TellMaster("I will not craft anything"); botAI->TellMaster("Я ничего не буду создавать");
return true; return true;
} }
@@ -37,7 +37,7 @@ bool SetCraftAction::Execute(Event event)
ItemIds itemIds = chat->parseItems(link); ItemIds itemIds = chat->parseItems(link);
if (itemIds.empty()) if (itemIds.empty())
{ {
botAI->TellMaster("Usage: 'craft [itemId]' or 'craft reset'"); botAI->TellMaster("Использование: «craft [ID предмета]» или «craft reset»");
return false; return false;
} }
@@ -93,7 +93,7 @@ bool SetCraftAction::Execute(Event event)
if (data.required.empty()) if (data.required.empty())
{ {
botAI->TellMaster("I cannot craft this"); botAI->TellMaster("Я не могу это создать");
return false; return false;
} }
@@ -108,7 +108,7 @@ void SetCraftAction::TellCraft()
CraftData& data = AI_VALUE(CraftData&, "craft"); CraftData& data = AI_VALUE(CraftData&, "craft");
if (data.IsEmpty()) if (data.IsEmpty())
{ {
botAI->TellMaster("I will not craft anything"); botAI->TellMaster("Я ничего не буду создавать");
return; return;
} }
@@ -117,7 +117,7 @@ void SetCraftAction::TellCraft()
return; return;
std::ostringstream out; std::ostringstream out;
out << "I will craft " << chat->FormatItem(proto) << " using reagents: "; out << "Я создам: " << chat->FormatItem(proto) << "; реагенты: ";
bool first = true; bool first = true;
for (std::map<uint32, uint32>::iterator i = data.required.begin(); i != data.required.end(); ++i) for (std::map<uint32, uint32>::iterator i = data.required.begin(); i != data.required.end(); ++i)
@@ -30,14 +30,14 @@ bool SetHomeAction::Execute(Event /*event*/)
{ {
Creature* creature = botAI->GetCreature(selection); Creature* creature = botAI->GetCreature(selection);
bot->GetSession()->SendBindPoint(creature); bot->GetSession()->SendBindPoint(creature);
botAI->TellMaster("This inn is my new home"); botAI->TellMaster("Эта таверна теперь мой дом");
return true; return true;
} }
else else
{ {
Creature* creature = botAI->GetCreature(selection); Creature* creature = botAI->GetCreature(selection);
bot->GetSession()->SendBindPoint(creature); bot->GetSession()->SendBindPoint(creature);
botAI->TellMaster("This inn is my new home"); botAI->TellMaster("Эта таверна теперь мой дом");
return true; return true;
} }
} }
@@ -50,10 +50,10 @@ bool SetHomeAction::Execute(Event /*event*/)
continue; continue;
bot->GetSession()->SendBindPoint(unit); bot->GetSession()->SendBindPoint(unit);
botAI->TellMaster("This inn is my new home"); botAI->TellMaster("Эта таверна теперь мой дом");
return true; return true;
} }
botAI->TellError("Can't find any innkeeper around"); botAI->TellError("Поблизости нет хозяина таверны");
return false; return false;
} }
@@ -32,7 +32,7 @@ bool ShareQuestAction::Execute(Event event)
WorldPacket p; WorldPacket p;
p << entry; p << entry;
bot->GetSession()->HandlePushQuestToParty(p); bot->GetSession()->HandlePushQuestToParty(p);
botAI->TellMaster("Quest shared"); botAI->TellMaster("Задание передано группе");
return true; return true;
} }
} }
@@ -99,7 +99,7 @@ bool AutoShareQuestAction::Execute(Event event)
WorldPacket p; WorldPacket p;
p << logQuest; p << logQuest;
bot->GetSession()->HandlePushQuestToParty(p); bot->GetSession()->HandlePushQuestToParty(p);
botAI->TellMaster("Quest shared"); botAI->TellMaster("Задание передано группе");
shared = true; shared = true;
} }
@@ -30,7 +30,7 @@ bool SkipSpellsListAction::Execute(Event event)
if (cmd == "reset") if (cmd == "reset")
{ {
skipSpells.clear(); skipSpells.clear();
botAI->TellMaster("Ignored spell list is empty"); botAI->TellMaster("Список игнорируемых заклинаний пуст");
return true; return true;
} }
@@ -39,11 +39,11 @@ bool SkipSpellsListAction::Execute(Event event)
std::ostringstream out; std::ostringstream out;
if (skipSpells.empty()) if (skipSpells.empty())
{ {
botAI->TellMaster("Ignored spell list is empty"); botAI->TellMaster("Список игнорируемых заклинаний пуст");
return true; return true;
} }
out << "Ignored spell list: "; out << "Список игнорируемых заклинаний: ";
bool first = true; bool first = true;
for (uint32 spellId : skipSpells) for (uint32 spellId : skipSpells)
@@ -71,7 +71,7 @@ bool SkipSpellsListAction::Execute(Event event)
uint32 spellId = chat->parseSpell(cmd); uint32 spellId = chat->parseSpell(cmd);
if (!spellId) if (!spellId)
{ {
botAI->TellError("Unknown spell"); botAI->TellError("Неизвестное заклинание");
return false; return false;
} }
@@ -19,7 +19,7 @@ bool TalkToQuestGiverAction::ProcessQuest(Quest const* quest, Object* questGiver
{ {
bool isCompleted = false; bool isCompleted = false;
std::ostringstream out; std::ostringstream out;
out << "Quest "; out << "Задание ";
QuestStatus status = bot->GetQuestStatus(quest->GetQuestId()); QuestStatus status = bot->GetQuestStatus(quest->GetQuestId());
Player* master = GetMaster(); Player* master = GetMaster();
@@ -92,7 +92,7 @@ bool TalkToQuestGiverAction::TurnInQuest(Quest const* quest, Object* questGiver,
const Quest* pQuest = sObjectMgr->GetQuestTemplate(questID); const Quest* pQuest = sObjectMgr->GetQuestTemplate(questID);
const std::string text_quest = ChatHelper::FormatQuest(pQuest); const std::string text_quest = ChatHelper::FormatQuest(pQuest);
LOG_INFO("playerbots", "{} => Quest [ {} ] completed", bot->GetName(), pQuest->GetTitle()); LOG_INFO("playerbots", "{} => Quest [ {} ] completed", bot->GetName(), pQuest->GetTitle());
bot->Say("Quest [ " + text_quest + " ] completed", LANG_UNIVERSAL); bot->Say("Задание [ " + text_quest + " ] completed", LANG_UNIVERSAL);
} }
return true; return true;
@@ -190,11 +190,11 @@ void TalkToQuestGiverAction::RewardMultipleItem(Quest const* quest, Object* ques
} }
ItemTemplate const* item = sObjectMgr->GetItemTemplate(quest->RewardChoiceItemId[best]); ItemTemplate const* item = sObjectMgr->GetItemTemplate(quest->RewardChoiceItemId[best]);
bot->RewardQuest(quest, best, questGiver, true); bot->RewardQuest(quest, best, questGiver, true);
out << "Rewarded " << ChatHelper::FormatItem(item); out << "Получена награда: " << ChatHelper::FormatItem(item);
} }
else else
{ {
out << "Unable to find suitable reward. Asking for help...."; out << "Не удалось подобрать подходящую награду. Нужна помощь...";
AskToSelectReward(quest, out, true); AskToSelectReward(quest, out, true);
} }
} }
@@ -218,7 +218,7 @@ void TalkToQuestGiverAction::RewardMultipleItem(Quest const* quest, Object* ques
ItemTemplate const* item = sObjectMgr->GetItemTemplate(quest->RewardChoiceItemId[firstId]); ItemTemplate const* item = sObjectMgr->GetItemTemplate(quest->RewardChoiceItemId[firstId]);
bot->RewardQuest(quest, firstId, questGiver, true); bot->RewardQuest(quest, firstId, questGiver, true);
out << "Rewarded " << ChatHelper::FormatItem(item); out << "Получена награда: " << ChatHelper::FormatItem(item);
} }
} }
} }
@@ -226,7 +226,7 @@ void TalkToQuestGiverAction::RewardMultipleItem(Quest const* quest, Object* ques
void TalkToQuestGiverAction::AskToSelectReward(Quest const* quest, std::ostringstream& out, bool forEquip) void TalkToQuestGiverAction::AskToSelectReward(Quest const* quest, std::ostringstream& out, bool forEquip)
{ {
std::ostringstream msg; std::ostringstream msg;
msg << "Choose reward: "; msg << "Выберите награду: ";
for (uint8 i = 0; i < quest->GetRewChoiceItemsCount(); ++i) for (uint8 i = 0; i < quest->GetRewChoiceItemsCount(); ++i)
{ {
@@ -240,7 +240,7 @@ void TalkToQuestGiverAction::AskToSelectReward(Quest const* quest, std::ostrings
} }
botAI->TellMaster(msg); botAI->TellMaster(msg);
out << "Reward pending"; out << "Ожидается выбор награды";
} }
bool TurnInQueryQuestAction::Execute(Event event) bool TurnInQueryQuestAction::Execute(Event event)
@@ -280,7 +280,7 @@ bool TurnInQueryQuestAction::Execute(Event event)
} }
} }
std::ostringstream out; std::ostringstream out;
out << "Quest "; out << "Задание ";
switch (status) switch (status)
{ {
case QUEST_STATUS_COMPLETE: case QUEST_STATUS_COMPLETE:
@@ -124,7 +124,7 @@ bool TameAction::Execute(Event event)
} }
catch (...) catch (...)
{ {
botAI->TellError("Invalid tame id."); botAI->TellError("Неверный ID приручения.");
} }
} }
else if (mode == "family" && !value.empty()) else if (mode == "family" && !value.empty())
@@ -163,7 +163,7 @@ bool TameAction::Execute(Event event)
} }
else else
{ {
botAI->TellMaster("Pet changed and initialized!"); botAI->TellMaster("Питомец заменён и подготовлен!");
} }
} }
@@ -198,7 +198,7 @@ bool TameAction::SetPetByName(const std::string& name)
// If the creature is exotic and the bot doesn't have Beast Mastery, show error and fail // If the creature is exotic and the bot doesn't have Beast Mastery, show error and fail
if (IsExoticPet(&creature) && !HasBeastMastery(bot)) if (IsExoticPet(&creature) && !HasBeastMastery(bot))
{ {
botAI->TellError("I cannot use exotic pets unless I have the Beast Mastery talent."); botAI->TellError("Я не могу использовать экзотических питомцев без таланта «Повелитель зверей».");
return false; return false;
} }
@@ -215,7 +215,7 @@ bool TameAction::SetPetByName(const std::string& name)
} }
// If no suitable pet found, show an error and return failure // If no suitable pet found, show an error and return failure
botAI->TellError("No tameable pet found with name: " + name); botAI->TellError("Не найден приручаемый питомец с именем: " + name);
return false; return false;
} }
@@ -232,21 +232,21 @@ bool TameAction::SetPetById(uint32 id)
if (!creature->IsTameable(true)) if (!creature->IsTameable(true))
{ {
// If not tameable at all, show an error and fail // If not tameable at all, show an error and fail
botAI->TellError("No tameable pet found with id: " + std::to_string(id)); botAI->TellError("Не найден приручаемый питомец с ID: " + std::to_string(id));
return false; return false;
} }
// If it's an exotic pet, make sure the bot has the Beast Mastery talent // If it's an exotic pet, make sure the bot has the Beast Mastery talent
if (IsExoticPet(creature) && !HasBeastMastery(bot)) if (IsExoticPet(creature) && !HasBeastMastery(bot))
{ {
botAI->TellError("I cannot use exotic pets unless I have the Beast Mastery talent."); botAI->TellError("Я не могу использовать экзотических питомцев без таланта «Повелитель зверей».");
return false; return false;
} }
// Check if the bot is actually allowed to tame this pet (honoring exotic pet rules) // Check if the bot is actually allowed to tame this pet (honoring exotic pet rules)
if (!creature->IsTameable(bot->CanTameExoticPets())) if (!creature->IsTameable(bot->CanTameExoticPets()))
{ {
botAI->TellError("No tameable pet found with id: " + std::to_string(id)); botAI->TellError("Не найден приручаемый питомец с ID: " + std::to_string(id));
return false; return false;
} }
@@ -258,7 +258,7 @@ bool TameAction::SetPetById(uint32 id)
} }
// If no valid creature was found by id, show an error // If no valid creature was found by id, show an error
botAI->TellError("No tameable pet found with id: " + std::to_string(id)); botAI->TellError("Не найден приручаемый питомец с ID: " + std::to_string(id));
return false; return false;
} }
@@ -316,9 +316,9 @@ bool TameAction::SetPetByFamily(const std::string& family)
if (candidates.empty()) if (candidates.empty())
{ {
if (foundExotic && !HasBeastMastery(bot)) if (foundExotic && !HasBeastMastery(bot))
botAI->TellError("I cannot use exotic pets unless I have the Beast Mastery talent."); botAI->TellError("Я не могу использовать экзотических питомцев без таланта «Повелитель зверей».");
else else
botAI->TellError("No tameable pet found with family: " + family); botAI->TellError("Не найден приручаемый питомец семейства: " + family);
return false; return false;
} }
@@ -343,14 +343,14 @@ bool TameAction::RenamePet(const std::string& newName)
// Check if the bot currently has a pet // Check if the bot currently has a pet
if (!pet) if (!pet)
{ {
botAI->TellError("You have no pet to rename."); botAI->TellError("У вас нет питомца для переименования.");
return false; return false;
} }
// Validate the new name: must not be empty and max 12 characters // Validate the new name: must not be empty and max 12 characters
if (newName.empty() || newName.length() > 12) if (newName.empty() || newName.length() > 12)
{ {
botAI->TellError("Pet name must be between 1 and 12 alphabetic characters."); botAI->TellError("Имя питомца должно содержать от 1 до 12 букв.");
return false; return false;
} }
@@ -359,7 +359,7 @@ bool TameAction::RenamePet(const std::string& newName)
{ {
if (!std::isalpha(static_cast<unsigned char>(c))) if (!std::isalpha(static_cast<unsigned char>(c)))
{ {
botAI->TellError("Pet name must only contain alphabetic characters (A-Z, a-z)."); botAI->TellError("Имя питомца должно состоять только из букв.");
return false; return false;
} }
} }
@@ -373,7 +373,7 @@ bool TameAction::RenamePet(const std::string& newName)
// Check if the new name is reserved or forbidden // Check if the new name is reserved or forbidden
if (sObjectMgr->IsReservedName(normalized)) if (sObjectMgr->IsReservedName(normalized))
{ {
botAI->TellError("That pet name is forbidden. Please choose another name."); botAI->TellError("Это имя питомца запрещено. Выберите другое.");
return false; return false;
} }
@@ -383,8 +383,8 @@ bool TameAction::RenamePet(const std::string& newName)
bot->GetSession()->SendPetNameQuery(pet->GetGUID(), pet->GetEntry()); bot->GetSession()->SendPetNameQuery(pet->GetGUID(), pet->GetEntry());
// Notify the master about the rename and give a tip to update the client name display // Notify the master about the rename and give a tip to update the client name display
botAI->TellMaster("Your pet has been renamed to " + normalized + "!"); botAI->TellMaster("Ваш питомец переименован в " + normalized + "!");
botAI->TellMaster("If you do not see the new name, please dismiss and recall your pet."); botAI->TellMaster("Если новое имя не появилось, отпустите и снова призовите питомца.");
// Remove the current pet and (re-)cast Call Pet spell if the bot is a hunter // Remove the current pet and (re-)cast Call Pet spell if the bot is a hunter
bot->RemovePet(nullptr, PET_SAVE_AS_CURRENT, true); bot->RemovePet(nullptr, PET_SAVE_AS_CURRENT, true);
@@ -402,7 +402,7 @@ bool TameAction::CreateAndSetPet(uint32 creatureEntry)
// Ensure the player is a hunter and at least level 10 (required for pets) // Ensure the player is a hunter and at least level 10 (required for pets)
if (bot->getClass() != CLASS_HUNTER || bot->GetLevel() < 10) if (bot->getClass() != CLASS_HUNTER || bot->GetLevel() < 10)
{ {
botAI->TellError("Only level 10+ hunters can have pets."); botAI->TellError("Питомцы доступны охотникам не ниже 10-го уровня.");
return false; return false;
} }
@@ -410,7 +410,7 @@ bool TameAction::CreateAndSetPet(uint32 creatureEntry)
CreatureTemplate const* creature = sObjectMgr->GetCreatureTemplate(creatureEntry); CreatureTemplate const* creature = sObjectMgr->GetCreatureTemplate(creatureEntry);
if (!creature) if (!creature)
{ {
botAI->TellError("Creature template not found."); botAI->TellError("Шаблон существа не найден.");
return false; return false;
} }
@@ -431,7 +431,7 @@ bool TameAction::CreateAndSetPet(uint32 creatureEntry)
Pet* pet = bot->CreateTamedPetFrom(creatureEntry, 0); Pet* pet = bot->CreateTamedPetFrom(creatureEntry, 0);
if (!pet) if (!pet)
{ {
botAI->TellError("Failed to create pet."); botAI->TellError("Не удалось создать питомца.");
return false; return false;
} }
@@ -486,13 +486,13 @@ bool TameAction::AbandonPet()
// Remove the pet from the bot and mark it as deleted in the database // Remove the pet from the bot and mark it as deleted in the database
bot->RemovePet(pet, PET_SAVE_AS_DELETED); bot->RemovePet(pet, PET_SAVE_AS_DELETED);
// Inform the bot's master/player that the pet was abandoned // Inform the bot's master/player that the pet was abandoned
botAI->TellMaster("Your pet has been abandoned."); botAI->TellMaster("Питомец отпущен.");
return true; return true;
} }
else else
{ {
// If there is no hunter pet, show an error message // If there is no hunter pet, show an error message
botAI->TellError("You have no hunter pet to abandon."); botAI->TellError("У вас нет питомца охотника, которого можно отпустить.");
return false; return false;
} }
} }
@@ -24,7 +24,7 @@ bool TaxiAction::Execute(Event event)
{ {
movement.taxiNodes.clear(); movement.taxiNodes.clear();
movement.Set(nullptr); movement.Set(nullptr);
botAI->TellMaster("I am ready for the next flight"); botAI->TellMaster("Можно отправляться в следующий полёт");
return true; return true;
} }
@@ -82,7 +82,7 @@ bool TaxiAction::Execute(Event event)
if (param == "?") if (param == "?")
{ {
botAI->TellMasterNoFacing("=== Taxi ==="); botAI->TellMasterNoFacing("=== Маршруты полётов ===");
uint32 index = 1; uint32 index = 1;
for (uint32 node : nodes) for (uint32 node : nodes)
@@ -118,13 +118,13 @@ bool TaxiAction::Execute(Event event)
{ {
movement.taxiNodes.clear(); movement.taxiNodes.clear();
movement.Set(nullptr); movement.Set(nullptr);
botAI->TellError("I can't fly with you"); botAI->TellError("Я не могу лететь вместе с вами");
return false; return false;
} }
return true; return true;
} }
botAI->TellError("Cannot find any flightmaster to talk"); botAI->TellError("Не удалось найти распорядителя полётов");
return false; return false;
} }
@@ -54,7 +54,7 @@ bool TeleportAction::Execute(Event /*event*/)
if (closestPortal && bot->IsWithinDistInMap(closestPortal, INTERACTION_DISTANCE)) if (closestPortal && bot->IsWithinDistInMap(closestPortal, INTERACTION_DISTANCE))
{ {
std::ostringstream out; std::ostringstream out;
out << "Using portal: " << closestPortal->GetName(); out << "Использую портал: " << closestPortal->GetName();
botAI->TellMasterNoFacing(out.str()); botAI->TellMasterNoFacing(out.str());
WorldPacket data(CMSG_GAMEOBJ_USE); WorldPacket data(CMSG_GAMEOBJ_USE);
@@ -82,7 +82,7 @@ bool TeleportAction::Execute(Event /*event*/)
continue; continue;
std::ostringstream out; std::ostringstream out;
out << "Teleporting using " << goInfo->name; out << "Телепортируюсь через: " << goInfo->name;
botAI->TellMasterNoFacing(out.str()); botAI->TellMasterNoFacing(out.str());
botAI->ChangeStrategy("-follow,+stay", BOT_STATE_NON_COMBAT); botAI->ChangeStrategy("-follow,+stay", BOT_STATE_NON_COMBAT);
@@ -109,6 +109,6 @@ bool TeleportAction::Execute(Event /*event*/)
} }
// If no teleport option is found // If no teleport option is found
botAI->TellError("Cannot find any portal to teleport"); botAI->TellError("Не удалось найти портал для телепортации");
return false; return false;
} }
@@ -28,26 +28,26 @@ bool TellCastFailedAction::Execute(Event event)
switch (result) switch (result)
{ {
case SPELL_FAILED_NOT_READY: case SPELL_FAILED_NOT_READY:
out << "not ready"; out << "ещё не готово";
break; break;
case SPELL_FAILED_REQUIRES_SPELL_FOCUS: case SPELL_FAILED_REQUIRES_SPELL_FOCUS:
out << "requires spell focus"; out << "требуется объект силы";
break; break;
case SPELL_FAILED_REQUIRES_AREA: case SPELL_FAILED_REQUIRES_AREA:
out << "cannot cast here"; out << "здесь применить нельзя";
break; break;
case SPELL_FAILED_EQUIPPED_ITEM_CLASS: case SPELL_FAILED_EQUIPPED_ITEM_CLASS:
out << "requires item"; out << "требуется предмет";
break; break;
case SPELL_FAILED_EQUIPPED_ITEM_CLASS_MAINHAND: case SPELL_FAILED_EQUIPPED_ITEM_CLASS_MAINHAND:
case SPELL_FAILED_EQUIPPED_ITEM_CLASS_OFFHAND: case SPELL_FAILED_EQUIPPED_ITEM_CLASS_OFFHAND:
out << "requires weapon"; out << "требуется оружие";
break; break;
case SPELL_FAILED_PREVENTED_BY_MECHANIC: case SPELL_FAILED_PREVENTED_BY_MECHANIC:
out << "interrupted"; out << "прервано";
break; break;
default: default:
out << "cannot cast"; out << "невозможно применить";
} }
if (spellInfo->CalcCastTime() >= 2000) if (spellInfo->CalcCastTime() >= 2000)
@@ -105,9 +105,9 @@ bool TellGlyphsAction::Execute(Event event)
// 4. Send chat messages // 4. Send chat messages
//----------------------------------------------------------------- //-----------------------------------------------------------------
if (first) // no glyphs if (first) // no glyphs
botAI->TellMaster("No glyphs equipped"); botAI->TellMaster("Символы не установлены");
else else
botAI->TellMaster(std::string("Glyphs: ") + list.str()); botAI->TellMaster(std::string("Символы: ") + list.str());
return true; return true;
} }
@@ -23,7 +23,7 @@ bool TellItemCountAction::Execute(Event event)
soulbound[proto->ItemId] = item->IsSoulBound(); soulbound[proto->ItemId] = item->IsSoulBound();
} }
botAI->TellMaster("=== Inventory ==="); botAI->TellMaster("=== Инвентарь ===");
for (std::map<uint32, uint32>::iterator i = itemMap.begin(); i != itemMap.end(); ++i) for (std::map<uint32, uint32>::iterator i = itemMap.begin(); i != itemMap.end(); ++i)
{ {
ItemTemplate const* proto = sObjectMgr->GetItemTemplate(i->first); ItemTemplate const* proto = sObjectMgr->GetItemTemplate(i->first);
@@ -77,7 +77,7 @@ void TellLosAction::ListGameObjects(std::string const title, GuidVector gos)
bool TellAuraAction::Execute(Event /*event*/) bool TellAuraAction::Execute(Event /*event*/)
{ {
botAI->TellMaster("--- Auras ---"); botAI->TellMaster("--- Ауры ---");
sLog->outMessage("playerbot", LOG_LEVEL_DEBUG, "--- Auras ---"); sLog->outMessage("playerbot", LOG_LEVEL_DEBUG, "--- Auras ---");
Unit::AuraApplicationMap& map = bot->GetAppliedAuras(); Unit::AuraApplicationMap& map = bot->GetAppliedAuras();
for (Unit::AuraApplicationMap::iterator i = map.begin(); i != map.end(); ++i) for (Unit::AuraApplicationMap::iterator i = map.begin(); i != map.end(); ++i)
@@ -104,7 +104,7 @@ bool TellAuraAction::Execute(Event /*event*/)
" isArea: " + std::to_string(is_area) + " duration: " + std::to_string(duration) + " isArea: " + std::to_string(is_area) + " duration: " + std::to_string(duration) +
" spellId: " + std::to_string(spellId) + " isPositive: " + std::to_string(isPositive)); " spellId: " + std::to_string(spellId) + " isPositive: " + std::to_string(isPositive));
botAI->TellMaster("Info of Aura - name: " + auraName + " caster: " + caster_name + " type: " + botAI->TellMaster("Сведения об ауре — название: " + auraName + " caster: " + caster_name + " type: " +
std::to_string(type) + " owner: " + owner_name + " distance: " + std::to_string(distance) + std::to_string(type) + " owner: " + owner_name + " distance: " + std::to_string(distance) +
" isArea: " + std::to_string(is_area) + " duration: " + std::to_string(duration) + " isArea: " + std::to_string(is_area) + " duration: " + std::to_string(duration) +
" spellId: " + std::to_string(spellId) + " isPositive: " + std::to_string(isPositive)); " spellId: " + std::to_string(spellId) + " isPositive: " + std::to_string(isPositive));
@@ -120,7 +120,7 @@ bool TellAuraAction::Execute(Event /*event*/)
" radius: " + std::to_string(radius) + " spell id: " + std::to_string(spellId) + " radius: " + std::to_string(radius) + " spell id: " + std::to_string(spellId) +
" duration: " + std::to_string(duration)); " duration: " + std::to_string(duration));
botAI->TellMaster(std::string("Info of DynamicObject -") + " name: " + dyn_owner->GetName() + botAI->TellMaster(std::string("Сведения о динамическом объекте —") + " name: " + dyn_owner->GetName() +
" radius: " + std::to_string(radius) + " spell id: " + std::to_string(spellId) + " radius: " + std::to_string(radius) + " spell id: " + std::to_string(spellId) +
" duration: " + std::to_string(duration)); " duration: " + std::to_string(duration));
} }
@@ -131,7 +131,7 @@ bool TellAuraAction::Execute(Event /*event*/)
bool TellEstimatedDpsAction::Execute(Event /*event*/) bool TellEstimatedDpsAction::Execute(Event /*event*/)
{ {
float dps = AI_VALUE(float, "estimated group dps"); float dps = AI_VALUE(float, "estimated group dps");
botAI->TellMaster("Estimated Group DPS: " + std::to_string(dps)); botAI->TellMaster("Расчётный урон группы в секунду: " + std::to_string(dps));
return true; return true;
} }
@@ -147,7 +147,7 @@ bool TellCalculateItemAction::Execute(Event event)
float score = calculator.CalculateItem(item.itemId, item.randomPropertyId); float score = calculator.CalculateItem(item.itemId, item.randomPropertyId);
std::ostringstream out; std::ostringstream out;
out << "Calculated score of " << chat->FormatItem(proto) << " : " << score; out << "Расчётная ценность предмета " << chat->FormatItem(proto) << " : " << score;
botAI->TellMasterNoFacing(out.str()); botAI->TellMasterNoFacing(out.str());
return true; return true;
} }
@@ -16,7 +16,7 @@ bool TellMasterAction::Execute(Event /*event*/)
bool OutOfReactRangeAction::Execute(Event /*event*/) bool OutOfReactRangeAction::Execute(Event /*event*/)
{ {
botAI->TellMaster("Wait for me!"); botAI->TellMaster("Подождите меня!");
return true; return true;
} }
@@ -36,16 +36,16 @@ bool TellReputationAction::Execute(Event /*event*/)
switch (rank) switch (rank)
{ {
case REP_HATED: case REP_HATED:
out << "cc2222hated"; out << "cc2222Ненависть";
break; break;
case REP_HOSTILE: case REP_HOSTILE:
out << "ff0000hostile"; out << "ff0000Враждебность";
break; break;
case REP_UNFRIENDLY: case REP_UNFRIENDLY:
out << "ee6622unfriendly"; out << "ee6622Неприязнь";
break; break;
case REP_NEUTRAL: case REP_NEUTRAL:
out << "ffff00neutral"; out << "ffff00Равнодушие";
break; break;
case REP_FRIENDLY: case REP_FRIENDLY:
out << "00ff00friendly"; out << "00ff00friendly";
@@ -16,7 +16,7 @@ bool TellTargetAction::Execute(Event /*event*/)
if (target) if (target)
{ {
std::ostringstream out; std::ostringstream out;
out << "Attacking " << target->GetName(); out << "Атакую: " << target->GetName();
botAI->TellMaster(out); botAI->TellMaster(out);
context->GetValue<Unit*>("old target")->Set(target); context->GetValue<Unit*>("old target")->Set(target);
@@ -27,7 +27,7 @@ bool TellTargetAction::Execute(Event /*event*/)
bool TellAttackersAction::Execute(Event /*event*/) bool TellAttackersAction::Execute(Event /*event*/)
{ {
botAI->TellMaster("--- Attackers ---"); botAI->TellMaster("--- Атакующие ---");
GuidVector attackers = context->GetValue<GuidVector>("attackers")->Get(); GuidVector attackers = context->GetValue<GuidVector>("attackers")->Get();
int32 count = 0; int32 count = 0;
@@ -40,7 +40,7 @@ bool TellAttackersAction::Execute(Event /*event*/)
botAI->TellMaster(std::to_string(++count) + std::string(".") + unit->GetName()); botAI->TellMaster(std::to_string(++count) + std::string(".") + unit->GetName());
} }
botAI->TellMaster("--- Threat ---"); botAI->TellMaster("--- Угроза ---");
HostileReference* ref = bot->getHostileRefMgr().getFirst(); HostileReference* ref = bot->getHostileRefMgr().getFirst();
if (!ref) if (!ref)
@@ -41,6 +41,14 @@ bool TradeAction::Execute(Event event)
WorldPacket packet(CMSG_INITIATE_TRADE); WorldPacket packet(CMSG_INITIATE_TRADE);
packet << player->GetGUID(); packet << player->GetGUID();
bot->GetSession()->HandleInitiateTradeOpcode(packet); bot->GetSession()->HandleInitiateTradeOpcode(packet);
// HandleInitiateTradeOpcode creates both TradeData objects
// synchronously. Continue processing the same `t <item>` command
// so a natural-language request can both open the trade and place
// the requested item without requiring the player to repeat it.
if (!bot->GetTrader() || bot->GetTrader() != player)
return true;
if (text.empty())
return true; return true;
} }
else if (player->GetTrader() != bot) else if (player->GetTrader() != bot)
@@ -16,6 +16,45 @@
#include "RandomPlayerbotMgr.h" #include "RandomPlayerbotMgr.h"
#include "SetCraftAction.h" #include "SetCraftAction.h"
namespace
{
std::string FormatMoneyRussian(uint32 copper)
{
std::ostringstream out;
if (!copper)
return "0 мед.";
uint32 gold = copper / 10000;
copper -= gold * 10000;
uint32 silver = copper / 100;
copper -= silver * 100;
bool space = false;
if (gold)
{
out << gold << " зол.";
space = true;
}
if (silver && gold < 50)
{
if (space)
out << ' ';
out << silver << " сер.";
space = true;
}
if (copper && gold < 10)
{
if (space)
out << ' ';
out << copper << " мед.";
}
return out.str();
}
}
bool TradeStatusAction::Execute(Event event) bool TradeStatusAction::Execute(Event event)
{ {
Player* trader = bot->GetTrader(); Player* trader = bot->GetTrader();
@@ -28,13 +67,13 @@ bool TradeStatusAction::Execute(Event event)
// Allow the master and group members to trade // Allow the master and group members to trade
if (trader != master && !traderBotAI && (!bot->GetGroup() || !bot->GetGroup()->IsMember(trader->GetGUID()))) if (trader != master && !traderBotAI && (!bot->GetGroup() || !bot->GetGroup()->IsMember(trader->GetGUID())))
{ {
bot->Whisper("I'm kind of busy now", LANG_UNIVERSAL, trader); bot->Whisper("Сейчас мне не до обмена", LANG_UNIVERSAL, trader);
return false; return false;
} }
if (sPlayerbotAIConfig.enableRandomBotTrading == 0 && (sRandomPlayerbotMgr.IsRandomBot(bot)|| sRandomPlayerbotMgr.IsAddclassBot(bot))) if (sPlayerbotAIConfig.enableRandomBotTrading == 0 && (sRandomPlayerbotMgr.IsRandomBot(bot)|| sRandomPlayerbotMgr.IsAddclassBot(bot)))
{ {
bot->Whisper("Trading is disabled", LANG_UNIVERSAL, trader); bot->Whisper("Обмен отключён", LANG_UNIVERSAL, trader);
return false; return false;
} }
@@ -138,7 +177,7 @@ void TradeStatusAction::BeginTrade()
ListItemsVisitor visitor; ListItemsVisitor visitor;
IterateItems(&visitor); IterateItems(&visitor);
botAI->TellMaster("=== Inventory ==="); botAI->TellMaster("=== Инвентарь ===");
TellItems(visitor.items, visitor.soulbound); TellItems(visitor.items, visitor.soulbound);
if (sRandomPlayerbotMgr.IsRandomBot(bot)) if (sRandomPlayerbotMgr.IsRandomBot(bot))
@@ -147,7 +186,7 @@ void TradeStatusAction::BeginTrade()
if (discount) if (discount)
{ {
std::ostringstream out; std::ostringstream out;
out << "Discount up to: " << chat->formatMoney(discount); out << "Доступная скидка: " << FormatMoneyRussian(discount);
botAI->TellMaster(out); botAI->TellMaster(out);
} }
} }
@@ -186,9 +225,9 @@ bool TradeStatusAction::CheckTrade()
{ {
if (bot->GetGroup() && bot->GetGroup()->IsMember(bot->GetTrader()->GetGUID()) && if (bot->GetGroup() && bot->GetGroup()->IsMember(bot->GetTrader()->GetGUID()) &&
botAI->HasRealPlayerMaster()) botAI->HasRealPlayerMaster())
botAI->TellMasterNoFacing("Thank you " + chat->FormatWorldobject(bot->GetTrader())); botAI->TellMasterNoFacing("Спасибо, " + chat->FormatWorldobject(bot->GetTrader()));
else else
bot->Say("Thank you " + chat->FormatWorldobject(bot->GetTrader()), bot->Say("Спасибо, " + chat->FormatWorldobject(bot->GetTrader()),
(bot->GetTeamId() == TEAM_ALLIANCE ? LANG_COMMON : LANG_ORCISH)); (bot->GetTeamId() == TEAM_ALLIANCE ? LANG_COMMON : LANG_ORCISH));
} }
return isGettingItem; return isGettingItem;
@@ -216,12 +255,12 @@ bool TradeStatusAction::CheckTrade()
int32 playerMoney = trader->GetTradeData()->GetMoney() + playerItemsMoney; int32 playerMoney = trader->GetTradeData()->GetMoney() + playerItemsMoney;
if (botItemsMoney > 0 && sPlayerbotAIConfig.enableRandomBotTrading == 2 && (sRandomPlayerbotMgr.IsRandomBot(bot)|| sRandomPlayerbotMgr.IsAddclassBot(bot))) if (botItemsMoney > 0 && sPlayerbotAIConfig.enableRandomBotTrading == 2 && (sRandomPlayerbotMgr.IsRandomBot(bot)|| sRandomPlayerbotMgr.IsAddclassBot(bot)))
{ {
bot->Whisper("Selling is disabled.", LANG_UNIVERSAL, trader); bot->Whisper("Продажа отключена.", LANG_UNIVERSAL, trader);
return false; return false;
} }
if (playerItemsMoney && sPlayerbotAIConfig.enableRandomBotTrading == 3 && (sRandomPlayerbotMgr.IsRandomBot(bot)|| sRandomPlayerbotMgr.IsAddclassBot(bot))) if (playerItemsMoney && sPlayerbotAIConfig.enableRandomBotTrading == 3 && (sRandomPlayerbotMgr.IsRandomBot(bot)|| sRandomPlayerbotMgr.IsAddclassBot(bot)))
{ {
bot->Whisper("Buying is disabled.", LANG_UNIVERSAL, trader); bot->Whisper("Покупка отключена.", LANG_UNIVERSAL, trader);
return false; return false;
} }
for (uint32 slot = 0; slot < TRADE_SLOT_TRADED_COUNT; ++slot) for (uint32 slot = 0; slot < TRADE_SLOT_TRADED_COUNT; ++slot)
@@ -258,7 +297,7 @@ bool TradeStatusAction::CheckTrade()
if (!botItemsMoney && !playerItemsMoney) if (!botItemsMoney && !playerItemsMoney)
{ {
botAI->TellError("There are no items to trade"); botAI->TellError("В обмене нет предметов");
return false; return false;
} }
@@ -272,7 +311,7 @@ bool TradeStatusAction::CheckTrade()
{ {
if (moneyDelta < 0) if (moneyDelta < 0)
{ {
botAI->TellError("You can use discount to buy items only"); botAI->TellError("Скидку можно использовать только для покупки предметов");
botAI->PlaySound(TEXT_EMOTE_NO); botAI->PlaySound(TEXT_EMOTE_NO);
return false; return false;
} }
@@ -288,16 +327,16 @@ bool TradeStatusAction::CheckTrade()
switch (urand(0, 4)) switch (urand(0, 4))
{ {
case 0: case 0:
botAI->TellMaster("A pleasure doing business with you"); botAI->TellMaster("Сделка состоялась");
break; break;
case 1: case 1:
botAI->TellMaster("Fair trade"); botAI->TellMaster("Честный обмен");
break; break;
case 2: case 2:
botAI->TellMaster("Thanks"); botAI->TellMaster("Спасибо");
break; break;
case 3: case 3:
botAI->TellMaster("Off with you"); botAI->TellMaster("До встречи");
break; break;
} }
@@ -306,7 +345,7 @@ bool TradeStatusAction::CheckTrade()
} }
std::ostringstream out; std::ostringstream out;
out << "I want " << chat->formatMoney(-(delta + discount)) << " for this"; out << "За это нужно " << FormatMoneyRussian(-(delta + discount));
botAI->TellMaster(out); botAI->TellMaster(out);
botAI->PlaySound(TEXT_EMOTE_NO); botAI->PlaySound(TEXT_EMOTE_NO);
return false; return false;
@@ -75,7 +75,7 @@ bool TradeStatusExtendedAction::Execute(Event event)
} }
else else
{ {
botAI->TellMaster("I can't unlock this item."); botAI->TellMaster("Я не могу открыть этот предмет.");
} }
} }
} }
@@ -117,7 +117,7 @@ bool TrainerAction::Execute(Event event)
if (trainer_spells.empty()) if (trainer_spells.empty())
{ {
botAI->TellError("No spells can be learned from this trainer"); botAI->TellError("У этого тренера нечему учиться");
return false; return false;
} }
@@ -150,7 +150,7 @@ void TrainerAction::TellFooter(uint32 totalCost)
if (totalCost) if (totalCost)
{ {
std::ostringstream out; std::ostringstream out;
out << "Total cost: " << chat->formatMoney(totalCost); out << "Общая стоимость: " << chat->formatMoney(totalCost);
botAI->TellMaster(out); botAI->TellMaster(out);
} }
} }
@@ -159,11 +159,11 @@ bool MaintenanceAction::Execute(Event /*event*/)
{ {
if (!sPlayerbotAIConfig.maintenanceCommand) if (!sPlayerbotAIConfig.maintenanceCommand)
{ {
botAI->TellError("maintenance command is not allowed, please check the configuration."); botAI->TellError("Команда maintenance отключена. Проверьте настройки.");
return false; return false;
} }
botAI->TellMaster("I'm maintaining"); botAI->TellMaster("Выполняю обслуживание");
PlayerbotFactory factory(bot, bot->GetLevel()); PlayerbotFactory factory(bot, bot->GetLevel());
if (!botAI->IsAlt()) if (!botAI->IsAlt())
@@ -269,18 +269,18 @@ bool AutoGearAction::Execute(Event /*event*/)
{ {
if (!sPlayerbotAIConfig.autoGearCommand) if (!sPlayerbotAIConfig.autoGearCommand)
{ {
botAI->TellError("autogear command is not allowed, please check the configuration."); botAI->TellError("Команда autogear отключена. Проверьте настройки.");
return false; return false;
} }
if (!sPlayerbotAIConfig.autoGearCommandAltBots && if (!sPlayerbotAIConfig.autoGearCommandAltBots &&
!sPlayerbotAIConfig.IsInRandomAccountList(bot->GetSession()->GetAccountId())) !sPlayerbotAIConfig.IsInRandomAccountList(bot->GetSession()->GetAccountId()))
{ {
botAI->TellError("You cannot use autogear on alt bots."); botAI->TellError("Нельзя использовать autogear для ботов альтернативных персонажей.");
return false; return false;
} }
botAI->TellMaster("I'm auto gearing"); botAI->TellMaster("Автоматически подбираю экипировку");
uint32 gs = sPlayerbotAIConfig.autoGearScoreLimit == 0 uint32 gs = sPlayerbotAIConfig.autoGearScoreLimit == 0
? 0 ? 0
: PlayerbotFactory::CalcMixedGearScore(sPlayerbotAIConfig.autoGearScoreLimit, : PlayerbotFactory::CalcMixedGearScore(sPlayerbotAIConfig.autoGearScoreLimit,
@@ -27,9 +27,9 @@ void UnlockItemAction::UnlockItem(Item* item)
if (botAI->CastSpell(PICK_LOCK_SPELL_ID, bot, item)) if (botAI->CastSpell(PICK_LOCK_SPELL_ID, bot, item))
{ {
std::ostringstream out; std::ostringstream out;
out << "Used Pick Lock on: " << item->GetTemplate()->Name1; out << "Замок открыт у предмета: " << item->GetTemplate()->Name1;
botAI->TellMaster(out.str()); botAI->TellMaster(out.str());
} }
else else
botAI->TellError("Failed to cast Pick Lock."); botAI->TellError("Не удалось применить «Взлом замка».");
} }
@@ -18,13 +18,13 @@ bool UnlockTradedItemAction::Execute(Event /*event*/)
Item* lockbox = tradeData->GetItem(TRADE_SLOT_NONTRADED); Item* lockbox = tradeData->GetItem(TRADE_SLOT_NONTRADED);
if (!lockbox) if (!lockbox)
{ {
botAI->TellError("No item in the Do Not Trade slot."); botAI->TellError("В ячейке «Не для обмена» нет предмета.");
return false; return false;
} }
if (!CanUnlockItem(lockbox)) if (!CanUnlockItem(lockbox))
{ {
botAI->TellError("Cannot unlock this item."); botAI->TellError("Этот предмет невозможно открыть.");
return false; return false;
} }
@@ -66,7 +66,7 @@ bool UnlockTradedItemAction::CanUnlockItem(Item* item)
else else
{ {
std::ostringstream out; std::ostringstream out;
out << "Lockpicking skill too low (" << botSkill << "/" << requiredSkill << ") to unlock: " out << "Навык взлома слишком низкий (" << botSkill << "/" << requiredSkill << ") для открытия: "
<< item->GetTemplate()->Name1; << item->GetTemplate()->Name1;
botAI->TellMaster(out.str()); botAI->TellMaster(out.str());
} }
@@ -80,7 +80,7 @@ void UnlockTradedItemAction::UnlockItem(Item* item)
{ {
if (!bot->HasSpell(PICK_LOCK_SPELL_ID)) if (!bot->HasSpell(PICK_LOCK_SPELL_ID))
{ {
botAI->TellError("Cannot unlock, Pick Lock spell is missing."); botAI->TellError("Не удалось открыть: отсутствует навык «Взлом замка».");
return; return;
} }
@@ -88,11 +88,11 @@ void UnlockTradedItemAction::UnlockItem(Item* item)
if (botAI->CastSpell(PICK_LOCK_SPELL_ID, bot->GetTrader(), item)) // Unit target is trader if (botAI->CastSpell(PICK_LOCK_SPELL_ID, bot->GetTrader(), item)) // Unit target is trader
{ {
std::ostringstream out; std::ostringstream out;
out << "Picking Lock on traded item: " << item->GetTemplate()->Name1; out << "Открываю замок на переданном предмете: " << item->GetTemplate()->Name1;
botAI->TellMaster(out.str()); botAI->TellMaster(out.str());
} }
else else
{ {
botAI->TellError("Failed to cast Pick Lock."); botAI->TellError("Не удалось применить «Взлом замка».");
} }
} }
@@ -35,7 +35,7 @@ bool UseItemAction::Execute(Event event)
return UseItemOnGameObject(*items.begin(), *gos.begin()); return UseItemOnGameObject(*items.begin(), *gos.begin());
} }
botAI->TellError("No items (or game objects) available"); botAI->TellError("Нет доступных предметов или игровых объектов");
return false; return false;
} }
@@ -48,7 +48,7 @@ bool UseItemAction::UseGameObject(ObjectGuid guid)
go->Use(bot); go->Use(bot);
std::ostringstream out; std::ostringstream out;
out << "Using " << chat->FormatGameobject(go); out << "Использую: " << chat->FormatGameobject(go);
botAI->TellMasterNoFacing(out.str()); botAI->TellMasterNoFacing(out.str());
return true; return true;
} }
@@ -94,7 +94,7 @@ bool UseItemAction::UseItem(Item* item, ObjectGuid goGuid, Item* itemTarget, Uni
bool targetSelected = false; bool targetSelected = false;
std::ostringstream out; std::ostringstream out;
out << "Using " << chat->FormatItem(item->GetTemplate()); out << "Использую: " << chat->FormatItem(item->GetTemplate());
if (item->GetTemplate()->Stackable > 1) if (item->GetTemplate()->Stackable > 1)
{ {
@@ -125,7 +125,7 @@ bool UseItemAction::UseItem(Item* item, ObjectGuid goGuid, Item* itemTarget, Uni
{ {
bool fit = SocketItem(itemTarget, item) || SocketItem(itemTarget, item, true); bool fit = SocketItem(itemTarget, item) || SocketItem(itemTarget, item, true);
if (!fit) if (!fit)
botAI->TellMaster("Socket does not fit"); botAI->TellMaster("Предмет не подходит для этой ячейки");
return fit; return fit;
} }
@@ -175,7 +175,7 @@ bool UseItemAction::UseItem(Item* item, ObjectGuid goGuid, Item* itemTarget, Uni
bot->GetSession()->HandleQuestgiverAcceptQuestOpcode(packet); bot->GetSession()->HandleQuestgiverAcceptQuestOpcode(packet);
std::ostringstream out; std::ostringstream out;
out << "Got quest " << chat->FormatQuest(qInfo); out << "Получено задание: " << chat->FormatQuest(qInfo);
botAI->TellMasterNoFacing(out.str()); botAI->TellMasterNoFacing(out.str());
return true; return true;
} }
@@ -374,7 +374,7 @@ bool UseItemAction::SocketItem(Item* item, Item* gem, bool replace)
if (fits) if (fits)
{ {
std::ostringstream out; std::ostringstream out;
out << "Socketing " << chat->FormatItem(item->GetTemplate()); out << "Вставляю самоцвет в: " << chat->FormatItem(item->GetTemplate());
out << " with " << chat->FormatItem(gem->GetTemplate()); out << " with " << chat->FormatItem(gem->GetTemplate());
botAI->TellMaster(out); botAI->TellMaster(out);
@@ -36,7 +36,7 @@ bool UseMeetingStoneAction::Execute(Event event)
if (bot->IsInCombat()) if (bot->IsInCombat())
{ {
botAI->TellError("I am in combat"); botAI->TellError("Я в бою");
return false; return false;
} }
@@ -73,13 +73,13 @@ bool SummonAction::Execute(Event /*event*/)
if (SummonUsingGos(master, bot, true) || SummonUsingNpcs(master, bot, true)) if (SummonUsingGos(master, bot, true) || SummonUsingNpcs(master, bot, true))
{ {
botAI->TellMasterNoFacing("Hello!"); botAI->TellMasterNoFacing("Здравствуйте!");
return true; return true;
} }
if (SummonUsingGos(bot, master, true) || SummonUsingNpcs(bot, master, true)) if (SummonUsingGos(bot, master, true) || SummonUsingNpcs(bot, master, true))
{ {
botAI->TellMasterNoFacing("Welcome!"); botAI->TellMasterNoFacing("Добро пожаловать!");
return true; return true;
} }
@@ -153,7 +153,7 @@ bool SummonAction::Teleport(Player* summoner, Player* player, bool preserveAuras
if (player->GetVehicle()) if (player->GetVehicle())
{ {
botAI->TellError("You cannot summon me while I'm on a vehicle"); botAI->TellError("Нельзя призвать меня, пока я нахожусь в транспорте");
return false; return false;
} }
@@ -174,20 +174,20 @@ bool SummonAction::Teleport(Player* summoner, Player* player, bool preserveAuras
if (summoner->IsInCombat() && !sPlayerbotAIConfig.allowSummonInCombat) if (summoner->IsInCombat() && !sPlayerbotAIConfig.allowSummonInCombat)
{ {
botAI->TellError("You cannot summon me while you're in combat"); botAI->TellError("Нельзя призвать меня, пока вы в бою");
return false; return false;
} }
if (!summoner->IsAlive() && !sPlayerbotAIConfig.allowSummonWhenMasterIsDead) if (!summoner->IsAlive() && !sPlayerbotAIConfig.allowSummonWhenMasterIsDead)
{ {
botAI->TellError("You cannot summon me while you're dead"); botAI->TellError("Нельзя призвать меня, пока вы мертвы");
return false; return false;
} }
if (bot->isDead() && !bot->HasPlayerFlag(PLAYER_FLAGS_GHOST) && if (bot->isDead() && !bot->HasPlayerFlag(PLAYER_FLAGS_GHOST) &&
!sPlayerbotAIConfig.allowSummonWhenBotIsDead) !sPlayerbotAIConfig.allowSummonWhenBotIsDead)
{ {
botAI->TellError("You cannot summon me while I'm dead, you need to release my spirit first"); botAI->TellError("Нельзя призвать меня до воскрешения. Сначала освободите мой дух");
return false; return false;
} }
@@ -199,7 +199,7 @@ bool SummonAction::Teleport(Player* summoner, Player* player, bool preserveAuras
{ {
bot->ResurrectPlayer(1.0f, false); bot->ResurrectPlayer(1.0f, false);
bot->SpawnCorpseBones(); bot->SpawnCorpseBones();
botAI->TellMasterNoFacing("I live, again!"); botAI->TellMasterNoFacing("Я снова жив!");
botAI->GetAiObjectContext()->GetValue<GuidVector>("prioritized targets")->Reset(); botAI->GetAiObjectContext()->GetValue<GuidVector>("prioritized targets")->Reset();
} }
@@ -229,6 +229,6 @@ bool SummonAction::Teleport(Player* summoner, Player* player, bool preserveAuras
} }
if (summoner != player) if (summoner != player)
botAI->TellError("Not enough place to summon"); botAI->TellError("Недостаточно места для призыва");
return false; return false;
} }
@@ -54,7 +54,7 @@ bool WhoAction::Execute(Event event)
if (!out.str().empty()) if (!out.str().empty())
out << ", "; out << ", ";
out << "playing with " << botAI->GetMaster()->GetName(); out << "играет вместе с: " << botAI->GetMaster()->GetName();
} }
std::string const tell = out.str(); std::string const tell = out.str();
@@ -78,7 +78,7 @@ std::string const WhoAction::QueryTrade(std::string const text)
if (!sellPrice) if (!sellPrice)
continue; continue;
out << "Selling " << chat->FormatItem(sell->GetTemplate(), sell->GetCount()) << " for " out << "Продаю: " << chat->FormatItem(sell->GetTemplate(), sell->GetCount()) << " за "
<< chat->formatMoney(sellPrice); << chat->formatMoney(sellPrice);
return out.str(); return out.str();
} }
@@ -50,7 +50,7 @@ bool WtsAction::Execute(Event event)
continue; continue;
std::ostringstream tell; std::ostringstream tell;
tell << "I'll buy " << chat->FormatItem(proto) << " for " << chat->formatMoney(buyPrice); tell << "Я куплю: " << chat->FormatItem(proto) << " за " << chat->formatMoney(buyPrice);
// ignore random bot chat filter // ignore random bot chat filter
bot->Whisper(tell.str(), LANG_UNIVERSAL, owner); bot->Whisper(tell.str(), LANG_UNIVERSAL, owner);

Some files were not shown because too many files have changed in this diff Show More