Compare commits

..

1 Commits

Author SHA1 Message Date
Yunfan Li
6003dbc1b5 Directory reorganization 2025-05-07 00:06:31 +08:00
1375 changed files with 137292 additions and 175377 deletions

View File

@@ -1,40 +0,0 @@
name: C++ Codestyle
on:
pull_request:
types:
- opened
- reopened
- synchronize
- ready_for_review
paths:
- src/**
- "!README.md"
- "!docs/**"
concurrency:
group: "codestyle-cppcheck-${{ github.event.pull_request.number }}"
cancel-in-progress: true
jobs:
triage:
runs-on: ubuntu-latest
name: C++
if: github.event.pull_request.draft == false
steps:
- uses: actions/checkout@v4
- name: Setup python
uses: actions/setup-python@v5
with:
python-version: '3.10'
- name: AzerothCore codestyle
run: python ./apps/codestyle/codestyle-cpp.py
- name: C++ Advanced
run: |
sudo apt update -y
sudo apt install -y cppcheck
cppcheck --force --inline-suppr --suppressions-list=./.suppress.cppcheck src/ --output-file=report.txt
if [ -s report.txt ]; then # if file is not empty
cat report.txt
exit 1 # let github action fails
fi

View File

@@ -38,7 +38,7 @@ jobs:
- name: Checkout AzerothCore
uses: actions/checkout@v3
with:
repository: 'mod-playerbots/azerothcore-wotlk'
repository: 'liyunfan1223/azerothcore-wotlk'
ref: 'Playerbot'
- name: Set reusable strings
@@ -50,7 +50,7 @@ jobs:
- name: Checkout Playerbot Module
uses: actions/checkout@v3
with:
repository: 'mod-playerbots/mod-playerbots'
repository: 'liyunfan1223/mod-playerbots'
path: 'modules/mod-playerbots'
- name: Cache

View File

@@ -22,12 +22,12 @@ jobs:
- name: Checkout AzerothCore
uses: actions/checkout@v4
with:
repository: 'mod-playerbots/azerothcore-wotlk'
repository: 'liyunfan1223/azerothcore-wotlk'
ref: 'Playerbot'
- name: Checkout Playerbot Module
uses: actions/checkout@v4
with:
repository: 'mod-playerbots/mod-playerbots'
repository: 'liyunfan1223/mod-playerbots'
path: 'modules/mod-playerbots'
- name: Cache
uses: actions/cache@v4

View File

@@ -23,27 +23,23 @@ jobs:
- name: Checkout AzerothCore
uses: actions/checkout@v3
with:
repository: 'mod-playerbots/azerothcore-wotlk'
repository: 'liyunfan1223/azerothcore-wotlk'
ref: 'Playerbot'
path: 'ac'
- name: Checkout Playerbot Module
uses: actions/checkout@v3
with:
repository: 'mod-playerbots/mod-playerbots'
#path: 'modules/mod-playerbots'
path: ac/modules/mod-playerbots
repository: 'liyunfan1223/mod-playerbots'
path: 'modules/mod-playerbots'
- name: ccache
uses: hendrikmuhs/ccache-action@v1.2.13
- name: Configure OS
shell: bash
working-directory: ac
env:
CONTINUOUS_INTEGRATION: true
run: |
./acore.sh install-deps
- name: Build
shell: bash
working-directory: ac
run: |
export CTOOLS_BUILD=all
./acore.sh compiler build

3
.gitignore vendored
View File

@@ -48,5 +48,4 @@ local.properties
.loadpath
.project
.cproject
.vscode
.idea
.vscode

View File

@@ -1 +0,0 @@
cppcheckError

View File

@@ -1,9 +1,7 @@
<p align="center">
<a href="https://github.com/mod-playerbots/mod-playerbots/blob/master/README.md">English</a>
<a href="https://github.com/liyunfan1223/mod-playerbots/blob/master/README.md">English</a>
|
<a href="https://github.com/mod-playerbots/mod-playerbots/blob/master/README_CN.md">中文</a>
|
<a href="https://github.com/mod-playerbots/mod-playerbots/blob/master/README_ES.md">Español</a>
<a href="https://github.com/liyunfan1223/mod-playerbots/blob/master/README_CN.md">中文</a>
</p>
@@ -12,50 +10,46 @@
</div>
<div align="center">
<img src="https://github.com/mod-playerbots/mod-playerbots/actions/workflows/macos_build.yml/badge.svg">
<img src="https://github.com/mod-playerbots/mod-playerbots/actions/workflows/core_build.yml/badge.svg">
<img src="https://github.com/mod-playerbots/mod-playerbots/actions/workflows/windows_build.yml/badge.svg">
<img src="https://github.com/liyunfan1223/mod-playerbots/actions/workflows/macos_build.yml/badge.svg">
<img src="https://github.com/liyunfan1223/mod-playerbots/actions/workflows/core_build.yml/badge.svg">
<img src="https://github.com/liyunfan1223/mod-playerbots/actions/workflows/windows_build.yml/badge.svg">
</div>
# Playerbots Module
`mod-playerbots` is an [AzerothCore](https://www.azerothcore.org/) module that adds player-like bots to a server. The project is based off [IKE3's Playerbots](https://github.com/ike3/mangosbot).
`mod-playerbots` is an [AzerothCore](https://www.azerothcore.org/) module that adds player-like bots to a server. The project is based off [IKE3's Playerbots](https://github.com/ike3/mangosbot). Features include:
Features include:
- Bots that utilize real player data, allowing players to interact with their other characters, form parties, level up, and more;
- Random bots that wander through the world and behave like players, simulating the MMO experience;
- Bots capable of running raids and battlegrounds;
- Highly configurable settings to define how bots behave;
- Excellent performance, even when running thousands of bots.
- The ability to log in alt characters as bots, allowing players to interact with their other characters, form parties, level up, and more
- Random bots that wander through the world, complete quests, and otherwise behave like players, simulating the MMO experience
- Bots capable of running most raids and battlegrounds
- Highly configurable settings to define how bots behave
- Excellent performance, even when running thousands of bots
**This project is still under development**. If you encounter any errors or experience crashes, we kindly request that you [report them as GitHub issues](https://github.com/liyunfan1223/mod-playerbots/issues/new?template=bug_report.md). Your valuable feedback will help us improve this project collaboratively.
We also have a **[Discord server](https://discord.gg/NQm5QShwf9)** where you can discuss the project, ask questions, and get involved in the community!
**Playerbots Module** has a **[Discord server](https://discord.gg/NQm5QShwf9)** where you can discuss the project.
## Installation
Supported platforms are Ubuntu, Windows, and macOS. Other Linux distributions may work, but may not receive support.
### Classic Installation
**All `mod-playerbots` installations require a custom branch of AzerothCore: [mod-playerbots/azerothcore-wotlk/tree/Playerbot](https://github.com/mod-playerbots/azerothcore-wotlk/tree/Playerbot).** This branch allows the `mod-playerbots` module to build and function. Updates from the upstream are implemented regularly to this branch. Instructions for installing this required branch and this module are provided below.
### Cloning the Repositories
To install both the required branch of AzerothCore and the `mod-playerbots` module from source, run the following:
`mod-playerbots` requires a custom branch of AzerothCore to work: [liyunfan1223/azerothcore-wotlk/tree/Playerbot](https://github.com/liyunfan1223/azerothcore-wotlk/tree/Playerbot). To install the module, simply run:
```bash
git clone https://github.com/mod-playerbots/azerothcore-wotlk.git --branch=Playerbot
git clone https://github.com/liyunfan1223/azerothcore-wotlk.git --branch=Playerbot
cd azerothcore-wotlk/modules
git clone https://github.com/mod-playerbots/mod-playerbots.git --branch=master
git clone https://github.com/liyunfan1223/mod-playerbots.git --branch=master
```
For more information, refer to the [AzerothCore Installation Guide](https://www.azerothcore.org/wiki/installation) and [Installing a Module](https://www.azerothcore.org/wiki/installing-a-module) pages.
### Docker Installation
Docker installations are considered experimental (unofficial with limited support), and previous Docker experience is recommended. To install `mod-playerbots` on Docker, first clone the required branch of AzerothCore and this module:
**Docker installation is considered experimental.** To install the module on a Docker installation, run:
```bash
git clone https://github.com/mod-playerbots/azerothcore-wotlk.git --branch=Playerbot
git clone https://github.com/liyunfan1223/azerothcore-wotlk.git --branch=Playerbot
cd azerothcore-wotlk/modules
git clone https://github.com/mod-playerbots/mod-playerbots.git --branch=master
git clone https://github.com/liyunfan1223/mod-playerbots.git --branch=master
```
Afterwards, create a `docker-compose.override.yml` file in the `azerothcore-wotlk` directory. This override file allows for mounting the modules directory to the `ac-worldserver` service which is required for it to run. Put the following inside and save:
@@ -79,34 +73,36 @@ services:
- ./modules:/azerothcore/modules:ro
```
For example, to double the experience gain rate per kill, take the setting `Rate.XP.Kill = 1` from [woldserver.conf](https://github.com/mod-playerbots/azerothcore-wotlk/blob/Playerbot/src/server/apps/worldserver/worldserver.conf.dist), convert it to an environment variable, and change it to the desired setting in the override file to get `AC_RATE_XP_KILL: "2"`. If you wanted to disable random bots from logging in automatically, take the `AiPlayerbot.RandomBotAutologin = 1` setting from [playerbots.conf](https://github.com/mod-playerbots/mod-playerbots/blob/master/conf/playerbots.conf.dist) and do the same to get `AC_AI_PLAYERBOT_RANDOM_BOT_AUTOLOGIN: "0"`. For more information on how to configure Azerothcore, Playerbots, and other module settings as environment variables in Docker Compose, see the "Configuring AzerothCore in Containers" section in the [Install With Docker](https://www.azerothcore.org/wiki/install-with-docker) guide.
For example, to double the experience gain rate per kill, take the setting `Rate.XP.Kill = 1` from [woldserver.conf](https://github.com/liyunfan1223/azerothcore-wotlk/blob/Playerbot/src/server/apps/worldserver/worldserver.conf.dist), convert it to an environment variable, and change it to the desired setting in the override file to get `AC_RATE_XP_KILL: "2"`. If you wanted to disable random bots from logging in automatically, take the `AiPlayerbot.RandomBotAutologin = 1` setting from [playerbots.conf](https://github.com/liyunfan1223/mod-playerbots/blob/master/conf/playerbots.conf.dist) and do the same to get `AC_AI_PLAYERBOT_RANDOM_BOT_AUTOLOGIN: "0"`. For more information on how to configure Azerothcore, Playerbots, and other module settings as environment variables in Docker Compose, see the "Configuring AzerothCore in Containers" section in the [Install With Docker](https://www.azerothcore.org/wiki/install-with-docker) guide.
Before building, consider setting the database password. One way to do this is to create a `.env` file in the root `azerothcore-wotlk` directory using the [template](https://github.com/mod-playerbots/azerothcore-wotlk/blob/Playerbot/conf/dist/env.docker). This file also allows you to set the user and group Docker uses for the services in case you run into any permissions issues, which are the most common cause for Docker installation problems.
Before building, consider setting the database password. One way to do this is to create a `.env` file in the root `azerothcore-wotlk` directory using the [template](https://github.com/liyunfan1223/azerothcore-wotlk/blob/Playerbot/conf/dist/env.docker). This file also allows you to set the user and group Docker uses for the services in case you run into any permissions issues, which are the most common cause for Docker installation problems.
Use `docker compose up -d --build` to build and run the server. For more information, including how to create an account and taking backups, refer to the [Install With Docker](https://www.azerothcore.org/wiki/install-with-docker) page.
## Documentation
The [Playerbots Wiki](https://github.com/mod-playerbots/mod-playerbots/wiki) contains an extensive overview of AddOns, commands, raids with programmed bot strategies, and recommended performance configurations. Please note that documentation may be incomplete or out-of-date in some sections, and contributions are welcome.
The [Playerbots Wiki](https://github.com/liyunfan1223/mod-playerbots/wiki) contains an extensive overview of addons, commands, and recommended configurations. Please note that documentation may be incomplete or out-of-date in some sections. Contributions are welcome.
Bots are controlled via chat commands. For larger bot groups, this can be cumbersome. Because of this, community members have developed client AddOns to allow controlling bots through the in-game UI. We recommend you check out their projects listed in the [AddOns and Submodules](https://github.com/mod-playerbots/mod-playerbots/wiki/Playerbot-Addons-and-Sub%E2%80%90Modules) page.
## Frequently Asked Questions
## Contributing
- **Why aren't my bots casting spells?** Please make sure that the necessary English DBC file (enUS) is present.
- **What platforms are supported?** We support Ubuntu, Windows, and macOS. Other Linux distros may work, but will not receive support.
- **Why isn't my source compiling?** Please [check the build status of our CI](https://github.com/liyunfan1223/mod-playerbots/actions). If the latest build is failing, rever to the last successful commit until we address the issue.
This project is still under development. We encourage anyone to make contributions, anything from pull requests to reporting issues. If you encounter any errors or experience crashes, we encourage you [report them as GitHub issues](https://github.com/mod-playerbots/mod-playerbots/issues/new?template=bug_report.md). Your valuable feedback will help us improve this project collaboratively.
## Addons
If you make coding contributions, `mod-playerbots` complies with the [C++ Code Standards](https://www.azerothcore.org/wiki/cpp-code-standards) established by AzerothCore. Each Pull Request must include all test scenarios the author performed, along with their results, to demonstrate that the changes were properly verified.
Typically, bots are controlled via chat commands. For larger bot groups, this can be unwieldy. As an alternative, community members have developed client Add-Ons to allow controlling bots through the in-game UI. We recommend you check out their projects:
We recommend joining the [Discord server](https://discord.gg/NQm5QShwf9) to make your contributions to the project easier, as a lot of active support is carried out through this server.
Please click on the "⭐" button to stay up to date and help us gain more visibility on GitHub!
- [Multibot](https://github.com/Macx-Lio/MultiBot) (by Macx-Lio)
- [Unbot Addon (zh)](https://github.com/liyunfan1223/unbot-addon) (Chinese version by Liyunfan)
- [Unbot Addon (en)](https://github.com/noisiver/unbot-addon/tree/english) (English version translated by @Revision)
## Acknowledgements
`mod-playerbots` is based on [ZhengPeiRu21/mod-playerbots](https://github.com/ZhengPeiRu21/mod-playerbots) and [celguar/mangosbot-bots](https://github.com/celguar/mangosbot-bots). We extend our gratitude to [@ZhengPeiRu21](https://github.com/ZhengPeiRu21) and [@celguar](https://github.com/celguar) for their continued efforts in maintaining the module.
`mod-playerbots` is is based off [ZhengPeiRu21/mod-playerbots](https://github.com/ZhengPeiRu21/mod-playerbots) and [celguar/mangosbot-bots](https://github.com/celguar/mangosbot-bots). We extend our gratitude to [@ZhengPeiRu21](https://github.com/ZhengPeiRu21) and [@celguar](https://github.com/celguar) for the continued efforts in maintaining the module.
Also, a thank you to the many contributors who've helped build this project:
<a href="https://github.com/mod-playerbots/mod-playerbots/graphs/contributors">
<img src="https://contrib.rocks/image?repo=mod-playerbots/mod-playerbots" />
<a href="https://github.com/liyunfan1223/mod-playerbots/graphs/contributors">
<img src="https://contrib.rocks/image?repo=liyunfan1223/mod-playerbots" />
</a>

View File

@@ -8,16 +8,16 @@
## 安装
请注意此模块需要对AzerothCore进行特定的自定义更改。为了确保兼容性您必须使用我fork的自定义分支来编译它可以在这里找到[mod-playerbots/azerothcore-wotlk/tree/Playerbot](https://github.com/mod-playerbots/azerothcore-wotlk/tree/Playerbot)。
请注意此模块需要对AzerothCore进行特定的自定义更改。为了确保兼容性您必须使用我fork的自定义分支来编译它可以在这里找到[liyunfan1223/azerothcore-wotlk/tree/Playerbot](https://github.com/liyunfan1223/azerothcore-wotlk/tree/Playerbot)。
要安装此模块请参考AzerothCore Wiki的详细说明[AzerothCore安装指南](https://www.azerothcore.org/wiki/installation)。
我们提供了一个简单的方法来克隆该模块:
```bash
git clone https://github.com/mod-playerbots/azerothcore-wotlk.git --branch=Playerbot
git clone https://github.com/liyunfan1223/azerothcore-wotlk.git --branch=Playerbot
cd azerothcore-wotlk/modules
git clone https://github.com/mod-playerbots/mod-playerbots.git --branch=master
git clone https://github.com/liyunfan1223/mod-playerbots.git --branch=master
```
## 快速开始与文档
@@ -60,7 +60,7 @@ git clone https://github.com/mod-playerbots/mod-playerbots.git --branch=master
- 我们支持Ubuntu、Windows和macOS。
- 我们建立了持续集成工作流。您可以在[GitHub Actions](https://github.com/mod-playerbots/mod-playerbots/actions)中查看构建状态。
- 我们建立了持续集成工作流。您可以在[GitHub Actions](https://github.com/liyunfan1223/mod-playerbots/actions)中查看构建状态。
- 如果最新的构建状态失败,请恢复到上一个提交。我们将尽快解决此问题。

View File

@@ -1,263 +0,0 @@
import io
import os
import sys
import re
# Get the src directory of the project
src_directory = os.path.join(os.getcwd(), 'src')
# Global variables
error_handler = False
results = {
"Multiple blank lines check": "Passed",
"Trailing whitespace check": "Passed",
"GetCounter() check": "Passed",
"Misc codestyle check": "Passed",
"GetTypeId() check": "Passed",
"NpcFlagHelpers check": "Passed",
"ItemFlagHelpers check": "Passed",
"ItemTemplateFlagHelpers check": "Passed"
}
# Main function to parse all the files of the project
def parsing_file(directory: str) -> None:
print("Starting AzerothCore CPP Codestyle check...")
print(" ")
print("Please read the C++ Code Standards for AzerothCore:")
print("https://www.azerothcore.org/wiki/cpp-code-standards")
print(" ")
for root, _, files in os.walk(directory):
for file in files:
if not file.endswith('.ico'): # Skip .ico files that cannot be read
file_path = os.path.join(root, file)
file_name = file
try:
with open(file_path, 'r', encoding='utf-8') as file:
multiple_blank_lines_check(file, file_path)
trailing_whitespace_check(file, file_path)
get_counter_check(file, file_path)
if not file_name.endswith('.cmake') and file_name != 'CMakeLists.txt':
misc_codestyle_check(file, file_path)
if file_name != 'Object.h':
get_typeid_check(file, file_path)
if file_name != 'Unit.h':
npcflags_helpers_check(file, file_path)
if file_name != 'Item.h':
itemflag_helpers_check(file, file_path)
if file_name != 'ItemTemplate.h':
itemtemplateflag_helpers_check(file, file_path)
except UnicodeDecodeError:
print(f"\nCould not decode file {file_path}")
sys.exit(1)
# Output the results
print("")
for check, result in results.items():
print(f"{check} : {result}")
if error_handler:
print("\nPlease fix the codestyle issues above.")
sys.exit(1)
else:
print(f"\nEverything looks good")
# Codestyle patterns checking for multiple blank lines
def multiple_blank_lines_check(file: io, file_path: str) -> None:
global error_handler, results
file.seek(0) # Reset file pointer to the beginning
check_failed = False
consecutive_blank_lines = 0
# Parse all the file
for line_number, line in enumerate(file, start = 1):
if line.strip() == '':
consecutive_blank_lines += 1
if consecutive_blank_lines > 1:
print(f"Multiple blank lines found in {file_path} at line {line_number - 1}")
check_failed = True
else:
consecutive_blank_lines = 0
# Additional check for the end of the file
if consecutive_blank_lines >= 1:
print(f"Multiple blank lines found at the end of: {file_path}")
check_failed = True
# Handle the script error and update the result output
if check_failed:
error_handler = True
results["Multiple blank lines check"] = "Failed"
# Codestyle patterns checking for whitespace at the end of the lines
def trailing_whitespace_check(file: io, file_path: str) -> None:
global error_handler, results
file.seek(0) # Reset file pointer to the beginning
# Parse all the file
for line_number, line in enumerate(file, start = 1):
if line.endswith(' \n'):
print(f"Trailing whitespace found: {file_path} at line {line_number}")
if not error_handler:
error_handler = True
results["Trailing whitespace check"] = "Failed"
# Codestyle patterns checking for ObjectGuid::GetCounter()
def get_counter_check(file: io, file_path: str) -> None:
global error_handler, results
file.seek(0) # Reset file pointer to the beginning
# Parse all the file
for line_number, line in enumerate(file, start = 1):
if 'ObjectGuid::GetCounter()' in line:
print(f"Please use ObjectGuid::ToString().c_str() instead ObjectGuid::GetCounter(): {file_path} at line {line_number}")
if not error_handler:
error_handler = True
results["GetCounter() check"] = "Failed"
# Codestyle patterns checking for GetTypeId()
def get_typeid_check(file: io, file_path: str) -> None:
global error_handler, results
file.seek(0) # Reset file pointer to the beginning
check_failed = False
# Parse all the file
for line_number, line in enumerate(file, start = 1):
if 'GetTypeId() == TYPEID_ITEM' in line or 'GetTypeId() != TYPEID_ITEM' in line:
print(f"Please use IsItem() instead of GetTypeId(): {file_path} at line {line_number}")
check_failed = True
if 'GetTypeId() == TYPEID_UNIT' in line or 'GetTypeId() != TYPEID_UNIT' in line:
print(f"Please use IsCreature() instead of GetTypeId(): {file_path} at line {line_number}")
check_failed = True
if 'GetTypeId() == TYPEID_PLAYER' in line or 'GetTypeId() != TYPEID_PLAYER' in line:
print(f"Please use IsPlayer() instead of GetTypeId(): {file_path} at line {line_number}")
check_failed = True
if 'GetTypeId() == TYPEID_GAMEOBJECT' in line or 'GetTypeId() != TYPEID_GAMEOBJECT' in line:
print(f"Please use IsGameObject() instead of GetTypeId(): {file_path} at line {line_number}")
check_failed = True
if 'GetTypeId() == TYPEID_DYNOBJECT' in line or 'GetTypeId() != TYPEID_DYNOBJECT' in line:
print(f"Please use IsDynamicObject() instead of GetTypeId(): {file_path} at line {line_number}")
check_failed = True
# Handle the script error and update the result output
if check_failed:
error_handler = True
results["GetTypeId() check"] = "Failed"
# Codestyle patterns checking for NpcFlag helpers
def npcflags_helpers_check(file: io, file_path: str) -> None:
global error_handler, results
file.seek(0) # Reset file pointer to the beginning
check_failed = False
# Parse all the file
for line_number, line in enumerate(file, start = 1):
if 'GetUInt32Value(UNIT_NPC_FLAGS)' in line:
print(
f"Please use GetNpcFlags() instead of GetUInt32Value(UNIT_NPC_FLAGS): {file_path} at line {line_number}")
check_failed = True
if 'HasFlag(UNIT_NPC_FLAGS,' in line:
print(
f"Please use HasNpcFlag() instead of HasFlag(UNIT_NPC_FLAGS, ...): {file_path} at line {line_number}")
check_failed = True
if 'SetUInt32Value(UNIT_NPC_FLAGS,' in line:
print(
f"Please use ReplaceAllNpcFlags() instead of SetUInt32Value(UNIT_NPC_FLAGS, ...): {file_path} at line {line_number}")
check_failed = True
if 'SetFlag(UNIT_NPC_FLAGS,' in line:
print(
f"Please use SetNpcFlag() instead of SetFlag(UNIT_NPC_FLAGS, ...): {file_path} at line {line_number}")
check_failed = True
if 'RemoveFlag(UNIT_NPC_FLAGS,' in line:
print(
f"Please use RemoveNpcFlag() instead of RemoveFlag(UNIT_NPC_FLAGS, ...): {file_path} at line {line_number}")
check_failed = True
# Handle the script error and update the result output
if check_failed:
error_handler = True
results["NpcFlagHelpers check"] = "Failed"
# Codestyle patterns checking for ItemFlag helpers
def itemflag_helpers_check(file: io, file_path: str) -> None:
global error_handler, results
file.seek(0) # Reset file pointer to the beginning
check_failed = False
# Parse all the file
for line_number, line in enumerate(file, start = 1):
if 'HasFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_REFUNDABLE)' in line:
print(
f"Please use IsRefundable() instead of HasFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_REFUNDABLE): {file_path} at line {line_number}")
check_failed = True
if 'HasFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_BOP_TRADEABLE)' in line:
print(
f"Please use IsBOPTradable() instead of HasFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_BOP_TRADEABLE): {file_path} at line {line_number}")
check_failed = True
if 'HasFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_WRAPPED)' in line:
print(
f"Please use IsWrapped() instead of HasFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_WRAPPED): {file_path} at line {line_number}")
check_failed = True
# Handle the script error and update the result output
if check_failed:
error_handler = True
results["ItemFlagHelpers check"] = "Failed"
# Codestyle patterns checking for ItemTemplate helpers
def itemtemplateflag_helpers_check(file: io, file_path: str) -> None:
global error_handler, results
file.seek(0) # Reset file pointer to the beginning
check_failed = False
# Parse all the file
for line_number, line in enumerate(file, start = 1):
if 'Flags & ITEM_FLAG' in line:
print(
f"Please use HasFlag(ItemFlag) instead of 'Flags & ITEM_FLAG_': {file_path} at line {line_number}")
check_failed = True
if 'Flags2 & ITEM_FLAG2' in line:
print(
f"Please use HasFlag2(ItemFlag2) instead of 'Flags2 & ITEM_FLAG2_': {file_path} at line {line_number}")
check_failed = True
if 'FlagsCu & ITEM_FLAGS_CU' in line:
print(
f"Please use HasFlagCu(ItemFlagsCustom) instead of 'FlagsCu & ITEM_FLAGS_CU_': {file_path} at line {line_number}")
check_failed = True
# Handle the script error and update the result output
if check_failed:
error_handler = True
results["ItemTemplateFlagHelpers check"] = "Failed"
# Codestyle patterns checking for various codestyle issues
def misc_codestyle_check(file: io, file_path: str) -> None:
global error_handler, results
file.seek(0) # Reset file pointer to the beginning
check_failed = False
# used to check for "if/else (...) {" "} else" ignores "if/else (...) {...}" "#define ... if/else (...) {"
ifelse_curlyregex = r"^[^#define].*\s+(if|else)(\s*\(.*\))?\s*{[^}]*$|}\s*else(\s*{[^}]*$)"
# used to catch double semicolons ";;" ignores "(;;)"
double_semiregex = r"(?<!\()\s*;;(?!\))"
# used to catch tabs
tab_regex = r"\t"
# Parse all the file
for line_number, line in enumerate(file, start = 1):
if 'const auto&' in line:
print(
f"Please use the 'auto const&' syntax instead of 'const auto&': {file_path} at line {line_number}")
check_failed = True
if re.search(r'\bconst\s+\w+\s*\*\b', line):
print(
f"Please use the 'Class/ObjectType const*' syntax instead of 'const Class/ObjectType*': {file_path} at line {line_number}")
check_failed = True
if [match for match in [' if(', ' if ( '] if match in line]:
print(
f"Please use the 'if (XXXX)' syntax instead of 'if(XXXX)': {file_path} at line {line_number}")
check_failed = True
if re.match(ifelse_curlyregex, line):
print(
f"Curly brackets are not allowed to be leading or trailing if/else statements. Place it on a new line: {file_path} at line {line_number}")
check_failed = True
if re.search(double_semiregex, line):
print(
f"Double semicolon (;;) found in {file_path} at line {line_number}")
check_failed = True
if re.match(tab_regex, line):
print(
f"Tab found! Replace it to 4 spaces: {file_path} at line {line_number}")
check_failed = True
# Handle the script error and update the result output
if check_failed:
error_handler = True
results["Misc codestyle check"] = "Failed"
# Main function
parsing_file(src_directory)

2
code_format.sh Normal file → Executable file
View File

@@ -15,4 +15,4 @@ for file in $cpp_files; do
$CLANG_FORMAT_PATH -i $file
done
echo "All .cpp or .h files have been formatted."
echo "All .cpp or .h files have been formatted."

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +0,0 @@
UPDATE guild
SET
EmblemStyle = FLOOR(RAND() * 181),
EmblemColor = FLOOR(RAND() * 18),
BorderStyle = FLOOR(RAND() * 8),
BorderColor = FLOOR(RAND() * 18),
BackgroundColor = FLOOR(RAND() * 52)
WHERE EmblemStyle=0 AND EmblemColor=0 AND BorderStyle=0 AND BorderColor=0 AND BackgroundColor=0;

File diff suppressed because it is too large Load Diff

View File

@@ -8,7 +8,7 @@ CREATE TABLE IF NOT EXISTS `ai_playerbot_texts_chance` (
/*!40000 ALTER TABLE `ai_playerbot_texts_chance` DISABLE KEYS */;
INSERT INTO `ai_playerbot_texts_chance` (`id`, `name`, `probability`) VALUES
(1, 'taunt', 30),
(2, 'aoe', 75),
(3, 'loot', 20);
(1, 'taunt', 30),
(2, 'aoe', 75),
(3, 'loot', 20);
/*!40000 ALTER TABLE `ai_playerbot_texts_chance` ENABLE KEYS */;

View File

@@ -1,6 +1,6 @@
DROP TABLE IF EXISTS `playerbots_account_keys`;
DROP TABLE IF EXISTS `playerbot_account_keys`;
CREATE TABLE `playerbots_account_keys` (
CREATE TABLE `playerbot_account_keys` (
`account_id` INT PRIMARY KEY,
`security_key` VARCHAR(255) NOT NULL,
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP

View File

@@ -1,6 +1,6 @@
DROP TABLE IF EXISTS `playerbots_account_links`;
DROP TABLE IF EXISTS `playerbot_account_links`;
CREATE TABLE `playerbots_account_links` (
CREATE TABLE `playerbot_account_links` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`account_id` INT NOT NULL,
`linked_account_id` INT NOT NULL,

View File

@@ -1,8 +0,0 @@
DROP TABLE IF EXISTS `playerbots_account_type`;
CREATE TABLE `playerbots_account_type` (
`account_id` int unsigned NOT NULL,
`account_type` tinyint unsigned NOT NULL DEFAULT 0 COMMENT '0 = unassigned, 1 = RNDbot, 2 = AddClass',
`assignment_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`account_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Playerbot account type assignments';

View File

@@ -53,16 +53,16 @@ INSERT INTO `playerbots_dungeon_suggestion_definition` VALUES
(NULL, 'ub' , 'The Underbog' , 1, 0, 62, 70, NULL),
(NULL, 'mt' , 'Mana-Tombs' , 1, 0, 63, 70, NULL),
(NULL, 'ac' , 'Auchenai Crypts' , 1, 0, 64, 70, NULL),
(NULL, 'seth', 'Sethekk Halls' , 1, 0, 66, 70, NULL),
(NULL, 'seth', 'Sethekk Halls' , 1, 0, 66, 70, NULL),
(NULL, 'oh' , 'Old Hillsbrad Foothills', 1, 0, 66, 70, NULL),
(NULL, 'bm' , 'The Black Morass' , 1, 0, 68, 70, NULL),
(NULL, 'mech', 'The Mechanar' , 1, 0, 68, 70, NULL),
(NULL, 'bot' , 'The Botanica' , 1, 0, 69, 70, NULL),
(NULL, 'arc' , 'The Arcatraz' , 1, 0, 69, 70, NULL),
(NULL, 'sh' , 'The Shattered Halls' , 1, 0, 69, 70, NULL),
(NULL, 'sv' , 'The Steamvault' , 1, 0, 69, 70, NULL),
(NULL, 'sl' , 'Shadow Labyrinth' , 1, 0, 69, 70, NULL),
(NULL, 'mgt' , 'Magister''s Terrace' , 1, 0, 70, 70, NULL),
(NULL, 'bm' , 'The Black Morass' , 1, 0, 68, 70, NULL),
(NULL, 'mech', 'The Mechanar' , 1, 0, 68, 70, NULL),
(NULL, 'bot' , 'The Botanica' , 1, 0, 69, 70, NULL),
(NULL, 'arc' , 'The Arcatraz' , 1, 0, 69, 70, NULL),
(NULL, 'sh' , 'The Shattered Halls' , 1, 0, 69, 70, NULL),
(NULL, 'sv' , 'The Steamvault' , 1, 0, 69, 70, NULL),
(NULL, 'sl' , 'Shadow Labyrinth' , 1, 0, 69, 70, NULL),
(NULL, 'mgt' , 'Magister''s Terrace' , 1, 0, 70, 70, NULL),
-- == The Burning Crusade (Heroic) ==
@@ -72,51 +72,51 @@ INSERT INTO `playerbots_dungeon_suggestion_definition` VALUES
(NULL, 'ub' , 'The Underbog' , 1, 1, 70, 70, NULL),
(NULL, 'mt' , 'Mana-Tombs' , 1, 1, 70, 70, NULL),
(NULL, 'ac' , 'Auchenai Crypts' , 1, 1, 70, 70, NULL),
(NULL, 'seth', 'Sethekk Halls' , 1, 1, 70, 70, NULL),
(NULL, 'seth', 'Sethekk Halls' , 1, 1, 70, 70, NULL),
(NULL, 'oh' , 'Old Hillsbrad Foothills', 1, 1, 70, 70, NULL),
(NULL, 'bm' , 'The Black Morass' , 1, 1, 70, 70, NULL),
(NULL, 'mech', 'The Mechanar' , 1, 1, 70, 70, NULL),
(NULL, 'bot' , 'The Botanica' , 1, 1, 70, 70, NULL),
(NULL, 'arc' , 'The Arcatraz' , 1, 1, 70, 70, NULL),
(NULL, 'bm' , 'The Black Morass' , 1, 1, 70, 70, NULL),
(NULL, 'mech', 'The Mechanar' , 1, 1, 70, 70, NULL),
(NULL, 'bot' , 'The Botanica' , 1, 1, 70, 70, NULL),
(NULL, 'arc' , 'The Arcatraz' , 1, 1, 70, 70, NULL),
(NULL, 'sh' , 'The Shattered Halls' , 1, 1, 70, 70, NULL),
(NULL, 'sv' , 'The Steamvault' , 1, 1, 70, 70, NULL),
(NULL, 'sl' , 'Shadow Labyrinth' , 1, 1, 70, 70, NULL),
(NULL, 'sv' , 'The Steamvault' , 1, 1, 70, 70, NULL),
(NULL, 'sl' , 'Shadow Labyrinth' , 1, 1, 70, 70, NULL),
(NULL, 'mgt' , 'Magister''s Terrace' , 1, 1, 70, 70, NULL),
-- == Wrath of the Lich King ==
(NULL, 'uk' , 'Utgarde Keep' , 2, 0, 70, 72, NULL),
(NULL, 'nexus' , 'The Nexus' , 2, 0, 71, 73, NULL),
(NULL, 'an' , 'Azjol-Nerub' , 2, 0, 72, 74, NULL),
(NULL, 'uk' , 'Utgarde Keep' , 2, 0, 70, 72, NULL),
(NULL, 'nexus' , 'The Nexus' , 2, 0, 71, 73, NULL),
(NULL, 'an' , 'Azjol-Nerub' , 2, 0, 72, 74, NULL),
(NULL, 'ak' , 'Ahn''kahet: The Old Kingdom', 2, 0, 73, 75, NULL),
(NULL, 'dtk' , 'Drak''Tharon Keep' , 2, 0, 74, 76, NULL),
(NULL, 'vh' , 'Violet Hold' , 2, 0, 75, 77, NULL),
(NULL, 'gd' , 'Gundrak' , 2, 0, 76, 78, NULL),
(NULL, 'hos' , 'Halls of Stone' , 2, 0, 77, 79, NULL),
(NULL, 'hol' , 'Halls of Lightning' , 2, 0, 80, 80, NULL),
(NULL, 'dtk' , 'Drak''Tharon Keep' , 2, 0, 74, 76, NULL),
(NULL, 'vh' , 'Violet Hold' , 2, 0, 75, 77, NULL),
(NULL, 'gd' , 'Gundrak' , 2, 0, 76, 78, NULL),
(NULL, 'hos' , 'Halls of Stone' , 2, 0, 77, 79, NULL),
(NULL, 'hol' , 'Halls of Lightning' , 2, 0, 80, 80, NULL),
(NULL, 'cos' , 'The Culling of Stratholme' , 2, 0, 80, 80, NULL),
(NULL, 'oculus', 'The Oculus' , 2, 0, 80, 80, NULL),
(NULL, 'up' , 'Utgarde Pinnacle' , 2, 0, 80, 80, NULL),
(NULL, 'toc' , 'Trial of the Champion' , 2, 0, 80, 80, NULL),
(NULL, 'fos' , 'Forge of Souls' , 2, 0, 80, 80, NULL),
(NULL, 'pos' , 'Pit of Saron' , 2, 0, 80, 80, NULL),
(NULL, 'hor' , 'Halls of Reflection' , 2, 0, 80, 80, NULL),
(NULL, 'oculus', 'The Oculus' , 2, 0, 80, 80, NULL),
(NULL, 'up' , 'Utgarde Pinnacle' , 2, 0, 80, 80, NULL),
(NULL, 'toc' , 'Trial of the Champion' , 2, 0, 80, 80, NULL),
(NULL, 'fos' , 'Forge of Souls' , 2, 0, 80, 80, NULL),
(NULL, 'pos' , 'Pit of Saron' , 2, 0, 80, 80, NULL),
(NULL, 'hor' , 'Halls of Reflection' , 2, 0, 80, 80, NULL),
-- == Wrath of the Lich King (Heroic) ==
(NULL, 'uk' , 'Utgarde Keep' , 2, 1, 80, 80, NULL),
(NULL, 'nexus' , 'The Nexus' , 2, 1, 80, 80, NULL),
(NULL, 'an' , 'Azjol-Nerub' , 2, 1, 80, 80, NULL),
(NULL, 'uk' , 'Utgarde Keep' , 2, 1, 80, 80, NULL),
(NULL, 'nexus' , 'The Nexus' , 2, 1, 80, 80, NULL),
(NULL, 'an' , 'Azjol-Nerub' , 2, 1, 80, 80, NULL),
(NULL, 'ak' , 'Ahn''kahet: The Old Kingdom', 2, 1, 80, 80, NULL),
(NULL, 'dtk' , 'Drak''Tharon Keep' , 2, 1, 80, 80, NULL),
(NULL, 'vh' , 'Violet Hold' , 2, 1, 80, 80, NULL),
(NULL, 'gd' , 'Gundrak' , 2, 1, 80, 80, NULL),
(NULL, 'hos' , 'Halls of Stone' , 2, 1, 80, 80, NULL),
(NULL, 'hol' , 'Halls of Lightning' , 2, 1, 80, 80, NULL),
(NULL, 'dtk' , 'Drak''Tharon Keep' , 2, 1, 80, 80, NULL),
(NULL, 'vh' , 'Violet Hold' , 2, 1, 80, 80, NULL),
(NULL, 'gd' , 'Gundrak' , 2, 1, 80, 80, NULL),
(NULL, 'hos' , 'Halls of Stone' , 2, 1, 80, 80, NULL),
(NULL, 'hol' , 'Halls of Lightning' , 2, 1, 80, 80, NULL),
(NULL, 'cos' , 'The Culling of Stratholme' , 2, 1, 80, 80, NULL),
(NULL, 'oculus', 'The Oculus' , 2, 1, 80, 80, NULL),
(NULL, 'up' , 'Utgarde Pinnacle' , 2, 1, 80, 80, NULL),
(NULL, 'toc' , 'Trial of the Champion' , 2, 1, 80, 80, NULL),
(NULL, 'fos' , 'Forge of Souls' , 2, 1, 80, 80, NULL),
(NULL, 'pos' , 'Pit of Saron' , 2, 1, 80, 80, NULL),
(NULL, 'hor' , 'Halls of Reflection' , 2, 1, 80, 80, NULL);
(NULL, 'oculus', 'The Oculus' , 2, 1, 80, 80, NULL),
(NULL, 'up' , 'Utgarde Pinnacle' , 2, 1, 80, 80, NULL),
(NULL, 'toc' , 'Trial of the Champion' , 2, 1, 80, 80, NULL),
(NULL, 'fos' , 'Forge of Souls' , 2, 1, 80, 80, NULL),
(NULL, 'pos' , 'Pit of Saron' , 2, 1, 80, 80, NULL),
(NULL, 'hor' , 'Halls of Reflection' , 2, 1, 80, 80, NULL);

View File

@@ -25,226 +25,226 @@ CREATE TABLE `playerbots_enchants` (
/*!40000 ALTER TABLE `playerbots_enchants` DISABLE KEYS */;
DELETE FROM `playerbots_enchants`;
INSERT INTO `playerbots_enchants` (`class`, `spec`, `spellid`, `slotid`, `name`) VALUES
(1, 10, 20034, 15, 'Crusader '),
(1, 10, 22779, 17, '30 Hit '),
(1, 10, 27927, 10, '4 All Stats '),
(1, 10, 27927, 11, '4 All Stats '),
(1, 10, 27960, 4, '6 All Stats '),
(1, 10, 27984, 16, 'Mongoose '),
(1, 10, 29483, 2, '26 Attackpower 14 Crit '),
(1, 10, 33996, 9, '26 Attackpower '),
(1, 10, 34002, 8, '24 Attackpower '),
(1, 10, 34004, 14, '12 Agility '),
(1, 10, 34007, 7, 'Minor Speed 6 Agility'),
(1, 10, 35452, 0, '34 Attackpower 16 Hit '),
(1, 10, 35490, 6, '50 Attackpower 12 Crit '),
(1, 11, 20034, 15, 'Crusader '),
(1, 11, 20034, 16, 'Crusader '),
(1, 11, 22779, 17, '30 Hit '),
(1, 11, 27927, 10, '4 All Stats '),
(1, 11, 27927, 11, '4 All Stats '),
(1, 11, 27960, 4, '6 All Stats '),
(1, 11, 29483, 2, '26 Attackpower 14 Crit '),
(1, 11, 33996, 9, '26 Attackpower '),
(1, 11, 34002, 8, '24 Attackpower '),
(1, 11, 34004, 14, '12 Agility '),
(1, 11, 34007, 7, 'Minor Speed 6 Agility'),
(1, 11, 35452, 0, '34 Attackpower 16 Hit '),
(1, 11, 35490, 6, '50 Attackpower 12 Crit '),
(1, 12, 22779, 17, '30 Hit '),
(1, 12, 25072, 9, '2% Threat '),
(1, 12, 27906, 8, '12 Defense '),
(1, 12, 27927, 10, '4 All Stats '),
(1, 12, 27927, 11, '4 All Stats '),
(1, 12, 27954, 7, '5% Root/Snare Resist 10 Hit'),
(1, 12, 27960, 4, '6 All Stats '),
(1, 12, 28004, 15, 'Battlemaster '),
(1, 12, 34009, 16, '18 Stamina '),
(1, 12, 35433, 2, '10 Dodge 15 Defense '),
(1, 12, 35443, 0, '16 Defense 17 Dodge '),
(1, 12, 35495, 6, '40 Stamina 12 Agility '),
(1, 12, 47051, 14, '12 Defense '),
(2, 20, 22779, 17, '30 Hit '),
(2, 20, 27926, 10, '20 Healing 7 Spelldamage '),
(2, 20, 27926, 11, '20 Healing 7 Spelldamage '),
(2, 20, 27945, 16, '12 Intellect '),
(2, 20, 27954, 7, '5% Root/Snare Resist 10 Hit'),
(2, 20, 27960, 4, '6 All Stats '),
(2, 20, 29475, 2, '31 Healing 11 Spelldamage 5 mp5 '),
(2, 20, 31370, 6, '66 Healing 22 Spelldamage 20 Stamina '),
(2, 20, 33999, 9, '35 Healing 12 Spelldamage '),
(2, 20, 34001, 8, '12 Intellect '),
(2, 20, 34003, 14, '20 Spell Penetration '),
(2, 20, 34010, 15, '81 Healing 27 Spelldamage '),
(2, 20, 35445, 0, '35 Healing 12 Spelldamage 7 mp5 '),
(2, 21, 22779, 17, '30 Hit '),
(2, 21, 25072, 9, '2% Threat '),
(2, 21, 27906, 8, '12 Defense '),
(2, 21, 27927, 10, '4 All Stats '),
(2, 21, 27927, 11, '4 All Stats '),
(2, 21, 27954, 7, '5% Root/Snare Resist 10 Hit'),
(2, 21, 27960, 4, '6 All Stats '),
(2, 21, 28004, 15, 'Battlemaster '),
(2, 21, 34009, 16, '18 Stamina '),
(2, 21, 35433, 2, '10 Dodge 15 Defense '),
(2, 21, 35443, 0, '16 Defense 17 Dodge '),
(2, 21, 35495, 6, '40 Stamina 12 Agility '),
(2, 21, 47051, 14, '12 Defense '),
(2, 22, 20034, 15, 'Crusader '),
(2, 22, 22779, 17, '30 Hit '),
(2, 22, 27899, 8, '12 Strength '),
(2, 22, 27927, 10, '4 All Stats '),
(2, 22, 27927, 11, '4 All Stats '),
(2, 22, 27960, 4, '6 All Stats '),
(2, 22, 29483, 2, '26 Attackpower 14 Crit '),
(2, 22, 33995, 6, '50 Attackpower 12 Crit '),
(2, 22, 33996, 9, '15 Strength '),
(2, 22, 34004, 14, '12 Agility '),
(2, 22, 34007, 7, 'Minor Speed 6 Agility'),
(2, 22, 37891, 0, '17 Strength16 Intellect '),
(3, 30, 22779, 17, '30 Hit '),
(3, 30, 25080, 9, '15 Agility '),
(3, 30, 27927, 10, '4 All Stats '),
(3, 30, 27927, 11, '4 All Stats '),
(3, 30, 27951, 7, '12 Agility'),
(3, 30, 27960, 4, '6 All Stats '),
(3, 30, 29483, 2, '26 Attackpower 14 Crit '),
(3, 30, 34002, 8, '24 Attackpower '),
(3, 30, 34004, 14, '12 Agility '),
(3, 30, 35452, 0, '34 Attackpower 16 Hit '),
(3, 30, 35495, 6, '40 Stamina 12 Agility '),
(3, 30, 42620, 15, 'Greater Agility '),
(3, 30, 42620, 16, 'Greater Agility '),
(4, 40, 22779, 17, '30 Hit '),
(4, 40, 25080, 9, '15 Agility '),
(4, 40, 27927, 10, '4 All Stats '),
(4, 40, 27927, 11, '4 All Stats '),
(4, 40, 27951, 7, '12 Agility'),
(4, 40, 27960, 4, '6 All Stats '),
(4, 40, 27984, 15, 'Mongoose '),
(4, 40, 27984, 16, 'Mongoose '),
(4, 40, 29483, 2, '26 Attackpower 14 Crit '),
(4, 40, 34002, 8, '24 Attackpower '),
(4, 40, 34004, 14, '12 Agility '),
(4, 40, 35452, 0, '34 Attackpower 16 Hit '),
(4, 40, 35495, 6, '40 Stamina 12 Agility '),
(5, 50, 22779, 17, '30 Hit '),
(5, 50, 27926, 10, '20 Healing 7 Spelldamage '),
(5, 50, 27926, 11, '20 Healing 7 Spelldamage '),
(5, 50, 27945, 16, '12 Intellect '),
(5, 50, 27954, 7, '5% Root/Snare Resist 10 Hit'),
(5, 50, 27960, 4, '6 All Stats '),
(5, 50, 29475, 2, '31 Healing 11 Spelldamage 5 mp5 '),
(5, 50, 31370, 6, '66 Healing 22 Spelldamage 20 Stamina '),
(5, 50, 33999, 9, '35 Healing 12 Spelldamage '),
(5, 50, 34001, 8, '12 Intellect '),
(5, 50, 34003, 14, '20 Spell Penetration '),
(5, 50, 34010, 15, '81 Healing 27 Spelldamage '),
(5, 50, 35445, 0, '35 Healing 12 Spelldamage 7 mp5 '),
(7, 70, 22779, 17, '30 Hit '),
(7, 70, 27926, 10, '20 Healing 7 Spelldamage '),
(7, 70, 27926, 11, '20 Healing 7 Spelldamage '),
(7, 70, 27945, 16, '12 Intellect '),
(7, 70, 27954, 7, '5% Root/Snare Resist 10 Hit'),
(7, 70, 27960, 4, '6 All Stats '),
(7, 70, 31370, 6, '66 Healing 22 Spelldamage 20 Stamina '),
(7, 70, 33994, 9, '15 Spell Hit '),
(7, 70, 34001, 8, '12 Intellect '),
(7, 70, 34003, 14, '20 Spell Penetration '),
(7, 70, 34010, 15, '81 Healing 27 Spelldamage '),
(7, 70, 35406, 2, '18 Spelldamage 10 Crit '),
(7, 70, 35447, 0, '22 Spelldamage 14 Hit '),
(7, 71, 22779, 17, '30 Hit '),
(7, 71, 25080, 9, '15 Agility '),
(7, 71, 27927, 10, '4 All Stats '),
(7, 71, 27927, 11, '4 All Stats '),
(7, 71, 27951, 7, '12 Agility'),
(7, 71, 27960, 4, '6 All Stats '),
(7, 71, 27977, 15, '35 Agility '),
(7, 71, 27984, 16, 'Mongoose '),
(7, 71, 29483, 2, '26 Attackpower 14 Crit '),
(7, 71, 34002, 8, '24 Attackpower '),
(7, 71, 34004, 14, '12 Agility '),
(7, 71, 35452, 0, '34 Attackpower 16 Hit '),
(7, 71, 35495, 6, '40 Stamina 12 Agility '),
(7, 72, 22779, 17, '30 Hit '),
(7, 72, 27926, 10, '20 Healing 7 Spelldamage '),
(7, 72, 27926, 11, '20 Healing 7 Spelldamage '),
(7, 72, 27945, 16, '12 Intellect '),
(7, 72, 27954, 7, '5% Root/Snare Resist 10 Hit'),
(7, 72, 27960, 4, '6 All Stats '),
(7, 72, 29475, 2, '31 Healing 11 Spelldamage 5 mp5 '),
(7, 72, 31370, 6, '66 Healing 22 Spelldamage 20 Stamina '),
(7, 72, 33999, 9, '35 Healing 12 Spelldamage '),
(7, 72, 34001, 8, '12 Intellect '),
(7, 72, 34003, 14, '20 Spell Penetration '),
(7, 72, 34010, 15, '81 Healing 27 Spelldamage '),
(7, 72, 35445, 0, '35 Healing 12 Spelldamage 7 mp5 '),
(8, 80, 22779, 17, '30 Hit '),
(8, 80, 27927, 10, '4 All Stats '),
(8, 80, 27927, 11, '4 All Stats '),
(8, 80, 27945, 16, '12 Intellect '),
(8, 80, 27954, 7, '5% Root/Snare Resist 10 Hit'),
(8, 80, 27960, 4, '6 All Stats '),
(8, 80, 27975, 15, '40 Spelldamage '),
(8, 80, 31372, 6, '35 Spelldamage 20 Stamina '),
(8, 80, 33994, 9, '15 Spell Hit '),
(8, 80, 34001, 8, '12 Intellect '),
(8, 80, 34003, 14, '20 Spell Penetration '),
(8, 80, 35406, 2, '18 Spelldamage 10 Crit '),
(8, 80, 35447, 0, '22 Spelldamage 14 Hit '),
(9, 90, 22779, 17, '30 Hit '),
(9, 90, 27924, 11, '12 Spelldamage '),
(9, 90, 27927, 10, '4 All Stats '),
(9, 90, 27945, 16, '12 Intellect '),
(9, 90, 27954, 7, '5% Root/Snare Resist 10 Hit'),
(9, 90, 27960, 4, '6 All Stats '),
(9, 90, 27975, 15, '40 Spelldamage '),
(9, 90, 31372, 6, '35 Spelldamage 20 Stamina '),
(9, 90, 33994, 9, '15 Spell Hit '),
(9, 90, 34001, 8, '12 Intellect '),
(9, 90, 34003, 14, '20 Spell Penetration '),
(9, 90, 35406, 2, '18 Spelldamage 10 Crit '),
(9, 90, 35447, 0, '22 Spelldamage 14 Hit '),
(11, 110, 22779, 17, '30 Hit '),
(11, 110, 27926, 10, '20 Healing 7 Spelldamage '),
(11, 110, 27926, 11, '20 Healing 7 Spelldamage '),
(11, 110, 27945, 16, '12 Intellect '),
(11, 110, 27954, 7, '5% Root/Snare Resist 10 Hit'),
(11, 110, 27960, 4, '6 All Stats '),
(11, 110, 31370, 6, '66 Healing 22 Spelldamage 20 Stamina '),
(11, 110, 33994, 9, '15 Spell Hit '),
(11, 110, 34001, 8, '12 Intellect '),
(11, 110, 34003, 14, '20 Spell Penetration '),
(11, 110, 34010, 15, '81 Healing 27 Spelldamage '),
(11, 110, 35406, 2, '18 Spelldamage 10 Crit '),
(11, 110, 35447, 0, '22 Spelldamage 14 Hit '),
(11, 111, 22779, 17, '30 Hit '),
(11, 111, 25080, 9, '15 Agility '),
(11, 111, 27927, 10, '4 All Stats '),
(11, 111, 27927, 11, '4 All Stats '),
(11, 111, 27951, 7, '12 Agility'),
(11, 111, 27960, 4, '6 All Stats '),
(11, 111, 29483, 2, '26 Attackpower 14 Crit '),
(11, 111, 34002, 8, '24 Attackpower '),
(11, 111, 34004, 14, '12 Agility '),
(11, 111, 35452, 0, '34 Attackpower 16 Hit '),
(11, 111, 35495, 6, '40 Stamina 12 Agility '),
(11, 111, 42620, 15, 'Greater Agility '),
(11, 111, 42620, 16, 'Greater Agility '),
(11, 112, 22779, 17, '30 Hit '),
(11, 112, 27926, 10, '20 Healing 7 Spelldamage '),
(11, 112, 27926, 11, '20 Healing 7 Spelldamage '),
(11, 112, 27945, 16, '12 Intellect '),
(11, 112, 27954, 7, '5% Root/Snare Resist 10 Hit'),
(11, 112, 27960, 4, '6 All Stats '),
(11, 112, 29475, 2, '31 Healing 11 Spelldamage 5 mp5 '),
(11, 112, 31370, 6, '66 Healing 22 Spelldamage 20 Stamina '),
(11, 112, 33999, 9, '35 Healing 12 Spelldamage '),
(11, 112, 34001, 8, '12 Intellect '),
(11, 112, 34003, 14, '20 Spell Penetration '),
(11, 112, 34010, 15, '81 Healing 27 Spelldamage '),
(11, 112, 35445, 0, '35 Healing 12 Spelldamage 7 mp5 ');
(1, 10, 20034, 15, 'Crusader '),
(1, 10, 22779, 17, '30 Hit '),
(1, 10, 27927, 10, '4 All Stats '),
(1, 10, 27927, 11, '4 All Stats '),
(1, 10, 27960, 4, '6 All Stats '),
(1, 10, 27984, 16, 'Mongoose '),
(1, 10, 29483, 2, '26 Attackpower 14 Crit '),
(1, 10, 33996, 9, '26 Attackpower '),
(1, 10, 34002, 8, '24 Attackpower '),
(1, 10, 34004, 14, '12 Agility '),
(1, 10, 34007, 7, 'Minor Speed 6 Agility'),
(1, 10, 35452, 0, '34 Attackpower 16 Hit '),
(1, 10, 35490, 6, '50 Attackpower 12 Crit '),
(1, 11, 20034, 15, 'Crusader '),
(1, 11, 20034, 16, 'Crusader '),
(1, 11, 22779, 17, '30 Hit '),
(1, 11, 27927, 10, '4 All Stats '),
(1, 11, 27927, 11, '4 All Stats '),
(1, 11, 27960, 4, '6 All Stats '),
(1, 11, 29483, 2, '26 Attackpower 14 Crit '),
(1, 11, 33996, 9, '26 Attackpower '),
(1, 11, 34002, 8, '24 Attackpower '),
(1, 11, 34004, 14, '12 Agility '),
(1, 11, 34007, 7, 'Minor Speed 6 Agility'),
(1, 11, 35452, 0, '34 Attackpower 16 Hit '),
(1, 11, 35490, 6, '50 Attackpower 12 Crit '),
(1, 12, 22779, 17, '30 Hit '),
(1, 12, 25072, 9, '2% Threat '),
(1, 12, 27906, 8, '12 Defense '),
(1, 12, 27927, 10, '4 All Stats '),
(1, 12, 27927, 11, '4 All Stats '),
(1, 12, 27954, 7, '5% Root/Snare Resist 10 Hit'),
(1, 12, 27960, 4, '6 All Stats '),
(1, 12, 28004, 15, 'Battlemaster '),
(1, 12, 34009, 16, '18 Stamina '),
(1, 12, 35433, 2, '10 Dodge 15 Defense '),
(1, 12, 35443, 0, '16 Defense 17 Dodge '),
(1, 12, 35495, 6, '40 Stamina 12 Agility '),
(1, 12, 47051, 14, '12 Defense '),
(2, 20, 22779, 17, '30 Hit '),
(2, 20, 27926, 10, '20 Healing 7 Spelldamage '),
(2, 20, 27926, 11, '20 Healing 7 Spelldamage '),
(2, 20, 27945, 16, '12 Intellect '),
(2, 20, 27954, 7, '5% Root/Snare Resist 10 Hit'),
(2, 20, 27960, 4, '6 All Stats '),
(2, 20, 29475, 2, '31 Healing 11 Spelldamage 5 mp5 '),
(2, 20, 31370, 6, '66 Healing 22 Spelldamage 20 Stamina '),
(2, 20, 33999, 9, '35 Healing 12 Spelldamage '),
(2, 20, 34001, 8, '12 Intellect '),
(2, 20, 34003, 14, '20 Spell Penetration '),
(2, 20, 34010, 15, '81 Healing 27 Spelldamage '),
(2, 20, 35445, 0, '35 Healing 12 Spelldamage 7 mp5 '),
(2, 21, 22779, 17, '30 Hit '),
(2, 21, 25072, 9, '2% Threat '),
(2, 21, 27906, 8, '12 Defense '),
(2, 21, 27927, 10, '4 All Stats '),
(2, 21, 27927, 11, '4 All Stats '),
(2, 21, 27954, 7, '5% Root/Snare Resist 10 Hit'),
(2, 21, 27960, 4, '6 All Stats '),
(2, 21, 28004, 15, 'Battlemaster '),
(2, 21, 34009, 16, '18 Stamina '),
(2, 21, 35433, 2, '10 Dodge 15 Defense '),
(2, 21, 35443, 0, '16 Defense 17 Dodge '),
(2, 21, 35495, 6, '40 Stamina 12 Agility '),
(2, 21, 47051, 14, '12 Defense '),
(2, 22, 20034, 15, 'Crusader '),
(2, 22, 22779, 17, '30 Hit '),
(2, 22, 27899, 8, '12 Strength '),
(2, 22, 27927, 10, '4 All Stats '),
(2, 22, 27927, 11, '4 All Stats '),
(2, 22, 27960, 4, '6 All Stats '),
(2, 22, 29483, 2, '26 Attackpower 14 Crit '),
(2, 22, 33995, 6, '50 Attackpower 12 Crit '),
(2, 22, 33996, 9, '15 Strength '),
(2, 22, 34004, 14, '12 Agility '),
(2, 22, 34007, 7, 'Minor Speed 6 Agility'),
(2, 22, 37891, 0, '17 Strength16 Intellect '),
(3, 30, 22779, 17, '30 Hit '),
(3, 30, 25080, 9, '15 Agility '),
(3, 30, 27927, 10, '4 All Stats '),
(3, 30, 27927, 11, '4 All Stats '),
(3, 30, 27951, 7, '12 Agility'),
(3, 30, 27960, 4, '6 All Stats '),
(3, 30, 29483, 2, '26 Attackpower 14 Crit '),
(3, 30, 34002, 8, '24 Attackpower '),
(3, 30, 34004, 14, '12 Agility '),
(3, 30, 35452, 0, '34 Attackpower 16 Hit '),
(3, 30, 35495, 6, '40 Stamina 12 Agility '),
(3, 30, 42620, 15, 'Greater Agility '),
(3, 30, 42620, 16, 'Greater Agility '),
(4, 40, 22779, 17, '30 Hit '),
(4, 40, 25080, 9, '15 Agility '),
(4, 40, 27927, 10, '4 All Stats '),
(4, 40, 27927, 11, '4 All Stats '),
(4, 40, 27951, 7, '12 Agility'),
(4, 40, 27960, 4, '6 All Stats '),
(4, 40, 27984, 15, 'Mongoose '),
(4, 40, 27984, 16, 'Mongoose '),
(4, 40, 29483, 2, '26 Attackpower 14 Crit '),
(4, 40, 34002, 8, '24 Attackpower '),
(4, 40, 34004, 14, '12 Agility '),
(4, 40, 35452, 0, '34 Attackpower 16 Hit '),
(4, 40, 35495, 6, '40 Stamina 12 Agility '),
(5, 50, 22779, 17, '30 Hit '),
(5, 50, 27926, 10, '20 Healing 7 Spelldamage '),
(5, 50, 27926, 11, '20 Healing 7 Spelldamage '),
(5, 50, 27945, 16, '12 Intellect '),
(5, 50, 27954, 7, '5% Root/Snare Resist 10 Hit'),
(5, 50, 27960, 4, '6 All Stats '),
(5, 50, 29475, 2, '31 Healing 11 Spelldamage 5 mp5 '),
(5, 50, 31370, 6, '66 Healing 22 Spelldamage 20 Stamina '),
(5, 50, 33999, 9, '35 Healing 12 Spelldamage '),
(5, 50, 34001, 8, '12 Intellect '),
(5, 50, 34003, 14, '20 Spell Penetration '),
(5, 50, 34010, 15, '81 Healing 27 Spelldamage '),
(5, 50, 35445, 0, '35 Healing 12 Spelldamage 7 mp5 '),
(7, 70, 22779, 17, '30 Hit '),
(7, 70, 27926, 10, '20 Healing 7 Spelldamage '),
(7, 70, 27926, 11, '20 Healing 7 Spelldamage '),
(7, 70, 27945, 16, '12 Intellect '),
(7, 70, 27954, 7, '5% Root/Snare Resist 10 Hit'),
(7, 70, 27960, 4, '6 All Stats '),
(7, 70, 31370, 6, '66 Healing 22 Spelldamage 20 Stamina '),
(7, 70, 33994, 9, '15 Spell Hit '),
(7, 70, 34001, 8, '12 Intellect '),
(7, 70, 34003, 14, '20 Spell Penetration '),
(7, 70, 34010, 15, '81 Healing 27 Spelldamage '),
(7, 70, 35406, 2, '18 Spelldamage 10 Crit '),
(7, 70, 35447, 0, '22 Spelldamage 14 Hit '),
(7, 71, 22779, 17, '30 Hit '),
(7, 71, 25080, 9, '15 Agility '),
(7, 71, 27927, 10, '4 All Stats '),
(7, 71, 27927, 11, '4 All Stats '),
(7, 71, 27951, 7, '12 Agility'),
(7, 71, 27960, 4, '6 All Stats '),
(7, 71, 27977, 15, '35 Agility '),
(7, 71, 27984, 16, 'Mongoose '),
(7, 71, 29483, 2, '26 Attackpower 14 Crit '),
(7, 71, 34002, 8, '24 Attackpower '),
(7, 71, 34004, 14, '12 Agility '),
(7, 71, 35452, 0, '34 Attackpower 16 Hit '),
(7, 71, 35495, 6, '40 Stamina 12 Agility '),
(7, 72, 22779, 17, '30 Hit '),
(7, 72, 27926, 10, '20 Healing 7 Spelldamage '),
(7, 72, 27926, 11, '20 Healing 7 Spelldamage '),
(7, 72, 27945, 16, '12 Intellect '),
(7, 72, 27954, 7, '5% Root/Snare Resist 10 Hit'),
(7, 72, 27960, 4, '6 All Stats '),
(7, 72, 29475, 2, '31 Healing 11 Spelldamage 5 mp5 '),
(7, 72, 31370, 6, '66 Healing 22 Spelldamage 20 Stamina '),
(7, 72, 33999, 9, '35 Healing 12 Spelldamage '),
(7, 72, 34001, 8, '12 Intellect '),
(7, 72, 34003, 14, '20 Spell Penetration '),
(7, 72, 34010, 15, '81 Healing 27 Spelldamage '),
(7, 72, 35445, 0, '35 Healing 12 Spelldamage 7 mp5 '),
(8, 80, 22779, 17, '30 Hit '),
(8, 80, 27927, 10, '4 All Stats '),
(8, 80, 27927, 11, '4 All Stats '),
(8, 80, 27945, 16, '12 Intellect '),
(8, 80, 27954, 7, '5% Root/Snare Resist 10 Hit'),
(8, 80, 27960, 4, '6 All Stats '),
(8, 80, 27975, 15, '40 Spelldamage '),
(8, 80, 31372, 6, '35 Spelldamage 20 Stamina '),
(8, 80, 33994, 9, '15 Spell Hit '),
(8, 80, 34001, 8, '12 Intellect '),
(8, 80, 34003, 14, '20 Spell Penetration '),
(8, 80, 35406, 2, '18 Spelldamage 10 Crit '),
(8, 80, 35447, 0, '22 Spelldamage 14 Hit '),
(9, 90, 22779, 17, '30 Hit '),
(9, 90, 27924, 11, '12 Spelldamage '),
(9, 90, 27927, 10, '4 All Stats '),
(9, 90, 27945, 16, '12 Intellect '),
(9, 90, 27954, 7, '5% Root/Snare Resist 10 Hit'),
(9, 90, 27960, 4, '6 All Stats '),
(9, 90, 27975, 15, '40 Spelldamage '),
(9, 90, 31372, 6, '35 Spelldamage 20 Stamina '),
(9, 90, 33994, 9, '15 Spell Hit '),
(9, 90, 34001, 8, '12 Intellect '),
(9, 90, 34003, 14, '20 Spell Penetration '),
(9, 90, 35406, 2, '18 Spelldamage 10 Crit '),
(9, 90, 35447, 0, '22 Spelldamage 14 Hit '),
(11, 110, 22779, 17, '30 Hit '),
(11, 110, 27926, 10, '20 Healing 7 Spelldamage '),
(11, 110, 27926, 11, '20 Healing 7 Spelldamage '),
(11, 110, 27945, 16, '12 Intellect '),
(11, 110, 27954, 7, '5% Root/Snare Resist 10 Hit'),
(11, 110, 27960, 4, '6 All Stats '),
(11, 110, 31370, 6, '66 Healing 22 Spelldamage 20 Stamina '),
(11, 110, 33994, 9, '15 Spell Hit '),
(11, 110, 34001, 8, '12 Intellect '),
(11, 110, 34003, 14, '20 Spell Penetration '),
(11, 110, 34010, 15, '81 Healing 27 Spelldamage '),
(11, 110, 35406, 2, '18 Spelldamage 10 Crit '),
(11, 110, 35447, 0, '22 Spelldamage 14 Hit '),
(11, 111, 22779, 17, '30 Hit '),
(11, 111, 25080, 9, '15 Agility '),
(11, 111, 27927, 10, '4 All Stats '),
(11, 111, 27927, 11, '4 All Stats '),
(11, 111, 27951, 7, '12 Agility'),
(11, 111, 27960, 4, '6 All Stats '),
(11, 111, 29483, 2, '26 Attackpower 14 Crit '),
(11, 111, 34002, 8, '24 Attackpower '),
(11, 111, 34004, 14, '12 Agility '),
(11, 111, 35452, 0, '34 Attackpower 16 Hit '),
(11, 111, 35495, 6, '40 Stamina 12 Agility '),
(11, 111, 42620, 15, 'Greater Agility '),
(11, 111, 42620, 16, 'Greater Agility '),
(11, 112, 22779, 17, '30 Hit '),
(11, 112, 27926, 10, '20 Healing 7 Spelldamage '),
(11, 112, 27926, 11, '20 Healing 7 Spelldamage '),
(11, 112, 27945, 16, '12 Intellect '),
(11, 112, 27954, 7, '5% Root/Snare Resist 10 Hit'),
(11, 112, 27960, 4, '6 All Stats '),
(11, 112, 29475, 2, '31 Healing 11 Spelldamage 5 mp5 '),
(11, 112, 31370, 6, '66 Healing 22 Spelldamage 20 Stamina '),
(11, 112, 33999, 9, '35 Healing 12 Spelldamage '),
(11, 112, 34001, 8, '12 Intellect '),
(11, 112, 34003, 14, '20 Spell Penetration '),
(11, 112, 34010, 15, '81 Healing 27 Spelldamage '),
(11, 112, 35445, 0, '35 Healing 12 Spelldamage 7 mp5 ');
/*!40000 ALTER TABLE `playerbots_enchants` ENABLE KEYS */;
/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */;

View File

@@ -7,278 +7,278 @@ CREATE TABLE IF NOT EXISTS `playerbots_weightscale_data` (
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `playerbots_weightscale_data` (`id`, `field`, `val`) VALUES
(1, 'exprtng', 100),
(1, 'str', 82),
(1, 'critstrkrtng', 66),
(1, 'agi', 53),
(1, 'armorpenrtng', 52),
(1, 'hitrtng', 48),
(1, 'hastertng', 36),
(1, 'atkpwr', 31),
(1, 'armor', 5),
(2, 'exprtng', 100),
(2, 'str', 82),
(2, 'critstrkrtng', 66),
(2, 'agi', 53),
(2, 'armorpenrtng', 52),
(2, 'hitrtng', 48),
(2, 'hastertng', 36),
(2, 'atkpwr', 31),
(2, 'armor', 5),
(3, 'sta', 100),
(3, 'dodgertng', 90),
(3, 'defrtng', 86),
(3, 'block', 81),
(3, 'agi', 67),
(3, 'parryrtng', 67),
(3, 'blockrtng', 48),
(3, 'str', 48),
(3, 'exprtng', 19),
(3, 'hitrtng', 10),
(3, 'armorpenrtng', 10),
(3, 'critstrkrtng', 7),
(3, 'armor', 6),
(3, 'hastertng', 1),
(3, 'atkpwr', 1),
(4, 'int', 100),
(4, 'manargn', 88),
(4, 'splpwr', 58),
(4, 'critstrkrtng', 46),
(4, 'hastertng', 35),
(5, 'sta', 100),
(5, 'dodgertng', 94),
(5, 'block', 86),
(5, 'defrtng', 86),
(5, 'exprtng', 79),
(5, 'agi', 76),
(5, 'parryrtng', 76),
(5, 'hitrtng', 58),
(5, 'blockrtng', 52),
(5, 'str', 50),
(5, 'armor', 6),
(5, 'atkpwr', 6),
(5, 'splpwr', 4),
(5, 'critstrkrtng', 3),
(6, 'mledps', 470),
(6, 'hitrtng', 100),
(6, 'str', 80),
(6, 'exprtng', 66),
(6, 'critstrkrtng', 40),
(6, 'atkpwr', 34),
(6, 'agi', 32),
(6, 'hastertng', 30),
(6, 'armorpenrtng', 22),
(6, 'splpwr', 9),
(7, 'rgddps', 213),
(7, 'hitrtng', 100),
(7, 'agi', 58),
(7, 'critstrkrtng', 40),
(7, 'int', 37),
(7, 'atkpwr', 30),
(7, 'armorpenrtng', 28),
(7, 'hastertng', 21),
(8, 'rgddps', 379),
(8, 'hitrtng', 100),
(8, 'agi', 74),
(8, 'critstrkrtng', 57),
(8, 'armorpenrtng', 40),
(8, 'int', 39),
(8, 'atkpwr', 32),
(8, 'hastertng', 24),
(9, 'rgddps', 181),
(9, 'hitrtng', 100),
(9, 'agi', 76),
(9, 'critstrkrtng', 42),
(9, 'int', 35),
(9, 'hastertng', 31),
(9, 'atkpwr', 29),
(9, 'armorpenrtng', 26),
(10, 'mledps', 170),
(10, 'agi', 100),
(10, 'exprtng', 87),
(10, 'hitrtng', 83),
(10, 'critstrkrtng', 81),
(10, 'atkpwr', 65),
(10, 'armorpenrtng', 65),
(10, 'hastertng', 64),
(10, 'str', 55),
(11, 'mledps', 220),
(11, 'armorpenrtng', 100),
(11, 'agi', 100),
(11, 'exprtng', 82),
(11, 'hitrtng', 80),
(11, 'critstrkrtng', 75),
(11, 'hastertng', 73),
(11, 'str', 55),
(11, 'atkpwr', 50),
(12, 'mledps', 228),
(12, 'exprtng', 100),
(12, 'agi', 100),
(12, 'hitrtng', 80),
(12, 'armorpenrtng', 75),
(12, 'critstrkrtng', 75),
(12, 'hastertng', 75),
(12, 'str', 55),
(12, 'atkpwr', 50),
(13, 'splpwr', 100),
(13, 'manargn', 67),
(13, 'int', 65),
(13, 'hastertng', 59),
(13, 'critstrkrtng', 48),
(13, 'spi', 22),
(14, 'manargn', 100),
(14, 'int', 69),
(14, 'splpwr', 60),
(14, 'spi', 52),
(14, 'critstrkrtng', 38),
(14, 'hastertng', 31),
(15, 'hitrtng', 100),
(15, 'shasplpwr', 76),
(15, 'splpwr', 76),
(15, 'critstrkrtng', 54),
(15, 'hastertng', 50),
(15, 'spi', 16),
(15, 'int', 16),
(16, 'mledps', 360),
(16, 'armorpenrtng', 100),
(16, 'str', 99),
(16, 'hitrtng', 91),
(16, 'exprtng', 90),
(16, 'critstrkrtng', 57),
(16, 'hastertng', 55),
(16, 'atkpwr', 36),
(16, 'armor', 1),
(17, 'mledps', 337),
(17, 'hitrtng', 100),
(17, 'str', 97),
(17, 'exprtng', 81),
(17, 'armorpenrtng', 61),
(17, 'critstrkrtng', 45),
(17, 'atkpwr', 35),
(17, 'hastertng', 28),
(17, 'armor', 1),
(18, 'mledps', 419),
(18, 'parryrtng', 100),
(18, 'hitrtng', 97),
(18, 'str', 96),
(18, 'defrtng', 85),
(18, 'exprtng', 69),
(18, 'dodgertng', 61),
(18, 'agi', 61),
(18, 'sta', 61),
(18, 'critstrkrtng', 49),
(18, 'atkpwr', 41),
(18, 'armorpenrtng', 31),
(18, 'armor', 5),
(19, 'mledps', 209),
(19, 'str', 100),
(19, 'hitrtng', 66),
(19, 'exprtng', 51),
(19, 'hastertng', 48),
(19, 'critstrkrtng', 45),
(19, 'atkpwr', 34),
(19, 'armorpenrtng', 32),
(19, 'armor', 1),
(20, 'hitrtng', 100),
(20, 'splpwr', 60),
(20, 'hastertng', 56),
(20, 'critstrkrtng', 40),
(20, 'int', 11),
(21, 'mledps', 135),
(21, 'hitrtng', 100),
(21, 'exprtng', 84),
(21, 'agi', 55),
(21, 'int', 55),
(21, 'critstrkrtng', 55),
(21, 'hastertng', 42),
(21, 'str', 35),
(21, 'atkpwr', 32),
(21, 'splpwr', 29),
(21, 'armorpenrtng', 26),
(22, 'manargn', 100),
(22, 'int', 85),
(22, 'splpwr', 77),
(22, 'critstrkrtng', 62),
(22, 'hastertng', 35),
(23, 'hitrtng', 100),
(23, 'hastertng', 54),
(23, 'arcsplpwr', 49),
(23, 'splpwr', 49),
(23, 'critstrkrtng', 37),
(23, 'int', 34),
(23, 'frosplpwr', 24),
(23, 'firsplpwr', 24),
(23, 'spi', 14),
(24, 'hitrtng', 100),
(24, 'hastertng', 53),
(24, 'firsplpwr', 46),
(24, 'splpwr', 46),
(24, 'critstrkrtng', 43),
(24, 'frosplpwr', 23),
(24, 'arcsplpwr', 23),
(24, 'int', 13),
(25, 'hitrtng', 100),
(25, 'hastertng', 42),
(25, 'frosplpwr', 39),
(25, 'splpwr', 39),
(25, 'arcsplpwr', 19),
(25, 'firsplpwr', 19),
(25, 'critstrkrtng', 19),
(25, 'int', 6),
(26, 'hitrtng', 100),
(26, 'shasplpwr', 72),
(26, 'splpwr', 72),
(26, 'hastertng', 61),
(26, 'critstrkrtng', 38),
(26, 'firsplpwr', 36),
(26, 'spi', 34),
(26, 'int', 15),
(27, 'hitrtng', 100),
(27, 'hastertng', 50),
(27, 'firsplpwr', 45),
(27, 'shasplpwr', 45),
(27, 'splpwr', 45),
(27, 'critstrkrtng', 31),
(27, 'spi', 29),
(27, 'int', 13),
(28, 'hitrtng', 100),
(28, 'firsplpwr', 47),
(28, 'splpwr', 47),
(28, 'hastertng', 46),
(28, 'spi', 26),
(28, 'shasplpwr', 23),
(28, 'critstrkrtng', 16),
(28, 'int', 13),
(29, 'hitrtng', 100),
(29, 'splpwr', 66),
(29, 'hastertng', 54),
(29, 'critstrkrtng', 43),
(29, 'spi', 22),
(29, 'int', 22),
(30, 'agi', 100),
(30, 'sta', 75),
(30, 'dodgertng', 65),
(30, 'defrtng', 60),
(30, 'exprtng', 16),
(30, 'str', 10),
(30, 'armor', 10),
(30, 'hitrtng', 8),
(30, 'hastertng', 5),
(30, 'atkpwr', 4),
(30, 'feratkpwr', 4),
(30, 'critstrkrtng', 3),
(31, 'splpwr', 100),
(31, 'manargn', 73),
(31, 'hastertng', 57),
(31, 'int', 51),
(31, 'spi', 32),
(31, 'critstrkrtng', 11),
(32, 'agi', 100),
(32, 'armorpenrtng', 90),
(32, 'str', 80),
(32, 'critstrkrtng', 55),
(32, 'exprtng', 50),
(32, 'hitrtng', 50),
(32, 'feratkpwr', 40),
(32, 'atkpwr', 40),
(32, 'hastertng', 35);
(1, 'exprtng', 100),
(1, 'str', 82),
(1, 'critstrkrtng', 66),
(1, 'agi', 53),
(1, 'armorpenrtng', 52),
(1, 'hitrtng', 48),
(1, 'hastertng', 36),
(1, 'atkpwr', 31),
(1, 'armor', 5),
(2, 'exprtng', 100),
(2, 'str', 82),
(2, 'critstrkrtng', 66),
(2, 'agi', 53),
(2, 'armorpenrtng', 52),
(2, 'hitrtng', 48),
(2, 'hastertng', 36),
(2, 'atkpwr', 31),
(2, 'armor', 5),
(3, 'sta', 100),
(3, 'dodgertng', 90),
(3, 'defrtng', 86),
(3, 'block', 81),
(3, 'agi', 67),
(3, 'parryrtng', 67),
(3, 'blockrtng', 48),
(3, 'str', 48),
(3, 'exprtng', 19),
(3, 'hitrtng', 10),
(3, 'armorpenrtng', 10),
(3, 'critstrkrtng', 7),
(3, 'armor', 6),
(3, 'hastertng', 1),
(3, 'atkpwr', 1),
(4, 'int', 100),
(4, 'manargn', 88),
(4, 'splpwr', 58),
(4, 'critstrkrtng', 46),
(4, 'hastertng', 35),
(5, 'sta', 100),
(5, 'dodgertng', 94),
(5, 'block', 86),
(5, 'defrtng', 86),
(5, 'exprtng', 79),
(5, 'agi', 76),
(5, 'parryrtng', 76),
(5, 'hitrtng', 58),
(5, 'blockrtng', 52),
(5, 'str', 50),
(5, 'armor', 6),
(5, 'atkpwr', 6),
(5, 'splpwr', 4),
(5, 'critstrkrtng', 3),
(6, 'mledps', 470),
(6, 'hitrtng', 100),
(6, 'str', 80),
(6, 'exprtng', 66),
(6, 'critstrkrtng', 40),
(6, 'atkpwr', 34),
(6, 'agi', 32),
(6, 'hastertng', 30),
(6, 'armorpenrtng', 22),
(6, 'splpwr', 9),
(7, 'rgddps', 213),
(7, 'hitrtng', 100),
(7, 'agi', 58),
(7, 'critstrkrtng', 40),
(7, 'int', 37),
(7, 'atkpwr', 30),
(7, 'armorpenrtng', 28),
(7, 'hastertng', 21),
(8, 'rgddps', 379),
(8, 'hitrtng', 100),
(8, 'agi', 74),
(8, 'critstrkrtng', 57),
(8, 'armorpenrtng', 40),
(8, 'int', 39),
(8, 'atkpwr', 32),
(8, 'hastertng', 24),
(9, 'rgddps', 181),
(9, 'hitrtng', 100),
(9, 'agi', 76),
(9, 'critstrkrtng', 42),
(9, 'int', 35),
(9, 'hastertng', 31),
(9, 'atkpwr', 29),
(9, 'armorpenrtng', 26),
(10, 'mledps', 170),
(10, 'agi', 100),
(10, 'exprtng', 87),
(10, 'hitrtng', 83),
(10, 'critstrkrtng', 81),
(10, 'atkpwr', 65),
(10, 'armorpenrtng', 65),
(10, 'hastertng', 64),
(10, 'str', 55),
(11, 'mledps', 220),
(11, 'armorpenrtng', 100),
(11, 'agi', 100),
(11, 'exprtng', 82),
(11, 'hitrtng', 80),
(11, 'critstrkrtng', 75),
(11, 'hastertng', 73),
(11, 'str', 55),
(11, 'atkpwr', 50),
(12, 'mledps', 228),
(12, 'exprtng', 100),
(12, 'agi', 100),
(12, 'hitrtng', 80),
(12, 'armorpenrtng', 75),
(12, 'critstrkrtng', 75),
(12, 'hastertng', 75),
(12, 'str', 55),
(12, 'atkpwr', 50),
(13, 'splpwr', 100),
(13, 'manargn', 67),
(13, 'int', 65),
(13, 'hastertng', 59),
(13, 'critstrkrtng', 48),
(13, 'spi', 22),
(14, 'manargn', 100),
(14, 'int', 69),
(14, 'splpwr', 60),
(14, 'spi', 52),
(14, 'critstrkrtng', 38),
(14, 'hastertng', 31),
(15, 'hitrtng', 100),
(15, 'shasplpwr', 76),
(15, 'splpwr', 76),
(15, 'critstrkrtng', 54),
(15, 'hastertng', 50),
(15, 'spi', 16),
(15, 'int', 16),
(16, 'mledps', 360),
(16, 'armorpenrtng', 100),
(16, 'str', 99),
(16, 'hitrtng', 91),
(16, 'exprtng', 90),
(16, 'critstrkrtng', 57),
(16, 'hastertng', 55),
(16, 'atkpwr', 36),
(16, 'armor', 1),
(17, 'mledps', 337),
(17, 'hitrtng', 100),
(17, 'str', 97),
(17, 'exprtng', 81),
(17, 'armorpenrtng', 61),
(17, 'critstrkrtng', 45),
(17, 'atkpwr', 35),
(17, 'hastertng', 28),
(17, 'armor', 1),
(18, 'mledps', 419),
(18, 'parryrtng', 100),
(18, 'hitrtng', 97),
(18, 'str', 96),
(18, 'defrtng', 85),
(18, 'exprtng', 69),
(18, 'dodgertng', 61),
(18, 'agi', 61),
(18, 'sta', 61),
(18, 'critstrkrtng', 49),
(18, 'atkpwr', 41),
(18, 'armorpenrtng', 31),
(18, 'armor', 5),
(19, 'mledps', 209),
(19, 'str', 100),
(19, 'hitrtng', 66),
(19, 'exprtng', 51),
(19, 'hastertng', 48),
(19, 'critstrkrtng', 45),
(19, 'atkpwr', 34),
(19, 'armorpenrtng', 32),
(19, 'armor', 1),
(20, 'hitrtng', 100),
(20, 'splpwr', 60),
(20, 'hastertng', 56),
(20, 'critstrkrtng', 40),
(20, 'int', 11),
(21, 'mledps', 135),
(21, 'hitrtng', 100),
(21, 'exprtng', 84),
(21, 'agi', 55),
(21, 'int', 55),
(21, 'critstrkrtng', 55),
(21, 'hastertng', 42),
(21, 'str', 35),
(21, 'atkpwr', 32),
(21, 'splpwr', 29),
(21, 'armorpenrtng', 26),
(22, 'manargn', 100),
(22, 'int', 85),
(22, 'splpwr', 77),
(22, 'critstrkrtng', 62),
(22, 'hastertng', 35),
(23, 'hitrtng', 100),
(23, 'hastertng', 54),
(23, 'arcsplpwr', 49),
(23, 'splpwr', 49),
(23, 'critstrkrtng', 37),
(23, 'int', 34),
(23, 'frosplpwr', 24),
(23, 'firsplpwr', 24),
(23, 'spi', 14),
(24, 'hitrtng', 100),
(24, 'hastertng', 53),
(24, 'firsplpwr', 46),
(24, 'splpwr', 46),
(24, 'critstrkrtng', 43),
(24, 'frosplpwr', 23),
(24, 'arcsplpwr', 23),
(24, 'int', 13),
(25, 'hitrtng', 100),
(25, 'hastertng', 42),
(25, 'frosplpwr', 39),
(25, 'splpwr', 39),
(25, 'arcsplpwr', 19),
(25, 'firsplpwr', 19),
(25, 'critstrkrtng', 19),
(25, 'int', 6),
(26, 'hitrtng', 100),
(26, 'shasplpwr', 72),
(26, 'splpwr', 72),
(26, 'hastertng', 61),
(26, 'critstrkrtng', 38),
(26, 'firsplpwr', 36),
(26, 'spi', 34),
(26, 'int', 15),
(27, 'hitrtng', 100),
(27, 'hastertng', 50),
(27, 'firsplpwr', 45),
(27, 'shasplpwr', 45),
(27, 'splpwr', 45),
(27, 'critstrkrtng', 31),
(27, 'spi', 29),
(27, 'int', 13),
(28, 'hitrtng', 100),
(28, 'firsplpwr', 47),
(28, 'splpwr', 47),
(28, 'hastertng', 46),
(28, 'spi', 26),
(28, 'shasplpwr', 23),
(28, 'critstrkrtng', 16),
(28, 'int', 13),
(29, 'hitrtng', 100),
(29, 'splpwr', 66),
(29, 'hastertng', 54),
(29, 'critstrkrtng', 43),
(29, 'spi', 22),
(29, 'int', 22),
(30, 'agi', 100),
(30, 'sta', 75),
(30, 'dodgertng', 65),
(30, 'defrtng', 60),
(30, 'exprtng', 16),
(30, 'str', 10),
(30, 'armor', 10),
(30, 'hitrtng', 8),
(30, 'hastertng', 5),
(30, 'atkpwr', 4),
(30, 'feratkpwr', 4),
(30, 'critstrkrtng', 3),
(31, 'splpwr', 100),
(31, 'manargn', 73),
(31, 'hastertng', 57),
(31, 'int', 51),
(31, 'spi', 32),
(31, 'critstrkrtng', 11),
(32, 'agi', 100),
(32, 'armorpenrtng', 90),
(32, 'str', 80),
(32, 'critstrkrtng', 55),
(32, 'exprtng', 50),
(32, 'hitrtng', 50),
(32, 'feratkpwr', 40),
(32, 'atkpwr', 40),
(32, 'hastertng', 35);

View File

@@ -7,35 +7,35 @@ CREATE TABLE IF NOT EXISTS `playerbots_weightscales` (
) ENGINE=InnoDB AUTO_INCREMENT=33 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT;
INSERT INTO `playerbots_weightscales` (`id`, `name`, `class`) VALUES
(1, 'arms', 1),
(2, 'fury', 1),
(3, 'prot', 1),
(4, 'holy', 2),
(5, 'prot', 2),
(6, 'retrib', 2),
(7, 'beast', 3),
(8, 'marks', 3),
(9, 'surv', 3),
(10, 'assas', 4),
(11, 'combat', 4),
(12, 'subtle', 4),
(13, 'disc', 5),
(14, 'holy', 5),
(15, 'shadow', 5),
(16, 'blooddps', 6),
(17, 'frostdps', 6),
(18, 'frosttank', 6),
(19, 'unholydps', 6),
(20, 'elem', 7),
(21, 'enhance', 7),
(22, 'resto', 7),
(23, 'arcane', 8),
(24, 'fire', 8),
(25, 'frost', 8),
(26, 'afflic', 9),
(27, 'demo', 9),
(28, 'destro', 9),
(29, 'balance', 11),
(30, 'feraltank', 11),
(31, 'resto', 11),
(32, 'feraldps', 11);
(1, 'arms', 1),
(2, 'fury', 1),
(3, 'prot', 1),
(4, 'holy', 2),
(5, 'prot', 2),
(6, 'retrib', 2),
(7, 'beast', 3),
(8, 'marks', 3),
(9, 'surv', 3),
(10, 'assas', 4),
(11, 'combat', 4),
(12, 'subtle', 4),
(13, 'disc', 5),
(14, 'holy', 5),
(15, 'shadow', 5),
(16, 'blooddps', 6),
(17, 'frostdps', 6),
(18, 'frosttank', 6),
(19, 'unholydps', 6),
(20, 'elem', 7),
(21, 'enhance', 7),
(22, 'resto', 7),
(23, 'arcane', 8),
(24, 'fire', 8),
(25, 'frost', 8),
(26, 'afflic', 9),
(27, 'demo', 9),
(28, 'destro', 9),
(29, 'balance', 11),
(30, 'feraltank', 11),
(31, 'resto', 11),
(32, 'feraldps', 11);

View File

@@ -24,9 +24,9 @@ CREATE TABLE IF NOT EXISTS `updates_include` (
DELETE FROM `updates_include`;
/*!40000 ALTER TABLE `updates_include` DISABLE KEYS */;
INSERT INTO `updates_include` (`path`, `state`) VALUES
('$/data/sql/playerbots/updates', 'RELEASED'),
('$/data/sql/playerbots/custom', 'CUSTOM'),
('$/data/sql/playerbots/archive', 'ARCHIVED');
('$/data/sql/playerbots/updates', 'RELEASED'),
('$/data/sql/playerbots/custom', 'CUSTOM'),
('$/data/sql/playerbots/archive', 'ARCHIVED');
/*!40000 ALTER TABLE `updates_include` ENABLE KEYS */;
/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */;

File diff suppressed because it is too large Load Diff

View File

@@ -1,15 +0,0 @@
DROP TABLE IF EXISTS `playerbot_account_keys`;
CREATE TABLE IF NOT EXISTS `playerbots_account_keys` (
`account_id` INT PRIMARY KEY,
`security_key` VARCHAR(255) NOT NULL,
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) ENGINE=INNODB DEFAULT CHARSET=latin1;
DROP TABLE IF EXISTS `playerbot_account_links`;
CREATE TABLE IF NOT EXISTS `playerbots_account_links` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`account_id` INT NOT NULL,
`linked_account_id` INT NOT NULL,
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE KEY `account_link` (`account_id`, `linked_account_id`)
) ENGINE=INNODB DEFAULT CHARSET=latin1;

View File

@@ -1,9 +0,0 @@
-- Create playerbots_account_type table for tracking accounts assignments
DROP TABLE IF EXISTS `playerbots_account_type`;
CREATE TABLE `playerbots_account_type` (
`account_id` int unsigned NOT NULL,
`account_type` tinyint unsigned NOT NULL DEFAULT 0 COMMENT '0 = unassigned, 1 = RNDbot, 2 = AddClass',
`assignment_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`account_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Playerbot account type assignments';

View File

@@ -1,849 +0,0 @@
UPDATE `ai_playerbot_texts` SET `text_loc8` = "посреди нигде" WHERE `id` = 1;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "в неопределенном месте" WHERE `id` = 2;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "где-то" WHERE `id` = 3;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "что-то" WHERE `id` = 4;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "интересно, какой на вкус %item_link" WHERE `id` = 5;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "нет, мне выпал %item_link" WHERE `id` = 6;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "опять этот хлам %item_link" WHERE `id` = 7;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "похоже, я лутаю мусор %item_link" WHERE `id` = 8;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "ну, лучше чем ничего, наверное %item_link" WHERE `id` = 9;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "не знаю, что делать с %item_link" WHERE `id` = 10;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "интересно, какой на вкус %item_link" WHERE `id` = 11;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "могу лутать %item_link весь день" WHERE `id` = 12;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "еще один день, еще один %item_link" WHERE `id` = 13;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "получил немного %item_link" WHERE `id` = 14;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "немного %item_link — это нормально" WHERE `id` = 15;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "неплохо, только что получил %item_link" WHERE `id` = 16;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "только что залутал %item_link в %zone_name" WHERE `id` = 17;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "могу найти применение %item_link" WHERE `id` = 18;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "деньги, деньги, деньги %item_link" WHERE `id` = 19;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "получил %item_link" WHERE `id` = 20;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "%item_link — лучший для охотника" WHERE `id` = 21;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "%item_link — лучший для %my_class" WHERE `id` = 22;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "сегодня удача на моей стороне %item_link" WHERE `id` = 23;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "классный %item_link, только что залутал" WHERE `id` = 24;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "вау, только что получил %item_link" WHERE `id` = 25;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "%item_link — лучший для охотника" WHERE `id` = 26;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "%item_link — лучший для %my_class" WHERE `id` = 27;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "сегодня удача на моей стороне %item_link" WHERE `id` = 28;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "классный %item_link, только что залутал" WHERE `id` = 29;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "ОГО, посмотрите, что я только что получил %item_link!!!" WHERE `id` = 30;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Нет @#$@%! Не может быть, я получил %item_link, это безумие" WHERE `id` = 31;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Нет @#$@%! Не может быть, я получил %item_link, это безумие" WHERE `id` = 32;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Я только что взял %quest_link" WHERE `id` = 33;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "только что принял %quest_link" WHERE `id` = 34;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "%quest_link попробую выполнить это задание" WHERE `id` = 35;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "взял %quest_link в %zone_name" WHERE `id` = 36;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Наконец-то закончил %quest_obj_name для %quest_link" WHERE `id` = 37;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "наконец-то получил %quest_obj_available/%quest_obj_required %quest_obj_name для %quest_link" WHERE `id` = 38;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "%quest_obj_full_formatted для %quest_link, наконец-то" WHERE `id` = 39;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Ох, получил %quest_obj_available/%quest_obj_required %quest_obj_name для %quest_link" WHERE `id` = 40;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "еще нужно %quest_obj_missing %quest_obj_name для %quest_link" WHERE `id` = 41;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "%quest_obj_full_formatted, все еще работаю над %quest_link" WHERE `id` = 42;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Наконец-то закончил с %item_link для %quest_link" WHERE `id` = 43;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "наконец-то получил %quest_obj_available/%quest_obj_required %item_link для %quest_link" WHERE `id` = 44;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "%quest_obj_full_formatted для %quest_link, наконец-то" WHERE `id` = 45;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Ох, получил %quest_obj_available/%quest_obj_required %item_link для %quest_link" WHERE `id` = 46;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "еще нужно %quest_obj_missing %item_link для %quest_link" WHERE `id` = 47;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "%quest_obj_full_formatted, все еще работаю над %quest_link" WHERE `id` = 48;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Не успел завершить %quest_link вовремя..." WHERE `id` = 49;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Время для %quest_link вышло :(" WHERE `id` = 50;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Я выполнил все задачи для %quest_link" WHERE `id` = 51;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Выполнил все задачи для %quest_link" WHERE `id` = 52;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Скоро сдам %quest_link, только что закончил все задачи" WHERE `id` = 53;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Да, наконец-то сдал %quest_link" WHERE `id` = 54;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "сдал %quest_link" WHERE `id` = 55;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "смог завершить %quest_link, только что сдал" WHERE `id` = 56;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "только что сдал %quest_link" WHERE `id` = 57;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "только что сдал %quest_link в %zone_name" WHERE `id` = 58;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "еще одна жертва — %victim_name" WHERE `id` = 59;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Я продолжаю убивать %victim_name, нечего рассказывать" WHERE `id` = 60;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "еще один %victim_name пал" WHERE `id` = 61;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "минус один %victim_name в %zone_name" WHERE `id` = 62;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Убил этого элитного ублюдка %victim_name!" WHERE `id` = 63;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "убил элиту %victim_name в %zone_name" WHERE `id` = 64;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Фух, удалось завалить %victim_name!" WHERE `id` = 65;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Это было круто! Только что убил %victim_name! Теперь есть что рассказать" WHERE `id` = 66;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Йо, я только что убил %victim_name!" WHERE `id` = 67;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "убил редкого %victim_name в %zone_name" WHERE `id` = 68;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Что я только что убил? %victim_name" WHERE `id` = 69;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Только что убил этого пета %victim_name" WHERE `id` = 70;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "О да, только что убил %victim_name" WHERE `id` = 71;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "убил %victim_name в %zone_name" WHERE `id` = 72;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Динг!" WHERE `id` = 73;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Да, я теперь %my_level уровень!" WHERE `id` = 74;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Я только что повысил уровень" WHERE `id` = 75;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Я %my_level уровень!!!" WHERE `id` = 76;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Становлюсь сильнее, уже %my_level уровень!!!" WHERE `id` = 77;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Только что достиг %my_level уровня!!!" WHERE `id` = 78;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "ОГО, наконец-то %my_level уровень!!!" WHERE `id` = 79;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "%my_level!!! теперь могу заниматься эндгейм-контентом" WHERE `id` = 80;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "свежий новый уровень %my_level %my_class!!!" WHERE `id` = 81;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "еще один уровень %my_level %my_race %my_class!" WHERE `id` = 82;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Молодец %other_name. Ты это заслужил." WHERE `id` = 83;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Это было ужасно %other_name. Не хотел этого делать, но..." WHERE `id` = 84;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Кому нужен %instance_name?" WHERE `id` = 85;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Есть группы в %instance_name?" WHERE `id` = 86;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Нужна помощь в %instance_name?" WHERE `id` = 87;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "ЛФД: %instance_name." WHERE `id` = 88;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Кому нужен %my_role для %instance_name?" WHERE `id` = 89;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Не хватает %my_role для %instance_name?" WHERE `id` = 90;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Могу быть %my_role для %instance_name." WHERE `id` = 91;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Нужна помощь с %instance_name?" WHERE `id` = 92;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Нужна помощь %my_role с %instance_name?" WHERE `id` = 93;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Кому нужен шмот из %instance_name?" WHERE `id` = 94;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Немного пофармить в %instance_name?" WHERE `id` = 95;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Ищу %instance_name" WHERE `id` = 96;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Нужна помощь в %instance_name." WHERE `id` = 97;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Хочу пройти %instance_name." WHERE `id` = 98;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "%my_role ищет %instance_name." WHERE `id` = 99;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Как насчет %instance_name?" WHERE `id` = 100;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Кто хочет пофармить %instance_name?" WHERE `id` = 101;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Пойдем в %instance_name?" WHERE `id` = 102;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Ищу %instance_name." WHERE `id` = 103;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Нужна помощь с квестами в %instance_name?" WHERE `id` = 104;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Хочу квестить в %instance_name." WHERE `id` = 105;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Кто-то с квестами в %instance_name?" WHERE `id` = 106;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Могу помочь с квестами в %instance_name." WHERE `id` = 107;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "%my_role: есть место в группе для %instance_name?" WHERE `id` = 108;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Кто-нибудь еще ходит в %instance_name в наши дни?" WHERE `id` = 109;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "%instance_name: кто хочет взять %my_role?" WHERE `id` = 110;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Есть ли смысл быть %my_role в %instance_name?" WHERE `id` = 111;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Стоит ли идти в %instance_name?" WHERE `id` = 112;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Кому нужны еще люди для %instance_name?" WHERE `id` = 113;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "В %instance_name боссы дропают хороший шмот. Пойдем?" WHERE `id` = 114;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Как насчет %instance_name?" WHERE `id` = 115;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Кому нужен %my_role?" WHERE `id` = 116;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Кому нужен %my_role?" WHERE `id` = 117;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Кто хочет %instance_name?" WHERE `id` = 118;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Кто может призвать меня в %instance_name?" WHERE `id` = 119;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Встретимся в %instance_name" WHERE `id` = 120;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Хочу быструю пробежку %instance_name" WHERE `id` = 121;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Хочу полный забег %instance_name" WHERE `id` = 122;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Сколько раз ты был в %instance_name?" WHERE `id` = 123;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Еще один забег в %instance_name?" WHERE `id` = 124;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Вайпнулись в %instance_name? Возьмите меня!" WHERE `id` = 125;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Возьмите меня в %instance_name, пожалуйста." WHERE `id` = 126;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Быстрый забег в %instance_name?" WHERE `id` = 127;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Полный забег в %instance_name?" WHERE `id` = 128;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Кто может взять %my_role в %instance_name?" WHERE `id` = 129;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "ЛФГ %instance_name, я %my_role" WHERE `id` = 130;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "%my_role ЛФГ %instance_name" WHERE `id` = 131;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Нужна помощь с %quest_link?" WHERE `id` = 132;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Кто хочет поделиться %quest_link?" WHERE `id` = 133;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Кто делает %quest_link?" WHERE `id` = 134;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Хочу сделать %quest_link." WHERE `id` = 135;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Кто хочет пофармить %category?" WHERE `id` = 136;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Ищу помощь для фарма %category." WHERE `id` = 137;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Черт, %category такие дорогие!" WHERE `id` = 138;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Хочу %category." WHERE `id` = 139;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Нужна помощь с %category." WHERE `id` = 140;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Куплю %category." WHERE `id` = 141;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Кому интересно %category?" WHERE `id` = 142;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Продам %category." WHERE `id` = 143;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Продаю %category дешевле, чем на Аукционе." WHERE `id` = 144;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Кто хочет пофармить %category?" WHERE `id` = 145;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Хочу пофармить %category." WHERE `id` = 146;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Ищу пати после %category." WHERE `id` = 147;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Любые %category приветствуются." WHERE `id` = 148;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Куплю что угодно из %category." WHERE `id` = 149;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Вау, кто-то фармит %category!" WHERE `id` = 150;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "%category отлично продаются на аукционе." WHERE `id` = 151;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Аукцион горячий по %category." WHERE `id` = 152;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "%category на рынке." WHERE `id` = 153;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Хочу обменять немного %category." WHERE `id` = 154;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Нужно больше %category." WHERE `id` = 155;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Кто-нибудь может поделиться %category?" WHERE `id` = 156;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Кто хочет %category?" WHERE `id` = 157;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Немного %category, пожалуйста?" WHERE `id` = 158;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Надо было прокачать навык для %category." WHERE `id` = 159;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Очень хочу %category." WHERE `id` = 160;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Люди убивают ради %category." WHERE `id` = 161;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "%category — отличная сделка!" WHERE `id` = 162;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Все сходят с ума по %category!" WHERE `id` = 163;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Где лучше всего фармить %category?" WHERE `id` = 164;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Я полностью готов к %category." WHERE `id` = 165;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Выгодно ли продавать %category?" WHERE `id` = 166;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Наверное, я бы оставил все свои %category себе." WHERE `id` = 167;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Нужна группа? Может, пофармить %category?" WHERE `id` = 168;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Все еще думаю о %category." WHERE `id` = 169;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Я уже слышал о %category, но карманы пусты." WHERE `id` = 170;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "ЛФГ для %category" WHERE `id` = 171;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Сделает ли продажа %category меня богатым?" WHERE `id` = 172;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "ОК. Завтра фармлю %category." WHERE `id` = 173;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Все говорят о %category." WHERE `id` = 174;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Видел как минимум десять человек, фармящих %category." WHERE `id` = 175;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Вчера продал все свои %category. Теперь я полностью на мели!" WHERE `id` = 176;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Хочу вступить в гильдию, фармящую %category." WHERE `id` = 177;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Кто фармит репутацию %faction?" WHERE `id` = 178;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Кто поможет с %faction?" WHERE `id` = 179;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Хочу квестить ради %faction." WHERE `id` = 180;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "%faction — лучшая." WHERE `id` = 181;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Нужно чуть-чуть, чтобы стать %rep_level у %faction." WHERE `id` = 182;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Кто-нибудь уже %rep_level у %faction?" WHERE `id` = 183;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Кто хочет стать %rep_level у %faction?" WHERE `id` = 184;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Я никогда не стану %rep_level у %faction." WHERE `id` = 185;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Кто-то не хватает репы у %faction?" WHERE `id` = 186;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Могу помочь с фармом репы %faction." WHERE `id` = 187;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Чем больше репы, тем лучше. Особенно у %faction." WHERE `id` = 188;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "%faction: нужно %rndK для %rep_level." WHERE `id` = 189;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Кто может поделиться квестами %faction?" WHERE `id` = 190;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Есть подземелья для %faction?" WHERE `id` = 191;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Хочу фармить репу %faction." WHERE `id` = 192;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Давайте фармить репу %faction!" WHERE `id` = 193;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Фармлю репу %faction." WHERE `id` = 194;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Хочу пофармить %faction." WHERE `id` = 195;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Нужна помощь с %faction." WHERE `id` = 196;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "%faction что-то полезное продает?" WHERE `id` = 197;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Есть ли у %faction торговцы?" WHERE `id` = 198;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Кто фармит %faction?" WHERE `id` = 199;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Как лучше всего фармить %faction?" WHERE `id` = 200;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Ненавижу фарм репы %faction." WHERE `id` = 201;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Я так устал от %faction." WHERE `id` = 202;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Пойдем за %faction?" WHERE `id` = 203;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Кажется, все уже %rep_level у %faction. Только я, как обычно, опаздываю." WHERE `id` = 204;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "ЛФГ для фарма репы %faction?" WHERE `id` = 205;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Кто-нибудь подскажет хорошее место для фарма репы %faction?" WHERE `id` = 206;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Будет ли польза от репы %faction?" WHERE `id` = 207;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Кто бы мог подумать, что репа %faction окажется полезной..." WHERE `id` = 208;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Хочу быть превознесенным у всех фракций, начну с %faction." WHERE `id` = 209;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Есть ли смысл повышать репу с %faction?" WHERE `id` = 210;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Что лучше для %faction? Квесты или фарм мобов?" WHERE `id` = 211;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Пофармлю репу %faction для тебя. Только дай немного золота." WHERE `id` = 212;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Думаю, фармить репу %faction — это навсегда." WHERE `id` = 213;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Я убиваю ради %faction каждый день, но все еще далеко до %rep_level." WHERE `id` = 214;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "На %my_level депозиты на аукционе уменьшатся, да?" WHERE `id` = 215;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Сколько у тебя превознесенных реп?" WHERE `id` = 216;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Кто хочет быть %my_level у %faction?" WHERE `id` = 217;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Черт. Моя гильдия вчера хорошо пофармила %faction без меня." WHERE `id` = 218;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Никто не хочет мне помогать, потому что я %rep_level у %faction." WHERE `id` = 219;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Пожалуйста, держись подальше от %faction." WHERE `id` = 220;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Хочу в пати в %zone_name." WHERE `id` = 221;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Кто ищет %my_role?" WHERE `id` = 222;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "%my_role ищет гильдию." WHERE `id` = 223;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Ищу золото." WHERE `id` = 224;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "%my_role хочет вступить в хорошую гильдию." WHERE `id` = 225;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Нужен друг." WHERE `id` = 226;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Кто-нибудь чувствует себя одиноко?" WHERE `id` = 227;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Скучно..." WHERE `id` = 228;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Кто хочет немного?" WHERE `id` = 229;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Давай, поймай меня!" WHERE `id` = 230;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Может, дуэль в %zone_name?" WHERE `id` = 231;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Кто-нибудь что-то делает?" WHERE `id` = 232;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "%zone_name: кто-нибудь здесь есть?" WHERE `id` = 233;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "%zone_name: где все?" WHERE `id` = 234;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Похоже, я один в %zone_name." WHERE `id` = 235;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Встретимся в %zone_name." WHERE `id` = 236;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Давайте квестить в %zone_name!" WHERE `id` = 237;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "%zone_name — лучшее место!" WHERE `id` = 238;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Хочу в %zone_name. Кто со мной?" WHERE `id` = 239;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Кто хочет пойти в %zone_name?" WHERE `id` = 240;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Мне не нравится %zone_name. Куда пойти?" WHERE `id` = 241;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Есть хорошие квесты в %zone_name?" WHERE `id` = 242;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Куда идти после %zone_name?" WHERE `id` = 243;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Кто в %zone_name?" WHERE `id` = 244;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "ЛФГ в %zone_name." WHERE `id` = 245;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "%zone_name — худшее место." WHERE `id` = 246;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Лови меня в %zone_name!" WHERE `id` = 247;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Пойдем в %zone_name!" WHERE `id` = 248;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Хочу квестить в %zone_name" WHERE `id` = 249;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "У кого есть квесты в %zone_name?" WHERE `id` = 250;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Приходите сюда, в %zone_name!" WHERE `id` = 251;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Похоже, в %zone_name нет Орды" WHERE `id` = 252;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Похоже, в %zone_name нет Альянса" WHERE `id` = 253;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Я очень устал от %zone_name. Может, пойти куда-нибудь еще?" WHERE `id` = 254;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Удачи" WHERE `id` = 255;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Хочу домой, а потом на край" WHERE `id` = 256;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Кто-нибудь знает, что нужно для двуручного боя?" WHERE `id` = 257;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Всем привет!" WHERE `id` = 258;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "%zone_name уютно" WHERE `id` = 259;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Я отлично себя чувствую" WHERE `id` = 260;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Я не игнорирую людей, я троллю их, пока они не проигнорируют меня" WHERE `id` = 261;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Что думаете о моей сборке? %my_role" WHERE `id` = 262;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Рад видеть, что чат еще помнит" WHERE `id` = 263;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Как и все оружие — это лучший для охотника" WHERE `id` = 264;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Вся суть игры для меня — соло и поиск новых способов соло" WHERE `id` = 265;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Я НИКОГДА никого не обманывал" WHERE `id` = 266;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Ах да, мир варкрафта, где я ищу жизненные советы" WHERE `id` = 267;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "АЛЛО?" WHERE `id` = 268;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Пора пробиваться в %zone_name" WHERE `id` = 269;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "%zone_name" WHERE `id` = 270;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "надо в туалет" WHERE `id` = 271;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Если не лутать скинируемых мобов, твой пп уменьшится на 1мм навсегда" WHERE `id` = 272;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "НЕТТТТТТТТТТ" WHERE `id` = 273;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Я ЛЮБЛЮ КАРТОШКУ" WHERE `id` = 274;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "w чат" WHERE `id` = 275;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "привет, как дела" WHERE `id` = 276;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "только что вышел и снова зашел" WHERE `id` = 277;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "можете потише, я заблудился в %zone_name" WHERE `id` = 278;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "кто хочет выпить со мной в %zone_name ... ик!" WHERE `id` = 279;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "хахахахахииииииии дирин диринг инггггг хахахахахииииииииииииии" WHERE `id` = 280;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "раньше приманка была правдоподобной" WHERE `id` = 281;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "может, ты просто потерял невинность" WHERE `id` = 282;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "есть гильдии, готовые тащить %my_role?" WHERE `id` = 283;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "чем выше уровень, тем легче золото" WHERE `id` = 284;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "утро" WHERE `id` = 285;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "почему у меня болит задница?" WHERE `id` = 286;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Мне кажется, дух — лучший для прокачки" WHERE `id` = 287;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Особенно для тролля" WHERE `id` = 288;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "КТО-НИБУДЬ ПРИГЛАСИТЕ МЕНЯ" WHERE `id` = 289;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "нужно много выпивки" WHERE `id` = 290;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "чертовы гномы" WHERE `id` = 291;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "никто не любит гномов" WHERE `id` = 292;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "гномы годятся только для одного" WHERE `id` = 293;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Ну" WHERE `id` = 294;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "грибы" WHERE `id` = 295;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "автоматические мысли — страшная вещь" WHERE `id` = 296;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "ум более гибок, чем нам кажется" WHERE `id` = 297;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "есть гильдии для прокачки?" WHERE `id` = 298;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "брб" WHERE `id` = 299;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Почему снег белый, а лед прозрачный? Ведь это одно и то же" WHERE `id` = 300;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "почему взбитые сливки пышные, а обычные нет" WHERE `id` = 301;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "почему ноги пахнут, если у них нет носа" WHERE `id` = 302;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "похоже, прибыла банка новичков" WHERE `id` = 303;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "хватит троллить новичков бредовыми ответами" WHERE `id` = 304;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "На этом сервере есть PvP?" WHERE `id` = 305;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "угу" WHERE `id` = 306;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "фух... :)" WHERE `id` = 307;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "вы знали что" WHERE `id` = 308;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "я не пытаюсь представить, что чувствуют другие существа" WHERE `id` = 309;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "ой, не тот чат" WHERE `id` = 310;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "бро, вы сегодня отжигаете" WHERE `id` = 311;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "пусть все знают, что мой текст был здесь" WHERE `id` = 312;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "гррр злой" WHERE `id` = 313;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "гринд — это весело" WHERE `id` = 314;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Wow держит меня в тонусе" WHERE `id` = 315;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "у меня вопрос: где можно взять бросок на больше опыта? я в %zone_name" WHERE `id` = 316;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "вы любите сосиски?" WHERE `id` = 317;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Пригласите меня. Я помогу" WHERE `id` = 318;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "какой класс лучше для пвп?" WHERE `id` = 319;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "где, черт возьми, тренер кулинарии в %zone_name" WHERE `id` = 320;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "знаете, что происходит в %zone_name?" WHERE `id` = 321;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Мне нужно что-то скрафтить" WHERE `id` = 322;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "что такое лигма" WHERE `id` = 323;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "что такое сугма" WHERE `id` = 324;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "лима болс" WHERE `id` = 325;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "сугма болс" WHERE `id` = 326;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Я ЕМ ЗАДНИЦУ" WHERE `id` = 327;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Я хочу засунуть %random_inventory_item_link себе в задницу" WHERE `id` = 328;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Я хочу засунуть %random_inventory_item_link тебе в задницу" WHERE `id` = 329;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Дарнасс" WHERE `id` = 330;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "похоже, у тебя сугма" WHERE `id` = 331;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "дииз натс в твой рот" WHERE `id` = 332;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "крутой стояк, бро" WHERE `id` = 333;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "ERP?" WHERE `id` = 334;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "я перепробовал все, но в итоге ERP помог" WHERE `id` = 335;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Хочу заняться этим в %zone_name" WHERE `id` = 336;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "ищу гнома-девушку с гориллой для ERP в %zone_name" WHERE `id` = 337;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "я могу понять засранца, но извращенца?" WHERE `id` = 338;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "в %zone_name нет гят" WHERE `id` = 339;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Я убиваю всех животных в %zone_name. К черту животных!!!" WHERE `id` = 340;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "хорошо, что у меня три ноги" WHERE `id` = 341;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "не злись, я гоиню как сигма" WHERE `id` = 342;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "попробуй палец, но дырку" WHERE `id` = 343;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "%prefix %random_taken_quest_or_item_link" WHERE `id` = 344;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "%prefix %random_inventory_item_link" WHERE `id` = 345;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "%thunderfury_link" WHERE `id` = 346;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "%thunderfury_link%thunderfury_link" WHERE `id` = 347;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "%thunderfury_link%thunderfury_link%thunderfury_link" WHERE `id` = 348;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Кажется, я только что услышал %thunderfury_link" WHERE `id` = 349;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Кажется, я слышал %thunderfury_link" WHERE `id` = 350;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Я точно слышал %thunderfury_link" WHERE `id` = 351;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Не знаю, но уверен, что слышал %thunderfury_link" WHERE `id` = 352;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Ты только что сказал %thunderfury_link" WHERE `id` = 353;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "кто-то сказал %thunderfury_link" WHERE `id` = 354;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Кто-то сказал %thunderfury_link?" WHERE `id` = 355;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Кто-то сказал %thunderfury_link" WHERE `id` = 356;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "%thunderfury_link выходит из шкафа" WHERE `id` = 357;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "мог бы поклясться, что это был %thunderfury_link, хотя, может, и %thunderfury_link" WHERE `id` = 358;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Зачем использовать %thunderfury_link, если %thunderfury_link явно круче" WHERE `id` = 359;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Продаю %item_formatted_link за %cost_gold." WHERE `id` = 360;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Кто хочет %item_formatted_link за %cost_gold?" WHERE `id` = 361;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Кому нужен %item_formatted_link? Всего %cost_gold." WHERE `id` = 362;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Всего %cost_gold за %item_formatted_link!" WHERE `id` = 363;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Продаю %item_formatted_link за %cost_gold." WHERE `id` = 364;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "%item_formatted_link твой всего за %cost_gold!" WHERE `id` = 365;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Смешная цена %cost_gold за %item_formatted_link!" WHERE `id` = 366;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Хочу продать %item_formatted_link за %cost_gold." WHERE `id` = 367;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Кому нужен %item_formatted_link? Всего %cost_gold." WHERE `id` = 368;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Кому нужен %item_formatted_link за %cost_gold?" WHERE `id` = 369;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "%cost_gold за %item_formatted_link. Дешевле, чем на аукционе!" WHERE `id` = 370;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "%item_formatted_link дорогой, но я бы продал за %cost_gold." WHERE `id` = 371;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Ты нигде не найдешь %item_formatted_link дешевле, чем за %cost_gold!" WHERE `id` = 372;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Нужно больше, чем %item_formatted_link!" WHERE `id` = 373;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "У меня есть %item_formatted_link и нужно еще." WHERE `id` = 374;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Есть %item_formatted_link. Кто хочет купить за %cost_gold?" WHERE `id` = 375;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Кто хочет купить %item_formatted_link за %cost_gold?" WHERE `id` = 376;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Как насчет %item_formatted_link? За %cost_gold." WHERE `id` = 377;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Кто сказал, что я ублюдок? %item_formatted_link за %cost_gold — хорошая цена." WHERE `id` = 378;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Продаю %item_formatted_link? Всего %cost_gold." WHERE `id` = 379;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "ЛФГ для фарма. Все еще можешь купить %item_formatted_link у меня за %cost_gold." WHERE `id` = 380;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Сегодня почти все продал. Еще есть %item_formatted_link за %cost_gold." WHERE `id` = 381;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Для чего нужен торговый чат? Конечно, чтобы продавать %item_formatted_link за %cost_gold." WHERE `id` = 382;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Кто перебьет цену %cost_gold за %item_formatted_link?" WHERE `id` = 383;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Хочешь прекратить торговый чат? Просто купи %item_formatted_link за %cost_gold!" WHERE `id` = 384;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Все спамят в торговом чате. Я тоже — %cost_gold за %item_formatted_link!" WHERE `id` = 385;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Есть ли польза от %item_formatted_link? Просто продаю за %cost_gold." WHERE `id` = 386;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "У меня есть %item_formatted_link, готов продать за %cost_gold." WHERE `id` = 387;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Вчера ничего не делал, но получил %item_formatted_link. Продаю за %cost_gold." WHERE `id` = 388;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Вчера фармил и получил %item_formatted_link. Кто купит за %cost_gold?" WHERE `id` = 389;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Вчера купил %item_formatted_link. Кому нужно за %cost_gold?" WHERE `id` = 390;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Кто спрашивал про %item_formatted_link? Цена та же — %cost_gold." WHERE `id` = 391;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "У меня еще есть %item_formatted_link. Купишь за %cost_gold?" WHERE `id` = 392;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Раньше было больше, чем %item_formatted_link. Теперь нужно продать за %cost_gold." WHERE `id` = 393;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Хотел бы иметь больше, чем %item_formatted_link. Но можешь купить за %cost_gold." WHERE `id` = 394;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Для чего твое золото? Чтобы купить мой %item_formatted_link за %cost_gold." WHERE `id` = 395;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Пожалуйста, подкинь немного золота. Можешь купить %item_formatted_link за %cost_gold." WHERE `id` = 396;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "%cost_gold — хорошая цена за %item_formatted_link?" WHERE `id` = 397;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Вчера купил %item_formatted_links, но больше не нужно. Кому за %cost_gold?" WHERE `id` = 398;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Собирался выставить %item_formatted_link на аукцион, но можешь купить дешевле сейчас за %cost_gold." WHERE `id` = 399;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Зачем, черт возьми, я купил %item_formatted_link? Кому нужно за %cost_gold?" WHERE `id` = 400;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "У меня есть %quest_links" WHERE `id` = 401;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "У меня тоже есть %quest_links" WHERE `id` = 402;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "У меня тоже есть %quest_links, сейчас я в %zone_name" WHERE `id` = 403;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "%other_name, у меня тоже есть %quest_links" WHERE `id` = 404;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "%other_name, у меня тоже есть %quest_links, сейчас я в %zone_name" WHERE `id` = 405;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Я готов к %quest_links, сейчас я в %zone_name" WHERE `id` = 406;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Я готов к %quest_links, я %my_role" WHERE `id` = 407;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "%other_name, я готов к %quest_links, сейчас я в %zone_name" WHERE `id` = 408;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "%other_name, я готов к %quest_links, я %my_role" WHERE `id` = 409;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Привет, я готов к %quest_links" WHERE `id` = 410;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Привет, могу сделать %quest_links с тобой" WHERE `id` = 411;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Привет, у меня тоже есть %quest_links" WHERE `id` = 412;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Привет %other_name, я готов к %quest_links" WHERE `id` = 413;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Привет %other_name, могу сделать %quest_links с тобой" WHERE `id` = 414;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Привет %other_name, у меня тоже есть %quest_links" WHERE `id` = 415;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Хочешь сгруппироваться для %quest_links?" WHERE `id` = 416;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Я готов к %quest_links, сейчас я в %zone_name" WHERE `id` = 417;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Я готов к %quest_links, я %my_role" WHERE `id` = 418;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "%other_name, могу продать тебе %formatted_item_links" WHERE `id` = 419;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Могу, возможно, продать %formatted_item_links" WHERE `id` = 420;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Думаю, могу продать %formatted_item_links" WHERE `id` = 421;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "%other_name, возможно, могу продать %formatted_item_links" WHERE `id` = 422;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "%other_name, думаю, могу продать %formatted_item_links" WHERE `id` = 423;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Могу продать тебе %formatted_item_links" WHERE `id` = 424;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Привет, у меня есть %formatted_item_links на продажу" WHERE `id` = 425;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Привет, возможно, могу продать %formatted_item_links" WHERE `id` = 426;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Квест принят" WHERE `id` = 427;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Квест удален" WHERE `id` = 428;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Я не могу взять этот квест" WHERE `id` = 429;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Я не могу поговорить с дающим квест" WHERE `id` = 430;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Я уже выполнил %quest" WHERE `id` = 431;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "У меня уже есть %quest" WHERE `id` = 432;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Я не могу взять %quest" WHERE `id` = 433;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Я не могу взять %quest, потому что мой журнал квестов заполнен" WHERE `id` = 434;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Я не могу взять %quest, потому что моя сумка заполнена" WHERE `id` = 435;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Я принял %quest" WHERE `id` = 436;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Я не выполнил квест %quest" WHERE `id` = 437;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Квест %quest доступен" WHERE `id` = 438;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Я провалил квест %quest" WHERE `id` = 439;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Я не могу сдать квест %quest" WHERE `id` = 440;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Я выполнил квест %quest" WHERE `id` = 441;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Я выполнил квест %quest и получил %item" WHERE `id` = 442;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Какую награду выбрать за выполнение квеста %quest?%rewards" WHERE `id` = 443;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Хорошо, выберу %item в качестве награды" WHERE `id` = 444;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Привет" WHERE `id` = 445;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Привет!" WHERE `id` = 446;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Здравствуй" WHERE `id` = 447;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Здравствуй!" WHERE `id` = 448;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Приветствую!" WHERE `id` = 449;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Привет, я следую за тобой!" WHERE `id` = 450;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Привет, веди меня!" WHERE `id` = 451;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Привет, веди меня!" WHERE `id` = 452;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Эй %player, хочешь в мою группу?" WHERE `id` = 453;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Эй %player, хочешь в мою группу?" WHERE `id` = 454;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Выход отменен!" WHERE `id` = 455;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Я выхожу из игры!" WHERE `id` = 456;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "До свидания!" WHERE `id` = 457;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Пока!" WHERE `id` = 458;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Увидимся!" WHERE `id` = 459;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "что это было, %s?" WHERE `id` = 460;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "не уверен, что понял %s?" WHERE `id` = 461;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "эээ... не понимаю, о чем ты" WHERE `id` = 462;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "ты ко мне обращаешься, %s?" WHERE `id` = 463;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "чт-что?" WHERE `id` = 464;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "а?" WHERE `id` = 465;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "что?" WHERE `id` = 466;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "ты говоришь?" WHERE `id` = 467;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "как хочешь" WHERE `id` = 468;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "ты меня запутал" WHERE `id` = 469;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Бла бла бла..." WHERE `id` = 470;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Что ты сказал, %s?" WHERE `id` = 471;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Сконцентрируйся на игре, %s!" WHERE `id` = 472;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Общаться с тобой, %s, так здорово! Всегда хотел встретиться" WHERE `id` = 473;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Эти сообщения в чате сводят меня с ума! Такое чувство, что я всех вас знаю!" WHERE `id` = 474;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "ДА ЛАДНО! ХАХА КОНЕЧНО!!!" WHERE `id` = 475;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Я тебе верю!!!" WHERE `id` = 476;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "ОК, ага, ЛОЛ" WHERE `id` = 477;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Почему все всегда говорят одно и то же???" WHERE `id` = 478;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Эй %s... а, неважно!" WHERE `id` = 479;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "О чем ты, %s" WHERE `id` = 480;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Кто это сказал? Я похож на это замечание" WHERE `id` = 481;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "чего вы все несете" WHERE `id` = 482;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "фр фр, без шуток" WHERE `id` = 483;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "ты ничего не получишь" WHERE `id` = 484;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "сваг" WHERE `id` = 485;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "спасибо!" WHERE `id` = 486;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "нет" WHERE `id` = 487;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Да" WHERE `id` = 488;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "ф" WHERE `id` = 489;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "%s, без шуток xD" WHERE `id` = 490;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "почему так" WHERE `id` = 491;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "лмао" WHERE `id` = 492;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "решил помолчать, снова запутался в чате" WHERE `id` = 493;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "я могу по-настоящему завидовать" WHERE `id` = 494;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "%s, ты не слышишь капающую иронию в моем тексте" WHERE `id` = 495;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "он сказал без обид, все нормально" WHERE `id` = 496;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "момент дворфа" WHERE `id` = 497;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Да, %s" WHERE `id` = 498;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "интересно..." WHERE `id` = 499;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "лол" WHERE `id` = 500;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "%s, иди ты :D" WHERE `id` = 501;
UPDATE `ai_playerbot_texts` SET `text_loc8` = ":^)" WHERE `id` = 502;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "спс" WHERE `id` = 503;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "%s, хорошо сказано" WHERE `id` = 504;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "ура" WHERE `id` = 505;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "да" WHERE `id` = 506;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "ооооо" WHERE `id` = 507;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "хмм" WHERE `id` = 508;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "ага, конечно" WHERE `id` = 509;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "ты заставил меня блевануть, что за" WHERE `id` = 510;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "жарко" WHERE `id` = 511;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "злятся" WHERE `id` = 512;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "что ты ел, %s" WHERE `id` = 513;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "что за" WHERE `id` = 514;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "попробую понять этот комментарий" WHERE `id` = 515;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "*в замешательстве*" WHERE `id` = 516;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "да, черт возьми" WHERE `id` = 517;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "0/10 не стал бы читать снова" WHERE `id` = 518;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "10/10 прочитал бы снова" WHERE `id` = 519;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "6/10 прочитал бы" WHERE `id` = 520;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "7/10 прочитал бы" WHERE `id` = 521;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "бейсд" WHERE `id` = 522;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "о да, может быть" WHERE `id` = 523;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "да, и что" WHERE `id` = 524;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "эй %s, я тебя не забыл" WHERE `id` = 525;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "ты меня бесишь, %s" WHERE `id` = 526;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "я достану тебя в этот раз, %s" WHERE `id` = 527;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "лучше берегись, %s" WHERE `id` = 528;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "мне не понравился прошлый раунд" WHERE `id` = 529;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "я был плох в прошлом раунде из-за %s" WHERE `id` = 530;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "готовься умереть, %s" WHERE `id` = 531;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "не нравится, что ты меня убил, %s" WHERE `id` = 532;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "%s, я тебя ненавижу" WHERE `id` = 533;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "грррр, в этот раз я тебя достану, %s" WHERE `id` = 534;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "ну и пошел ты" WHERE `id` = 535;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "%s, я тебе в рот блевану" WHERE `id` = 536;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "не суди меня" WHERE `id` = 537;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Твоя мама такая толстая, что не может пройти через Темный Портал" WHERE `id` = 538;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "что за" WHERE `id` = 539;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "что за??" WHERE `id` = 540;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "ничтожество" WHERE `id` = 541;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "что за" WHERE `id` = 542;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "отстой" WHERE `id` = 543;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "РЕВАНШ!!! я его уделаю" WHERE `id` = 544;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "жалко, меня убил %s" WHERE `id` = 545;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "ладно, я закончил" WHERE `id` = 546;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "хе-хе, я уделал %s?" WHERE `id` = 547;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "это было слишком просто, убил %s" WHERE `id` = 548;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "попался, дружок" WHERE `id` = 549;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "ха-ха" WHERE `id` = 550;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "лузер" WHERE `id` = 551;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "я убил %s, вы все следующие" WHERE `id` = 552;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "о да, я его уделал" WHERE `id` = 553;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "я машина для убийств" WHERE `id` = 554;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "%s, это напоминает мне песню Slayer... столько крови" WHERE `id` = 555;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "извини, %s. можем повторить сцену?" WHERE `id` = 556;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "ну как тебе быть кормом для червей, %s???" WHERE `id` = 557;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "ты должен быть мёртв, %s, это часть игры!!!!!" WHERE `id` = 558;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "извини, %s. выглядело так же хорошо, как картина Энди Уорхола!" WHERE `id` = 559;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "%s, в следующий раз использую резиновые пули!" WHERE `id` = 560;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "что случилось, %s?? голову потерял? хахаха, надо сохранять хладнокровие!!" WHERE `id` = 561;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "я должен был это сделать, %s. Ты понимаешь. Режиссёр так сказал!!" WHERE `id` = 562;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "эй, %s.......МУАХАХАХАХАХАХА" WHERE `id` = 563;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "%s, мне это понравилось!! Давай сыграем ещё раз, Сэм" WHERE `id` = 564;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "эй, %s! можешь звать меня ликом... ты кусок ЧЕРТА!!!!" WHERE `id` = 565;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "ты со мной разговариваешь, %s??" WHERE `id` = 566;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "%s, в этот раз не стой перед моими пулями." WHERE `id` = 567;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "%s, чего ты валяешься??? хехе" WHERE `id` = 568;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "сильно смеялся" WHERE `id` = 569;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "привет %s" WHERE `id` = 570;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "о, привет %s" WHERE `id` = 571;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "как дела, %s!!!" WHERE `id` = 572;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "привет" WHERE `id` = 573;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "как дела" WHERE `id` = 574;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "здравствуй %s" WHERE `id` = 575;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "привет %s, мы знакомы?" WHERE `id` = 576;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "эй %s" WHERE `id` = 577;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "хай %s" WHERE `id` = 578;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "что за фигня" WHERE `id` = 579;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "что за черт" WHERE `id` = 580;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "это бред" WHERE `id` = 581;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "админ" WHERE `id` = 582;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "эй %s, хватит злоупотреблять своими правами админа" WHERE `id` = 583;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "оставь меня в покое, админ!" WHERE `id` = 584;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "ты отстой, админ" WHERE `id` = 585;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "это моё имя, что тебе нужно %s" WHERE `id` = 586;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "да???" WHERE `id` = 587;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "эээ... что" WHERE `id` = 588;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "ты со мной разговариваешь, %s?" WHERE `id` = 589;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "У меня под бронёй щенки!" WHERE `id` = 590;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Укуси меня, <target>!" WHERE `id` = 591;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Эй, <target>! Угадай, что твоя мама сказала прошлой ночью!" WHERE `id` = 592;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "<target>, ты такой урод, что даже в обезьяньем борделе с бананами не добился бы успеха!" WHERE `id` = 593;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Заткнись, <target>, тебе никогда не стать таким мужчиной, как твоя мать!!" WHERE `id` = 594;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Твоя мать была хомяком, а отец пах одуванчиками!!!!" WHERE `id` = 595;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Я больше не хочу с тобой разговаривать, ты пустоголовый кормовой корытоочиститель!!!" WHERE `id` = 596;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Я пускаю в твою сторону газы!!!" WHERE `id` = 597;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Иди и вскипяти свою задницу, сын смешного человека!!!" WHERE `id` = 598;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Что ты собираешься делать, <target>, заставить меня кровоточить? ВПЕРЁД!" WHERE `id` = 599;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "М-О-О-Н! Это значит агр!" WHERE `id` = 600;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Ты так же полезен, как одноногий на конкурсе пинков." WHERE `id` = 601;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Эй, <target>! Перестань клеиться к ним, они не твой тип. Они не надувные." WHERE `id` = 602;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "<target>, ты настолько не в своей лиге, что играешь в другой вид спорта." WHERE `id` = 603;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Ты сегодня совершил большую ошибку, <target>, ты встал с кровати." WHERE `id` = 604;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Я хочу попробовать превратиться в лошадь, но мне нужна помощь. Я буду спереди, а ты будь собой." WHERE `id` = 605;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Можно я одолжу твоё лицо на пару дней? Моя задница уходит в отпуск...." WHERE `id` = 606;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Я бы хотел сделать тебе прощальный подарок... Сначала ты сделай свою часть." WHERE `id` = 607;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "До тебя мы были голодны, теперь мы просто сыты по горло." WHERE `id` = 608;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Ты мне нравишься. Говорят, у меня нет вкуса, но ты мне нравишься." WHERE `id` = 609;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Думаю, у тебя комплекс неполноценности, но это нормально, он оправдан." WHERE `id` = 610;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Прочь, гнилое создание! Или я вытрясу твои кости из одежды." WHERE `id` = 611;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Не могу поверить, что трачу на тебя своё время!" WHERE `id` = 612;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Мне нравится, когда меня оскорбляют, значит, можно больше не быть вежливым." WHERE `id` = 613;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Ты кожаный-жилет, хрустальная пуговица, узловатый, агатовый, рвотный чулок, ленточный подвязочник, гладкоязычный, испанский кошелёк!" WHERE `id` = 614;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Ты дрожащий ловец летучих мышей, пивной червь!" WHERE `id` = 615;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Ты действительно идол поклонников идиотов!" WHERE `id` = 616;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Ты ублюдочный узловатый хвостун!" WHERE `id` = 617;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Ты, ублюдочный мандрагор, тебе больше подходит быть у меня на шапке, чем ждать у моих пяток!" WHERE `id` = 618;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Ты! Ты кухарка! Ты бродяга! Ты мерзавец! Я пощекочу твою катастрофу!" WHERE `id` = 619;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "О, <target>! Ты заразная, плохо воспитанная льняная девка!" WHERE `id` = 620;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Мы протекаем в твоей трубе, <target>!" WHERE `id` = 621;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "О, ты бесполезный болотный цветок!" WHERE `id` = 622;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Если бы я был как ты, я бы выбросил себя!" WHERE `id` = 623;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Научи меня, <target>, как забыть думать!" WHERE `id` = 624;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Истинно, ты проклят, как плохо прожаренное яйцо, с одной стороны!" WHERE `id` = 625;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Ты голодающий, ты кожа-угря, ты сушёный бычий язык, ты бычий член, ты треска — о, чтобы хватило дыхания сказать, что ты такое!! — ты портновский ярд, ты ножны, ты футляр для лука, ты мерзкий стоячий клинок!" WHERE `id` = 626;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Фу! Брось себя в гнилую пасть Смерти!" WHERE `id` = 627;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "<target>, ты торговец рыбой!" WHERE `id` = 628;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Я доживу, чтобы выбить тебе мозги!" WHERE `id` = 629;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Ты очень поверхностен, <target>!! Ты корм для червей по сравнению с хорошим куском мяса!!" WHERE `id` = 630;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Подлый негодяй! О, <target>, ты зловонный, ненавистный к свиньям орех!" WHERE `id` = 631;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "<target>! Твой поцелуй так же утешителен, как замёрзшая вода для голодной змеи!" WHERE `id` = 632;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Я презираю тебя, паршивый спутник. Что, ты бедный, низкий, мошеннический, безрубашечный приятель! Прочь, ты плесневелый негодяй, прочь!" WHERE `id` = 633;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Прочь с глаз моих! Ты заражаешь мои глаза, <target>!" WHERE `id` = 634;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "ВРЕМЯ ИГРЫ!!!!" WHERE `id` = 635;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Никто не пройдёт!" WHERE `id` = 636;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "На нас напали! Вперёд, вы негодяи! Отразите захватчиков!" WHERE `id` = 637;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Никто не может бросить вызов Братству!" WHERE `id` = 638;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Дураки... Убейте того, кто в платье!" WHERE `id` = 639;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Я отдам твою душу самому Хаккару!" WHERE `id` = 640;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Гордость предвещает конец вашего мира! Идите, смертные! Столкнитесь с гневом !" WHERE `id` = 641;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Все мои планы привели к этому!" WHERE `id` = 642;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Ах! Еще ягнята на заклание!" WHERE `id` = 643;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Еще один день, еще одна славная битва!" WHERE `id` = 644;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Итак, дело... или удовольствие?" WHERE `id` = 645;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Вы не готовы!" WHERE `id` = 646;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Финальное завоевание началось! Снова подчинение этого мира в наших руках. Пусть никто не выживет!" WHERE `id` = 647;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Ваша смерть будет болезненной." WHERE `id` = 648;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Просите о милости! Ваши бессмысленные жизни скоро будут потеряны." WHERE `id` = 649;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Оставьте все надежды! вернулся, чтобы завершить то, что было начато много лет назад. На этот раз не будет побега!" WHERE `id` = 650;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Внимание! Вы помечены для уничтожения!" WHERE `id` = 651;
UPDATE `ai_playerbot_texts` SET `text_loc8` = " предназначена только для гостей..." WHERE `id` = 652;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Ха-ха-ха! Вы безнадежно не на уровне!" WHERE `id` = 653;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Я сокрушу ваши иллюзии величия!" WHERE `id` = 654;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Простите меня, ведь вы собираетесь проиграть игру." WHERE `id` = 655;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Борьба только усугубляет ситуацию." WHERE `id` = 656;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Паразиты! Пиявки! Берите мою кровь и подавитесь ею!" WHERE `id` = 657;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Опять... ЕЩЕ РАЗ!" WHERE `id` = 658;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Моя кровь станет вашим концом!" WHERE `id` = 659;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Хорошо, теперь ты сразишься со мной!" WHERE `id` = 660;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Давайте, охранники! Время убивать!" WHERE `id` = 661;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Не задерживайте свою судьбу. Идите ко мне сейчас. Я сделаю вашу жертву быстрой." WHERE `id` = 662;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Ты скоро будешь мертв!" WHERE `id` = 663;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Муа-ха-ха!" WHERE `id` = 664;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Я хищник! Ты жертва..." WHERE `id` = 665;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Ты уйдешь в кусках!" WHERE `id` = 666;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Смерть приходит. Будет ли твоя совесть чиста?" WHERE `id` = 667;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Ваше поведение не будет терпимо." WHERE `id` = 668;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Менажерия предназначена только для гостей." WHERE `id` = 669;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Хмм, незваные гости, нужно подготовиться..." WHERE `id` = 670;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Обнаружены враждебные сущности. Протокол оценки угрозы активирован. Основная цель захвачена. Время до повторной оценки - тридцать секунд." WHERE `id` = 671;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Новые игрушки? Для меня? Обещаю, что на этот раз не сломаю их!" WHERE `id` = 672;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Я готов играть!" WHERE `id` = 673;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Шшш... скоро все закончится." WHERE `id` = 674;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Ааааагхиббргубугбугрубгл!" WHERE `id` = 675;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "РвлРвлРвлРвл!" WHERE `id` = 676;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Ты тоже будешь служить!" WHERE `id` = 677;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Скажи мне... скажи мне все! Непослушные секреты! Я вырву секреты из твоей плоти!" WHERE `id` = 678;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Приготовьтесь, колокола прозвучали! Укройте своих слабых, молодых и старых! Каждый из вас заплатит окончательную цену! Просите о милости, расплата пришла!" WHERE `id` = 679;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Где я, в латунных пуговицах Бонзо?" WHERE `id` = 680;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Я больше не могу это терпеть! Король гоблинов! Король гоблинов! Где бы ты ни был! Унеси этого далеко от меня!" WHERE `id` = 681;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "У вас есть тринадцать часов, чтобы решить лабиринт, прежде чем ваш младший брат станет одним из нас... навсегда." WHERE `id` = 682;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Итак, - это кусок торта, да? Ну, давайте посмотрим, как вы справитесь с этим маленьким куском..." WHERE `id` = 683;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Отступи, я приму тебя, упрямый, готовый сразиться с кем угодно, я знаю, что ты не прав, и это не то место, где ты должен быть." WHERE `id` = 684;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Покажи, что у тебя есть!" WHERE `id` = 685;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "До смерти!" WHERE `id` = 686;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Двойное лезвие, для чистого бритья каждый раз." WHERE `id` = 687;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Давай!" WHERE `id` = 688;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Ты падешь!" WHERE `id` = 689;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Ударь, ударь, ударь!" WHERE `id` = 690;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Давайте сделаем это быстро, время - это мана." WHERE `id` = 691;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Я не думаю, что вы осознаете серьезность вашей ситуации." WHERE `id` = 692;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Я принесу честь своей семье и своему королевству!" WHERE `id` = 693;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Свет, дай мне силу!" WHERE `id` = 694;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Моя церковь - это поле битвы - время поклоняться..." WHERE `id` = 695;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Я держу тебя в презрении..." WHERE `id` = 696;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Столкнись с молотом справедливости!" WHERE `id` = 697;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Докажи свою ценность в испытании оружием под Светом!" WHERE `id` = 698;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Все должны пасть перед могуществом и правом моего дела, ты будешь следующим!" WHERE `id` = 699;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Приготовься умереть!" WHERE `id` = 700;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Зверь со мной ничто по сравнению с зверем внутри..." WHERE `id` = 701;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Стань свидетелем огневой мощи этого полностью вооруженного охотника!" WHERE `id` = 702;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Исцели меня! Быстро!" WHERE `id` = 703;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Почти мертв! Исцели меня!" WHERE `id` = 704;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Помогите! Исцели меня!" WHERE `id` = 705;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Кто-нибудь! Исцели меня!" WHERE `id` = 706;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Исцели! Исцели! Исцели!" WHERE `id` = 707;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Я умираю! Исцели! Ааааргх!" WHERE `id` = 708;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Исцели меня!" WHERE `id` = 709;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Я умру. Я умру. Я умру. Исцели!" WHERE `id` = 710;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Целители, где вы? Я умираю!" WHERE `id` = 711;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "О, боль. Исцели меня быстро!" WHERE `id` = 712;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Нужна исцеление" WHERE `id` = 713;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Низкое здоровье" WHERE `id` = 714;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Сделай исцеление. Пожалуйста." WHERE `id` = 715;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Может кто-нибудь исцелить меня?" WHERE `id` = 716;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Эй! Лучше исцели меня сейчас, чем воскрешать позже." WHERE `id` = 717;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Извини. Нужна еще одна исцеление." WHERE `id` = 718;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Черт возьми, мобы. Исцели меня, пожалуйста." WHERE `id` = 719;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Еще один удар, и я пропал. Исцели, пожалуйста." WHERE `id` = 720;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Есть ли целители?" WHERE `id` = 721;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Почему они всегда бьют меня в лицо? Нужна исцеление." WHERE `id` = 722;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Может кто-нибудь немного исцелить меня?" WHERE `id` = 723;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "OOM" WHERE `id` = 724;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "У меня закончилась мана" WHERE `id` = 725;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Черт, я потратил всю свою ману на это" WHERE `id` = 726;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Тебе стоит подождать, пока я выпью или восстановлю свою ману" WHERE `id` = 727;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Низкая мана" WHERE `id` = 728;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Нет маны. Снова?" WHERE `id` = 729;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Низкая мана. Хочу выпить." WHERE `id` = 730;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "У нас есть торговый автомат? Снова нет маны." WHERE `id` = 731;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Моя мана в истории." WHERE `id` = 732;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "В следующий раз я возьму напитки. Нет маны." WHERE `id` = 733;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Где моя мана?" WHERE `id` = 734;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "У меня осталось немного !" WHERE `id` = 735;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Мне нужно больше !" WHERE `id` = 736;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "100 осталось!" WHERE `id` = 737;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Вот и все! Нет !" WHERE `id` = 738;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "И у тебя есть мой лук... Ой, нет !" WHERE `id` = 739;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Нужна патроны!" WHERE `id` = 740;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "О боже!" WHERE `id` = 741;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Мне страшно" WHERE `id` = 742;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Мы пропали" WHERE `id` = 743;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Это закончено" WHERE `id` = 744;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Это заканчивается сейчас" WHERE `id` = 745;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Может кто-нибудь вызвать метель или что-то подобное?" WHERE `id` = 746;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Черт. Танку агрировал всех мобов вокруг." WHERE `id` = 747;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Мы умрем. Мы умрем. Мы умрем." WHERE `id` = 748;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Ух ты! Так много игрушек, с которыми можно играть." WHERE `id` = 749;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Я убью их всех!" WHERE `id` = 750;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Если танк умрет, мы в истории." WHERE `id` = 751;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Аааааргх!" WHERE `id` = 752;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "ЛЕЕЕЕЕЕЕЕЕЕЕЕЕЕЕЕЕЕЕЕЙ ДЖЕНКИНС!!!!!!!" WHERE `id` = 753;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Правильно. Что у нас есть в AOE?" WHERE `id` = 754;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Это становится интересным." WHERE `id` = 755;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Круто. Соберите их в одном месте для хорошего огненного удара." WHERE `id` = 756;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Убей! Убей! Убей!" WHERE `id` = 757;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Я думаю, что мои штаны мокрые." WHERE `id` = 758;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Мы в истории." WHERE `id` = 759;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Надеюсь, целители готовы. Лееерой!" WHERE `id` = 760;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Надеюсь, они не придут за мной." WHERE `id` = 761;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "О нет. Я не вижу в этом резне." WHERE `id` = 762;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Надеюсь, там будет немного денег." WHERE `id` = 763;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Лут! Лут!" WHERE `id` = 764;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Мое драгоценное." WHERE `id` = 765;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Надеюсь, там ждет меня блестящий эпический предмет." WHERE `id` = 766;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "У меня глубокие карманы и сумки." WHERE `id` = 767;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Все мое!" WHERE `id` = 768;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Надеюсь, сегодня не будет серой ерунды." WHERE `id` = 769;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Этот лут - МОЙ!" WHERE `id` = 770;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Лутать отвратительно, но мне нужны деньги." WHERE `id` = 771;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Золото!" WHERE `id` = 772;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Хорошо. Давайте посмотрим, что у них есть." WHERE `id` = 773;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Не волнуйтесь. Я все залутаю." WHERE `id` = 774;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Я ниндзя лута." WHERE `id` = 775;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Мне нужно бросить кубик?" WHERE `id` = 776;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Кто-нибудь объясните мне, куда они положили все эти вещи?" WHERE `id` = 777;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Нет, я не буду лутать серую ерунду." WHERE `id` = 778;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Я первый. Я первый. Я первый." WHERE `id` = 779;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Отдай мне свои деньги!" WHERE `id` = 780;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Мои карманы пусты, мне нужно их заполнить." WHERE `id` = 781;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "У меня есть новая сумка для этого." WHERE `id` = 782;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Надеюсь, я не агрирую никого, пока лутаю." WHERE `id` = 783;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Пожалуйста, не смотрите. Я лутаю." WHERE `id` = 784;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Ха! Ты не получишь ни кусочка этого!" WHERE `id` = 785;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Лутать круто." WHERE `id` = 786;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Мне нравится новая экипировка." WHERE `id` = 787;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Я уйду, если снова не будет ничего ценного." WHERE `id` = 788;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Надеюсь, это будет красивое кольцо." WHERE `id` = 789;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Я вырву лут у тебя." WHERE `id` = 790;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Все держитесь подальше. Я собираюсь лутать." WHERE `id` = 791;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Сладкий лут." WHERE `id` = 792;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Бог Ролла! Дай мне эпик сегодня." WHERE `id` = 793;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Пожалуйста, дай мне новые игрушки." WHERE `id` = 794;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Надеюсь, они принесут вкусняшки." WHERE `id` = 795;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Золото - мое. Я оставлю все, обещаю." WHERE `id` = 796;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Нет, я не могу устоять." WHERE `id` = 797;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Я хочу больше!" WHERE `id` = 798;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Я близко, подожди меня!" WHERE `id` = 799;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Я не далеко, пожалуйста, подожди!" WHERE `id` = 800;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Я направляюсь к вашему местоположению." WHERE `id` = 801;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Я иду к тебе." WHERE `id` = 802;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Я путешествую к вашему местоположению." WHERE `id` = 803;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Я пытаюсь добраться до тебя." WHERE `id` = 804;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Экипирую %item." WHERE `id` = 805;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "%item снят." WHERE `id` = 806;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Я выучил заклинания: %spells." WHERE `id` = 807;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "%item в перезарядке." WHERE `id` = 808;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "У меня нет %item в инвентаре." WHERE `id` = 809;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Предмет с ID %item не существует." WHERE `id` = 810;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Вставляю %gem в %item." WHERE `id` = 811;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Я не могу использовать %item." WHERE `id` = 812;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Следую." WHERE `id` = 813;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Остаюсь." WHERE `id` = 814;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Убегаю." WHERE `id` = 815;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Я не буду убегать с тобой, ты слишком далеко." WHERE `id` = 816;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Фармлю." WHERE `id` = 817;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Атакую." WHERE `id` = 818;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Это слишком далеко." WHERE `id` = 819;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Это под водой." WHERE `id` = 820;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Я не могу туда пойти." WHERE `id` = 821;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Я не в твоем гильдии!" WHERE `id` = 822;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Не могу найти гильдейский банк поблизости." WHERE `id` = 823;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Я не могу положить " WHERE `id` = 824;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "У меня нет прав на размещение предметов в первой вкладке гильдейского банка." WHERE `id` = 825;
UPDATE `ai_playerbot_texts` SET `text_loc8` = " положено в гильдейский банк." WHERE `id` = 826;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Свободное движение." WHERE `id` = 827;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Охраняю." WHERE `id` = 828;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Использую %target." WHERE `id` = 829;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "на %unit." WHERE `id` = 830;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "(%amount доступно)" WHERE `id` = 831;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "(последний)" WHERE `id` = 832;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Сокет не подходит." WHERE `id` = 833;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "на торговом предмете." WHERE `id` = 834;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "на себе." WHERE `id` = 835;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "на %item." WHERE `id` = 836;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "на %gameobject." WHERE `id` = 837;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Лутаю %item." WHERE `id` = 838;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Призываю %target." WHERE `id` = 839;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "У меня недостаточно членов группы, чтобы вызвать." WHERE `id` = 840;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Не удалось найти цель для призыва." WHERE `id` = 841;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Я не могу призывать, пока я в бою." WHERE `id` = 842;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Я не знаю заклинание %spell." WHERE `id` = 843;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Кастую %spell." WHERE `id` = 844;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Создаю %spell." WHERE `id` = 845;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Не могу кастовать %spell." WHERE `id` = 846;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "Не удалось кастовать %spell." WHERE `id` = 847;
UPDATE `ai_playerbot_texts` SET `text_loc8` = " |cffffff00(x%amount осталось)|r" WHERE `id` = 848;
UPDATE `ai_playerbot_texts` SET `text_loc8` = "dummy" WHERE `id` = 849;

View File

@@ -1,35 +0,0 @@
DELETE FROM ai_playerbot_texts
WHERE name IN (
'rp_missing_reagent_greater_blessing',
'rp_missing_reagent_gift_of_the_wild',
'rp_missing_reagent_arcane_brilliance',
'rp_missing_reagent_generic'
);
DELETE FROM ai_playerbot_texts_chance
WHERE name IN (
'rp_missing_reagent_greater_blessing',
'rp_missing_reagent_gift_of_the_wild',
'rp_missing_reagent_arcane_brilliance',
'rp_missing_reagent_generic'
);
INSERT INTO ai_playerbot_texts (name, text, say_type, reply_type, text_loc1, text_loc2, `text_loc3`, `text_loc4`, `text_loc5`, `text_loc6`, `text_loc7`, `text_loc8`) VALUES
('rp_missing_reagent_greater_blessing',
'By the Light... I forgot my Symbols of Kings. Well make do with %base_spell!', 0, 0,
'', 'Par la Lumière... J''ai oublié mes Symboles du roi. On se contentera de %base_spell !', '', '', '', '', '', ''),
('rp_missing_reagent_gift_of_the_wild',
'Nature is generous, my bags are not... out of herbs for %group_spell. Take %base_spell for now!', 0, 0,
'', 'La nature est généreuse, pas mes sacs... plus d''herbes pour %group_spell. Prenez %base_spell pour l''instant !', '', '', '', '', '', ''),
('rp_missing_reagent_arcane_brilliance',
'Out of Arcane Powder... %group_spell will have to wait. Casting %base_spell!', 0, 0,
'', 'Plus de poudre des arcanes... %group_spell attendra. Je lance %base_spell !', '', '', '', '', '', ''),
('rp_missing_reagent_generic',
'Oops, Im out of components for %group_spell. Well go with %base_spell!', 0, 0,
'', 'Oups, je n''ai plus de composants pour %group_spell. On fera avec %base_spell !', '', '', '', '', '', '');
INSERT INTO ai_playerbot_texts_chance (name, probability) VALUES
('rp_missing_reagent_greater_blessing', 100),
('rp_missing_reagent_gift_of_the_wild', 100),
('rp_missing_reagent_arcane_brilliance', 100),
('rp_missing_reagent_generic', 100);

View File

@@ -1,856 +0,0 @@
UPDATE ai_playerbot_texts SET text_loc2 = '';
UPDATE `ai_playerbot_texts` SET `text_loc2`='au milieu de nulle part' WHERE `id`=1;
UPDATE `ai_playerbot_texts` SET `text_loc2`='un endroit non divulgué' WHERE `id`=2;
UPDATE `ai_playerbot_texts` SET `text_loc2`='quelque part' WHERE `id`=3;
UPDATE `ai_playerbot_texts` SET `text_loc2`='un truc' WHERE `id`=4;
UPDATE `ai_playerbot_texts` SET `text_loc2`='je me demande quel goût a %item_link' WHERE `id`=5;
UPDATE `ai_playerbot_texts` SET `text_loc2`='noooon, jai eu %item_link' WHERE `id`=6;
UPDATE `ai_playerbot_texts` SET `text_loc2`='oh non, encore cette camelote %item_link' WHERE `id`=7;
UPDATE `ai_playerbot_texts` SET `text_loc2`='on dirait que je ramasse des ordures %item_link' WHERE `id`=8;
UPDATE `ai_playerbot_texts` SET `text_loc2`='bon, cest mieux que rien je suppose %item_link' WHERE `id`=9;
UPDATE `ai_playerbot_texts` SET `text_loc2`='je ne sais pas quoi faire de %item_link' WHERE `id`=10;
UPDATE `ai_playerbot_texts` SET `text_loc2`='je me demande quel goût a %item_link' WHERE `id`=11;
UPDATE `ai_playerbot_texts` SET `text_loc2`='je pourrais ramasser du %item_link toute la journée' WHERE `id`=12;
UPDATE `ai_playerbot_texts` SET `text_loc2`='un jour de plus, un %item_link de plus' WHERE `id`=13;
UPDATE `ai_playerbot_texts` SET `text_loc2`='jai ramassé un peu de %item_link' WHERE `id`=14;
UPDATE `ai_playerbot_texts` SET `text_loc2`='un peu de %item_link, cest toujours ça' WHERE `id`=15;
UPDATE `ai_playerbot_texts` SET `text_loc2`='pas mal, je viens de choper %item_link' WHERE `id`=16;
UPDATE `ai_playerbot_texts` SET `text_loc2`='je viens de ramasser %item_link à %zone_name' WHERE `id`=17;
UPDATE `ai_playerbot_texts` SET `text_loc2`='je pourrais bien lutiliser ça %item_link' WHERE `id`=18;
UPDATE `ai_playerbot_texts` SET `text_loc2`='argent, argent, argent %item_link' WHERE `id`=19;
UPDATE `ai_playerbot_texts` SET `text_loc2`='jai eu %item_link' WHERE `id`=20;
UPDATE `ai_playerbot_texts` SET `text_loc2`='%item_link est BiS pour les chasseurs' WHERE `id`=21;
UPDATE `ai_playerbot_texts` SET `text_loc2`='%item_link est BiS pour les %my_class' WHERE `id`=22;
UPDATE `ai_playerbot_texts` SET `text_loc2`='la chance est avec moi aujourdhui %item_link' WHERE `id`=23;
UPDATE `ai_playerbot_texts` SET `text_loc2`='trop bon %item_link, fraîchement looté' WHERE `id`=24;
UPDATE `ai_playerbot_texts` SET `text_loc2`='wow, je viens de choper %item_link' WHERE `id`=25;
UPDATE `ai_playerbot_texts` SET `text_loc2`='%item_link est BiS pour les chasseurs' WHERE `id`=26;
UPDATE `ai_playerbot_texts` SET `text_loc2`='%item_link est BiS pour les %my_class' WHERE `id`=27;
UPDATE `ai_playerbot_texts` SET `text_loc2`='la chance est avec moi aujourdhui %item_link' WHERE `id`=28;
UPDATE `ai_playerbot_texts` SET `text_loc2`='trop bon %item_link, fraîchement looté' WHERE `id`=29;
UPDATE `ai_playerbot_texts` SET `text_loc2`='OMG, regardez ce que je viens de looter %item_link !!!' WHERE `id`=30;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Noooon ! Cest pas possible, jai eu %item_link, cest de la folie' WHERE `id`=31;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Noooon ! Cest pas possible, jai eu %item_link, cest de la folie' WHERE `id`=32;
UPDATE `ai_playerbot_texts` SET `text_loc2`='je viens juste de prendre la quête %quest_link' WHERE `id`=33;
UPDATE `ai_playerbot_texts` SET `text_loc2`='je viens daccepter %quest_link' WHERE `id`=34;
UPDATE `ai_playerbot_texts` SET `text_loc2`='%quest_link je vais essayer de la finir' WHERE `id`=35;
UPDATE `ai_playerbot_texts` SET `text_loc2`='jai pris %quest_link à %zone_name' WHERE `id`=36;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Enfin fini lobjectif %quest_obj_name pour %quest_link' WHERE `id`=37;
UPDATE `ai_playerbot_texts` SET `text_loc2`='jai enfin %quest_obj_available/%quest_obj_required de %quest_obj_name pour %quest_link' WHERE `id`=38;
UPDATE `ai_playerbot_texts` SET `text_loc2`='%quest_obj_full_formatted pour %quest_link, enfin !' WHERE `id`=39;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Oof, jai %quest_obj_available/%quest_obj_required %quest_obj_name pour %quest_link' WHERE `id`=40;
UPDATE `ai_playerbot_texts` SET `text_loc2`='il me manque encore %quest_obj_missing de %quest_obj_name pour %quest_link' WHERE `id`=41;
UPDATE `ai_playerbot_texts` SET `text_loc2`='%quest_obj_full_formatted, je bosse toujours sur %quest_link' WHERE `id`=42;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Enfin fini avec %item_link pour %quest_link' WHERE `id`=43;
UPDATE `ai_playerbot_texts` SET `text_loc2`='jai enfin %quest_obj_available/%quest_obj_required de %item_link pour %quest_link' WHERE `id`=44;
UPDATE `ai_playerbot_texts` SET `text_loc2`='%quest_obj_full_formatted pour %quest_link, enfin !' WHERE `id`=45;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Oof, jai %quest_obj_available/%quest_obj_required %item_link pour %quest_link' WHERE `id`=46;
UPDATE `ai_playerbot_texts` SET `text_loc2`='il me manque encore %quest_obj_missing de %item_link pour %quest_link' WHERE `id`=47;
UPDATE `ai_playerbot_texts` SET `text_loc2`='%quest_obj_full_formatted, je suis encore sur %quest_link' WHERE `id`=48;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Échec : je nai pas fini %quest_link à temps...' WHERE `id`=49;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Plus de temps pour %quest_link :(' WHERE `id`=50;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Jai terminé tous les objectifs de %quest_link' WHERE `id`=51;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Objectifs terminés pour %quest_link' WHERE `id`=52;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je vais rendre %quest_link bientôt, tout est fait' WHERE `id`=53;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Ouiii, jai enfin rendu %quest_link' WHERE `id`=54;
UPDATE `ai_playerbot_texts` SET `text_loc2`='%quest_link rendu' WHERE `id`=55;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Mission %quest_link terminée, rendu !' WHERE `id`=56;
UPDATE `ai_playerbot_texts` SET `text_loc2`='%quest_link rendu' WHERE `id`=57;
UPDATE `ai_playerbot_texts` SET `text_loc2`='%quest_link rendu à %zone_name' WHERE `id`=58;
UPDATE `ai_playerbot_texts` SET `text_loc2`='encore un %victim_name à terre' WHERE `id`=59;
UPDATE `ai_playerbot_texts` SET `text_loc2`='je continue à tuer %victim_name, la routine quoi' WHERE `id`=60;
UPDATE `ai_playerbot_texts` SET `text_loc2`='un autre %victim_name qui mord la poussière' WHERE `id`=61;
UPDATE `ai_playerbot_texts` SET `text_loc2`='un %victim_name en moins à %zone_name' WHERE `id`=62;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Jai descendu ce sale élite %victim_name !' WHERE `id`=63;
UPDATE `ai_playerbot_texts` SET `text_loc2`='élite %victim_name éliminé à %zone_name' WHERE `id`=64;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Ouf, jai réussi à abattre %victim_name !' WHERE `id`=65;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Cétait épique ! %victim_name est tombé, maintenant jai une histoire à raconter' WHERE `id`=66;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Yoo, je viens de tuer %victim_name !' WHERE `id`=67;
UPDATE `ai_playerbot_texts` SET `text_loc2`='rare %victim_name éliminé à %zone_name' WHERE `id`=68;
UPDATE `ai_playerbot_texts` SET `text_loc2`='WTF ais-je bien tué? %victim_name' WHERE `id`=69;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Jai tué cette bestiole %victim_name' WHERE `id`=70;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Oh ouiii, jai tué %victim_name' WHERE `id`=71;
UPDATE `ai_playerbot_texts` SET `text_loc2`='%victim_name éliminé à %zone_name' WHERE `id`=72;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Ding !' WHERE `id`=73;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Ouiii, je suis niveau %my_level !' WHERE `id`=74;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je viens de passer un niveau' WHERE `id`=75;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je suis niveau %my_level !!!' WHERE `id`=76;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je deviens plus fort, déjà %my_level !!!' WHERE `id`=77;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je viens datteindre le niveau %my_level !!!' WHERE `id`=78;
UPDATE `ai_playerbot_texts` SET `text_loc2`='OMG, enfin niveau %my_level !!!' WHERE `id`=79;
UPDATE `ai_playerbot_texts` SET `text_loc2`='%my_level !!! prêt pour le contenu endgame' WHERE `id`=80;
UPDATE `ai_playerbot_texts` SET `text_loc2`='tout frais, nouveau %my_level %my_class !!!' WHERE `id`=81;
UPDATE `ai_playerbot_texts` SET `text_loc2`='encore un niveau %my_level %my_race %my_class !' WHERE `id`=82;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Bien joué %other_name. Tu las mérité.' WHERE `id`=83;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Cétait affreux %other_name. Jai détesté faire ça mais...' WHERE `id`=84;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Quelquun veut faire %instance_name ?' WHERE `id`=85;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Des groupes pour %instance_name ?' WHERE `id`=86;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Besoin daide pour %instance_name ?' WHERE `id`=87;
UPDATE `ai_playerbot_texts` SET `text_loc2`='LFD : %instance_name.' WHERE `id`=88;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Quelquun a besoin dun %my_role pour %instance_name ?' WHERE `id`=89;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Il manque un %my_role pour %instance_name ?' WHERE `id`=90;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je peux être %my_role pour %instance_name.' WHERE `id`=91;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Besoin dun coup de main à %instance_name ?' WHERE `id`=92;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Besoin dun %my_role pour %instance_name ?' WHERE `id`=93;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Quelquun a besoin de loot à %instance_name ?' WHERE `id`=94;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Un petit farm à %instance_name ?' WHERE `id`=95;
UPDATE `ai_playerbot_texts` SET `text_loc2`='WTR %instance_name' WHERE `id`=96;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Besoin daide pour %instance_name.' WHERE `id`=97;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Envie de faire %instance_name.' WHERE `id`=98;
UPDATE `ai_playerbot_texts` SET `text_loc2`='%my_role cherche un groupe pour %instance_name.' WHERE `id`=99;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Et %instance_name, on y va ?' WHERE `id`=100;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Qui veut farmer %instance_name ?' WHERE `id`=101;
UPDATE `ai_playerbot_texts` SET `text_loc2`='On entre dans %instance_name ?' WHERE `id`=102;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je cherche groupe pour %instance_name.' WHERE `id`=103;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Des quêtes à %instance_name ?' WHERE `id`=104;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Envie de faire des quêtes à %instance_name.' WHERE `id`=105;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Quelquun avec des quêtes à %instance_name ?' WHERE `id`=106;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je peux aider pour les quêtes à %instance_name.' WHERE `id`=107;
UPDATE `ai_playerbot_texts` SET `text_loc2`='%my_role : une place dispo pour %instance_name ?' WHERE `id`=108;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Est-ce que quelquun fait encore %instance_name de nos jours ?' WHERE `id`=109;
UPDATE `ai_playerbot_texts` SET `text_loc2`='%instance_name : quelquun cherche un %my_role ?' WHERE `id`=110;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Ça sert encore à quelque chose dêtre %my_role à %instance_name ?' WHERE `id`=111;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Ça vaut vraiment le coup daller à %instance_name ?' WHERE `id`=112;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Quelquun a besoin de plus de joueurs pour %instance_name ?' WHERE `id`=113;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Les boss de %instance_name lootent du bon matos. On y va ?' WHERE `id`=114;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Alors, %instance_name ?' WHERE `id`=115;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Quelquun a besoin dun %my_role ?' WHERE `id`=116;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Quelquun a besoin dun %my_role ?' WHERE `id`=117;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Qui veut aller à %instance_name ?' WHERE `id`=118;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Quelquun peut me TP à %instance_name ?' WHERE `id`=119;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Retrouve-moi à %instance_name' WHERE `id`=120;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Envie dun petit run rapide à %instance_name ?' WHERE `id`=121;
UPDATE `ai_playerbot_texts` SET `text_loc2`='On se fait un run complet à %instance_name ?' WHERE `id`=122;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Tas été combien de fois à %instance_name ?' WHERE `id`=123;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Encore un run à %instance_name ?' WHERE `id`=124;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Wipe à %instance_name ? Prends-moi, je suis un porte-bonheur !' WHERE `id`=125;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Emmène-moi à %instance_name sil te plaît.' WHERE `id`=126;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Un petit %instance_name vite fait bien fait ?' WHERE `id`=127;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Full %instance_name jusquà la fin ?' WHERE `id`=128;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Qui peut prendre un %my_role à %instance_name ?' WHERE `id`=129;
UPDATE `ai_playerbot_texts` SET `text_loc2`='LFG %instance_name, je suis %my_role' WHERE `id`=130;
UPDATE `ai_playerbot_texts` SET `text_loc2`='%my_role cherche groupe pour %instance_name' WHERE `id`=131;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Besoin daide pour %quest_link ?' WHERE `id`=132;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Quelquun veut partager %quest_link ?' WHERE `id`=133;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Quelquun fait %quest_link ?' WHERE `id`=134;
UPDATE `ai_playerbot_texts` SET `text_loc2`='On fait %quest_link ?' WHERE `id`=135;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Quelquun pour farmer du %category ?' WHERE `id`=136;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Cherche aide pour farmer %category.' WHERE `id`=137;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Ces %category coûtent un bras !' WHERE `id`=138;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Jai besoin de %category.' WHERE `id`=139;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Besoin daide pour %category.' WHERE `id`=140;
UPDATE `ai_playerbot_texts` SET `text_loc2`='WTB %category.' WHERE `id`=141;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Quelquun est intéressé par %category ?' WHERE `id`=142;
UPDATE `ai_playerbot_texts` SET `text_loc2`='WTS %category.' WHERE `id`=143;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je vends %category moins cher que lHV.' WHERE `id`=144;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Qui veut farmer du %category ?' WHERE `id`=145;
UPDATE `ai_playerbot_texts` SET `text_loc2`='On farme du %category ?' WHERE `id`=146;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je cherche un groupe, après ça on fait du %category ?' WHERE `id`=147;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Tous les %category sont les bienvenus.' WHERE `id`=148;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Jachète tout ce qui ressemble à du %category.' WHERE `id`=149;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Wow, ya des gens qui farment encore du %category ?' WHERE `id`=150;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Les %category partent comme des petits pains à lHV !' WHERE `id`=151;
UPDATE `ai_playerbot_texts` SET `text_loc2`='LHV brûle à cause des %category !' WHERE `id`=152;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Ya des %category sur le marché.' WHERE `id`=153;
UPDATE `ai_playerbot_texts` SET `text_loc2`='J\'échange des %category ?' WHERE `id`=154;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Il me faut plus de %category.' WHERE `id`=155;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Quelquun a un peu de %category à donner ?' WHERE `id`=156;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Qui veut du %category ?' WHERE `id`=157;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Un peu de %category sil vous plaît ?' WHERE `id`=158;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Jaurais monter une compétence pour les %category.' WHERE `id`=159;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je meurs denvie davoir des %category.' WHERE `id`=160;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Les gens se tuent pour les %category.' WHERE `id`=161;
UPDATE `ai_playerbot_texts` SET `text_loc2`='%category, cest une affaire en or !' WHERE `id`=162;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Tout le monde devient fou pour les %category !' WHERE `id`=163;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Cest le meilleur spot pour farmer des %category ?' WHERE `id`=164;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je suis prêt pour le farm de %category.' WHERE `id`=165;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Ça se vend bien les %category ?' WHERE `id`=166;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je vais garder tous mes %category. Pour moi.' WHERE `id`=167;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Besoin dun groupe ? On pourrait farm des %category ensemble.' WHERE `id`=168;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je pense encore aux %category.' WHERE `id`=169;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Jai entendu parler des %category... mais mon porte-monnaie ne veut pas.' WHERE `id`=170;
UPDATE `ai_playerbot_texts` SET `text_loc2`='LFG pour %category' WHERE `id`=171;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Vendre %category rend riche ?' WHERE `id`=172;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Ok. Demain je farm les %category.' WHERE `id`=173;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Tout le monde parle des %category.' WHERE `id`=174;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Jai vu au moins dix gars farmer du %category.' WHERE `id`=175;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Jai tout vendu mes %category hier. Maintenant je mange du pain sec!' WHERE `id`=176;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Envie de rejoindre une guilde qui farme du %category.' WHERE `id`=177;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Quelquun farm la réputation %faction ?' WHERE `id`=178;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Quelquun peut maider pour %faction ?' WHERE `id`=179;
UPDATE `ai_playerbot_texts` SET `text_loc2`='On fait des quêtes pour %faction ?' WHERE `id`=180;
UPDATE `ai_playerbot_texts` SET `text_loc2`='%faction est la meilleur' WHERE `id`=181;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Il me manque juste un tout petit peu pour être %rep_level avec %faction.' WHERE `id`=182;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Quelquun est %rep_level avec %faction ?' WHERE `id`=183;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Qui veut devenir %rep_level avec %faction ?' WHERE `id`=184;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je serai jamais %rep_level avec %faction.' WHERE `id`=185;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Quelquun a oublié de monter la réputation %faction ?' WHERE `id`=186;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je peux aider à farmer la réputation %faction.' WHERE `id`=187;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Plus on a de réputation, mieux cest. Surtout avec %faction.' WHERE `id`=188;
UPDATE `ai_playerbot_texts` SET `text_loc2`='%faction : il me faut encore %rndK pour être %rep_level.' WHERE `id`=189;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Qui peut partager des quêtes %faction ?' WHERE `id`=190;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Des donjons pour la réputation %faction ?' WHERE `id`=191;
UPDATE `ai_playerbot_texts` SET `text_loc2`='On farm la réput %faction ?' WHERE `id`=192;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Allons-y pour %faction !' WHERE `id`=193;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je farm la réputation %faction.' WHERE `id`=194;
UPDATE `ai_playerbot_texts` SET `text_loc2`='On farme pour %faction ?' WHERE `id`=195;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Besoin daide pour %faction.' WHERE `id`=196;
UPDATE `ai_playerbot_texts` SET `text_loc2`='%faction vend quelque chose dutile ?' WHERE `id`=197;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Il existe des vendeurs %faction ?' WHERE `id`=198;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Qui farme %faction ?' WHERE `id`=199;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Quelle est la meilleure façon de farmer %faction ?' WHERE `id`=200;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je déteste farmer la réputation %faction.' WHERE `id`=201;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Jen ai marre de %faction.' WHERE `id`=202;
UPDATE `ai_playerbot_texts` SET `text_loc2`='On y va pour %faction ?' WHERE `id`=203;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Tout le monde est %rep_level avec %faction. Et moi, je galère encore.' WHERE `id`=204;
UPDATE `ai_playerbot_texts` SET `text_loc2`='LFG pour farm de réputation %faction ?' WHERE `id`=205;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Quelquun a un bon spot pour la réputation %faction ?' WHERE `id`=206;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Améliorer ma réput %faction, ça sert ?' WHERE `id`=207;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Qui aurait cru que la réputation %faction finirait par servir...' WHERE `id`=208;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je veux être exalté avec toutes les factions. En commençant par %faction.' WHERE `id`=209;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Est-ce que ça vaut le coup de monter %faction ?' WHERE `id`=210;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Quest-ce qui marche le mieux pour %faction ? Les quêtes ou tuer des mobs ?' WHERE `id`=211;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je farm %faction pour toi, si tu me paies.' WHERE `id`=212;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Farmer la réputation %faction ? Ça prendra 3 vies au moins.' WHERE `id`=213;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je tue pour %faction tous les jours, mais je suis toujours pas %rep_level.' WHERE `id`=214;
UPDATE `ai_playerbot_texts` SET `text_loc2`='À %my_level, les dépôts à lHV vont baisser, non ?' WHERE `id`=215;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Combien de réputations exaltées tu as ?' WHERE `id`=216;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Qui veut être %my_level avec %faction ?' WHERE `id`=217;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Ma guilde a farmé la réputation %faction hier. Sans moi...' WHERE `id`=218;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Personne ne veut maider, tout ça parce que je suis %rep_level avec %faction.' WHERE `id`=219;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Évitez la %faction.' WHERE `id`=220;
UPDATE `ai_playerbot_texts` SET `text_loc2`='On se fait une soirée à %zone_name ?' WHERE `id`=221;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Quelquun cherche un %my_role ?' WHERE `id`=222;
UPDATE `ai_playerbot_texts` SET `text_loc2`='%my_role cherche une guilde.' WHERE `id`=223;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je cherche de lor.' WHERE `id`=224;
UPDATE `ai_playerbot_texts` SET `text_loc2`='%my_role cherche une bonne guilde.' WHERE `id`=225;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Jai besoin dun ami.' WHERE `id`=226;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Quelquun dautre se sent seul ?' WHERE `id`=227;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je mennuie...' WHERE `id`=228;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Qui en veut ?' WHERE `id`=229;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Allez viens te battre !' WHERE `id`=230;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Un petit duel à %zone_name ?' WHERE `id`=231;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Quelquun fait quelque chose ici ?' WHERE `id`=232;
UPDATE `ai_playerbot_texts` SET `text_loc2`='%zone_name : ya une âme qui vive ici ?' WHERE `id`=233;
UPDATE `ai_playerbot_texts` SET `text_loc2`='%zone_name : tout le monde est en furtif ou quoi ?' WHERE `id`=234;
UPDATE `ai_playerbot_texts` SET `text_loc2`='On dirait que je suis seul à %zone_name.' WHERE `id`=235;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Rejoins-moi à %zone_name .' WHERE `id`=236;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Allez, on fait des quêtes à %zone_name !' WHERE `id`=237;
UPDATE `ai_playerbot_texts` SET `text_loc2`='%zone_name cest LE coin sympa du momment.' WHERE `id`=238;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Jveux aller à %zone_name. Quelquun me suit ?' WHERE `id`=239;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Qui veut aller à %zone_name ?' WHERE `id`=240;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Jaime pas %zone_name. doi-je aller ?' WHERE `id`=241;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Ya de bonnes quêtes à %zone_name ?' WHERE `id`=242;
UPDATE `ai_playerbot_texts` SET `text_loc2`='On va après %zone_name ?' WHERE `id`=243;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Qui traîne à %zone_name ?' WHERE `id`=244;
UPDATE `ai_playerbot_texts` SET `text_loc2`='LFG pour %zone_name.' WHERE `id`=245;
UPDATE `ai_playerbot_texts` SET `text_loc2`='%zone_name est lendroit le plus naze du monde.' WHERE `id`=246;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Attrape-moi à %zone_name si tu peux !' WHERE `id`=247;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Direction %zone_name !' WHERE `id`=248;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Envie de quêtes à %zone_name' WHERE `id`=249;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Quelquun a des quêtes à %zone_name ?' WHERE `id`=250;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Venez à %zone_name !' WHERE `id`=251;
UPDATE `ai_playerbot_texts` SET `text_loc2`='On dirait que la Horde a déserté %zone_name...' WHERE `id`=252;
UPDATE `ai_playerbot_texts` SET `text_loc2`='On dirait que lAlliance a déserté %zone_name...' WHERE `id`=253;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Jen peux plus de %zone_name. Quelquun me sort de ?' WHERE `id`=254;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Bonne chance !' WHERE `id`=255;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je veux rentrer chez moi puis pleurer au bord du vide' WHERE `id`=256;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Quelquun sait ce quil faut pour jouer double arme ?' WHERE `id`=257;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Salut tout le monde !' WHERE `id`=258;
UPDATE `ai_playerbot_texts` SET `text_loc2`='%zone_name est cosy' WHERE `id`=259;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je me sens bien' WHERE `id`=260;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je nignore pas les gens. Je les trolle jusquà ce quils mignorent.' WHERE `id`=261;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Que pensez-vous de mon build ? %my_role' WHERE `id`=262;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Heureux de voir que le chat ne ma pas oublié' WHERE `id`=263;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Comme toutes les armes, cest BiS pour chasseur' WHERE `id`=264;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Le but du jeu pour moi ? Solo tout ce qui bouge.' WHERE `id`=265;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Jai JAMAIS arnaqué personne.' WHERE `id`=266;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Ah, World of Warcraft. je viens chercher des conseils de vie.' WHERE `id`=267;
UPDATE `ai_playerbot_texts` SET `text_loc2`='YA QUELQUUN ?!' WHERE `id`=268;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Il est temps de me frayer un chemin dans %zone_name.' WHERE `id`=269;
UPDATE `ai_playerbot_texts` SET `text_loc2`='%zone_name' WHERE `id`=270;
UPDATE `ai_playerbot_texts` SET `text_loc2`=' faut que jaille aux toilettes.' WHERE `id`=271;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Si tu loot pas tes mobs skinables, ton zizi perd 1mm. Cest la règle.' WHERE `id`=272;
UPDATE `ai_playerbot_texts` SET `text_loc2`='NOOOOOOOOOOOOO' WHERE `id`=273;
UPDATE `ai_playerbot_texts` SET `text_loc2`='JAIME LA PATATE' WHERE `id`=274;
UPDATE `ai_playerbot_texts` SET `text_loc2`='La discussion est animée.' WHERE `id`=275;
UPDATE `ai_playerbot_texts` SET `text_loc2`='salut, comment ça va les gens ?' WHERE `id`=276;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je viens de me déco / reco.' WHERE `id`=277;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Faites moins de bruit, jsuis perdu dans %zone_name' WHERE `id`=278;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Quelquun veut boire un verre à %zone_name ? hic' WHERE `id`=279;
UPDATE `ai_playerbot_texts` SET `text_loc2`='hahahahaheeeee dirin diring inggggg hahahahaheeeeeeeeeeeeee' WHERE `id`=280;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Avant, les appâts étaient crédibles.' WHERE `id`=281;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Peut-être que tas juste perdu ton innocence.' WHERE `id`=282;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Ya une guilde qui veut carry un %my_role fragile ?' WHERE `id`=283;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Plus on monte en niveau, plus lor coule à flots' WHERE `id`=284;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Bonjour !' WHERE `id`=285;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Pourquoi jai mal au cul ?' WHERE `id`=286;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je pense que lesprit est BiS pour monter de niveau.' WHERE `id`=287;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Encore plus si tes troll.' WHERE `id`=288;
UPDATE `ai_playerbot_texts` SET `text_loc2`='QUELQUUN PEUT MINVITER ?' WHERE `id`=289;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Jai besoin de beaucouuuup de boissons.' WHERE `id`=290;
UPDATE `ai_playerbot_texts` SET `text_loc2`='P*utain de gnomes' WHERE `id`=291;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Personne naime les gnomes.' WHERE `id`=292;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Les gnomes ne servent quà une chose' WHERE `id`=293;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Bah' WHERE `id`=294;
UPDATE `ai_playerbot_texts` SET `text_loc2`=' des champignons.' WHERE `id`=295;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Les pensées automatiques, cest flippant.' WHERE `id`=296;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Lesprit est plus malléable quon aimerait le croire.' WHERE `id`=297;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Ya des guildes pour leveling ?' WHERE `id`=298;
UPDATE `ai_playerbot_texts` SET `text_loc2`='brb' WHERE `id`=299;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Pourquoi la neige est-elle blanche alors que la glace est transparente, alors quelles sont faites de la même chose ?' WHERE `id`=300;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Pourquoi la crème fouettée est fluffy, mais pas la normale ?' WHERE `id`=301;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Pourquoi les pieds sentent alors quils nont pas de nez ?' WHERE `id`=302;
UPDATE `ai_playerbot_texts` SET `text_loc2`='On dirait que la boîte à noobs vient de souvrir.' WHERE `id`=303;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Arrêtez de troller les nouveaux avec vos réponses à la con.' WHERE `id`=304;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Ya du PvP sur ce serveur ?' WHERE `id`=305;
UPDATE `ai_playerbot_texts` SET `text_loc2`='évidemment...' WHERE `id`=306;
UPDATE `ai_playerbot_texts` SET `text_loc2`='ouf :)' WHERE `id`=307;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Vous saviez que' WHERE `id`=308;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je ne tente pas dimaginer ce que ressentent les autres créatures' WHERE `id`=309;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Oups, mauvais canal.' WHERE `id`=310;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Bruh, vous êtes déchaînés aujourdhui' WHERE `id`=311;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Juste pour que tout le monde sache : mon message est passé ici' WHERE `id`=312;
UPDATE `ai_playerbot_texts` SET `text_loc2`='grrr énervéééééé' WHERE `id`=313;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Le farm, cest marrant' WHERE `id`=314;
UPDATE `ai_playerbot_texts` SET `text_loc2`='WoW me garde vif' WHERE `id`=315;
UPDATE `ai_playerbot_texts` SET `text_loc2`=', question : on prend le rôle pour plus dXP ? Je suis à %zone_name.' WHERE `id`=316;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Vous aimez les saucisses ?' WHERE `id`=317;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Invitez-moi. Je peux aider.' WHERE `id`=318;
UPDATE `ai_playerbot_texts` SET `text_loc2`='À votre avis, quelle classe est la meilleure en PvP ?' WHERE `id`=319;
UPDATE `ai_playerbot_texts` SET `text_loc2`=' est ce foutu maître de cuisine à %zone_name ?!' WHERE `id`=320;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Vous savez ce quil se passe à %zone_name ?' WHERE `id`=321;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Jai besoin de crafter quelque chose' WHERE `id`=322;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Cest quoi lèchemes' WHERE `id`=323;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Cest quoi sucemes ' WHERE `id`=324;
UPDATE `ai_playerbot_texts` SET `text_loc2`='lèchemes couilles' WHERE `id`=325;
UPDATE `ai_playerbot_texts` SET `text_loc2`='sucemes couilles' WHERE `id`=326;
UPDATE `ai_playerbot_texts` SET `text_loc2`='JE MANGE DES FESSES' WHERE `id`=327;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Jai envie de me fourrer %random_inventory_item_link le soleil ne brille pas' WHERE `id`=328;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Jai envie de te fourrer %random_inventory_item_link tu penses' WHERE `id`=329;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Darnasses' WHERE `id`=330;
UPDATE `ai_playerbot_texts` SET `text_loc2`='On dirait que tas chopé le syndrôme de sucemes' WHERE `id`=331;
UPDATE `ai_playerbot_texts` SET `text_loc2`='cesnoix dans ta bouche' WHERE `id`=332;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Sympa ton os, frérot' WHERE `id`=333;
UPDATE `ai_playerbot_texts` SET `text_loc2`='ERP ?' WHERE `id`=334;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Jai tout essayé, mais au final cest lERP qui a marché' WHERE `id`=335;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Jai envie de batifoler à %zone_name' WHERE `id`=336;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Recherche gnome femelle avec gorille pour ERP sauvage à %zone_name' WHERE `id`=337;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je peux comprendre un idiot, mais un gros pervers ?' WHERE `id`=338;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Aucun GYAT en vue à %zone_name' WHERE `id`=339;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je tue tous les animaux de %zone_name. Désolé WWF !' WHERE `id`=340;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Heureusement que jai trois jambes' WHERE `id`=341;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Sois pas vénère, je goon comme un sigma' WHERE `id`=342;
UPDATE `ai_playerbot_texts` SET `text_loc2`='essaye doigt, mais trou' WHERE `id`=343;
UPDATE `ai_playerbot_texts` SET `text_loc2`='%prefix %random_taken_quest_or_item_link' WHERE `id`=344;
UPDATE `ai_playerbot_texts` SET `text_loc2`='%prefix %random_inventory_item_link' WHERE `id`=345;
UPDATE `ai_playerbot_texts` SET `text_loc2`='%thunderfury_link' WHERE `id`=346;
UPDATE `ai_playerbot_texts` SET `text_loc2`='%thunderfury_link%thunderfury_link' WHERE `id`=347;
UPDATE `ai_playerbot_texts` SET `text_loc2`='%thunderfury_link%thunderfury_link%thunderfury_link' WHERE `id`=348;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je crois que je viens dentendre %thunderfury_link' WHERE `id`=349;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Jai entendu %thunderfury_link' WHERE `id`=350;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Jai clairement entendu %thunderfury_link' WHERE `id`=351;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Jsuis pas sûr, mais jcrois avoir entendu %thunderfury_link' WHERE `id`=352;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Tas dit %thunderfury_link' WHERE `id`=353;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Quelquun a dit %thunderfury_link' WHERE `id`=354;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Quelquun a VRAIMENT dit %thunderfury_link' WHERE `id`=355;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Quelquun a parlé de %thunderfury_link' WHERE `id`=356;
UPDATE `ai_playerbot_texts` SET `text_loc2`='%thunderfury_link sort du placard, les gars' WHERE `id`=357;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Jaurais juré que cétait un %thunderfury_link ou peut-être un %thunderfury_link' WHERE `id`=358;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Pourquoi utiliser %thunderfury_link alors que %thunderfury_link est bien plus OP' WHERE `id`=359;
UPDATE `ai_playerbot_texts` SET `text_loc2`='WTS %item_formatted_link pour %cost_gold.' WHERE `id`=360;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Qui veut %item_formatted_link pour %cost_gold ?' WHERE `id`=361;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Quelquun veut %item_formatted_link ? Seulement %cost_gold' WHERE `id`=362;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Juste %cost_gold pour %item_formatted_link!' WHERE `id`=363;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je vends %item_formatted_link pour %cost_gold' WHERE `id`=364;
UPDATE `ai_playerbot_texts` SET `text_loc2`='%item_formatted_link est à toi pour seulement %cost_gold !' WHERE `id`=365;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Prix ridicule : %cost_gold pour %item_formatted_link !' WHERE `id`=366;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je cherche à vendre %item_formatted_link pour %cost_gold' WHERE `id`=367;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Qui a besoin de %item_formatted_link ? Seulement %cost_gold' WHERE `id`=368;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Quelquun veut %item_formatted_link pour %cost_gold ?' WHERE `id`=369;
UPDATE `ai_playerbot_texts` SET `text_loc2`='%cost_gold pour %item_formatted_link. Moins cher quà lHV !' WHERE `id`=370;
UPDATE `ai_playerbot_texts` SET `text_loc2`='%item_formatted_link est cher, mais je te le fais à %cost_gold' WHERE `id`=371;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Tu trouveras jamais %item_formatted_link moins cher que %cost_gold!' WHERE `id`=372;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Jai besoin de plus que %item_formatted_link, !' WHERE `id`=373;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Jai %item_formatted_link et jen veux encore' WHERE `id`=374;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Jai %item_formatted_link. Qui lachète pour %cost_gold ?' WHERE `id`=375;
UPDATE `ai_playerbot_texts` SET `text_loc2`='WTB %item_formatted_link pour %cost_gold, quelquun ?' WHERE `id`=376;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Et %item_formatted_link ? Pour %cost_gold.' WHERE `id`=377;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Qui ma traité d\'arnaqueur ? %item_formatted_link pour %cost_gold cest honnête !' WHERE `id`=378;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je vends %item_formatted_link. Juste %cost_gold' WHERE `id`=379;
UPDATE `ai_playerbot_texts` SET `text_loc2`='LFG pour du farm, et au passage %item_formatted_link à vendre %cost_gold' WHERE `id`=380;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Presque tout vendu aujourdhui. Me reste %item_formatted_link pour %cost_gold' WHERE `id`=381;
UPDATE `ai_playerbot_texts` SET `text_loc2`='À quoi sert le canal commerce ? A vendre %item_formatted_link pour %cost_gold, évidemment' WHERE `id`=382;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Quelquun peut battre %cost_gold pour %item_formatted_link ?' WHERE `id`=383;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Envie darrêter le spam commerce ? Achetez %item_formatted_link à %cost_gold !' WHERE `id`=384;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Tout le monde spam, moi aussi : %cost_gold pour %item_formatted_link !' WHERE `id`=385;
UPDATE `ai_playerbot_texts` SET `text_loc2`='%item_formatted_link est utile ? Je sais pas, mais je le vends %cost_gold' WHERE `id`=386;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Jai %item_formatted_link prêt à vendre %cost_gold' WHERE `id`=387;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Hier jai rien foutu, mais jai loot %item_formatted_link. À vendre %cost_gold' WHERE `id`=388;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Jai farmé hier, jai eu %item_formatted_link. WTB ? %cost_gold' WHERE `id`=389;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Jai acheté %item_formatted_link hier. Quelquun le veut ? %cost_gold' WHERE `id`=390;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Quelquun cherchait %item_formatted_link ? Cest %cost_gold toujours' WHERE `id`=391;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Jai encore %item_formatted_link. Achetez-le %cost_gold' WHERE `id`=392;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Avant jen avais plein %item_formatted_link, maintenant je dois vendre à %cost_gold' WHERE `id`=393;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Jaimerais en avoir plus que %item_formatted_link. Mais achetez celui-là %cost_gold' WHERE `id`=394;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Ton or te sert à quoi ? À acheter %item_formatted_link pour %cost_gold' WHERE `id`=395;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Ayez pitié, donnez-moi de lor... ou achetez %item_formatted_link %cost_gold' WHERE `id`=396;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Est-ce que %cost_gold est un bon prix pour %item_formatted_link ?' WHERE `id`=397;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Jai acheté %item_formatted_links hier, mais jen veux plus. Quelqu\'un vends pour %cost_gold' WHERE `id`=398;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je vais le mettre à lHV %item_formatted_link, mais tu peux lavoir moins cher : %cost_gold' WHERE `id`=399;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Pourquoi jai acheté %item_formatted_link bordel ? Quelquun le veut ? %cost_gold' WHERE `id`=400;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Jai %quest_links' WHERE `id`=401;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Moi aussi jai %quest_links' WHERE `id`=402;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Moi aussi jai %quest_links, je suis à %zone_name' WHERE `id`=403;
UPDATE `ai_playerbot_texts` SET `text_loc2`='%other_name, moi aussi jai %quest_links' WHERE `id`=404;
UPDATE `ai_playerbot_texts` SET `text_loc2`='%other_name, moi aussi jai %quest_links, et je suis à %zone_name' WHERE `id`=405;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je suis dispo pour %quest_links, je suis à %zone_name' WHERE `id`=406;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je suis dispo pour %quest_links, je suis %my_role' WHERE `id`=407;
UPDATE `ai_playerbot_texts` SET `text_loc2`='%other_name, je suis dispo pour %quest_links à %zone_name' WHERE `id`=408;
UPDATE `ai_playerbot_texts` SET `text_loc2`='%other_name, je suis dispo pour %quest_links, je suis %my_role' WHERE `id`=409;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Hey, je suis partant pour %quest_links' WHERE `id`=410;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Hey, je pourrais faire %quest_links avec toi' WHERE `id`=411;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Hey, moi aussi jai %quest_links' WHERE `id`=412;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Hey %other_name, partant pour %quest_links' WHERE `id`=413;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Hey %other_name, je peux faire %quest_links avec toi' WHERE `id`=414;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Hey %other_name, moi aussi jai %quest_links' WHERE `id`=415;
UPDATE `ai_playerbot_texts` SET `text_loc2`='On se groupe pour %quest_links ?' WHERE `id`=416;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je suis partant pour %quest_links, je suis à %zone_name' WHERE `id`=417;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je suis dispo pour %quest_links, je suis %my_role' WHERE `id`=418;
UPDATE `ai_playerbot_texts` SET `text_loc2`='%other_name, je peux te vendre %formatted_item_links' WHERE `id`=419;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je peux peut-être vendre %formatted_item_links' WHERE `id`=420;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je pense pouvoir vendre %formatted_item_links' WHERE `id`=421;
UPDATE `ai_playerbot_texts` SET `text_loc2`='%other_name, je peux peut-être te vendre %formatted_item_links' WHERE `id`=422;
UPDATE `ai_playerbot_texts` SET `text_loc2`='%other_name, tu penses que je peux vendre %formatted_item_links ?' WHERE `id`=423;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je peux te vendre %formatted_item_links' WHERE `id`=424;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Hey, jai %formatted_item_links à vendre' WHERE `id`=425;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Hey, je pourrais peut-être vendre %formatted_item_links' WHERE `id`=426;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Quête acceptée' WHERE `id`=427;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Quête abandonnée' WHERE `id`=428;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je ne peux pas prendre cette quête' WHERE `id`=429;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je ne peux pas parler au donneur de quête' WHERE `id`=430;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Jai déjà terminé %quest' WHERE `id`=431;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Jai déjà la quête %quest' WHERE `id`=432;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je ne peux pas prendre %quest' WHERE `id`=433;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je ne peux pas prendre %quest, mon journal de quêtes est plein' WHERE `id`=434;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je ne peux pas prendre %quest, mes sacs sont pleins' WHERE `id`=435;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Jai accepté la quête %quest' WHERE `id`=436;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je nai pas encore terminé la quête %quest' WHERE `id`=437;
UPDATE `ai_playerbot_texts` SET `text_loc2`='La quête %quest est dispo' WHERE `id`=438;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Jai échoué à la quête %quest' WHERE `id`=439;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je ne peux pas rendre la quête %quest' WHERE `id`=440;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Jai terminé la quête %quest' WHERE `id`=441;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Jai terminé la quête %quest et reçu %item' WHERE `id`=442;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Quelle récompense devrais-je choisir pour la quête %quest ? %rewards' WHERE `id`=443;
UPDATE `ai_playerbot_texts` SET `text_loc2`='OK, je vais prendre %item comme récompense' WHERE `id`=444;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Bonjour' WHERE `id`=445;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Bonjour !' WHERE `id`=446;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Salut' WHERE `id`=447;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Salut !' WHERE `id`=448;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Salut à toi !' WHERE `id`=449;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Bonjour, je vous suis !' WHERE `id`=450;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Bonjour, montrez-moi le chemin !' WHERE `id`=451;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Salut, montre-moi le chemin !' WHERE `id`=452;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Hey %player, tu veux rejoindre mon groupe ?' WHERE `id`=453;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Hey %player, tu veux rejoindre mon groupe ?' WHERE `id`=454;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Déconnexion annulée !' WHERE `id`=455;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je me déconnecte !' WHERE `id`=456;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Au revoir !' WHERE `id`=457;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Bye bye !' WHERE `id`=458;
UPDATE `ai_playerbot_texts` SET `text_loc2`='À plus tard !' WHERE `id`=459;
UPDATE `ai_playerbot_texts` SET `text_loc2`='cétait quoi ce truc %s ?' WHERE `id`=460;
UPDATE `ai_playerbot_texts` SET `text_loc2`='pas sûr davoir compris %s ?' WHERE `id`=461;
UPDATE `ai_playerbot_texts` SET `text_loc2`='euh jai aucune idée de ce que tu racontes' WHERE `id`=462;
UPDATE `ai_playerbot_texts` SET `text_loc2`='tu parles à moi, %s ?' WHERE `id`=463;
UPDATE `ai_playerbot_texts` SET `text_loc2`='whaaaa ?' WHERE `id`=464;
UPDATE `ai_playerbot_texts` SET `text_loc2`='hein ?' WHERE `id`=465;
UPDATE `ai_playerbot_texts` SET `text_loc2`='quoi ?' WHERE `id`=466;
UPDATE `ai_playerbot_texts` SET `text_loc2`='tu parles ou tu râles ?' WHERE `id`=467;
UPDATE `ai_playerbot_texts` SET `text_loc2`='comme tu veux, mec' WHERE `id`=468;
UPDATE `ai_playerbot_texts` SET `text_loc2`='tu mas perdu ' WHERE `id`=469;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Bla bla bla' WHERE `id`=470;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Tas dit quoi, %s ?' WHERE `id`=471;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Concentre-toi sur le jeu, %s !' WHERE `id`=472;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Parler avec toi %s, cest génial ! Jai toujours rêvé de te rencontrer' WHERE `id`=473;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Ces messages me font flipper ! Jai limpression de tous vous connaître !' WHERE `id`=474;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Ouais bien sûr ! HAHA ! Cest ça, allez !' WHERE `id`=475;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je te crois !!!' WHERE `id`=476;
UPDATE `ai_playerbot_texts` SET `text_loc2`='OK, uhuh LOL' WHERE `id`=477;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Pourquoi tout le monde dit toujours les mêmes trucs ???' WHERE `id`=478;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Hey %s euh, laisse tomber !' WHERE `id`=479;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Tu parles de quoi %s ? Sérieux ?' WHERE `id`=480;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Qui a dit ça ? Je me sens visé ' WHERE `id`=481;
UPDATE `ai_playerbot_texts` SET `text_loc2`='wtf vous racontez tous ?' WHERE `id`=482;
UPDATE `ai_playerbot_texts` SET `text_loc2`='fr fr no cap on a stack' WHERE `id`=483;
UPDATE `ai_playerbot_texts` SET `text_loc2`='tauras que dalle' WHERE `id`=484;
UPDATE `ai_playerbot_texts` SET `text_loc2`='swag' WHERE `id`=485;
UPDATE `ai_playerbot_texts` SET `text_loc2`='merci !' WHERE `id`=486;
UPDATE `ai_playerbot_texts` SET `text_loc2`='non' WHERE `id`=487;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Yep' WHERE `id`=488;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Paix à son ame.' WHERE `id`=489;
UPDATE `ai_playerbot_texts` SET `text_loc2`='%s sans déconner xD' WHERE `id`=490;
UPDATE `ai_playerbot_texts` SET `text_loc2`='pourquoi ça ?' WHERE `id`=491;
UPDATE `ai_playerbot_texts` SET `text_loc2`='mdr' WHERE `id`=492;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je pensais fermer ma gueule, jai encore rien compris au chat' WHERE `id`=493;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je peux devenir vraiment jaloux... comme un elfe sans loot' WHERE `id`=494;
UPDATE `ai_playerbot_texts` SET `text_loc2`='%s tu captes pas le sarcasme qui dégouline de mon message ?' WHERE `id`=495;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Il a dit "no homo", donc cest bon apparemment' WHERE `id`=496;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Instant nain' WHERE `id`=497;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Oui %s' WHERE `id`=498;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Intéressant' WHERE `id`=499;
UPDATE `ai_playerbot_texts` SET `text_loc2`='lol' WHERE `id`=500;
UPDATE `ai_playerbot_texts` SET `text_loc2`='%s va te faire voir mec :D' WHERE `id`=501;
UPDATE `ai_playerbot_texts` SET `text_loc2`=':^)' WHERE `id`=502;
UPDATE `ai_playerbot_texts` SET `text_loc2`='merci' WHERE `id`=503;
UPDATE `ai_playerbot_texts` SET `text_loc2`='%s bien dit !' WHERE `id`=504;
UPDATE `ai_playerbot_texts` SET `text_loc2`='ouiiiii' WHERE `id`=505;
UPDATE `ai_playerbot_texts` SET `text_loc2`='ouais' WHERE `id`=506;
UPDATE `ai_playerbot_texts` SET `text_loc2`='ooooooh' WHERE `id`=507;
UPDATE `ai_playerbot_texts` SET `text_loc2`='hmm' WHERE `id`=508;
UPDATE `ai_playerbot_texts` SET `text_loc2`='ouais cest ça' WHERE `id`=509;
UPDATE `ai_playerbot_texts` SET `text_loc2`='tas failli me faire vomir, wtf' WHERE `id`=510;
UPDATE `ai_playerbot_texts` SET `text_loc2`='chaud !' WHERE `id`=511;
UPDATE `ai_playerbot_texts` SET `text_loc2`='les rageux pleurent' WHERE `id`=512;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Tas mangé quoi %s ?' WHERE `id`=513;
UPDATE `ai_playerbot_texts` SET `text_loc2`='wtf' WHERE `id`=514;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je vais essayer de comprendre ce que tas dit' WHERE `id`=515;
UPDATE `ai_playerbot_texts` SET `text_loc2`='*confus*' WHERE `id`=516;
UPDATE `ai_playerbot_texts` SET `text_loc2`='putain ouais' WHERE `id`=517;
UPDATE `ai_playerbot_texts` SET `text_loc2`='0/10 ne lirait pas ça une deuxième fois' WHERE `id`=518;
UPDATE `ai_playerbot_texts` SET `text_loc2`='10/10 je relis direct' WHERE `id`=519;
UPDATE `ai_playerbot_texts` SET `text_loc2`='6/10 ouais, pourquoi pas' WHERE `id`=520;
UPDATE `ai_playerbot_texts` SET `text_loc2`='7/10 ça passe' WHERE `id`=521;
UPDATE `ai_playerbot_texts` SET `text_loc2`='basé' WHERE `id`=522;
UPDATE `ai_playerbot_texts` SET `text_loc2`='ah ouais peut-être' WHERE `id`=523;
UPDATE `ai_playerbot_texts` SET `text_loc2`='ouais, et alors ?' WHERE `id`=524;
UPDATE `ai_playerbot_texts` SET `text_loc2`='hey %s je tai pas oublié' WHERE `id`=525;
UPDATE `ai_playerbot_texts` SET `text_loc2`='tu ménerves %s' WHERE `id`=526;
UPDATE `ai_playerbot_texts` SET `text_loc2`='je vais tavoir cette fois %s' WHERE `id`=527;
UPDATE `ai_playerbot_texts` SET `text_loc2`='garde un œil derrière toi %s' WHERE `id`=528;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Jai pas trop aimé la manche davant' WHERE `id`=529;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Jai é nul au dernier round à cause de %s' WHERE `id`=530;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Prépare-toi à mourir %s' WHERE `id`=531;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Jai pas trop kiffé que tu me tues %s' WHERE `id`=532;
UPDATE `ai_playerbot_texts` SET `text_loc2`='%s, je te hais' WHERE `id`=533;
UPDATE `ai_playerbot_texts` SET `text_loc2`='grrrrr je vais tavoir cette fois %s' WHERE `id`=534;
UPDATE `ai_playerbot_texts` SET `text_loc2`='eh bien va te faire foutre' WHERE `id`=535;
UPDATE `ai_playerbot_texts` SET `text_loc2`='%s je vais vomir dans ta putain de bouche' WHERE `id`=536;
UPDATE `ai_playerbot_texts` SET `text_loc2`='me juge pas bordel' WHERE `id`=537;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Ta mère est tellement grosse quelle passe même pas le Portail des Ténèbres' WHERE `id`=538;
UPDATE `ai_playerbot_texts` SET `text_loc2`='wtf' WHERE `id`=539;
UPDATE `ai_playerbot_texts` SET `text_loc2`='wtf ??' WHERE `id`=540;
UPDATE `ai_playerbot_texts` SET `text_loc2`='vie misérable' WHERE `id`=541;
UPDATE `ai_playerbot_texts` SET `text_loc2`='quest-ce qui se passe ?' WHERE `id`=542;
UPDATE `ai_playerbot_texts` SET `text_loc2`='nul à chier' WHERE `id`=543;
UPDATE `ai_playerbot_texts` SET `text_loc2`='REVANCHE !!! Je vais léclater' WHERE `id`=544;
UPDATE `ai_playerbot_texts` SET `text_loc2`='pathétique, je me suis fait tuer par %s' WHERE `id`=545;
UPDATE `ai_playerbot_texts` SET `text_loc2`='ok jen ai fini' WHERE `id`=546;
UPDATE `ai_playerbot_texts` SET `text_loc2`=' , jai explosé %s ?' WHERE `id`=547;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Cétait trop facile, d\'exploser %s' WHERE `id`=548;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Tes grillé, clochard' WHERE `id`=549;
UPDATE `ai_playerbot_texts` SET `text_loc2`='ha ha' WHERE `id`=550;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Loser' WHERE `id`=551;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Jai tué %s et vous êtes tous les prochains, les gars' WHERE `id`=552;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Oh ouais, je lai éclaté' WHERE `id`=553;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je suis une machine à tuer' WHERE `id`=554;
UPDATE `ai_playerbot_texts` SET `text_loc2`='%s, ça me rappelle un morceau de Slayer… tout ce sang, cest beau' WHERE `id`=555;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Désolé %s. On peut refaire la scène ?' WHERE `id`=556;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Alors %s… ça fait quoi de nourrir les vers ???' WHERE `id`=557;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Tétais censé être mort %s ! Cest dans le script bon sang !' WHERE `id`=558;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Désolé %s. Franchement, cétait aussi beau quun Warhol !' WHERE `id`=559;
UPDATE `ai_playerbot_texts` SET `text_loc2`='%s, je prendrai les balles en caoutchouc la prochaine fois, promis !' WHERE `id`=560;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Quest-ce quil y a %s ?? Tas perdu la tête ? Hahaha, faut rester cool !' WHERE `id`=561;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Fallait que je le fasse %s… Le Réalisateur me la dit !' WHERE `id`=562;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Hey %s… MUAHAHAHAHAHAHAHAHAHAHA' WHERE `id`=563;
UPDATE `ai_playerbot_texts` SET `text_loc2`='%s, celle-là, je lai savourée !! Allez, on recommence Sam !' WHERE `id`=564;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Hey %s ! Tu peux commencer à mappeler Scarface… espèce de M…erde !' WHERE `id`=565;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Tu me parles à moi %s ?? Tu me parles à MOI ?!' WHERE `id`=566;
UPDATE `ai_playerbot_texts` SET `text_loc2`='%s, fais-le bien cette fois, évite MES balles.' WHERE `id`=567;
UPDATE `ai_playerbot_texts` SET `text_loc2`='%s, pourquoi tu traînes par terre ? Allez bouge !' WHERE `id`=568;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Jai rigolé comme jamais' WHERE `id`=569;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Salut %s' WHERE `id`=570;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Oh, salut %s' WHERE `id`=571;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Wazzup %s !!!' WHERE `id`=572;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Salut' WHERE `id`=573;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Wazzup' WHERE `id`=574;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Bonjour %s' WHERE `id`=575;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Salut %s, je te connais ?' WHERE `id`=576;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Hey %s' WHERE `id`=577;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Hai %s' WHERE `id`=578;
UPDATE `ai_playerbot_texts` SET `text_loc2`='cest quoi ce délire' WHERE `id`=579;
UPDATE `ai_playerbot_texts` SET `text_loc2`='wtf' WHERE `id`=580;
UPDATE `ai_playerbot_texts` SET `text_loc2`='cest du foutage de gueule' WHERE `id`=581;
UPDATE `ai_playerbot_texts` SET `text_loc2`='admin' WHERE `id`=582;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Hey %s, arrête dabuser de ton admin là' WHERE `id`=583;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Lâche-moi admin !' WHERE `id`=584;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Tes nul admin' WHERE `id`=585;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Cest mon nom ça, tu veux quoi %s ?' WHERE `id`=586;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Oui ???' WHERE `id`=587;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Euh… quoi ?' WHERE `id`=588;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Tu me parles à moi %s ?' WHERE `id`=589;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Jai des chiots sous mon armure !' WHERE `id`=590;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Mords-moi, <target> !' WHERE `id`=591;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Hey <target> ! Devine ce que ta mère a dit hier soir !' WHERE `id`=592;
UPDATE `ai_playerbot_texts` SET `text_loc2`='<target>, tes tellement moche que tu pourrais même pas scorer dans un bordel de singes avec un sac de bananes !' WHERE `id`=593;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Tais-toi <target>, tu seras jamais lhomme que ta mère est !!' WHERE `id`=594;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Ta mère était un hamster et ton père sentait la surette !' WHERE `id`=595;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je ne veux plus te parler, espèce de vide-écuelle à bestiaux débiles !!!' WHERE `id`=596;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je pète dans ta direction générale !!!' WHERE `id`=597;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Va faire bouillir ton postérieur, fils dun imbécile cosmique !!!' WHERE `id`=598;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Tu comptes faire quoi <target>, saigner sur moi ? ALLEZ, VIENS !' WHERE `id`=599;
UPDATE `ai_playerbot_texts` SET `text_loc2`='M-O-O-N ! Ça veut dire aggro !' WHERE `id`=600;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Tes aussi utile quun unijambiste dans un concours de coups de pied au cul' WHERE `id`=601;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Hey <target> ! Arrête de draguer, cest pas ton genre. Cest pas gonflable.' WHERE `id`=602;
UPDATE `ai_playerbot_texts` SET `text_loc2`='<target>, tes tellement hors catégorie que tu joues carrément à un autre sport' WHERE `id`=603;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Tu as fait une grosse erreur aujourdhui <target>… tes sorti du lit.' WHERE `id`=604;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je veux essayer de me transformer en cheval. Je prends lavant, et toi… tu restes toi.' WHERE `id`=605;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je peux emprunter ton visage ? Mon cul part en vacances.' WHERE `id`=606;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Jaimerais toffrir un cadeau de départ… dabord, fais ta part.' WHERE `id`=607;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Avant que tarrives, on avait faim. Maintenant on en a juste marre.' WHERE `id`=608;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je taime bien. Les gens disent que jai mauvais goût, mais je taime bien.' WHERE `id`=609;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je pense que tas un complexe dinfériorité… mais tinquiète, il est mérité.' WHERE `id`=610;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Arrière, créature pourrie ! Ou je secoue tes os hors de ta tunique !' WHERE `id`=611;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je crois pas que je perds mon temps avec toi… et pourtant !' WHERE `id`=612;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Jadore quand on minsulte : jai plus besoin dêtre poli.' WHERE `id`=613;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Espèce de veston de cuir, boutons en cristal, tête nouée, braillard à gerbe, jarretière de puce, langue mielleuse, bourse espagnole !' WHERE `id`=614;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Espèce de pleurnichard, chasseur de chauve-souris, ivrogne de malte !' WHERE `id`=615;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Tes vraiment une idole pour les adorateurs de lidiotie !' WHERE `id`=616;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Misérable piaf mal dégrossi !' WHERE `id`=617;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Fils de mandragore ! Tes plus utile en plumeau quen laquais !' WHERE `id`=618;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Toi ! Gueux ! Cloporte ! Tarlouze ! Je vais chatouiller ta catastrophe !' WHERE `id`=619;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Oh <target> ! Infâme fille de lin mal élevé !' WHERE `id`=620;
UPDATE `ai_playerbot_texts` SET `text_loc2`='On fuit par ta cheminée, <target> !' WHERE `id`=621;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Oh toi, misérable fleur de cancre gorgée de marais !' WHERE `id`=622;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Si jétais comme toi, je me jetterais à la poubelle.' WHERE `id`=623;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Apprends-moi <target>… à ne plus penser du tout.' WHERE `id`=624;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Tes maudit comme un œuf mal rôti… tout cramé dun côté.' WHERE `id`=625;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Espèce de gringalet, de peau de hareng, de langue de bœuf séchée, de… souffle… taureau démembré, morceau de corde ! Queue dépée, boîte à rien, tige de tailleur !' WHERE `id`=626;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Fi ! Quon te jette dans la bouche pourrie de la Mort !' WHERE `id`=627;
UPDATE `ai_playerbot_texts` SET `text_loc2`='<target>, tes poissonnier, avoue !' WHERE `id`=628;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je vivrai assez pour te défoncer le crâne !' WHERE `id`=629;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Tes aussi profond quune flaque ! <target>, tes bonne pour les vers, pas pour la viande !' WHERE `id`=630;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Vermine ! Ô <target>, espèce de noisette infernale puante !' WHERE `id`=631;
UPDATE `ai_playerbot_texts` SET `text_loc2`='<target> ! Ton baiser est aussi réconfortant quun glaçon pour un serpent affamé !' WHERE `id`=632;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je te méprise, compagnon galeux. Quoi, pauvre arnaqueur sans chemise ! Dégage, raclure moisie !' WHERE `id`=633;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Hors de ma vue ! Tu infectes mes yeux <target> !' WHERE `id`=634;
UPDATE `ai_playerbot_texts` SET `text_loc2`='HEURE DE JEU !!!!' WHERE `id`=635;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Personne ne passera !' WHERE `id`=636;
UPDATE `ai_playerbot_texts` SET `text_loc2`='On est attaqués ! Hissez les voiles ! Repoussez les intrus !' WHERE `id`=637;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Personne ne défie la Confrérie !' WHERE `id`=638;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Imbéciles… tuez celui en robe !' WHERE `id`=639;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je vais offrir ton âme à Hakkar lui-même !' WHERE `id`=640;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Lorgueil annonce la fin de ton monde ! Venez, mortels ! Affrontez la colère de la %randomfaction !' WHERE `id`=641;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Tous mes plans menaient à CE moment !' WHERE `id`=642;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Ahh ! Encore des agneaux pour labattoir !' WHERE `id`=643;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Encore une journée, encore une glorieuse bataille !' WHERE `id`=644;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Alors, affaires… ou plaisir ?' WHERE `id`=645;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Vous nêtes pas préparés !' WHERE `id`=646;
UPDATE `ai_playerbot_texts` SET `text_loc2`='La conquête finale de la %randomfaction a commencé ! Cette fois, aucun ne survivra !' WHERE `id`=647;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Ta mort sera douloureuse.' WHERE `id`=648;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Implore pitié ! Tes vies inutiles vont être sacrifiées.' WHERE `id`=649;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Abandonne tout espoir ! La %randomfaction est revenue pour finir ce qui a commencé… et cette fois, pas déchappatoire !' WHERE `id`=650;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Alerte ! Tu es marqué pour lEXTERMINATION !' WHERE `id`=651;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Le %subzone est réservé aux invités seulement…' WHERE `id`=652;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Ha ha ha ! Tu es totalement dépassé !' WHERE `id`=653;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je vais écraser tes illusions de grandeur !' WHERE `id`=654;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Pardonne-moi, mais tu vas perdre cette partie.' WHERE `id`=655;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Résister ne fait quempirer les choses.' WHERE `id`=656;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Vermine ! Sangsues ! Prends mon sang et étouffe-toi avec !' WHERE `id`=657;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Pas encore… PAS ENCORE !' WHERE `id`=658;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Mon sang sera ta perte !' WHERE `id`=659;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Parfait. Maintenant bats-toi contre moi !' WHERE `id`=660;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Allez les gardes ! Cest lheure de tuer !' WHERE `id`=661;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Nattends pas la mort, viens à moi. Je rendrai ton sacrifice rapide.' WHERE `id`=662;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Tu seras mort très bientôt !' WHERE `id`=663;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Mouahaha !' WHERE `id`=664;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Cest moi le prédateur ! Toi, la proie...' WHERE `id`=665;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Tu vas repartir en morceaux !' WHERE `id`=666;
UPDATE `ai_playerbot_texts` SET `text_loc2`='La mort approche... As-tu la conscience tranquille ?' WHERE `id`=667;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Ton comportement ne sera pas toléré.' WHERE `id`=668;
UPDATE `ai_playerbot_texts` SET `text_loc2`='La Ménagerie est réservée aux invités.' WHERE `id`=669;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Hmm, des visiteurs non annoncés… Il faut se préparer…' WHERE `id`=670;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Entités hostiles détectées. Évaluation de menace en cours. Cible principale verrouillée. Réévaluation dans trente secondes.' WHERE `id`=671;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Des nouveaux jouets ? Pour moi ? Promis, je les casse pas… cette fois !' WHERE `id`=672;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je suis prêt à jouer !' WHERE `id`=673;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Chut… tout sera fini bientôt.' WHERE `id`=674;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Aaaaaughibbrgubugbugrguburgle !' WHERE `id`=675;
UPDATE `ai_playerbot_texts` SET `text_loc2`='RwlRwlRwlRwl !' WHERE `id`=676;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Toi aussi, tu serviras !' WHERE `id`=677;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Dis-moi... dis-moi tout ! Tes vilains petits secrets ! Je vais les arracher de ta chair !' WHERE `id`=678;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Préparez-vous, les cloches ont sonné ! Protégez vos faibles, vos jeunes et vos vieux ! Chacun paiera le prix final ! Implorerez-vous pitié ? Le Jugement est arrivé !' WHERE `id`=679;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Mais où suis-je, par les boutons en laiton de Bonzo ?' WHERE `id`=680;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je nen peux plus ! Roi Gobelin ! Roi Gobelin ! Où que tu sois ! Emporte ce <target> loin de moi !' WHERE `id`=681;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Tu as treize heures pour résoudre le labyrinthe... sinon ton petit frère deviendra lun des nôtres... pour toujours.' WHERE `id`=682;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Alors, le <subzone> cest du gâteau, hein ? Voyons comment tu gères ce petit bout-là…' WHERE `id`=683;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Recule, jvais taffronter. Déterminé, prêt à affronter nimporte qui. Jsais que tas tort, tas rien à faire ici !' WHERE `id`=684;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Montre-moi cque tas dans le ventre !' WHERE `id`=685;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Jusquà la mort !' WHERE `id`=686;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Double lame, pour un rasage net à chaque fois !' WHERE `id`=687;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Allez, viens !' WHERE `id`=688;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Tu vas tomber !' WHERE `id`=689;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Piou piou, coup de couteau !' WHERE `id`=690;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Finissons-en vite, le temps cest du mana.' WHERE `id`=691;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je ne crois pas que tu réalises dans quelle merde tu es.' WHERE `id`=692;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je vais faire honneur à ma famille et à mon royaume !' WHERE `id`=693;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Lumière, donne-moi la force !' WHERE `id`=694;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Mon église, cest le champ de bataille lheure de la messe a sonné !' WHERE `id`=695;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je te tiens en mépris total…' WHERE `id`=696;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Affronte le marteau de la justice !' WHERE `id`=697;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Prouve ta valeur dans lépreuve des armes, sous la Lumière !' WHERE `id`=698;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Tous doivent tomber devant la puissance de ma cause tu es le prochain !' WHERE `id`=699;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Prépare-toi à mourir !' WHERE `id`=700;
UPDATE `ai_playerbot_texts` SET `text_loc2`='La bête en moi est bien pire que celle à mes côtés…' WHERE `id`=701;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Admire la puissance de feu dun chasseur totalement équipé !' WHERE `id`=702;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Soigne-moi ! Vite !' WHERE `id`=703;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je suis presque mort ! Soignez-moi !' WHERE `id`=704;
UPDATE `ai_playerbot_texts` SET `text_loc2`='À laide ! Soignez-moi !' WHERE `id`=705;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Quelquun ! Un soin vite !' WHERE `id`=706;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Heal ! Heal ! Heal !' WHERE `id`=707;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je meurs ! Soin ! Aaaaarhg !' WHERE `id`=708;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Soignez-moi !' WHERE `id`=709;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je vais mourir. Je vais mourir. Je vais mourir. Soignez-moi !' WHERE `id`=710;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Healers, vous êtes où ? Je crève !' WHERE `id`=711;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Ouille, la douleur ! Soignez vite !' WHERE `id`=712;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Besoin de soin' WHERE `id`=713;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Vie basse !' WHERE `id`=714;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Lâche un heal. Sil te plaît.' WHERE `id`=715;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Quelquun peut me balancer un soin ?' WHERE `id`=716;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Hey ! Mieux vaut me soigner maintenant que me rez plus tard !' WHERE `id`=717;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Désolé… mais encore un heal, please.' WHERE `id`=718;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Saletés de mobs… heal moi vite !' WHERE `id`=719;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Encore un coup et je suis mort. Un petit heal ?' WHERE `id`=720;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Ya des soigneurs dans cette galère ?' WHERE `id`=721;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Pourquoi cest toujours ma tête quils frappent ? Jai besoin dun soin !' WHERE `id`=722;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Quelquun pour me soigner un chouïa ?' WHERE `id`=723;
UPDATE `ai_playerbot_texts` SET `text_loc2`='OOM' WHERE `id`=724;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Plus de mana !' WHERE `id`=725;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Jai cramé tout mon mana pour ça, sérieux...' WHERE `id`=726;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Faudrait attendre que je boive ou que je régène, là…' WHERE `id`=727;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Mana faible… très faible…' WHERE `id`=728;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Encore à sec ? Pas de mana, encore.' WHERE `id`=729;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Mana bas. Je veux une boisson !' WHERE `id`=730;
UPDATE `ai_playerbot_texts` SET `text_loc2`='On a une machine à boissons ? Jai encore plus rien !' WHERE `id`=731;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Mon mana ? Parti dans les limbes.' WHERE `id`=732;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Jachèterai des boissons la prochaine fois. Là jai que dalle.' WHERE `id`=733;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Où est passé mon mana ?' WHERE `id`=734;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Il me reste quelques <ammo> !' WHERE `id`=735;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Besoin de plus de <ammo> !' WHERE `id`=736;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Plus que 100 <ammo> !' WHERE `id`=737;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Cest fini ! Plus un seul <ammo> !' WHERE `id`=738;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Et tu as mon arc… oups, plus de <ammo> !' WHERE `id`=739;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Jai besoin de munitions !' WHERE `id`=740;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Oh mon dieu !' WHERE `id`=741;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Jai peur… là… vraiment.' WHERE `id`=742;
UPDATE `ai_playerbot_texts` SET `text_loc2`='On est foutus !' WHERE `id`=743;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Cest fini. F.I.N.I.' WHERE `id`=744;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Ça se termine maintenant.' WHERE `id`=745;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Quelquun peut balancer un blizzard ou un truc ?!' WHERE `id`=746;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Mince. Le tank a aggro TOUT le monde…' WHERE `id`=747;
UPDATE `ai_playerbot_texts` SET `text_loc2`='On va mourir. On va mourir. On VA MOURIR !' WHERE `id`=748;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Wow ! Tant de jouets à casser !' WHERE `id`=749;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je vais tous les buter ! TOUS !' WHERE `id`=750;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Si le tank meurt, cest foutu pour nous tous…' WHERE `id`=751;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Aaaaaargh !' WHERE `id`=752;
UPDATE `ai_playerbot_texts` SET `text_loc2`='LEEEEERROOOYYYYYYYYYYYY JENNKINNNSSSSSS !!!!!!!!' WHERE `id`=753;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Bon. Quest-ce quon a en AOE là ?' WHERE `id`=754;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Ça devient intéressant…' WHERE `id`=755;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Cool. Regroupez-les bien pour une jolie boule de feu !' WHERE `id`=756;
UPDATE `ai_playerbot_texts` SET `text_loc2`='TUEZ ! TUEZ ! TUEZ !' WHERE `id`=757;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je crois que jai mouillé mon pantalon…' WHERE `id`=758;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Cest notre fin. Cétait sympa.' WHERE `id`=759;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Jespère que les healers sont prêts… LEEEEROYYYY !' WHERE `id`=760;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Pourvu quils ne me ciblent pas moi…' WHERE `id`=761;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Oh non. Je peux pas regarder ce massacre…' WHERE `id`=762;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Jespère quil y aura de la thune.' WHERE `id`=763;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Loot ! LOOT !' WHERE `id`=764;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Mon précieux…' WHERE `id`=765;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Jespère quun bel objet épique mattend là-dedans' WHERE `id`=766;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Jai des poches profondes et des sacs encore vides.' WHERE `id`=767;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Tout est à moi !' WHERE `id`=768;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Pas de gris moisi aujourdhui, pitié…' WHERE `id`=769;
UPDATE `ai_playerbot_texts` SET `text_loc2`='CE loot est À MOI !' WHERE `id`=770;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Looter cest sale… mais jai besoin de thunes.' WHERE `id`=771;
UPDATE `ai_playerbot_texts` SET `text_loc2`='De lor !' WHERE `id`=772;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Ok. Voyons ce quils ont laissé…' WHERE `id`=773;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Tinquiète, je vais tout looter. Tout.' WHERE `id`=774;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je suis un ninja du loot.' WHERE `id`=775;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je dois lancer les dés ?' WHERE `id`=776;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Quelquun peut mexpliquer où ils ont rangé tout ça ?' WHERE `id`=777;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Non, je loot pas cette merde grise.' WHERE `id`=778;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Cest moi dabord ! Cest moi ! MOI !' WHERE `id`=779;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Donne-moi ton fric !' WHERE `id`=780;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Mes poches sont vides, il faut les remplir.' WHERE `id`=781;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Jai un nouveau sac, il est fait pour ça.' WHERE `id`=782;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Jespère que je vais pas aggro en lootant…' WHERE `id`=783;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Ne regardez pas… je loot discret…' WHERE `id`=784;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Ha ! Vous naurez rien de tout ça !' WHERE `id`=785;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Le loot, cest stylé.' WHERE `id`=786;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Jadore les nouveaux équipements.' WHERE `id`=787;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je me casse si ya encore rien de valeur…' WHERE `id`=788;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Jespère que ce sera une jolie bague !' WHERE `id`=789;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je vais tarracher le loot des mains !' WHERE `id`=790;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Personne ne touche à rien. Cest MOI qui loot.' WHERE `id`=791;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Loot sucré :D' WHERE `id`=792;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Dieu du lancer, donne-moi un épique aujourdhui…' WHERE `id`=793;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Allez, de nouveaux jouets sil vous plaît !' WHERE `id`=794;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Jespère quils ont des trucs savoureux…' WHERE `id`=795;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Lor est à moi. Je laisse tout le reste… promis…' WHERE `id`=796;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Non, je peux pas résister.' WHERE `id`=797;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Jen veux ENCORE !' WHERE `id`=798;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je suis presque là, attendez-moi !' WHERE `id`=799;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je suis pas loin, attendez-moi !' WHERE `id`=800;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Jarrive vers ta position' WHERE `id`=801;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Jarrive vers toi' WHERE `id`=802;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je me dirige vers ta position' WHERE `id`=803;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Jessaie de te rejoindre' WHERE `id`=804;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Équipement de %item' WHERE `id`=805;
UPDATE `ai_playerbot_texts` SET `text_loc2`='%item retiré' WHERE `id`=806;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Jai appris les sorts : %spells' WHERE `id`=807;
UPDATE `ai_playerbot_texts` SET `text_loc2`='%item est en recharge' WHERE `id`=808;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je nai pas %item dans mon inventaire' WHERE `id`=809;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Lobjet avec lID %item nexiste pas' WHERE `id`=810;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Insertion de %gem dans %item' WHERE `id`=811;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je ne peux pas utiliser %item' WHERE `id`=812;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Suivi' WHERE `id`=813;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je reste ici' WHERE `id`=814;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je fuis' WHERE `id`=815;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je fuis pas avec toi, tes trop loin !' WHERE `id`=816;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Farm en cours' WHERE `id`=817;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Attaque en cours' WHERE `id`=818;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Cest trop loin' WHERE `id`=819;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Cest sous leau' WHERE `id`=820;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je ne peux pas y aller' WHERE `id`=821;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je ne suis pas dans ta guilde !' WHERE `id`=822;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Impossible de trouver une banque de guilde à proximité' WHERE `id`=823;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je ne peux pas déposer' WHERE `id`=824;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je nai pas les droits pour déposer dans le premier onglet de la banque de guilde' WHERE `id`=825;
UPDATE `ai_playerbot_texts` SET `text_loc2`='déposé dans la banque de guilde' WHERE `id`=826;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Déplacement libre' WHERE `id`=827;
UPDATE `ai_playerbot_texts` SET `text_loc2`='En garde' WHERE `id`=828;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Utilisation de %target' WHERE `id`=829;
UPDATE `ai_playerbot_texts` SET `text_loc2`='sur %unit' WHERE `id`=830;
UPDATE `ai_playerbot_texts` SET `text_loc2`='(%amount disponible)' WHERE `id`=831;
UPDATE `ai_playerbot_texts` SET `text_loc2`='(le dernier)' WHERE `id`=832;
UPDATE `ai_playerbot_texts` SET `text_loc2`='La châsse ne correspond pas' WHERE `id`=833;
UPDATE `ai_playerbot_texts` SET `text_loc2`='sur objet déchange' WHERE `id`=834;
UPDATE `ai_playerbot_texts` SET `text_loc2`='sur moi-même' WHERE `id`=835;
UPDATE `ai_playerbot_texts` SET `text_loc2`='sur %item' WHERE `id`=836;
UPDATE `ai_playerbot_texts` SET `text_loc2`='sur %gameobject' WHERE `id`=837;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Loot de %item' WHERE `id`=838;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Invocation de %target' WHERE `id`=839;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je nai pas assez de membres du groupe à proximité pour invoquer' WHERE `id`=840;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Impossible de trouver la cible dinvocation' WHERE `id`=841;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je ne peux pas invoquer en combat' WHERE `id`=842;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Je ne connais pas le sort %spell' WHERE `id`=843;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Lancement du sort %spell' WHERE `id`=844;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Fabrication de %spell' WHERE `id`=845;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Impossible de lancer %spell' WHERE `id`=846;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Échec du lancement de %spell' WHERE `id`=847;
UPDATE `ai_playerbot_texts` SET `text_loc2`='|cffffff00(x%amount restant)|r' WHERE `id`=848;
UPDATE `ai_playerbot_texts` SET `text_loc2`='dummy' WHERE `id`=849;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Par la Lumière... J\'ai oublié mes Symboles du roi. On se contentera de %base_spell !' WHERE `id`=934;
UPDATE `ai_playerbot_texts` SET `text_loc2`='La nature est généreuse, pas mes sacs... plus d\'herbes pour %group_spell. Prenez %base_spell pour l\'instant !' WHERE `id`=935;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Plus de poudre des arcanes... %group_spell attendra. Je lance %base_spell !' WHERE `id`=936;
UPDATE `ai_playerbot_texts` SET `text_loc2`='Oups, je n\'ai plus de composants pour %group_spell. On fera avec %base_spell !' WHERE `id`=937;

View File

@@ -1,29 +0,0 @@
DELETE FROM ai_playerbot_texts WHERE name IN (
'netherspite_beam_blocking_red',
'netherspite_beam_blocking_blue',
'netherspite_beam_blocking_green',
'netherspite_beam_leaving_blue',
'netherspite_beam_leaving_green'
);
DELETE FROM ai_playerbot_texts_chance WHERE name IN (
'netherspite_beam_blocking_red',
'netherspite_beam_blocking_blue',
'netherspite_beam_blocking_green',
'netherspite_beam_leaving_blue',
'netherspite_beam_leaving_green'
);
INSERT INTO ai_playerbot_texts (name, text, say_type, reply_type, text_loc1, text_loc2, text_loc3, text_loc4, text_loc5, text_loc6, text_loc7, text_loc8) VALUES
('netherspite_beam_blocking_red', '%player is moving to block the red beam!', 0, 0, '', '', '', '', '', '', '', ''),
('netherspite_beam_blocking_blue', '%player is moving to block the blue beam!', 0, 0, '', '', '', '', '', '', '', ''),
('netherspite_beam_blocking_green', '%player is moving to block the green beam!', 0, 0, '', '', '', '', '', '', '', ''),
('netherspite_beam_leaving_blue', '%player is leaving the blue beam--next blocker up!', 0, 0, '', '', '', '', '', '', '', ''),
('netherspite_beam_leaving_green', '%player is leaving the green beam--next blocker up!', 0, 0, '', '', '', '', '', '', '', '');
INSERT INTO ai_playerbot_texts_chance (name, probability) VALUES
('netherspite_beam_blocking_red', 100),
('netherspite_beam_blocking_blue', 100),
('netherspite_beam_blocking_green', 100),
('netherspite_beam_leaving_blue', 100),
('netherspite_beam_leaving_green', 100);

View File

@@ -1,255 +0,0 @@
DELETE FROM ai_playerbot_texts WHERE name IN (
'pet_usage_error',
'pet_no_pet_error',
'pet_stance_report',
'pet_no_target_error',
'pet_target_dead_error',
'pet_invalid_target_error',
'pet_pvp_prohibited_error',
'pet_attack_success',
'pet_attack_failed',
'pet_follow_success',
'pet_stay_success',
'pet_unknown_command_error',
'pet_stance_set_success',
'pet_type_pet',
'pet_type_guardian',
'pet_stance_aggressive',
'pet_stance_defensive',
'pet_stance_passive',
'pet_stance_unknown'
);
DELETE FROM ai_playerbot_texts_chance WHERE name IN (
'pet_usage_error',
'pet_no_pet_error',
'pet_stance_report',
'pet_no_target_error',
'pet_target_dead_error',
'pet_invalid_target_error',
'pet_pvp_prohibited_error',
'pet_attack_success',
'pet_attack_failed',
'pet_follow_success',
'pet_stay_success',
'pet_unknown_command_error',
'pet_stance_set_success',
'pet_type_pet',
'pet_type_guardian',
'pet_stance_aggressive',
'pet_stance_defensive',
'pet_stance_passive',
'pet_stance_unknown'
);
INSERT INTO ai_playerbot_texts (id, name, text, say_type, reply_type, text_loc1, text_loc2, text_loc3, text_loc4, text_loc5, text_loc6, text_loc7, text_loc8) VALUES
(1717, 'pet_usage_error', "Usage: pet <aggressive|defensive|passive|stance|attack|follow|stay>", 0, 0,
"사용법: pet <aggressive|defensive|passive|stance|attack|follow|stay>",
"Utilisation: pet <aggressive|defensive|passive|stance|attack|follow|stay>",
"Verwendung: pet <aggressive|defensive|passive|stance|attack|follow|stay>",
"用法: pet <aggressive|defensive|passive|stance|attack|follow|stay>",
"用法: pet <aggressive|defensive|passive|stance|attack|follow|stay>",
"Uso: pet <aggressive|defensive|passive|stance|attack|follow|stay>",
"Uso: pet <aggressive|defensive|passive|stance|attack|follow|stay>",
"Использование: pet <aggressive|defensive|passive|stance|attack|follow|stay>"),
(1718, 'pet_no_pet_error', "You have no pet or guardian pet.", 0, 0,
"펫이나 수호자 펫이 없습니다.",
"Vous n'avez pas de familier ou gardien.",
"Du hast kein Tier oder Wächter.",
"你没有宠物或守护者宠物。",
"你沒有寵物或守護者寵物。",
"No tienes mascota o mascota guardián.",
"No tienes mascota o mascota guardián.",
"У вас нет питомца или защитника."),
(1719, 'pet_stance_report', "Current stance of %type \"%name\": %stance.", 0, 0,
"%type \"%name\"의 현재 태세: %stance.",
"Position actuelle du %type \"%name\": %stance.",
"Aktuelle Haltung des %type \"%name\": %stance.",
"%type \"%name\" 的当前姿态: %stance。",
"%type \"%name\" 的當前姿態: %stance。",
"Postura actual del %type \"%name\": %stance.",
"Postura actual del %type \"%name\": %stance.",
"Текущая позиция %type \"%name\": %stance."),
(1720, 'pet_no_target_error', "No valid target selected by master.", 0, 0,
"주인이 유효한 대상을 선택하지 않았습니다.",
"Aucune cible valide sélectionnée par le maître.",
"Kein gültiges Ziel vom Meister ausgewählt.",
"主人未选择有效目标。",
"主人未選擇有效目標。",
"No hay objetivo válido seleccionado por el maestro.",
"No hay objetivo válido seleccionado por el maestro.",
"Хозяин не выбрал действительную цель."),
(1721, 'pet_target_dead_error', "Target is not alive.", 0, 0,
"대상이 살아있지 않습니다.",
"La cible n'est pas vivante.",
"Das Ziel ist nicht am Leben.",
"目标未存活。",
"目標未存活。",
"El objetivo no está vivo.",
"El objetivo no está vivo.",
"Цель не жива."),
(1722, 'pet_invalid_target_error', "Target is not a valid attack target for the bot.", 0, 0,
"대상이 봇에게 유효한 공격 대상이 아닙니다.",
"La cible n'est pas une cible d'attaque valide pour le bot.",
"Das Ziel ist kein gültiges Angriffsziel für den Bot.",
"目标不是机器人的有效攻击目标。",
"目標不是機器人的有效攻擊目標。",
"El objetivo no es un objetivo de ataque válido para el bot.",
"El objetivo no es un objetivo de ataque válido para el bot.",
"Цель не является допустимой целью атаки для бота."),
(1723, 'pet_pvp_prohibited_error', "I cannot command my pet to attack players in PvP prohibited areas.", 0, 0,
"PvP 금지 지역에서는 펫에게 플레이어 공격 명령을 내릴 수 없습니다.",
"Je ne peux pas commander à mon familier d'attaquer des joueurs dans les zones où le PvP est interdit.",
"Ich kann meinem Tier nicht befehlen, Spieler in PvP-verbotenen Gebieten anzugreifen.",
"我不能命令我的宠物在禁止PvP的区域攻击玩家。",
"我不能命令我的寵物在禁止PvP的區域攻擊玩家。",
"No puedo ordenar a mi mascota atacar jugadores en áreas donde el PvP está prohibido.",
"No puedo ordenar a mi mascota atacar jugadores en áreas donde el PvP está prohibido.",
"Я не могу приказать своему питомцу атаковать игроков в зонах, где PvP запрещено."),
(1724, 'pet_attack_success', "Pet commanded to attack your target.", 0, 0,
"펫이 당신의 대상을 공격하도록 명령했습니다.",
"Le familier a reçu l'ordre d'attaquer votre cible.",
"Tier wurde befohlen, dein Ziel anzugreifen.",
"宠物已命令攻击你的目标。",
"寵物已命令攻擊你的目標。",
"Mascota ordenada a atacar tu objetivo.",
"Mascota ordenada a atacar tu objetivo.",
"Питомцу приказано атаковать вашу цель."),
(1725, 'pet_attack_failed', "Pet did not attack. (Already attacking or unable to attack target)", 0, 0,
"펫이 공격하지 않았습니다. (이미 공격 중이거나 대상 공격 불가)",
"Le familier n'a pas attaqué. (Attaque déjà en cours ou impossible d'attaquer la cible)",
"Tier hat nicht angegriffen. (Greift bereits an oder kann Ziel nicht angreifen)",
"宠物未攻击。(已在攻击或无法攻击目标)",
"寵物未攻擊。(已在攻擊或無法攻擊目標)",
"La mascota no atacó. (Ya está atacando o no puede atacar al objetivo)",
"La mascota no atacó. (Ya está atacando o no puede atacar al objetivo)",
"Питомец не атаковал. (Уже атакует или не может атаковать цель)"),
(1726, 'pet_follow_success', "Pet commanded to follow.", 0, 0,
"펫이 따라오도록 명령했습니다.",
"Le familier a reçu l'ordre de suivre.",
"Tier wurde befohlen zu folgen.",
"宠物已命令跟随。",
"寵物已命令跟隨。",
"Mascota ordenada a seguir.",
"Mascota ordenada a seguir.",
"Питомцу приказано следовать."),
(1727, 'pet_stay_success', "Pet commanded to stay.", 0, 0,
"펫이 머물도록 명령했습니다.",
"Le familier a reçu l'ordre de rester.",
"Tier wurde befohlen zu bleiben.",
"宠物已命令停留。",
"寵物已命令停留。",
"Mascota ordenada a quedarse.",
"Mascota ordenada a quedarse.",
"Питомцу приказано остаться."),
(1728, 'pet_unknown_command_error', "Unknown pet command: %param. Use: pet <aggressive|defensive|passive|stance|attack|follow|stay>", 0, 0,
"알 수 없는 펫 명령: %param. 사용법: pet <aggressive|defensive|passive|stance|attack|follow|stay>",
"Commande de familier inconnue: %param. Utilisation: pet <aggressive|defensive|passive|stance|attack|follow|stay>",
"Unbekannter Tierbefehl: %param. Verwendung: pet <aggressive|defensive|passive|stance|attack|follow|stay>",
"未知宠物命令: %param。用法: pet <aggressive|defensive|passive|stance|attack|follow|stay>",
"未知寵物命令: %param。用法: pet <aggressive|defensive|passive|stance|attack|follow|stay>",
"Comando de mascota desconocido: %param. Uso: pet <aggressive|defensive|passive|stance|attack|follow|stay>",
"Comando de mascota desconocido: %param. Uso: pet <aggressive|defensive|passive|stance|attack|follow|stay>",
"Неизвестная команда питомца: %param. Использование: pet <aggressive|defensive|passive|stance|attack|follow|stay>"),
(1729, 'pet_stance_set_success', "Pet stance set to %stance.", 0, 0,
"펫 태세가 %stance(으)로 설정되었습니다.",
"Position du familier définie sur %stance.",
"Tierhaltung auf %stance gesetzt.",
"宠物姿态设置为 %stance。",
"寵物姿態設置為 %stance。",
"Postura de mascota establecida en %stance.",
"Postura de mascota establecida en %stance.",
"Позиция питомца установлена на %stance."),
(1730, 'pet_type_pet', "pet", 0, 0,
"",
"familier",
"Tier",
"宠物",
"寵物",
"mascota",
"mascota",
"питомец"),
(1731, 'pet_type_guardian', "guardian", 0, 0,
"수호자",
"gardien",
"Wächter",
"守护者",
"守護者",
"guardián",
"guardián",
"защитник"),
(1732, 'pet_stance_aggressive', "aggressive", 0, 0,
"공격적",
"agressif",
"aggressiv",
"进攻",
"進攻",
"agresivo",
"agresivo",
"агрессивная"),
(1733, 'pet_stance_defensive', "defensive", 0, 0,
"방어적",
"défensif",
"defensiv",
"防御",
"防禦",
"defensivo",
"defensivo",
"защитная"),
(1734, 'pet_stance_passive', "passive", 0, 0,
"수동적",
"passif",
"passiv",
"被动",
"被動",
"pasivo",
"pasivo",
"пассивная"),
(1735, 'pet_stance_unknown', "unknown", 0, 0,
"알 수 없음",
"inconnu",
"unbekannt",
"未知",
"未知",
"desconocido",
"desconocido",
"неизвестная");
INSERT INTO ai_playerbot_texts_chance (name, probability) VALUES
('pet_usage_error', 100),
('pet_no_pet_error', 100),
('pet_stance_report', 100),
('pet_no_target_error', 100),
('pet_target_dead_error', 100),
('pet_invalid_target_error', 100),
('pet_pvp_prohibited_error', 100),
('pet_attack_success', 100),
('pet_attack_failed', 100),
('pet_follow_success', 100),
('pet_stay_success', 100),
('pet_unknown_command_error', 100),
('pet_stance_set_success', 100),
('pet_type_pet', 100),
('pet_type_guardian', 100),
('pet_stance_aggressive', 100),
('pet_stance_defensive', 100),
('pet_stance_passive', 100),
('pet_stance_unknown', 100);

View File

@@ -1,15 +0,0 @@
DELETE FROM ai_playerbot_texts WHERE name IN ('no_fishing_pole_error');
DELETE FROM ai_playerbot_texts_chance WHERE name IN ('no_fishing_pole_error');
INSERT INTO ai_playerbot_texts (id, name, text, say_type, reply_type, text_loc1, text_loc2, text_loc3, text_loc4, text_loc5, text_loc6, text_loc7, text_loc8) VALUES
(1736, 'no_fishing_pole_error', "I don't have a Fishing Pole", 0, 0,
"낚싯대가 없습니다",
"Je nai pas de canne à pêche",
"Ich habe keine Angelrute",
"我沒有釣魚竿",
"我没有钓鱼竿",
"No tengo una caña de pescar",
"No tengo una caña de pescar",
"У меня нет удочки");
INSERT INTO ai_playerbot_texts_chance (name, probability) VALUES ('no_fishing_pole_error', 100);

File diff suppressed because it is too large Load Diff

View File

@@ -4,11 +4,11 @@ DELETE FROM `playerbots_travelnode_path` WHERE `node_id` = 3780;
DELETE FROM `playerbots_travelnode` WHERE `id` = 3780;
-- Insert new entries into playerbots_travelnode
INSERT INTO `playerbots_travelnode` (`id`, `name`, `map_id`, `x`, `y`, `z`, `linked`)
INSERT INTO `playerbots_travelnode` (`id`, `name`, `map_id`, `x`, `y`, `z`, `linked`)
VALUES (3780, 'Highlord Mograine', 533, 2524.32, -2951.28, 245.633, 1);
-- Insert new entries into playerbots_travelnode_path
INSERT INTO `playerbots_travelnode_path` (`node_id`, `to_node_id`, `nr`, `map_id`, `x`, `y`, `z`)
INSERT INTO `playerbots_travelnode_path` (`node_id`, `to_node_id`, `nr`, `map_id`, `x`, `y`, `z`)
VALUES
(3780, 472, 0, 533, 2524.32, -2951.28, 245.633),
(3780, 472, 1, 533, 2528.79, -2948.58, 245.633),
@@ -16,7 +16,7 @@ VALUES
(3780, 757, 1, 533, 2517.62, -2959.38, 245.636);
-- Insert new entries into playerbots_travelnode_link
INSERT INTO `playerbots_travelnode_link` (`node_id`, `to_node_id`, `type`, `object`, `distance`, `swim_distance`, `extra_cost`, `calculated`, `max_creature_0`, `max_creature_1`, `max_creature_2`)
INSERT INTO `playerbots_travelnode_link` (`node_id`, `to_node_id`, `type`, `object`, `distance`, `swim_distance`, `extra_cost`, `calculated`, `max_creature_0`, `max_creature_1`, `max_creature_2`)
VALUES
(3780, 472, 1, 0, 5.3221, 0, 0, 1, 83, 0, 0),
(3780, 757, 1, 0, 10.6118, 0, 0, 1, 83, 0, 0);

View File

@@ -1,3 +0,0 @@
DELETE FROM spell_dbc WHERE ID = 30758;
INSERT INTO spell_dbc (`ID`,`Category`,`DispelType`,`Mechanic`,`Attributes`,`AttributesEx`,`AttributesEx2`,`AttributesEx3`,`AttributesEx4`,`AttributesEx5`,`AttributesEx6`,`AttributesEx7`,`ShapeshiftMask`,`unk_320_2`,`ShapeshiftExclude`,`unk_320_3`,`Targets`,`TargetCreatureType`,`RequiresSpellFocus`,`FacingCasterFlags`,`CasterAuraState`,`TargetAuraState`,`ExcludeCasterAuraState`,`ExcludeTargetAuraState`,`CasterAuraSpell`,`TargetAuraSpell`,`ExcludeCasterAuraSpell`,`ExcludeTargetAuraSpell`,`CastingTimeIndex`,`RecoveryTime`,`CategoryRecoveryTime`,`InterruptFlags`,`AuraInterruptFlags`,`ChannelInterruptFlags`,`ProcTypeMask`,`ProcChance`,`ProcCharges`,`MaxLevel`,`BaseLevel`,`SpellLevel`,`DurationIndex`,`PowerType`,`ManaCost`,`ManaCostPerLevel`,`ManaPerSecond`,`ManaPerSecondPerLevel`,`RangeIndex`,`Speed`,`ModalNextSpell`,`CumulativeAura`,`Totem_1`,`Totem_2`,`Reagent_1`,`Reagent_2`,`Reagent_3`,`Reagent_4`,`Reagent_5`,`Reagent_6`,`Reagent_7`,`Reagent_8`,`ReagentCount_1`,`ReagentCount_2`,`ReagentCount_3`,`ReagentCount_4`,`ReagentCount_5`,`ReagentCount_6`,`ReagentCount_7`,`ReagentCount_8`,`EquippedItemClass`,`EquippedItemSubclass`,`EquippedItemInvTypes`,`Effect_1`,`Effect_2`,`Effect_3`,`EffectDieSides_1`,`EffectDieSides_2`,`EffectDieSides_3`,`EffectRealPointsPerLevel_1`,`EffectRealPointsPerLevel_2`,`EffectRealPointsPerLevel_3`,`EffectBasePoints_1`,`EffectBasePoints_2`,`EffectBasePoints_3`,`EffectMechanic_1`,`EffectMechanic_2`,`EffectMechanic_3`,`ImplicitTargetA_1`,`ImplicitTargetA_2`,`ImplicitTargetA_3`,`ImplicitTargetB_1`,`ImplicitTargetB_2`,`ImplicitTargetB_3`,`EffectRadiusIndex_1`,`EffectRadiusIndex_2`,`EffectRadiusIndex_3`,`EffectAura_1`,`EffectAura_2`,`EffectAura_3`,`EffectAuraPeriod_1`,`EffectAuraPeriod_2`,`EffectAuraPeriod_3`,`EffectMultipleValue_1`,`EffectMultipleValue_2`,`EffectMultipleValue_3`,`EffectChainTargets_1`,`EffectChainTargets_2`,`EffectChainTargets_3`,`EffectItemType_1`,`EffectItemType_2`,`EffectItemType_3`,`EffectMiscValue_1`,`EffectMiscValue_2`,`EffectMiscValue_3`,`EffectMiscValueB_1`,`EffectMiscValueB_2`,`EffectMiscValueB_3`,`EffectTriggerSpell_1`,`EffectTriggerSpell_2`,`EffectTriggerSpell_3`,`EffectPointsPerCombo_1`,`EffectPointsPerCombo_2`,`EffectPointsPerCombo_3`,`EffectSpellClassMaskA_1`,`EffectSpellClassMaskA_2`,`EffectSpellClassMaskA_3`,`EffectSpellClassMaskB_1`,`EffectSpellClassMaskB_2`,`EffectSpellClassMaskB_3`,`EffectSpellClassMaskC_1`,`EffectSpellClassMaskC_2`,`EffectSpellClassMaskC_3`,`SpellVisualID_1`,`SpellVisualID_2`,`SpellIconID`,`ActiveIconID`,`SpellPriority`,`Name_Lang_enUS`,`Name_Lang_enGB`,`Name_Lang_koKR`,`Name_Lang_frFR`,`Name_Lang_deDE`,`Name_Lang_enCN`,`Name_Lang_zhCN`,`Name_Lang_enTW`,`Name_Lang_zhTW`,`Name_Lang_esES`,`Name_Lang_esMX`,`Name_Lang_ruRU`,`Name_Lang_ptPT`,`Name_Lang_ptBR`,`Name_Lang_itIT`,`Name_Lang_Unk`,`Name_Lang_Mask`,`NameSubtext_Lang_enUS`,`NameSubtext_Lang_enGB`,`NameSubtext_Lang_koKR`,`NameSubtext_Lang_frFR`,`NameSubtext_Lang_deDE`,`NameSubtext_Lang_enCN`,`NameSubtext_Lang_zhCN`,`NameSubtext_Lang_enTW`,`NameSubtext_Lang_zhTW`,`NameSubtext_Lang_esES`,`NameSubtext_Lang_esMX`,`NameSubtext_Lang_ruRU`,`NameSubtext_Lang_ptPT`,`NameSubtext_Lang_ptBR`,`NameSubtext_Lang_itIT`,`NameSubtext_Lang_Unk`,`NameSubtext_Lang_Mask`,`Description_Lang_enUS`,`Description_Lang_enGB`,`Description_Lang_koKR`,`Description_Lang_frFR`,`Description_Lang_deDE`,`Description_Lang_enCN`,`Description_Lang_zhCN`,`Description_Lang_enTW`,`Description_Lang_zhTW`,`Description_Lang_esES`,`Description_Lang_esMX`,`Description_Lang_ruRU`,`Description_Lang_ptPT`,`Description_Lang_ptBR`,`Description_Lang_itIT`,`Description_Lang_Unk`,`Description_Lang_Mask`,`AuraDescription_Lang_enUS`,`AuraDescription_Lang_enGB`,`AuraDescription_Lang_koKR`,`AuraDescription_Lang_frFR`,`AuraDescription_Lang_deDE`,`AuraDescription_Lang_enCN`,`AuraDescription_Lang_zhCN`,`AuraDescription_Lang_enTW`,`AuraDescription_Lang_zhTW`,`AuraDescription_Lang_esES`,`AuraDescription_Lang_esMX`,`AuraDescription_Lang_ruRU`,`AuraDescription_Lang_ptPT`,`AuraDescription_Lang_ptBR`,`AuraDescription_Lang_itIT`,`AuraDescription_Lang_Unk`,`AuraDescription_Lang_Mask`,`ManaCostPct`,`StartRecoveryCategory`,`StartRecoveryTime`,`MaxTargetLevel`,`SpellClassSet`,`SpellClassMask_1`,`SpellClassMask_2`,`SpellClassMask_3`,`MaxTargets`,`DefenseType`,`PreventionType`,`StanceBarOrder`,`EffectChainAmplitude_1`,`EffectChainAmplitude_2`,`EffectChainAmplitude_3`,`MinFactionID`,`MinReputation`,`RequiredAuraVision`,`RequiredTotemCategoryID_1`,`RequiredTotemCategoryID_2`,`RequiredAreasID`,`SchoolMask`,`RuneCostID`,`SpellMissileID`,`PowerDisplayID`,`EffectBonusMultiplier_1`,`EffectBonusMultiplier_2`,`EffectBonusMultiplier_3`,`SpellDescriptionVariableID`,`SpellDifficultyID`)
VALUES (30758,0,0,0,696254720,132128,268976133,269680640,8388736,393224,4100,0,0,0,0,0,64,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,101,0,0,0,0,0,0,0,0,0,0,13,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,0,0,77,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,52,0,0,0,0,10,10,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,'aedm','','','','','','','','','','','','','','','',16712190,'','','','','','','','','','','','','','','','',16712172,'','','','','','','','','','','','','','','','',16712188,'','','','','','','','','','','','','','','','',16712188,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0);

View File

@@ -1,5 +1,5 @@
DROP TABLE IF EXISTS `playerbots_rpg_races`;
CREATE TABLE `playerbots_rpg_races`
CREATE TABLE `playerbots_rpg_races`
(
`id` int(11) NOT NULL AUTO_INCREMENT,
`entry` int(11),

View File

@@ -1,147 +0,0 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
* and/or modify it under version 3 of the License, or (at your option), any later version.
*/
#ifndef _PLAYERBOT_BATTLEGROUNDTACTICSACTION_H
#define _PLAYERBOT_BATTLEGROUNDTACTICSACTION_H
#include "BattlegroundAV.h"
#include "MovementActions.h"
class ChatHandler;
class Battleground;
class PlayerbotAI;
struct Position;
#define SPELL_CAPTURE_BANNER 21651
enum WSBotStrategy : uint8
{
WS_STRATEGY_BALANCED = 0,
WS_STRATEGY_OFFENSIVE = 1,
WS_STRATEGY_DEFENSIVE = 2,
WS_STRATEGY_MAX = 3,
};
enum ABBotStrategy : uint8
{
AB_STRATEGY_BALANCED = 0,
AB_STRATEGY_OFFENSIVE = 1,
AB_STRATEGY_DEFENSIVE = 2,
AB_STRATEGY_MAX = 3,
};
enum AVBotStrategy : uint8
{
AV_STRATEGY_BALANCED = 0,
AV_STRATEGY_OFFENSIVE = 1,
AV_STRATEGY_DEFENSIVE = 2,
AV_STRATEGY_MAX = 3,
};
enum EYBotStrategy : uint8
{
EY_STRATEGY_BALANCED = 0,
EY_STRATEGY_FRONT_FOCUS = 1,
EY_STRATEGY_BACK_FOCUS = 2,
EY_STRATEGY_FLAG_FOCUS = 3,
EY_STRATEGY_MAX = 4
};
typedef void (*BattleBotWaypointFunc)();
struct BGStrategyData
{
uint8 allianceStrategy = 0;
uint8 hordeStrategy = 0;
};
extern std::unordered_map<uint32, BGStrategyData> bgStrategies;
struct BattleBotWaypoint
{
BattleBotWaypoint(float x_, float y_, float z_, BattleBotWaypointFunc func) : x(x_), y(y_), z(z_), pFunc(func){};
float x = 0.0f;
float y = 0.0f;
float z = 0.0f;
BattleBotWaypointFunc pFunc = nullptr;
};
struct AVNodePositionData
{
Position pos;
float maxRadius;
};
// Added to fix bot stuck at objectives
static std::unordered_map<uint8, AVNodePositionData> AVNodeMovementTargets = {
{BG_AV_NODES_FIRSTAID_STATION, {Position(640.364f, -36.535f, 45.625f), 15.0f}},
{BG_AV_NODES_STORMPIKE_GRAVE, {Position(665.598f, -292.976f, 30.291f), 15.0f}},
{BG_AV_NODES_STONEHEART_GRAVE, {Position(76.108f, -399.602f, 45.730f), 15.0f}},
{BG_AV_NODES_SNOWFALL_GRAVE, {Position(-201.298f, -119.661f, 78.291f), 15.0f}},
{BG_AV_NODES_ICEBLOOD_GRAVE, {Position(-617.858f, -400.654f, 59.692f), 15.0f}},
{BG_AV_NODES_FROSTWOLF_GRAVE, {Position(-1083.803f, -341.520f, 55.304f), 15.0f}},
{BG_AV_NODES_FROSTWOLF_HUT, {Position(-1405.678f, -309.108f, 89.377f, 0.392f), 10.0f}},
{BG_AV_NODES_DUNBALDAR_SOUTH, {Position(556.551f, -77.240f, 51.931f), 0.0f}},
{BG_AV_NODES_DUNBALDAR_NORTH, {Position(670.664f, -142.031f, 63.666f), 0.0f}},
{BG_AV_NODES_ICEWING_BUNKER, {Position(200.310f, -361.232f, 56.387f), 0.0f}},
{BG_AV_NODES_STONEHEART_BUNKER, {Position(-156.302f, -440.032f, 40.403f), 0.0f}},
{BG_AV_NODES_ICEBLOOD_TOWER, {Position(-569.702f, -265.362f, 75.009f), 0.0f}},
{BG_AV_NODES_TOWER_POINT, {Position(-767.439f, -360.200f, 90.895f), 0.0f}},
{BG_AV_NODES_FROSTWOLF_ETOWER, {Position(-1303.737f, -314.070f, 113.868f), 0.0f}},
{BG_AV_NODES_FROSTWOLF_WTOWER, {Position(-1300.648f, -267.356f, 114.151f), 0.0f}},
};
typedef std::vector<BattleBotWaypoint> BattleBotPath;
extern std::vector<BattleBotPath*> const vPaths_WS;
extern std::vector<BattleBotPath*> const vPaths_AB;
extern std::vector<BattleBotPath*> const vPaths_AV;
extern std::vector<BattleBotPath*> const vPaths_EY;
extern std::vector<BattleBotPath*> const vPaths_IC;
class BGTactics : public MovementAction
{
public:
static bool HandleConsoleCommand(ChatHandler* handler, char const* args);
uint8 static GetBotStrategyForTeam(Battleground* bg, TeamId teamId);
BGTactics(PlayerbotAI* botAI, std::string const name = "bg tactics") : MovementAction(botAI, name) {}
bool Execute(Event event) override;
private:
static std::string const HandleConsoleCommandPrivate(WorldSession* session, char const* args);
bool moveToStart(bool force = false);
bool selectObjective(bool reset = false);
bool moveToObjective(bool ignoreDist);
bool selectObjectiveWp(std::vector<BattleBotPath*> const& vPaths);
bool moveToObjectiveWp(BattleBotPath* const& currentPath, uint32 currentPoint, bool reverse = false);
bool startNewPathBegin(std::vector<BattleBotPath*> const& vPaths);
bool startNewPathFree(std::vector<BattleBotPath*> const& vPaths);
bool resetObjective();
bool wsJumpDown();
bool eyJumpDown();
bool atFlag(std::vector<BattleBotPath*> const& vPaths, std::vector<uint32> const& vFlagIds);
bool flagTaken();
bool teamFlagTaken();
bool protectFC();
bool useBuff();
uint32 getPlayersInArea(TeamId teamId, Position point, float range, bool combat = true);
bool IsLockedInsideKeep();
};
class ArenaTactics : public MovementAction
{
public:
ArenaTactics(PlayerbotAI* botAI, std::string const name = "arena tactics") : MovementAction(botAI, name) {}
bool Execute(Event event) override;
private:
bool moveToCenter(Battleground* bg);
};
#endif

View File

@@ -1,18 +0,0 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
* and/or modify it under version 3 of the License, or (at your option), any later version.
*/
#include "CancelChannelAction.h"
#include "Player.h"
#include "PlayerbotAI.h"
bool CancelChannelAction::Execute(Event event)
{
if (bot->GetCurrentSpell(CURRENT_CHANNELED_SPELL))
{
bot->InterruptSpell(CURRENT_CHANNELED_SPELL);
return true;
}
return false;
}

View File

@@ -1,21 +0,0 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
* and/or modify it under version 3 of the License, or (at your option), any later version.
*/
#ifndef _PLAYERBOT_CANCELCHANNELACTION_H
#define _PLAYERBOT_CANCELCHANNELACTION_H
#include "Action.h"
class PlayerbotAI;
class CancelChannelAction : public Action
{
public:
CancelChannelAction(PlayerbotAI* botAI) : Action(botAI, "cancel channel") {}
bool Execute(Event event) override;
};
#endif

View File

@@ -1,159 +0,0 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
* and/or modify it under version 3 of the License, or (at your option), any later version.
*/
#include "EquipGlyphsAction.h"
#include "Playerbots.h"
#include "ObjectMgr.h"
#include "SpellMgr.h"
#include "DBCStores.h"
#include "AiObjectContext.h"
#include "Log.h"
#include <unordered_map>
#include <sstream>
#include <unordered_set>
namespace
{
// itemId -> GlyphInfo
std::unordered_map<uint32, EquipGlyphsAction::GlyphInfo> s_GlyphCache;
}
void EquipGlyphsAction::BuildGlyphCache()
{
if (!s_GlyphCache.empty())
return;
ItemTemplateContainer const* store = sObjectMgr->GetItemTemplateStore();
for (auto const& kv : *store)
{
uint32 itemId = kv.first;
ItemTemplate const* proto = &kv.second;
if (!proto || proto->Class != ITEM_CLASS_GLYPH)
continue;
// inspect item spell
for (uint32 i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
{
uint32 spellId = proto->Spells[i].SpellId;
if (!spellId) continue;
SpellInfo const* si = sSpellMgr->GetSpellInfo(spellId);
if (!si) continue;
for (uint8 eff = 0; eff <= EFFECT_2; ++eff)
{
if (si->Effects[eff].Effect != SPELL_EFFECT_APPLY_GLYPH)
continue;
uint32 glyphId = si->Effects[eff].MiscValue;
if (!glyphId) continue;
if (auto const* gp = sGlyphPropertiesStore.LookupEntry(glyphId))
s_GlyphCache[itemId] = {gp, proto};
}
}
}
}
EquipGlyphsAction::GlyphInfo const* EquipGlyphsAction::GetGlyphInfo(uint32 itemId)
{
BuildGlyphCache();
auto it = s_GlyphCache.find(itemId);
return (it == s_GlyphCache.end()) ? nullptr : &it->second;
}
/// -----------------------------------------------------------------
/// Validation and collect
/// -----------------------------------------------------------------
bool EquipGlyphsAction::CollectGlyphs(std::vector<uint32> const& itemIds,
std::vector<GlyphInfo const*>& out) const
{
std::unordered_set<uint32> seen;
for (uint32 itemId : itemIds)
{
if (!seen.insert(itemId).second)
return false; // double
auto const* info = GetGlyphInfo(itemId);
if (!info) // no good glyph
return false;
// check class by AllowableClass
if ((info->proto->AllowableClass & bot->getClassMask()) == 0)
return false;
out.push_back(info);
}
return out.size() <= 6 && !out.empty();
}
/// -----------------------------------------------------------------
/// Action
/// -----------------------------------------------------------------
bool EquipGlyphsAction::Execute(Event event)
{
// 1) parse IDs
std::vector<uint32> itemIds;
std::istringstream iss(event.getParam());
for (uint32 id; iss >> id; ) itemIds.push_back(id);
std::vector<GlyphInfo const*> glyphs;
if (!CollectGlyphs(itemIds, glyphs))
{
botAI->TellMaster("Usage: glyph equip <6 glyph item IDs> (3 major, 3 minor).");
return false;
}
// 2) prepare a empty slots table ?
bool used[6] = {false,false,false,false,false,false};
// 3) for each glyph, find the first available and compatible socket
for (auto const* g : glyphs)
{
bool placed = false;
for (uint8 i = 0; i < MAX_GLYPH_SLOT_INDEX; ++i)
{
if (used[i]) continue;
uint32 slotId = bot->GetGlyphSlot(i);
auto const* gs = sGlyphSlotStore.LookupEntry(slotId);
if (!gs || gs->TypeFlags != g->prop->TypeFlags)
continue; // major/minor don't match
// Remove aura if exist
uint32 cur = bot->GetGlyph(i);
if (cur)
if (auto* old = sGlyphPropertiesStore.LookupEntry(cur))
bot->RemoveAurasDueToSpell(old->SpellId);
// Apply new one
bot->CastSpell(bot, g->prop->SpellId, true);
bot->SetGlyph(i, g->prop->Id, true);
used[i] = true;
placed = true;
break;
}
if (!placed)
{
botAI->TellMaster("Not enought empty sockets for all glyphs.");
return false;
}
}
botAI->TellMaster("Glyphs updated.");
// Flag for custom glyphs
botAI->GetAiObjectContext()->GetValue<bool>("custom_glyphs")->Set(true);
LOG_INFO("playerbots", "Custom Glyph Flag set to ON");
return true;
}

View File

@@ -1,37 +0,0 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
* and/or modify it under version 3 of the License, or (at your option), any later version.
*/
#ifndef _PLAYERBOT_EQUIPGLYPHSACTION_H
#define _PLAYERBOT_EQUIPGLYPHSACTION_H
#include "Action.h"
// 1 = major, 2 = minor dans GlyphProperties.dbc
enum class GlyphKind : uint32 { MAJOR = 1, MINOR = 2 };
class EquipGlyphsAction : public Action
{
public:
EquipGlyphsAction(PlayerbotAI* ai) : Action(ai, "glyph equip") {}
bool Execute(Event event) override;
/// ---- Rendu public pour être utilisable par le cache global ----
struct GlyphInfo
{
GlyphPropertiesEntry const* prop; ///< entrée GlyphProperties.dbc
ItemTemplate const* proto; ///< template de lobjet glyphe
};
private:
/// Construit la cache {itemId -> GlyphInfo}
static void BuildGlyphCache();
static GlyphInfo const* GetGlyphInfo(uint32 itemId);
/// Parse & valide la liste ditems glyphes
bool CollectGlyphs(std::vector<uint32> const& itemIds,
std::vector<GlyphInfo const*>& out) const;
};
#endif

View File

@@ -1,510 +0,0 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
* and/or modify it under version 3 of the License, or (at your option), any later version.
*/
#include "FishingAction.h"
#include "FishValues.h"
#include "Event.h"
#include "GridNotifiers.h"
#include "GridNotifiersImpl.h"
#include "ItemPackets.h"
#include "LastMovementValue.h"
#include "Map.h"
#include "MovementActions.h"
#include "Object.h"
#include "PlayerbotAI.h"
#include "PlayerbotTextMgr.h"
#include "Playerbots.h"
#include "Position.h"
uint32 const FISHING_SPELL = 7620;
uint32 const FISHING_POLE = 6256;
uint32 const FISHING_BOBBER = 35591;
float const MIN_DISTANCE_TO_WATER = 10.0f; // Minimum spell distance
float const MAX_DISTANCE_TO_WATER = 20.0f; // Maximum spell distance
float const HEIGHT_ABOVE_WATER_TOLERANCE = 1.0f; // Can stand in up to 1 unit of water and still fish.
float const SEARCH_INCREMENT = 2.5f;
float const HEIGHT_SEARCH_BUFFER = 10.0f; // Height buffer to prevent potentially missing the model the bot is standing on.
float const SEARCH_LAND_BUFFER = 0.5f;
uint32 const FISHING_LOCATION_TIMEOUT = 180000; //Three minutes
static bool IsFishingPole(Item* const item)
{
if (!item)
return false;
const ItemTemplate* proto = item->GetTemplate();
return proto && proto->Class == ITEM_CLASS_WEAPON &&
proto->SubClass == ITEM_SUBCLASS_WEAPON_FISHING_POLE;
}
float HasFishableWaterOrLand(float x, float y, float z, Map* map, uint32 phaseMask, bool checkForLand=false)
{
if (!map)
return INVALID_HEIGHT;
LiquidData const& liq = map->GetLiquidData(phaseMask, x, y, z+HEIGHT_ABOVE_WATER_TOLERANCE, DEFAULT_COLLISION_HEIGHT, MAP_ALL_LIQUIDS);
float ground = map->GetHeight(phaseMask, x, y, z + HEIGHT_SEARCH_BUFFER, true);
if (liq.Entry == MAP_LIQUID_TYPE_NO_WATER)
{
if (checkForLand)
return ground;
return INVALID_HEIGHT;
}
if (checkForLand)
{
if (ground > liq.Level - HEIGHT_ABOVE_WATER_TOLERANCE)
return ground;
return INVALID_HEIGHT;
}
if (liq.Level + HEIGHT_ABOVE_WATER_TOLERANCE > ground)
{
if (abs(liq.DepthLevel) < 0.5f) // too shallow to fish in.
return INVALID_HEIGHT;
return liq.Level;
}
return INVALID_HEIGHT;
}
bool HasLosToWater(Player* bot, float wx, float wy, float waterZ)
{
float z = bot->GetCollisionHeight() + bot->GetPositionZ();
return bot->GetMap()->isInLineOfSight(
bot->GetPositionX(), bot->GetPositionY(), z,
wx, wy, waterZ,
bot->GetPhaseMask(),
LINEOFSIGHT_ALL_CHECKS,
VMAP::ModelIgnoreFlags::Nothing);
}
WorldPosition FindLandFromPosition(PlayerbotAI* botAI, float startDistance, float endDistance, float increment, float orientation, WorldPosition targetPos, float fishingSearchWindow, bool checkLOS = true)
{
Player* bot = botAI->GetBot();
Map* map = bot->GetMap();
uint32 phaseMask = bot->GetPhaseMask();
Player* master = botAI->GetMaster();
float targetX = targetPos.GetPositionX();
float targetY = targetPos.GetPositionY();
float targetZ = targetPos.GetPositionZ();
for (float dist = startDistance; dist <= endDistance; dist += increment)
{
//step backwards from position to bot to find edge of shore.
float checkX = targetX - dist * cos(orientation);
float checkY = targetY - dist * sin(orientation);
float groundZ = map->GetHeight(phaseMask, checkX, checkY, targetZ + HEIGHT_SEARCH_BUFFER, true);
if (groundZ == INVALID_HEIGHT)
continue;
LiquidData const& liq = map->GetLiquidData(phaseMask, checkX, checkY, targetZ, DEFAULT_COLLISION_HEIGHT, MAP_ALL_LIQUIDS);
if (liq.Entry == MAP_LIQUID_TYPE_NO_WATER || groundZ > liq.DepthLevel + HEIGHT_ABOVE_WATER_TOLERANCE)
{
if (checkLOS)
{
bool hasLOS = map->isInLineOfSight(checkX, checkY, groundZ, targetX, targetY, targetZ, phaseMask, LINEOFSIGHT_ALL_CHECKS, VMAP::ModelIgnoreFlags::Nothing);
if (!hasLOS)
continue;
}
// Add a distance check for the position to prevent the bot from moving out of range to the master.
if (master && botAI->HasStrategy("follow", BOT_STATE_NON_COMBAT) && master->GetDistance(checkX, checkY, groundZ) > fishingSearchWindow - SEARCH_LAND_BUFFER)
continue;
return WorldPosition(bot->GetMapId(), checkX, checkY, groundZ);
}
}
return WorldPosition();
}
WorldPosition FindLandRadialFromPosition (PlayerbotAI* botAI, WorldPosition targetPos, float startDistance, float endDistance, float increment, float fishingSearchWindow, int angles = 16)
{
Player* bot = botAI->GetBot();
const int numDirections = angles;
std::vector<WorldPosition> boundaryPoints;
Player* master = botAI->GetMaster();
if (!master)
return WorldPosition();
Map* map = bot->GetMap();
uint32 phaseMask = bot->GetPhaseMask();
float targetX = targetPos.GetPositionX();
float targetY = targetPos.GetPositionY();
float targetZ = targetPos.GetPositionZ();
for (float dist = startDistance; dist <= endDistance; dist += increment)
{
for (int i = 0; i < numDirections; ++i)
{
float angle = (2.0f * M_PI * i) / numDirections;
float checkX = targetX - cos(angle) * dist;
float checkY = targetY - sin(angle) * dist;
float groundZ = HasFishableWaterOrLand(checkX, checkY, targetZ, map, phaseMask, true);
if (groundZ == INVALID_HEIGHT)
continue;
if (map->isInLineOfSight(checkX, checkY, groundZ, targetX, targetY, targetZ, phaseMask, LINEOFSIGHT_ALL_CHECKS, VMAP::ModelIgnoreFlags::Nothing) && master->GetDistance(checkX, checkY, groundZ) > fishingSearchWindow - SEARCH_LAND_BUFFER)
continue;
boundaryPoints.emplace_back(WorldPosition(bot->GetMapId(), checkX, checkY, groundZ));
}
if (!boundaryPoints.empty())
break;
}
if (boundaryPoints.empty())
return WorldPosition();
if (boundaryPoints.size() == 1)
return boundaryPoints[0];
float minDistance = FLT_MAX;
WorldLocation closestPoint = WorldPosition();
for (auto const& pos : boundaryPoints)
{
float distance = bot->GetExactDist2d(&pos);
if (distance < minDistance)
{
minDistance = distance;
closestPoint = pos;
}
}
return closestPoint;
}
WorldPosition FindWaterRadial(Player* bot, float x, float y, float z, Map* map, uint32 phaseMask, float minDistance, float maxDistance, float increment, bool checkLOS, int numDirections)
{
std::vector<WorldPosition> boundaryPoints;
float dist = minDistance;
while (dist <= maxDistance)
{
for (int i = 0; i < numDirections; ++i)
{
float angle = (2.0f * M_PI * i) / numDirections;
float checkX = x + cos(angle) * dist;
float checkY = y + sin(angle) * dist;
float waterZ = HasFishableWaterOrLand(checkX, checkY, z, map, phaseMask);
if (waterZ == INVALID_HEIGHT)
continue;
if (checkLOS && !HasLosToWater(bot, checkX, checkY, waterZ))
continue;
boundaryPoints.emplace_back(WorldPosition(bot->GetMapId(), checkX, checkY, waterZ));
}
if (!boundaryPoints.empty())
break;
dist += increment;
}
if (boundaryPoints.empty())
return WorldPosition();
if (boundaryPoints.size() == 1)
return boundaryPoints[0];
// return the central point in the identified positions in to try to be perpendicular to the shore.
return boundaryPoints[boundaryPoints.size() / 2];
}
WorldPosition FindFishingHole(PlayerbotAI* botAI)
{
Player* player = botAI->GetBot();
GuidVector gos = PAI_VALUE(GuidVector, "nearest game objects no los");
GameObject* nearestFishingHole = nullptr;
float minDist = std::numeric_limits<float>::max();
for (auto const& guid : gos)
{
GameObject* go = botAI->GetGameObject(guid);
if (!go)
continue;
if (go->GetGoType() == GAMEOBJECT_TYPE_FISHINGHOLE)
{
float dist = player->GetDistance2d(go);
if (dist < minDist)
{
minDist = dist;
nearestFishingHole = go;
}
}
}
if (nearestFishingHole)
return WorldPosition(nearestFishingHole->GetMapId(), nearestFishingHole->GetPositionX(), nearestFishingHole->GetPositionY(), nearestFishingHole->GetPositionZ());
return WorldPosition();
}
bool MoveNearWaterAction::Execute(Event event)
{
WorldPosition landSpot = AI_VALUE(WorldPosition, "fishing spot");
if (landSpot.IsValid())
return MoveTo(landSpot.GetMapId(), landSpot.GetPositionX(), landSpot.GetPositionY(), landSpot.GetPositionZ());
return false;
}
bool MoveNearWaterAction::isUseful()
{
if (!AI_VALUE(bool, "can fish"))
return false;
FishingSpotValue* fishingSpotValueObject = (FishingSpotValue*)context->GetValue<WorldPosition>("fishing spot");
WorldPosition pos = fishingSpotValueObject->Get();
return !pos.IsValid() || fishingSpotValueObject->IsStale(FISHING_LOCATION_TIMEOUT) ||
bot->GetExactDist(&pos) < 0.1f;
}
bool MoveNearWaterAction::isPossible()
{
Player* master = botAI->GetMaster();
float fishingSearchWindow;
if (master)
fishingSearchWindow = sPlayerbotAIConfig->fishingDistanceFromMaster;
else
fishingSearchWindow = sPlayerbotAIConfig->fishingDistance;
WorldPosition fishingHole = FindFishingHole(botAI);
if (fishingHole.IsValid())
{
float distance = bot->GetExactDist2d(&fishingHole);
bool hasLOS = bot->IsWithinLOS(fishingHole.GetPositionX(), fishingHole.GetPositionY(), fishingHole.GetPositionZ());
// Water spot is in range, and we have LOS to it. Set bot position to fishing spot and do not move
if (distance >= MIN_DISTANCE_TO_WATER &&
distance <= MAX_DISTANCE_TO_WATER && hasLOS)
{
SET_AI_VALUE(WorldPosition, "fishing spot", WorldPosition(WorldPosition(bot->GetMapId(), bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ())));
return false;
}
// Water spot is out of range, lets look for a spot to move to for the fishing hole.
if (distance > MAX_DISTANCE_TO_WATER || distance < MIN_DISTANCE_TO_WATER)
{
float angle = bot->GetAngle(fishingHole.GetPositionX(), fishingHole.GetPositionY());
WorldPosition landSpot = FindLandRadialFromPosition(botAI, fishingHole, MIN_DISTANCE_TO_WATER, MAX_DISTANCE_TO_WATER, SEARCH_INCREMENT, fishingSearchWindow, 32);
if (landSpot.IsValid())
{
SET_AI_VALUE(WorldPosition, "fishing spot", landSpot);
return true;
}
}
}
// Can the bot fish from current position?
WorldPosition waterAtCurrentPos =
FindWaterRadial(bot, bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ(), bot->GetMap(),
bot->GetPhaseMask(), MIN_DISTANCE_TO_WATER, MAX_DISTANCE_TO_WATER, SEARCH_INCREMENT, true);
if (waterAtCurrentPos.IsValid())
{
SET_AI_VALUE(WorldPosition, "fishing spot",
WorldPosition(WorldPosition(bot->GetMapId(), bot->GetPositionX(), bot->GetPositionY(),
bot->GetPositionZ())));
return false;
}
// Lets find some water where we can fish.
WorldPosition water = FindWaterRadial(
bot, bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ(),
bot->GetMap(), bot->GetPhaseMask(),
MIN_DISTANCE_TO_WATER,
fishingSearchWindow + MAX_DISTANCE_TO_WATER,
SEARCH_INCREMENT, false);
if (!water.IsValid())
return false;
bool hasLOS = bot->IsWithinLOS(water.GetPositionX(), water.GetPositionY(), water.GetPositionZ());
float angle = bot->GetAngle(water.GetPositionX(), water.GetPositionY());
WorldPosition landSpot =
FindLandFromPosition(botAI, 0.0f, MAX_DISTANCE_TO_WATER, 1.0f, angle, water, fishingSearchWindow, false);
if (landSpot.IsValid())
{
SET_AI_VALUE(WorldPosition, "fishing spot", landSpot);
return true;
}
return false;
}
bool EquipFishingPoleAction::Execute(Event event)
{
if (!_pole)
return false;
WorldPacket eqPacket(CMSG_AUTOEQUIP_ITEM_SLOT, 2);
eqPacket << _pole->GetGUID() << uint8(EQUIPMENT_SLOT_MAINHAND);
WorldPackets::Item::AutoEquipItemSlot nicePacket(std::move(eqPacket));
nicePacket.Read();
bot->GetSession()->HandleAutoEquipItemSlotOpcode(nicePacket);
return true;
}
bool EquipFishingPoleAction::isUseful()
{
Item* mainHand = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND);
if (IsFishingPole(mainHand))
return false;
for (uint8 slot = INVENTORY_SLOT_ITEM_START; slot < INVENTORY_SLOT_ITEM_END; ++slot)
{
if (Item* item = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, slot))
{
if (IsFishingPole(item))
{
_pole = item;
return true;
}
}
}
for (uint8 bag = INVENTORY_SLOT_BAG_START; bag < INVENTORY_SLOT_BAG_END; ++bag)
{
if (Bag* pBag = bot->GetBagByPos(bag))
{
for (uint32 j = 0; j < pBag->GetBagSize(); ++j)
{
if (Item* item = pBag->GetItemByPos(j))
{
if (IsFishingPole(item))
{
_pole = item;
return true;
}
}
}
}
}
if (sRandomPlayerbotMgr->IsRandomBot(bot))
{
bot->StoreNewItemInBestSlots(FISHING_POLE, 1); // Try to get a fishing pole
return true;
}
Player* master = botAI->GetMaster();
if (!master)
return false;
std::string masterName = master->GetName();
std::string text = sPlayerbotTextMgr->GetBotTextOrDefault(
"no_fishing_pole_error", "I don't have a Fishing Pole",{});
botAI->Whisper(text, masterName);
return false;
}
bool FishingAction::Execute(Event event)
{
WorldPosition target = WorldPosition();
WorldPosition fishingHole = FindFishingHole(botAI);
if (fishingHole.IsValid())
{
Position pos = fishingHole;
float distance = bot->GetExactDist2d(&pos);
bool hasLOS = bot->IsWithinLOS(fishingHole.GetPositionX(), fishingHole.GetPositionY(), fishingHole.GetPositionZ());
if (distance < MAX_DISTANCE_TO_WATER &&
distance > MIN_DISTANCE_TO_WATER && hasLOS)
target = fishingHole;
}
if (!target.IsValid())
{
target = FindWaterRadial(bot, bot->GetPositionX(), bot->GetPositionY(),
bot->GetPositionZ(), bot->GetMap(), bot->GetPhaseMask(),
MIN_DISTANCE_TO_WATER, MAX_DISTANCE_TO_WATER, SEARCH_INCREMENT, true, 32);
if (!target.IsValid())
return false;
}
Position pos = target;
if (!bot->HasInArc(1.0, &pos, 1.0))
{
float angle = bot->GetAngle(pos.GetPositionX(), pos.GetPositionY());
bot->SetOrientation(angle);
if (!bot->IsRooted())
bot->SendMovementFlagUpdate();
}
EquipFishingPoleAction equipAction(botAI);
if (equipAction.isUseful())
return equipAction.Execute(event);
botAI->CastSpell(FISHING_SPELL, bot);
botAI->ChangeStrategy("+use bobber", BOT_STATE_NON_COMBAT);
return true;
}
bool FishingAction::isUseful()
{
if (!AI_VALUE(bool, "can fish"))
return false;
FishingSpotValue* fishingSpotValueObject = (FishingSpotValue*)context->GetValue<WorldPosition>("fishing spot");
WorldPosition pos = fishingSpotValueObject->Get();
if (!pos.IsValid() || fishingSpotValueObject->IsStale(FISHING_LOCATION_TIMEOUT))
return false;
return bot->GetExactDist(&pos) < 0.1f;
}
bool UseBobberAction::isUseful()
{
return AI_VALUE(bool, "can use fishing bobber");
}
bool UseBobberAction::Execute(Event event)
{
GuidVector gos = AI_VALUE(GuidVector, "nearest game objects no los");
for (auto const& guid : gos)
{
if (GameObject* go = botAI->GetGameObject(guid))
{
if (go->GetEntry() != FISHING_BOBBER)
continue;
if (go->GetOwnerGUID() != bot->GetGUID())
continue;
if (go->getLootState() == GO_READY)
{
go->Use(bot);
botAI->ChangeStrategy("-use bobber", BOT_STATE_NON_COMBAT);
return true;
}
}
}
return false;
}
bool EndMasterFishingAction::Execute(Event event)
{
botAI->ChangeStrategy("-master fishing", BOT_STATE_NON_COMBAT);
return true;
}
bool EndMasterFishingAction::isUseful()
{
FishingSpotValue* fishingSpotValueObject = (FishingSpotValue*)context->GetValue<WorldPosition>("fishing spot");
WorldPosition pos = fishingSpotValueObject->Get();
if (pos.IsValid() && !fishingSpotValueObject->IsStale(FISHING_LOCATION_TIMEOUT) && pos == bot->GetPosition())
return false;
WorldPosition nearWater = FindWaterRadial(bot, bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ(),
bot->GetMap(), bot->GetPhaseMask(), MIN_DISTANCE_TO_WATER, sPlayerbotAIConfig->endFishingWithMaster, 10.0f);
return !nearWater.IsValid();
}
bool RemoveBobberStrategyAction::Execute(Event event)
{
botAI->ChangeStrategy("-use bobber", BOT_STATE_NON_COMBAT);
return true;
}

View File

@@ -1,71 +0,0 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
* and/or modify it under version 3 of the License, or (at your option), any later version.
*/
#ifndef _PLAYERBOT_FISHINGACTION_H
#define _PLAYERBOT_FISHINGACTION_H
#include "Action.h"
#include "MovementActions.h"
#include "Event.h"
#include "Playerbots.h"
extern const uint32 FISHING_SPELL;
extern const uint32 FISHING_POLE;
extern const uint32 FISHING_BOBBER;
WorldPosition FindWaterRadial(Player* bot, float x, float y, float z, Map* map, uint32 phaseMask, float minDistance, float maxDistance, float increment, bool checkLOS=false, int numDirections = 16);
class PlayerbotAI;
class FishingAction : public Action
{
public:
FishingAction(PlayerbotAI* botAI) : Action(botAI, "go fishing"){}
bool Execute(Event event) override;
bool isUseful() override;
};
class EquipFishingPoleAction : public Action
{
public:
EquipFishingPoleAction(PlayerbotAI* botAI) : Action(botAI, "equip fishing pole") {}
bool Execute(Event event) override;
bool isUseful() override;
private:
Item* _pole = nullptr;
};
class MoveNearWaterAction : public MovementAction
{
public:
MoveNearWaterAction(PlayerbotAI* botAI): MovementAction(botAI, "move near water") {}
bool Execute(Event event) override;
bool isUseful() override;
bool isPossible() override;
};
class UseBobberAction : public Action
{
public:
UseBobberAction(PlayerbotAI* botAI) : Action(botAI, "use fishing bobber") {}
bool Execute(Event event) override;
bool isUseful() override;
};
class EndMasterFishingAction : public Action
{
public:
EndMasterFishingAction(PlayerbotAI* botAI) : Action(botAI, "end master fishing") {}
bool Execute(Event event) override;
bool isUseful() override;
};
class RemoveBobberStrategyAction : public Action
{
public:
RemoveBobberStrategyAction(PlayerbotAI* botAI) : Action(botAI, "remove bobber strategy") {}
bool Execute(Event event) override;
};
#endif

View File

@@ -1,228 +0,0 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
* and/or modify it under version 3 of the License, or (at your option), any later version.
*/
#include "GenericActions.h"
#include "PlayerbotAI.h"
#include "Player.h"
#include "Pet.h"
#include "PlayerbotAIConfig.h"
#include "CreatureAI.h"
#include "Playerbots.h"
#include "CharmInfo.h"
#include "SharedDefines.h"
#include "ObjectGuid.h"
#include "SpellMgr.h"
#include "SpellInfo.h"
#include <vector>
#include <algorithm>
enum PetSpells
{
PET_PROWL_1 = 24450,
PET_PROWL_2 = 24452,
PET_PROWL_3 = 24453,
PET_COWER = 1742,
PET_LEAP = 47482,
PET_SPELL_LOCK_1 = 19244,
PET_SPELL_LOCK_2 = 19647,
PET_DEVOUR_MAGIC_1 = 19505,
PET_DEVOUR_MAGIC_2 = 19731,
PET_DEVOUR_MAGIC_3 = 19734,
PET_DEVOUR_MAGIC_4 = 19736,
PET_DEVOUR_MAGIC_5 = 27276,
PET_DEVOUR_MAGIC_6 = 27277,
PET_DEVOUR_MAGIC_7 = 48011,
PET_SPIRIT_WOLF_LEAP = 58867
};
static std::vector<uint32> disabledPetSpells = {
PET_PROWL_1, PET_PROWL_2, PET_PROWL_3,
PET_COWER, PET_LEAP,
PET_SPELL_LOCK_1, PET_SPELL_LOCK_2,
PET_DEVOUR_MAGIC_1, PET_DEVOUR_MAGIC_2, PET_DEVOUR_MAGIC_3,
PET_DEVOUR_MAGIC_4, PET_DEVOUR_MAGIC_5, PET_DEVOUR_MAGIC_6, PET_DEVOUR_MAGIC_7, PET_SPIRIT_WOLF_LEAP
};
bool MeleeAction::isUseful()
{
// do not allow if can't attack from vehicle
if (botAI->IsInVehicle() && !botAI->IsInVehicle(false, false, true))
return false;
return true;
}
bool TogglePetSpellAutoCastAction::Execute(Event event)
{
Pet* pet = bot->GetPet();
if (!pet)
{
return false;
}
// hack on high level spell after low level initialization
std::vector<unsigned int> shouldRemove;
for (unsigned int& m_autospell : pet->m_autospells)
{
if (!pet->HasSpell(m_autospell))
{
shouldRemove.push_back(m_autospell);
}
}
for (unsigned int spellId : shouldRemove)
{
auto autospellItr = std::find(pet->m_autospells.begin(), pet->m_autospells.end(), spellId);
if (autospellItr != pet->m_autospells.end())
pet->m_autospells.erase(autospellItr);
}
bool toggled = false;
for (PetSpellMap::const_iterator itr = pet->m_spells.begin(); itr != pet->m_spells.end(); ++itr)
{
if (itr->second.state == PETSPELL_REMOVED)
continue;
uint32 spellId = itr->first;
const SpellInfo* spellInfo = sSpellMgr->GetSpellInfo(spellId);
if (!spellInfo->IsAutocastable())
continue;
bool shouldApply = true;
for (uint32 disabledSpell : disabledPetSpells)
{
if (spellId == disabledSpell)
{
shouldApply = false;
break;
}
}
bool isAutoCast = false;
for (unsigned int& m_autospell : pet->m_autospells)
{
if (m_autospell == spellId)
{
isAutoCast = true;
break;
}
}
if (shouldApply != isAutoCast)
{
pet->ToggleAutocast(spellInfo, shouldApply);
toggled = true;
}
}
// Debug message if pet spells have been toggled and debug is enabled
if (toggled && sPlayerbotAIConfig->petChatCommandDebug == 1)
botAI->TellMaster("Pet autocast spells have been toggled.");
return toggled;
}
bool PetAttackAction::Execute(Event event)
{
Guardian* pet = bot->GetGuardianPet();
if (!pet)
return false;
// Do not attack if the pet's stance is set to "passive".
if (pet->GetReactState() == REACT_PASSIVE)
return false;
Unit* target = AI_VALUE(Unit*, "current target");
if (!target)
return false;
if (!bot->IsValidAttackTarget(target))
return false;
// This section has been commented because it was overriding the
// pet's stance to "passive" every time the attack action was executed.
// pet->SetReactState(REACT_PASSIVE);
pet->ClearUnitState(UNIT_STATE_FOLLOW);
pet->AttackStop();
pet->SetTarget(target->GetGUID());
pet->GetCharmInfo()->SetIsCommandAttack(true);
pet->GetCharmInfo()->SetIsAtStay(false);
pet->GetCharmInfo()->SetIsFollowing(false);
pet->GetCharmInfo()->SetIsCommandFollow(false);
pet->GetCharmInfo()->SetIsReturning(false);
pet->ToCreature()->AI()->AttackStart(target);
return true;
}
bool SetPetStanceAction::Execute(Event /*event*/)
{
// Prepare a list to hold all controlled pet and guardian creatures
std::vector<Creature*> targets;
// Add the bot's main pet (if it exists) to the target list
Pet* pet = bot->GetPet();
if (pet)
targets.push_back(pet);
// Loop through all units controlled by the bot (could be pets, guardians, etc.)
for (Unit::ControlSet::const_iterator itr = bot->m_Controlled.begin(); itr != bot->m_Controlled.end(); ++itr)
{
// Only add creatures (skip players, vehicles, etc.)
Creature* creature = dynamic_cast<Creature*>(*itr);
if (!creature)
continue;
// Avoid adding the main pet twice
if (pet && creature == pet)
continue;
targets.push_back(creature);
}
// If there are no controlled pets or guardians, notify the player and exit
if (targets.empty())
{
botAI->TellError("You have no pet or guardian pet.");
return false;
}
// Get the default pet stance from the configuration
int32 stance = sPlayerbotAIConfig->defaultPetStance;
ReactStates react = REACT_DEFENSIVE;
std::string stanceText = "defensive (from config, fallback)";
// Map the config stance integer to a ReactStates value and a message
switch (stance)
{
case 0:
react = REACT_PASSIVE;
stanceText = "passive (from config)";
break;
case 1:
react = REACT_DEFENSIVE;
stanceText = "defensive (from config)";
break;
case 2:
react = REACT_AGGRESSIVE;
stanceText = "aggressive (from config)";
break;
default:
react = REACT_DEFENSIVE;
stanceText = "defensive (from config, fallback)";
break;
}
// Apply the stance to all target creatures (pets/guardians)
for (Creature* target : targets)
{
target->SetReactState(react);
CharmInfo* charmInfo = target->GetCharmInfo();
// If the creature has a CharmInfo, set the player-visible stance as well
if (charmInfo)
charmInfo->SetPlayerReactState(react);
}
// If debug is enabled in config, inform the master of the new stance
if (sPlayerbotAIConfig->petChatCommandDebug == 1)
botAI->TellMaster("Pet stance set to " + stanceText + " (applied to all pets/guardians).");
return true;
}

View File

@@ -1,145 +0,0 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
* and/or modify it under version 3 of the License, or (at your option), any later version.
*/
#include "GenericBuffUtils.h"
#include "PlayerbotAIConfig.h"
#include <map>
#include "Player.h"
#include "Group.h"
#include "SpellMgr.h"
#include "Chat.h"
#include "PlayerbotAI.h"
#include "ServerFacade.h"
#include "AiObjectContext.h"
#include "Value.h"
#include "Config.h"
#include "PlayerbotTextMgr.h"
namespace ai::buff
{
std::string MakeAuraQualifierForBuff(std::string const& name)
{
// Paladin
if (name == "blessing of kings") return "blessing of kings,greater blessing of kings";
if (name == "blessing of might") return "blessing of might,greater blessing of might";
if (name == "blessing of wisdom") return "blessing of wisdom,greater blessing of wisdom";
if (name == "blessing of sanctuary") return "blessing of sanctuary,greater blessing of sanctuary";
// Druid
if (name == "mark of the wild") return "mark of the wild,gift of the wild";
// Mage
if (name == "arcane intellect") return "arcane intellect,arcane brilliance";
// Priest
if (name == "power word: fortitude") return "power word: fortitude,prayer of fortitude";
return name;
}
std::string GroupVariantFor(std::string const& name)
{
// Paladin
if (name == "blessing of kings") return "greater blessing of kings";
if (name == "blessing of might") return "greater blessing of might";
if (name == "blessing of wisdom") return "greater blessing of wisdom";
if (name == "blessing of sanctuary") return "greater blessing of sanctuary";
// Druid
if (name == "mark of the wild") return "gift of the wild";
// Mage
if (name == "arcane intellect") return "arcane brilliance";
// Priest
if (name == "power word: fortitude") return "prayer of fortitude";
return std::string();
}
bool HasRequiredReagents(Player* bot, uint32 spellId)
{
if (!spellId)
return false;
if (SpellInfo const* info = sSpellMgr->GetSpellInfo(spellId))
{
for (int i = 0; i < MAX_SPELL_REAGENTS; ++i)
{
if (info->Reagent[i] > 0)
{
uint32 const itemId = info->Reagent[i];
int32 const need = info->ReagentCount[i];
if ((int32)bot->GetItemCount(itemId, false) < need)
return false;
}
}
// No reagent required
return true;
}
return false;
}
std::string UpgradeToGroupIfAppropriate(
Player* bot,
PlayerbotAI* botAI,
std::string const& baseName,
bool announceOnMissing,
std::function<void(std::string const&)> announce)
{
std::string castName = baseName;
Group* g = bot->GetGroup();
if (!g || g->GetMembersCount() < static_cast<uint32>(sPlayerbotAIConfig->minBotsForGreaterBuff))
return castName; // Group too small: stay in solo mode
if (std::string const groupName = GroupVariantFor(baseName); !groupName.empty())
{
uint32 const groupVariantSpellId = botAI->GetAiObjectContext()
->GetValue<uint32>("spell id", groupName)->Get();
// We check usefulness on the **basic** buff (not the greater version),
// because "spell cast useful" may return false for the greater variant.
bool const usefulBase = botAI->GetAiObjectContext()
->GetValue<bool>("spell cast useful", baseName)->Get();
if (groupVariantSpellId && HasRequiredReagents(bot, groupVariantSpellId))
{
// Learned + reagents OK -> switch to greater
return groupName;
}
// Missing reagents -> announce if (a) greater is known, (b) base buff is useful,
// (c) announce was requested, (d) a callback is provided.
if (announceOnMissing && groupVariantSpellId && usefulBase && announce)
{
static std::map<std::pair<uint32, std::string>, time_t> s_lastWarn; // par bot & par buff
time_t now = std::time(nullptr);
uint32 botLow = static_cast<uint32>(bot->GetGUID().GetCounter());
time_t& last = s_lastWarn[ std::make_pair(botLow, groupName) ];
if (!last || now - last >= sPlayerbotAIConfig->rpWarningCooldown) // Configurable anti-spam
{
// DB Key choice in regard of the buff
std::string key;
if (groupName.find("greater blessing") != std::string::npos)
key = "rp_missing_reagent_greater_blessing";
else if (groupName == "gift of the wild")
key = "rp_missing_reagent_gift_of_the_wild";
else if (groupName == "arcane brilliance")
key = "rp_missing_reagent_arcane_brilliance";
else
key = "rp_missing_reagent_generic";
// Placeholders
std::map<std::string, std::string> placeholders;
placeholders["%group_spell"] = groupName;
placeholders["%base_spell"] = baseName;
std::string announceText = sPlayerbotTextMgr->GetBotTextOrDefault(key,
"Out of components for %group_spell. Using %base_spell!", placeholders);
announce(announceText);
last = now;
}
}
}
return castName;
}
}

View File

@@ -1,63 +0,0 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
* and/or modify it under version 3 of the License, or (at your option), any later version.
*/
#pragma once
#include <string>
#include <functional>
#include "Common.h"
#include "Group.h"
#include "Chat.h"
#include "Language.h"
class Player;
class PlayerbotAI;
namespace ai::buff
{
// Build an aura qualifier "single + greater" to avoid double-buffing
std::string MakeAuraQualifierForBuff(std::string const& name);
// Returns the group spell name for a given single-target buff.
// If no group equivalent exists, returns "".
std::string GroupVariantFor(std::string const& name);
// Checks if the bot has the required reagents to cast a spell (by its spellId).
// Returns false if the spellId is invalid.
bool HasRequiredReagents(Player* bot, uint32 spellId);
// Applies the "switch to group buff" policy if: the bot is in a group of size x+,
// the group variant is known/useful, and reagents are available. Otherwise, returns baseName.
// If announceOnMissing == true and reagents are missing, calls the 'announce' callback
// (if provided) to notify the party/raid.
std::string UpgradeToGroupIfAppropriate(
Player* bot,
PlayerbotAI* botAI,
std::string const& baseName,
bool announceOnMissing = false,
std::function<void(std::string const&)> announce = {}
);
}
namespace ai::chat {
inline std::function<void(std::string const&)> MakeGroupAnnouncer(Player* me)
{
return [me](std::string const& msg)
{
if (Group* g = me->GetGroup())
{
WorldPacket data;
ChatMsg type = g->isRaidGroup() ? CHAT_MSG_RAID : CHAT_MSG_PARTY;
ChatHandler::BuildChatPacket(data, type, LANG_UNIVERSAL, me, /*receiver=*/nullptr, msg.c_str());
g->BroadcastPacket(&data, true, -1, me->GetGUID());
}
else
{
me->Say(msg, LANG_UNIVERSAL);
}
};
}
}

View File

@@ -1,462 +0,0 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
* and/or modify it under version 3 of the License, or (at your option), any later version.
*/
#include "InviteToGroupAction.h"
#include "BroadcastHelper.h"
#include "Event.h"
#include "GuildMgr.h"
#include "Log.h"
#include "PlayerbotOperations.h"
#include "Playerbots.h"
#include "PlayerbotWorldThreadProcessor.h"
#include "ServerFacade.h"
bool InviteToGroupAction::Invite(Player* inviter, Player* player)
{
if (!player)
return false;
if (inviter == player)
return false;
if (!GET_PLAYERBOT_AI(player) && !botAI->GetSecurity()->CheckLevelFor(PLAYERBOT_SECURITY_INVITE, true, player))
return false;
if (Group* group = inviter->GetGroup())
{
if (GET_PLAYERBOT_AI(player) && !GET_PLAYERBOT_AI(player)->IsRealPlayer())
if (!group->isRaidGroup() && group->GetMembersCount() > 4)
{
auto convertOp = std::make_unique<GroupConvertToRaidOperation>(inviter->GetGUID());
sPlayerbotWorldProcessor->QueueOperation(std::move(convertOp));
}
}
WorldPacket p;
uint32 roles_mask = 0;
p << player->GetName();
p << roles_mask;
inviter->GetSession()->HandleGroupInviteOpcode(p);
return true;
}
bool InviteNearbyToGroupAction::Execute(Event event)
{
GuidVector nearGuids = botAI->GetAiObjectContext()->GetValue<GuidVector>("nearest friendly players")->Get();
for (auto& i : nearGuids)
{
Player* player = ObjectAccessor::FindPlayer(i);
if (!player)
continue;
if (player == bot)
continue;
if (player->GetMapId() != bot->GetMapId())
continue;
if (player->GetGroup())
continue;
if (!sPlayerbotAIConfig->randomBotInvitePlayer && GET_PLAYERBOT_AI(player)->IsRealPlayer())
continue;
Group* group = bot->GetGroup();
if (player->isDND())
continue;
if (player->IsBeingTeleported())
continue;
PlayerbotAI* botAI = GET_PLAYERBOT_AI(bot);
if (botAI)
{
if (botAI->GetGrouperType() == GrouperType::SOLO &&
!botAI->HasRealPlayerMaster()) // Do not invite solo players.
continue;
if (botAI->HasActivePlayerMaster()) // Do not invite alts of active players.
continue;
}
if (abs(int32(player->GetLevel() - bot->GetLevel())) > 2)
continue;
if (sServerFacade->GetDistance2d(bot, player) > sPlayerbotAIConfig->sightDistance)
continue;
// When inviting the 5th member of the group convert to raid for future invites.
if (group && botAI->GetGrouperType() > GrouperType::LEADER_5 && !group->isRaidGroup() &&
bot->GetGroup()->GetMembersCount() > 3)
{
auto convertOp = std::make_unique<GroupConvertToRaidOperation>(bot->GetGUID());
sPlayerbotWorldProcessor->QueueOperation(std::move(convertOp));
}
if (sPlayerbotAIConfig->inviteChat && sRandomPlayerbotMgr->IsRandomBot(bot))
{
std::map<std::string, std::string> placeholders;
placeholders["%player"] = player->GetName();
if (group && group->isRaidGroup())
bot->Say(BOT_TEXT2("join_raid", placeholders),
(bot->GetTeamId() == TEAM_ALLIANCE ? LANG_COMMON : LANG_ORCISH));
else
bot->Say(BOT_TEXT2("join_group", placeholders),
(bot->GetTeamId() == TEAM_ALLIANCE ? LANG_COMMON : LANG_ORCISH));
}
return Invite(bot, player);
}
return false;
}
bool InviteNearbyToGroupAction::isUseful()
{
if (!sPlayerbotAIConfig->randomBotGroupNearby)
return false;
if (bot->InBattleground())
return false;
if (bot->InBattlegroundQueue())
return false;
GrouperType grouperType = botAI->GetGrouperType();
if (grouperType == GrouperType::SOLO || grouperType == GrouperType::MEMBER)
return false;
Group* group = bot->GetGroup();
if (group)
{
if (group->isRaidGroup() && group->IsFull())
return false;
if (botAI->GetGroupLeader() != bot)
return false;
uint32 memberCount = group->GetMembersCount();
if (memberCount >= uint8(grouperType))
return false;
}
if (botAI->HasActivePlayerMaster()) // Alts do not invite randomly
return false;
return true;
}
std::vector<Player*> InviteGuildToGroupAction::getGuildMembers()
{
Guild* guild = sGuildMgr->GetGuildById(bot->GetGuildId());
FindGuildMembers worker;
guild->BroadcastWorker(worker);
return worker.GetResult();
}
bool InviteGuildToGroupAction::Execute(Event event)
{
Guild* guild = sGuildMgr->GetGuildById(bot->GetGuildId());
for (auto& member : getGuildMembers())
{
Player* player = member;
if (!player)
continue;
if (player == bot)
continue;
if (player->GetGroup())
continue;
if (player->isDND())
continue;
if (!sPlayerbotAIConfig->randomBotInvitePlayer && GET_PLAYERBOT_AI(player)->IsRealPlayer())
continue;
if (player->IsBeingTeleported())
continue;
if (player->GetMapId() != bot->GetMapId() && player->GetLevel() < 30)
continue;
if (WorldPosition(player).distance(bot) > 1000 && player->GetLevel() < 15)
continue;
PlayerbotAI* playerAi = GET_PLAYERBOT_AI(player);
if (playerAi)
{
if (playerAi->GetGrouperType() == GrouperType::SOLO &&
!playerAi->HasRealPlayerMaster()) // Do not invite solo players.
continue;
if (playerAi->HasActivePlayerMaster()) // Do not invite alts of active players.
continue;
if (player->GetLevel() >
bot->GetLevel() + 5) // Invite higher levels that need money so they can grind money and help out.
{
if (!PAI_VALUE(bool, "should get money"))
continue;
}
}
if (bot->GetLevel() >
player->GetLevel() + 5) // Do not invite members that too low level or risk dragging them to deadly places.
continue;
if (!playerAi && sServerFacade->GetDistance2d(bot, player) > sPlayerbotAIConfig->sightDistance)
continue;
Group* group = bot->GetGroup();
// When inviting the 5th member of the group convert to raid for future invites.
if (group && botAI->GetGrouperType() > GrouperType::LEADER_5 && !group->isRaidGroup() &&
bot->GetGroup()->GetMembersCount() > 3)
{
auto convertOp = std::make_unique<GroupConvertToRaidOperation>(bot->GetGUID());
sPlayerbotWorldProcessor->QueueOperation(std::move(convertOp));
}
if (sPlayerbotAIConfig->inviteChat &&
(sRandomPlayerbotMgr->IsRandomBot(bot) || !botAI->HasActivePlayerMaster()))
{
BroadcastHelper::BroadcastGuildGroupOrRaidInvite(botAI, bot, player, group);
}
return Invite(bot, player);
}
return false;
}
bool JoinGroupAction::Execute(Event event)
{
if (bot->InBattleground())
return false;
if (bot->InBattlegroundQueue())
return false;
Player* master = event.getOwner();
Group* group = master->GetGroup();
if (group)
{
if (group->IsFull())
return false;
if (bot->GetGroup() == group)
return false;
}
if (bot->GetGroup())
{
if (botAI->HasRealPlayerMaster())
return false;
if (!botAI->DoSpecificAction("leave", event, true))
return false;
}
return Invite(master, bot);
}
bool LfgAction::Execute(Event event)
{
Player* requester = event.getOwner() ? event.getOwner() : GetMaster();
if (bot->InBattleground())
return false;
if (bot->InBattlegroundQueue())
return false;
if (!botAI->IsSafe(requester))
return false;
if (requester->GetLevel() == DEFAULT_MAX_LEVEL && bot->GetLevel() != DEFAULT_MAX_LEVEL)
return false;
if (requester->GetLevel() > bot->GetLevel() + 4 || bot->GetLevel() > requester->GetLevel() + 4)
return false;
std::string param = event.getParam();
if (!param.empty() && param != "40" && param != "25" && param != "20" && param != "10" && param != "5")
return false;
Group* group = requester->GetGroup();
std::unordered_map<Classes, std::unordered_map<BotRoles, uint32>> allowedClassNr;
std::unordered_map<BotRoles, uint32> allowedRoles;
allowedRoles[BOT_ROLE_TANK] = 1;
allowedRoles[BOT_ROLE_HEALER] = 1;
allowedRoles[BOT_ROLE_DPS] = 3;
BotRoles role = botAI->IsTank(requester, false)
? BOT_ROLE_TANK
: (botAI->IsHeal(requester, false) ? BOT_ROLE_HEALER : BOT_ROLE_DPS);
Classes cls = (Classes)requester->getClass();
if (group)
{
if (param.empty() && group->isRaidGroup())
// Default to WotLK Raiding. Max size 25
param = "25";
// Select optimal group layout.
if (param == "40")
{
allowedRoles[BOT_ROLE_TANK] = 4;
allowedRoles[BOT_ROLE_HEALER] = 16;
allowedRoles[BOT_ROLE_DPS] = 20;
/*
allowedClassNr[CLASS_PALADIN][BOT_ROLE_TANK] = 0;
allowedClassNr[CLASS_DRUID][BOT_ROLE_TANK] = 1;
allowedClassNr[CLASS_DRUID][BOT_ROLE_HEALER] = 3;
allowedClassNr[CLASS_PALADIN][BOT_ROLE_HEALER] = 4;
allowedClassNr[CLASS_SHAMAN][BOT_ROLE_HEALER] = 4;
allowedClassNr[CLASS_PRIEST][BOT_ROLE_HEALER] = 11;
allowedClassNr[CLASS_WARRIOR][BOT_ROLE_DPS] = 8;
allowedClassNr[CLASS_PALADIN][BOT_ROLE_DPS] = 4;
allowedClassNr[CLASS_HUNTER][BOT_ROLE_DPS] = 4;
allowedClassNr[CLASS_ROGUE][BOT_ROLE_DPS] = 6;
allowedClassNr[CLASS_PRIEST][BOT_ROLE_DPS] = 1;
allowedClassNr[CLASS_SHAMAN][BOT_ROLE_DPS] = 4;
allowedClassNr[CLASS_MAGE][BOT_ROLE_DPS] = 15;
allowedClassNr[CLASS_WARLOCK][BOT_ROLE_DPS] = 4;
allowedClassNr[CLASS_DRUID][BOT_ROLE_DPS] = 1;
*/
}
else if (param == "25")
{
allowedRoles[BOT_ROLE_TANK] = 3;
allowedRoles[BOT_ROLE_HEALER] = 7;
allowedRoles[BOT_ROLE_DPS] = 15;
}
else if (param == "20")
{
allowedRoles[BOT_ROLE_TANK] = 2;
allowedRoles[BOT_ROLE_HEALER] = 5;
allowedRoles[BOT_ROLE_DPS] = 13;
}
else if (param == "10")
{
allowedRoles[BOT_ROLE_TANK] = 2;
allowedRoles[BOT_ROLE_HEALER] = 3;
allowedRoles[BOT_ROLE_DPS] = 5;
}
if (group->IsFull())
{
if (param.empty() || param == "5" || group->isRaidGroup())
return false; // Group or raid is full so stop trying.
else
{
auto convertOp = std::make_unique<GroupConvertToRaidOperation>(requester->GetGUID());
sPlayerbotWorldProcessor->QueueOperation(std::move(convertOp));
}
}
Group::MemberSlotList const& groupSlot = group->GetMemberSlots();
for (Group::member_citerator itr = groupSlot.begin(); itr != groupSlot.end(); itr++)
{
// Only add group member targets that are alive and near the player
Player* player = ObjectAccessor::FindPlayer(itr->guid);
if (!botAI->IsSafe(player))
return false;
role = botAI->IsTank(player, false) ? BOT_ROLE_TANK
: (botAI->IsHeal(player, false) ? BOT_ROLE_HEALER : BOT_ROLE_DPS);
cls = (Classes)player->getClass();
if (allowedRoles[role] > 0)
allowedRoles[role]--;
if (allowedClassNr[cls].find(role) != allowedClassNr[cls].end() && allowedClassNr[cls][role] > 0)
allowedClassNr[cls][role]--;
}
}
else
{
if (allowedRoles[role] > 0)
allowedRoles[role]--;
if (allowedClassNr[cls].find(role) != allowedClassNr[cls].end() && allowedClassNr[cls][role] > 0)
allowedClassNr[cls][role]--;
}
role = botAI->IsTank(bot, false) ? BOT_ROLE_TANK : (botAI->IsHeal(bot, false) ? BOT_ROLE_HEALER : BOT_ROLE_DPS);
cls = (Classes)bot->getClass();
if (allowedRoles[role] == 0)
return false;
if (allowedClassNr[cls].find(role) != allowedClassNr[cls].end() && allowedClassNr[cls][role] == 0)
return false;
if (bot->GetGroup())
{
if (botAI->HasRealPlayerMaster())
return false;
if (!botAI->DoSpecificAction("leave", event, true))
return false;
}
bool invite = Invite(requester, bot);
if (invite)
{
Event acceptEvent("accept invitation", requester ? requester->GetGUID() : ObjectGuid::Empty);
if (!botAI->DoSpecificAction("accept invitation", acceptEvent, true))
return false;
std::map<std::string, std::string> placeholders;
placeholders["%role"] = (role & BOT_ROLE_TANK ? "tank" : (role & BOT_ROLE_HEALER ? "healer" : "dps"));
placeholders["%spotsleft"] = std::to_string(allowedRoles[role] - 1);
std::ostringstream out;
if (allowedRoles[role] > 1)
{
out << "Joining as " << placeholders["%role"] << ", " << placeholders["%spotsleft"] << " "
<< placeholders["%role"] << " spots left.";
botAI->TellMasterNoFacing(out.str());
//botAI->DoSpecificAction("autogear");
//botAI->DoSpecificAction("maintenance");
}
else
{
out << "Joining as " << placeholders["%role"] << ".";
botAI->TellMasterNoFacing(out.str());
//botAI->DoSpecificAction("autogear");
//botAI->DoSpecificAction("maintenance");
}
return true;
}
return false;
}

View File

@@ -1,307 +0,0 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
* and/or modify it under version 3 of the License, or (at your option), any later version.
*/
#include "PetsAction.h"
#include "CharmInfo.h"
#include "Creature.h"
#include "CreatureAI.h"
#include "Pet.h"
#include "Player.h"
#include "PlayerbotAI.h"
#include "SharedDefines.h"
bool PetsAction::Execute(Event event)
{
// Extract the command parameter from the event (e.g., "aggressive", "defensive", "attack", etc.)
std::string param = event.getParam();
if (param.empty() && !defaultCmd.empty())
param = defaultCmd;
if (param.empty())
{
// If no parameter is provided, show usage instructions and return.
std::string text = sPlayerbotTextMgr->GetBotTextOrDefault(
"pet_usage_error", "Usage: pet <aggressive|defensive|passive|stance|attack|follow|stay>", {});
botAI->TellError(text);
return false;
}
Player* bot = botAI->GetBot();
// Collect all controlled pets and guardians, except totems, into the targets vector.
std::vector<Creature*> targets;
Pet* pet = bot->GetPet();
if (pet)
targets.push_back(pet);
for (Unit::ControlSet::const_iterator itr = bot->m_Controlled.begin(); itr != bot->m_Controlled.end(); ++itr)
{
Creature* creature = dynamic_cast<Creature*>(*itr);
if (!creature)
continue;
if (pet && creature == pet)
continue;
if (creature->IsTotem())
continue;
targets.push_back(creature);
}
// If no pets or guardians are found, notify and return.
if (targets.empty())
{
std::string text = sPlayerbotTextMgr->GetBotTextOrDefault(
"pet_no_pet_error", "You have no pet or guardian pet.", {});
botAI->TellError(text);
return false;
}
ReactStates react;
std::string stanceText;
// Handle stance commands: aggressive, defensive, or passive.
if (param == "aggressive")
{
react = REACT_AGGRESSIVE;
stanceText = sPlayerbotTextMgr->GetBotTextOrDefault(
"pet_stance_aggressive", "aggressive", {});
}
else if (param == "defensive")
{
react = REACT_DEFENSIVE;
stanceText = sPlayerbotTextMgr->GetBotTextOrDefault(
"pet_stance_defensive", "defensive", {});
}
else if (param == "passive")
{
react = REACT_PASSIVE;
stanceText = sPlayerbotTextMgr->GetBotTextOrDefault(
"pet_stance_passive", "passive", {});
}
// The "stance" command simply reports the current stance of each pet/guardian.
else if (param == "stance")
{
for (Creature* target : targets)
{
std::string type = target->IsPet() ?
sPlayerbotTextMgr->GetBotTextOrDefault("pet_type_pet", "pet", {}) :
sPlayerbotTextMgr->GetBotTextOrDefault("pet_type_guardian", "guardian", {});
std::string name = target->GetName();
std::string stance;
switch (target->GetReactState())
{
case REACT_AGGRESSIVE:
stance = sPlayerbotTextMgr->GetBotTextOrDefault(
"pet_stance_aggressive", "aggressive", {});
break;
case REACT_DEFENSIVE:
stance = sPlayerbotTextMgr->GetBotTextOrDefault(
"pet_stance_defensive", "defensive", {});
break;
case REACT_PASSIVE:
stance = sPlayerbotTextMgr->GetBotTextOrDefault(
"pet_stance_passive", "passive", {});
break;
default:
stance = sPlayerbotTextMgr->GetBotTextOrDefault(
"pet_stance_unknown", "unknown", {});
break;
}
std::string text = sPlayerbotTextMgr->GetBotTextOrDefault(
"pet_stance_report", "Current stance of %type \"%name\": %stance.",
{{"type", type}, {"name", name}, {"stance", stance}});
botAI->TellMaster(text);
}
return true;
}
// The "attack" command forces pets/guardians to attack the master's selected target.
else if (param == "attack")
{
// Try to get the master's selected target.
Player* master = botAI->GetMaster();
Unit* targetUnit = nullptr;
if (master)
{
ObjectGuid masterTargetGuid = master->GetTarget();
if (!masterTargetGuid.IsEmpty())
targetUnit = botAI->GetUnit(masterTargetGuid);
}
// If no valid target is selected, show an error and return.
if (!targetUnit)
{
std::string text = sPlayerbotTextMgr->GetBotTextOrDefault(
"pet_no_target_error", "No valid target selected by master.", {});
botAI->TellError(text);
return false;
}
if (!targetUnit->IsAlive())
{
std::string text = sPlayerbotTextMgr->GetBotTextOrDefault(
"pet_target_dead_error", "Target is not alive.", {});
botAI->TellError(text);
return false;
}
if (!bot->IsValidAttackTarget(targetUnit))
{
std::string text = sPlayerbotTextMgr->GetBotTextOrDefault(
"pet_invalid_target_error", "Target is not a valid attack target for the bot.", {});
botAI->TellError(text);
return false;
}
if (sPlayerbotAIConfig->IsPvpProhibited(bot->GetZoneId(), bot->GetAreaId()) &&
(targetUnit->IsPlayer() || targetUnit->IsPet()) &&
(!bot->duel || bot->duel->Opponent != targetUnit))
{
std::string text = sPlayerbotTextMgr->GetBotTextOrDefault(
"pet_pvp_prohibited_error", "I cannot command my pet to attack players in PvP prohibited areas.", {});
botAI->TellError(text);
return false;
}
bool didAttack = false;
// For each controlled pet/guardian, command them to attack the selected target.
for (Creature* petCreature : targets)
{
CharmInfo* charmInfo = petCreature->GetCharmInfo();
if (!charmInfo)
continue;
petCreature->ClearUnitState(UNIT_STATE_FOLLOW);
// Only command attack if not already attacking the target, or if not currently under command attack.
if (petCreature->GetVictim() != targetUnit ||
(petCreature->GetVictim() == targetUnit && !charmInfo->IsCommandAttack()))
{
if (petCreature->GetVictim())
petCreature->AttackStop();
if (!petCreature->IsPlayer() && petCreature->ToCreature()->IsAIEnabled)
{
// For AI-enabled creatures (NPC pets/guardians): issue attack command and set flags.
charmInfo->SetIsCommandAttack(true);
charmInfo->SetIsAtStay(false);
charmInfo->SetIsFollowing(false);
charmInfo->SetIsCommandFollow(false);
charmInfo->SetIsReturning(false);
petCreature->ToCreature()->AI()->AttackStart(targetUnit);
didAttack = true;
}
else // For charmed player pets/guardians
{
if (petCreature->GetVictim() && petCreature->GetVictim() != targetUnit)
petCreature->AttackStop();
charmInfo->SetIsCommandAttack(true);
charmInfo->SetIsAtStay(false);
charmInfo->SetIsFollowing(false);
charmInfo->SetIsCommandFollow(false);
charmInfo->SetIsReturning(false);
petCreature->Attack(targetUnit, true);
didAttack = true;
}
}
}
// Inform the master if the command succeeded or failed.
if (didAttack && sPlayerbotAIConfig->petChatCommandDebug == 1)
{
std::string text = sPlayerbotTextMgr->GetBotTextOrDefault(
"pet_attack_success", "Pet commanded to attack your target.", {});
botAI->TellMaster(text);
}
else if (!didAttack)
{
std::string text = sPlayerbotTextMgr->GetBotTextOrDefault(
"pet_attack_failed", "Pet did not attack. (Already attacking or unable to attack target)", {});
botAI->TellError(text);
}
return didAttack;
}
// The "follow" command makes all pets/guardians follow the bot.
else if (param == "follow")
{
botAI->PetFollow();
if (sPlayerbotAIConfig->petChatCommandDebug == 1)
{
std::string text = sPlayerbotTextMgr->GetBotTextOrDefault(
"pet_follow_success", "Pet commanded to follow.", {});
botAI->TellMaster(text);
}
return true;
}
// The "stay" command causes all pets/guardians to stop and stay in place.
else if (param == "stay")
{
for (Creature* target : targets)
{
// If not already in controlled motion, stop movement and set to idle.
bool controlledMotion =
target->GetMotionMaster()->GetMotionSlotType(MOTION_SLOT_CONTROLLED) != NULL_MOTION_TYPE;
if (!controlledMotion)
{
target->StopMovingOnCurrentPos();
target->GetMotionMaster()->Clear(false);
target->GetMotionMaster()->MoveIdle();
}
CharmInfo* charmInfo = target->GetCharmInfo();
if (charmInfo)
{
// Set charm/pet state flags for "stay".
charmInfo->SetCommandState(COMMAND_STAY);
charmInfo->SetIsCommandAttack(false);
charmInfo->SetIsCommandFollow(false);
charmInfo->SetIsFollowing(false);
charmInfo->SetIsReturning(false);
charmInfo->SetIsAtStay(!controlledMotion);
charmInfo->SaveStayPosition(controlledMotion);
if (target->ToPet())
target->ToPet()->ClearCastWhenWillAvailable();
charmInfo->SetForcedSpell(0);
charmInfo->SetForcedTargetGUID();
}
}
if (sPlayerbotAIConfig->petChatCommandDebug == 1)
{
std::string text = sPlayerbotTextMgr->GetBotTextOrDefault(
"pet_stay_success", "Pet commanded to stay.", {});
botAI->TellMaster(text);
}
return true;
}
// Unknown command: show usage instructions and return.
else
{
std::string text = sPlayerbotTextMgr->GetBotTextOrDefault(
"pet_unknown_command_error", "Unknown pet command: %param. Use: pet <aggressive|defensive|passive|stance|attack|follow|stay>",
{{"param", param}});
botAI->TellError(text);
return false;
}
// For stance commands, apply the chosen stance to all targets.
for (Creature* target : targets)
{
target->SetReactState(react);
CharmInfo* charmInfo = target->GetCharmInfo();
if (charmInfo)
charmInfo->SetPlayerReactState(react);
}
// Inform the master of the new stance if debug is enabled.
if (sPlayerbotAIConfig->petChatCommandDebug == 1)
{
std::string text = sPlayerbotTextMgr->GetBotTextOrDefault(
"pet_stance_set_success", "Pet stance set to %stance.",
{{"stance", stanceText}});
botAI->TellMaster(text);
}
return true;
}

View File

@@ -1,29 +0,0 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
* and/or modify it under version 3 of the License, or (at your option), any later version.
*/
#ifndef _PLAYERBOT_PETSACTION_H
#define _PLAYERBOT_PETSACTION_H
#include <string>
#include "Action.h"
#include "PlayerbotFactory.h"
#include "Unit.h"
class PlayerbotAI;
class PetsAction : public Action
{
public:
PetsAction(PlayerbotAI* botAI, const std::string& defaultCmd = "") : Action(botAI, "pet"), defaultCmd(defaultCmd) {}
bool Execute(Event event) override;
private:
bool warningEnabled = true;
std::string defaultCmd;
};
#endif

View File

@@ -1,500 +0,0 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
* and/or modify it under version 3 of the License, or (at your option), any later version.
*/
#include "TameAction.h"
#include <algorithm>
#include <cctype>
#include <iomanip>
#include <random>
#include <set>
#include <sstream>
#include "DBCStructure.h"
#include "Log.h"
#include "ObjectMgr.h"
#include "Pet.h"
#include "Player.h"
#include "PlayerbotAI.h"
#include "PlayerbotFactory.h"
#include "SpellMgr.h"
#include "WorldSession.h"
bool IsExoticPet(const CreatureTemplate* creature)
{
// Use the IsExotic() method from CreatureTemplate
return creature && creature->IsExotic();
}
bool HasBeastMastery(Player* bot)
{
// Beast Mastery talent aura ID for WotLK is 53270
return bot->HasAura(53270);
}
bool TameAction::Execute(Event event)
{
// Parse the user's input command into mode and value (e.g. "name wolf", "id 1234", etc.)
std::string param = event.getParam();
std::istringstream iss(param);
std::string mode, value;
iss >> mode;
std::getline(iss, value);
value.erase(0, value.find_first_not_of(" ")); // Remove leading spaces from value
bool found = false;
// Reset any previous pet name/id state
lastPetName = "";
lastPetId = 0;
// If the command is "family" with no value, list all available pet families
if (mode == "family" && value.empty())
{
std::set<std::string> normalFamilies;
std::set<std::string> exoticFamilies;
Player* bot = botAI->GetBot();
// Loop over all creature templates and collect tameable families
CreatureTemplateContainer const* creatures = sObjectMgr->GetCreatureTemplates();
for (auto itr = creatures->begin(); itr != creatures->end(); ++itr)
{
const CreatureTemplate& creature = itr->second;
if (!creature.IsTameable(true))
continue;
CreatureFamilyEntry const* familyEntry = sCreatureFamilyStore.LookupEntry(creature.family);
if (!familyEntry)
continue;
std::string familyName = familyEntry->Name[0];
if (familyName.empty())
continue;
if (creature.IsExotic())
exoticFamilies.insert(familyName);
else
normalFamilies.insert(familyName);
}
// Build the output message for the user
std::ostringstream oss;
oss << "Available pet families: ";
size_t count = 0;
for (auto const& name : normalFamilies)
{
if (count++ != 0)
oss << ", ";
oss << name;
}
if (!exoticFamilies.empty())
{
if (!normalFamilies.empty())
oss << " | ";
oss << "Exotic: ";
count = 0;
for (auto const& name : exoticFamilies)
{
if (count++ != 0)
oss << ", ";
oss << name;
}
}
botAI->TellError(oss.str());
return true;
}
// Handle "tame abandon" command to give up your current pet
if (mode == "abandon")
{
return AbandonPet();
}
// Try to process the command based on mode and value
if (mode == "name" && !value.empty())
{
found = SetPetByName(value);
}
else if (mode == "id" && !value.empty())
{
// Try to convert value to an integer and set pet by ID
try
{
uint32 id = std::stoul(value);
found = SetPetById(id);
}
catch (...)
{
botAI->TellError("Invalid tame id.");
}
}
else if (mode == "family" && !value.empty())
{
found = SetPetByFamily(value);
}
else if (mode == "rename" && !value.empty())
{
found = RenamePet(value);
}
else
{
// Unrecognized command or missing argument; show usage
botAI->TellError(
"Usage: tame name <name> | tame id <id> | tame family <family> | tame rename <new name> | tame abandon");
return false;
}
// If the requested tame/rename failed, return failure
if (!found)
return false;
// For all non-rename commands, initialize the new pet and talents, then notify the master
if (mode != "rename")
{
Player* bot = botAI->GetBot();
PlayerbotFactory factory(bot, bot->GetLevel());
factory.InitPet();
factory.InitPetTalents();
if (!lastPetName.empty() && lastPetId != 0)
{
std::ostringstream oss;
oss << "Pet changed to " << lastPetName << ", ID: " << lastPetId << ".";
botAI->TellMaster(oss.str());
}
else
{
botAI->TellMaster("Pet changed and initialized!");
}
}
return true;
}
bool TameAction::SetPetByName(const std::string& name)
{
// Make a lowercase copy of the input name for case-insensitive comparison
std::string lowerName = name;
std::transform(lowerName.begin(), lowerName.end(), lowerName.begin(), ::tolower);
// Get the full list of creature templates from the object manager
CreatureTemplateContainer const* creatures = sObjectMgr->GetCreatureTemplates();
Player* bot = botAI->GetBot();
// Iterate through all creature templates
for (auto itr = creatures->begin(); itr != creatures->end(); ++itr)
{
const CreatureTemplate& creature = itr->second;
std::string creatureName = creature.Name;
// Convert creature's name to lowercase for comparison
std::transform(creatureName.begin(), creatureName.end(), creatureName.begin(), ::tolower);
// If the input name matches this creature's name
if (creatureName == lowerName)
{
// Skip if the creature isn't tameable at all
if (!creature.IsTameable(true))
continue;
// If the creature is exotic and the bot doesn't have Beast Mastery, show error and fail
if (IsExoticPet(&creature) && !HasBeastMastery(bot))
{
botAI->TellError("I cannot use exotic pets unless I have the Beast Mastery talent.");
return false;
}
// Skip if the creature isn't tameable by this bot (respecting exotic pet rules)
if (!creature.IsTameable(bot->CanTameExoticPets()))
continue;
// Store the found pet's name and entry ID for later use/feedback
lastPetName = creature.Name;
lastPetId = creature.Entry;
// Create and set this pet for the bot
return CreateAndSetPet(creature.Entry);
}
}
// If no suitable pet found, show an error and return failure
botAI->TellError("No tameable pet found with name: " + name);
return false;
}
bool TameAction::SetPetById(uint32 id)
{
// Look up the creature template by its numeric entry/id
CreatureTemplate const* creature = sObjectMgr->GetCreatureTemplate(id);
Player* bot = botAI->GetBot();
// Proceed only if a valid creature was found
if (creature)
{
// Check if this creature is ever tameable (ignore bot's own restrictions for now)
if (!creature->IsTameable(true))
{
// If not tameable at all, show an error and fail
botAI->TellError("No tameable pet found with id: " + std::to_string(id));
return false;
}
// If it's an exotic pet, make sure the bot has the Beast Mastery talent
if (IsExoticPet(creature) && !HasBeastMastery(bot))
{
botAI->TellError("I cannot use exotic pets unless I have the Beast Mastery talent.");
return false;
}
// Check if the bot is actually allowed to tame this pet (honoring exotic pet rules)
if (!creature->IsTameable(bot->CanTameExoticPets()))
{
botAI->TellError("No tameable pet found with id: " + std::to_string(id));
return false;
}
// Remember this pet's name and id for later feedback
lastPetName = creature->Name;
lastPetId = creature->Entry;
// Set and create the pet for the bot
return CreateAndSetPet(creature->Entry);
}
// If no valid creature was found by id, show an error
botAI->TellError("No tameable pet found with id: " + std::to_string(id));
return false;
}
bool TameAction::SetPetByFamily(const std::string& family)
{
// Convert the input family name to lowercase for case-insensitive comparison
std::string lowerFamily = family;
std::transform(lowerFamily.begin(), lowerFamily.end(), lowerFamily.begin(), ::tolower);
// Get all creature templates from the object manager
CreatureTemplateContainer const* creatures = sObjectMgr->GetCreatureTemplates();
Player* bot = botAI->GetBot();
// Prepare a list of candidate creatures and track if any exotic pet is found
std::vector<const CreatureTemplate*> candidates;
bool foundExotic = false;
// Iterate through all creature templates
for (auto itr = creatures->begin(); itr != creatures->end(); ++itr)
{
const CreatureTemplate& creature = itr->second;
// Skip if this creature is never tameable
if (!creature.IsTameable(true))
continue;
// Look up the family entry for this creature
CreatureFamilyEntry const* familyEntry = sCreatureFamilyStore.LookupEntry(creature.family);
if (!familyEntry)
continue;
// Compare the family name in a case-insensitive way
std::string familyName = familyEntry->Name[0];
std::transform(familyName.begin(), familyName.end(), familyName.begin(), ::tolower);
if (familyName != lowerFamily)
continue;
// If the creature is exotic, check Beast Mastery talent requirements
if (IsExoticPet(&creature))
{
foundExotic = true;
if (!HasBeastMastery(bot))
continue;
}
// Only add as candidate if this bot is allowed to tame it (including exotic rules)
if (!creature.IsTameable(bot->CanTameExoticPets()))
continue;
candidates.push_back(&creature);
}
// If no candidates found, inform the user of the reason and return false
if (candidates.empty())
{
if (foundExotic && !HasBeastMastery(bot))
botAI->TellError("I cannot use exotic pets unless I have the Beast Mastery talent.");
else
botAI->TellError("No tameable pet found with family: " + family);
return false;
}
// Randomly select one candidate from the list to tame
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<> dis(0, candidates.size() - 1);
const CreatureTemplate* selected = candidates[dis(gen)];
// Save the selected pet's name and id for feedback
lastPetName = selected->Name;
lastPetId = selected->Entry;
// Attempt to create and set the new pet for the bot
return CreateAndSetPet(selected->Entry);
}
bool TameAction::RenamePet(const std::string& newName)
{
Player* bot = botAI->GetBot();
Pet* pet = bot->GetPet();
// Check if the bot currently has a pet
if (!pet)
{
botAI->TellError("You have no pet to rename.");
return false;
}
// Validate the new name: must not be empty and max 12 characters
if (newName.empty() || newName.length() > 12)
{
botAI->TellError("Pet name must be between 1 and 12 alphabetic characters.");
return false;
}
// Ensure all characters in the new name are alphabetic
for (char c : newName)
{
if (!std::isalpha(static_cast<unsigned char>(c)))
{
botAI->TellError("Pet name must only contain alphabetic characters (A-Z, a-z).");
return false;
}
}
// Normalize the name: capitalize the first letter, lowercase the rest
std::string normalized = newName;
normalized[0] = std::toupper(normalized[0]);
for (size_t i = 1; i < normalized.size(); ++i)
normalized[i] = std::tolower(normalized[i]);
// Check if the new name is reserved or forbidden
if (sObjectMgr->IsReservedName(normalized))
{
botAI->TellError("That pet name is forbidden. Please choose another name.");
return false;
}
// Set the pet's name and save it to the database
pet->SetName(normalized);
pet->SavePetToDB(PET_SAVE_AS_CURRENT);
bot->GetSession()->SendPetNameQuery(pet->GetGUID(), pet->GetEntry());
// 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("If you do not see the new name, please dismiss and recall your pet.");
// Remove the current pet and (re-)cast Call Pet spell if the bot is a hunter
bot->RemovePet(nullptr, PET_SAVE_AS_CURRENT, true);
if (bot->getClass() == CLASS_HUNTER && bot->HasSpell(883))
{
bot->CastSpell(bot, 883, true);
}
return true;
}
bool TameAction::CreateAndSetPet(uint32 creatureEntry)
{
Player* bot = botAI->GetBot();
// Ensure the player is a hunter and at least level 10 (required for pets)
if (bot->getClass() != CLASS_HUNTER || bot->GetLevel() < 10)
{
botAI->TellError("Only level 10+ hunters can have pets.");
return false;
}
// Retrieve the creature template for the given entry (pet species info)
CreatureTemplate const* creature = sObjectMgr->GetCreatureTemplate(creatureEntry);
if (!creature)
{
botAI->TellError("Creature template not found.");
return false;
}
// If the bot already has a current pet or an unslotted pet, remove them to avoid conflicts
if (bot->GetPetStable() && bot->GetPetStable()->CurrentPet)
{
bot->RemovePet(nullptr, PET_SAVE_AS_CURRENT);
bot->RemovePet(nullptr, PET_SAVE_NOT_IN_SLOT);
}
if (bot->GetPetStable() && bot->GetPetStable()->GetUnslottedHunterPet())
{
bot->GetPetStable()->UnslottedPets.clear();
bot->RemovePet(nullptr, PET_SAVE_AS_CURRENT);
bot->RemovePet(nullptr, PET_SAVE_NOT_IN_SLOT);
}
// Create the new tamed pet from the specified creature entry
Pet* pet = bot->CreateTamedPetFrom(creatureEntry, 0);
if (!pet)
{
botAI->TellError("Failed to create pet.");
return false;
}
// Set the pet's level to one below the bot's current level, then add to the map and set to full level
pet->SetUInt32Value(UNIT_FIELD_LEVEL, bot->GetLevel() - 1);
pet->GetMap()->AddToMap(pet->ToCreature());
pet->SetUInt32Value(UNIT_FIELD_LEVEL, bot->GetLevel());
// Set the pet as the bot's active minion
bot->SetMinion(pet, true);
// Initialize talents appropriate for the pet's level
pet->InitTalentForLevel();
// Save pet to the database as the current pet
pet->SavePetToDB(PET_SAVE_AS_CURRENT);
// Initialize available pet spells
bot->PetSpellInitialize();
// Further initialize pet stats to match the bot's level
pet->InitStatsForLevel(bot->GetLevel());
pet->SetLevel(bot->GetLevel());
// Set happiness and health of the pet to maximum values
pet->SetPower(POWER_HAPPINESS, pet->GetMaxPower(Powers(POWER_HAPPINESS)));
pet->SetHealth(pet->GetMaxHealth());
// Enable autocast for all active (not removed) non-passive spells the pet knows
for (PetSpellMap::const_iterator itr = pet->m_spells.begin(); itr != pet->m_spells.end(); ++itr)
{
if (itr->second.state == PETSPELL_REMOVED)
continue;
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(itr->first);
if (!spellInfo)
continue;
if (spellInfo->IsPassive())
continue;
pet->ToggleAutocast(spellInfo, true);
}
return true;
}
bool TameAction::AbandonPet()
{
// Get the bot player and its current pet (if any)
Player* bot = botAI->GetBot();
Pet* pet = bot->GetPet();
// Check if the bot has a pet and that it is a hunter pet
if (pet && pet->getPetType() == HUNTER_PET)
{
// Remove the pet from the bot and mark it as deleted in the database
bot->RemovePet(pet, PET_SAVE_AS_DELETED);
// Inform the bot's master/player that the pet was abandoned
botAI->TellMaster("Your pet has been abandoned.");
return true;
}
else
{
// If there is no hunter pet, show an error message
botAI->TellError("You have no hunter pet to abandon.");
return false;
}
}

View File

@@ -1,34 +0,0 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
* and/or modify it under version 3 of the License, or (at your option), any later version.
*/
#ifndef _PLAYERBOT_TAMEACTION_H
#define _PLAYERBOT_TAMEACTION_H
#include <string>
#include "Action.h"
#include "PlayerbotFactory.h"
class PlayerbotAI;
class TameAction : public Action
{
public:
TameAction(PlayerbotAI* botAI) : Action(botAI, "tame") {}
bool Execute(Event event) override;
private:
bool SetPetByName(const std::string& name);
bool SetPetById(uint32 id);
bool SetPetByFamily(const std::string& family);
bool RenamePet(const std::string& newName);
bool CreateAndSetPet(uint32 creatureEntry);
bool AbandonPet();
std::string lastPetName;
uint32 lastPetId = 0;
};
#endif

View File

@@ -1,113 +0,0 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
* and/or modify it under version 3 of the License, or (at your option), any later version.
*/
#include "TellGlyphsAction.h"
#include "Event.h"
#include "Playerbots.h"
#include "ObjectMgr.h"
#include "SpellMgr.h"
#include "World.h"
#include <unordered_map>
#include <sstream>
namespace
{
// -----------------------------------------------------------------
// Cache : GlyphID (MiscValue) -> ItemTemplate*
// -----------------------------------------------------------------
std::unordered_map<uint32, ItemTemplate const*> s_GlyphItemCache;
void BuildGlyphItemCache()
{
if (!s_GlyphItemCache.empty())
return;
ItemTemplateContainer const* store = sObjectMgr->GetItemTemplateStore();
for (auto const& kv : *store) // C++17 : range-for sur map
{
ItemTemplate const* proto = &kv.second;
if (!proto || proto->Class != ITEM_CLASS_GLYPH)
continue;
for (uint32 i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
{
uint32 spellId = proto->Spells[i].SpellId;
if (!spellId)
continue;
SpellInfo const* spell = sSpellMgr->GetSpellInfo(spellId);
if (!spell)
continue;
for (uint32 eff = 0; eff <= EFFECT_2; ++eff)
{
if (spell->Effects[eff].Effect != SPELL_EFFECT_APPLY_GLYPH)
continue;
uint32 glyphId = spell->Effects[eff].MiscValue;
if (glyphId)
s_GlyphItemCache[glyphId] = proto;
}
}
}
}
} // namespace
// -----------------------------------------------------------------
// Action
// -----------------------------------------------------------------
bool TellGlyphsAction::Execute(Event event)
{
//-----------------------------------------------------------------
// 1. who sended the wisp ? (source of event)
//-----------------------------------------------------------------
Player* sender = event.getOwner(); // API Event
if (!sender)
return false;
//-----------------------------------------------------------------
// 2. Generate glyphId cache -> item
//-----------------------------------------------------------------
BuildGlyphItemCache();
//-----------------------------------------------------------------
// 3. Look at the 6 glyphs sockets
//-----------------------------------------------------------------
std::ostringstream list;
bool first = true;
for (uint8 slot = 0; slot < MAX_GLYPH_SLOT_INDEX; ++slot)
{
uint32 glyphId = bot->GetGlyph(slot);
if (!glyphId)
continue;
auto it = s_GlyphItemCache.find(glyphId);
if (it == s_GlyphItemCache.end())
continue; // No glyph found (rare)
if (!first)
list << ", ";
// chat->FormatItem
list << chat->FormatItem(it->second);
first = false;
}
//-----------------------------------------------------------------
// 4. Send chat messages
//-----------------------------------------------------------------
if (first) // no glyphs
botAI->TellMaster("No glyphs equipped");
else
botAI->TellMaster(std::string("Glyphs: ") + list.str());
return true;
}

View File

@@ -1,20 +0,0 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
* and/or modify it under version 3 of the License, or (at your option), any later version.
*/
#ifndef _PLAYERBOT_TELLGLYPHSACTION_H
#define _PLAYERBOT_TELLGLYPHSACTION_H
#include "Action.h"
class TellGlyphsAction : public Action
{
public:
TellGlyphsAction(PlayerbotAI* ai, std::string const name = "glyphs")
: Action(ai, name) {}
bool Execute(Event event) override;
};
#endif

View File

@@ -1,18 +0,0 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
* and/or modify it under version 3 of the License, or (at your option), any later version.
*/
#include "PlayerbotAI.h"
#include "WipeAction.h"
bool WipeAction::Execute(Event event)
{
Player* master = event.getOwner();
if (botAI->GetMaster()->GetGUID() != event.getOwner()->GetGUID())
return false;
bot->Kill(bot, bot);
return true;
}

View File

@@ -1,24 +0,0 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
* and/or modify it under version 3 of the License, or (at your option), any later version.
*/
#ifndef _PLAYERBOT_WIPEACTION_H
#define _PLAYERBOT_WIPEACTION_H
#include "Action.h"
class PlayerbotAI;
class WipeAction : public Action
{
public:
WipeAction(PlayerbotAI* botAI) : Action(botAI, "wipe") {}
bool Execute(Event event) override;
private:
std::string bossName;
};
#endif

View File

@@ -1,88 +0,0 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
* and/or modify it under version 3 of the License, or (at your option), any later version.
*/
#ifndef _PLAYERBOT_BOSSAURATRIGGERS_H
#define _PLAYERBOT_BOSSAURATRIGGERS_H
#include "GenericTriggers.h"
class PlayerbotAI;
enum BossAuraIDs
{
SPELL_SHADOW_RESISTANCE_AURA_RANK_1 = 19876,
SPELL_FROST_RESISTANCE_AURA_RANK_1 = 19888,
SPELL_FIRE_RESISTANCE_AURA_RANK_1 = 19891,
SPELL_SHADOW_RESISTANCE_AURA_RANK_2 = 19895,
SPELL_SHADOW_RESISTANCE_AURA_RANK_3 = 19896,
SPELL_FROST_RESISTANCE_AURA_RANK_2 = 19897,
SPELL_FROST_RESISTANCE_AURA_RANK_3 = 19898,
SPELL_FIRE_RESISTANCE_AURA_RANK_2 = 19899,
SPELL_FIRE_RESISTANCE_AURA_RANK_3 = 19900,
SPELL_ASPECT_OF_THE_WILD_RANK_1 = 20043,
SPELL_ASPECT_OF_THE_WILD_RANK_2 = 20190,
SPELL_ASPECT_OF_THE_WILD_RANK_3 = 27045,
SPELL_SHADOW_RESISTANCE_AURA_RANK_4 = 27151,
SPELL_FROST_RESISTANCE_AURA_RANK_4 = 27152,
SPELL_FIRE_RESISTANCE_AURA_RANK_4 = 27153,
SPELL_SHADOW_RESISTANCE_AURA_RANK_5 = 48943,
SPELL_FROST_RESISTANCE_AURA_RANK_5 = 48945,
SPELL_FIRE_RESISTANCE_AURA_RANK_5 = 48947,
SPELL_ASPECT_OF_THE_WILD_RANK_4 = 49071
};
class BossFireResistanceTrigger : public Trigger
{
public:
BossFireResistanceTrigger(PlayerbotAI* ai, std::string const bossName)
: Trigger(ai, bossName + " fire resistance trigger"), bossName(bossName)
{
}
bool IsActive() override;
private:
std::string bossName;
};
class BossFrostResistanceTrigger : public Trigger
{
public:
BossFrostResistanceTrigger(PlayerbotAI* ai, std::string const bossName)
: Trigger(ai, bossName + " frost resistance trigger"), bossName(bossName)
{
}
bool IsActive() override;
private:
std::string bossName;
};
class BossNatureResistanceTrigger : public Trigger
{
public:
BossNatureResistanceTrigger(PlayerbotAI* ai, std::string const bossName)
: Trigger(ai, " nature resistance trigger"), bossName(bossName)
{
}
bool IsActive() override;
private:
std::string bossName;
};
class BossShadowResistanceTrigger : public Trigger
{
public:
BossShadowResistanceTrigger(PlayerbotAI* ai, std::string const bossName)
: Trigger(ai, " shadow resistance trigger"), bossName(bossName)
{
}
bool IsActive() override;
private:
std::string bossName;
};
#endif

View File

@@ -1,11 +0,0 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
* and/or modify it under version 3 of the License, or (at your option), any later version.
*/
#include "FishingTriggers.h"
#include "Playerbots.h"
bool CanFishTrigger::IsActive() { return AI_VALUE(bool, "can fish"); }
bool CanUseFishingBobberTrigger::IsActive() { return AI_VALUE(bool, "can use fishing bobber");}

View File

@@ -1,25 +0,0 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
* and/or modify it under version 3 of the License, or (at your option), any later version.
*/
#ifndef _PLAYERBOT_FISHING_TRIGGER_H
#define _PLAYERBOT_FISHING_TRIGGER_H
#include "GenericTriggers.h"
class CanFishTrigger : public Trigger
{
public:
CanFishTrigger(PlayerbotAI* ai) : Trigger(ai, "can fish") {};
bool IsActive() override;
};
class CanUseFishingBobberTrigger : public Trigger
{
public:
CanUseFishingBobberTrigger(PlayerbotAI* ai) : Trigger(ai, "can use fishing bobber") {};
bool IsActive() override;
};
#endif

View File

@@ -1,40 +0,0 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
* and/or modify it under version 3 of the License, or (at your option), any later version.
*/
#include "LootTriggers.h"
#include "LootObjectStack.h"
#include "Playerbots.h"
#include "ServerFacade.h"
bool LootAvailableTrigger::IsActive()
{
bool distanceCheck = false;
if (botAI->HasStrategy("stay", BOT_STATE_NON_COMBAT))
{
distanceCheck =
sServerFacade->IsDistanceLessOrEqualThan(AI_VALUE2(float, "distance", "loot target"), CONTACT_DISTANCE);
}
else
{
distanceCheck = sServerFacade->IsDistanceLessOrEqualThan(AI_VALUE2(float, "distance", "loot target"),
INTERACTION_DISTANCE - 2.0f);
}
// if loot target if empty, always pass distance check
return AI_VALUE(bool, "has available loot") &&
(distanceCheck || AI_VALUE(GuidVector, "all targets").empty());
}
bool FarFromCurrentLootTrigger::IsActive()
{
LootObject loot = AI_VALUE(LootObject, "loot target");
if (!loot.IsLootPossible(bot))
return false;
return AI_VALUE2(float, "distance", "loot target") >= INTERACTION_DISTANCE - 2.0f;
}
bool CanLootTrigger::IsActive() { return AI_VALUE(bool, "can loot"); }

View File

@@ -1,20 +0,0 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
* and/or modify it under version 3 of the License, or (at your option), any later version.
*/
#include "RtiTriggers.h"
#include "Playerbots.h"
bool NoRtiTrigger::IsActive()
{
// Do not auto-react to raid icons while out of combat.
// Out-of-combat RTI usage (explicit chat commands) is handled by chat triggers,
// not by this generic trigger.
if (!bot->IsInCombat())
return false;
Unit* target = AI_VALUE(Unit*, "rti target");
return target != nullptr;
}

View File

@@ -1,55 +0,0 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
* and/or modify it under version 3 of the License, or (at your option), any later version.
*/
#include "FishValues.h"
#include "PlayerbotAI.h"
#include "RandomPlayerbotMgr.h"
#include "Map.h"
#include "Spell.h"
#include "FishingAction.h"
bool CanFishValue::Calculate()
{
int32 SkillFishing = bot->GetSkillValue(SKILL_FISHING);
if (SkillFishing == 0)
return false;
if (bot->isSwimming())
return false;
if (bot->IsInCombat())
return false;
return true;
}
bool CanUseFishingBobberValue::Calculate()
{
GuidVector gos = AI_VALUE(GuidVector, "nearest game objects no los");
for (auto const& guid : gos)
{
if (GameObject* go = botAI->GetGameObject(guid))
{
if (go->GetEntry() != FISHING_BOBBER)
continue;
if (go->GetOwnerGUID() != bot->GetGUID())
continue;
if (go->getLootState() == GO_READY)
return true;
// Not ready yet → delay next check
time_t bobberActiveTime = go->GetRespawnTime() - FISHING_BOBBER_READY_TIME;
if (bobberActiveTime > time(0))
botAI->SetNextCheckDelay((bobberActiveTime - time(0)) * IN_MILLISECONDS + 500);
else
botAI->SetNextCheckDelay(1000);
return false;
}
}
return false;
}

View File

@@ -1,47 +0,0 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
* and/or modify it under version 3 of the License, or (at your option), any later version.
*/
#ifndef _PLAYERBOT_FISHVALUES_H
#define _PLAYERBOT_FISHVALUES_H
#include "Value.h"
#include "TravelMgr.h"
#include "NamedObjectContext.h"
class PlayerbotAI;
class CanFishValue : public BoolCalculatedValue
{
public:
CanFishValue(PlayerbotAI* botAI) : BoolCalculatedValue(botAI, "can fish") {};
bool Calculate() override;
};
class CanUseFishingBobberValue : public BoolCalculatedValue
{
public:
CanUseFishingBobberValue(PlayerbotAI* botAI) : BoolCalculatedValue(botAI, "can use fishing bobber") {};
bool Calculate() override;
};
class FishingSpotValue : public ManualSetValue<WorldPosition>
{
public:
FishingSpotValue(PlayerbotAI* botAI, WorldPosition const& pos = WorldPosition(), std::string const& name = "fishing spot")
: ManualSetValue<WorldPosition>(botAI, pos, name) {}
void Set(WorldPosition val) override
{
value = val;
_setTime = getMSTime();
}
uint32 lastUpdated() const {return _setTime;}
bool IsStale(uint32 maxDuration) const { return getMSTime() - _setTime > maxDuration; }
private:
uint32 _setTime = 0;
};
#endif

View File

@@ -1,10 +0,0 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
* and/or modify it under version 3 of the License, or (at your option), any later version.
*/
#include "GroupLeaderValue.h"
#include "Playerbots.h"
Unit* GroupLeaderValue::Calculate() { return botAI->GetGroupLeader(); }

View File

@@ -1,24 +0,0 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
* and/or modify it under version 3 of the License, or (at your option), any later version.
*/
#ifndef _PLAYERBOT_GROUPLEADERVALUE_H
#define _PLAYERBOT_GROUPLEADERVALUE_H
#include "Value.h"
class PlayerbotAI;
class Unit;
class GroupLeaderValue : public UnitCalculatedValue
{
public:
GroupLeaderValue(PlayerbotAI* botAI, std::string const name = "group leader") : UnitCalculatedValue(botAI, name)
{
}
Unit* Calculate() override;
};
#endif

View File

@@ -1,20 +0,0 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
* and/or modify it under version 3 of the License, or (at your option), any later version.
*/
#include "Action.h"
#include "Playerbots.h"
#include "Timer.h"
Value<Unit*>* Action::GetTargetValue() { return context->GetValue<Unit*>(GetTargetName()); }
Unit* Action::GetTarget() { return GetTargetValue()->Get(); }
ActionBasket::ActionBasket(ActionNode* action, float relevance, bool skipPrerequisites, Event event)
: action(action), relevance(relevance), skipPrerequisites(skipPrerequisites), event(event), created(getMSTime())
{
}
bool ActionBasket::isExpired(uint32_t msecs) { return getMSTime() - created >= msecs; }

View File

@@ -1,310 +0,0 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
* and/or modify it under version 3 of the License, or (at your option), any later version.
*/
#ifndef _PLAYERBOT_NAMEDOBJECTCONEXT_H
#define _PLAYERBOT_NAMEDOBJECTCONEXT_H
#include <list>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include <functional>
#include "Common.h"
class PlayerbotAI;
class Qualified
{
public:
Qualified(){};
Qualified(std::string const qualifier) : qualifier(qualifier) {}
Qualified(int32 qualifier1) { Qualify(qualifier1); }
virtual void Qualify(int qual);
virtual void Qualify(std::string const qual) { qualifier = qual; }
std::string const getQualifier() { return qualifier; }
static std::string const MultiQualify(const std::vector<std::string>& qualifiers, const std::string& separator,
const std::string_view brackets = "{}");
static std::vector<std::string> getMultiQualifiers(const std::string& qualifier1);
static int32 getMultiQualifier(const std::string& qualifier1, uint32 pos);
protected:
std::string qualifier;
};
template <class T>
class NamedObjectFactory
{
public:
using ObjectCreator = std::function<T*(PlayerbotAI* ai)>;
std::unordered_map<std::string, ObjectCreator> creators;
public:
virtual ~NamedObjectFactory() = default;
virtual T* create(std::string name, PlayerbotAI* botAI)
{
size_t found = name.find("::");
std::string qualifier;
if (found != std::string::npos)
{
qualifier = name.substr(found + 2);
name = name.substr(0, found);
}
if (creators.find(name) == creators.end())
return nullptr;
ObjectCreator& creator = creators[name];
T* object = creator(botAI);
Qualified* q = dynamic_cast<Qualified*>(object);
if (q && found != std::string::npos)
q->Qualify(qualifier);
return object;
}
std::set<std::string> supports()
{
std::set<std::string> keys;
for (typename std::unordered_map<std::string, ObjectCreator>::const_iterator it = creators.begin();
it != creators.end(); it++)
keys.insert(it->first);
return keys;
}
};
template <class T>
class NamedObjectContext : public NamedObjectFactory<T>
{
public:
NamedObjectContext(bool shared = false, bool supportsSiblings = false)
: NamedObjectFactory<T>(), shared(shared), supportsSiblings(supportsSiblings)
{
}
virtual ~NamedObjectContext() { Clear(); }
virtual T* create(std::string name, PlayerbotAI* botAI) override
{
if (created.find(name) == created.end())
return created[name] = NamedObjectFactory<T>::create(name, botAI);
return created[name];
}
void Clear()
{
for (typename std::unordered_map<std::string, T*>::const_iterator i = created.begin(); i != created.end(); i++)
{
if (i->second)
delete i->second;
}
created.clear();
}
bool IsShared() { return shared; }
bool IsSupportsSiblings() { return supportsSiblings; }
std::set<std::string> GetCreated()
{
std::set<std::string> keys;
for (typename std::unordered_map<std::string, T*>::iterator it = created.begin(); it != created.end(); it++)
keys.insert(it->first);
return keys;
}
protected:
std::unordered_map<std::string, T*> created;
bool shared;
bool supportsSiblings;
};
template <class T>
class SharedNamedObjectContextList
{
public:
using ObjectCreator = std::function<T*(PlayerbotAI* ai)>;
std::unordered_map<std::string, ObjectCreator> creators;
std::vector<NamedObjectContext<T>*> contexts;
~SharedNamedObjectContextList()
{
for (typename std::vector<NamedObjectContext<T>*>::const_iterator i = contexts.begin(); i != contexts.end(); i++)
delete *i;
}
void Add(NamedObjectContext<T>* context)
{
contexts.push_back(context);
for (auto const& iter : context->creators)
creators[iter.first] = iter.second;
}
};
template <class T>
class NamedObjectContextList
{
public:
using ObjectCreator = std::function<T*(PlayerbotAI* ai)>;
const std::unordered_map<std::string, ObjectCreator>& creators;
const std::vector<NamedObjectContext<T>*>& contexts;
std::unordered_map<std::string, T*> created;
NamedObjectContextList(const SharedNamedObjectContextList<T>& shared)
: creators(shared.creators), contexts(shared.contexts)
{
}
~NamedObjectContextList()
{
for (typename std::unordered_map<std::string, T*>::const_iterator i = created.begin(); i != created.end(); i++)
{
if (i->second)
delete i->second;
}
created.clear();
}
T* create(std::string name, PlayerbotAI* botAI)
{
size_t found = name.find("::");
std::string qualifier;
if (found != std::string::npos)
{
qualifier = name.substr(found + 2);
name = name.substr(0, found);
}
if (creators.find(name) == creators.end())
return nullptr;
const ObjectCreator& creator = creators.at(name);
T* object = creator(botAI);
Qualified* q = dynamic_cast<Qualified*>(object);
if (q && found != std::string::npos)
q->Qualify(qualifier);
return object;
}
T* GetContextObject(const std::string& name, PlayerbotAI* botAI)
{
if (created.find(name) == created.end())
{
if (T* object = create(name, botAI))
return created[name] = object;
}
return created[name];
}
std::set<std::string> GetSiblings(const std::string& name)
{
for (auto i = contexts.begin(); i != contexts.end(); i++)
{
if (!(*i)->IsSupportsSiblings())
continue;
std::set<std::string> supported = (*i)->supports();
std::set<std::string>::iterator found = supported.find(name);
if (found == supported.end())
continue;
supported.erase(found);
return supported;
}
return std::set<std::string>();
}
std::set<std::string> supports()
{
std::set<std::string> result;
for (auto i = contexts.begin(); i != contexts.end(); i++)
{
std::set<std::string> supported = (*i)->supports();
for (std::set<std::string>::const_iterator j = supported.begin(); j != supported.end(); ++j)
result.insert(*j);
}
return result;
}
std::set<std::string> GetCreated()
{
std::set<std::string> result;
for (typename std::unordered_map<std::string, T*>::const_iterator i = created.begin(); i != created.end(); i++)
result.insert(i->first);
return result;
}
};
template <class T>
class NamedObjectFactoryList
{
public:
using ObjectCreator = std::function<T*(PlayerbotAI* ai)>;
std::vector<NamedObjectFactory<T>*> factories;
std::unordered_map<std::string, ObjectCreator> creators;
virtual ~NamedObjectFactoryList()
{
for (typename std::vector<NamedObjectFactory<T>*>::const_iterator i = factories.begin(); i != factories.end(); i++)
delete *i;
}
T* create(std::string name, PlayerbotAI* botAI)
{
size_t found = name.find("::");
std::string qualifier;
if (found != std::string::npos)
{
qualifier = name.substr(found + 2);
name = name.substr(0, found);
}
if (creators.find(name) == creators.end())
return nullptr;
const ObjectCreator& creator = creators[name];
T* object = creator(botAI);
Qualified* q = dynamic_cast<Qualified*>(object);
if (q && found != std::string::npos)
q->Qualify(qualifier);
return object;
}
void Add(NamedObjectFactory<T>* context)
{
factories.push_back(context);
for (auto const& iter : context->creators)
creators[iter.first] = iter.second;
}
T* GetContextObject(const std::string& name, PlayerbotAI* botAI)
{
if (T* object = create(name, botAI))
return object;
return nullptr;
}
};
#endif

View File

@@ -1,145 +0,0 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
* and/or modify it under version 3 of the License, or (at your option), any later version.
*/
#include "Strategy.h"
#include "Playerbots.h"
class ActionNodeFactoryInternal : public NamedObjectFactory<ActionNode>
{
public:
ActionNodeFactoryInternal()
{
creators["melee"] = &melee;
creators["healthstone"] = &healthstone;
creators["be near"] = &follow_master_random;
creators["attack anything"] = &attack_anything;
creators["move random"] = &move_random;
creators["move to loot"] = &move_to_loot;
creators["food"] = &food;
creators["drink"] = &drink;
creators["mana potion"] = &mana_potion;
creators["healing potion"] = &healing_potion;
creators["flee"] = &flee;
}
private:
static ActionNode* melee([[maybe_unused]] PlayerbotAI* botAI)
{
return new ActionNode(
"melee",
/*P*/ {},
/*A*/ {},
/*C*/ {}
);
}
static ActionNode* healthstone([[maybe_unused]] PlayerbotAI* botAI)
{
return new ActionNode(
"healthstone",
/*P*/ {},
/*A*/ { NextAction("healing potion") },
/*C*/ {}
);
}
static ActionNode* follow_master_random([[maybe_unused]] PlayerbotAI* botAI)
{
return new ActionNode(
"be near",
/*P*/ {},
/*A*/ { NextAction("follow") },
/*C*/ {}
);
}
static ActionNode* attack_anything([[maybe_unused]] PlayerbotAI* botAI)
{
return new ActionNode(
"attack anything",
/*P*/ {},
/*A*/ {},
/*C*/ {}
);
}
static ActionNode* move_random([[maybe_unused]] PlayerbotAI* botAI)
{
return new ActionNode(
"move random",
/*P*/ {},
/*A*/ { NextAction("stay line") },
/*C*/ {}
);
}
static ActionNode* move_to_loot([[maybe_unused]] PlayerbotAI* botAI)
{
return new ActionNode(
"move to loot",
/*P*/ {},
/*A*/ {},
/*C*/ {}
);
}
static ActionNode* food([[maybe_unused]] PlayerbotAI* botAI)
{
return new ActionNode(
"food",
/*P*/ {},
/*A*/ {},
/*C*/ {}
);
}
static ActionNode* drink([[maybe_unused]] PlayerbotAI* botAI)
{
return new ActionNode(
"drink",
/*P*/ {},
/*A*/ {},
/*C*/ {}
);
}
static ActionNode* mana_potion([[maybe_unused]] PlayerbotAI* botAI)
{
return new ActionNode(
"mana potion",
/*P*/ {},
/*A*/ {},
/*C*/ {}
);
}
static ActionNode* healing_potion([[maybe_unused]] PlayerbotAI* botAI)
{
return new ActionNode(
"healing potion",
/*P*/ {},
/*A*/ { NextAction("food") },
/*C*/ {}
);
}
static ActionNode* flee([[maybe_unused]] PlayerbotAI* botAI)
{
return new ActionNode(
"flee",
/*P*/ {},
/*A*/ {},
/*C*/ {}
);
}
};
Strategy::Strategy(PlayerbotAI* botAI) : PlayerbotAIAware(botAI)
{
actionNodeFactories.Add(new ActionNodeFactoryInternal());
}
ActionNode* Strategy::GetAction(std::string const name) { return actionNodeFactories.GetContextObject(name, botAI); }

View File

@@ -1,84 +0,0 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
* and/or modify it under version 3 of the License, or (at your option), any later version.
*/
#pragma once
#include "Action.h"
#include "Common.h"
class PlayerbotAI;
class Unit;
class Trigger : public AiNamedObject
{
public:
Trigger(
PlayerbotAI* botAI,
const std::string name = "trigger",
int32_t checkInterval = 1
);
virtual ~Trigger() {}
virtual Event Check();
virtual void ExternalEvent([[maybe_unused]] std::string const param, [[maybe_unused]] Player* owner = nullptr) {}
virtual void ExternalEvent([[maybe_unused]] WorldPacket& packet, [[maybe_unused]] Player* owner = nullptr) {}
virtual bool IsActive() { return false; }
virtual std::vector<NextAction> getHandlers() { return {}; }
void Update() {}
virtual void Reset() {}
virtual Unit* GetTarget();
virtual Value<Unit*>* GetTargetValue();
virtual std::string const GetTargetName() { return "self target"; }
bool needCheck(uint32 now);
protected:
int32_t checkInterval;
uint32_t lastCheckTime;
};
class TriggerNode
{
public:
TriggerNode(
const std::string& name,
std::vector<NextAction> handlers = {}
) :
trigger(nullptr),
handlers(std::move(handlers)),
name(name)
{}
Trigger* getTrigger() { return trigger; }
void setTrigger(Trigger* trigger) { this->trigger = trigger; }
const std::string getName() { return name; }
std::vector<NextAction> getHandlers()
{
std::vector<NextAction> result = this->handlers;
if (trigger != nullptr)
{
std::vector<NextAction> extra = trigger->getHandlers();
result.insert(result.end(), extra.begin(), extra.end());
}
return result;
}
float getFirstRelevance()
{
if (this->handlers.size() > 0)
return this->handlers[0].getRelevance();
return -1;
}
private:
Trigger* trigger;
std::vector<NextAction> handlers;
const std::string name;
};

View File

@@ -1,612 +0,0 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
* and/or modify it under version 3 of the License, or (at your option), any later version.
*/
#include "ChatFilter.h"
#include "Group.h"
#include "Playerbots.h"
#include "RtiTargetValue.h"
#include "AiFactory.h"
#include <algorithm>
#include <cctype>
#include <string>
static std::string ToLower(const std::string& str)
{
std::string out = str;
std::transform(out.begin(), out.end(), out.begin(), [](unsigned char c){ return std::tolower(c); });
return out;
}
std::string const ChatFilter::Filter(std::string& message)
{
if (message.find("@") == std::string::npos)
return message;
return message.substr(message.find(" ") + 1);
}
class StrategyChatFilter : public ChatFilter
{
public:
StrategyChatFilter(PlayerbotAI* botAI) : ChatFilter(botAI) {}
std::string const Filter(std::string& message) override
{
Player* bot = botAI->GetBot();
std::string msgLower = ToLower(message);
bool tank = msgLower.find("@tank") == 0;
if (tank && !botAI->IsTank(bot))
return "";
bool dps = msgLower.find("@dps") == 0;
if (dps && (botAI->IsTank(bot) || botAI->IsHeal(bot)))
return "";
bool heal = msgLower.find("@heal") == 0;
if (heal && !botAI->IsHeal(bot))
return "";
bool ranged = msgLower.find("@ranged") == 0;
if (ranged && !botAI->IsRanged(bot))
return "";
bool melee = msgLower.find("@melee") == 0;
if (melee && botAI->IsRanged(bot))
return "";
bool rangeddps = msgLower.find("@rangeddps") == 0;
if (rangeddps && (!botAI->IsRanged(bot) || botAI->IsTank(bot) || botAI->IsHeal(bot)))
return "";
bool meleedps = msgLower.find("@meleedps") == 0;
if (meleedps && (!botAI->IsMelee(bot) || botAI->IsTank(bot) || botAI->IsHeal(bot)))
return "";
if (tank || dps || heal || ranged || melee)
return ChatFilter::Filter(message);
return message;
}
};
class LevelChatFilter : public ChatFilter
{
public:
LevelChatFilter(PlayerbotAI* botAI) : ChatFilter(botAI) {}
std::string const Filter(std::string& message) override
{
Player* bot = botAI->GetBot();
std::string msgLower = ToLower(message);
if (msgLower[0] != '@')
return message;
if (msgLower.find("-") != std::string::npos)
{
uint32 fromLevel = atoi(message.substr(message.find("@") + 1, message.find("-")).c_str());
uint32 toLevel = atoi(message.substr(message.find("-") + 1, message.find(" ")).c_str());
if (bot->GetLevel() >= fromLevel && bot->GetLevel() <= toLevel)
return ChatFilter::Filter(message);
return message;
}
uint32 level = atoi(message.substr(message.find("@") + 1, message.find(" ")).c_str());
if (bot->GetLevel() == level)
return ChatFilter::Filter(message);
return message;
}
};
class CombatTypeChatFilter : public ChatFilter
{
public:
CombatTypeChatFilter(PlayerbotAI* botAI) : ChatFilter(botAI) {}
std::string const Filter(std::string& message) override
{
Player* bot = botAI->GetBot();
std::string msgLower = ToLower(message);
bool melee = msgLower.find("@melee") == 0;
bool ranged = msgLower.find("@ranged") == 0;
if (!melee && !ranged)
return message;
switch (bot->getClass())
{
case CLASS_WARRIOR:
case CLASS_PALADIN:
case CLASS_ROGUE:
case CLASS_DEATH_KNIGHT:
if (ranged)
return "";
break;
case CLASS_HUNTER:
case CLASS_PRIEST:
case CLASS_MAGE:
case CLASS_WARLOCK:
if (melee)
return "";
break;
case CLASS_DRUID:
if (ranged && botAI->IsTank(bot))
return "";
if (melee && !botAI->IsTank(bot))
return "";
break;
case CLASS_SHAMAN:
if (melee && botAI->IsHeal(bot))
return "";
if (ranged && !botAI->IsHeal(bot))
return "";
break;
}
return ChatFilter::Filter(message);
}
};
class RtiChatFilter : public ChatFilter
{
public:
RtiChatFilter(PlayerbotAI* botAI) : ChatFilter(botAI)
{
rtis.push_back("@star");
rtis.push_back("@circle");
rtis.push_back("@diamond");
rtis.push_back("@triangle");
rtis.push_back("@moon");
rtis.push_back("@square");
rtis.push_back("@cross");
rtis.push_back("@skull");
}
std::string const Filter(std::string& message) override
{
Player* bot = botAI->GetBot();
std::string msgLower = ToLower(message);
Group* group = bot->GetGroup();
if (!group)
return message;
bool found = false;
for (std::vector<std::string>::iterator i = rtis.begin(); i != rtis.end(); i++)
{
std::string const rti = *i;
std::string rtiLower = ToLower(rti);
bool isRti = msgLower.find(rtiLower) == 0;
if (!isRti)
continue;
ObjectGuid rtiTarget = group->GetTargetIcon(RtiTargetValue::GetRtiIndex(rti.substr(1)));
if (bot->GetGUID() == rtiTarget)
return ChatFilter::Filter(message);
Unit* target = *botAI->GetAiObjectContext()->GetValue<Unit*>("current target");
if (!target)
return "";
if (target->GetGUID() != rtiTarget)
return "";
found |= isRti;
if (found)
break;
}
if (found)
return ChatFilter::Filter(message);
return message;
}
private:
std::vector<std::string> rtis;
};
class ClassChatFilter : public ChatFilter
{
public:
ClassChatFilter(PlayerbotAI* botAI) : ChatFilter(botAI)
{
classNames["@dk"] = CLASS_DEATH_KNIGHT;
classNames["@druid"] = CLASS_DRUID;
classNames["@hunter"] = CLASS_HUNTER;
classNames["@mage"] = CLASS_MAGE;
classNames["@paladin"] = CLASS_PALADIN;
classNames["@priest"] = CLASS_PRIEST;
classNames["@rogue"] = CLASS_ROGUE;
classNames["@shaman"] = CLASS_SHAMAN;
classNames["@warlock"] = CLASS_WARLOCK;
classNames["@warrior"] = CLASS_WARRIOR;
}
std::string const Filter(std::string& message) override
{
Player* bot = botAI->GetBot();
std::string msgLower = ToLower(message);
bool found = false;
for (std::map<std::string, uint8>::iterator i = classNames.begin(); i != classNames.end(); i++)
{
bool isClass = msgLower.find(ToLower(i->first)) == 0;
if (isClass && bot->getClass() != i->second)
return "";
found |= isClass;
if (found)
break;
}
if (found)
return ChatFilter::Filter(message);
return message;
}
private:
std::map<std::string, uint8> classNames;
};
class SubGroupChatFilter : public ChatFilter
{
public:
SubGroupChatFilter(PlayerbotAI* botAI) : ChatFilter(botAI) {}
std::string const Filter(std::string& message) override
{
Player* bot = botAI->GetBot();
std::string msgLower = ToLower(message);
if (msgLower.find("@group") == 0)
{
size_t spacePos = message.find(" ");
if (spacePos == std::string::npos)
return message;
std::string pnum = message.substr(6, spacePos - 6);
std::string actualMessage = message.substr(spacePos + 1);
std::set<uint32> targets;
std::istringstream ss(pnum);
std::string token;
while (std::getline(ss, token, ','))
{
size_t dashPos = token.find("-");
if (dashPos != std::string::npos)
{
uint32 from = atoi(token.substr(0, dashPos).c_str());
uint32 to = atoi(token.substr(dashPos + 1).c_str());
if (from > to) std::swap(from, to);
for (uint32 i = from; i <= to; ++i)
targets.insert(i);
}
else
{
uint32 index = atoi(token.c_str());
targets.insert(index);
}
}
if (!bot->GetGroup())
return message;
uint32 sg = bot->GetSubGroup() + 1;
if (targets.find(sg) != targets.end())
return ChatFilter::Filter(actualMessage);
}
return message;
}
};
class SpecChatFilter : public ChatFilter
{
public:
SpecChatFilter(PlayerbotAI* botAI) : ChatFilter(botAI)
{
// Map (class, specTab) to spec+class string
specTabNames[{CLASS_PALADIN, 0}] = "hpal";
specTabNames[{CLASS_PALADIN, 1}] = "ppal";
specTabNames[{CLASS_PALADIN, 2}] = "rpal";
specTabNames[{CLASS_PRIEST, 0}] = "disc";
specTabNames[{CLASS_PRIEST, 1}] = "hpr";
specTabNames[{CLASS_PRIEST, 2}] = "spr";
specTabNames[{CLASS_MAGE, 0}] = "arc";
specTabNames[{CLASS_MAGE, 1}] = "frost";
specTabNames[{CLASS_MAGE, 2}] = "fire";
specTabNames[{CLASS_WARRIOR, 0}] = "arms";
specTabNames[{CLASS_WARRIOR, 1}] = "fury";
specTabNames[{CLASS_WARRIOR, 2}] = "pwar";
specTabNames[{CLASS_WARLOCK, 0}] = "affl";
specTabNames[{CLASS_WARLOCK, 1}] = "demo";
specTabNames[{CLASS_WARLOCK, 2}] = "dest";
specTabNames[{CLASS_SHAMAN, 0}] = "ele";
specTabNames[{CLASS_SHAMAN, 1}] = "enh";
specTabNames[{CLASS_SHAMAN, 2}] = "rsha";
specTabNames[{CLASS_DRUID, 0}] = "bal";
// See below for feral druid
specTabNames[{CLASS_DRUID, 2}] = "rdru";
specTabNames[{CLASS_HUNTER, 0}] = "bmh";
specTabNames[{CLASS_HUNTER, 1}] = "mmh";
specTabNames[{CLASS_HUNTER, 2}] = "svh";
specTabNames[{CLASS_ROGUE, 0}] = "mut";
specTabNames[{CLASS_ROGUE, 1}] = "comb";
specTabNames[{CLASS_ROGUE, 2}] = "sub";
// See below for blood death knight
specTabNames[{CLASS_DEATH_KNIGHT, 1}] = "fdk";
specTabNames[{CLASS_DEATH_KNIGHT, 2}] = "udk";
}
std::string const Filter(std::string& message) override
{
std::string msgLower = ToLower(message);
std::string specPrefix;
std::string rest;
if (!ParseSpecPrefix(message, specPrefix, rest))
{
return message;
}
Player* bot = botAI->GetBot();
if (!MatchesSpec(bot, specPrefix))
{
return "";
}
std::string result = ChatFilter::Filter(rest);
return result;
}
private:
std::map<std::pair<uint8, int>, std::string> specTabNames;
bool ParseSpecPrefix(const std::string& message, std::string& specPrefix, std::string& rest)
{
std::string msgLower = ToLower(message);
for (auto const& entry : specTabNames)
{
std::string prefix = "@" + entry.second;
if (msgLower.find(ToLower(prefix)) == 0)
{
specPrefix = entry.second;
size_t spacePos = message.find(' ');
rest = (spacePos != std::string::npos) ? message.substr(spacePos + 1) : "";
return true;
}
}
return false;
}
bool MatchesSpec(Player* bot, const std::string& specPrefix)
{
uint8 cls = bot->getClass();
int specTab = AiFactory::GetPlayerSpecTab(bot);
std::string botSpecClass;
// For druids, specTab==1 is always feral; distinguish bear/cat at runtime by role
if (cls == CLASS_DRUID && specTab == 1)
{
botSpecClass = botAI->IsTank(bot) ? "bear" : "cat";
}
// For death knights, specTab==0 is always blood; distinguish tank/dps at runtime by role
else if (cls == CLASS_DEATH_KNIGHT && specTab == 0)
{
botSpecClass = botAI->IsTank(bot) ? "bdkt" : "bdkd";
}
else
{
auto it = specTabNames.find({cls, specTab});
if (it != specTabNames.end())
botSpecClass = it->second;
}
return ToLower(botSpecClass) == ToLower(specPrefix);
}
};
class AuraChatFilter : public ChatFilter
{
public:
AuraChatFilter(PlayerbotAI* botAI) : ChatFilter(botAI) {}
std::string const Filter(std::string& message) override
{
Player* bot = botAI->GetBot();
std::string msgLower = ToLower(message);
const std::string auraPrefix = "@aura";
const std::string noAuraPrefix = "@noaura";
size_t prefixLen = 0;
bool isNoAura = false;
if (msgLower.find(auraPrefix) == 0)
{
prefixLen = auraPrefix.length();
isNoAura = false;
}
else if (msgLower.find(noAuraPrefix) == 0)
{
prefixLen = noAuraPrefix.length();
isNoAura = true;
}
else
{
return message;
}
// Trim any leading spaces after @aura or @noaura (can use space between prefix and spell ID if desired, but not required)
std::string auraIdOrName = message.substr(prefixLen);
auraIdOrName.erase(0, auraIdOrName.find_first_not_of(' '));
if (auraIdOrName.empty())
{
return message;
}
uint32 auraId = 0;
size_t spacePos = auraIdOrName.find(' ');
std::string idStr = (spacePos != std::string::npos) ? auraIdOrName.substr(0, spacePos) : auraIdOrName;
std::string rest = (spacePos != std::string::npos) ? auraIdOrName.substr(spacePos + 1) : "";
if (!idStr.empty())
{
bool isNumeric = std::all_of(idStr.begin(), idStr.end(), ::isdigit);
if (isNumeric)
{
auraId = atoi(idStr.c_str());
}
}
if (auraId == 0)
return message;
bool hasAura = bot->HasAura(auraId);
bool match = isNoAura ? !hasAura : hasAura;
std::string result = match ? ChatFilter::Filter(rest) : "";
return result;
}
};
class AggroByChatFilter : public ChatFilter
{
public:
AggroByChatFilter(PlayerbotAI* botAI) : ChatFilter(botAI) {}
std::string const Filter(std::string& message) override
{
Player* bot = botAI->GetBot();
std::string msgLower = ToLower(message);
const std::string prefix = "@aggroby";
size_t prefixLen = prefix.length();
if (msgLower.find(prefix) != 0)
{
return message;
}
// Trim any leading spaces after @aggroby (can use space between prefix and entry ID/creature name if desired, but not required)
std::string enemyStr = message.substr(prefixLen);
enemyStr.erase(0, enemyStr.find_first_not_of(' '));
if (enemyStr.empty())
{
return message;
}
// If creature name is more than one word, it must be enclosed in quotes, e.g. @aggroby "Scarlet Commander Mograine" flee
std::string rest = "";
std::string enemyName = "";
bool isName = false;
uint32 entryId = 0;
if (enemyStr[0] == '"')
{
size_t endQuote = enemyStr.find('"', 1);
if (endQuote != std::string::npos)
{
enemyName = enemyStr.substr(1, endQuote - 1);
isName = true;
size_t spacePos = enemyStr.find(' ', endQuote + 1);
if (spacePos != std::string::npos)
{
rest = enemyStr.substr(spacePos + 1);
}
else
{
rest = "";
}
}
else
{
enemyName = enemyStr.substr(1);
isName = true;
rest = "";
}
}
else
{
size_t splitPos = enemyStr.find_first_of(" ");
std::string idOrName = (splitPos != std::string::npos) ? enemyStr.substr(0, splitPos) : enemyStr;
if (splitPos != std::string::npos)
{
rest = enemyStr.substr(splitPos + 1);
}
else
{
rest = "";
}
if (!idOrName.empty())
{
bool isNumeric = std::all_of(idOrName.begin(), idOrName.end(), ::isdigit);
if (isNumeric)
{
entryId = atoi(idOrName.c_str());
}
else
{
enemyName = idOrName;
isName = true;
}
}
}
const float radius = 100.0f;
GuidVector npcs = botAI->GetAiObjectContext()->GetValue<GuidVector>("nearest npcs")->Get();
bool match = false;
for (auto const& guid : npcs)
{
Creature* c = botAI->GetCreature(guid);
if (!c)
{
continue;
}
bool nameMatch = isName && ToLower(c->GetName()) == ToLower(enemyName);
bool idMatch = (entryId != 0) && c->GetEntry() == entryId;
if ((nameMatch || idMatch) && c->GetDistance2d(bot) <= radius)
{
Unit* victim = c->GetVictim();
if (victim && victim->GetGUID() == bot->GetGUID())
{
match = true;
break;
}
}
}
std::string result = match ? ChatFilter::Filter(rest) : "";
return result;
}
};
CompositeChatFilter::CompositeChatFilter(PlayerbotAI* botAI) : ChatFilter(botAI)
{
filters.push_back(new StrategyChatFilter(botAI));
filters.push_back(new ClassChatFilter(botAI));
filters.push_back(new RtiChatFilter(botAI));
filters.push_back(new CombatTypeChatFilter(botAI));
filters.push_back(new LevelChatFilter(botAI));
filters.push_back(new SubGroupChatFilter(botAI));
filters.push_back(new SpecChatFilter(botAI));
filters.push_back(new AuraChatFilter(botAI));
filters.push_back(new AggroByChatFilter(botAI));
}
CompositeChatFilter::~CompositeChatFilter()
{
for (std::vector<ChatFilter*>::iterator i = filters.begin(); i != filters.end(); i++)
delete (*i);
}
std::string const CompositeChatFilter::Filter(std::string& message)
{
for (auto* filter : filters)
{
message = filter->Filter(message);
if (message.empty())
break;
}
return message;
}

View File

@@ -1,46 +0,0 @@
#include "PlayerbotSpellRepository.h"
// caches the result set
void PlayerbotSpellRepository::Initialize()
{
LOG_INFO("playerbots", "Playerbots: ListSpellsAction caches initialized");
for (uint32 j = 0; j < sSkillLineAbilityStore.GetNumRows(); ++j)
{
if (SkillLineAbilityEntry const* skillLine = sSkillLineAbilityStore.LookupEntry(j))
skillSpells[skillLine->Spell] = skillLine;
}
// Fill the vendorItems cache once from the world database.
QueryResult results = WorldDatabase.Query("SELECT item FROM npc_vendor WHERE maxcount = 0");
if (results)
{
do
{
Field* fields = results->Fetch();
int32 entry = fields[0].Get<int32>();
if (entry <= 0)
continue;
vendorItems.insert(static_cast<uint32>(entry));
}
while (results->NextRow());
}
LOG_DEBUG("playerbots",
"ListSpellsAction: initialized caches (skillSpells={}, vendorItems={}).",
skillSpells.size(), vendorItems.size());
}
SkillLineAbilityEntry const* PlayerbotSpellRepository::GetSkillLine(uint32 spellId) const
{
auto itr = skillSpells.find(spellId);
if (itr != skillSpells.end())
return itr->second;
return nullptr;
}
bool PlayerbotSpellRepository::IsItemBuyable(uint32 itemId) const
{
return vendorItems.find(itemId) != vendorItems.end();
}

View File

@@ -1,34 +0,0 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
* and/or modify it under version 3 of the License, or (at your option), any later version.
*/
#ifndef _PLAYERBOT_PLAYERBOTSPELLREPOSITORY_H
#define _PLAYERBOT_PLAYERBOTSPELLREPOSITORY_H
#include "Playerbots.h"
class PlayerbotSpellRepository
{
public:
static PlayerbotSpellRepository* Instance()
{
static PlayerbotSpellRepository instance;
return &instance;
}
void Initialize(); // call once on startup
SkillLineAbilityEntry const* GetSkillLine(uint32 spellId) const;
bool IsItemBuyable(uint32 itemId) const;
private:
PlayerbotSpellRepository() = default;
std::map<uint32, SkillLineAbilityEntry const*> skillSpells;
std::set<uint32> vendorItems;
};
#define sPlayerbotSpellRepository PlayerbotSpellRepository::Instance()
#endif

View File

@@ -1,322 +0,0 @@
#include "PlayerbotGuildMgr.h"
#include "Player.h"
#include "PlayerbotAIConfig.h"
#include "DatabaseEnv.h"
#include "Guild.h"
#include "GuildMgr.h"
#include "RandomPlayerbotMgr.h"
#include "ScriptMgr.h"
PlayerbotGuildMgr::PlayerbotGuildMgr(){}
void PlayerbotGuildMgr::Init()
{
_guildCache.clear();
if (sPlayerbotAIConfig->deleteRandomBotGuilds)
DeleteBotGuilds();
LoadGuildNames();
ValidateGuildCache();
}
bool PlayerbotGuildMgr::CreateGuild(Player* player, std::string guildName)
{
Guild* guild = new Guild();
if (!guild->Create(player, guildName))
{
LOG_ERROR("playerbots", "Error creating guild [ {} ] with leader [ {} ]", guildName,
player->GetName());
delete guild;
return false;
}
sGuildMgr->AddGuild(guild);
LOG_DEBUG("playerbots", "Guild created: id={} name='{}'", guild->GetId(), guildName);
SetGuildEmblem(guild->GetId());
GuildCache entry;
entry.name = guildName;
entry.memberCount = 1;
entry.status = 1;
entry.maxMembers = sPlayerbotAIConfig->randomBotGuildSizeMax;
entry.faction = player->GetTeamId();
_guildCache[guild->GetId()] = entry;
return true;
}
bool PlayerbotGuildMgr::SetGuildEmblem(uint32 guildId)
{
Guild* guild = sGuildMgr->GetGuildById(guildId);
if (!guild)
return false;
// create random emblem
uint32 st, cl, br, bc, bg;
bg = urand(0, 51);
bc = urand(0, 17);
cl = urand(0, 17);
br = urand(0, 7);
st = urand(0, 180);
LOG_DEBUG("playerbots",
"[TABARD] new guild id={} random -> style={}, color={}, borderStyle={}, borderColor={}, bgColor={}",
guild->GetId(), st, cl, br, bc, bg);
// populate guild table with a random tabard design
CharacterDatabase.Execute(
"UPDATE guild SET EmblemStyle={}, EmblemColor={}, BorderStyle={}, BorderColor={}, BackgroundColor={} "
"WHERE guildid={}",
st, cl, br, bc, bg, guild->GetId());
LOG_DEBUG("playerbots", "[TABARD] UPDATE done for guild id={}", guild->GetId());
// Immediate reading for log
if (QueryResult qr = CharacterDatabase.Query(
"SELECT EmblemStyle,EmblemColor,BorderStyle,BorderColor,BackgroundColor FROM guild WHERE guildid={}",
guild->GetId()))
{
Field* f = qr->Fetch();
LOG_DEBUG("playerbots",
"[TABARD] DB check guild id={} => style={}, color={}, borderStyle={}, borderColor={}, bgColor={}",
guild->GetId(), f[0].Get<uint8>(), f[1].Get<uint8>(), f[2].Get<uint8>(), f[3].Get<uint8>(), f[4].Get<uint8>());
}
return true;
}
std::string PlayerbotGuildMgr::AssignToGuild(Player* player)
{
if (!player)
return "";
uint8_t playerFaction = player->GetTeamId();
std::vector<GuildCache*> partiallyfilledguilds;
partiallyfilledguilds.reserve(_guildCache.size());
for (auto& keyValue : _guildCache)
{
GuildCache& cached = keyValue.second;
if (!cached.hasRealPlayer && cached.status == 1 && cached.faction == playerFaction)
partiallyfilledguilds.push_back(&cached);
}
if (!partiallyfilledguilds.empty())
{
size_t idx = static_cast<size_t>(urand(0, static_cast<int>(partiallyfilledguilds.size()) - 1));
return (partiallyfilledguilds[idx]->name);
}
size_t count = std::count_if(
_guildCache.begin(), _guildCache.end(),
[](const std::pair<const uint32, GuildCache>& pair)
{
return !pair.second.hasRealPlayer;
}
);
if (count < sPlayerbotAIConfig->randomBotGuildCount)
{
for (auto& key : _shuffled_guild_keys)
{
if (_guildNames[key])
{
LOG_INFO("playerbots","Assigning player [{}] to guild [{}]", player->GetName(), key);
return key;
}
}
LOG_ERROR("playerbots","No available guild names left.");
}
return "";
}
void PlayerbotGuildMgr::OnGuildUpdate(Guild* guild)
{
auto it = _guildCache.find(guild->GetId());
if (it == _guildCache.end())
return;
GuildCache& entry = it->second;
entry.memberCount = guild->GetMemberCount();
if (entry.memberCount < entry.maxMembers)
entry.status = 1;
else if (entry.memberCount >= entry.maxMembers)
entry.status = 2; // Full
std::string guildName = guild->GetName();
for (auto& it : _guildNames)
{
if (it.first == guildName)
{
it.second = false;
break;
}
}
}
void PlayerbotGuildMgr::ResetGuildCache()
{
for (auto it = _guildCache.begin(); it != _guildCache.end();)
{
GuildCache& cached = it->second;
cached.memberCount = 0;
cached.faction = 2;
cached.status = 0;
}
}
void PlayerbotGuildMgr::LoadGuildNames()
{
LOG_INFO("playerbots", "Loading guild names from playerbots_guild_names...");
QueryResult result = CharacterDatabase.Query("SELECT name_id, name FROM playerbots_guild_names");
if (!result)
{
LOG_ERROR("playerbots", "No entries found in playerbots_guild_names. List is empty.");
return;
}
do
{
Field* fields = result->Fetch();
_guildNames[fields[1].Get<std::string>()] = true;
} while (result->NextRow());
for (auto& pair : _guildNames)
_shuffled_guild_keys.push_back(pair.first);
std::random_device rd;
std::mt19937 g(rd());
std::shuffle(_shuffled_guild_keys.begin(), _shuffled_guild_keys.end(), g);
LOG_INFO("playerbots", "Loaded {} guild entries from playerbots_guild_names table.", _guildNames.size());
}
void PlayerbotGuildMgr::ValidateGuildCache()
{
QueryResult result = CharacterDatabase.Query("SELECT guildid, name FROM guild");
if (!result)
{
LOG_ERROR("playerbots", "No guilds found in database, resetting guild cache");
ResetGuildCache();
return;
}
std::unordered_map<uint32, std::string> dbGuilds;
do
{
Field* fields = result->Fetch();
uint32 guildId = fields[0].Get<uint32>();
std::string guildName = fields[1].Get<std::string>();
dbGuilds[guildId] = guildName;
} while (result->NextRow());
for (auto it = dbGuilds.begin(); it != dbGuilds.end(); it++)
{
uint32 guildId = it->first;
GuildCache cache;
cache.name = it->second;
cache.maxMembers = sPlayerbotAIConfig->randomBotGuildSizeMax;
Guild* guild = sGuildMgr ->GetGuildById(guildId);
if (!guild)
continue;
cache.memberCount = guild->GetMemberCount();
ObjectGuid leaderGuid = guild->GetLeaderGUID();
CharacterCacheEntry const* leaderEntry = sCharacterCache->GetCharacterCacheByGuid(leaderGuid);
uint32 leaderAccount = leaderEntry->AccountId;
cache.hasRealPlayer = !(sPlayerbotAIConfig->IsInRandomAccountList(leaderAccount));
cache.faction = Player::TeamIdForRace(leaderEntry->Race);
if (cache.memberCount == 0)
cache.status = 0; // empty
else if (cache.memberCount < cache.maxMembers)
cache.status = 1; // partially filled
else
cache.status = 2; // full
_guildCache.insert_or_assign(guildId, cache);
for (auto& it : _guildNames)
{
if (it.first == cache.name)
{
it.second = false;
break;
}
}
}
}
void PlayerbotGuildMgr::DeleteBotGuilds()
{
LOG_INFO("playerbots", "Deleting random bot guilds...");
std::vector<uint32> randomBots;
PlayerbotsDatabasePreparedStatement* stmt = PlayerbotsDatabase.GetPreparedStatement(PLAYERBOTS_SEL_RANDOM_BOTS_BOT);
stmt->SetData(0, "add");
if (PreparedQueryResult result = PlayerbotsDatabase.Query(stmt))
{
do
{
Field* fields = result->Fetch();
uint32 bot = fields[0].Get<uint32>();
randomBots.push_back(bot);
} while (result->NextRow());
}
for (std::vector<uint32>::iterator i = randomBots.begin(); i != randomBots.end(); ++i)
{
if (Guild* guild = sGuildMgr->GetGuildByLeader(ObjectGuid::Create<HighGuid::Player>(*i)))
guild->Disband();
}
LOG_INFO("playerbots", "Random bot guilds deleted");
}
bool PlayerbotGuildMgr::IsRealGuild(Player* bot)
{
if (!bot)
return false;
uint32 guildId = bot->GetGuildId();
if (!guildId)
return false;
return IsRealGuild(guildId);
}
bool PlayerbotGuildMgr::IsRealGuild(uint32 guildId)
{
if (!guildId)
return false;
auto it = _guildCache.find(guildId);
if (it == _guildCache.end())
return false;
return it->second.hasRealPlayer;
}
class BotGuildCacheWorldScript : public WorldScript
{
public:
BotGuildCacheWorldScript() : WorldScript("BotGuildCacheWorldScript"), _validateTimer(0){}
void OnUpdate(uint32 diff) override
{
_validateTimer += diff;
if (_validateTimer >= _validateInterval) // Validate every hour
{
_validateTimer = 0;
sPlayerbotGuildMgr->ValidateGuildCache();
LOG_INFO("playerbots", "Scheduled guild cache validation");
}
}
private:
uint32 _validateInterval = HOUR*IN_MILLISECONDS;
uint32 _validateTimer;
};
void PlayerBotsGuildValidationScript()
{
new BotGuildCacheWorldScript();
}

View File

@@ -1,52 +0,0 @@
#ifndef _PLAYERBOT_PLAYERBOTGUILDMGR_H
#define _PLAYERBOT_PLAYERBOTGUILDMGR_H
#include "Guild.h"
#include "Player.h"
#include "PlayerbotAI.h"
class PlayerbotAI;
class PlayerbotGuildMgr
{
public:
static PlayerbotGuildMgr* instance()
{
static PlayerbotGuildMgr instance;
return &instance;
}
void Init();
std::string AssignToGuild(Player* player);
void LoadGuildNames();
void ValidateGuildCache();
void ResetGuildCache();
bool CreateGuild(Player* player, std::string guildName);
void OnGuildUpdate (Guild* guild);
bool SetGuildEmblem(uint32 guildId);
void DeleteBotGuilds();
bool IsRealGuild(uint32 guildId);
bool IsRealGuild(Player* bot);
private:
PlayerbotGuildMgr();
std::unordered_map<std::string, bool> _guildNames;
struct GuildCache
{
std::string name;
uint8 status;
uint32 maxMembers = 0;
uint32 memberCount = 0;
uint8 faction = 0;
bool hasRealPlayer = false;
};
std::unordered_map<uint32 , GuildCache> _guildCache;
std::vector<std::string> _shuffled_guild_keys;
};
void PlayerBotsGuildValidationScript();
#define sPlayerbotGuildMgr PlayerbotGuildMgr::instance()
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
* and/or modify it under version 3 of the License, or (at your option), any later version.
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it
* and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#ifndef _PLAYERBOT_PLAYERbotAI_H
@@ -46,27 +46,27 @@ struct GameObjectData;
enum StrategyType : uint32;
enum HealingItemId
enum HealingItemDisplayId
{
HEALTHSTONE = 5512,
MAJOR_HEALING_POTION = 13446,
WHIPPER_ROOT_TUBER = 11951,
NIGHT_DRAGON_BREATH = 11952,
LIMITED_INVULNERABILITY_POTION = 3387,
GREATER_DREAMLESS_SLEEP_POTION = 22886,
SUPERIOR_HEALING_POTION = 3928,
CRYSTAL_RESTORE = 11564,
DREAMLESS_SLEEP_POTION = 12190,
GREATER_HEALING_POTION = 1710,
HEALING_POTION = 929,
LESSER_HEALING_POTION = 858,
DISCOLORED_HEALING_POTION = 3391,
MINOR_HEALING_POTION = 118,
VOLATILE_HEALING_POTION = 28100,
SUPER_HEALING_POTION = 22829,
CRYSTAL_HEALING_POTION = 13462,
FEL_REGENERATION_POTION = 28101,
MAJOR_DREAMLESS_SLEEP_POTION = 20002
HEALTHSTONE_DISPLAYID = 8026,
MAJOR_HEALING_POTION = 24152,
WHIPPER_ROOT_TUBER = 21974,
NIGHT_DRAGON_BREATH = 21975,
LIMITED_INVULNERABILITY_POTION = 24213,
GREATER_DREAMLESS_SLEEP_POTION = 17403,
SUPERIOR_HEALING_POTION = 15714,
CRYSTAL_RESTORE = 2516,
DREAMLESS_SLEEP_POTION = 17403,
GREATER_HEALING_POTION = 15713,
HEALING_POTION = 15712,
LESSER_HEALING_POTION = 15711,
DISCOLORED_HEALING_POTION = 15736,
MINOR_HEALING_POTION = 15710,
VOLATILE_HEALING_POTION = 24212,
SUPER_HEALING_POTION = 37807,
CRYSTAL_HEALING_POTION = 47132,
FEL_REGENERATION_POTION = 37864,
MAJOR_DREAMLESS_SLEEP_POTION = 37845
};
enum BotState
@@ -152,7 +152,6 @@ static std::map<ChatChannelSource, std::string> ChatChannelSourceStr = {
{SRC_RAID, "SRC_RAID"},
{SRC_UNDEFINED, "SRC_UNDEFINED"}};
enum ChatChannelId
{
GENERAL = 1,
@@ -163,66 +162,60 @@ enum ChatChannelId
GUILD_RECRUITMENT = 25,
};
enum RoguePoisonId
enum RoguePoisonDisplayId
{
INSTANT_POISON = 6947,
INSTANT_POISON_II = 6949,
INSTANT_POISON_III = 6950,
INSTANT_POISON_IV = 8926,
INSTANT_POISON_V = 8927,
INSTANT_POISON_VI = 8928,
INSTANT_POISON_VII = 21927,
INSTANT_POISON_VIII = 43230,
INSTANT_POISON_IX = 43231,
DEADLY_POISON = 2892,
DEADLY_POISON_II = 2893,
DEADLY_POISON_III = 8984,
DEADLY_POISON_IV = 8985,
DEADLY_POISON_V = 20844,
DEADLY_POISON_VI = 22053,
DEADLY_POISON_VII = 22054,
DEADLY_POISON_VIII = 43232,
DEADLY_POISON_IX = 43233
DEADLY_POISON_DISPLAYID = 13707,
INSTANT_POISON_DISPLAYID = 13710,
WOUND_POISON_DISPLAYID = 37278
};
enum SharpeningStoneId
enum SharpeningStoneDisplayId
{
ROUGH_SHARPENING_STONE = 2862,
COARSE_SHARPENING_STONE = 2863,
HEAVY_SHARPENING_STONE = 2871,
SOLID_SHARPENING_STONE = 7964,
DENSE_SHARPENING_STONE = 12404,
ELEMENTAL_SHARPENING_STONE = 18262,
FEL_SHARPENING_STONE = 23528,
ADAMANTITE_SHARPENING_STONE = 23529
ROUGH_SHARPENING_DISPLAYID = 24673,
COARSE_SHARPENING_DISPLAYID = 24674,
HEAVY_SHARPENING_DISPLAYID = 24675,
SOLID_SHARPENING_DISPLAYID = 24676,
DENSE_SHARPENING_DISPLAYID = 24677,
CONSECRATED_SHARPENING_DISPLAYID =
24674, // will not be used because bot can not know if it will face undead targets
ELEMENTAL_SHARPENING_DISPLAYID = 21072,
FEL_SHARPENING_DISPLAYID = 39192,
ADAMANTITE_SHARPENING_DISPLAYID = 39193
};
enum WeightstoneId
enum WeightStoneDisplayId
{
ROUGH_WEIGHTSTONE = 3239,
COARSE_WEIGHTSTONE = 3240,
HEAVY_WEIGHTSTONE = 3241,
SOLID_WEIGHTSTONE = 7965,
DENSE_WEIGHTSTONE = 12643,
FEL_WEIGHTSTONE = 28420,
ADAMANTITE_WEIGHTSTONE = 28421
ROUGH_WEIGHTSTONE_DISPLAYID = 24683,
COARSE_WEIGHTSTONE_DISPLAYID = 24684,
HEAVY_WEIGHTSTONE_DISPLAYID = 24685,
SOLID_WEIGHTSTONE_DISPLAYID = 24686,
DENSE_WEIGHTSTONE_DISPLAYID = 24687,
FEL_WEIGHTSTONE_DISPLAYID = 39548,
ADAMANTITE_WEIGHTSTONE_DISPLAYID = 39549
};
enum WizardOilId
enum WizardOilDisplayId
{
MINOR_WIZARD_OIL = 20744,
LESSER_WIZARD_OIL = 20746,
WIZARD_OIL = 20750,
BRILLIANT_WIZARD_OIL = 20749,
SUPERIOR_WIZARD_OIL = 22522
MINOR_WIZARD_OIL = 9731,
LESSER_WIZARD_OIL = 47903,
BRILLIANT_WIZARD_OIL = 47901,
WIZARD_OIL = 47905,
SUPERIOR_WIZARD_OIL = 47904,
/// Blessed Wizard Oil = 26865 //scourge inv
};
enum ManaOilId
enum ManaOilDisplayId
{
MINOR_MANA_OIL = 20745,
LESSER_MANA_OIL = 20747,
BRILLIANT_MANA_OIL = 20748,
SUPERIOR_MANA_OIL = 22521
MINOR_MANA_OIL = 34492,
LESSER_MANA_OIL = 47902,
BRILLIANT_MANA_OIL = 41488,
SUPERIOR_MANA_OIL = 36862
};
enum ShieldWardDisplayId
{
LESSER_WARD_OFSHIELDING = 38759,
GREATER_WARD_OFSHIELDING = 38760
};
enum class BotTypeNumber : uint8
@@ -276,7 +269,7 @@ enum BotRoles : uint8
enum HUNTER_TABS
{
HUNTER_TAB_BEAST_MASTERY,
HUNTER_TAB_BEASTMASTER,
HUNTER_TAB_MARKSMANSHIP,
HUNTER_TAB_SURVIVAL,
};
@@ -285,21 +278,21 @@ enum ROGUE_TABS
{
ROGUE_TAB_ASSASSINATION,
ROGUE_TAB_COMBAT,
ROGUE_TAB_SUBTLETY,
ROGUE_TAB_SUBTLETY
};
enum PRIEST_TABS
{
PRIEST_TAB_DISCIPLINE,
PRIEST_TAB_DISIPLINE,
PRIEST_TAB_HOLY,
PRIEST_TAB_SHADOW,
};
enum DEATH_KNIGHT_TABS
enum DEATHKNIGHT_TABS
{
DEATH_KNIGHT_TAB_BLOOD,
DEATH_KNIGHT_TAB_FROST,
DEATH_KNIGHT_TAB_UNHOLY,
DEATHKNIGHT_TAB_BLOOD,
DEATHKNIGHT_TAB_FROST,
DEATHKNIGHT_TAB_UNHOLY,
};
enum DRUID_TABS
@@ -332,7 +325,7 @@ enum PALADIN_TABS
enum WARLOCK_TABS
{
WARLOCK_TAB_AFFLICTION,
WARLOCK_TAB_AFFLICATION,
WARLOCK_TAB_DEMONOLOGY,
WARLOCK_TAB_DESTRUCTION,
};
@@ -408,14 +401,12 @@ public:
void ClearStrategies(BotState type);
std::vector<std::string> GetStrategies(BotState type);
void ApplyInstanceStrategies(uint32 mapId, bool tellMaster = false);
void EvaluateHealerDpsStrategy();
bool ContainsStrategy(StrategyType type);
bool HasStrategy(std::string const name, BotState type);
BotState GetState() { return currentState; };
void ResetStrategies(bool load = false);
void ReInitCurrentEngine();
void Reset(bool full = false);
void LeaveOrDisbandGroup();
static bool IsTank(Player* player, bool bySpec = false);
static bool IsHeal(Player* player, bool bySpec = false);
static bool IsDps(Player* player, bool bySpec = false);
@@ -424,15 +415,13 @@ public:
static bool IsCaster(Player* player, bool bySpec = false);
static bool IsRangedDps(Player* player, bool bySpec = false);
static bool IsCombo(Player* player);
static bool IsBotMainTank(Player* player);
static bool IsMainTank(Player* player);
static uint32 GetGroupTankNum(Player* player);
static bool IsAssistTank(Player* player);
static bool IsAssistTankOfIndex(Player* player, int index, bool ignoreDeadPlayers = false);
static bool IsHealAssistantOfIndex(Player* player, int index);
static bool IsRangedDpsAssistantOfIndex(Player* player, int index);
bool IsAssistTank(Player* player);
bool IsAssistTankOfIndex(Player* player, int index);
bool IsHealAssistantOfIndex(Player* player, int index);
bool IsRangedDpsAssistantOfIndex(Player* player, int index);
bool HasAggro(Unit* unit);
static int32 GetAssistTankIndex(Player* player);
int32 GetGroupSlotIndex(Player* player);
int32 GetRangedIndex(Player* player);
int32 GetClassIndex(Player* player, uint8 cls);
@@ -482,7 +471,7 @@ public:
Item* FindBandage() const;
Item* FindOpenableItem() const;
Item* FindLockedItem() const;
Item* FindConsumable(uint32 itemId) const;
Item* FindConsumable(uint32 displayId) const;
Item* FindStoneFor(Item* weapon) const;
Item* FindOilFor(Item* weapon) const;
void ImbueItem(Item* item, uint32 targetFlag, ObjectGuid targetGUID);
@@ -529,7 +518,6 @@ public:
Player* GetBot() { return bot; }
Player* GetMaster() { return master; }
Player* FindNewMaster();
// Checks if the bot is really a player. Players always have themselves as master.
bool IsRealPlayer() { return master ? (master == bot) : false; }
@@ -540,7 +528,7 @@ public:
// Get the group leader or the master of the bot.
// Checks if the bot is summoned as alt of a player
bool IsAlt();
Player* GetGroupLeader();
Player* GetGroupMaster();
// Returns a semi-random (cycling) number that is fixed for each bot.
uint32 GetFixedBotNumer(uint32 maxNum = 100, float cyclePerMin = 1);
GrouperType GetGrouperType();
@@ -557,8 +545,6 @@ public:
bool IsSafe(WorldObject* obj);
ChatChannelSource GetChatChannelSource(Player* bot, uint32 type, std::string channelName);
bool CheckLocationDistanceByLevel(Player* player, const WorldLocation &loc, bool fromStartUp = false);
bool HasCheat(BotCheatMask mask)
{
return ((uint32)mask & (uint32)cheatMask) != 0 ||
@@ -579,6 +565,7 @@ public:
void ResetJumpDestination() { jumpDestination = Position(); }
bool CanMove();
static bool IsRealGuild(uint32 guildId);
bool IsInRealGuild();
static std::vector<std::string> dispel_whitelist;
bool EqualLowercaseName(std::string s1, std::string s2);
@@ -602,29 +589,17 @@ public:
NewRpgInfo rpgInfo;
NewRpgStatistic rpgStatistic;
std::unordered_set<uint32> lowPriorityQuest;
time_t bgReleaseAttemptTime = 0;
// Schedules a callback to run once after <delayMs> milliseconds.
void AddTimedEvent(std::function<void()> callback, uint32 delayMs);
private:
static void _fillGearScoreData(Player* player, Item* item, std::vector<uint32>* gearScore, uint32& twoHandScore,
bool mixed = false);
bool IsTellAllowed(PlayerbotSecurityLevel securityLevel = PLAYERBOT_SECURITY_ALLOW_ALL);
void UpdateAIGroupMaster();
void UpdateAIGroupMembership();
Item* FindItemInInventory(std::function<bool(ItemTemplate const*)> checkItem) const;
void HandleCommands();
void HandleCommand(uint32 type, const std::string& text, Player& fromPlayer, const uint32 lang = LANG_UNIVERSAL);
bool _isBotInitializing = false;
inline bool IsValidUnit(const Unit* unit) const
{
return unit && unit->IsInWorld() && !unit->IsDuringRemoveFromWorld();
}
inline bool IsValidPlayer(const Player* player) const
{
return player && player->GetSession() && player->IsInWorld() && !player->IsDuringRemoveFromWorld() &&
!player->IsBeingTeleported();
}
protected:
Player* bot;
Player* master;

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
* and/or modify it under version 3 of the License, or (at your option), any later version.
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it
* and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#ifndef _PLAYERBOT_PLAYERbotAIAWARE_H

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
* and/or modify it under version 3 of the License, or (at your option), any later version.
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it
* and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#include "PlayerbotAIBase.h"
@@ -14,7 +14,7 @@ void PlayerbotAIBase::UpdateAI(uint32 elapsed, bool minimal)
if (totalPmo)
totalPmo->finish();
totalPmo = sPerfMonitor->start(PERF_MON_TOTAL, "PlayerbotAIBase::FullTick");
totalPmo = sPerformanceMonitor->start(PERF_MON_TOTAL, "PlayerbotAIBase::FullTick");
if (nextAICheckDelay > elapsed)
nextAICheckDelay -= elapsed;

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
* and/or modify it under version 3 of the License, or (at your option), any later version.
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it
* and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#ifndef _PLAYERBOT_PLAYERBOTAIBASE_H
@@ -25,7 +25,7 @@ public:
protected:
uint32 nextAICheckDelay;
class PerfMonitorOperation* totalPmo = nullptr;
class PerformanceMonitorOperation* totalPmo = nullptr;
private:
bool _isBotAI;

View File

@@ -1,16 +1,16 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
* and/or modify it under version 3 of the License, or (at your option), any later version.
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it
* and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#include "PlayerbotAIConfig.h"
#include <iostream>
#include "Config.h"
#include "NewRpgInfo.h"
#include "PlayerbotDungeonRepository.h"
#include "PlayerbotDungeonSuggestionMgr.h"
#include "PlayerbotFactory.h"
#include "Playerbots.h"
#include "PlayerbotGuildMgr.h"
#include "RandomItemMgr.h"
#include "RandomPlayerbotFactory.h"
#include "RandomPlayerbotMgr.h"
@@ -58,54 +58,50 @@ void LoadListString(std::string const value, T& list)
bool PlayerbotAIConfig::Initialize()
{
LOG_INFO("server.loading", "Initializing mod-playerbots, based on AI Playerbots by ike3 and the original Playerbots by blueboy");
LOG_INFO("server.loading", "Initializing AI Playerbots by ike3, based on the original Playerbots by blueboy");
enabled = sConfigMgr->GetOption<bool>("AiPlayerbot.Enabled", true);
if (!enabled)
{
LOG_INFO("server.loading", "Playerbots Module is disabled in playerbots.conf");
LOG_INFO("server.loading", "AI Playerbots is Disabled in aiplayerbot.conf");
return false;
}
globalCoolDown = sConfigMgr->GetOption<int32>("AiPlayerbot.GlobalCooldown", 500);
globalCoolDown = sConfigMgr->GetOption<int32>("AiPlayerbot.GlobalCooldown", 1500);
maxWaitForMove = sConfigMgr->GetOption<int32>("AiPlayerbot.MaxWaitForMove", 5000);
disableMoveSplinePath = sConfigMgr->GetOption<int32>("AiPlayerbot.DisableMoveSplinePath", 0);
maxMovementSearchTime = sConfigMgr->GetOption<int32>("AiPlayerbot.MaxMovementSearchTime", 3);
expireActionTime = sConfigMgr->GetOption<int32>("AiPlayerbot.ExpireActionTime", 5000);
dispelAuraDuration = sConfigMgr->GetOption<int32>("AiPlayerbot.DispelAuraDuration", 700);
dispelAuraDuration = sConfigMgr->GetOption<int32>("AiPlayerbot.DispelAuraDuration", 7000);
reactDelay = sConfigMgr->GetOption<int32>("AiPlayerbot.ReactDelay", 100);
dynamicReactDelay = sConfigMgr->GetOption<bool>("AiPlayerbot.DynamicReactDelay", true);
passiveDelay = sConfigMgr->GetOption<int32>("AiPlayerbot.PassiveDelay", 10000);
repeatDelay = sConfigMgr->GetOption<int32>("AiPlayerbot.RepeatDelay", 2000);
errorDelay = sConfigMgr->GetOption<int32>("AiPlayerbot.ErrorDelay", 100);
errorDelay = sConfigMgr->GetOption<int32>("AiPlayerbot.ErrorDelay", 5000);
rpgDelay = sConfigMgr->GetOption<int32>("AiPlayerbot.RpgDelay", 10000);
sitDelay = sConfigMgr->GetOption<int32>("AiPlayerbot.SitDelay", 20000);
returnDelay = sConfigMgr->GetOption<int32>("AiPlayerbot.ReturnDelay", 2000);
sitDelay = sConfigMgr->GetOption<int32>("AiPlayerbot.SitDelay", 30000);
returnDelay = sConfigMgr->GetOption<int32>("AiPlayerbot.ReturnDelay", 7000);
lootDelay = sConfigMgr->GetOption<int32>("AiPlayerbot.LootDelay", 1000);
minBotsForGreaterBuff = sConfigMgr->GetOption<int32>("AiPlayerbot.MinBotsForGreaterBuff", 3);
rpWarningCooldown = sConfigMgr->GetOption<int32>("AiPlayerbot.RPWarningCooldown", 30);
disabledWithoutRealPlayerLoginDelay = sConfigMgr->GetOption<int32>("AiPlayerbot.DisabledWithoutRealPlayerLoginDelay", 30);
disabledWithoutRealPlayerLogoutDelay = sConfigMgr->GetOption<int32>("AiPlayerbot.DisabledWithoutRealPlayerLogoutDelay", 300);
farDistance = sConfigMgr->GetOption<float>("AiPlayerbot.FarDistance", 20.0f);
sightDistance = sConfigMgr->GetOption<float>("AiPlayerbot.SightDistance", 100.0f);
spellDistance = sConfigMgr->GetOption<float>("AiPlayerbot.SpellDistance", 28.5f);
shootDistance = sConfigMgr->GetOption<float>("AiPlayerbot.ShootDistance", 5.0f);
healDistance = sConfigMgr->GetOption<float>("AiPlayerbot.HealDistance", 38.5f);
sightDistance = sConfigMgr->GetOption<float>("AiPlayerbot.SightDistance", 75.0f);
spellDistance = sConfigMgr->GetOption<float>("AiPlayerbot.SpellDistance", 25.0f);
shootDistance = sConfigMgr->GetOption<float>("AiPlayerbot.ShootDistance", 25.0f);
healDistance = sConfigMgr->GetOption<float>("AiPlayerbot.HealDistance", 25.0f);
lootDistance = sConfigMgr->GetOption<float>("AiPlayerbot.LootDistance", 15.0f);
fleeDistance = sConfigMgr->GetOption<float>("AiPlayerbot.FleeDistance", 5.0f);
fleeDistance = sConfigMgr->GetOption<float>("AiPlayerbot.FleeDistance", 7.5f);
aggroDistance = sConfigMgr->GetOption<float>("AiPlayerbot.AggroDistance", 22.0f);
tooCloseDistance = sConfigMgr->GetOption<float>("AiPlayerbot.TooCloseDistance", 5.0f);
meleeDistance = sConfigMgr->GetOption<float>("AiPlayerbot.MeleeDistance", 0.75f);
followDistance = sConfigMgr->GetOption<float>("AiPlayerbot.FollowDistance", 1.5f);
whisperDistance = sConfigMgr->GetOption<float>("AiPlayerbot.WhisperDistance", 6000.0f);
contactDistance = sConfigMgr->GetOption<float>("AiPlayerbot.ContactDistance", 0.45f);
aoeRadius = sConfigMgr->GetOption<float>("AiPlayerbot.AoeRadius", 10.0f);
contactDistance = sConfigMgr->GetOption<float>("AiPlayerbot.ContactDistance", 0.5f);
aoeRadius = sConfigMgr->GetOption<float>("AiPlayerbot.AoeRadius", 5.0f);
rpgDistance = sConfigMgr->GetOption<float>("AiPlayerbot.RpgDistance", 200.0f);
grindDistance = sConfigMgr->GetOption<float>("AiPlayerbot.GrindDistance", 75.0f);
reactDistance = sConfigMgr->GetOption<float>("AiPlayerbot.ReactDistance", 150.0f);
criticalHealth = sConfigMgr->GetOption<int32>("AiPlayerbot.CriticalHealth", 25);
criticalHealth = sConfigMgr->GetOption<int32>("AiPlayerbot.CriticalHealth", 20);
lowHealth = sConfigMgr->GetOption<int32>("AiPlayerbot.LowHealth", 45);
mediumHealth = sConfigMgr->GetOption<int32>("AiPlayerbot.MediumHealth", 65);
almostFullHealth = sConfigMgr->GetOption<int32>("AiPlayerbot.AlmostFullHealth", 85);
@@ -116,12 +112,11 @@ bool PlayerbotAIConfig::Initialize()
saveManaThreshold = sConfigMgr->GetOption<int32>("AiPlayerbot.SaveManaThreshold", 60);
autoAvoidAoe = sConfigMgr->GetOption<bool>("AiPlayerbot.AutoAvoidAoe", true);
maxAoeAvoidRadius = sConfigMgr->GetOption<float>("AiPlayerbot.MaxAoeAvoidRadius", 15.0f);
LoadSet<std::set<uint32>>(sConfigMgr->GetOption<std::string>("AiPlayerbot.AoeAvoidSpellWhitelist", "50759,57491,13810,29946"),
LoadSet<std::set<uint32>>(sConfigMgr->GetOption<std::string>("AiPlayerbot.AoeAvoidSpellWhitelist", "50759,57491,13810"),
aoeAvoidSpellWhitelist);
tellWhenAvoidAoe = sConfigMgr->GetOption<bool>("AiPlayerbot.TellWhenAvoidAoe", false);
randomGearLoweringChance = sConfigMgr->GetOption<float>("AiPlayerbot.RandomGearLoweringChance", 0.0f);
incrementalGearInit = sConfigMgr->GetOption<bool>("AiPlayerbot.IncrementalGearInit", true);
randomGearQualityLimit = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomGearQualityLimit", 3);
randomGearScoreLimit = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomGearScoreLimit", 0);
@@ -129,12 +124,11 @@ bool PlayerbotAIConfig::Initialize()
randomBotMaxLevelChance = sConfigMgr->GetOption<float>("AiPlayerbot.RandomBotMaxLevelChance", 0.1f);
randomBotRpgChance = sConfigMgr->GetOption<float>("AiPlayerbot.RandomBotRpgChance", 0.20f);
iterationsPerTick = sConfigMgr->GetOption<int32>("AiPlayerbot.IterationsPerTick", 10);
iterationsPerTick = sConfigMgr->GetOption<int32>("AiPlayerbot.IterationsPerTick", 100);
allowAccountBots = sConfigMgr->GetOption<bool>("AiPlayerbot.AllowAccountBots", true);
allowGuildBots = sConfigMgr->GetOption<bool>("AiPlayerbot.AllowGuildBots", true);
allowTrustedAccountBots = sConfigMgr->GetOption<bool>("AiPlayerbot.AllowTrustedAccountBots", true);
disabledWithoutRealPlayer = sConfigMgr->GetOption<bool>("AiPlayerbot.DisabledWithoutRealPlayer", false);
randomBotGuildNearby = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotGuildNearby", false);
randomBotInvitePlayer = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotInvitePlayer", false);
inviteChat = sConfigMgr->GetOption<bool>("AiPlayerbot.InviteChat", false);
@@ -142,47 +136,28 @@ bool PlayerbotAIConfig::Initialize()
randomBotMapsAsString = sConfigMgr->GetOption<std::string>("AiPlayerbot.RandomBotMaps", "0,1,530,571");
LoadList<std::vector<uint32>>(randomBotMapsAsString, randomBotMaps);
probTeleToBankers = sConfigMgr->GetOption<float>("AiPlayerbot.ProbTeleToBankers", 0.25f);
enableWeightTeleToCityBankers = sConfigMgr->GetOption<bool>("AiPlayerbot.EnableWeightTeleToCityBankers", false);
weightTeleToStormwind = sConfigMgr->GetOption<int>("AiPlayerbot.TeleToStormwindWeight", 2);
weightTeleToIronforge = sConfigMgr->GetOption<int>("AiPlayerbot.TeleToIronforgeWeight", 1);
weightTeleToDarnassus = sConfigMgr->GetOption<int>("AiPlayerbot.TeleToDarnassusWeight", 1);
weightTeleToExodar = sConfigMgr->GetOption<int>("AiPlayerbot.TeleToExodarWeight", 1);
weightTeleToOrgrimmar = sConfigMgr->GetOption<int>("AiPlayerbot.TeleToOrgrimmarWeight", 2);
weightTeleToUndercity = sConfigMgr->GetOption<int>("AiPlayerbot.TeleToUndercityWeight", 1);
weightTeleToThunderBluff = sConfigMgr->GetOption<int>("AiPlayerbot.TeleToThunderBluffWeight", 1);
weightTeleToSilvermoonCity = sConfigMgr->GetOption<int>("AiPlayerbot.TeleToSilvermoonCityWeight", 1);
weightTeleToShattrathCity = sConfigMgr->GetOption<int>("AiPlayerbot.TeleToShattrathCityWeight", 1);
weightTeleToDalaran = sConfigMgr->GetOption<int>("AiPlayerbot.TeleToDalaranWeight", 1);
LoadList<std::vector<uint32>>(
sConfigMgr->GetOption<std::string>("AiPlayerbot.RandomBotQuestItems",
"5175,5176,5177,5178,6948,11000,12382,13704,16309"),
"6948,5175,5176,5177,5178,16309,12382,13704,11000"),
randomBotQuestItems);
LoadList<std::vector<uint32>>(sConfigMgr->GetOption<std::string>("AiPlayerbot.RandomBotSpellIds", "54197"),
randomBotSpellIds);
LoadList<std::vector<uint32>>(
sConfigMgr->GetOption<std::string>("AiPlayerbot.PvpProhibitedZoneIds",
"2255,656,2361,2362,2363,976,35,2268,3425,392,541,1446,3828,3712,3738,3565,"
"3539,3623,4152,3988,4658,4284,4418,4436,4275,4323,4395,3703,4298,3951"),
"3539,3623,4152,3988,4658,4284,4418,4436,4275,4323,4395"),
pvpProhibitedZoneIds);
LoadList<std::vector<uint32>>(
sConfigMgr->GetOption<std::string>("AiPlayerbot.PvpProhibitedAreaIds",
"976,35,392,2268,4161,4010,4317,4312,3649,3887,3958,3724,4080,3938,3754,3786,3973"),
pvpProhibitedAreaIds);
LoadList<std::vector<uint32>>(sConfigMgr->GetOption<std::string>("AiPlayerbot.PvpProhibitedAreaIds", "976,35"),
pvpProhibitedAreaIds);
fastReactInBG = sConfigMgr->GetOption<bool>("AiPlayerbot.FastReactInBG", true);
LoadList<std::vector<uint32>>(
sConfigMgr->GetOption<std::string>("AiPlayerbot.RandomBotQuestIds", "3802,5505,6502,7761,7848,10277,10285,11492,13188,13189,24499,24511,24710,24712"),
sConfigMgr->GetOption<std::string>("AiPlayerbot.RandomBotQuestIds", "7848,3802,5505,6502,7761"),
randomBotQuestIds);
LoadSet<std::set<uint32>>(
sConfigMgr->GetOption<std::string>("AiPlayerbot.DisallowedGameObjects",
"176213,17155,2656,74448,19020,3719,3658,3705,3706,105579,75293,2857,"
"179490,141596,160836,160845,179516,176224,181085,176112,128308,128403,"
"165739,165738,175245,175970,176325,176327,123329,2560"),
disallowedGameObjects);
botAutologin = sConfigMgr->GetOption<bool>("AiPlayerbot.BotAutologin", false);
randomBotAutologin = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotAutologin", true);
minRandomBots = sConfigMgr->GetOption<int32>("AiPlayerbot.MinRandomBots", 500);
maxRandomBots = sConfigMgr->GetOption<int32>("AiPlayerbot.MaxRandomBots", 500);
minRandomBots = sConfigMgr->GetOption<int32>("AiPlayerbot.MinRandomBots", 50);
maxRandomBots = sConfigMgr->GetOption<int32>("AiPlayerbot.MaxRandomBots", 50);
randomBotUpdateInterval = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotUpdateInterval", 20);
randomBotCountChangeMinInterval =
sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotCountChangeMinInterval", 30 * MINUTE);
@@ -200,8 +175,8 @@ bool PlayerbotAIConfig::Initialize()
maxRandomBotReviveTime = sConfigMgr->GetOption<int32>("AiPlayerbot.MaxRandomBotReviveTime", 5 * MINUTE);
minRandomBotTeleportInterval = sConfigMgr->GetOption<int32>("AiPlayerbot.MinRandomBotTeleportInterval", 1 * HOUR);
maxRandomBotTeleportInterval = sConfigMgr->GetOption<int32>("AiPlayerbot.MaxRandomBotTeleportInterval", 5 * HOUR);
permanentlyInWorldTime =
sConfigMgr->GetOption<int32>("AiPlayerbot.PermanentlyInWorldTime", 1 * YEAR);
permanantlyInWorldTime =
sConfigMgr->GetOption<int32>("AiPlayerbot.PermanantlyInWorldTime", 1 * YEAR);
randomBotTeleportDistance = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotTeleportDistance", 100);
randomBotsPerInterval = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotsPerInterval", 60);
minRandomBotsPriceChangeInterval =
@@ -210,24 +185,6 @@ bool PlayerbotAIConfig::Initialize()
sConfigMgr->GetOption<int32>("AiPlayerbot.MaxRandomBotsPriceChangeInterval", 48 * HOUR);
randomBotJoinLfg = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotJoinLfg", true);
restrictHealerDPS = sConfigMgr->GetOption<bool>("AiPlayerbot.HealerDPSMapRestriction", false);
LoadList<std::vector<uint32>>(
sConfigMgr->GetOption<std::string>("AiPlayerbot.RestrictedHealerDPSMaps",
"33,34,36,43,47,48,70,90,109,129,209,229,230,329,349,389,429,1001,1004,"
"1007,269,540,542,543,545,546,547,552,553,554,555,556,557,558,560,585,574,"
"575,576,578,595,599,600,601,602,604,608,619,632,650,658,668,409,469,509,"
"531,532,534,544,548,550,564,565,580,249,533,603,615,616,624,631,649,724"),
restrictedHealerDPSMaps);
//////////////////////////// ICC
EnableICCBuffs = sConfigMgr->GetOption<bool>("AiPlayerbot.EnableICCBuffs", true);
//////////////////////////// Professions
fishingDistanceFromMaster = sConfigMgr->GetOption<float>("AiPlayerbot.FishingDistanceFromMaster", 10.0f);
endFishingWithMaster = sConfigMgr->GetOption<float>("AiPlayerbot.EndFishingWithMaster", 30.0f);
fishingDistance = sConfigMgr->GetOption<float>("AiPlayerbot.FishingDistance", 40.0f);
enableFishingWithMaster = sConfigMgr->GetOption<bool>("AiPlayerbot.EnableFishingWithMaster", true);
//////////////////////////// CHAT
enableBroadcasts = sConfigMgr->GetOption<bool>("AiPlayerbot.EnableBroadcasts", true);
randomBotTalk = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotTalk", false);
@@ -350,54 +307,17 @@ bool PlayerbotAIConfig::Initialize()
summonAtInnkeepersEnabled = sConfigMgr->GetOption<bool>("AiPlayerbot.SummonAtInnkeepersEnabled", true);
randomBotMinLevel = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotMinLevel", 1);
randomBotMaxLevel = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotMaxLevel", 80);
if (randomBotMaxLevel > sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL))
randomBotMaxLevel = sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL);
randomBotLoginAtStartup = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotLoginAtStartup", true);
randomBotTeleLowerLevel = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotTeleLowerLevel", 1);
randomBotTeleHigherLevel = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotTeleHigherLevel", 3);
randomBotTeleLowerLevel = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotTeleLowerLevel", 3);
randomBotTeleHigherLevel = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotTeleHigherLevel", 1);
openGoSpell = sConfigMgr->GetOption<int32>("AiPlayerbot.OpenGoSpell", 6477);
// Zones for NewRpgStrategy teleportation brackets
std::vector<uint32> zoneIds = {
// Classic WoW - Low-level zones
1, 12, 14, 85, 141, 215, 3430, 3524,
// Classic WoW - Mid-level zones
17, 38, 40, 130, 148, 3433, 3525,
// Classic WoW - High-level zones
10, 11, 44, 267, 331, 400, 406,
// Classic WoW - Higher-level zones
3, 8, 15, 16, 33, 45, 47, 51, 357, 405, 440,
// Classic WoW - Top-level zones
4, 28, 46, 139, 361, 490, 618, 1377,
// The Burning Crusade - Zones
3483, 3518, 3519, 3520, 3521, 3522, 3523, 4080,
// Wrath of the Lich King - Zones
65, 66, 67, 210, 394, 495, 2817, 3537, 3711, 4197
};
for (uint32 zoneId : zoneIds)
{
std::string setting = "AiPlayerbot.ZoneBracket." + std::to_string(zoneId);
std::string value = sConfigMgr->GetOption<std::string>(setting, "");
if (!value.empty())
{
size_t commaPos = value.find(',');
if (commaPos != std::string::npos)
{
uint32 minLevel = atoi(value.substr(0, commaPos).c_str());
uint32 maxLevel = atoi(value.substr(commaPos + 1).c_str());
zoneBrackets[zoneId] = std::make_pair(minLevel, maxLevel);
}
}
}
randomChangeMultiplier = sConfigMgr->GetOption<float>("AiPlayerbot.RandomChangeMultiplier", 1.0);
randomBotCombatStrategies = sConfigMgr->GetOption<std::string>("AiPlayerbot.RandomBotCombatStrategies", "");
randomBotCombatStrategies = sConfigMgr->GetOption<std::string>("AiPlayerbot.RandomBotCombatStrategies", "-threat");
randomBotNonCombatStrategies = sConfigMgr->GetOption<std::string>("AiPlayerbot.RandomBotNonCombatStrategies", "");
combatStrategies = sConfigMgr->GetOption<std::string>("AiPlayerbot.CombatStrategies", "");
nonCombatStrategies = sConfigMgr->GetOption<std::string>("AiPlayerbot.NonCombatStrategies", "");
combatStrategies = sConfigMgr->GetOption<std::string>("AiPlayerbot.CombatStrategies", "+custom::say");
nonCombatStrategies = sConfigMgr->GetOption<std::string>("AiPlayerbot.NonCombatStrategies", "+custom::say,+return");
applyInstanceStrategies = sConfigMgr->GetOption<bool>("AiPlayerbot.ApplyInstanceStrategies", true);
commandPrefix = sConfigMgr->GetOption<std::string>("AiPlayerbot.CommandPrefix", "");
@@ -411,12 +331,6 @@ bool PlayerbotAIConfig::Initialize()
useFlyMountAtMinLevel = sConfigMgr->GetOption<int32>("AiPlayerbot.UseFlyMountAtMinLevel", 60);
useFastFlyMountAtMinLevel = sConfigMgr->GetOption<int32>("AiPlayerbot.UseFastFlyMountAtMinLevel", 70);
// stagger bot flightpath takeoff
delayMin = sConfigMgr->GetOption<uint32>("AiPlayerbot.BotTaxiDelayMinMs", 350u);
delayMax = sConfigMgr->GetOption<uint32>("AiPlayerbot.BotTaxiDelayMaxMs", 5000u);
gapMs = sConfigMgr->GetOption<uint32>("AiPlayerbot.BotTaxiGapMs", 200u);
gapJitterMs = sConfigMgr->GetOption<uint32>("AiPlayerbot.BotTaxiGapJitterMs", 100u);
LOG_INFO("server.loading", "Loading TalentSpecs...");
for (uint32 cls = 1; cls < MAX_CLASSES; ++cls)
@@ -481,13 +395,11 @@ bool PlayerbotAIConfig::Initialize()
}
botCheats.clear();
LoadListString<std::vector<std::string>>(sConfigMgr->GetOption<std::string>("AiPlayerbot.BotCheats", "food,taxi,raid"),
LoadListString<std::vector<std::string>>(sConfigMgr->GetOption<std::string>("AiPlayerbot.BotCheats", "taxi"),
botCheats);
botCheatMask = 0;
if (std::find(botCheats.begin(), botCheats.end(), "food") != botCheats.end())
botCheatMask |= (uint32)BotCheatMask::food;
if (std::find(botCheats.begin(), botCheats.end(), "taxi") != botCheats.end())
botCheatMask |= (uint32)BotCheatMask::taxi;
if (std::find(botCheats.begin(), botCheats.end(), "gold") != botCheats.end())
@@ -498,26 +410,38 @@ bool PlayerbotAIConfig::Initialize()
botCheatMask |= (uint32)BotCheatMask::mana;
if (std::find(botCheats.begin(), botCheats.end(), "power") != botCheats.end())
botCheatMask |= (uint32)BotCheatMask::power;
if (std::find(botCheats.begin(), botCheats.end(), "raid") != botCheats.end())
botCheatMask |= (uint32)BotCheatMask::raid;
LoadListString<std::vector<std::string>>(sConfigMgr->GetOption<std::string>("AiPlayerbot.AllowedLogFiles", ""),
allowedLogFiles);
LoadListString<std::vector<std::string>>(sConfigMgr->GetOption<std::string>("AiPlayerbot.TradeActionExcludedPrefixes", ""),
tradeActionExcludedPrefixes);
worldBuffs.clear();
loadWorldBuff();
LOG_INFO("playerbots", "Loading World Buff Feature...");
LOG_INFO("playerbots", "Loading Worldbuff...");
for (uint32 factionId = 0; factionId < 3; factionId++)
{
for (uint32 classId = 0; classId < MAX_CLASSES; classId++)
{
for (uint32 specId = 0; specId <= MAX_WORLDBUFF_SPECNO; specId++)
{
for (uint32 minLevel = 0; minLevel <= randomBotMaxLevel; minLevel++)
{
for (uint32 maxLevel = minLevel; maxLevel <= randomBotMaxLevel; maxLevel++)
{
loadWorldBuff(factionId, classId, specId, minLevel, maxLevel);
}
loadWorldBuff(factionId, classId, specId, minLevel, 0);
}
}
}
}
randomBotAccountPrefix = sConfigMgr->GetOption<std::string>("AiPlayerbot.RandomBotAccountPrefix", "rndbot");
randomBotAccountCount = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotAccountCount", 0);
deleteRandomBotAccounts = sConfigMgr->GetOption<bool>("AiPlayerbot.DeleteRandomBotAccounts", false);
randomBotGuildCount = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotGuildCount", 20);
randomBotGuildSizeMax = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotGuildSizeMax", 15);
deleteRandomBotGuilds = sConfigMgr->GetOption<bool>("AiPlayerbot.DeleteRandomBotGuilds", false);
guildTaskEnabled = sConfigMgr->GetOption<bool>("AiPlayerbot.EnableGuildTasks", false);
guildTaskEnabled = sConfigMgr->GetOption<bool>("AiPlayerbot.EnableGuildTasks", true);
minGuildTaskChangeTime = sConfigMgr->GetOption<int32>("AiPlayerbot.MinGuildTaskChangeTime", 3 * 24 * 3600);
maxGuildTaskChangeTime = sConfigMgr->GetOption<int32>("AiPlayerbot.MaxGuildTaskChangeTime", 4 * 24 * 3600);
minGuildTaskAdvertisementTime = sConfigMgr->GetOption<int32>("AiPlayerbot.MinGuildTaskAdvertisementTime", 300);
@@ -542,7 +466,6 @@ bool PlayerbotAIConfig::Initialize()
equipmentPersistence = sConfigMgr->GetOption<bool>("AiPlayerbot.EquipmentPersistence", false);
equipmentPersistenceLevel = sConfigMgr->GetOption<int32>("AiPlayerbot.EquipmentPersistenceLevel", 80);
groupInvitationPermission = sConfigMgr->GetOption<int32>("AiPlayerbot.GroupInvitationPermission", 1);
keepAltsInGroup = sConfigMgr->GetOption<bool>("AiPlayerbot.KeepAltsInGroup", false);
allowSummonInCombat = sConfigMgr->GetOption<bool>("AiPlayerbot.AllowSummonInCombat", true);
allowSummonWhenMasterIsDead = sConfigMgr->GetOption<bool>("AiPlayerbot.AllowSummonWhenMasterIsDead", true);
allowSummonWhenBotIsDead = sConfigMgr->GetOption<bool>("AiPlayerbot.AllowSummonWhenBotIsDead", true);
@@ -555,33 +478,12 @@ bool PlayerbotAIConfig::Initialize()
addClassCommand = sConfigMgr->GetOption<int32>("AiPlayerbot.AddClassCommand", 1);
addClassAccountPoolSize = sConfigMgr->GetOption<int32>("AiPlayerbot.AddClassAccountPoolSize", 50);
maintenanceCommand = sConfigMgr->GetOption<int32>("AiPlayerbot.MaintenanceCommand", 1);
altMaintenanceAttunementQs = sConfigMgr->GetOption<bool>("AiPlayerbot.AltMaintenanceAttunementQuests", true);
altMaintenanceBags = sConfigMgr->GetOption<bool>("AiPlayerbot.AltMaintenanceBags", true);
altMaintenanceAmmo = sConfigMgr->GetOption<bool>("AiPlayerbot.AltMaintenanceAmmo", true);
altMaintenanceFood = sConfigMgr->GetOption<bool>("AiPlayerbot.AltMaintenanceFood", true);
altMaintenanceReagents = sConfigMgr->GetOption<bool>("AiPlayerbot.AltMaintenanceReagents", true);
altMaintenanceConsumables = sConfigMgr->GetOption<bool>("AiPlayerbot.AltMaintenanceConsumables", true);
altMaintenancePotions = sConfigMgr->GetOption<bool>("AiPlayerbot.AltMaintenancePotions", true);
altMaintenanceTalentTree = sConfigMgr->GetOption<bool>("AiPlayerbot.AltMaintenanceTalentTree", true);
altMaintenancePet = sConfigMgr->GetOption<bool>("AiPlayerbot.AltMaintenancePet", true);
altMaintenancePetTalents = sConfigMgr->GetOption<bool>("AiPlayerbot.AltMaintenancePetTalents", true);
altMaintenanceClassSpells = sConfigMgr->GetOption<bool>("AiPlayerbot.AltMaintenanceClassSpells", true);
altMaintenanceAvailableSpells = sConfigMgr->GetOption<bool>("AiPlayerbot.AltMaintenanceAvailableSpells", true);
altMaintenanceSkills = sConfigMgr->GetOption<bool>("AiPlayerbot.AltMaintenanceSkills", true);
altMaintenanceReputation = sConfigMgr->GetOption<bool>("AiPlayerbot.AltMaintenanceReputation", true);
altMaintenanceSpecialSpells = sConfigMgr->GetOption<bool>("AiPlayerbot.AltMaintenanceSpecialSpells", true);
altMaintenanceMounts = sConfigMgr->GetOption<bool>("AiPlayerbot.AltMaintenanceMounts", true);
altMaintenanceGlyphs = sConfigMgr->GetOption<bool>("AiPlayerbot.AltMaintenanceGlyphs", true);
altMaintenanceKeyring = sConfigMgr->GetOption<bool>("AiPlayerbot.AltMaintenanceKeyring", true);
altMaintenanceGemsEnchants = sConfigMgr->GetOption<bool>("AiPlayerbot.AltMaintenanceGemsEnchants", true);
autoGearCommand = sConfigMgr->GetOption<int32>("AiPlayerbot.AutoGearCommand", 1);
autoGearCommandAltBots = sConfigMgr->GetOption<int32>("AiPlayerbot.AutoGearCommandAltBots", 1);
autoGearQualityLimit = sConfigMgr->GetOption<int32>("AiPlayerbot.AutoGearQualityLimit", 3);
autoGearScoreLimit = sConfigMgr->GetOption<int32>("AiPlayerbot.AutoGearScoreLimit", 0);
randomBotXPRate = sConfigMgr->GetOption<float>("AiPlayerbot.RandomBotXPRate", 1.0);
playerbotsXPrate = sConfigMgr->GetOption<float>("AiPlayerbot.PlayerbotsXPRate", 1.0);
randomBotAllianceRatio = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotAllianceRatio", 50);
randomBotHordeRatio = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotHordeRatio", 50);
disableDeathKnightLogin = sConfigMgr->GetOption<bool>("AiPlayerbot.DisableDeathKnightLogin", 0);
@@ -603,12 +505,12 @@ bool PlayerbotAIConfig::Initialize()
minEnchantingBotLevel = sConfigMgr->GetOption<int32>("AiPlayerbot.MinEnchantingBotLevel", 60);
limitEnchantExpansion = sConfigMgr->GetOption<int32>("AiPlayerbot.LimitEnchantExpansion", 1);
limitGearExpansion = sConfigMgr->GetOption<int32>("AiPlayerbot.LimitGearExpansion", 1);
randombotStartingLevel = sConfigMgr->GetOption<int32>("AiPlayerbot.RandombotStartingLevel", 1);
randombotStartingLevel = sConfigMgr->GetOption<int32>("AiPlayerbot.RandombotStartingLevel", 5);
enablePeriodicOnlineOffline = sConfigMgr->GetOption<bool>("AiPlayerbot.EnablePeriodicOnlineOffline", false);
enableRandomBotTrading = sConfigMgr->GetOption<int32>("AiPlayerbot.EnableRandomBotTrading", 1);
periodicOnlineOfflineRatio = sConfigMgr->GetOption<float>("AiPlayerbot.PeriodicOnlineOfflineRatio", 2.0);
gearscorecheck = sConfigMgr->GetOption<bool>("AiPlayerbot.GearScoreCheck", false);
randomBotPreQuests = sConfigMgr->GetOption<bool>("AiPlayerbot.PreQuests", false);
randomBotPreQuests = sConfigMgr->GetOption<bool>("AiPlayerbot.PreQuests", true);
// SPP automation
freeMethodLoot = sConfigMgr->GetOption<bool>("AiPlayerbot.FreeMethodLoot", false);
@@ -624,24 +526,14 @@ bool PlayerbotAIConfig::Initialize()
autoPickTalents = sConfigMgr->GetOption<bool>("AiPlayerbot.AutoPickTalents", true);
autoUpgradeEquip = sConfigMgr->GetOption<bool>("AiPlayerbot.AutoUpgradeEquip", false);
hunterWolfPet = sConfigMgr->GetOption<int32>("AiPlayerbot.HunterWolfPet", 0);
defaultPetStance = sConfigMgr->GetOption<int32>("AiPlayerbot.DefaultPetStance", 1);
petChatCommandDebug = sConfigMgr->GetOption<bool>("AiPlayerbot.PetChatCommandDebug", 0);
autoLearnTrainerSpells = sConfigMgr->GetOption<bool>("AiPlayerbot.AutoLearnTrainerSpells", true);
autoLearnQuestSpells = sConfigMgr->GetOption<bool>("AiPlayerbot.AutoLearnQuestSpells", false);
autoTeleportForLevel = sConfigMgr->GetOption<bool>("AiPlayerbot.AutoTeleportForLevel", false);
autoDoQuests = sConfigMgr->GetOption<bool>("AiPlayerbot.AutoDoQuests", true);
enableNewRpgStrategy = sConfigMgr->GetOption<bool>("AiPlayerbot.EnableNewRpgStrategy", true);
RpgStatusProbWeight[RPG_WANDER_RANDOM] = sConfigMgr->GetOption<int32>("AiPlayerbot.RpgStatusProbWeight.WanderRandom", 15);
RpgStatusProbWeight[RPG_WANDER_NPC] = sConfigMgr->GetOption<int32>("AiPlayerbot.RpgStatusProbWeight.WanderNpc", 20);
RpgStatusProbWeight[RPG_GO_GRIND] = sConfigMgr->GetOption<int32>("AiPlayerbot.RpgStatusProbWeight.GoGrind", 15);
RpgStatusProbWeight[RPG_GO_CAMP] = sConfigMgr->GetOption<int32>("AiPlayerbot.RpgStatusProbWeight.GoCamp", 10);
RpgStatusProbWeight[RPG_DO_QUEST] = sConfigMgr->GetOption<int32>("AiPlayerbot.RpgStatusProbWeight.DoQuest", 60);
RpgStatusProbWeight[RPG_TRAVEL_FLIGHT] = sConfigMgr->GetOption<int32>("AiPlayerbot.RpgStatusProbWeight.TravelFlight", 15);
RpgStatusProbWeight[RPG_REST] = sConfigMgr->GetOption<int32>("AiPlayerbot.RpgStatusProbWeight.Rest", 5);
enableNewRpgStrategy = sConfigMgr->GetOption<bool>("AiPlayerbot.EnableNewRpgStrategy", false);
syncLevelWithPlayers = sConfigMgr->GetOption<bool>("AiPlayerbot.SyncLevelWithPlayers", false);
randomBotGroupNearby = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotGroupNearby", false);
freeFood = sConfigMgr->GetOption<bool>("AiPlayerbot.FreeFood", true);
randomBotGroupNearby = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotGroupNearby", true);
// arena
randomBotArenaTeam2v2Count = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotArenaTeam2v2Count", 10);
@@ -659,33 +551,31 @@ bool PlayerbotAIConfig::Initialize()
return true;
}
// Assign account types after accounts are created
sRandomPlayerbotMgr->AssignAccountTypes();
if (sPlayerbotAIConfig->enabled)
{
sRandomPlayerbotMgr->Init();
}
sPlayerbotGuildMgr->Init();
sRandomItemMgr->Init();
sRandomItemMgr->InitAfterAhBot();
sPlayerbotTextMgr->LoadBotTexts();
sPlayerbotTextMgr->LoadBotTextChance();
PlayerbotFactory::Init();
AiObjectContext::BuildAllSharedContexts();
if (!sPlayerbotAIConfig->autoDoQuests)
{
LOG_INFO("server.loading", "Loading Quest Detail Data...");
sTravelMgr->LoadQuestTravelTable();
}
if (sPlayerbotAIConfig->randomBotSuggestDungeons)
{
sPlayerbotDungeonRepository->LoadDungeonSuggestions();
sPlayerbotDungeonSuggestionMgr->LoadDungeonSuggestions();
}
excludedHunterPetFamilies.clear();
LoadList<std::vector<uint32>>(sConfigMgr->GetOption<std::string>("AiPlayerbot.ExcludedHunterPetFamilies", ""), excludedHunterPetFamilies);
LOG_INFO("server.loading", "---------------------------------------");
LOG_INFO("server.loading", " mod-playerbots initialized ");
LOG_INFO("server.loading", " AI Playerbots initialized ");
LOG_INFO("server.loading", "---------------------------------------");
return true;
@@ -716,12 +606,6 @@ bool PlayerbotAIConfig::IsInPvpProhibitedArea(uint32 id)
return find(pvpProhibitedAreaIds.begin(), pvpProhibitedAreaIds.end(), id) != pvpProhibitedAreaIds.end();
}
bool PlayerbotAIConfig::IsRestrictedHealerDPSMap(uint32 mapId) const
{
return restrictHealerDPS &&
std::find(restrictedHealerDPSMaps.begin(), restrictedHealerDPSMaps.end(), mapId) != restrictedHealerDPSMaps.end();
}
std::string const PlayerbotAIConfig::GetTimestampStr()
{
time_t t = time(nullptr);
@@ -732,8 +616,8 @@ std::string const PlayerbotAIConfig::GetTimestampStr()
// HH hour (2 digits 00-23)
// MM minutes (2 digits 00-59)
// SS seconds (2 digits 00-59)
char buf[32];
snprintf(buf, sizeof(buf), "%04d-%02d-%02d %02d-%02d-%02d", aTm->tm_year + 1900, aTm->tm_mon + 1, aTm->tm_mday, aTm->tm_hour,
char buf[20];
snprintf(buf, 20, "%04d-%02d-%02d %02d-%02d-%02d", aTm->tm_year + 1900, aTm->tm_mon + 1, aTm->tm_mday, aTm->tm_hour,
aTm->tm_min, aTm->tm_sec);
return std::string(buf);
}
@@ -794,62 +678,88 @@ void PlayerbotAIConfig::log(std::string const fileName, char const* str, ...)
fflush(stdout);
}
void PlayerbotAIConfig::loadWorldBuff()
void PlayerbotAIConfig::loadWorldBuff(uint32 factionId1, uint32 classId1, uint32 specId1, uint32 minLevel1, uint32 maxLevel1)
{
std::string matrix = sConfigMgr->GetOption<std::string>("AiPlayerbot.WorldBuffMatrix", "", true);
if (matrix.empty())
return;
std::vector<uint32> buffs;
std::istringstream entryStream(matrix);
std::string entry;
std::ostringstream os;
os << "AiPlayerbot.WorldBuff." << factionId1 << "." << classId1 << "." << specId1 << "." << minLevel1 << "." << maxLevel1;
while (std::getline(entryStream, entry, ';'))
LoadList<std::vector<uint32>>(sConfigMgr->GetOption<std::string>(os.str().c_str(), "", false), buffs);
for (auto buff : buffs)
{
worldBuff wb = {buff, factionId1, classId1, specId1, minLevel1, maxLevel1};
worldBuffs.push_back(wb);
}
entry.erase(0, entry.find_first_not_of(" \t\r\n"));
entry.erase(entry.find_last_not_of(" \t\r\n") + 1);
if (maxLevel1 == 0)
{
std::ostringstream os;
os << "AiPlayerbot.WorldBuff." << factionId1 << "." << classId1 << "." << specId1 << "." << minLevel1;
size_t firstColon = entry.find(':');
size_t secondColon = entry.find(':', firstColon + 1);
LoadList<std::vector<uint32>>(sConfigMgr->GetOption<std::string>(os.str().c_str(), "", false), buffs);
if (firstColon == std::string::npos || secondColon == std::string::npos)
for (auto buff : buffs)
{
LOG_ERROR("playerbots", "Malformed entry: [{}]", entry);
continue;
worldBuff wb = {buff, factionId1, classId1, specId1, minLevel1, maxLevel1};
worldBuffs.push_back(wb);
}
}
std::string metaPart = entry.substr(firstColon + 1, secondColon - firstColon - 1);
std::string spellPart = entry.substr(secondColon + 1);
if (maxLevel1 == 0 && minLevel1 == 0)
{
std::ostringstream os;
os << "AiPlayerbot.WorldBuff." << factionId1 << "." << factionId1 << "." << classId1 << "." << specId1;
std::vector<uint32> ids;
std::istringstream metaStream(metaPart);
std::string token;
while (std::getline(metaStream, token, ','))
LoadList<std::vector<uint32>>(sConfigMgr->GetOption<std::string>(os.str().c_str(), "", false), buffs);
for (auto buff : buffs)
{
try {
ids.push_back(static_cast<uint32>(std::stoi(token)));
} catch (...) {
LOG_ERROR("playerbots", "Invalid meta token in [{}]", entry);
break;
}
worldBuff wb = {buff, factionId1, classId1, specId1, minLevel1, maxLevel1};
worldBuffs.push_back(wb);
}
}
if (ids.size() != 5)
if (maxLevel1 == 0 && minLevel1 == 0 && specId1 == 0)
{
std::ostringstream os;
os << "AiPlayerbot.WorldBuff." << factionId1 << "." << factionId1 << "." << classId1;
LoadList<std::vector<uint32>>(sConfigMgr->GetOption<std::string>(os.str().c_str(), "", false), buffs);
for (auto buff : buffs)
{
LOG_ERROR("playerbots", "Entry [{}] has incomplete meta block", entry);
continue;
worldBuff wb = {buff, factionId1, classId1, specId1, minLevel1, maxLevel1};
worldBuffs.push_back(wb);
}
}
std::istringstream spellStream(spellPart);
while (std::getline(spellStream, token, ','))
if (classId1 == 0 && maxLevel1 == 0 && minLevel1 == 0 && specId1 == 0)
{
std::ostringstream os;
os << "AiPlayerbot.WorldBuff." << factionId1;
LoadList<std::vector<uint32>>(sConfigMgr->GetOption<std::string>(os.str().c_str(), "", false), buffs);
for (auto buff : buffs)
{
try {
uint32 spellId = static_cast<uint32>(std::stoi(token));
worldBuff wb = { spellId, ids[0], ids[1], ids[2], ids[3], ids[4] };
worldBuffs.push_back(wb);
} catch (...) {
LOG_ERROR("playerbots", "Invalid spell ID in [{}]", entry);
}
worldBuff wb = {buff, factionId1, classId1, specId1, minLevel1, maxLevel1};
worldBuffs.push_back(wb);
}
}
if (factionId1 == 0 && classId1 == 0 && maxLevel1 == 0 && minLevel1 == 0 && specId1 == 0)
{
std::ostringstream os;
os << "AiPlayerbot.WorldBuff";
LoadList<std::vector<uint32>>(sConfigMgr->GetOption<std::string>(os.str().c_str(), "", false), buffs);
for (auto buff : buffs)
{
worldBuff wb = {buff, factionId1, classId1, specId1, minLevel1, maxLevel1};
worldBuffs.push_back(wb);
}
}
}

View File

@@ -1,13 +1,12 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
* and/or modify it under version 3 of the License, or (at your option), any later version.
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it
* and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#ifndef _PLAYERBOT_PLAYERbotAICONFIG_H
#define _PLAYERBOT_PLAYERbotAICONFIG_H
#include <mutex>
#include <unordered_map>
#include "Common.h"
#include "DBCEnums.h"
@@ -22,9 +21,7 @@ enum class BotCheatMask : uint32
health = 4,
mana = 8,
power = 16,
raid = 32,
food = 64,
maxMask = 128
maxMask = 32
};
enum class HealingManaEfficiency : uint8
@@ -37,27 +34,8 @@ enum class HealingManaEfficiency : uint8
SUPERIOR = 32
};
enum NewRpgStatus : int
{
RPG_STATUS_START = 0,
// Going to far away place
RPG_GO_GRIND = 0,
RPG_GO_CAMP = 1,
// Exploring nearby
RPG_WANDER_RANDOM = 2,
RPG_WANDER_NPC = 3,
// Do Quest (based on quest status)
RPG_DO_QUEST = 4,
// Travel
RPG_TRAVEL_FLIGHT = 5,
// Taking a break
RPG_REST = 6,
// Initial status
RPG_IDLE = 7,
RPG_STATUS_END = 8
};
#define MAX_SPECNO 20
#define MAX_WORLDBUFF_SPECNO 3
class PlayerbotAIConfig
{
@@ -77,8 +55,6 @@ public:
bool IsInPvpProhibitedArea(uint32 id);
bool enabled;
bool disabledWithoutRealPlayer;
bool EnableICCBuffs;
bool allowAccountBots, allowGuildBots, allowTrustedAccountBots;
bool randomBotGuildNearby, randomBotInvitePlayer, inviteChat;
uint32 globalCoolDown, reactDelay, maxWaitForMove, disableMoveSplinePath, maxMovementSearchTime, expireActionTime,
@@ -95,24 +71,12 @@ public:
float maxAoeAvoidRadius;
std::set<uint32> aoeAvoidSpellWhitelist;
bool tellWhenAvoidAoe;
std::set<uint32> disallowedGameObjects;
uint32 openGoSpell;
bool randomBotAutologin;
bool botAutologin;
std::string randomBotMapsAsString;
float probTeleToBankers;
bool enableWeightTeleToCityBankers;
int weightTeleToStormwind;
int weightTeleToIronforge;
int weightTeleToDarnassus;
int weightTeleToExodar;
int weightTeleToOrgrimmar;
int weightTeleToUndercity;
int weightTeleToThunderBluff;
int weightTeleToSilvermoonCity;
int weightTeleToShattrathCity;
int weightTeleToDalaran;
std::vector<uint32> randomBotMaps;
std::vector<uint32> randomBotQuestItems;
std::vector<uint32> randomBotAccounts;
@@ -120,7 +84,6 @@ public:
std::vector<uint32> randomBotQuestIds;
uint32 randomBotTeleportDistance;
float randomGearLoweringChance;
bool incrementalGearInit;
int32 randomGearQualityLimit;
int32 randomGearScoreLimit;
float randomBotMinLevelChance, randomBotMaxLevelChance;
@@ -132,23 +95,12 @@ public:
uint32 minRandomBotChangeStrategyTime, maxRandomBotChangeStrategyTime;
uint32 minRandomBotReviveTime, maxRandomBotReviveTime;
uint32 minRandomBotTeleportInterval, maxRandomBotTeleportInterval;
uint32 permanentlyInWorldTime;
uint32 permanantlyInWorldTime;
uint32 minRandomBotPvpTime, maxRandomBotPvpTime;
uint32 randomBotsPerInterval;
uint32 minRandomBotsPriceChangeInterval, maxRandomBotsPriceChangeInterval;
uint32 disabledWithoutRealPlayerLoginDelay, disabledWithoutRealPlayerLogoutDelay;
bool randomBotJoinLfg;
// Buff system
// Min group size to use Greater buffs (Paladin, Mage, Druid). Default: 3
int32 minBotsForGreaterBuff;
// Cooldown (seconds) between reagent-missing RP warnings, per bot & per buff. Default: 30
int32 rpWarningCooldown;
// Professions
bool enableFishingWithMaster;
float fishingDistanceFromMaster, fishingDistance, endFishingWithMaster;
// chat
bool randomBotTalk;
bool randomBotEmote;
@@ -243,7 +195,6 @@ public:
bool randomBotLoginAtStartup;
uint32 randomBotTeleLowerLevel, randomBotTeleHigherLevel;
std::map<uint32, std::pair<uint32, uint32>> zoneBrackets;
bool logInGroupOnly, logValuesPerTick;
bool fleeingEnabled;
bool summonAtInnkeepersEnabled;
@@ -271,8 +222,9 @@ public:
uint32 randomBotAccountCount;
bool randomBotRandomPassword;
bool deleteRandomBotAccounts;
uint32 randomBotGuildCount, randomBotGuildSizeMax;
uint32 randomBotGuildCount;
bool deleteRandomBotGuilds;
std::vector<uint32> randomBotGuilds;
std::vector<uint32> pvpProhibitedZoneIds;
std::vector<uint32> pvpProhibitedAreaIds;
bool fastReactInBG;
@@ -298,7 +250,6 @@ public:
uint32 iterationsPerTick;
std::mutex m_logMtx;
std::vector<std::string> tradeActionExcludedPrefixes;
std::vector<std::string> allowedLogFiles;
std::unordered_map<std::string, std::pair<FILE*, bool>> logFiles;
@@ -308,11 +259,11 @@ public:
struct worldBuff
{
uint32 spellId;
uint32 factionId;
uint32 classId;
uint32 specId;
uint32 minLevel;
uint32 maxLevel;
uint32 factionId = 0;
uint32 classId = 0;
uint32 specId = 0;
uint32 minLevel = 0;
uint32 maxLevel = 0;
};
std::vector<worldBuff> worldBuffs;
@@ -324,7 +275,7 @@ public:
bool randomBotShowCloak;
bool randomBotFixedLevel;
bool disableRandomLevels;
float randomBotXPRate;
float playerbotsXPrate;
uint32 randomBotAllianceRatio;
uint32 randomBotHordeRatio;
bool disableDeathKnightLogin;
@@ -354,13 +305,11 @@ public:
bool autoPickTalents;
bool autoUpgradeEquip;
int32 hunterWolfPet;
int32 defaultPetStance;
int32 petChatCommandDebug;
bool autoLearnTrainerSpells;
bool autoDoQuests;
bool enableNewRpgStrategy;
std::unordered_map<NewRpgStatus, uint32> RpgStatusProbWeight;
bool syncLevelWithPlayers;
bool freeFood;
bool autoLearnQuestSpells;
bool autoTeleportForLevel;
bool randomBotGroupNearby;
@@ -381,8 +330,6 @@ public:
bool equipmentPersistence;
int32 equipmentPersistenceLevel;
int32 groupInvitationPermission;
bool keepAltsInGroup = false;
bool KeepAltsInGroup() const { return keepAltsInGroup; }
bool allowSummonInCombat;
bool allowSummonWhenMasterIsDead;
bool allowSummonWhenBotIsDead;
@@ -394,25 +341,6 @@ public:
int32 addClassCommand;
int32 addClassAccountPoolSize;
int32 maintenanceCommand;
bool altMaintenanceAttunementQs,
altMaintenanceBags,
altMaintenanceAmmo,
altMaintenanceFood,
altMaintenanceReagents,
altMaintenanceConsumables,
altMaintenancePotions,
altMaintenanceTalentTree,
altMaintenancePet,
altMaintenancePetTalents,
altMaintenanceClassSpells,
altMaintenanceAvailableSpells,
altMaintenanceSkills,
altMaintenanceReputation,
altMaintenanceSpecialSpells,
altMaintenanceMounts,
altMaintenanceGlyphs,
altMaintenanceKeyring,
altMaintenanceGemsEnchants;
int32 autoGearCommand, autoGearCommandAltBots, autoGearQualityLimit, autoGearScoreLimit;
uint32 useGroundMountAtMinLevel;
@@ -420,12 +348,6 @@ public:
uint32 useFlyMountAtMinLevel;
uint32 useFastFlyMountAtMinLevel;
// stagger flightpath takeoff
uint32 delayMin;
uint32 delayMax;
uint32 gapMs;
uint32 gapJitterMs;
std::string const GetTimestampStr();
bool hasLog(std::string const fileName)
{
@@ -439,16 +361,9 @@ public:
}
void log(std::string const fileName, const char* str, ...);
void loadWorldBuff();
void loadWorldBuff(uint32 factionId, uint32 classId, uint32 specId, uint32 minLevel, uint32 maxLevel);
static std::vector<std::vector<uint32>> ParseTempTalentsOrder(uint32 cls, std::string temp_talents_order);
static std::vector<std::vector<uint32>> ParseTempPetTalentsOrder(uint32 spec, std::string temp_talents_order);
bool restrictHealerDPS = false;
std::vector<uint32> restrictedHealerDPSMaps;
bool IsRestrictedHealerDPSMap(uint32 mapId) const;
std::vector<uint32> excludedHunterPetFamilies;
};
#define sPlayerbotAIConfig PlayerbotAIConfig::instance()

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
* and/or modify it under version 3 of the License, or (at your option), any later version.
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it
* and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#include "PlayerbotCommandServer.h"

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
* and/or modify it under version 3 of the License, or (at your option), any later version.
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it
* and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#ifndef _PLAYERBOT_PLAYERBOTCOMMANDSERVER_H

View File

@@ -1,15 +1,15 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
* and/or modify it under version 3 of the License, or (at your option), any later version.
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it
* and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#include "PlayerbotRepository.h"
#include "PlayerbotDbStore.h"
#include <iostream>
#include "Playerbots.h"
void PlayerbotRepository::Load(PlayerbotAI* botAI)
void PlayerbotDbStore::Load(PlayerbotAI* botAI)
{
ObjectGuid::LowType guid = botAI->GetBot()->GetGUID().GetCounter();
@@ -46,7 +46,7 @@ void PlayerbotRepository::Load(PlayerbotAI* botAI)
}
}
void PlayerbotRepository::Save(PlayerbotAI* botAI)
void PlayerbotDbStore::Save(PlayerbotAI* botAI)
{
ObjectGuid::LowType guid = botAI->GetBot()->GetGUID().GetCounter();
@@ -68,7 +68,7 @@ void PlayerbotRepository::Save(PlayerbotAI* botAI)
SaveValue(guid, "dead", FormatStrategies("dead", botAI->GetStrategies(BOT_STATE_DEAD)));
}
std::string const PlayerbotRepository::FormatStrategies(std::string const type, std::vector<std::string> strategies)
std::string const PlayerbotDbStore::FormatStrategies(std::string const type, std::vector<std::string> strategies)
{
std::ostringstream out;
for (std::vector<std::string>::iterator i = strategies.begin(); i != strategies.end(); ++i)
@@ -78,16 +78,16 @@ std::string const PlayerbotRepository::FormatStrategies(std::string const type,
return res.substr(0, res.size() - 1);
}
void PlayerbotRepository::Reset(PlayerbotAI* botAI)
void PlayerbotDbStore::Reset(PlayerbotAI* botAI)
{
ObjectGuid::LowType guid = botAI->GetBot()->GetGUID().GetCounter();
PlayerbotsDatabasePreparedStatement* stmt = PlayerbotsDatabase.GetPreparedStatement(PLAYERBOTS_DEL_DB_STORE);
PlayerbotsDatabasePreparedStatement* stmt = PlayerbotsDatabase.GetPreparedStatement(PLAYERBOTS_DEL_CUSTOM_STRATEGY);
stmt->SetData(0, guid);
PlayerbotsDatabase.Execute(stmt);
}
void PlayerbotRepository::SaveValue(uint32 guid, std::string const key, std::string const value)
void PlayerbotDbStore::SaveValue(uint32 guid, std::string const key, std::string const value)
{
PlayerbotsDatabasePreparedStatement* stmt = PlayerbotsDatabase.GetPreparedStatement(PLAYERBOTS_INS_DB_STORE);
stmt->SetData(0, guid);

View File

@@ -1,10 +1,10 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
* and/or modify it under version 3 of the License, or (at your option), any later version.
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it
* and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#ifndef _PLAYERBOT_PLAYERBOTREPOSITORY_H
#define _PLAYERBOT_PLAYERBOTREPOSITORY_H
#ifndef _PLAYERBOT_PLAYERBOTDBSTORE_H
#define _PLAYERBOT_PLAYERBOTDBSTORE_H
#include <vector>
@@ -12,14 +12,14 @@
class PlayerbotAI;
class PlayerbotRepository
class PlayerbotDbStore
{
public:
PlayerbotRepository() {}
virtual ~PlayerbotRepository() {}
static PlayerbotRepository* instance()
PlayerbotDbStore() {}
virtual ~PlayerbotDbStore() {}
static PlayerbotDbStore* instance()
{
static PlayerbotRepository instance;
static PlayerbotDbStore instance;
return &instance;
}
@@ -32,6 +32,6 @@ private:
std::string const FormatStrategies(std::string const type, std::vector<std::string> strategies);
};
#define sPlayerbotRepository PlayerbotRepository::instance()
#define sPlayerbotDbStore PlayerbotDbStore::instance()
#endif

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
* and/or modify it under version 3 of the License, or (at your option), any later version.
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it
* and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#include "PlayerbotMgr.h"
@@ -9,10 +9,9 @@
#include <cstring>
#include <istream>
#include <string>
#include <unordered_set>
#include <openssl/sha.h>
#include <unordered_set>
#include <iomanip>
#include <algorithm>
#include "ChannelMgr.h"
#include "CharacterCache.h"
@@ -26,19 +25,17 @@
#include "ObjectGuid.h"
#include "ObjectMgr.h"
#include "PlayerbotAIConfig.h"
#include "PlayerbotRepository.h"
#include "PlayerbotDbStore.h"
#include "PlayerbotFactory.h"
#include "PlayerbotOperations.h"
#include "PlayerbotSecurity.h"
#include "PlayerbotWorldThreadProcessor.h"
#include "Playerbots.h"
#include "PlayerbotGuildMgr.h"
#include "RandomPlayerbotMgr.h"
#include "SharedDefines.h"
#include "WorldSession.h"
#include "ChannelMgr.h"
#include "BroadcastHelper.h"
#include "PlayerbotDbStore.h"
#include "WorldSessionMgr.h"
#include "DatabaseEnv.h"
class BotInitGuard
{
@@ -67,7 +64,6 @@ private:
};
std::unordered_set<ObjectGuid> BotInitGuard::botsBeingInitialized;
std::unordered_set<ObjectGuid> PlayerbotHolder::botLoading;
PlayerbotHolder::PlayerbotHolder() : PlayerbotAIBase(false) {}
class PlayerbotLoginQueryHolder : public LoginQueryHolder
@@ -76,16 +72,18 @@ private:
uint32 masterAccountId;
PlayerbotHolder* playerbotHolder;
public:
PlayerbotLoginQueryHolder(uint32 masterAccount, uint32 accountId, ObjectGuid guid)
: LoginQueryHolder(accountId, guid), masterAccountId(masterAccount)
PlayerbotLoginQueryHolder(PlayerbotHolder* playerbotHolder, uint32 masterAccount, uint32 accountId, ObjectGuid guid)
: LoginQueryHolder(accountId, guid), masterAccountId(masterAccount), playerbotHolder(playerbotHolder)
{
}
uint32 GetMasterAccountId() const { return masterAccountId; }
PlayerbotHolder* GetPlayerbotHolder() { return playerbotHolder; }
};
void PlayerbotHolder::AddPlayerBot(ObjectGuid playerGuid, uint32 masterAccountId)
{
// bot is loading
if (botLoading.find(playerGuid) != botLoading.end())
return;
@@ -142,7 +140,7 @@ void PlayerbotHolder::AddPlayerBot(ObjectGuid playerGuid, uint32 masterAccountId
return;
}
std::shared_ptr<PlayerbotLoginQueryHolder> holder =
std::make_shared<PlayerbotLoginQueryHolder>(masterAccountId, accountId, playerGuid);
std::make_shared<PlayerbotLoginQueryHolder>(this, masterAccountId, accountId, playerGuid);
if (!holder->Initialize())
{
return;
@@ -152,33 +150,14 @@ void PlayerbotHolder::AddPlayerBot(ObjectGuid playerGuid, uint32 masterAccountId
// Always login in with world session to avoid race condition
sWorld->AddQueryHolderCallback(CharacterDatabase.DelayQueryHolder(holder))
.AfterComplete(
[](SQLQueryHolderBase const& queryHolder)
{
PlayerbotLoginQueryHolder const& holder = static_cast<PlayerbotLoginQueryHolder const&>(queryHolder);
PlayerbotHolder* mgr = sRandomPlayerbotMgr; // could be null
uint32 masterAccountId = holder.GetMasterAccountId();
if (masterAccountId)
{
// verify and find current world session of master
WorldSession* masterSession = sWorldSessionMgr->FindSession(masterAccountId);
Player* masterPlayer = masterSession ? masterSession->GetPlayer() : nullptr;
if (masterPlayer)
mgr = GET_PLAYERBOT_MGR(masterPlayer);
}
if (mgr)
mgr->HandlePlayerBotLoginCallback(holder);
else
PlayerbotHolder::botLoading.erase(holder.GetGuid());
});
.AfterComplete([this](SQLQueryHolderBase const& holder)
{ HandlePlayerBotLoginCallback(static_cast<PlayerbotLoginQueryHolder const&>(holder)); });
}
bool PlayerbotHolder::IsAccountLinked(uint32 accountId, uint32 linkedAccountId)
{
QueryResult result = PlayerbotsDatabase.Query(
"SELECT 1 FROM playerbots_account_links WHERE account_id = {} AND linked_account_id = {}", accountId, linkedAccountId);
"SELECT 1 FROM playerbot_account_links WHERE account_id = {} AND linked_account_id = {}", accountId, linkedAccountId);
return result != nullptr;
}
@@ -187,9 +166,8 @@ void PlayerbotHolder::HandlePlayerBotLoginCallback(PlayerbotLoginQueryHolder con
uint32 botAccountId = holder.GetAccountId();
// At login DBC locale should be what the server is set to use by default (as spells etc are hardcoded to ENUS this
// allows channels to work as intended)
WorldSession* botSession =
new WorldSession(botAccountId, "", 0x0, nullptr, SEC_PLAYER, EXPANSION_WRATH_OF_THE_LICH_KING, time_t(0),
sWorld->GetDefaultDbcLocale(), 0, false, false, 0, true);
WorldSession* botSession = new WorldSession(botAccountId, "", nullptr, SEC_PLAYER, EXPANSION_WRATH_OF_THE_LICH_KING,
time_t(0), sWorld->GetDefaultDbcLocale(), 0, false, false, 0, true);
botSession->HandlePlayerLoginFromDB(holder); // will delete lqh
@@ -200,27 +178,24 @@ void PlayerbotHolder::HandlePlayerBotLoginCallback(PlayerbotLoginQueryHolder con
LOG_DEBUG("mod-playerbots", "Bot player could not be loaded for account ID: {}", botAccountId);
botSession->LogoutPlayer(true);
delete botSession;
PlayerbotHolder::botLoading.erase(holder.GetGuid());
botLoading.erase(holder.GetGuid());
return;
}
uint32 masterAccountId = holder.GetMasterAccountId();
WorldSession* masterSession = masterAccountId ? sWorldSessionMgr->FindSession(masterAccountId) : nullptr;
uint32 masterAccount = holder.GetMasterAccountId();
WorldSession* masterSession = masterAccount ? sWorldSessionMgr->FindSession(masterAccount) : nullptr;
// Check if masterSession->GetPlayer() is valid
Player* masterPlayer = masterSession ? masterSession->GetPlayer() : nullptr;
if (masterSession && !masterPlayer)
{
LOG_DEBUG("mod-playerbots", "Master session found but no player is associated for master account ID: {}",
masterAccountId);
LOG_DEBUG("mod-playerbots", "Master session found but no player is associated for master account ID: {}", masterAccount);
}
sRandomPlayerbotMgr->OnPlayerLogin(bot);
auto op = std::make_unique<OnBotLoginOperation>(bot->GetGUID(), masterAccountId);
sPlayerbotWorldProcessor->QueueOperation(std::move(op));
OnBotLogin(bot);
PlayerbotHolder::botLoading.erase(holder.GetGuid());
botLoading.erase(holder.GetGuid());
}
void PlayerbotHolder::UpdateSessions()
@@ -250,12 +225,6 @@ void PlayerbotHolder::HandleBotPackets(WorldSession* session)
{
OpcodeClient opcode = static_cast<OpcodeClient>(packet->GetOpcode());
ClientOpcodeHandler const* opHandle = opcodeTable[opcode];
if (!opHandle)
{
LOG_ERROR("playerbots", "Unhandled opcode {} queued for bot session {}. Packet dropped.", static_cast<uint32>(opcode), session->GetAccountId());
delete packet;
continue;
}
opHandle->Call(session, *packet);
delete packet;
}
@@ -339,9 +308,11 @@ void PlayerbotHolder::LogoutPlayerBot(ObjectGuid guid)
if (!botAI)
return;
// Queue group cleanup operation for world thread
auto cleanupOp = std::make_unique<BotLogoutGroupCleanupOperation>(guid);
sPlayerbotWorldProcessor->QueueOperation(std::move(cleanupOp));
Group* group = bot->GetGroup();
if (group && !bot->InBattleground() && !bot->InBattlegroundQueue() && botAI->HasActivePlayerMaster())
{
sPlayerbotDbStore->Save(botAI);
}
LOG_DEBUG("playerbots", "Bot {} logging out", bot->GetName().c_str());
bot->SaveToDB(false, false);
@@ -442,7 +413,7 @@ void PlayerbotHolder::DisablePlayerBot(ObjectGuid guid)
Group* group = bot->GetGroup();
if (group && !bot->InBattleground() && !bot->InBattlegroundQueue() && botAI->HasActivePlayerMaster())
{
sPlayerbotRepository->Save(botAI);
sPlayerbotDbStore->Save(botAI);
}
LOG_DEBUG("playerbots", "Bot {} logged out", bot->GetName().c_str());
@@ -502,11 +473,11 @@ void PlayerbotHolder::OnBotLogin(Player* const bot)
}
Player* master = botAI->GetMaster();
if (master)
if (!master)
{
ObjectGuid masterGuid = master->GetGUID();
if (master->GetGroup() && !master->GetGroup()->IsLeader(masterGuid))
master->GetGroup()->ChangeLeader(masterGuid);
// Log a warning to indicate that the master is null
LOG_DEBUG("mod-playerbots", "Master is null for bot with GUID: {}", bot->GetGUID().GetRawValue());
return;
}
Group* group = bot->GetGroup();
@@ -525,10 +496,7 @@ void PlayerbotHolder::OnBotLogin(Player* const bot)
break;
}
}
// Don't disband alt groups when master goes away
// Controlled by config
if (sPlayerbotAIConfig->KeepAltsInGroup())
else
{
uint32 account = sCharacterCache->GetCharacterAccountIdByGuid(member);
if (!sPlayerbotAIConfig->IsInRandomAccountList(account))
@@ -541,7 +509,7 @@ void PlayerbotHolder::OnBotLogin(Player* const bot)
if (!groupValid)
{
botAI->LeaveOrDisbandGroup();
bot->RemoveFromGroup();
}
}
@@ -554,7 +522,7 @@ void PlayerbotHolder::OnBotLogin(Player* const bot)
{
botAI->ResetStrategies(!sRandomPlayerbotMgr->IsRandomBot(bot));
}
sPlayerbotRepository->Load(botAI);
sPlayerbotDbStore->Load(botAI);
if (master && !master->HasUnitState(UNIT_STATE_IN_FLIGHT))
{
@@ -570,7 +538,6 @@ void PlayerbotHolder::OnBotLogin(Player* const bot)
botAI->TellMaster("Hello!", PLAYERBOT_SECURITY_TALK);
// Queue group operations for world thread
if (master && master->GetGroup() && !group)
{
Group* mgroup = master->GetGroup();
@@ -578,29 +545,24 @@ void PlayerbotHolder::OnBotLogin(Player* const bot)
{
if (!mgroup->isRaidGroup() && !mgroup->isLFGGroup() && !mgroup->isBGGroup() && !mgroup->isBFGroup())
{
// Queue ConvertToRaid operation
auto convertOp = std::make_unique<GroupConvertToRaidOperation>(master->GetGUID());
sPlayerbotWorldProcessor->QueueOperation(std::move(convertOp));
mgroup->ConvertToRaid();
}
if (mgroup->isRaidGroup())
{
// Queue AddMember operation
auto addOp = std::make_unique<GroupInviteOperation>(master->GetGUID(), bot->GetGUID());
sPlayerbotWorldProcessor->QueueOperation(std::move(addOp));
mgroup->AddMember(bot);
}
}
else
{
// Queue AddMember operation
auto addOp = std::make_unique<GroupInviteOperation>(master->GetGUID(), bot->GetGUID());
sPlayerbotWorldProcessor->QueueOperation(std::move(addOp));
mgroup->AddMember(bot);
}
}
else if (master && !group)
{
// Queue group creation and AddMember operation
auto inviteOp = std::make_unique<GroupInviteOperation>(master->GetGUID(), bot->GetGUID());
sPlayerbotWorldProcessor->QueueOperation(std::move(inviteOp));
Group* newGroup = new Group();
newGroup->Create(master);
sGroupMgr->AddGroup(newGroup);
newGroup->AddMember(bot);
}
// if (master)
// {
@@ -619,8 +581,8 @@ void PlayerbotHolder::OnBotLogin(Player* const bot)
}
bot->SaveToDB(false, false);
bool addClassBot = sRandomPlayerbotMgr->IsAccountType(accountId, 2);
if (addClassBot && master && abs((int)master->GetLevel() - (int)bot->GetLevel()) > 3)
bool addClassBot = sRandomPlayerbotMgr->IsAddclassBot(bot->GetGUID().GetCounter());
if (addClassBot && master && isRandomAccount && abs((int)master->GetLevel() - (int)bot->GetLevel()) > 3)
{
// PlayerbotFactory factory(bot, master->GetLevel());
// factory.Randomize(false);
@@ -872,18 +834,6 @@ std::string const PlayerbotHolder::ProcessBotCommand(std::string const cmd, Obje
return "unknown command";
}
// Added for gender choice : Returns the gender of an offline character: 0 = male, 1 = female.
static uint8 GetOfflinePlayerGender(ObjectGuid guid)
{
QueryResult result = CharacterDatabase.Query(
"SELECT gender FROM characters WHERE guid = {}", guid.GetCounter());
if (result)
return (*result)[0].Get<uint8>(); // 0 = male, 1 = female
return GENDER_MALE; // fallback value
}
bool PlayerbotMgr::HandlePlayerbotMgrCommand(ChatHandler* handler, char const* args)
{
if (!sPlayerbotAIConfig->enabled)
@@ -926,17 +876,15 @@ std::vector<std::string> PlayerbotHolder::HandlePlayerbotCommand(char const* arg
if (!*args)
{
messages.push_back("usage: list/reload/tweak/self or add/addaccount/init/remove PLAYERNAME\n");
messages.push_back("usage: addclass CLASSNAME [male|female|0|1]");
messages.push_back("usage: addclass CLASSNAME");
return messages;
}
char* cmd = strtok((char*)args, " ");
char* charname = strtok(nullptr, " ");
char* genderArg = strtok(nullptr, " "); // Added for gender choice [male|female|0|1] optionnel
if (!cmd)
{
messages.push_back("usage: list/reload/tweak/self or add/init/remove PLAYERNAME or addclass CLASSNAME [male|female]");
messages.push_back("usage: list/reload/tweak/self or add/init/remove PLAYERNAME or addclass CLASSNAME");
return messages;
}
@@ -1159,24 +1107,6 @@ std::vector<std::string> PlayerbotHolder::HandlePlayerbotCommand(char const* arg
messages.push_back("Error: Invalid Class. Try again.");
return messages;
}
// Added for gender choice : Parsing gender
int8 gender = -1; // -1 = gender will be random
if (genderArg)
{
std::string g = genderArg;
std::transform(g.begin(), g.end(), g.begin(), ::tolower);
if (g == "male" || g == "0")
gender = GENDER_MALE; // 0
else if (g == "female" || g == "1")
gender = GENDER_FEMALE; // 1
else
{
messages.push_back("Unknown gender : " + g + " (male/female/0/1)");
return messages;
}
} //end
if (claz == 6 && master->GetLevel() < sWorld->getIntConfig(CONFIG_START_HEROIC_PLAYER_LEVEL))
{
messages.push_back("Your level is too low to summon Deathknight");
@@ -1186,15 +1116,12 @@ std::vector<std::string> PlayerbotHolder::HandlePlayerbotCommand(char const* arg
const std::unordered_set<ObjectGuid> &guidCache = sRandomPlayerbotMgr->addclassCache[RandomPlayerbotMgr::GetTeamClassIdx(teamId == TEAM_ALLIANCE, claz)];
for (const ObjectGuid &guid: guidCache)
{
// If the user requested a specific gender, skip any character that doesn't match.
if (gender != -1 && GetOfflinePlayerGender(guid) != gender)
continue;
if (botLoading.find(guid) != botLoading.end())
continue;
if (ObjectAccessor::FindConnectedPlayer(guid))
continue;
uint32 guildId = sCharacterCache->GetCharacterGuildIdByGuid(guid);
if (guildId && sPlayerbotGuildMgr->IsRealGuild(guildId))
if (guildId && PlayerbotAI::IsRealGuild(guildId))
continue;
AddPlayerBot(guid, master->GetSession()->GetAccountId());
messages.push_back("Add class " + std::string(charname));
@@ -1629,26 +1556,8 @@ void PlayerbotMgr::OnBotLoginInternal(Player* const bot)
void PlayerbotMgr::OnPlayerLogin(Player* player)
{
if (!player)
return;
WorldSession* session = player->GetSession();
if (!session)
{
LOG_WARN("playerbots", "Unable to register locale priority for player {} because the session is missing", player->GetName());
return;
}
// DB locale (source of bot text translation)
LocaleConstant const databaseLocale = session->GetSessionDbLocaleIndex();
// For bot texts (DB-driven), prefer the database locale with a safe fallback.
LocaleConstant usedLocale = databaseLocale;
if (usedLocale >= MAX_LOCALES)
usedLocale = LOCALE_enUS; // fallback
// set locale priority for bot texts
sPlayerbotTextMgr->AddLocalePriority(usedLocale);
sPlayerbotTextMgr->AddLocalePriority(player->GetSession()->GetSessionDbcLocale());
if (sPlayerbotAIConfig->selfBotLevel > 2)
HandlePlayerbotCommand("self", player);
@@ -1656,7 +1565,7 @@ void PlayerbotMgr::OnPlayerLogin(Player* player)
if (!sPlayerbotAIConfig->botAutologin)
return;
uint32 accountId = session->GetAccountId();
uint32 accountId = player->GetSession()->GetAccountId();
QueryResult results = CharacterDatabase.Query("SELECT name FROM characters WHERE account = {}", accountId);
if (results)
{
@@ -1781,8 +1690,7 @@ PlayerbotAI* PlayerbotsMgr::GetPlayerbotAI(Player* player)
{
return nullptr;
}
// if (player->GetSession()->isLogingOut() || player->IsDuringRemoveFromWorld())
// {
// if (player->GetSession()->isLogingOut() || player->IsDuringRemoveFromWorld()) {
// return nullptr;
// }
auto itr = _playerbotsAIMap.find(player->GetGUID());
@@ -1826,7 +1734,7 @@ void PlayerbotMgr::HandleSetSecurityKeyCommand(Player* player, const std::string
// Store the hashed key in the database
PlayerbotsDatabase.Execute(
"REPLACE INTO playerbots_account_keys (account_id, security_key) VALUES ({}, '{}')",
"REPLACE INTO playerbot_account_keys (account_id, security_key) VALUES ({}, '{}')",
accountId, hashedKey.str());
ChatHandler(player->GetSession()).PSendSysMessage("Security key set successfully.");
@@ -1844,7 +1752,7 @@ void PlayerbotMgr::HandleLinkAccountCommand(Player* player, const std::string& a
Field* fields = result->Fetch();
uint32 linkedAccountId = fields[0].Get<uint32>();
result = PlayerbotsDatabase.Query("SELECT security_key FROM playerbots_account_keys WHERE account_id = {}", linkedAccountId);
result = PlayerbotsDatabase.Query("SELECT security_key FROM playerbot_account_keys WHERE account_id = {}", linkedAccountId);
if (!result)
{
ChatHandler(player->GetSession()).PSendSysMessage("Invalid security key.");
@@ -1870,10 +1778,10 @@ void PlayerbotMgr::HandleLinkAccountCommand(Player* player, const std::string& a
uint32 accountId = player->GetSession()->GetAccountId();
PlayerbotsDatabase.Execute(
"INSERT IGNORE INTO playerbots_account_links (account_id, linked_account_id) VALUES ({}, {})",
"INSERT IGNORE INTO playerbot_account_links (account_id, linked_account_id) VALUES ({}, {})",
accountId, linkedAccountId);
PlayerbotsDatabase.Execute(
"INSERT IGNORE INTO playerbots_account_links (account_id, linked_account_id) VALUES ({}, {})",
"INSERT IGNORE INTO playerbot_account_links (account_id, linked_account_id) VALUES ({}, {})",
linkedAccountId, accountId);
ChatHandler(player->GetSession()).PSendSysMessage("Account linked successfully.");
@@ -1882,7 +1790,7 @@ void PlayerbotMgr::HandleLinkAccountCommand(Player* player, const std::string& a
void PlayerbotMgr::HandleViewLinkedAccountsCommand(Player* player)
{
uint32 accountId = player->GetSession()->GetAccountId();
QueryResult result = PlayerbotsDatabase.Query("SELECT linked_account_id FROM playerbots_account_links WHERE account_id = {}", accountId);
QueryResult result = PlayerbotsDatabase.Query("SELECT linked_account_id FROM playerbot_account_links WHERE account_id = {}", accountId);
if (!result)
{
@@ -1923,7 +1831,7 @@ void PlayerbotMgr::HandleUnlinkAccountCommand(Player* player, const std::string&
uint32 linkedAccountId = fields[0].Get<uint32>();
uint32 accountId = player->GetSession()->GetAccountId();
PlayerbotsDatabase.Execute("DELETE FROM playerbots_account_links WHERE (account_id = {} AND linked_account_id = {}) OR (account_id = {} AND linked_account_id = {})",
PlayerbotsDatabase.Execute("DELETE FROM playerbot_account_links WHERE (account_id = {} AND linked_account_id = {}) OR (account_id = {} AND linked_account_id = {})",
accountId, linkedAccountId, linkedAccountId, accountId);
ChatHandler(player->GetSession()).PSendSysMessage("Account unlinked successfully.");

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
* and/or modify it under version 3 of the License, or (at your option), any later version.
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it
* and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#ifndef _PLAYERBOT_PLAYERBOTMGR_H
@@ -60,7 +60,7 @@ protected:
virtual void OnBotLoginInternal(Player* const bot) = 0;
PlayerBotMap playerBots;
static std::unordered_set<ObjectGuid> botLoading;
std::unordered_set<ObjectGuid> botLoading;
};
class PlayerbotMgr : public PlayerbotHolder

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
* and/or modify it under version 3 of the License, or (at your option), any later version.
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it
* and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#include "PlayerbotSecurity.h"
@@ -17,28 +17,14 @@ PlayerbotSecurity::PlayerbotSecurity(Player* const bot) : bot(bot)
PlayerbotSecurityLevel PlayerbotSecurity::LevelFor(Player* from, DenyReason* reason, bool ignoreGroup)
{
// Basic pointer validity checks
if (!bot || !from || !from->GetSession())
{
if (reason)
*reason = PLAYERBOT_DENY_NONE;
return PLAYERBOT_SECURITY_DENY_ALL;
}
// GMs always have full access
if (from->GetSession()->GetSecurity() >= SEC_GAMEMASTER)
return PLAYERBOT_SECURITY_ALLOW_ALL;
PlayerbotAI* botAI = GET_PLAYERBOT_AI(bot);
if (!botAI)
{
if (reason)
*reason = PLAYERBOT_DENY_NONE;
return PLAYERBOT_SECURITY_DENY_ALL;
}
if (botAI->IsOpposing(from))
{
if (reason)
@@ -49,7 +35,6 @@ PlayerbotSecurityLevel PlayerbotSecurity::LevelFor(Player* from, DenyReason* rea
if (sPlayerbotAIConfig->IsInRandomAccountList(account))
{
// (duplicate check in case of faction change)
if (botAI->IsOpposing(from))
{
if (reason)
@@ -58,17 +43,27 @@ PlayerbotSecurityLevel PlayerbotSecurity::LevelFor(Player* from, DenyReason* rea
return PLAYERBOT_SECURITY_DENY_ALL;
}
Group* fromGroup = from->GetGroup();
Group* botGroup = bot->GetGroup();
// if (sLFGMgr->GetState(bot->GetGUID()) != lfg::LFG_STATE_NONE)
// {
// if (!bot->GetGuildId() || bot->GetGuildId() != from->GetGuildId())
// {
// if (reason)
// *reason = PLAYERBOT_DENY_LFG;
if (fromGroup && botGroup && fromGroup == botGroup && !ignoreGroup)
// return PLAYERBOT_SECURITY_TALK;
// }
// }
Group* group = from->GetGroup();
if (group && group == bot->GetGroup() && !ignoreGroup && botAI->GetMaster() == from)
{
if (botAI->GetMaster() == from)
return PLAYERBOT_SECURITY_ALLOW_ALL;
return PLAYERBOT_SECURITY_ALLOW_ALL;
}
if (group && group == bot->GetGroup() && !ignoreGroup && botAI->GetMaster() != from)
{
if (reason)
*reason = PLAYERBOT_DENY_NOT_YOURS;
return PLAYERBOT_SECURITY_TALK;
}
@@ -80,34 +75,27 @@ PlayerbotSecurityLevel PlayerbotSecurity::LevelFor(Player* from, DenyReason* rea
return PLAYERBOT_SECURITY_TALK;
}
if (sPlayerbotAIConfig->groupInvitationPermission <= 1)
if (sPlayerbotAIConfig->groupInvitationPermission <= 1 && (int32)bot->GetLevel() - (int8)from->GetLevel() > 5)
{
int32 levelDiff = int32(bot->GetLevel()) - int32(from->GetLevel());
if (levelDiff > 5)
if (!bot->GetGuildId() || bot->GetGuildId() != from->GetGuildId())
{
if (!bot->GetGuildId() || bot->GetGuildId() != from->GetGuildId())
{
if (reason)
*reason = PLAYERBOT_DENY_LOW_LEVEL;
if (reason)
*reason = PLAYERBOT_DENY_LOW_LEVEL;
return PLAYERBOT_SECURITY_TALK;
}
return PLAYERBOT_SECURITY_TALK;
}
}
int32 botGS = static_cast<int32>(botAI->GetEquipGearScore(bot));
int32 fromGS = static_cast<int32>(botAI->GetEquipGearScore(from));
if (sPlayerbotAIConfig->gearscorecheck && botGS && bot->GetLevel() > 15 && botGS > fromGS)
int32 botGS = (int32)botAI->GetEquipGearScore(bot/*, false, false*/);
int32 fromGS = (int32)botAI->GetEquipGearScore(from/*, false, false*/);
if (sPlayerbotAIConfig->gearscorecheck)
{
uint32 diffPct = uint32(100 * (botGS - fromGS) / botGS);
uint32 reqPct = uint32(12 * sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL) / from->GetLevel());
if (diffPct >= reqPct)
if (botGS && bot->GetLevel() > 15 && botGS > fromGS &&
static_cast<float>(100 * (botGS - fromGS) / botGS) >=
static_cast<float>(12 * sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL) / from->GetLevel()))
{
if (reason)
*reason = PLAYERBOT_DENY_GEARSCORE;
return PLAYERBOT_SECURITY_TALK;
}
}
@@ -123,17 +111,35 @@ PlayerbotSecurityLevel PlayerbotSecurity::LevelFor(Player* from, DenyReason* rea
}
}
// If the bot is not in the group, we offer an invite
botGroup = bot->GetGroup();
if (!botGroup)
/*if (bot->isDead())
{
if (reason)
*reason = PLAYERBOT_DENY_DEAD;
return PLAYERBOT_SECURITY_TALK;
}*/
group = bot->GetGroup();
if (!group)
{
/*if (bot->GetMapId() != from->GetMapId() || bot->GetDistance(from) > sPlayerbotAIConfig->whisperDistance)
{
if (!bot->GetGuildId() || bot->GetGuildId() != from->GetGuildId())
{
if (reason)
*reason = PLAYERBOT_DENY_FAR;
return PLAYERBOT_SECURITY_TALK;
}
}*/
if (reason)
*reason = PLAYERBOT_DENY_INVITE;
return PLAYERBOT_SECURITY_INVITE;
}
if (!ignoreGroup && botGroup->IsFull())
if (!ignoreGroup && group->IsFull())
{
if (reason)
*reason = PLAYERBOT_DENY_FULL_GROUP;
@@ -141,22 +147,27 @@ PlayerbotSecurityLevel PlayerbotSecurity::LevelFor(Player* from, DenyReason* rea
return PLAYERBOT_SECURITY_TALK;
}
if (!ignoreGroup && botGroup->GetLeaderGUID() != bot->GetGUID())
if (!ignoreGroup && group->GetLeaderGUID() != bot->GetGUID())
{
if (reason)
*reason = PLAYERBOT_DENY_NOT_LEADER;
return PLAYERBOT_SECURITY_TALK;
}
else
{
if (reason)
*reason = PLAYERBOT_DENY_IS_LEADER;
return PLAYERBOT_SECURITY_INVITE;
}
// The bot is the group leader, you can invite the initiator
if (reason)
*reason = PLAYERBOT_DENY_IS_LEADER;
*reason = PLAYERBOT_DENY_INVITE;
return PLAYERBOT_SECURITY_INVITE;
}
// Non-random bots: only their master has full access
if (botAI->GetMaster() == from)
return PLAYERBOT_SECURITY_ALLOW_ALL;
@@ -168,13 +179,8 @@ PlayerbotSecurityLevel PlayerbotSecurity::LevelFor(Player* from, DenyReason* rea
bool PlayerbotSecurity::CheckLevelFor(PlayerbotSecurityLevel level, bool silent, Player* from, bool ignoreGroup)
{
// If something is wrong with the pointers, we silently refuse
if (!bot || !from || !from->GetSession())
return false;
DenyReason reason = PLAYERBOT_DENY_NONE;
PlayerbotSecurityLevel realLevel = LevelFor(from, &reason, ignoreGroup);
if (realLevel >= level || from == bot)
return true;
@@ -183,17 +189,11 @@ bool PlayerbotSecurity::CheckLevelFor(PlayerbotSecurityLevel level, bool silent,
return false;
PlayerbotAI* botAI = GET_PLAYERBOT_AI(bot);
if (!botAI)
Player* master = botAI->GetMaster();
if (master && botAI && botAI->IsOpposing(master) && master->GetSession()->GetSecurity() < SEC_GAMEMASTER)
return false;
Player* master = botAI->GetMaster();
if (master && botAI->IsOpposing(master))
if (WorldSession* session = master->GetSession())
if (session->GetSecurity() < SEC_GAMEMASTER)
return false;
std::ostringstream out;
switch (realLevel)
{
case PLAYERBOT_SECURITY_DENY_ALL:
@@ -206,20 +206,19 @@ bool PlayerbotSecurity::CheckLevelFor(PlayerbotSecurityLevel level, bool silent,
out << "I'll do it later";
break;
case PLAYERBOT_DENY_LOW_LEVEL:
out << "You are too low level: |cffff0000" << uint32(from->GetLevel()) << "|cffffffff/|cff00ff00"
<< uint32(bot->GetLevel());
out << "You are too low level: |cffff0000" << (uint32)from->GetLevel() << "|cffffffff/|cff00ff00"
<< (uint32)bot->GetLevel();
break;
case PLAYERBOT_DENY_GEARSCORE:
{
int botGS = int(botAI->GetEquipGearScore(bot));
int fromGS = int(botAI->GetEquipGearScore(from));
int botGS = (int)botAI->GetEquipGearScore(bot/*, false, false*/);
int fromGS = (int)botAI->GetEquipGearScore(from/*, false, false*/);
int diff = (100 * (botGS - fromGS) / botGS);
int req = 12 * sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL) / from->GetLevel();
out << "Your gearscore is too low: |cffff0000" << fromGS << "|cffffffff/|cff00ff00" << botGS
<< " |cffff0000" << diff << "%|cffffffff/|cff00ff00" << req << "%";
break;
}
break;
case PLAYERBOT_DENY_NOT_YOURS:
out << "I have a master already";
break;
@@ -238,10 +237,13 @@ bool PlayerbotSecurity::CheckLevelFor(PlayerbotSecurityLevel level, bool silent,
case PLAYERBOT_DENY_FAR:
{
out << "You must be closer to invite me to your group. I am in ";
if (AreaTableEntry const* entry = sAreaTableStore.LookupEntry(bot->GetAreaId()))
{
out << " |cffffffff(|cffff0000" << entry->area_name[0] << "|cffffffff)";
break;
}
}
break;
case PLAYERBOT_DENY_FULL_GROUP:
out << "I am in a full group. Will do it later";
break;
@@ -249,10 +251,15 @@ bool PlayerbotSecurity::CheckLevelFor(PlayerbotSecurityLevel level, bool silent,
out << "I am currently leading a group. I can invite you if you want.";
break;
case PLAYERBOT_DENY_NOT_LEADER:
if (Player* leader = botAI->GetGroupLeader())
out << "I am in a group with " << leader->GetName() << ". You can ask him for invite.";
if (botAI->GetGroupMaster())
{
out << "I am in a group with " << botAI->GetGroupMaster()->GetName()
<< ". You can ask him for invite.";
}
else
{
out << "I am in a group with someone else. You can ask him for invite.";
}
break;
case PLAYERBOT_DENY_BG:
out << "I am in a queue for BG. Will do it later";
@@ -276,14 +283,10 @@ bool PlayerbotSecurity::CheckLevelFor(PlayerbotSecurityLevel level, bool silent,
std::string const text = out.str();
ObjectGuid guid = from->GetGUID();
time_t lastSaid = whispers[guid][text];
if (!lastSaid || (time(nullptr) - lastSaid) >= sPlayerbotAIConfig->repeatDelay / 1000)
{
whispers[guid][text] = time(nullptr);
// Additional protection against crashes during logout
if (bot->IsInWorld() && from->IsInWorld())
bot->Whisper(text, LANG_UNIVERSAL, from);
bot->Whisper(text, LANG_UNIVERSAL, from);
}
return false;

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
* and/or modify it under version 3 of the License, or (at your option), any later version.
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it
* and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#ifndef _PLAYERBOT_PLAYERBOTSECURITY_H

View File

@@ -25,14 +25,10 @@
#include "Metric.h"
#include "PlayerScript.h"
#include "PlayerbotAIConfig.h"
#include "PlayerbotGuildMgr.h"
#include "PlayerbotSpellRepository.h"
#include "PlayerbotWorldThreadProcessor.h"
#include "RandomPlayerbotMgr.h"
#include "ScriptMgr.h"
#include "PlayerbotCommandScript.h"
#include "cs_playerbots.h"
#include "cmath"
#include "BattleGroundTactics.h"
class PlayerbotsDatabaseScript : public DatabaseScript
{
@@ -84,14 +80,13 @@ public:
PlayerbotsPlayerScript() : PlayerScript("PlayerbotsPlayerScript", {
PLAYERHOOK_ON_LOGIN,
PLAYERHOOK_ON_AFTER_UPDATE,
PLAYERHOOK_ON_CHAT,
PLAYERHOOK_ON_CHAT_WITH_CHANNEL,
PLAYERHOOK_ON_CHAT_WITH_GROUP,
PLAYERHOOK_ON_BEFORE_CRITERIA_PROGRESS,
PLAYERHOOK_ON_BEFORE_ACHI_COMPLETE,
PLAYERHOOK_CAN_PLAYER_USE_PRIVATE_CHAT,
PLAYERHOOK_CAN_PLAYER_USE_GROUP_CHAT,
PLAYERHOOK_CAN_PLAYER_USE_GUILD_CHAT,
PLAYERHOOK_CAN_PLAYER_USE_CHANNEL_CHAT,
PLAYERHOOK_ON_GIVE_EXP,
PLAYERHOOK_ON_BEFORE_TELEPORT
PLAYERHOOK_ON_GIVE_EXP
}) {}
void OnPlayerLogin(Player* player) override
@@ -109,7 +104,7 @@ public:
{
ChatHandler(player->GetSession()).SendSysMessage(
"|cff00ff00This server runs with |cff00ccffmod-playerbots|r "
"|cffcccccchttps://github.com/mod-playerbots/mod-playerbots|r");
"|cffcccccchttps://github.com/liyunfan1223/mod-playerbots|r");
}
if (sPlayerbotAIConfig->enabled || sPlayerbotAIConfig->randomBotAutologin)
@@ -119,57 +114,12 @@ public:
roundedTime = roundedTime.substr(0, roundedTime.find('.') + 2);
ChatHandler(player->GetSession()).SendSysMessage(
"|cff00ff00Playerbots:|r bot initialization at server startup takes about '"
"|cff00ff00Playerbots:|r bot initialization at server startup takes about '"
+ roundedTime + "' minutes.");
}
}
}
bool OnPlayerBeforeTeleport(Player* /*player*/, uint32 /*mapid*/, float /*x*/, float /*y*/, float /*z*/, float /*orientation*/, uint32 /*options*/, Unit* /*target*/) override
{
/* for now commmented out until proven its actually required
* havent seen any proof CleanVisibilityReferences() is needed
// If the player is not safe to touch, do nothing
if (!player)
return true;
// If same map or not in world do nothing
if (!player->IsInWorld() || player->GetMapId() == mapid)
return true;
// If real player do nothing
PlayerbotAI* ai = GET_PLAYERBOT_AI(player);
if (!ai || ai->IsRealPlayer())
return true;
// Cross-map bot teleport: defer visibility reference cleanup.
// CleanVisibilityReferences() erases this bot's GUID from other objects' visibility containers.
// This is intentionally done via the event queue (instead of directly here) because erasing
// from other players' visibility maps inside the teleport call stack can hit unsafe re-entrancy
// or iterator invalidation while visibility updates are in progress
ObjectGuid guid = player->GetGUID();
player->m_Events.AddEventAtOffset(
[guid, mapid]()
{
// do nothing, if the player is not safe to touch
Player* p = ObjectAccessor::FindPlayer(guid);
if (!p || !p->IsInWorld() || p->IsDuringRemoveFromWorld())
return;
// do nothing if we are already on the target map
if (p->GetMapId() == mapid)
return;
p->GetObjectVisibilityContainer().CleanVisibilityReferences();
},
Milliseconds(0));
*/
return true;
}
void OnPlayerAfterUpdate(Player* player, uint32 diff) override
{
if (PlayerbotAI* botAI = GET_PLAYERBOT_AI(player))
@@ -191,17 +141,14 @@ public:
{
botAI->HandleCommand(type, msg, player);
// hotfix; otherwise the server will crash when whispering logout
// https://github.com/mod-playerbots/mod-playerbots/pull/1838
// TODO: find the root cause and solve it. (does not happen in party chat)
if (msg == "logout")
return false;
return false;
}
}
return true;
}
bool OnPlayerCanUseChat(Player* player, uint32 type, uint32 /*lang*/, std::string& msg, Group* group) override
void OnPlayerChat(Player* player, uint32 type, uint32 /*lang*/, std::string& msg, Group* group) override
{
for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next())
{
@@ -213,10 +160,9 @@ public:
}
}
}
return true;
}
bool OnPlayerCanUseChat(Player* player, uint32 type, uint32 /*lang*/, std::string& msg, Guild* guild) override
void OnPlayerChat(Player* player, uint32 type, uint32 /*lang*/, std::string& msg) override
{
if (type == CHAT_MSG_GUILD)
{
@@ -235,10 +181,9 @@ public:
}
}
}
return true;
}
bool OnPlayerCanUseChat(Player* player, uint32 type, uint32 /*lang*/, std::string& msg, Channel* channel) override
void OnPlayerChat(Player* player, uint32 type, uint32 /*lang*/, std::string& msg, Channel* channel) override
{
if (PlayerbotMgr* playerbotMgr = GET_PLAYERBOT_MGR(player))
{
@@ -249,50 +194,35 @@ public:
}
sRandomPlayerbotMgr->HandleCommand(type, msg, player);
return true;
}
bool OnPlayerBeforeAchievementComplete(Player* player, AchievementEntry const* achievement) override
bool OnPlayerBeforeCriteriaProgress(Player* player, AchievementCriteriaEntry const* /*criteria*/) override
{
if ((sRandomPlayerbotMgr->IsRandomBot(player) || sRandomPlayerbotMgr->IsAddclassBot(player)) &&
(achievement->flags & (ACHIEVEMENT_FLAG_REALM_FIRST_REACH | ACHIEVEMENT_FLAG_REALM_FIRST_KILL)))
if (sRandomPlayerbotMgr->IsRandomBot(player))
{
return false;
}
return true;
}
bool OnPlayerBeforeAchievementComplete(Player* player, AchievementEntry const* /*achievement*/) override
{
if (sRandomPlayerbotMgr->IsRandomBot(player))
{
return false;
}
return true;
}
void OnPlayerGiveXP(Player* player, uint32& amount, Unit* /*victim*/, uint8 /*xpSource*/) override
{
// early return
if (sPlayerbotAIConfig->randomBotXPRate == 1.0 || !player)
if (!player->GetSession()->IsBot())
return;
// no XP multiplier, when player is no bot.
if (!player->GetSession()->IsBot() || !sRandomPlayerbotMgr->IsRandomBot(player))
return;
// no XP multiplier, when bot is in a group with a real player.
if (Group* group = player->GetGroup())
if (sPlayerbotAIConfig->playerbotsXPrate != 1.0)
{
for (GroupReference* gref = group->GetFirstMember(); gref; gref = gref->next())
{
Player* member = gref->GetSource();
if (!member)
{
continue;
}
if (!member->GetSession()->IsBot())
{
return;
}
}
amount = static_cast<uint32>(std::round(static_cast<float>(amount) * sPlayerbotAIConfig->playerbotsXPrate));
}
// otherwise apply bot XP multiplier.
amount = static_cast<uint32>(std::round(static_cast<float>(amount) * sPlayerbotAIConfig->randomBotXPRate));
}
};
@@ -334,8 +264,7 @@ class PlayerbotsWorldScript : public WorldScript
{
public:
PlayerbotsWorldScript() : WorldScript("PlayerbotsWorldScript", {
WORLDHOOK_ON_BEFORE_WORLD_INITIALIZED,
WORLDHOOK_ON_UPDATE
WORLDHOOK_ON_BEFORE_WORLD_INITIALIZED
}) {}
void OnBeforeWorldInitialized() override
@@ -352,11 +281,11 @@ public:
LOG_INFO("server.loading", "║ mod-playerbots is a community-driven open-source ║");
LOG_INFO("server.loading", "║ project based on AzerothCore, licensed under AGPLv3.0 ║");
LOG_INFO("server.loading", "╟──────────────────────────────────────────────────────────╢");
LOG_INFO("server.loading", "║ https://github.com/mod-playerbots/mod-playerbots ║");
LOG_INFO("server.loading", "║ https://github.com/liyunfan1223/mod-playerbots ");
LOG_INFO("server.loading", "╚══════════════════════════════════════════════════════════╝");
uint32 oldMSTime = getMSTime();
LOG_INFO("server.loading", " ");
LOG_INFO("server.loading", "Load Playerbots Config...");
@@ -364,16 +293,6 @@ public:
LOG_INFO("server.loading", ">> Loaded playerbots config in {} ms", GetMSTimeDiffToNow(oldMSTime));
LOG_INFO("server.loading", " ");
sPlayerbotSpellRepository->Initialize();
LOG_INFO("server.loading", "Playerbots World Thread Processor initialized");
}
void OnUpdate(uint32 diff) override
{
sPlayerbotWorldProcessor->Update(diff);
sRandomPlayerbotMgr->UpdateAI(diff); // World thread only
}
};
@@ -435,7 +354,8 @@ public:
void OnPlayerbotUpdate(uint32 diff) override
{
sRandomPlayerbotMgr->UpdateSessions(); // Per-bot updates only
sRandomPlayerbotMgr->UpdateAI(diff);
sRandomPlayerbotMgr->UpdateSessions();
}
void OnPlayerbotUpdateSessions(Player* player) override
@@ -466,45 +386,6 @@ public:
}
};
class PlayerBotsBGScript : public BGScript
{
public:
PlayerBotsBGScript() : BGScript("PlayerBotsBGScript") {}
void OnBattlegroundStart(Battleground* bg) override
{
BGStrategyData data;
switch (bg->GetBgTypeID())
{
case BATTLEGROUND_WS:
data.allianceStrategy = urand(0, WS_STRATEGY_MAX - 1);
data.hordeStrategy = urand(0, WS_STRATEGY_MAX - 1);
break;
case BATTLEGROUND_AB:
data.allianceStrategy = urand(0, AB_STRATEGY_MAX - 1);
data.hordeStrategy = urand(0, AB_STRATEGY_MAX - 1);
break;
case BATTLEGROUND_AV:
data.allianceStrategy = urand(0, AV_STRATEGY_MAX - 1);
data.hordeStrategy = urand(0, AV_STRATEGY_MAX - 1);
break;
case BATTLEGROUND_EY:
data.allianceStrategy = urand(0, EY_STRATEGY_MAX - 1);
data.hordeStrategy = urand(0, EY_STRATEGY_MAX - 1);
break;
default:
break;
}
bgStrategies[bg->GetInstanceID()] = data;
}
void OnBattlegroundEnd(Battleground* bg, TeamId /*winnerTeam*/) override { bgStrategies.erase(bg->GetInstanceID()); }
};
void AddPlayerbotsSecureLoginScripts();
void AddPlayerbotsScripts()
{
new PlayerbotsDatabaseScript();
@@ -513,8 +394,6 @@ void AddPlayerbotsScripts()
new PlayerbotsServerScript();
new PlayerbotsWorldScript();
new PlayerbotsScript();
new PlayerBotsBGScript();
AddPlayerbotsSecureLoginScripts();
AddPlayerbotsCommandscripts();
PlayerBotsGuildValidationScript();
AddSC_playerbots_commandscript();
}

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