mirror of
https://github.com/mod-playerbots/mod-playerbots.git
synced 2026-01-18 11:15:43 +00:00
Compare commits
1 Commits
master
...
project_tr
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8d09a08dfd |
40
.github/workflows/codestyle_cpp.yml
vendored
40
.github/workflows/codestyle_cpp.yml
vendored
@@ -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
|
|
||||||
6
.github/workflows/windows_build.yml
vendored
6
.github/workflows/windows_build.yml
vendored
@@ -25,25 +25,21 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
repository: 'mod-playerbots/azerothcore-wotlk'
|
repository: 'mod-playerbots/azerothcore-wotlk'
|
||||||
ref: 'Playerbot'
|
ref: 'Playerbot'
|
||||||
path: 'ac'
|
|
||||||
- name: Checkout Playerbot Module
|
- name: Checkout Playerbot Module
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
repository: 'mod-playerbots/mod-playerbots'
|
repository: 'mod-playerbots/mod-playerbots'
|
||||||
#path: 'modules/mod-playerbots'
|
path: 'modules/mod-playerbots'
|
||||||
path: ac/modules/mod-playerbots
|
|
||||||
- name: ccache
|
- name: ccache
|
||||||
uses: hendrikmuhs/ccache-action@v1.2.13
|
uses: hendrikmuhs/ccache-action@v1.2.13
|
||||||
- name: Configure OS
|
- name: Configure OS
|
||||||
shell: bash
|
shell: bash
|
||||||
working-directory: ac
|
|
||||||
env:
|
env:
|
||||||
CONTINUOUS_INTEGRATION: true
|
CONTINUOUS_INTEGRATION: true
|
||||||
run: |
|
run: |
|
||||||
./acore.sh install-deps
|
./acore.sh install-deps
|
||||||
- name: Build
|
- name: Build
|
||||||
shell: bash
|
shell: bash
|
||||||
working-directory: ac
|
|
||||||
run: |
|
run: |
|
||||||
export CTOOLS_BUILD=all
|
export CTOOLS_BUILD=all
|
||||||
./acore.sh compiler build
|
./acore.sh compiler build
|
||||||
|
|||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -49,4 +49,3 @@ local.properties
|
|||||||
.project
|
.project
|
||||||
.cproject
|
.cproject
|
||||||
.vscode
|
.vscode
|
||||||
.idea
|
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
cppcheckError
|
|
||||||
48
README.md
48
README.md
@@ -3,7 +3,7 @@
|
|||||||
|
|
|
|
||||||
<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_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/brighton-chi/mod-playerbots/blob/readme/README_ES.md">Español</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
|
||||||
@@ -18,27 +18,25 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
# Playerbots Module
|
# 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) and requires a custom branch of AzerothCore to compile and run: [mod-playerbots/azerothcore-wotlk/tree/Playerbot](https://github.com/mod-playerbots/azerothcore-wotlk/tree/Playerbot).
|
||||||
|
|
||||||
Features include:
|
Features include:
|
||||||
|
|
||||||
- The ability to log in alt characters as bots, allowing players to interact with their other characters, form parties, level up, and more
|
- 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
|
- 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
|
- Bots capable of running most raids and battlegrounds;
|
||||||
- Highly configurable settings to define how bots behave
|
- Highly configurable settings to define how bots behave;
|
||||||
- Excellent performance, even when running thousands of bots
|
- Excellent performance, even when running thousands of bots.
|
||||||
|
|
||||||
We also have a **[Discord server](https://discord.gg/NQm5QShwf9)** where you can discuss the project, ask questions, and get involved in the community!
|
**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/mod-playerbots/mod-playerbots/issues/new?template=bug_report.md). Your valuable feedback will help us improve this project collaboratively.
|
||||||
|
|
||||||
|
`mod-playerbots` has a **[Discord server](https://discord.gg/NQm5QShwf9)** where you can discuss the project, ask questions, and get involved in the community!
|
||||||
|
|
||||||
## Installation
|
## 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.
|
As noted above, `mod-playerbots` requires a custom branch of AzerothCore: [mod-playerbots/azerothcore-wotlk/tree/Playerbot](https://github.com/mod-playerbots/azerothcore-wotlk/tree/Playerbot). To install the module, simply run:
|
||||||
|
|
||||||
### Cloning the Repositories
|
|
||||||
|
|
||||||
To install both the required branch of AzerothCore and the `mod-playerbots` module from source, run the following:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone https://github.com/mod-playerbots/azerothcore-wotlk.git --branch=Playerbot
|
git clone https://github.com/mod-playerbots/azerothcore-wotlk.git --branch=Playerbot
|
||||||
@@ -50,7 +48,7 @@ For more information, refer to the [AzerothCore Installation Guide](https://www.
|
|||||||
|
|
||||||
### Docker Installation
|
### 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
|
```bash
|
||||||
git clone https://github.com/mod-playerbots/azerothcore-wotlk.git --branch=Playerbot
|
git clone https://github.com/mod-playerbots/azerothcore-wotlk.git --branch=Playerbot
|
||||||
@@ -87,23 +85,25 @@ Use `docker compose up -d --build` to build and run the server. For more informa
|
|||||||
|
|
||||||
## Documentation
|
## 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/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. 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 ensure that you are compiling with the required [custom branch of AzerothCore](https://github.com/mod-playerbots/azerothcore-wotlk/tree/Playerbot). Additionally, please [check the build status of our CI](https://github.com/mod-playerbots/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.
|
- [Multibot](https://github.com/Macx-Lio/MultiBot) (by Macx-Lio), which includes English, Chinese, French, German, Korean, Russian, and Spanish support [note: active development is temporarily continuing on a fork in Macx-Lio's absence (https://github.com/Wishmaster117/MultiBot)]
|
||||||
|
- [Unbot Addon (zh)](https://github.com/liyunfan1223/unbot-addon) (Chinese version by Liyunfan) [note: no longer under active development]
|
||||||
Please click on the "⭐" button to stay up to date and help us gain more visibility on GitHub!
|
- [Unbot Addon (en)](https://github.com/noisiver/unbot-addon/tree/english) (English version translated by @Revision) [note: no longer under active development]
|
||||||
|
|
||||||
## Acknowledgements
|
## 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:
|
Also, a thank you to the many contributors who've helped build this project:
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
|
||||||
0
code_format.sh
Normal file → Executable file
0
code_format.sh
Normal file → Executable file
@@ -21,11 +21,10 @@
|
|||||||
# THRESHOLDS
|
# THRESHOLDS
|
||||||
# QUESTS
|
# QUESTS
|
||||||
# COMBAT
|
# COMBAT
|
||||||
# GREATER BUFFS STRATEGIES
|
# PALADIN BUFFS STRATEGIES
|
||||||
# CHEATS
|
# CHEATS
|
||||||
# SPELLS
|
# SPELLS
|
||||||
# FLIGHTPATH
|
# FLIGHTPATH
|
||||||
# PROFESSIONS
|
|
||||||
# RANDOMBOT-SPECIFIC SETTINGS
|
# RANDOMBOT-SPECIFIC SETTINGS
|
||||||
# GENERAL
|
# GENERAL
|
||||||
# LEVELS
|
# LEVELS
|
||||||
@@ -37,7 +36,7 @@
|
|||||||
# RPG STRATEGY
|
# RPG STRATEGY
|
||||||
# TELEPORTS
|
# TELEPORTS
|
||||||
# BATTLEGROUND & ARENA & PVP
|
# BATTLEGROUND & ARENA & PVP
|
||||||
# RANDOM BOT TIMING AND BEHAVIOR
|
# INTERVALS
|
||||||
# PREMADE SPECS
|
# PREMADE SPECS
|
||||||
# INFORMATION
|
# INFORMATION
|
||||||
# WARRIOR
|
# WARRIOR
|
||||||
@@ -45,7 +44,7 @@
|
|||||||
# HUNTER
|
# HUNTER
|
||||||
# ROGUE
|
# ROGUE
|
||||||
# PRIEST
|
# PRIEST
|
||||||
# DEATH KNIGHT
|
# DEATHKNIGHT
|
||||||
# SHAMAN
|
# SHAMAN
|
||||||
# MAGE
|
# MAGE
|
||||||
# WARLOCK
|
# WARLOCK
|
||||||
@@ -56,7 +55,7 @@
|
|||||||
# HUNTER
|
# HUNTER
|
||||||
# ROGUE
|
# ROGUE
|
||||||
# PRIEST
|
# PRIEST
|
||||||
# DEATH KNIGHT
|
# DEATHKNIGHT
|
||||||
# SHAMAN
|
# SHAMAN
|
||||||
# MAGE
|
# MAGE
|
||||||
# WARLOCK
|
# WARLOCK
|
||||||
@@ -91,20 +90,17 @@ AiPlayerbot.MinRandomBots = 500
|
|||||||
AiPlayerbot.MaxRandomBots = 500
|
AiPlayerbot.MaxRandomBots = 500
|
||||||
|
|
||||||
# Randombot accounts
|
# Randombot accounts
|
||||||
# If you are not using any expansion at all, you may have to set this manually, in which case please
|
# If you are not using any expansion at all, you may have to set this manually, in which case please ensure that RandomBotAccountCount is at least greater than (MaxRandomBots / 10 + AddClassAccountPoolSize)
|
||||||
# ensure that RandomBotAccountCount is at least greater than (MaxRandomBots / 10 + AddClassAccountPoolSize)
|
|
||||||
# Default: 0 (automatic)
|
# Default: 0 (automatic)
|
||||||
AiPlayerbot.RandomBotAccountCount = 0
|
AiPlayerbot.RandomBotAccountCount = 0
|
||||||
|
|
||||||
# Delete all randombot accounts
|
# Delete all randombot accounts
|
||||||
# To apply this, set the number to 1 and run the Worldserver. Once deletion is complete, if you would
|
# To apply this, set the number to 1 and run the Worldserver. Once deletion is complete, if you would like to recreate randombots, set the number back to 0 and rerun the Worldserver.
|
||||||
# like to recreate randombots, set the number back to 0 and rerun the Worldserver.
|
|
||||||
AiPlayerbot.DeleteRandomBotAccounts = 0
|
AiPlayerbot.DeleteRandomBotAccounts = 0
|
||||||
|
|
||||||
# Disable randombots when no real players are logged in
|
# Disable randombots when no real players are logged in
|
||||||
# Default: 0 (randombots will login when server starts)
|
# Default: 0 (randombots will login when server starts)
|
||||||
# If enabled, randombots will only log in 30 seconds (default) after a real player logs in, and will
|
# If enabled, randombots will only log in 30 seconds (default) after a real player logs in, and will log out 300 seconds (default) after all real players log out
|
||||||
# log out 300 seconds (default) after all real players log out
|
|
||||||
AiPlayerbot.DisabledWithoutRealPlayer = 0
|
AiPlayerbot.DisabledWithoutRealPlayer = 0
|
||||||
AiPlayerbot.DisabledWithoutRealPlayerLoginDelay = 30
|
AiPlayerbot.DisabledWithoutRealPlayerLoginDelay = 30
|
||||||
AiPlayerbot.DisabledWithoutRealPlayerLogoutDelay = 300
|
AiPlayerbot.DisabledWithoutRealPlayerLogoutDelay = 300
|
||||||
@@ -156,8 +152,7 @@ AiPlayerbot.AllowGuildBots = 1
|
|||||||
AiPlayerbot.AllowTrustedAccountBots = 1
|
AiPlayerbot.AllowTrustedAccountBots = 1
|
||||||
|
|
||||||
# Randombots will create guilds with nearby randombots
|
# Randombots will create guilds with nearby randombots
|
||||||
# Note: currently, randombots will not invite more bots after a guild is created,
|
# Note: currently, randombots will not invite more bots after a guild is created (i.e., randombot guilds will have only the 10 initial randombots needed to sign the charter)
|
||||||
# meaning randombot guilds will have only the 10 initial randombots needed to sign the charter
|
|
||||||
# Default: 0 (disabled)
|
# Default: 0 (disabled)
|
||||||
AiPlayerbot.RandomBotGuildNearby = 0
|
AiPlayerbot.RandomBotGuildNearby = 0
|
||||||
|
|
||||||
@@ -191,8 +186,7 @@ AiPlayerbot.AutoInitOnly = 0
|
|||||||
# Default: 1.0 (same with the player)
|
# Default: 1.0 (same with the player)
|
||||||
AiPlayerbot.AutoInitEquipLevelLimitRatio = 1.0
|
AiPlayerbot.AutoInitEquipLevelLimitRatio = 1.0
|
||||||
|
|
||||||
# Bot automatically trains spells when talking to trainer
|
# Bot automatically trains spells when talking to trainer (yes = train all available spells as long as the bot has the money, free = auto trains with no money cost, no = only list spells)
|
||||||
# yes = train all available spells as long as the bot has the money, free = auto trains with no money cost, no = only list spells
|
|
||||||
AiPlayerbot.AutoTrainSpells = yes
|
AiPlayerbot.AutoTrainSpells = yes
|
||||||
|
|
||||||
#
|
#
|
||||||
@@ -269,7 +263,7 @@ AiPlayerbot.UseFastFlyMountAtMinLevel = 70
|
|||||||
AiPlayerbot.RandomBotShowHelmet = 1
|
AiPlayerbot.RandomBotShowHelmet = 1
|
||||||
AiPlayerbot.RandomBotShowCloak = 1
|
AiPlayerbot.RandomBotShowCloak = 1
|
||||||
|
|
||||||
# Randombots and altbots automatically equip any items in their inventory that are sufficient upgrades
|
# Randombots and altbots automatically equip upgrades (bots will equip any item obtained from looting or a quest if they are sufficient upgrades)
|
||||||
# Default: 1 (enabled)
|
# Default: 1 (enabled)
|
||||||
AiPlayerbot.AutoEquipUpgradeLoot = 1
|
AiPlayerbot.AutoEquipUpgradeLoot = 1
|
||||||
|
|
||||||
@@ -290,6 +284,9 @@ AiPlayerbot.TwoRoundsGearInit = 0
|
|||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
|
||||||
|
# Bots will say information about items when collecting them
|
||||||
|
AiPlayerbot.SayWhenCollectingItems = 1
|
||||||
|
|
||||||
# Bots keep looting when loot system is set to free for all
|
# Bots keep looting when loot system is set to free for all
|
||||||
# Default: 0 (disabled)
|
# Default: 0 (disabled)
|
||||||
AiPlayerbot.FreeMethodLoot = 0
|
AiPlayerbot.FreeMethodLoot = 0
|
||||||
@@ -317,8 +314,7 @@ AiPlayerbot.GlobalCooldown = 500
|
|||||||
# Max wait time when moving
|
# Max wait time when moving
|
||||||
AiPlayerbot.MaxWaitForMove = 5000
|
AiPlayerbot.MaxWaitForMove = 5000
|
||||||
|
|
||||||
# Enable/disable use of MoveSplinePath for bot movement
|
# Disable use of MoveSplinePath for bot movement, will result in more erratic bot movement but means stun/snare/root/etc will work on bots (they wont reliably work when MoveSplinePath is enabled, though slowing effects still work ok)
|
||||||
# Disabling will result in more erratic movement but is required for stuns, snares, and roots to work on bots
|
|
||||||
# Default: 0 - MoveSplinePath enabled
|
# Default: 0 - MoveSplinePath enabled
|
||||||
# 1 - MoveSplinePath disabled in BG/Arena only
|
# 1 - MoveSplinePath disabled in BG/Arena only
|
||||||
# 2 - MoveSplinePath disabled everywhere
|
# 2 - MoveSplinePath disabled everywhere
|
||||||
@@ -364,15 +360,15 @@ AiPlayerbot.LootDelay = 1000
|
|||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
|
||||||
# Distances are in yards
|
|
||||||
AiPlayerbot.FarDistance = 20.0
|
AiPlayerbot.FarDistance = 20.0
|
||||||
AiPlayerbot.SightDistance = 100.0
|
AiPlayerbot.SightDistance = 75.0
|
||||||
AiPlayerbot.SpellDistance = 28.5
|
AiPlayerbot.SpellDistance = 28.5
|
||||||
AiPlayerbot.ShootDistance = 5.0
|
AiPlayerbot.ShootDistance = 5.0
|
||||||
|
AiPlayerbot.ReactDistance = 150.0
|
||||||
|
AiPlayerbot.GrindDistance = 75.0
|
||||||
AiPlayerbot.HealDistance = 38.5
|
AiPlayerbot.HealDistance = 38.5
|
||||||
AiPlayerbot.LootDistance = 15.0
|
AiPlayerbot.LootDistance = 15.0
|
||||||
AiPlayerbot.FleeDistance = 5.0
|
AiPlayerbot.FleeDistance = 5.0
|
||||||
AiPlayerbot.AggroDistance = 22
|
|
||||||
AiPlayerbot.TooCloseDistance = 5.0
|
AiPlayerbot.TooCloseDistance = 5.0
|
||||||
AiPlayerbot.MeleeDistance = 0.75
|
AiPlayerbot.MeleeDistance = 0.75
|
||||||
AiPlayerbot.FollowDistance = 1.5
|
AiPlayerbot.FollowDistance = 1.5
|
||||||
@@ -380,8 +376,7 @@ AiPlayerbot.WhisperDistance = 6000.0
|
|||||||
AiPlayerbot.ContactDistance = 0.45
|
AiPlayerbot.ContactDistance = 0.45
|
||||||
AiPlayerbot.AoeRadius = 10
|
AiPlayerbot.AoeRadius = 10
|
||||||
AiPlayerbot.RpgDistance = 200
|
AiPlayerbot.RpgDistance = 200
|
||||||
AiPlayerbot.GrindDistance = 75.0
|
AiPlayerbot.AggroDistance = 22
|
||||||
AiPlayerbot.ReactDistance = 150.0
|
|
||||||
|
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
@@ -412,11 +407,10 @@ AiPlayerbot.HighMana = 65
|
|||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
|
||||||
# Bots pick their quest rewards
|
# Bots pick their quest rewards (yes = picks the most useful item, no = list all rewards, ask = pick useful item and lists if multiple)
|
||||||
# yes = picks the most useful item, no = list all rewards, ask = pick useful item and lists if multiple
|
|
||||||
AiPlayerbot.AutoPickReward = yes
|
AiPlayerbot.AutoPickReward = yes
|
||||||
|
|
||||||
# Sync quests with player (bots will complete quests the moment you hand them in and will not loot quest items.)
|
# Sync quests with player (Bots will complete quests the moment you hand them in and will not loot quest items.)
|
||||||
# Default: 1 (enabled)
|
# Default: 1 (enabled)
|
||||||
AiPlayerbot.SyncQuestWithPlayer = 1
|
AiPlayerbot.SyncQuestWithPlayer = 1
|
||||||
|
|
||||||
@@ -441,7 +435,7 @@ AiPlayerbot.DropObsoleteQuests = 1
|
|||||||
# Auto add dungeon/raid strategies when entering the instance if implemented
|
# Auto add dungeon/raid strategies when entering the instance if implemented
|
||||||
AiPlayerbot.ApplyInstanceStrategies = 1
|
AiPlayerbot.ApplyInstanceStrategies = 1
|
||||||
|
|
||||||
# Enable auto avoid aoe strategy
|
# Enable auto avoid aoe strategy (experimental)
|
||||||
# Default: 1 (enabled)
|
# Default: 1 (enabled)
|
||||||
AiPlayerbot.AutoAvoidAoe = 1
|
AiPlayerbot.AutoAvoidAoe = 1
|
||||||
|
|
||||||
@@ -468,7 +462,7 @@ AiPlayerbot.FleeingEnabled = 1
|
|||||||
####################################################################################################
|
####################################################################################################
|
||||||
|
|
||||||
####################################################################################################
|
####################################################################################################
|
||||||
# GREATER BUFFS STRATEGIES
|
# PALADIN BUFFS STRATEGIES
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
|
||||||
@@ -490,14 +484,12 @@ AiPlayerbot.RPWarningCooldown = 30
|
|||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
|
||||||
# Enable/Disable maintenance command
|
# Enable/Disable maintenance command (learn all available spells and skills, supplement consumables, repair, enchant equipment if bot's level is above AiPlayerbot.MinEnchantingBotLevel)
|
||||||
# Learn all available spells and skills, assign talent points, refresh consumables, repair, enchant equipment, socket gems, etc.
|
|
||||||
# Applies if bot's level is above AiPlayerbot.MinEnchantingBotLevel
|
|
||||||
# Default: 1 (enabled)
|
# Default: 1 (enabled)
|
||||||
AiPlayerbot.MaintenanceCommand = 1
|
AiPlayerbot.MaintenanceCommand = 1
|
||||||
|
|
||||||
# Enable/Disable specific maintenance command functionality for alt bots
|
# Enable/Disable specific maintenance command functionality for alt bots
|
||||||
# Disable to prevent players from giving free bags, spells, skill levels, etc. to their alt bots
|
# Disable to prevent players from giving free bags, spells, skill levels etc to their alt bots
|
||||||
# Default: 1 (enabled)
|
# Default: 1 (enabled)
|
||||||
AiPlayerbot.AltMaintenanceAmmo = 1
|
AiPlayerbot.AltMaintenanceAmmo = 1
|
||||||
AiPlayerbot.AltMaintenanceFood = 1
|
AiPlayerbot.AltMaintenanceFood = 1
|
||||||
@@ -509,7 +501,6 @@ AiPlayerbot.AltMaintenanceBags = 1
|
|||||||
AiPlayerbot.AltMaintenanceMounts = 1
|
AiPlayerbot.AltMaintenanceMounts = 1
|
||||||
AiPlayerbot.AltMaintenanceSkills = 1
|
AiPlayerbot.AltMaintenanceSkills = 1
|
||||||
|
|
||||||
# "Special Spells" consist of any spells listed in AiPlayerbot.RandomBotSpellIds and Death Gate for Death Knights
|
|
||||||
AiPlayerbot.AltMaintenanceClassSpells = 1
|
AiPlayerbot.AltMaintenanceClassSpells = 1
|
||||||
AiPlayerbot.AltMaintenanceAvailableSpells = 1
|
AiPlayerbot.AltMaintenanceAvailableSpells = 1
|
||||||
AiPlayerbot.AltMaintenanceSpecialSpells = 1
|
AiPlayerbot.AltMaintenanceSpecialSpells = 1
|
||||||
@@ -524,8 +515,8 @@ AiPlayerbot.AltMaintenanceReputation = 1
|
|||||||
AiPlayerbot.AltMaintenanceAttunementQuests = 1
|
AiPlayerbot.AltMaintenanceAttunementQuests = 1
|
||||||
AiPlayerbot.AltMaintenanceKeyring = 1
|
AiPlayerbot.AltMaintenanceKeyring = 1
|
||||||
|
|
||||||
# Enable/Disable autogear command, which automatically upgrades bots' gear
|
|
||||||
# The quality is limited by AutoGearQualityLimit and AutoGearScoreLimit
|
# Enable/Disable autogear command, which automatically upgrades bots' gear; the quality is limited by AutoGearQualityLimit and AutoGearScoreLimit
|
||||||
# Default: 1 (enabled)
|
# Default: 1 (enabled)
|
||||||
AiPlayerbot.AutoGearCommand = 1
|
AiPlayerbot.AutoGearCommand = 1
|
||||||
|
|
||||||
@@ -557,7 +548,7 @@ AiPlayerbot.AutoGearScoreLimit = 0
|
|||||||
# "mana" (bots have infinite mana)
|
# "mana" (bots have infinite mana)
|
||||||
# "power" (bots have infinite energy, rage, and runic power)
|
# "power" (bots have infinite energy, rage, and runic power)
|
||||||
# "taxi" (bots may use all flight paths, though they will not actually learn them)
|
# "taxi" (bots may use all flight paths, though they will not actually learn them)
|
||||||
# "raid" (bots use cheats implemented into raid strategies (currently only for Ulduar))
|
# "raid" (bots use cheats implemented into raid strategies)
|
||||||
# To use multiple cheats, separate them by commas below (e.g., to enable all, use "gold,health,mana,power,raid,taxi")
|
# To use multiple cheats, separate them by commas below (e.g., to enable all, use "gold,health,mana,power,raid,taxi")
|
||||||
# Default: food, taxi, and raid are enabled
|
# Default: food, taxi, and raid are enabled
|
||||||
AiPlayerbot.BotCheats = "food,taxi,raid"
|
AiPlayerbot.BotCheats = "food,taxi,raid"
|
||||||
@@ -589,30 +580,6 @@ AiPlayerbot.BotTaxiGapJitterMs = 100
|
|||||||
#
|
#
|
||||||
####################################################################################################
|
####################################################################################################
|
||||||
|
|
||||||
####################################################################################################
|
|
||||||
# PROFESSIONS
|
|
||||||
# Note: Random bots currently do not get professions
|
|
||||||
#
|
|
||||||
|
|
||||||
# Automatically adds the 'master fishing' strategy to bots that have the fishing skill when the bots master fishes.
|
|
||||||
# Default: 1 (Enabled)
|
|
||||||
AiPlayerbot.EnableFishingWithMaster = 1
|
|
||||||
|
|
||||||
# Distance from itself (in yards) that a bot with a master will search for water to fish
|
|
||||||
AiPlayerbot.FishingDistanceFromMaster = 10.0
|
|
||||||
|
|
||||||
# Distance from itself (in yards) that a bot without a master will search for water to fish
|
|
||||||
# Currently not relevant since masterless bots will not fish
|
|
||||||
AiPlayerbot.FishingDistance = 40.0
|
|
||||||
|
|
||||||
# Distance from water (in yards) beyond which a bot will remove the 'master fishing' strategy
|
|
||||||
AiPlayerbot.EndFishingWithMaster = 30.0
|
|
||||||
|
|
||||||
#
|
|
||||||
#
|
|
||||||
#
|
|
||||||
####################################################################################################
|
|
||||||
|
|
||||||
#######################################
|
#######################################
|
||||||
# #
|
# #
|
||||||
# RANDOMBOT-SPECIFIC SETTINGS #
|
# RANDOMBOT-SPECIFIC SETTINGS #
|
||||||
@@ -639,11 +606,9 @@ AiPlayerbot.RandomBotMaxLevel = 80
|
|||||||
AiPlayerbot.SyncLevelWithPlayers = 0
|
AiPlayerbot.SyncLevelWithPlayers = 0
|
||||||
|
|
||||||
# Mark many quests ≤ bot level as complete (slows down bot creation)
|
# Mark many quests ≤ bot level as complete (slows down bot creation)
|
||||||
# Default: 0 (disabled)
|
|
||||||
AiPlayerbot.PreQuests = 0
|
AiPlayerbot.PreQuests = 0
|
||||||
|
|
||||||
# Enable LFG for randombots
|
# Enable LFG for randombots
|
||||||
# Default: 1 (enabled)
|
|
||||||
AiPlayerbot.RandomBotJoinLfg = 1
|
AiPlayerbot.RandomBotJoinLfg = 1
|
||||||
|
|
||||||
# Enable/Disable periodic online - offline of randombots to mimic the real-world scenario where not all players are online simultaneously
|
# Enable/Disable periodic online - offline of randombots to mimic the real-world scenario where not all players are online simultaneously
|
||||||
@@ -664,8 +629,7 @@ AiPlayerbot.RandomBotHordeRatio = 50
|
|||||||
AiPlayerbot.DisableDeathKnightLogin = 0
|
AiPlayerbot.DisableDeathKnightLogin = 0
|
||||||
|
|
||||||
# Enable simulated expansion limitation for talents and glyphs
|
# Enable simulated expansion limitation for talents and glyphs
|
||||||
# If enabled, limits talent trees to 5 rows plus the middle talent of the 6th row for bots until level 61
|
# If enabled, limits talent trees to 5 rows plus the middle talent of the 6th row for bots until level 61 and 7 rows plus the middle talent of the 8th row for bots until level 71
|
||||||
# and 7 rows plus the middle talent of the 8th row for bots from level 61 until level 71
|
|
||||||
# Default: 0 (disabled)
|
# Default: 0 (disabled)
|
||||||
AiPlayerbot.LimitTalentsExpansion = 0
|
AiPlayerbot.LimitTalentsExpansion = 0
|
||||||
|
|
||||||
@@ -734,7 +698,7 @@ AiPlayerbot.RandomGearQualityLimit = 3
|
|||||||
# Max iLVL Phase 1(MC, Ony, ZG) = 78 | Phase 2(BWL) = 83 | Phase 2.5(AQ40) = 88 | Phase 3(Naxx40) = 92
|
# Max iLVL Phase 1(MC, Ony, ZG) = 78 | Phase 2(BWL) = 83 | Phase 2.5(AQ40) = 88 | Phase 3(Naxx40) = 92
|
||||||
# TBC
|
# TBC
|
||||||
# Max iLVL Tier 4 = 120 | Tier 5 = 133 | Tier 6 = 164
|
# Max iLVL Tier 4 = 120 | Tier 5 = 133 | Tier 6 = 164
|
||||||
# Max iLVL Phase 1(Kara, Gruul, Mag) = 125 | Phase 2(SSC, TK, ZA) = 141 | Phase 3(Hyjal, BT) = 156 | Phase 4(Sunwell) = 164
|
# Max iLVL Phase 1(Kara, Gruul, Mag) = 125 | Phase 1.5(ZA) = 138 | Phase 2(SC, TK) = 141 | Phase 3(Hyjal, BT) = 156 | Phase 4(Sunwell) = 164
|
||||||
# Wotlk
|
# Wotlk
|
||||||
# Max iLVL Tier 7(10/25) = 200/213 | Tier 8(10/25) = 225/232 | Tier 9(10/25) = 232/245 | Tier 10(10/25/HC) = 251/264/290
|
# Max iLVL Tier 7(10/25) = 200/213 | Tier 8(10/25) = 225/232 | Tier 9(10/25) = 232/245 | Tier 10(10/25/HC) = 251/264/290
|
||||||
# Max iLVL Phase 1(Naxx) = 224 | Phase 2(Ulduar) = 245 | Phase 3(ToC) = 258 | Phase 4(ICC) = 290
|
# Max iLVL Phase 1(Naxx) = 224 | Phase 2(Ulduar) = 245 | Phase 3(ToC) = 258 | Phase 4(ICC) = 290
|
||||||
@@ -745,13 +709,12 @@ AiPlayerbot.RandomGearScoreLimit = 0
|
|||||||
# Default: 1 (enabled)
|
# Default: 1 (enabled)
|
||||||
AiPlayerbot.IncrementalGearInit = 1
|
AiPlayerbot.IncrementalGearInit = 1
|
||||||
|
|
||||||
# Set minimum level of bots that will enchant and socket gems into their equipment with maintenance
|
# Set minimum level of bots that will enchant their equipment (if greater than RandomBotMaxlevel, bots will not enchant equipment)
|
||||||
# If greater than RandomBotMaxlevel, bots will not automatically enchant equipment or socket gems
|
|
||||||
# Default: 60
|
# Default: 60
|
||||||
AiPlayerbot.MinEnchantingBotLevel = 60
|
AiPlayerbot.MinEnchantingBotLevel = 60
|
||||||
|
|
||||||
# Enable expansion limitation for bot enchants and gems
|
# Enable expansion limitation for bot enchants
|
||||||
# If enabled, bots will not use TBC enchants until level 61 or WotLK enchants and gems until level 71
|
# If enabled, bots will not use TBC enchants until level 61 or WotLK enchants until level 71
|
||||||
# Default: 1 (enabled)
|
# Default: 1 (enabled)
|
||||||
AiPlayerbot.LimitEnchantExpansion = 1
|
AiPlayerbot.LimitEnchantExpansion = 1
|
||||||
|
|
||||||
@@ -847,7 +810,7 @@ AiPlayerbot.botActiveAloneSmartScaleWhenMaxLevel = 80
|
|||||||
#
|
#
|
||||||
|
|
||||||
# Quest that will be completed and rewarded for all randombots
|
# Quest that will be completed and rewarded for all randombots
|
||||||
AiPlayerbot.RandomBotQuestIds = "3802,5505,6502,7761,7848,10277,10285,11492,13188,13189,24499,24511,24710,24712"
|
AiPlayerbot.RandomBotQuestIds = "7848,3802,5505,6502,7761,10277,10285,11492,13188,13189,24499,24511,24710,24712"
|
||||||
|
|
||||||
# Randombots will group with nearby randombots to do shared quests
|
# Randombots will group with nearby randombots to do shared quests
|
||||||
AiPlayerbot.RandomBotGroupNearby = 0
|
AiPlayerbot.RandomBotGroupNearby = 0
|
||||||
@@ -898,21 +861,19 @@ AiPlayerbot.OpenGoSpell = 6477
|
|||||||
#
|
#
|
||||||
|
|
||||||
# Additional randombot strategies
|
# Additional randombot strategies
|
||||||
# Strategies added here are applied to all randombots, in addition (or subtraction) to spec/role-based default strategies.
|
# Strategies added here are applied to all randombots, in addition (or subtraction) to spec/role-based default strategies. These rules are processed after the defaults.
|
||||||
# These rules are processed after the defaults.
|
|
||||||
# Example: "+threat,-potions"
|
# Example: "+threat,-potions"
|
||||||
AiPlayerbot.RandomBotCombatStrategies = ""
|
AiPlayerbot.RandomBotCombatStrategies = ""
|
||||||
AiPlayerbot.RandomBotNonCombatStrategies = ""
|
AiPlayerbot.RandomBotNonCombatStrategies = ""
|
||||||
|
|
||||||
# Additional altbot strategies
|
# Additional altbot strategies
|
||||||
# Strategies added here are applied to all altbots, in addition (or subtraction) to spec/role-based default strategies.
|
# Strategies added here are applied to all altbots, in addition (or subtraction) to spec/role-based default strategies. These rules are processed after the defaults.
|
||||||
# These rules are processed after the defaults.
|
|
||||||
AiPlayerbot.CombatStrategies = ""
|
AiPlayerbot.CombatStrategies = ""
|
||||||
AiPlayerbot.NonCombatStrategies = ""
|
AiPlayerbot.NonCombatStrategies = ""
|
||||||
|
|
||||||
# Remove "healer dps" strategy on the maps specified below.
|
# Remove "healer dps" strategy on specified maps.
|
||||||
# Default: 1 (enabled)
|
# Default: 0 (disabled)
|
||||||
AiPlayerbot.HealerDPSMapRestriction = 1
|
AiPlayerbot.HealerDPSMapRestriction = 0
|
||||||
|
|
||||||
# List of Map IDs where "healer dps" strategy will be removed if AiPlayerbot.HealerDPSMapRestriction is enabled
|
# List of Map IDs where "healer dps" strategy will be removed if AiPlayerbot.HealerDPSMapRestriction is enabled
|
||||||
# Default: (Dungeon and Raid maps) "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"
|
# Default: (Dungeon and Raid maps) "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"
|
||||||
@@ -1096,8 +1057,7 @@ AiPlayerbot.ZoneBracket.4197 = 79,80
|
|||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
|
||||||
# Map IDs where bots can be teleported to
|
# Maps where bots can be teleported to
|
||||||
# Defaults: 0 = Eastern Kingdoms, 1 = Kalimdor, 530 = Outland, 571 = Northrend
|
|
||||||
AiPlayerbot.RandomBotMaps = 0,1,530,571
|
AiPlayerbot.RandomBotMaps = 0,1,530,571
|
||||||
|
|
||||||
# Probabilty bots teleport to banker (city)
|
# Probabilty bots teleport to banker (city)
|
||||||
@@ -1222,7 +1182,7 @@ AiPlayerbot.DeleteRandomBotArenaTeams = 0
|
|||||||
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"
|
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"
|
||||||
|
|
||||||
# PvP Restricted Areas (bots don't pvp)
|
# PvP Restricted Areas (bots don't pvp)
|
||||||
AiPlayerbot.PvpProhibitedAreaIds = "976,35,392,2268,4161,4010,4317,4312,3649,3887,3958,3724,4080,3938,3754,3786,3973"
|
AiPlayerbot.PvpProhibitedAreaIds = "976,35,392,2268,4161,4010,4317,4312,3649,3887,3958,3724,4080,3938,3754"
|
||||||
|
|
||||||
# Improve reaction speeds in battlegrounds and arenas (may cause lag)
|
# Improve reaction speeds in battlegrounds and arenas (may cause lag)
|
||||||
AiPlayerbot.FastReactInBG = 1
|
AiPlayerbot.FastReactInBG = 1
|
||||||
@@ -1233,46 +1193,24 @@ AiPlayerbot.FastReactInBG = 1
|
|||||||
####################################################################################################
|
####################################################################################################
|
||||||
|
|
||||||
####################################################################################################
|
####################################################################################################
|
||||||
# RANDOM BOT TIMING AND BEHAVIOR
|
# INTERVALS
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
|
||||||
# How often (in seconds) the random bot manager runs its main update loop
|
# All in seconds
|
||||||
# Default: 20
|
|
||||||
AiPlayerbot.RandomBotUpdateInterval = 20
|
AiPlayerbot.RandomBotUpdateInterval = 20
|
||||||
|
|
||||||
# Minimum and maximum seconds before the manager re-evaluates and adjusts total random bot count
|
|
||||||
# Defaults: 1800 (min), 7200 (max)
|
|
||||||
AiPlayerbot.RandomBotCountChangeMinInterval = 1800
|
AiPlayerbot.RandomBotCountChangeMinInterval = 1800
|
||||||
AiPlayerbot.RandomBotCountChangeMaxInterval = 7200
|
AiPlayerbot.RandomBotCountChangeMaxInterval = 7200
|
||||||
|
|
||||||
# Minimum and maximum seconds a random bot will stay online before logging out
|
|
||||||
# Defaults: 600 (min), 28800 (max)
|
|
||||||
AiPlayerbot.MinRandomBotInWorldTime = 600
|
AiPlayerbot.MinRandomBotInWorldTime = 600
|
||||||
AiPlayerbot.MaxRandomBotInWorldTime = 28800
|
AiPlayerbot.MaxRandomBotInWorldTime = 28800
|
||||||
|
|
||||||
# Minimum and maximum seconds before a bot is eligible for re-randomization (gear, class, talents, etc.)
|
|
||||||
# Defaults: 7200 (min), 1209600 (max)
|
|
||||||
AiPlayerbot.MinRandomBotRandomizeTime = 7200
|
AiPlayerbot.MinRandomBotRandomizeTime = 7200
|
||||||
AiPlayerbot.MaxRandomBotRandomizeTime = 1209600
|
AiPlayerbot.MaxRandomBotRandomizeTime = 1209600
|
||||||
|
|
||||||
# Number of bots processed (login, logout, update) per manager update cycle
|
|
||||||
# Default: 60
|
|
||||||
AiPlayerbot.RandomBotsPerInterval = 60
|
AiPlayerbot.RandomBotsPerInterval = 60
|
||||||
|
|
||||||
# Minimum and maximum seconds after death before a bot revives
|
|
||||||
# Defaults: 60 (min), 300 (max)
|
|
||||||
AiPlayerbot.MinRandomBotReviveTime = 60
|
AiPlayerbot.MinRandomBotReviveTime = 60
|
||||||
AiPlayerbot.MaxRandomBotReviveTime = 300
|
AiPlayerbot.MaxRandomBotReviveTime = 300
|
||||||
|
|
||||||
# Minimum and maximum seconds between bot teleports to new areas or zones
|
|
||||||
# Defaults: 3600 (min), 18000 (max)
|
|
||||||
AiPlayerbot.MinRandomBotTeleportInterval = 3600
|
AiPlayerbot.MinRandomBotTeleportInterval = 3600
|
||||||
AiPlayerbot.MaxRandomBotTeleportInterval = 18000
|
AiPlayerbot.MaxRandomBotTeleportInterval = 18000
|
||||||
|
AiPlayerbot.PermanantlyInWorldTime = 31104000
|
||||||
# Number of seconds bots flagged as permanent stay in the world (31,104,000 ≈ 1 year)
|
|
||||||
# Default: 31104000
|
|
||||||
AiPlayerbot.PermanentlyInWorldTime = 31104000
|
|
||||||
|
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
@@ -1492,7 +1430,7 @@ AiPlayerbot.PremadeSpecLink.5.5.80 = 50332031003--005323241223112003102311351
|
|||||||
####################################################################################################
|
####################################################################################################
|
||||||
|
|
||||||
####################################################################################################
|
####################################################################################################
|
||||||
# DEATH KNIGHT
|
# DEATHKNIGHT
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
|
||||||
@@ -1815,7 +1753,7 @@ AiPlayerbot.RandomClassSpecIndex.5.2 = 2
|
|||||||
####################################################################################################
|
####################################################################################################
|
||||||
|
|
||||||
####################################################################################################
|
####################################################################################################
|
||||||
# DEATH KNIGHT
|
# DEATHKNIGHT
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -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);
|
|
||||||
@@ -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 n’ai 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);
|
|
||||||
@@ -140,37 +140,37 @@ BotRoles AiFactory::GetPlayerRoles(Player* player)
|
|||||||
switch (player->getClass())
|
switch (player->getClass())
|
||||||
{
|
{
|
||||||
case CLASS_PRIEST:
|
case CLASS_PRIEST:
|
||||||
if (tab == PRIEST_TAB_SHADOW)
|
if (tab == 2)
|
||||||
role = BOT_ROLE_DPS;
|
role = BOT_ROLE_DPS;
|
||||||
else
|
else
|
||||||
role = BOT_ROLE_HEALER;
|
role = BOT_ROLE_HEALER;
|
||||||
break;
|
break;
|
||||||
case CLASS_SHAMAN:
|
case CLASS_SHAMAN:
|
||||||
if (tab == SHAMAN_TAB_RESTORATION)
|
if (tab == 2)
|
||||||
role = BOT_ROLE_HEALER;
|
role = BOT_ROLE_HEALER;
|
||||||
else
|
else
|
||||||
role = BOT_ROLE_DPS;
|
role = BOT_ROLE_DPS;
|
||||||
break;
|
break;
|
||||||
case CLASS_WARRIOR:
|
case CLASS_WARRIOR:
|
||||||
if (tab == WARRIOR_TAB_PROTECTION)
|
if (tab == 2)
|
||||||
role = BOT_ROLE_TANK;
|
role = BOT_ROLE_TANK;
|
||||||
else
|
else
|
||||||
role = BOT_ROLE_DPS;
|
role = BOT_ROLE_DPS;
|
||||||
break;
|
break;
|
||||||
case CLASS_PALADIN:
|
case CLASS_PALADIN:
|
||||||
if (tab == PALADIN_TAB_HOLY)
|
if (tab == 0)
|
||||||
role = BOT_ROLE_HEALER;
|
role = BOT_ROLE_HEALER;
|
||||||
else if (tab == PALADIN_TAB_PROTECTION)
|
else if (tab == 1)
|
||||||
role = BOT_ROLE_TANK;
|
role = BOT_ROLE_TANK;
|
||||||
else if (tab == PALADIN_TAB_RETRIBUTION)
|
else if (tab == 2)
|
||||||
role = BOT_ROLE_DPS;
|
role = BOT_ROLE_DPS;
|
||||||
break;
|
break;
|
||||||
case CLASS_DRUID:
|
case CLASS_DRUID:
|
||||||
if (tab == DRUID_TAB_BALANCE)
|
if (tab == 0)
|
||||||
role = BOT_ROLE_DPS;
|
role = BOT_ROLE_DPS;
|
||||||
else if (tab == DRUID_TAB_FERAL)
|
else if (tab == 1)
|
||||||
role = (BotRoles)(BOT_ROLE_TANK | BOT_ROLE_DPS);
|
role = (BotRoles)(BOT_ROLE_TANK | BOT_ROLE_DPS);
|
||||||
else if (tab == DRUID_TAB_RESTORATION)
|
else if (tab == 2)
|
||||||
role = BOT_ROLE_HEALER;
|
role = BOT_ROLE_HEALER;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -188,83 +188,84 @@ std::string AiFactory::GetPlayerSpecName(Player* player)
|
|||||||
switch (player->getClass())
|
switch (player->getClass())
|
||||||
{
|
{
|
||||||
case CLASS_PRIEST:
|
case CLASS_PRIEST:
|
||||||
if (tab == PRIEST_TAB_SHADOW)
|
if (tab == 2)
|
||||||
specName = "shadow";
|
specName = "shadow";
|
||||||
else if (tab == PRIEST_TAB_HOLY)
|
else if (tab == 1)
|
||||||
specName = "holy";
|
specName = "holy";
|
||||||
else
|
else
|
||||||
specName = "disc";
|
specName = "disc";
|
||||||
|
;
|
||||||
break;
|
break;
|
||||||
case CLASS_SHAMAN:
|
case CLASS_SHAMAN:
|
||||||
if (tab == SHAMAN_TAB_RESTORATION)
|
if (tab == 2)
|
||||||
specName = "resto";
|
specName = "resto";
|
||||||
else if (tab == SHAMAN_TAB_ENHANCEMENT)
|
else if (tab == 1)
|
||||||
specName = "enhance";
|
specName = "enhance";
|
||||||
else
|
else
|
||||||
specName = "elem";
|
specName = "elem";
|
||||||
break;
|
break;
|
||||||
case CLASS_WARRIOR:
|
case CLASS_WARRIOR:
|
||||||
if (tab == WARRIOR_TAB_PROTECTION)
|
if (tab == 2)
|
||||||
specName = "prot";
|
specName = "prot";
|
||||||
else if (tab == WARRIOR_TAB_FURY)
|
else if (tab == 1)
|
||||||
specName = "fury";
|
specName = "fury";
|
||||||
else
|
else
|
||||||
specName = "arms";
|
specName = "arms";
|
||||||
break;
|
break;
|
||||||
case CLASS_PALADIN:
|
case CLASS_PALADIN:
|
||||||
if (tab == PALADIN_TAB_HOLY)
|
if (tab == 0)
|
||||||
specName = "holy";
|
specName = "holy";
|
||||||
else if (tab == PALADIN_TAB_PROTECTION)
|
else if (tab == 1)
|
||||||
specName = "prot";
|
specName = "prot";
|
||||||
else if (tab == PALADIN_TAB_RETRIBUTION)
|
else if (tab == 2)
|
||||||
specName = "retrib";
|
specName = "retrib";
|
||||||
break;
|
break;
|
||||||
case CLASS_DRUID:
|
case CLASS_DRUID:
|
||||||
if (tab == DRUID_TAB_BALANCE)
|
if (tab == 0)
|
||||||
specName = "balance";
|
specName = "balance";
|
||||||
else if (tab == DRUID_TAB_FERAL)
|
else if (tab == 1)
|
||||||
specName = "feraldps";
|
specName = "feraldps";
|
||||||
else if (tab == DRUID_TAB_RESTORATION)
|
else if (tab == 2)
|
||||||
specName = "resto";
|
specName = "resto";
|
||||||
break;
|
break;
|
||||||
case CLASS_ROGUE:
|
case CLASS_ROGUE:
|
||||||
if (tab == ROGUE_TAB_ASSASSINATION)
|
if (tab == 0)
|
||||||
specName = "assas";
|
specName = "assas";
|
||||||
else if (tab == ROGUE_TAB_COMBAT)
|
else if (tab == 1)
|
||||||
specName = "combat";
|
specName = "combat";
|
||||||
else if (tab == ROGUE_TAB_SUBTLETY)
|
else if (tab == 2)
|
||||||
specName = "subtle";
|
specName = "subtle";
|
||||||
break;
|
break;
|
||||||
case CLASS_HUNTER:
|
case CLASS_HUNTER:
|
||||||
if (tab == HUNTER_TAB_BEAST_MASTERY)
|
if (tab == 0)
|
||||||
specName = "beast";
|
specName = "beast";
|
||||||
else if (tab == HUNTER_TAB_MARKSMANSHIP)
|
else if (tab == 1)
|
||||||
specName = "marks";
|
specName = "marks";
|
||||||
else if (tab == HUNTER_TAB_SURVIVAL)
|
else if (tab == 2)
|
||||||
specName = "surv";
|
specName = "surv";
|
||||||
break;
|
break;
|
||||||
case CLASS_DEATH_KNIGHT:
|
case CLASS_DEATH_KNIGHT:
|
||||||
if (tab == DEATH_KNIGHT_TAB_BLOOD)
|
if (tab == 0)
|
||||||
specName = "blooddps";
|
specName = "blooddps";
|
||||||
else if (tab == DEATH_KNIGHT_TAB_FROST)
|
else if (tab == 1)
|
||||||
specName = "frostdps";
|
specName = "frostdps";
|
||||||
else if (tab == DEATH_KNIGHT_TAB_UNHOLY)
|
else if (tab == 2)
|
||||||
specName = "unholydps";
|
specName = "unholydps";
|
||||||
break;
|
break;
|
||||||
case CLASS_MAGE:
|
case CLASS_MAGE:
|
||||||
if (tab == MAGE_TAB_ARCANE)
|
if (tab == 0)
|
||||||
specName = "arcane";
|
specName = "arcane";
|
||||||
else if (tab == MAGE_TAB_FIRE)
|
else if (tab == 1)
|
||||||
specName = "fire";
|
specName = "fire";
|
||||||
else if (tab == MAGE_TAB_FROST)
|
else if (tab == 2)
|
||||||
specName = "frost";
|
specName = "frost";
|
||||||
break;
|
break;
|
||||||
case CLASS_WARLOCK:
|
case CLASS_WARLOCK:
|
||||||
if (tab == WARLOCK_TAB_AFFLICTION)
|
if (tab == 0)
|
||||||
specName = "afflic";
|
specName = "afflic";
|
||||||
else if (tab == WARLOCK_TAB_DEMONOLOGY)
|
else if (tab == 1)
|
||||||
specName = "demo";
|
specName = "demo";
|
||||||
else if (tab == WARLOCK_TAB_DESTRUCTION)
|
else if (tab == 2)
|
||||||
specName = "destro";
|
specName = "destro";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -279,124 +280,145 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa
|
|||||||
uint8 tab = GetPlayerSpecTab(player);
|
uint8 tab = GetPlayerSpecTab(player);
|
||||||
|
|
||||||
if (!player->InBattleground())
|
if (!player->InBattleground())
|
||||||
|
{
|
||||||
engine->addStrategiesNoInit("racials", "chat", "default", "cast time", "potions", "duel", "boost", nullptr);
|
engine->addStrategiesNoInit("racials", "chat", "default", "cast time", "potions", "duel", "boost", nullptr);
|
||||||
|
}
|
||||||
if (sPlayerbotAIConfig->autoAvoidAoe && facade->HasRealPlayerMaster())
|
if (sPlayerbotAIConfig->autoAvoidAoe && facade->HasRealPlayerMaster())
|
||||||
|
{
|
||||||
engine->addStrategy("avoid aoe", false);
|
engine->addStrategy("avoid aoe", false);
|
||||||
|
}
|
||||||
engine->addStrategy("formation", false);
|
engine->addStrategy("formation", false);
|
||||||
|
|
||||||
switch (player->getClass())
|
switch (player->getClass())
|
||||||
{
|
{
|
||||||
case CLASS_PRIEST:
|
case CLASS_PRIEST:
|
||||||
if (tab == PRIEST_TAB_SHADOW)
|
if (tab == 2)
|
||||||
|
{
|
||||||
engine->addStrategiesNoInit("dps", "shadow debuff", "shadow aoe", nullptr);
|
engine->addStrategiesNoInit("dps", "shadow debuff", "shadow aoe", nullptr);
|
||||||
|
}
|
||||||
else if (tab == PRIEST_TAB_DISCIPLINE)
|
else if (tab == PRIEST_TAB_DISCIPLINE)
|
||||||
|
{
|
||||||
engine->addStrategiesNoInit("heal", nullptr);
|
engine->addStrategiesNoInit("heal", nullptr);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
engine->addStrategiesNoInit("holy heal", nullptr);
|
engine->addStrategiesNoInit("holy heal", nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
engine->addStrategiesNoInit("dps assist", "cure", nullptr);
|
engine->addStrategiesNoInit("dps assist", "cure", nullptr);
|
||||||
break;
|
break;
|
||||||
case CLASS_MAGE:
|
case CLASS_MAGE:
|
||||||
if (tab == MAGE_TAB_ARCANE)
|
if (tab == 0) // Arcane
|
||||||
engine->addStrategiesNoInit("arcane", nullptr);
|
engine->addStrategiesNoInit("arcane", nullptr);
|
||||||
else if (tab == MAGE_TAB_FIRE)
|
else if (tab == 1) // Fire
|
||||||
{
|
{
|
||||||
if (player->HasSpell(44614) /*Frostfire Bolt*/ && player->HasAura(15047) /*Ice Shards*/)
|
if (player->HasSpell(44614) /*Frostfire Bolt*/ && player->HasAura(15047) /*Ice Shards*/)
|
||||||
|
{
|
||||||
engine->addStrategiesNoInit("frostfire", nullptr);
|
engine->addStrategiesNoInit("frostfire", nullptr);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
engine->addStrategiesNoInit("fire", nullptr);
|
engine->addStrategiesNoInit("fire", nullptr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else // Frost
|
||||||
engine->addStrategiesNoInit("frost", nullptr);
|
engine->addStrategiesNoInit("frost", nullptr);
|
||||||
|
|
||||||
engine->addStrategiesNoInit("dps", "dps assist", "cure", "aoe", nullptr);
|
engine->addStrategiesNoInit("dps", "dps assist", "cure", "aoe", nullptr);
|
||||||
break;
|
break;
|
||||||
case CLASS_WARRIOR:
|
case CLASS_WARRIOR:
|
||||||
if (tab == WARRIOR_TAB_PROTECTION)
|
if (tab == 2)
|
||||||
engine->addStrategiesNoInit("tank", "tank assist", "aoe", nullptr);
|
engine->addStrategiesNoInit("tank", "tank assist", "aoe", nullptr);
|
||||||
else if (tab == WARRIOR_TAB_ARMS || !player->HasSpell(1680)) // Whirlwind
|
else if (tab == 0 || !player->HasSpell(1680)) // Whirlwind
|
||||||
engine->addStrategiesNoInit("arms", "aoe", "dps assist", nullptr);
|
engine->addStrategiesNoInit("arms", "aoe", "dps assist", /*"behind",*/ nullptr);
|
||||||
else
|
else
|
||||||
engine->addStrategiesNoInit("fury", "aoe", "dps assist", nullptr);
|
engine->addStrategiesNoInit("fury", "aoe", "dps assist", /*"behind",*/ nullptr);
|
||||||
break;
|
break;
|
||||||
case CLASS_SHAMAN:
|
case CLASS_SHAMAN:
|
||||||
if (tab == SHAMAN_TAB_ELEMENTAL)
|
if (tab == 0) // Elemental
|
||||||
engine->addStrategiesNoInit("ele", "stoneskin", "wrath", "mana spring", "wrath of air", nullptr);
|
engine->addStrategiesNoInit("ele", "stoneskin", "wrath", "mana spring", "wrath of air", nullptr);
|
||||||
else if (tab == SHAMAN_TAB_RESTORATION)
|
else if (tab == 2) // Restoration
|
||||||
engine->addStrategiesNoInit("resto", "stoneskin", "flametongue", "mana spring", "wrath of air", nullptr);
|
engine->addStrategiesNoInit("resto", "stoneskin", "flametongue", "mana spring", "wrath of air", nullptr);
|
||||||
else
|
else // Enhancement
|
||||||
engine->addStrategiesNoInit("enh", "strength of earth", "magma", "healing stream", "windfury", nullptr);
|
engine->addStrategiesNoInit("enh", "strength of earth", "magma", "healing stream", "windfury", nullptr);
|
||||||
|
|
||||||
engine->addStrategiesNoInit("dps assist", "cure", "aoe", nullptr);
|
engine->addStrategiesNoInit("dps assist", "cure", "aoe", nullptr);
|
||||||
break;
|
break;
|
||||||
case CLASS_PALADIN:
|
case CLASS_PALADIN:
|
||||||
if (tab == PALADIN_TAB_PROTECTION)
|
if (tab == 1)
|
||||||
engine->addStrategiesNoInit("tank", "tank assist", "bthreat", "barmor", "cure", nullptr);
|
engine->addStrategiesNoInit("tank", "tank assist", "bthreat", "barmor", "cure", nullptr);
|
||||||
else if (tab == PALADIN_TAB_HOLY)
|
else if (tab == 0)
|
||||||
engine->addStrategiesNoInit("heal", "dps assist", "cure", "bcast", nullptr);
|
engine->addStrategiesNoInit("heal", "dps assist", "cure", "bcast", nullptr);
|
||||||
else
|
else
|
||||||
engine->addStrategiesNoInit("dps", "dps assist", "cure", "baoe", nullptr);
|
engine->addStrategiesNoInit("dps", "dps assist", "cure", "baoe", nullptr);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case CLASS_DRUID:
|
case CLASS_DRUID:
|
||||||
if (tab == DRUID_TAB_BALANCE)
|
if (tab == 0)
|
||||||
{
|
{
|
||||||
engine->addStrategiesNoInit("caster", "cure", "caster aoe", "dps assist", nullptr);
|
engine->addStrategiesNoInit("caster", "cure", "caster aoe", "dps assist", nullptr);
|
||||||
engine->addStrategy("caster debuff", false);
|
engine->addStrategy("caster debuff", false);
|
||||||
}
|
}
|
||||||
else if (tab == DRUID_TAB_RESTORATION)
|
else if (tab == 2)
|
||||||
engine->addStrategiesNoInit("heal", "cure", "dps assist", nullptr);
|
engine->addStrategiesNoInit("heal", "cure", "dps assist", nullptr);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (player->HasSpell(768) /*cat form*/ && !player->HasAura(16931) /*thick hide*/)
|
if (player->HasSpell(768) /*cat form*/&& !player->HasAura(16931) /*thick hide*/)
|
||||||
|
{
|
||||||
engine->addStrategiesNoInit("cat", "dps assist", nullptr);
|
engine->addStrategiesNoInit("cat", "dps assist", nullptr);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
engine->addStrategiesNoInit("bear", "tank assist", nullptr);
|
engine->addStrategiesNoInit("bear", "tank assist", nullptr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CLASS_HUNTER:
|
case CLASS_HUNTER:
|
||||||
if (tab == HUNTER_TAB_BEAST_MASTERY)
|
if (tab == 0) // Beast Mastery
|
||||||
engine->addStrategiesNoInit("bm", nullptr);
|
engine->addStrategiesNoInit("bm", nullptr);
|
||||||
else if (tab == HUNTER_TAB_MARKSMANSHIP)
|
else if (tab == 1) // Marksmanship
|
||||||
engine->addStrategiesNoInit("mm", nullptr);
|
engine->addStrategiesNoInit("mm", nullptr);
|
||||||
else
|
else if (tab == 2) // Survival
|
||||||
engine->addStrategiesNoInit("surv", nullptr);
|
engine->addStrategiesNoInit("surv", nullptr);
|
||||||
|
|
||||||
engine->addStrategiesNoInit("cc", "dps assist", "aoe", nullptr);
|
engine->addStrategiesNoInit("cc", "dps assist", "aoe", nullptr);
|
||||||
break;
|
break;
|
||||||
case CLASS_ROGUE:
|
case CLASS_ROGUE:
|
||||||
if (tab == ROGUE_TAB_ASSASSINATION || tab == ROGUE_TAB_SUBTLETY)
|
if (tab == ROGUE_TAB_ASSASSINATION || tab == ROGUE_TAB_SUBTLETY)
|
||||||
|
{
|
||||||
engine->addStrategiesNoInit("melee", "dps assist", "aoe", nullptr);
|
engine->addStrategiesNoInit("melee", "dps assist", "aoe", nullptr);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
engine->addStrategiesNoInit("dps", "dps assist", "aoe", nullptr);
|
engine->addStrategiesNoInit("dps", "dps assist", "aoe", nullptr);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case CLASS_WARLOCK:
|
case CLASS_WARLOCK:
|
||||||
if (tab == WARLOCK_TAB_AFFLICTION)
|
if (tab == 0) // Affliction
|
||||||
engine->addStrategiesNoInit("affli", "curse of agony", nullptr);
|
engine->addStrategiesNoInit("affli", "curse of agony", nullptr);
|
||||||
else if (tab == WARLOCK_TAB_DEMONOLOGY)
|
else if (tab == 1) // Demonology
|
||||||
engine->addStrategiesNoInit("demo", "curse of agony", "meta melee", nullptr);
|
engine->addStrategiesNoInit("demo", "curse of agony", "meta melee", nullptr);
|
||||||
else
|
else if (tab == 2) // Destruction
|
||||||
engine->addStrategiesNoInit("destro", "curse of elements", nullptr);
|
engine->addStrategiesNoInit("destro", "curse of elements", nullptr);
|
||||||
|
|
||||||
engine->addStrategiesNoInit("cc", "dps assist", "aoe", nullptr);
|
engine->addStrategiesNoInit("cc", "dps assist", "aoe", nullptr);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CLASS_DEATH_KNIGHT:
|
case CLASS_DEATH_KNIGHT:
|
||||||
if (tab == DEATH_KNIGHT_TAB_BLOOD)
|
if (tab == 0)
|
||||||
engine->addStrategiesNoInit("blood", "tank assist", nullptr);
|
engine->addStrategiesNoInit("blood", "tank assist", nullptr);
|
||||||
else if (tab == DEATH_KNIGHT_TAB_FROST)
|
else if (tab == 1)
|
||||||
engine->addStrategiesNoInit("frost", "frost aoe", "dps assist", nullptr);
|
engine->addStrategiesNoInit("frost", "frost aoe", "dps assist", nullptr);
|
||||||
else
|
else
|
||||||
engine->addStrategiesNoInit("unholy", "unholy aoe", "dps assist", nullptr);
|
engine->addStrategiesNoInit("unholy", "unholy aoe", "dps assist", nullptr);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (PlayerbotAI::IsTank(player, true)) {
|
||||||
if (PlayerbotAI::IsTank(player, true))
|
|
||||||
engine->addStrategy("tank face", false);
|
engine->addStrategy("tank face", false);
|
||||||
|
}
|
||||||
if (PlayerbotAI::IsMelee(player, true) && PlayerbotAI::IsDps(player, true))
|
if (PlayerbotAI::IsMelee(player, true) && PlayerbotAI::IsDps(player, true)) {
|
||||||
engine->addStrategy("behind", false);
|
engine->addStrategy("behind", false);
|
||||||
|
}
|
||||||
if (PlayerbotAI::IsHeal(player, true))
|
if (PlayerbotAI::IsHeal(player, true))
|
||||||
{
|
{
|
||||||
if (sPlayerbotAIConfig->autoSaveMana)
|
if (sPlayerbotAIConfig->autoSaveMana)
|
||||||
@@ -404,7 +426,6 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa
|
|||||||
if (!sPlayerbotAIConfig->IsRestrictedHealerDPSMap(player->GetMapId()))
|
if (!sPlayerbotAIConfig->IsRestrictedHealerDPSMap(player->GetMapId()))
|
||||||
engine->addStrategy("healer dps", false);
|
engine->addStrategy("healer dps", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (facade->IsRealPlayer() || sRandomPlayerbotMgr->IsRandomBot(player))
|
if (facade->IsRealPlayer() || sRandomPlayerbotMgr->IsRandomBot(player))
|
||||||
{
|
{
|
||||||
if (!player->GetGroup())
|
if (!player->GetGroup())
|
||||||
@@ -413,13 +434,15 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa
|
|||||||
engine->addStrategy("boost", false);
|
engine->addStrategy("boost", false);
|
||||||
engine->addStrategy("dps assist", false);
|
engine->addStrategy("dps assist", false);
|
||||||
engine->removeStrategy("threat", false);
|
engine->removeStrategy("threat", false);
|
||||||
|
// engine-
|
||||||
switch (player->getClass())
|
switch (player->getClass())
|
||||||
{
|
{
|
||||||
case CLASS_PRIEST:
|
case CLASS_PRIEST:
|
||||||
{
|
{
|
||||||
if (tab != PRIEST_TAB_SHADOW)
|
if (tab != PRIEST_TAB_SHADOW)
|
||||||
|
{
|
||||||
engine->addStrategiesNoInit("holy dps", "shadow debuff", "shadow aoe", nullptr);
|
engine->addStrategiesNoInit("holy dps", "shadow debuff", "shadow aoe", nullptr);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CLASS_DRUID:
|
case CLASS_DRUID:
|
||||||
@@ -434,13 +457,17 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa
|
|||||||
case CLASS_SHAMAN:
|
case CLASS_SHAMAN:
|
||||||
{
|
{
|
||||||
if (tab == SHAMAN_TAB_RESTORATION)
|
if (tab == SHAMAN_TAB_RESTORATION)
|
||||||
|
{
|
||||||
engine->addStrategiesNoInit("caster", "caster aoe", "bmana", nullptr);
|
engine->addStrategiesNoInit("caster", "caster aoe", "bmana", nullptr);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CLASS_PALADIN:
|
case CLASS_PALADIN:
|
||||||
{
|
{
|
||||||
if (tab == PALADIN_TAB_HOLY)
|
if (tab == PALADIN_TAB_HOLY)
|
||||||
|
{
|
||||||
engine->addStrategiesNoInit("dps", "dps assist", "baoe", nullptr);
|
engine->addStrategiesNoInit("dps", "dps assist", "baoe", nullptr);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@@ -449,9 +476,13 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (sRandomPlayerbotMgr->IsRandomBot(player))
|
if (sRandomPlayerbotMgr->IsRandomBot(player))
|
||||||
|
{
|
||||||
engine->ChangeStrategy(sPlayerbotAIConfig->randomBotCombatStrategies);
|
engine->ChangeStrategy(sPlayerbotAIConfig->randomBotCombatStrategies);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
engine->ChangeStrategy(sPlayerbotAIConfig->combatStrategies);
|
engine->ChangeStrategy(sPlayerbotAIConfig->combatStrategies);
|
||||||
|
}
|
||||||
|
|
||||||
// Battleground switch
|
// Battleground switch
|
||||||
if (player->InBattleground() && player->GetBattleground())
|
if (player->InBattleground() && player->GetBattleground())
|
||||||
@@ -478,15 +509,23 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa
|
|||||||
if (player->InArena())
|
if (player->InArena())
|
||||||
{
|
{
|
||||||
engine->addStrategy("arena", false);
|
engine->addStrategy("arena", false);
|
||||||
engine->addStrategiesNoInit("boost", "racials", "chat", "default", "aoe", "cast time", "dps assist", nullptr);
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
engine->addStrategiesNoInit("boost", "racials", "chat", "default", "aoe", "potions", "cast time", "dps assist", nullptr);
|
|
||||||
|
|
||||||
|
engine->addStrategiesNoInit("boost", "racials", "chat", "default", "aoe", "potions", "cast time", "dps assist",
|
||||||
|
nullptr);
|
||||||
engine->removeStrategy("custom::say", false);
|
engine->removeStrategy("custom::say", false);
|
||||||
engine->removeStrategy("flee", false);
|
engine->removeStrategy("flee", false);
|
||||||
engine->removeStrategy("threat", false);
|
engine->removeStrategy("threat", false);
|
||||||
engine->addStrategy("boost", false);
|
engine->addStrategy("boost", false);
|
||||||
|
|
||||||
|
// if ((player->getClass() == CLASS_DRUID && tab == 2) || (player->getClass() == CLASS_SHAMAN && tab == 2))
|
||||||
|
// engine->addStrategiesNoInit("caster", "caster aoe", nullptr);
|
||||||
|
|
||||||
|
// if (player->getClass() == CLASS_DRUID && tab == 1)
|
||||||
|
// engine->addStrategiesNoInit(/*"behind",*/ "dps", nullptr);
|
||||||
|
|
||||||
|
// if (player->getClass() == CLASS_ROGUE)
|
||||||
|
// engine->addStrategiesNoInit(/*"behind",*/ "stealth", nullptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -508,15 +547,19 @@ void AiFactory::AddDefaultNonCombatStrategies(Player* player, PlayerbotAI* const
|
|||||||
nonCombatEngine->addStrategiesNoInit("dps assist", "cure", nullptr);
|
nonCombatEngine->addStrategiesNoInit("dps assist", "cure", nullptr);
|
||||||
break;
|
break;
|
||||||
case CLASS_PALADIN:
|
case CLASS_PALADIN:
|
||||||
if (tab == PALADIN_TAB_PROTECTION)
|
if (tab == 1)
|
||||||
{
|
{
|
||||||
nonCombatEngine->addStrategiesNoInit("bthreat", "tank assist", "barmor", nullptr);
|
nonCombatEngine->addStrategiesNoInit("bthreat", "tank assist", "barmor", nullptr);
|
||||||
if (player->GetLevel() >= 20)
|
if (player->GetLevel() >= 20)
|
||||||
|
{
|
||||||
nonCombatEngine->addStrategy("bhealth", false);
|
nonCombatEngine->addStrategy("bhealth", false);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
nonCombatEngine->addStrategy("bdps", false);
|
nonCombatEngine->addStrategy("bdps", false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (tab == PALADIN_TAB_HOLY)
|
else if (tab == 0)
|
||||||
nonCombatEngine->addStrategiesNoInit("dps assist", "bmana", "bcast", nullptr);
|
nonCombatEngine->addStrategiesNoInit("dps assist", "bmana", "bcast", nullptr);
|
||||||
else
|
else
|
||||||
nonCombatEngine->addStrategiesNoInit("dps assist", "bdps", "baoe", nullptr);
|
nonCombatEngine->addStrategiesNoInit("dps assist", "bdps", "baoe", nullptr);
|
||||||
@@ -527,7 +570,7 @@ void AiFactory::AddDefaultNonCombatStrategies(Player* player, PlayerbotAI* const
|
|||||||
nonCombatEngine->addStrategiesNoInit("bdps", "dps assist", "pet", nullptr);
|
nonCombatEngine->addStrategiesNoInit("bdps", "dps assist", "pet", nullptr);
|
||||||
break;
|
break;
|
||||||
case CLASS_SHAMAN:
|
case CLASS_SHAMAN:
|
||||||
if (tab == SHAMAN_TAB_ELEMENTAL || tab == SHAMAN_TAB_RESTORATION)
|
if (tab == 0 || tab == 2)
|
||||||
nonCombatEngine->addStrategy("bmana", false);
|
nonCombatEngine->addStrategy("bmana", false);
|
||||||
else
|
else
|
||||||
nonCombatEngine->addStrategy("bdps", false);
|
nonCombatEngine->addStrategy("bdps", false);
|
||||||
@@ -543,34 +586,43 @@ void AiFactory::AddDefaultNonCombatStrategies(Player* player, PlayerbotAI* const
|
|||||||
nonCombatEngine->addStrategiesNoInit("dps assist", "cure", nullptr);
|
nonCombatEngine->addStrategiesNoInit("dps assist", "cure", nullptr);
|
||||||
break;
|
break;
|
||||||
case CLASS_DRUID:
|
case CLASS_DRUID:
|
||||||
if (tab == DRUID_TAB_FERAL)
|
if (tab == 1)
|
||||||
{
|
{
|
||||||
if (player->GetLevel() >= 20 && !player->HasAura(16931) /*thick hide*/)
|
if (player->GetLevel() >= 20 && !player->HasAura(16931) /*thick hide*/)
|
||||||
|
{
|
||||||
nonCombatEngine->addStrategy("dps assist", false);
|
nonCombatEngine->addStrategy("dps assist", false);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
nonCombatEngine->addStrategy("tank assist", false);
|
nonCombatEngine->addStrategy("tank assist", false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
nonCombatEngine->addStrategiesNoInit("dps assist", "cure", nullptr);
|
nonCombatEngine->addStrategiesNoInit("dps assist", "cure", nullptr);
|
||||||
break;
|
break;
|
||||||
case CLASS_WARRIOR:
|
case CLASS_WARRIOR:
|
||||||
if (tab == WARRIOR_TAB_PROTECTION)
|
if (tab == 2)
|
||||||
nonCombatEngine->addStrategy("tank assist", false);
|
nonCombatEngine->addStrategy("tank assist", false);
|
||||||
else
|
else
|
||||||
nonCombatEngine->addStrategy("dps assist", false);
|
nonCombatEngine->addStrategy("dps assist", false);
|
||||||
break;
|
break;
|
||||||
case CLASS_WARLOCK:
|
case CLASS_WARLOCK:
|
||||||
if (tab == WARLOCK_TAB_AFFLICTION)
|
if (tab == WARLOCK_TAB_AFFLICTION)
|
||||||
|
{
|
||||||
nonCombatEngine->addStrategiesNoInit("felhunter", "spellstone", nullptr);
|
nonCombatEngine->addStrategiesNoInit("felhunter", "spellstone", nullptr);
|
||||||
|
}
|
||||||
else if (tab == WARLOCK_TAB_DEMONOLOGY)
|
else if (tab == WARLOCK_TAB_DEMONOLOGY)
|
||||||
|
{
|
||||||
nonCombatEngine->addStrategiesNoInit("felguard", "spellstone", nullptr);
|
nonCombatEngine->addStrategiesNoInit("felguard", "spellstone", nullptr);
|
||||||
|
}
|
||||||
else if (tab == WARLOCK_TAB_DESTRUCTION)
|
else if (tab == WARLOCK_TAB_DESTRUCTION)
|
||||||
|
{
|
||||||
nonCombatEngine->addStrategiesNoInit("imp", "firestone", nullptr);
|
nonCombatEngine->addStrategiesNoInit("imp", "firestone", nullptr);
|
||||||
|
}
|
||||||
nonCombatEngine->addStrategiesNoInit("dps assist", "ss self", nullptr);
|
nonCombatEngine->addStrategiesNoInit("dps assist", "ss self", nullptr);
|
||||||
break;
|
break;
|
||||||
case CLASS_DEATH_KNIGHT:
|
case CLASS_DEATH_KNIGHT:
|
||||||
if (tab == DEATH_KNIGHT_TAB_BLOOD)
|
if (tab == 0)
|
||||||
nonCombatEngine->addStrategy("tank assist", false);
|
nonCombatEngine->addStrategy("tank assist", false);
|
||||||
else
|
else
|
||||||
nonCombatEngine->addStrategy("dps assist", false);
|
nonCombatEngine->addStrategy("dps assist", false);
|
||||||
@@ -587,7 +639,9 @@ void AiFactory::AddDefaultNonCombatStrategies(Player* player, PlayerbotAI* const
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (sPlayerbotAIConfig->autoSaveMana && PlayerbotAI::IsHeal(player, true))
|
if (sPlayerbotAIConfig->autoSaveMana && PlayerbotAI::IsHeal(player, true))
|
||||||
|
{
|
||||||
nonCombatEngine->addStrategy("save mana", false);
|
nonCombatEngine->addStrategy("save mana", false);
|
||||||
|
}
|
||||||
|
|
||||||
if ((sRandomPlayerbotMgr->IsRandomBot(player)) && !player->InBattleground())
|
if ((sRandomPlayerbotMgr->IsRandomBot(player)) && !player->InBattleground())
|
||||||
{
|
{
|
||||||
@@ -613,14 +667,18 @@ void AiFactory::AddDefaultNonCombatStrategies(Player* player, PlayerbotAI* const
|
|||||||
nonCombatEngine->addStrategy("grind", false);
|
nonCombatEngine->addStrategy("grind", false);
|
||||||
|
|
||||||
if (sPlayerbotAIConfig->enableNewRpgStrategy)
|
if (sPlayerbotAIConfig->enableNewRpgStrategy)
|
||||||
|
{
|
||||||
nonCombatEngine->addStrategy("new rpg", false);
|
nonCombatEngine->addStrategy("new rpg", false);
|
||||||
|
}
|
||||||
else if (sPlayerbotAIConfig->autoDoQuests)
|
else if (sPlayerbotAIConfig->autoDoQuests)
|
||||||
{
|
{
|
||||||
// nonCombatEngine->addStrategy("travel");
|
// nonCombatEngine->addStrategy("travel");
|
||||||
nonCombatEngine->addStrategy("rpg", false);
|
nonCombatEngine->addStrategy("rpg", false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
nonCombatEngine->addStrategy("move random", false);
|
nonCombatEngine->addStrategy("move random", false);
|
||||||
|
}
|
||||||
|
|
||||||
if (sPlayerbotAIConfig->randomBotJoinBG)
|
if (sPlayerbotAIConfig->randomBotJoinBG)
|
||||||
nonCombatEngine->addStrategy("bg", false);
|
nonCombatEngine->addStrategy("bg", false);
|
||||||
@@ -648,9 +706,7 @@ void AiFactory::AddDefaultNonCombatStrategies(Player* player, PlayerbotAI* const
|
|||||||
// {
|
// {
|
||||||
// // nonCombatEngine->addStrategy("travel");
|
// // nonCombatEngine->addStrategy("travel");
|
||||||
// nonCombatEngine->addStrategy("rpg");
|
// nonCombatEngine->addStrategy("rpg");
|
||||||
// }
|
// } else {
|
||||||
// else
|
|
||||||
// {
|
|
||||||
// nonCombatEngine->addStrategy("move random");
|
// nonCombatEngine->addStrategy("move random");
|
||||||
// }
|
// }
|
||||||
|
|
||||||
@@ -669,8 +725,11 @@ void AiFactory::AddDefaultNonCombatStrategies(Player* player, PlayerbotAI* const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
nonCombatEngine->ChangeStrategy(sPlayerbotAIConfig->nonCombatStrategies);
|
nonCombatEngine->ChangeStrategy(sPlayerbotAIConfig->nonCombatStrategies);
|
||||||
|
}
|
||||||
|
// nonCombatEngine->addStrategy("battleground");
|
||||||
|
// nonCombatEngine->addStrategy("warsong");
|
||||||
// Battleground switch
|
// Battleground switch
|
||||||
if (player->InBattleground() && player->GetBattleground())
|
if (player->InBattleground() && player->GetBattleground())
|
||||||
{
|
{
|
||||||
@@ -727,7 +786,9 @@ void AiFactory::AddDefaultDeadStrategies(Player* player, PlayerbotAI* const faca
|
|||||||
deadEngine->addStrategiesNoInit("dead", "stay", "chat", "default", "follow", nullptr);
|
deadEngine->addStrategiesNoInit("dead", "stay", "chat", "default", "follow", nullptr);
|
||||||
|
|
||||||
if (sRandomPlayerbotMgr->IsRandomBot(player) && !player->GetGroup())
|
if (sRandomPlayerbotMgr->IsRandomBot(player) && !player->GetGroup())
|
||||||
|
{
|
||||||
deadEngine->removeStrategy("follow", false);
|
deadEngine->removeStrategy("follow", false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Engine* AiFactory::createDeadEngine(Player* player, PlayerbotAI* const facade, AiObjectContext* AiObjectContext)
|
Engine* AiFactory::createDeadEngine(Player* player, PlayerbotAI* const facade, AiObjectContext* AiObjectContext)
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
@@ -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; }
|
|
||||||
@@ -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); }
|
|
||||||
@@ -70,7 +70,7 @@ bool BroadcastHelper::BroadcastToChannelWithGlobalChance(PlayerbotAI* ai, std::s
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto const& pair : toChannels)
|
for (const auto& pair : toChannels)
|
||||||
{
|
{
|
||||||
uint32 roll = urand(1, 100);
|
uint32 roll = urand(1, 100);
|
||||||
uint32 chance = pair.second;
|
uint32 chance = pair.second;
|
||||||
@@ -166,7 +166,7 @@ bool BroadcastHelper::BroadcastToChannelWithGlobalChance(PlayerbotAI* ai, std::s
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BroadcastHelper::BroadcastLootingItem(PlayerbotAI* ai, Player* bot, ItemTemplate const* proto)
|
bool BroadcastHelper::BroadcastLootingItem(PlayerbotAI* ai, Player* bot, const ItemTemplate *proto)
|
||||||
{
|
{
|
||||||
if (!sPlayerbotAIConfig->enableBroadcasts)
|
if (!sPlayerbotAIConfig->enableBroadcasts)
|
||||||
return false;
|
return false;
|
||||||
@@ -410,6 +410,7 @@ bool BroadcastHelper::BroadcastQuestUpdateComplete(PlayerbotAI* ai, Player* bot,
|
|||||||
placeholders["%my_race"] = ai->GetChatHelper()->FormatRace(bot->getRace());
|
placeholders["%my_race"] = ai->GetChatHelper()->FormatRace(bot->getRace());
|
||||||
placeholders["%my_level"] = std::to_string(bot->GetLevel());
|
placeholders["%my_level"] = std::to_string(bot->GetLevel());
|
||||||
|
|
||||||
|
|
||||||
return BroadcastToChannelWithGlobalChance(
|
return BroadcastToChannelWithGlobalChance(
|
||||||
ai,
|
ai,
|
||||||
BOT_TEXT2("broadcast_quest_update_complete", placeholders),
|
BOT_TEXT2("broadcast_quest_update_complete", placeholders),
|
||||||
@@ -373,7 +373,7 @@ private:
|
|||||||
bool ParseSpecPrefix(const std::string& message, std::string& specPrefix, std::string& rest)
|
bool ParseSpecPrefix(const std::string& message, std::string& specPrefix, std::string& rest)
|
||||||
{
|
{
|
||||||
std::string msgLower = ToLower(message);
|
std::string msgLower = ToLower(message);
|
||||||
for (auto const& entry : specTabNames)
|
for (const auto& entry : specTabNames)
|
||||||
{
|
{
|
||||||
std::string prefix = "@" + entry.second;
|
std::string prefix = "@" + entry.second;
|
||||||
if (msgLower.find(ToLower(prefix)) == 0)
|
if (msgLower.find(ToLower(prefix)) == 0)
|
||||||
@@ -555,7 +555,7 @@ public:
|
|||||||
const float radius = 100.0f;
|
const float radius = 100.0f;
|
||||||
GuidVector npcs = botAI->GetAiObjectContext()->GetValue<GuidVector>("nearest npcs")->Get();
|
GuidVector npcs = botAI->GetAiObjectContext()->GetValue<GuidVector>("nearest npcs")->Get();
|
||||||
bool match = false;
|
bool match = false;
|
||||||
for (auto const& guid : npcs)
|
for (const auto& guid : npcs)
|
||||||
{
|
{
|
||||||
Creature* c = botAI->GetCreature(guid);
|
Creature* c = botAI->GetCreature(guid);
|
||||||
if (!c)
|
if (!c)
|
||||||
@@ -329,11 +329,9 @@ ItemWithRandomProperty ChatHelper::parseItemWithRandomProperty(std::string const
|
|||||||
|
|
||||||
while (currentPos < text.length()) {
|
while (currentPos < text.length()) {
|
||||||
size_t nextColon = text.find(':', currentPos);
|
size_t nextColon = text.find(':', currentPos);
|
||||||
if (nextColon == std::string::npos)
|
if (nextColon == std::string::npos) {
|
||||||
{
|
|
||||||
size_t hTag = text.find("|h", currentPos);
|
size_t hTag = text.find("|h", currentPos);
|
||||||
if (hTag != std::string::npos)
|
if (hTag != std::string::npos) {
|
||||||
{
|
|
||||||
params.push_back(text.substr(currentPos, hTag - currentPos));
|
params.push_back(text.substr(currentPos, hTag - currentPos));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -343,8 +341,7 @@ ItemWithRandomProperty ChatHelper::parseItemWithRandomProperty(std::string const
|
|||||||
currentPos = nextColon + 1;
|
currentPos = nextColon + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (params.size() >= 6)
|
if (params.size() >= 6) {
|
||||||
{
|
|
||||||
res.randomPropertyId = atoi(params[5].c_str());
|
res.randomPropertyId = atoi(params[5].c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -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();
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
@@ -1067,7 +1067,7 @@ void GuildTaskMgr::SendCompletionMessage(Player* player, std::string const verb)
|
|||||||
void GuildTaskMgr::CheckKillTaskInternal(Player* player, Unit* victim)
|
void GuildTaskMgr::CheckKillTaskInternal(Player* player, Unit* victim)
|
||||||
{
|
{
|
||||||
ObjectGuid::LowType owner = player->GetGUID().GetCounter();
|
ObjectGuid::LowType owner = player->GetGUID().GetCounter();
|
||||||
if (!victim->IsCreature())
|
if (victim->GetTypeId() != TYPEID_UNIT)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Creature* creature = reinterpret_cast<Creature*>(victim);
|
Creature* creature = reinterpret_cast<Creature*>(victim);
|
||||||
50
src/Helpers.cpp
Normal file
50
src/Helpers.cpp
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* 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 "Helpers.h"
|
||||||
|
|
||||||
|
char* strstri(char const* haystack, char const* needle)
|
||||||
|
{
|
||||||
|
if (!*needle)
|
||||||
|
{
|
||||||
|
return (char*)haystack;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; *haystack; ++haystack)
|
||||||
|
{
|
||||||
|
if (tolower(*haystack) == tolower(*needle))
|
||||||
|
{
|
||||||
|
char const *h = haystack, *n = needle;
|
||||||
|
for (; *h && *n; ++h, ++n)
|
||||||
|
{
|
||||||
|
if (tolower(*h) != tolower(*n))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!*n)
|
||||||
|
{
|
||||||
|
return (char*)haystack;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string& ltrim(std::string& s)
|
||||||
|
{
|
||||||
|
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](int c) { return !std::isspace(c); }));
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string& rtrim(std::string& s)
|
||||||
|
{
|
||||||
|
s.erase(std::find_if(s.rbegin(), s.rend(), [](int c) { return !std::isspace(c); }).base(), s.end());
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string& trim(std::string& s) { return ltrim(rtrim(s)); }
|
||||||
55
src/Helpers.h
Normal file
55
src/Helpers.h
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
* 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_HELPERS_H
|
||||||
|
#define _PLAYERBOT_HELPERS_H
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cctype>
|
||||||
|
#include <functional>
|
||||||
|
#include <locale>
|
||||||
|
#include <map>
|
||||||
|
#include <sstream>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "Common.h"
|
||||||
|
|
||||||
|
void split(std::vector<std::string>& dest, std::string const str, char const* delim)
|
||||||
|
{
|
||||||
|
char* pTempStr = strdup(str.c_str());
|
||||||
|
char* pWord = strtok(pTempStr, delim);
|
||||||
|
|
||||||
|
while (pWord != nullptr)
|
||||||
|
{
|
||||||
|
dest.push_back(pWord);
|
||||||
|
pWord = strtok(nullptr, delim);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(pTempStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string>& split(std::string const s, char delim, std::vector<std::string>& elems)
|
||||||
|
{
|
||||||
|
std::stringstream ss(s);
|
||||||
|
std::string item;
|
||||||
|
|
||||||
|
while (getline(ss, item, delim))
|
||||||
|
{
|
||||||
|
elems.push_back(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
return elems;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> split(std::string const s, char delim)
|
||||||
|
{
|
||||||
|
std::vector<std::string> elems;
|
||||||
|
return split(s, delim, elems);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
39
src/LazyCalculatedValue.h
Normal file
39
src/LazyCalculatedValue.h
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* 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_LAZYCALCULATEDVALUE_H
|
||||||
|
#define _PLAYERBOT_LAZYCALCULATEDVALUE_H
|
||||||
|
|
||||||
|
template <class TValue, class TOwner>
|
||||||
|
class LazyCalculatedValue
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef TValue (TOwner::*Calculator)();
|
||||||
|
|
||||||
|
public:
|
||||||
|
LazyCalculatedValue(TOwner* owner, Calculator calculator) : calculator(calculator), owner(owner) { Reset(); }
|
||||||
|
|
||||||
|
public:
|
||||||
|
TValue GetValue()
|
||||||
|
{
|
||||||
|
if (!calculated)
|
||||||
|
{
|
||||||
|
value = (owner->*calculator)();
|
||||||
|
calculated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Reset() { calculated = false; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Calculator calculator;
|
||||||
|
TOwner* owner;
|
||||||
|
bool calculated;
|
||||||
|
TValue value;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -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();
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
@@ -3,11 +3,11 @@
|
|||||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "PerfMonitor.h"
|
#include "PerformanceMonitor.h"
|
||||||
|
|
||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
|
|
||||||
PerfMonitorOperation* PerfMonitor::start(PerformanceMetric metric, std::string const name,
|
PerformanceMonitorOperation* PerformanceMonitor::start(PerformanceMetric metric, std::string const name,
|
||||||
PerformanceStack* stack)
|
PerformanceStack* stack)
|
||||||
{
|
{
|
||||||
if (!sPlayerbotAIConfig->perfMonEnabled)
|
if (!sPlayerbotAIConfig->perfMonEnabled)
|
||||||
@@ -45,10 +45,10 @@ PerfMonitorOperation* PerfMonitor::start(PerformanceMetric metric, std::string c
|
|||||||
data[metric][stackName] = pd;
|
data[metric][stackName] = pd;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new PerfMonitorOperation(pd, name, stack);
|
return new PerformanceMonitorOperation(pd, name, stack);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PerfMonitor::PrintStats(bool perTick, bool fullStack)
|
void PerformanceMonitor::PrintStats(bool perTick, bool fullStack)
|
||||||
{
|
{
|
||||||
if (data.empty())
|
if (data.empty())
|
||||||
return;
|
return;
|
||||||
@@ -247,7 +247,7 @@ void PerfMonitor::PrintStats(bool perTick, bool fullStack)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PerfMonitor::Reset()
|
void PerformanceMonitor::Reset()
|
||||||
{
|
{
|
||||||
for (std::map<PerformanceMetric, std::map<std::string, PerformanceData*>>::iterator i = data.begin();
|
for (std::map<PerformanceMetric, std::map<std::string, PerformanceData*>>::iterator i = data.begin();
|
||||||
i != data.end(); ++i)
|
i != data.end(); ++i)
|
||||||
@@ -265,7 +265,7 @@ void PerfMonitor::Reset()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PerfMonitorOperation::PerfMonitorOperation(PerformanceData* data, std::string const name,
|
PerformanceMonitorOperation::PerformanceMonitorOperation(PerformanceData* data, std::string const name,
|
||||||
PerformanceStack* stack)
|
PerformanceStack* stack)
|
||||||
: data(data), name(name), stack(stack)
|
: data(data), name(name), stack(stack)
|
||||||
{
|
{
|
||||||
@@ -273,7 +273,7 @@ PerfMonitorOperation::PerfMonitorOperation(PerformanceData* data, std::string co
|
|||||||
.time_since_epoch();
|
.time_since_epoch();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PerfMonitorOperation::finish()
|
void PerformanceMonitorOperation::finish()
|
||||||
{
|
{
|
||||||
std::chrono::microseconds finished =
|
std::chrono::microseconds finished =
|
||||||
(std::chrono::time_point_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now()))
|
(std::chrono::time_point_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now()))
|
||||||
@@ -34,10 +34,10 @@ enum PerformanceMetric
|
|||||||
PERF_MON_TOTAL
|
PERF_MON_TOTAL
|
||||||
};
|
};
|
||||||
|
|
||||||
class PerfMonitorOperation
|
class PerformanceMonitorOperation
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
PerfMonitorOperation(PerformanceData* data, std::string const name, PerformanceStack* stack);
|
PerformanceMonitorOperation(PerformanceData* data, std::string const name, PerformanceStack* stack);
|
||||||
void finish();
|
void finish();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -47,19 +47,19 @@ private:
|
|||||||
std::chrono::microseconds started;
|
std::chrono::microseconds started;
|
||||||
};
|
};
|
||||||
|
|
||||||
class PerfMonitor
|
class PerformanceMonitor
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
PerfMonitor(){};
|
PerformanceMonitor(){};
|
||||||
virtual ~PerfMonitor(){};
|
virtual ~PerformanceMonitor(){};
|
||||||
static PerfMonitor* instance()
|
static PerformanceMonitor* instance()
|
||||||
{
|
{
|
||||||
static PerfMonitor instance;
|
static PerformanceMonitor instance;
|
||||||
return &instance;
|
return &instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PerfMonitorOperation* start(PerformanceMetric metric, std::string const name,
|
PerformanceMonitorOperation* start(PerformanceMetric metric, std::string const name,
|
||||||
PerformanceStack* stack = nullptr);
|
PerformanceStack* stack = nullptr);
|
||||||
void PrintStats(bool perTick = false, bool fullStack = false);
|
void PrintStats(bool perTick = false, bool fullStack = false);
|
||||||
void Reset();
|
void Reset();
|
||||||
@@ -69,6 +69,6 @@ private:
|
|||||||
std::mutex lock;
|
std::mutex lock;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define sPerfMonitor PerfMonitor::instance()
|
#define sPerformanceMonitor PerformanceMonitor::instance()
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include "Player.h"
|
#include "Player.h"
|
||||||
#include "PlayerbotDungeonRepository.h"
|
#include "PlayerbotDungeonSuggestionMgr.h"
|
||||||
|
|
||||||
typedef std::map<std::string, std::string> PlaceholderMap;
|
typedef std::map<std::string, std::string> PlaceholderMap;
|
||||||
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -276,7 +276,7 @@ enum BotRoles : uint8
|
|||||||
|
|
||||||
enum HUNTER_TABS
|
enum HUNTER_TABS
|
||||||
{
|
{
|
||||||
HUNTER_TAB_BEAST_MASTERY,
|
HUNTER_TAB_BEASTMASTERY,
|
||||||
HUNTER_TAB_MARKSMANSHIP,
|
HUNTER_TAB_MARKSMANSHIP,
|
||||||
HUNTER_TAB_SURVIVAL,
|
HUNTER_TAB_SURVIVAL,
|
||||||
};
|
};
|
||||||
@@ -295,11 +295,11 @@ enum PRIEST_TABS
|
|||||||
PRIEST_TAB_SHADOW,
|
PRIEST_TAB_SHADOW,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum DEATH_KNIGHT_TABS
|
enum DEATHKNIGHT_TABS
|
||||||
{
|
{
|
||||||
DEATH_KNIGHT_TAB_BLOOD,
|
DEATHKNIGHT_TAB_BLOOD,
|
||||||
DEATH_KNIGHT_TAB_FROST,
|
DEATHKNIGHT_TAB_FROST,
|
||||||
DEATH_KNIGHT_TAB_UNHOLY,
|
DEATHKNIGHT_TAB_UNHOLY,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum DRUID_TABS
|
enum DRUID_TABS
|
||||||
@@ -428,7 +428,7 @@ public:
|
|||||||
static bool IsMainTank(Player* player);
|
static bool IsMainTank(Player* player);
|
||||||
static uint32 GetGroupTankNum(Player* player);
|
static uint32 GetGroupTankNum(Player* player);
|
||||||
static bool IsAssistTank(Player* player);
|
static bool IsAssistTank(Player* player);
|
||||||
static bool IsAssistTankOfIndex(Player* player, int index, bool ignoreDeadPlayers = false);
|
static bool IsAssistTankOfIndex(Player* player, int index);
|
||||||
static bool IsHealAssistantOfIndex(Player* player, int index);
|
static bool IsHealAssistantOfIndex(Player* player, int index);
|
||||||
static bool IsRangedDpsAssistantOfIndex(Player* player, int index);
|
static bool IsRangedDpsAssistantOfIndex(Player* player, int index);
|
||||||
bool HasAggro(Unit* unit);
|
bool HasAggro(Unit* unit);
|
||||||
@@ -529,7 +529,6 @@ public:
|
|||||||
|
|
||||||
Player* GetBot() { return bot; }
|
Player* GetBot() { return bot; }
|
||||||
Player* GetMaster() { return master; }
|
Player* GetMaster() { return master; }
|
||||||
Player* FindNewMaster();
|
|
||||||
|
|
||||||
// Checks if the bot is really a player. Players always have themselves as master.
|
// Checks if the bot is really a player. Players always have themselves as master.
|
||||||
bool IsRealPlayer() { return master ? (master == bot) : false; }
|
bool IsRealPlayer() { return master ? (master == bot) : false; }
|
||||||
@@ -540,7 +539,7 @@ public:
|
|||||||
// Get the group leader or the master of the bot.
|
// Get the group leader or the master of the bot.
|
||||||
// Checks if the bot is summoned as alt of a player
|
// Checks if the bot is summoned as alt of a player
|
||||||
bool IsAlt();
|
bool IsAlt();
|
||||||
Player* GetGroupLeader();
|
Player* GetGroupMaster();
|
||||||
// Returns a semi-random (cycling) number that is fixed for each bot.
|
// Returns a semi-random (cycling) number that is fixed for each bot.
|
||||||
uint32 GetFixedBotNumer(uint32 maxNum = 100, float cyclePerMin = 1);
|
uint32 GetFixedBotNumer(uint32 maxNum = 100, float cyclePerMin = 1);
|
||||||
GrouperType GetGrouperType();
|
GrouperType GetGrouperType();
|
||||||
@@ -579,6 +578,7 @@ public:
|
|||||||
void ResetJumpDestination() { jumpDestination = Position(); }
|
void ResetJumpDestination() { jumpDestination = Position(); }
|
||||||
|
|
||||||
bool CanMove();
|
bool CanMove();
|
||||||
|
static bool IsRealGuild(uint32 guildId);
|
||||||
bool IsInRealGuild();
|
bool IsInRealGuild();
|
||||||
static std::vector<std::string> dispel_whitelist;
|
static std::vector<std::string> dispel_whitelist;
|
||||||
bool EqualLowercaseName(std::string s1, std::string s2);
|
bool EqualLowercaseName(std::string s1, std::string s2);
|
||||||
@@ -611,20 +611,12 @@ private:
|
|||||||
static void _fillGearScoreData(Player* player, Item* item, std::vector<uint32>* gearScore, uint32& twoHandScore,
|
static void _fillGearScoreData(Player* player, Item* item, std::vector<uint32>* gearScore, uint32& twoHandScore,
|
||||||
bool mixed = false);
|
bool mixed = false);
|
||||||
bool IsTellAllowed(PlayerbotSecurityLevel securityLevel = PLAYERBOT_SECURITY_ALLOW_ALL);
|
bool IsTellAllowed(PlayerbotSecurityLevel securityLevel = PLAYERBOT_SECURITY_ALLOW_ALL);
|
||||||
void UpdateAIGroupMaster();
|
void UpdateAIGroupMembership();
|
||||||
Item* FindItemInInventory(std::function<bool(ItemTemplate const*)> checkItem) const;
|
Item* FindItemInInventory(std::function<bool(ItemTemplate const*)> checkItem) const;
|
||||||
void HandleCommands();
|
void HandleCommands();
|
||||||
void HandleCommand(uint32 type, const std::string& text, Player& fromPlayer, const uint32 lang = LANG_UNIVERSAL);
|
void HandleCommand(uint32 type, const std::string& text, Player& fromPlayer, const uint32 lang = LANG_UNIVERSAL);
|
||||||
bool _isBotInitializing = false;
|
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:
|
protected:
|
||||||
Player* bot;
|
Player* bot;
|
||||||
Player* master;
|
Player* master;
|
||||||
@@ -14,7 +14,7 @@ void PlayerbotAIBase::UpdateAI(uint32 elapsed, bool minimal)
|
|||||||
if (totalPmo)
|
if (totalPmo)
|
||||||
totalPmo->finish();
|
totalPmo->finish();
|
||||||
|
|
||||||
totalPmo = sPerfMonitor->start(PERF_MON_TOTAL, "PlayerbotAIBase::FullTick");
|
totalPmo = sPerformanceMonitor->start(PERF_MON_TOTAL, "PlayerbotAIBase::FullTick");
|
||||||
|
|
||||||
if (nextAICheckDelay > elapsed)
|
if (nextAICheckDelay > elapsed)
|
||||||
nextAICheckDelay -= elapsed;
|
nextAICheckDelay -= elapsed;
|
||||||
@@ -25,7 +25,7 @@ public:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
uint32 nextAICheckDelay;
|
uint32 nextAICheckDelay;
|
||||||
class PerfMonitorOperation* totalPmo = nullptr;
|
class PerformanceMonitorOperation* totalPmo = nullptr;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool _isBotAI;
|
bool _isBotAI;
|
||||||
@@ -7,10 +7,9 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
#include "NewRpgInfo.h"
|
#include "NewRpgInfo.h"
|
||||||
#include "PlayerbotDungeonRepository.h"
|
#include "PlayerbotDungeonSuggestionMgr.h"
|
||||||
#include "PlayerbotFactory.h"
|
#include "PlayerbotFactory.h"
|
||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
#include "PlayerbotGuildMgr.h"
|
|
||||||
#include "RandomItemMgr.h"
|
#include "RandomItemMgr.h"
|
||||||
#include "RandomPlayerbotFactory.h"
|
#include "RandomPlayerbotFactory.h"
|
||||||
#include "RandomPlayerbotMgr.h"
|
#include "RandomPlayerbotMgr.h"
|
||||||
@@ -58,54 +57,55 @@ void LoadListString(std::string const value, T& list)
|
|||||||
|
|
||||||
bool PlayerbotAIConfig::Initialize()
|
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);
|
enabled = sConfigMgr->GetOption<bool>("AiPlayerbot.Enabled", true);
|
||||||
if (!enabled)
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
globalCoolDown = sConfigMgr->GetOption<int32>("AiPlayerbot.GlobalCooldown", 500);
|
globalCoolDown = sConfigMgr->GetOption<int32>("AiPlayerbot.GlobalCooldown", 1500);
|
||||||
maxWaitForMove = sConfigMgr->GetOption<int32>("AiPlayerbot.MaxWaitForMove", 5000);
|
maxWaitForMove = sConfigMgr->GetOption<int32>("AiPlayerbot.MaxWaitForMove", 5000);
|
||||||
disableMoveSplinePath = sConfigMgr->GetOption<int32>("AiPlayerbot.DisableMoveSplinePath", 0);
|
disableMoveSplinePath = sConfigMgr->GetOption<int32>("AiPlayerbot.DisableMoveSplinePath", 0);
|
||||||
maxMovementSearchTime = sConfigMgr->GetOption<int32>("AiPlayerbot.MaxMovementSearchTime", 3);
|
maxMovementSearchTime = sConfigMgr->GetOption<int32>("AiPlayerbot.MaxMovementSearchTime", 3);
|
||||||
expireActionTime = sConfigMgr->GetOption<int32>("AiPlayerbot.ExpireActionTime", 5000);
|
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);
|
reactDelay = sConfigMgr->GetOption<int32>("AiPlayerbot.ReactDelay", 100);
|
||||||
dynamicReactDelay = sConfigMgr->GetOption<bool>("AiPlayerbot.DynamicReactDelay", true);
|
dynamicReactDelay = sConfigMgr->GetOption<bool>("AiPlayerbot.DynamicReactDelay", true);
|
||||||
passiveDelay = sConfigMgr->GetOption<int32>("AiPlayerbot.PassiveDelay", 10000);
|
passiveDelay = sConfigMgr->GetOption<int32>("AiPlayerbot.PassiveDelay", 10000);
|
||||||
repeatDelay = sConfigMgr->GetOption<int32>("AiPlayerbot.RepeatDelay", 2000);
|
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);
|
rpgDelay = sConfigMgr->GetOption<int32>("AiPlayerbot.RpgDelay", 10000);
|
||||||
sitDelay = sConfigMgr->GetOption<int32>("AiPlayerbot.SitDelay", 20000);
|
sitDelay = sConfigMgr->GetOption<int32>("AiPlayerbot.SitDelay", 30000);
|
||||||
returnDelay = sConfigMgr->GetOption<int32>("AiPlayerbot.ReturnDelay", 2000);
|
returnDelay = sConfigMgr->GetOption<int32>("AiPlayerbot.ReturnDelay", 7000);
|
||||||
lootDelay = sConfigMgr->GetOption<int32>("AiPlayerbot.LootDelay", 1000);
|
lootDelay = sConfigMgr->GetOption<int32>("AiPlayerbot.LootDelay", 1000);
|
||||||
|
// Buff system
|
||||||
minBotsForGreaterBuff = sConfigMgr->GetOption<int32>("AiPlayerbot.MinBotsForGreaterBuff", 3);
|
minBotsForGreaterBuff = sConfigMgr->GetOption<int32>("AiPlayerbot.MinBotsForGreaterBuff", 3);
|
||||||
rpWarningCooldown = sConfigMgr->GetOption<int32>("AiPlayerbot.RPWarningCooldown", 30);
|
rpWarningCooldown = sConfigMgr->GetOption<int32>("AiPlayerbot.RPWarningCooldown", 30);
|
||||||
disabledWithoutRealPlayerLoginDelay = sConfigMgr->GetOption<int32>("AiPlayerbot.DisabledWithoutRealPlayerLoginDelay", 30);
|
disabledWithoutRealPlayerLoginDelay = sConfigMgr->GetOption<int32>("AiPlayerbot.DisabledWithoutRealPlayerLoginDelay", 30);
|
||||||
disabledWithoutRealPlayerLogoutDelay = sConfigMgr->GetOption<int32>("AiPlayerbot.DisabledWithoutRealPlayerLogoutDelay", 300);
|
disabledWithoutRealPlayerLogoutDelay = sConfigMgr->GetOption<int32>("AiPlayerbot.DisabledWithoutRealPlayerLogoutDelay", 300);
|
||||||
|
|
||||||
farDistance = sConfigMgr->GetOption<float>("AiPlayerbot.FarDistance", 20.0f);
|
farDistance = sConfigMgr->GetOption<float>("AiPlayerbot.FarDistance", 20.0f);
|
||||||
sightDistance = sConfigMgr->GetOption<float>("AiPlayerbot.SightDistance", 100.0f);
|
sightDistance = sConfigMgr->GetOption<float>("AiPlayerbot.SightDistance", 75.0f);
|
||||||
spellDistance = sConfigMgr->GetOption<float>("AiPlayerbot.SpellDistance", 28.5f);
|
spellDistance = sConfigMgr->GetOption<float>("AiPlayerbot.SpellDistance", 25.0f);
|
||||||
shootDistance = sConfigMgr->GetOption<float>("AiPlayerbot.ShootDistance", 5.0f);
|
shootDistance = sConfigMgr->GetOption<float>("AiPlayerbot.ShootDistance", 25.0f);
|
||||||
healDistance = sConfigMgr->GetOption<float>("AiPlayerbot.HealDistance", 38.5f);
|
healDistance = sConfigMgr->GetOption<float>("AiPlayerbot.HealDistance", 25.0f);
|
||||||
lootDistance = sConfigMgr->GetOption<float>("AiPlayerbot.LootDistance", 15.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);
|
aggroDistance = sConfigMgr->GetOption<float>("AiPlayerbot.AggroDistance", 22.0f);
|
||||||
tooCloseDistance = sConfigMgr->GetOption<float>("AiPlayerbot.TooCloseDistance", 5.0f);
|
tooCloseDistance = sConfigMgr->GetOption<float>("AiPlayerbot.TooCloseDistance", 5.0f);
|
||||||
meleeDistance = sConfigMgr->GetOption<float>("AiPlayerbot.MeleeDistance", 0.75f);
|
meleeDistance = sConfigMgr->GetOption<float>("AiPlayerbot.MeleeDistance", 0.75f);
|
||||||
followDistance = sConfigMgr->GetOption<float>("AiPlayerbot.FollowDistance", 1.5f);
|
followDistance = sConfigMgr->GetOption<float>("AiPlayerbot.FollowDistance", 1.5f);
|
||||||
whisperDistance = sConfigMgr->GetOption<float>("AiPlayerbot.WhisperDistance", 6000.0f);
|
whisperDistance = sConfigMgr->GetOption<float>("AiPlayerbot.WhisperDistance", 6000.0f);
|
||||||
contactDistance = sConfigMgr->GetOption<float>("AiPlayerbot.ContactDistance", 0.45f);
|
contactDistance = sConfigMgr->GetOption<float>("AiPlayerbot.ContactDistance", 0.5f);
|
||||||
aoeRadius = sConfigMgr->GetOption<float>("AiPlayerbot.AoeRadius", 10.0f);
|
aoeRadius = sConfigMgr->GetOption<float>("AiPlayerbot.AoeRadius", 5.0f);
|
||||||
rpgDistance = sConfigMgr->GetOption<float>("AiPlayerbot.RpgDistance", 200.0f);
|
rpgDistance = sConfigMgr->GetOption<float>("AiPlayerbot.RpgDistance", 200.0f);
|
||||||
grindDistance = sConfigMgr->GetOption<float>("AiPlayerbot.GrindDistance", 75.0f);
|
grindDistance = sConfigMgr->GetOption<float>("AiPlayerbot.GrindDistance", 75.0f);
|
||||||
reactDistance = sConfigMgr->GetOption<float>("AiPlayerbot.ReactDistance", 150.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);
|
lowHealth = sConfigMgr->GetOption<int32>("AiPlayerbot.LowHealth", 45);
|
||||||
mediumHealth = sConfigMgr->GetOption<int32>("AiPlayerbot.MediumHealth", 65);
|
mediumHealth = sConfigMgr->GetOption<int32>("AiPlayerbot.MediumHealth", 65);
|
||||||
almostFullHealth = sConfigMgr->GetOption<int32>("AiPlayerbot.AlmostFullHealth", 85);
|
almostFullHealth = sConfigMgr->GetOption<int32>("AiPlayerbot.AlmostFullHealth", 85);
|
||||||
@@ -116,7 +116,7 @@ bool PlayerbotAIConfig::Initialize()
|
|||||||
saveManaThreshold = sConfigMgr->GetOption<int32>("AiPlayerbot.SaveManaThreshold", 60);
|
saveManaThreshold = sConfigMgr->GetOption<int32>("AiPlayerbot.SaveManaThreshold", 60);
|
||||||
autoAvoidAoe = sConfigMgr->GetOption<bool>("AiPlayerbot.AutoAvoidAoe", true);
|
autoAvoidAoe = sConfigMgr->GetOption<bool>("AiPlayerbot.AutoAvoidAoe", true);
|
||||||
maxAoeAvoidRadius = sConfigMgr->GetOption<float>("AiPlayerbot.MaxAoeAvoidRadius", 15.0f);
|
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);
|
aoeAvoidSpellWhitelist);
|
||||||
tellWhenAvoidAoe = sConfigMgr->GetOption<bool>("AiPlayerbot.TellWhenAvoidAoe", false);
|
tellWhenAvoidAoe = sConfigMgr->GetOption<bool>("AiPlayerbot.TellWhenAvoidAoe", false);
|
||||||
|
|
||||||
@@ -129,7 +129,7 @@ bool PlayerbotAIConfig::Initialize()
|
|||||||
randomBotMaxLevelChance = sConfigMgr->GetOption<float>("AiPlayerbot.RandomBotMaxLevelChance", 0.1f);
|
randomBotMaxLevelChance = sConfigMgr->GetOption<float>("AiPlayerbot.RandomBotMaxLevelChance", 0.1f);
|
||||||
randomBotRpgChance = sConfigMgr->GetOption<float>("AiPlayerbot.RandomBotRpgChance", 0.20f);
|
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);
|
allowAccountBots = sConfigMgr->GetOption<bool>("AiPlayerbot.AllowAccountBots", true);
|
||||||
allowGuildBots = sConfigMgr->GetOption<bool>("AiPlayerbot.AllowGuildBots", true);
|
allowGuildBots = sConfigMgr->GetOption<bool>("AiPlayerbot.AllowGuildBots", true);
|
||||||
@@ -143,11 +143,11 @@ bool PlayerbotAIConfig::Initialize()
|
|||||||
LoadList<std::vector<uint32>>(randomBotMapsAsString, randomBotMaps);
|
LoadList<std::vector<uint32>>(randomBotMapsAsString, randomBotMaps);
|
||||||
probTeleToBankers = sConfigMgr->GetOption<float>("AiPlayerbot.ProbTeleToBankers", 0.25f);
|
probTeleToBankers = sConfigMgr->GetOption<float>("AiPlayerbot.ProbTeleToBankers", 0.25f);
|
||||||
enableWeightTeleToCityBankers = sConfigMgr->GetOption<bool>("AiPlayerbot.EnableWeightTeleToCityBankers", false);
|
enableWeightTeleToCityBankers = sConfigMgr->GetOption<bool>("AiPlayerbot.EnableWeightTeleToCityBankers", false);
|
||||||
weightTeleToStormwind = sConfigMgr->GetOption<int>("AiPlayerbot.TeleToStormwindWeight", 2);
|
weightTeleToStormwind = sConfigMgr->GetOption<int>("AiPlayerbot.TeleToStormwindWeight", 1);
|
||||||
weightTeleToIronforge = sConfigMgr->GetOption<int>("AiPlayerbot.TeleToIronforgeWeight", 1);
|
weightTeleToIronforge = sConfigMgr->GetOption<int>("AiPlayerbot.TeleToIronforgeWeight", 1);
|
||||||
weightTeleToDarnassus = sConfigMgr->GetOption<int>("AiPlayerbot.TeleToDarnassusWeight", 1);
|
weightTeleToDarnassus = sConfigMgr->GetOption<int>("AiPlayerbot.TeleToDarnassusWeight", 1);
|
||||||
weightTeleToExodar = sConfigMgr->GetOption<int>("AiPlayerbot.TeleToExodarWeight", 1);
|
weightTeleToExodar = sConfigMgr->GetOption<int>("AiPlayerbot.TeleToExodarWeight", 1);
|
||||||
weightTeleToOrgrimmar = sConfigMgr->GetOption<int>("AiPlayerbot.TeleToOrgrimmarWeight", 2);
|
weightTeleToOrgrimmar = sConfigMgr->GetOption<int>("AiPlayerbot.TeleToOrgrimmarWeight", 1);
|
||||||
weightTeleToUndercity = sConfigMgr->GetOption<int>("AiPlayerbot.TeleToUndercityWeight", 1);
|
weightTeleToUndercity = sConfigMgr->GetOption<int>("AiPlayerbot.TeleToUndercityWeight", 1);
|
||||||
weightTeleToThunderBluff = sConfigMgr->GetOption<int>("AiPlayerbot.TeleToThunderBluffWeight", 1);
|
weightTeleToThunderBluff = sConfigMgr->GetOption<int>("AiPlayerbot.TeleToThunderBluffWeight", 1);
|
||||||
weightTeleToSilvermoonCity = sConfigMgr->GetOption<int>("AiPlayerbot.TeleToSilvermoonCityWeight", 1);
|
weightTeleToSilvermoonCity = sConfigMgr->GetOption<int>("AiPlayerbot.TeleToSilvermoonCityWeight", 1);
|
||||||
@@ -155,7 +155,7 @@ bool PlayerbotAIConfig::Initialize()
|
|||||||
weightTeleToDalaran = sConfigMgr->GetOption<int>("AiPlayerbot.TeleToDalaranWeight", 1);
|
weightTeleToDalaran = sConfigMgr->GetOption<int>("AiPlayerbot.TeleToDalaranWeight", 1);
|
||||||
LoadList<std::vector<uint32>>(
|
LoadList<std::vector<uint32>>(
|
||||||
sConfigMgr->GetOption<std::string>("AiPlayerbot.RandomBotQuestItems",
|
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);
|
randomBotQuestItems);
|
||||||
LoadList<std::vector<uint32>>(sConfigMgr->GetOption<std::string>("AiPlayerbot.RandomBotSpellIds", "54197"),
|
LoadList<std::vector<uint32>>(sConfigMgr->GetOption<std::string>("AiPlayerbot.RandomBotSpellIds", "54197"),
|
||||||
randomBotSpellIds);
|
randomBotSpellIds);
|
||||||
@@ -166,11 +166,11 @@ bool PlayerbotAIConfig::Initialize()
|
|||||||
pvpProhibitedZoneIds);
|
pvpProhibitedZoneIds);
|
||||||
LoadList<std::vector<uint32>>(
|
LoadList<std::vector<uint32>>(
|
||||||
sConfigMgr->GetOption<std::string>("AiPlayerbot.PvpProhibitedAreaIds",
|
sConfigMgr->GetOption<std::string>("AiPlayerbot.PvpProhibitedAreaIds",
|
||||||
"976,35,392,2268,4161,4010,4317,4312,3649,3887,3958,3724,4080,3938,3754,3786,3973"),
|
"976,35,392,2268,4161,4010,4317,4312,3649,3887,3958,3724,4080,3938,3754"),
|
||||||
pvpProhibitedAreaIds);
|
pvpProhibitedAreaIds);
|
||||||
fastReactInBG = sConfigMgr->GetOption<bool>("AiPlayerbot.FastReactInBG", true);
|
fastReactInBG = sConfigMgr->GetOption<bool>("AiPlayerbot.FastReactInBG", true);
|
||||||
LoadList<std::vector<uint32>>(
|
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,10277,10285,11492,13188,13189,24499,24511,24710,24712"),
|
||||||
randomBotQuestIds);
|
randomBotQuestIds);
|
||||||
|
|
||||||
LoadSet<std::set<uint32>>(
|
LoadSet<std::set<uint32>>(
|
||||||
@@ -181,8 +181,8 @@ bool PlayerbotAIConfig::Initialize()
|
|||||||
disallowedGameObjects);
|
disallowedGameObjects);
|
||||||
botAutologin = sConfigMgr->GetOption<bool>("AiPlayerbot.BotAutologin", false);
|
botAutologin = sConfigMgr->GetOption<bool>("AiPlayerbot.BotAutologin", false);
|
||||||
randomBotAutologin = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotAutologin", true);
|
randomBotAutologin = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotAutologin", true);
|
||||||
minRandomBots = sConfigMgr->GetOption<int32>("AiPlayerbot.MinRandomBots", 500);
|
minRandomBots = sConfigMgr->GetOption<int32>("AiPlayerbot.MinRandomBots", 50);
|
||||||
maxRandomBots = sConfigMgr->GetOption<int32>("AiPlayerbot.MaxRandomBots", 500);
|
maxRandomBots = sConfigMgr->GetOption<int32>("AiPlayerbot.MaxRandomBots", 50);
|
||||||
randomBotUpdateInterval = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotUpdateInterval", 20);
|
randomBotUpdateInterval = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotUpdateInterval", 20);
|
||||||
randomBotCountChangeMinInterval =
|
randomBotCountChangeMinInterval =
|
||||||
sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotCountChangeMinInterval", 30 * MINUTE);
|
sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotCountChangeMinInterval", 30 * MINUTE);
|
||||||
@@ -200,8 +200,8 @@ bool PlayerbotAIConfig::Initialize()
|
|||||||
maxRandomBotReviveTime = sConfigMgr->GetOption<int32>("AiPlayerbot.MaxRandomBotReviveTime", 5 * MINUTE);
|
maxRandomBotReviveTime = sConfigMgr->GetOption<int32>("AiPlayerbot.MaxRandomBotReviveTime", 5 * MINUTE);
|
||||||
minRandomBotTeleportInterval = sConfigMgr->GetOption<int32>("AiPlayerbot.MinRandomBotTeleportInterval", 1 * HOUR);
|
minRandomBotTeleportInterval = sConfigMgr->GetOption<int32>("AiPlayerbot.MinRandomBotTeleportInterval", 1 * HOUR);
|
||||||
maxRandomBotTeleportInterval = sConfigMgr->GetOption<int32>("AiPlayerbot.MaxRandomBotTeleportInterval", 5 * HOUR);
|
maxRandomBotTeleportInterval = sConfigMgr->GetOption<int32>("AiPlayerbot.MaxRandomBotTeleportInterval", 5 * HOUR);
|
||||||
permanentlyInWorldTime =
|
permanantlyInWorldTime =
|
||||||
sConfigMgr->GetOption<int32>("AiPlayerbot.PermanentlyInWorldTime", 1 * YEAR);
|
sConfigMgr->GetOption<int32>("AiPlayerbot.PermanantlyInWorldTime", 1 * YEAR);
|
||||||
randomBotTeleportDistance = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotTeleportDistance", 100);
|
randomBotTeleportDistance = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotTeleportDistance", 100);
|
||||||
randomBotsPerInterval = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotsPerInterval", 60);
|
randomBotsPerInterval = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotsPerInterval", 60);
|
||||||
minRandomBotsPriceChangeInterval =
|
minRandomBotsPriceChangeInterval =
|
||||||
@@ -223,11 +223,6 @@ bool PlayerbotAIConfig::Initialize()
|
|||||||
|
|
||||||
EnableICCBuffs = sConfigMgr->GetOption<bool>("AiPlayerbot.EnableICCBuffs", true);
|
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
|
//////////////////////////// CHAT
|
||||||
enableBroadcasts = sConfigMgr->GetOption<bool>("AiPlayerbot.EnableBroadcasts", true);
|
enableBroadcasts = sConfigMgr->GetOption<bool>("AiPlayerbot.EnableBroadcasts", true);
|
||||||
randomBotTalk = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotTalk", false);
|
randomBotTalk = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotTalk", false);
|
||||||
@@ -396,8 +391,8 @@ bool PlayerbotAIConfig::Initialize()
|
|||||||
|
|
||||||
randomBotCombatStrategies = sConfigMgr->GetOption<std::string>("AiPlayerbot.RandomBotCombatStrategies", "");
|
randomBotCombatStrategies = sConfigMgr->GetOption<std::string>("AiPlayerbot.RandomBotCombatStrategies", "");
|
||||||
randomBotNonCombatStrategies = sConfigMgr->GetOption<std::string>("AiPlayerbot.RandomBotNonCombatStrategies", "");
|
randomBotNonCombatStrategies = sConfigMgr->GetOption<std::string>("AiPlayerbot.RandomBotNonCombatStrategies", "");
|
||||||
combatStrategies = sConfigMgr->GetOption<std::string>("AiPlayerbot.CombatStrategies", "");
|
combatStrategies = sConfigMgr->GetOption<std::string>("AiPlayerbot.CombatStrategies", "+custom::say");
|
||||||
nonCombatStrategies = sConfigMgr->GetOption<std::string>("AiPlayerbot.NonCombatStrategies", "");
|
nonCombatStrategies = sConfigMgr->GetOption<std::string>("AiPlayerbot.NonCombatStrategies", "+custom::say,+return");
|
||||||
applyInstanceStrategies = sConfigMgr->GetOption<bool>("AiPlayerbot.ApplyInstanceStrategies", true);
|
applyInstanceStrategies = sConfigMgr->GetOption<bool>("AiPlayerbot.ApplyInstanceStrategies", true);
|
||||||
|
|
||||||
commandPrefix = sConfigMgr->GetOption<std::string>("AiPlayerbot.CommandPrefix", "");
|
commandPrefix = sConfigMgr->GetOption<std::string>("AiPlayerbot.CommandPrefix", "");
|
||||||
@@ -517,7 +512,7 @@ bool PlayerbotAIConfig::Initialize()
|
|||||||
randomBotGuildSizeMax = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotGuildSizeMax", 15);
|
randomBotGuildSizeMax = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotGuildSizeMax", 15);
|
||||||
deleteRandomBotGuilds = sConfigMgr->GetOption<bool>("AiPlayerbot.DeleteRandomBotGuilds", false);
|
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);
|
minGuildTaskChangeTime = sConfigMgr->GetOption<int32>("AiPlayerbot.MinGuildTaskChangeTime", 3 * 24 * 3600);
|
||||||
maxGuildTaskChangeTime = sConfigMgr->GetOption<int32>("AiPlayerbot.MaxGuildTaskChangeTime", 4 * 24 * 3600);
|
maxGuildTaskChangeTime = sConfigMgr->GetOption<int32>("AiPlayerbot.MaxGuildTaskChangeTime", 4 * 24 * 3600);
|
||||||
minGuildTaskAdvertisementTime = sConfigMgr->GetOption<int32>("AiPlayerbot.MinGuildTaskAdvertisementTime", 300);
|
minGuildTaskAdvertisementTime = sConfigMgr->GetOption<int32>("AiPlayerbot.MinGuildTaskAdvertisementTime", 300);
|
||||||
@@ -603,12 +598,12 @@ bool PlayerbotAIConfig::Initialize()
|
|||||||
minEnchantingBotLevel = sConfigMgr->GetOption<int32>("AiPlayerbot.MinEnchantingBotLevel", 60);
|
minEnchantingBotLevel = sConfigMgr->GetOption<int32>("AiPlayerbot.MinEnchantingBotLevel", 60);
|
||||||
limitEnchantExpansion = sConfigMgr->GetOption<int32>("AiPlayerbot.LimitEnchantExpansion", 1);
|
limitEnchantExpansion = sConfigMgr->GetOption<int32>("AiPlayerbot.LimitEnchantExpansion", 1);
|
||||||
limitGearExpansion = sConfigMgr->GetOption<int32>("AiPlayerbot.LimitGearExpansion", 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);
|
enablePeriodicOnlineOffline = sConfigMgr->GetOption<bool>("AiPlayerbot.EnablePeriodicOnlineOffline", false);
|
||||||
enableRandomBotTrading = sConfigMgr->GetOption<int32>("AiPlayerbot.EnableRandomBotTrading", 1);
|
enableRandomBotTrading = sConfigMgr->GetOption<int32>("AiPlayerbot.EnableRandomBotTrading", 1);
|
||||||
periodicOnlineOfflineRatio = sConfigMgr->GetOption<float>("AiPlayerbot.PeriodicOnlineOfflineRatio", 2.0);
|
periodicOnlineOfflineRatio = sConfigMgr->GetOption<float>("AiPlayerbot.PeriodicOnlineOfflineRatio", 2.0);
|
||||||
gearscorecheck = sConfigMgr->GetOption<bool>("AiPlayerbot.GearScoreCheck", false);
|
gearscorecheck = sConfigMgr->GetOption<bool>("AiPlayerbot.GearScoreCheck", false);
|
||||||
randomBotPreQuests = sConfigMgr->GetOption<bool>("AiPlayerbot.PreQuests", false);
|
randomBotPreQuests = sConfigMgr->GetOption<bool>("AiPlayerbot.PreQuests", true);
|
||||||
|
|
||||||
// SPP automation
|
// SPP automation
|
||||||
freeMethodLoot = sConfigMgr->GetOption<bool>("AiPlayerbot.FreeMethodLoot", false);
|
freeMethodLoot = sConfigMgr->GetOption<bool>("AiPlayerbot.FreeMethodLoot", false);
|
||||||
@@ -641,7 +636,7 @@ bool PlayerbotAIConfig::Initialize()
|
|||||||
RpgStatusProbWeight[RPG_REST] = sConfigMgr->GetOption<int32>("AiPlayerbot.RpgStatusProbWeight.Rest", 5);
|
RpgStatusProbWeight[RPG_REST] = sConfigMgr->GetOption<int32>("AiPlayerbot.RpgStatusProbWeight.Rest", 5);
|
||||||
|
|
||||||
syncLevelWithPlayers = sConfigMgr->GetOption<bool>("AiPlayerbot.SyncLevelWithPlayers", false);
|
syncLevelWithPlayers = sConfigMgr->GetOption<bool>("AiPlayerbot.SyncLevelWithPlayers", false);
|
||||||
randomBotGroupNearby = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotGroupNearby", false);
|
randomBotGroupNearby = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotGroupNearby", true);
|
||||||
|
|
||||||
// arena
|
// arena
|
||||||
randomBotArenaTeam2v2Count = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotArenaTeam2v2Count", 10);
|
randomBotArenaTeam2v2Count = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotArenaTeam2v2Count", 10);
|
||||||
@@ -667,7 +662,6 @@ bool PlayerbotAIConfig::Initialize()
|
|||||||
sRandomPlayerbotMgr->Init();
|
sRandomPlayerbotMgr->Init();
|
||||||
}
|
}
|
||||||
|
|
||||||
sPlayerbotGuildMgr->Init();
|
|
||||||
sRandomItemMgr->Init();
|
sRandomItemMgr->Init();
|
||||||
sRandomItemMgr->InitAfterAhBot();
|
sRandomItemMgr->InitAfterAhBot();
|
||||||
sPlayerbotTextMgr->LoadBotTexts();
|
sPlayerbotTextMgr->LoadBotTexts();
|
||||||
@@ -678,14 +672,14 @@ bool PlayerbotAIConfig::Initialize()
|
|||||||
|
|
||||||
if (sPlayerbotAIConfig->randomBotSuggestDungeons)
|
if (sPlayerbotAIConfig->randomBotSuggestDungeons)
|
||||||
{
|
{
|
||||||
sPlayerbotDungeonRepository->LoadDungeonSuggestions();
|
sPlayerbotDungeonSuggestionMgr->LoadDungeonSuggestions();
|
||||||
}
|
}
|
||||||
|
|
||||||
excludedHunterPetFamilies.clear();
|
excludedHunterPetFamilies.clear();
|
||||||
LoadList<std::vector<uint32>>(sConfigMgr->GetOption<std::string>("AiPlayerbot.ExcludedHunterPetFamilies", ""), excludedHunterPetFamilies);
|
LoadList<std::vector<uint32>>(sConfigMgr->GetOption<std::string>("AiPlayerbot.ExcludedHunterPetFamilies", ""), excludedHunterPetFamilies);
|
||||||
|
|
||||||
LOG_INFO("server.loading", "---------------------------------------");
|
LOG_INFO("server.loading", "---------------------------------------");
|
||||||
LOG_INFO("server.loading", " mod-playerbots initialized ");
|
LOG_INFO("server.loading", " AI Playerbots initialized ");
|
||||||
LOG_INFO("server.loading", "---------------------------------------");
|
LOG_INFO("server.loading", "---------------------------------------");
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -732,8 +726,8 @@ std::string const PlayerbotAIConfig::GetTimestampStr()
|
|||||||
// HH hour (2 digits 00-23)
|
// HH hour (2 digits 00-23)
|
||||||
// MM minutes (2 digits 00-59)
|
// MM minutes (2 digits 00-59)
|
||||||
// SS seconds (2 digits 00-59)
|
// SS seconds (2 digits 00-59)
|
||||||
char buf[32];
|
char buf[20];
|
||||||
snprintf(buf, sizeof(buf), "%04d-%02d-%02d %02d-%02d-%02d", aTm->tm_year + 1900, aTm->tm_mon + 1, aTm->tm_mday, aTm->tm_hour,
|
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);
|
aTm->tm_min, aTm->tm_sec);
|
||||||
return std::string(buf);
|
return std::string(buf);
|
||||||
}
|
}
|
||||||
@@ -132,7 +132,7 @@ public:
|
|||||||
uint32 minRandomBotChangeStrategyTime, maxRandomBotChangeStrategyTime;
|
uint32 minRandomBotChangeStrategyTime, maxRandomBotChangeStrategyTime;
|
||||||
uint32 minRandomBotReviveTime, maxRandomBotReviveTime;
|
uint32 minRandomBotReviveTime, maxRandomBotReviveTime;
|
||||||
uint32 minRandomBotTeleportInterval, maxRandomBotTeleportInterval;
|
uint32 minRandomBotTeleportInterval, maxRandomBotTeleportInterval;
|
||||||
uint32 permanentlyInWorldTime;
|
uint32 permanantlyInWorldTime;
|
||||||
uint32 minRandomBotPvpTime, maxRandomBotPvpTime;
|
uint32 minRandomBotPvpTime, maxRandomBotPvpTime;
|
||||||
uint32 randomBotsPerInterval;
|
uint32 randomBotsPerInterval;
|
||||||
uint32 minRandomBotsPriceChangeInterval, maxRandomBotsPriceChangeInterval;
|
uint32 minRandomBotsPriceChangeInterval, maxRandomBotsPriceChangeInterval;
|
||||||
@@ -145,10 +145,6 @@ public:
|
|||||||
// Cooldown (seconds) between reagent-missing RP warnings, per bot & per buff. Default: 30
|
// Cooldown (seconds) between reagent-missing RP warnings, per bot & per buff. Default: 30
|
||||||
int32 rpWarningCooldown;
|
int32 rpWarningCooldown;
|
||||||
|
|
||||||
// Professions
|
|
||||||
bool enableFishingWithMaster;
|
|
||||||
float fishingDistanceFromMaster, fishingDistance, endFishingWithMaster;
|
|
||||||
|
|
||||||
// chat
|
// chat
|
||||||
bool randomBotTalk;
|
bool randomBotTalk;
|
||||||
bool randomBotEmote;
|
bool randomBotEmote;
|
||||||
@@ -273,6 +269,7 @@ public:
|
|||||||
bool deleteRandomBotAccounts;
|
bool deleteRandomBotAccounts;
|
||||||
uint32 randomBotGuildCount, randomBotGuildSizeMax;
|
uint32 randomBotGuildCount, randomBotGuildSizeMax;
|
||||||
bool deleteRandomBotGuilds;
|
bool deleteRandomBotGuilds;
|
||||||
|
std::vector<uint32> randomBotGuilds;
|
||||||
std::vector<uint32> pvpProhibitedZoneIds;
|
std::vector<uint32> pvpProhibitedZoneIds;
|
||||||
std::vector<uint32> pvpProhibitedAreaIds;
|
std::vector<uint32> pvpProhibitedAreaIds;
|
||||||
bool fastReactInBG;
|
bool fastReactInBG;
|
||||||
@@ -3,13 +3,13 @@
|
|||||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "PlayerbotRepository.h"
|
#include "PlayerbotDbStore.h"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
|
|
||||||
void PlayerbotRepository::Load(PlayerbotAI* botAI)
|
void PlayerbotDbStore::Load(PlayerbotAI* botAI)
|
||||||
{
|
{
|
||||||
ObjectGuid::LowType guid = botAI->GetBot()->GetGUID().GetCounter();
|
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();
|
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)));
|
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;
|
std::ostringstream out;
|
||||||
for (std::vector<std::string>::iterator i = strategies.begin(); i != strategies.end(); ++i)
|
for (std::vector<std::string>::iterator i = strategies.begin(); i != strategies.end(); ++i)
|
||||||
@@ -78,7 +78,7 @@ std::string const PlayerbotRepository::FormatStrategies(std::string const type,
|
|||||||
return res.substr(0, res.size() - 1);
|
return res.substr(0, res.size() - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerbotRepository::Reset(PlayerbotAI* botAI)
|
void PlayerbotDbStore::Reset(PlayerbotAI* botAI)
|
||||||
{
|
{
|
||||||
ObjectGuid::LowType guid = botAI->GetBot()->GetGUID().GetCounter();
|
ObjectGuid::LowType guid = botAI->GetBot()->GetGUID().GetCounter();
|
||||||
|
|
||||||
@@ -87,7 +87,7 @@ void PlayerbotRepository::Reset(PlayerbotAI* botAI)
|
|||||||
PlayerbotsDatabase.Execute(stmt);
|
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);
|
PlayerbotsDatabasePreparedStatement* stmt = PlayerbotsDatabase.GetPreparedStatement(PLAYERBOTS_INS_DB_STORE);
|
||||||
stmt->SetData(0, guid);
|
stmt->SetData(0, guid);
|
||||||
@@ -3,8 +3,8 @@
|
|||||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _PLAYERBOT_PLAYERBOTREPOSITORY_H
|
#ifndef _PLAYERBOT_PLAYERBOTDBSTORE_H
|
||||||
#define _PLAYERBOT_PLAYERBOTREPOSITORY_H
|
#define _PLAYERBOT_PLAYERBOTDBSTORE_H
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@@ -12,14 +12,14 @@
|
|||||||
|
|
||||||
class PlayerbotAI;
|
class PlayerbotAI;
|
||||||
|
|
||||||
class PlayerbotRepository
|
class PlayerbotDbStore
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
PlayerbotRepository() {}
|
PlayerbotDbStore() {}
|
||||||
virtual ~PlayerbotRepository() {}
|
virtual ~PlayerbotDbStore() {}
|
||||||
static PlayerbotRepository* instance()
|
static PlayerbotDbStore* instance()
|
||||||
{
|
{
|
||||||
static PlayerbotRepository instance;
|
static PlayerbotDbStore instance;
|
||||||
return &instance;
|
return &instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -32,6 +32,6 @@ private:
|
|||||||
std::string const FormatStrategies(std::string const type, std::vector<std::string> strategies);
|
std::string const FormatStrategies(std::string const type, std::vector<std::string> strategies);
|
||||||
};
|
};
|
||||||
|
|
||||||
#define sPlayerbotRepository PlayerbotRepository::instance()
|
#define sPlayerbotDbStore PlayerbotDbStore::instance()
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -3,16 +3,16 @@
|
|||||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "PlayerbotDungeonRepository.h"
|
#include "PlayerbotDungeonSuggestionMgr.h"
|
||||||
|
|
||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
|
|
||||||
std::vector<DungeonSuggestion> const PlayerbotDungeonRepository::GetDungeonSuggestions()
|
std::vector<DungeonSuggestion> const PlayerbotDungeonSuggestionMgr::GetDungeonSuggestions()
|
||||||
{
|
{
|
||||||
return m_dungeonSuggestions;
|
return m_dungeonSuggestions;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerbotDungeonRepository::LoadDungeonSuggestions()
|
void PlayerbotDungeonSuggestionMgr::LoadDungeonSuggestions()
|
||||||
{
|
{
|
||||||
LOG_INFO("server.loading", "Loading playerbots dungeon suggestions...");
|
LOG_INFO("server.loading", "Loading playerbots dungeon suggestions...");
|
||||||
uint32 oldMSTime = getMSTime();
|
uint32 oldMSTime = getMSTime();
|
||||||
@@ -3,8 +3,8 @@
|
|||||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _PLAYERBOT_PLAYERBOTDUNGEONREPOSITORY_H
|
#ifndef _PLAYERBOT_PLAYERBOTDUNGEONSUGGESTIONMGR_H
|
||||||
#define _PLAYERBOT_PLAYERBOTDUNGEONREPOSITORY_H
|
#define _PLAYERBOT_PLAYERBOTDUNGEONSUGGESTIONMGR_H
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@@ -22,14 +22,14 @@ struct DungeonSuggestion
|
|||||||
std::string strategy;
|
std::string strategy;
|
||||||
};
|
};
|
||||||
|
|
||||||
class PlayerbotDungeonRepository
|
class PlayerbotDungeonSuggestionMgr
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
PlayerbotDungeonRepository(){};
|
PlayerbotDungeonSuggestionMgr(){};
|
||||||
~PlayerbotDungeonRepository(){};
|
~PlayerbotDungeonSuggestionMgr(){};
|
||||||
static PlayerbotDungeonRepository* instance()
|
static PlayerbotDungeonSuggestionMgr* instance()
|
||||||
{
|
{
|
||||||
static PlayerbotDungeonRepository instance;
|
static PlayerbotDungeonSuggestionMgr instance;
|
||||||
return &instance;
|
return &instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,6 +40,6 @@ private:
|
|||||||
std::vector<DungeonSuggestion> m_dungeonSuggestions;
|
std::vector<DungeonSuggestion> m_dungeonSuggestions;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define sPlayerbotDungeonRepository PlayerbotDungeonRepository::instance()
|
#define sPlayerbotDungeonSuggestionMgr PlayerbotDungeonSuggestionMgr::instance()
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -9,10 +9,9 @@
|
|||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <istream>
|
#include <istream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_set>
|
|
||||||
#include <openssl/sha.h>
|
#include <openssl/sha.h>
|
||||||
|
#include <unordered_set>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
#include "ChannelMgr.h"
|
#include "ChannelMgr.h"
|
||||||
#include "CharacterCache.h"
|
#include "CharacterCache.h"
|
||||||
@@ -26,19 +25,19 @@
|
|||||||
#include "ObjectGuid.h"
|
#include "ObjectGuid.h"
|
||||||
#include "ObjectMgr.h"
|
#include "ObjectMgr.h"
|
||||||
#include "PlayerbotAIConfig.h"
|
#include "PlayerbotAIConfig.h"
|
||||||
#include "PlayerbotRepository.h"
|
#include "PlayerbotDbStore.h"
|
||||||
#include "PlayerbotFactory.h"
|
#include "PlayerbotFactory.h"
|
||||||
#include "PlayerbotOperations.h"
|
|
||||||
#include "PlayerbotSecurity.h"
|
#include "PlayerbotSecurity.h"
|
||||||
#include "PlayerbotWorldThreadProcessor.h"
|
|
||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
#include "PlayerbotGuildMgr.h"
|
|
||||||
#include "RandomPlayerbotMgr.h"
|
#include "RandomPlayerbotMgr.h"
|
||||||
#include "SharedDefines.h"
|
#include "SharedDefines.h"
|
||||||
#include "WorldSession.h"
|
#include "WorldSession.h"
|
||||||
|
#include "ChannelMgr.h"
|
||||||
#include "BroadcastHelper.h"
|
#include "BroadcastHelper.h"
|
||||||
|
#include "PlayerbotDbStore.h"
|
||||||
#include "WorldSessionMgr.h"
|
#include "WorldSessionMgr.h"
|
||||||
#include "DatabaseEnv.h"
|
#include "DatabaseEnv.h" // Added for gender choice
|
||||||
|
#include <algorithm> // Added for gender choice
|
||||||
|
|
||||||
class BotInitGuard
|
class BotInitGuard
|
||||||
{
|
{
|
||||||
@@ -67,7 +66,6 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
std::unordered_set<ObjectGuid> BotInitGuard::botsBeingInitialized;
|
std::unordered_set<ObjectGuid> BotInitGuard::botsBeingInitialized;
|
||||||
std::unordered_set<ObjectGuid> PlayerbotHolder::botLoading;
|
|
||||||
|
|
||||||
PlayerbotHolder::PlayerbotHolder() : PlayerbotAIBase(false) {}
|
PlayerbotHolder::PlayerbotHolder() : PlayerbotAIBase(false) {}
|
||||||
class PlayerbotLoginQueryHolder : public LoginQueryHolder
|
class PlayerbotLoginQueryHolder : public LoginQueryHolder
|
||||||
@@ -76,16 +74,18 @@ private:
|
|||||||
uint32 masterAccountId;
|
uint32 masterAccountId;
|
||||||
PlayerbotHolder* playerbotHolder;
|
PlayerbotHolder* playerbotHolder;
|
||||||
public:
|
public:
|
||||||
PlayerbotLoginQueryHolder(uint32 masterAccount, uint32 accountId, ObjectGuid guid)
|
PlayerbotLoginQueryHolder(PlayerbotHolder* playerbotHolder, uint32 masterAccount, uint32 accountId, ObjectGuid guid)
|
||||||
: LoginQueryHolder(accountId, guid), masterAccountId(masterAccount)
|
: LoginQueryHolder(accountId, guid), masterAccountId(masterAccount), playerbotHolder(playerbotHolder)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 GetMasterAccountId() const { return masterAccountId; }
|
uint32 GetMasterAccountId() const { return masterAccountId; }
|
||||||
|
PlayerbotHolder* GetPlayerbotHolder() { return playerbotHolder; }
|
||||||
};
|
};
|
||||||
|
|
||||||
void PlayerbotHolder::AddPlayerBot(ObjectGuid playerGuid, uint32 masterAccountId)
|
void PlayerbotHolder::AddPlayerBot(ObjectGuid playerGuid, uint32 masterAccountId)
|
||||||
{
|
{
|
||||||
|
// bot is loading
|
||||||
if (botLoading.find(playerGuid) != botLoading.end())
|
if (botLoading.find(playerGuid) != botLoading.end())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -142,7 +142,7 @@ void PlayerbotHolder::AddPlayerBot(ObjectGuid playerGuid, uint32 masterAccountId
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
std::shared_ptr<PlayerbotLoginQueryHolder> holder =
|
std::shared_ptr<PlayerbotLoginQueryHolder> holder =
|
||||||
std::make_shared<PlayerbotLoginQueryHolder>(masterAccountId, accountId, playerGuid);
|
std::make_shared<PlayerbotLoginQueryHolder>(this, masterAccountId, accountId, playerGuid);
|
||||||
if (!holder->Initialize())
|
if (!holder->Initialize())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@@ -152,27 +152,8 @@ void PlayerbotHolder::AddPlayerBot(ObjectGuid playerGuid, uint32 masterAccountId
|
|||||||
|
|
||||||
// Always login in with world session to avoid race condition
|
// Always login in with world session to avoid race condition
|
||||||
sWorld->AddQueryHolderCallback(CharacterDatabase.DelayQueryHolder(holder))
|
sWorld->AddQueryHolderCallback(CharacterDatabase.DelayQueryHolder(holder))
|
||||||
.AfterComplete(
|
.AfterComplete([this](SQLQueryHolderBase const& holder)
|
||||||
[](SQLQueryHolderBase const& queryHolder)
|
{ HandlePlayerBotLoginCallback(static_cast<PlayerbotLoginQueryHolder const&>(holder)); });
|
||||||
{
|
|
||||||
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());
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PlayerbotHolder::IsAccountLinked(uint32 accountId, uint32 linkedAccountId)
|
bool PlayerbotHolder::IsAccountLinked(uint32 accountId, uint32 linkedAccountId)
|
||||||
@@ -187,9 +168,8 @@ void PlayerbotHolder::HandlePlayerBotLoginCallback(PlayerbotLoginQueryHolder con
|
|||||||
uint32 botAccountId = holder.GetAccountId();
|
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
|
// 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)
|
// allows channels to work as intended)
|
||||||
WorldSession* botSession =
|
WorldSession* botSession = new WorldSession(botAccountId, "", 0x0, nullptr, SEC_PLAYER, EXPANSION_WRATH_OF_THE_LICH_KING,
|
||||||
new WorldSession(botAccountId, "", 0x0, nullptr, SEC_PLAYER, EXPANSION_WRATH_OF_THE_LICH_KING, time_t(0),
|
time_t(0), sWorld->GetDefaultDbcLocale(), 0, false, false, 0, true);
|
||||||
sWorld->GetDefaultDbcLocale(), 0, false, false, 0, true);
|
|
||||||
|
|
||||||
botSession->HandlePlayerLoginFromDB(holder); // will delete lqh
|
botSession->HandlePlayerLoginFromDB(holder); // will delete lqh
|
||||||
|
|
||||||
@@ -200,27 +180,24 @@ void PlayerbotHolder::HandlePlayerBotLoginCallback(PlayerbotLoginQueryHolder con
|
|||||||
LOG_DEBUG("mod-playerbots", "Bot player could not be loaded for account ID: {}", botAccountId);
|
LOG_DEBUG("mod-playerbots", "Bot player could not be loaded for account ID: {}", botAccountId);
|
||||||
botSession->LogoutPlayer(true);
|
botSession->LogoutPlayer(true);
|
||||||
delete botSession;
|
delete botSession;
|
||||||
PlayerbotHolder::botLoading.erase(holder.GetGuid());
|
botLoading.erase(holder.GetGuid());
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 masterAccountId = holder.GetMasterAccountId();
|
uint32 masterAccount = holder.GetMasterAccountId();
|
||||||
WorldSession* masterSession = masterAccountId ? sWorldSessionMgr->FindSession(masterAccountId) : nullptr;
|
WorldSession* masterSession = masterAccount ? sWorldSessionMgr->FindSession(masterAccount) : nullptr;
|
||||||
|
|
||||||
// Check if masterSession->GetPlayer() is valid
|
// Check if masterSession->GetPlayer() is valid
|
||||||
Player* masterPlayer = masterSession ? masterSession->GetPlayer() : nullptr;
|
Player* masterPlayer = masterSession ? masterSession->GetPlayer() : nullptr;
|
||||||
if (masterSession && !masterPlayer)
|
if (masterSession && !masterPlayer)
|
||||||
{
|
{
|
||||||
LOG_DEBUG("mod-playerbots", "Master session found but no player is associated for master account ID: {}",
|
LOG_DEBUG("mod-playerbots", "Master session found but no player is associated for master account ID: {}", masterAccount);
|
||||||
masterAccountId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sRandomPlayerbotMgr->OnPlayerLogin(bot);
|
sRandomPlayerbotMgr->OnPlayerLogin(bot);
|
||||||
auto op = std::make_unique<OnBotLoginOperation>(bot->GetGUID(), masterAccountId);
|
OnBotLogin(bot);
|
||||||
sPlayerbotWorldProcessor->QueueOperation(std::move(op));
|
|
||||||
|
|
||||||
PlayerbotHolder::botLoading.erase(holder.GetGuid());
|
botLoading.erase(holder.GetGuid());
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerbotHolder::UpdateSessions()
|
void PlayerbotHolder::UpdateSessions()
|
||||||
@@ -339,9 +316,11 @@ void PlayerbotHolder::LogoutPlayerBot(ObjectGuid guid)
|
|||||||
if (!botAI)
|
if (!botAI)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Queue group cleanup operation for world thread
|
Group* group = bot->GetGroup();
|
||||||
auto cleanupOp = std::make_unique<BotLogoutGroupCleanupOperation>(guid);
|
if (group && !bot->InBattleground() && !bot->InBattlegroundQueue() && botAI->HasActivePlayerMaster())
|
||||||
sPlayerbotWorldProcessor->QueueOperation(std::move(cleanupOp));
|
{
|
||||||
|
sPlayerbotDbStore->Save(botAI);
|
||||||
|
}
|
||||||
|
|
||||||
LOG_DEBUG("playerbots", "Bot {} logging out", bot->GetName().c_str());
|
LOG_DEBUG("playerbots", "Bot {} logging out", bot->GetName().c_str());
|
||||||
bot->SaveToDB(false, false);
|
bot->SaveToDB(false, false);
|
||||||
@@ -442,7 +421,7 @@ void PlayerbotHolder::DisablePlayerBot(ObjectGuid guid)
|
|||||||
Group* group = bot->GetGroup();
|
Group* group = bot->GetGroup();
|
||||||
if (group && !bot->InBattleground() && !bot->InBattlegroundQueue() && botAI->HasActivePlayerMaster())
|
if (group && !bot->InBattleground() && !bot->InBattlegroundQueue() && botAI->HasActivePlayerMaster())
|
||||||
{
|
{
|
||||||
sPlayerbotRepository->Save(botAI);
|
sPlayerbotDbStore->Save(botAI);
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_DEBUG("playerbots", "Bot {} logged out", bot->GetName().c_str());
|
LOG_DEBUG("playerbots", "Bot {} logged out", bot->GetName().c_str());
|
||||||
@@ -554,7 +533,7 @@ void PlayerbotHolder::OnBotLogin(Player* const bot)
|
|||||||
{
|
{
|
||||||
botAI->ResetStrategies(!sRandomPlayerbotMgr->IsRandomBot(bot));
|
botAI->ResetStrategies(!sRandomPlayerbotMgr->IsRandomBot(bot));
|
||||||
}
|
}
|
||||||
sPlayerbotRepository->Load(botAI);
|
sPlayerbotDbStore->Load(botAI);
|
||||||
|
|
||||||
if (master && !master->HasUnitState(UNIT_STATE_IN_FLIGHT))
|
if (master && !master->HasUnitState(UNIT_STATE_IN_FLIGHT))
|
||||||
{
|
{
|
||||||
@@ -570,7 +549,6 @@ void PlayerbotHolder::OnBotLogin(Player* const bot)
|
|||||||
|
|
||||||
botAI->TellMaster("Hello!", PLAYERBOT_SECURITY_TALK);
|
botAI->TellMaster("Hello!", PLAYERBOT_SECURITY_TALK);
|
||||||
|
|
||||||
// Queue group operations for world thread
|
|
||||||
if (master && master->GetGroup() && !group)
|
if (master && master->GetGroup() && !group)
|
||||||
{
|
{
|
||||||
Group* mgroup = master->GetGroup();
|
Group* mgroup = master->GetGroup();
|
||||||
@@ -578,29 +556,24 @@ void PlayerbotHolder::OnBotLogin(Player* const bot)
|
|||||||
{
|
{
|
||||||
if (!mgroup->isRaidGroup() && !mgroup->isLFGGroup() && !mgroup->isBGGroup() && !mgroup->isBFGroup())
|
if (!mgroup->isRaidGroup() && !mgroup->isLFGGroup() && !mgroup->isBGGroup() && !mgroup->isBFGroup())
|
||||||
{
|
{
|
||||||
// Queue ConvertToRaid operation
|
mgroup->ConvertToRaid();
|
||||||
auto convertOp = std::make_unique<GroupConvertToRaidOperation>(master->GetGUID());
|
|
||||||
sPlayerbotWorldProcessor->QueueOperation(std::move(convertOp));
|
|
||||||
}
|
}
|
||||||
if (mgroup->isRaidGroup())
|
if (mgroup->isRaidGroup())
|
||||||
{
|
{
|
||||||
// Queue AddMember operation
|
mgroup->AddMember(bot);
|
||||||
auto addOp = std::make_unique<GroupInviteOperation>(master->GetGUID(), bot->GetGUID());
|
|
||||||
sPlayerbotWorldProcessor->QueueOperation(std::move(addOp));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Queue AddMember operation
|
mgroup->AddMember(bot);
|
||||||
auto addOp = std::make_unique<GroupInviteOperation>(master->GetGUID(), bot->GetGUID());
|
|
||||||
sPlayerbotWorldProcessor->QueueOperation(std::move(addOp));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (master && !group)
|
else if (master && !group)
|
||||||
{
|
{
|
||||||
// Queue group creation and AddMember operation
|
Group* newGroup = new Group();
|
||||||
auto inviteOp = std::make_unique<GroupInviteOperation>(master->GetGUID(), bot->GetGUID());
|
newGroup->Create(master);
|
||||||
sPlayerbotWorldProcessor->QueueOperation(std::move(inviteOp));
|
sGroupMgr->AddGroup(newGroup);
|
||||||
|
newGroup->AddMember(bot);
|
||||||
}
|
}
|
||||||
// if (master)
|
// if (master)
|
||||||
// {
|
// {
|
||||||
@@ -1194,7 +1167,7 @@ std::vector<std::string> PlayerbotHolder::HandlePlayerbotCommand(char const* arg
|
|||||||
if (ObjectAccessor::FindConnectedPlayer(guid))
|
if (ObjectAccessor::FindConnectedPlayer(guid))
|
||||||
continue;
|
continue;
|
||||||
uint32 guildId = sCharacterCache->GetCharacterGuildIdByGuid(guid);
|
uint32 guildId = sCharacterCache->GetCharacterGuildIdByGuid(guid);
|
||||||
if (guildId && sPlayerbotGuildMgr->IsRealGuild(guildId))
|
if (guildId && PlayerbotAI::IsRealGuild(guildId))
|
||||||
continue;
|
continue;
|
||||||
AddPlayerBot(guid, master->GetSession()->GetAccountId());
|
AddPlayerBot(guid, master->GetSession()->GetAccountId());
|
||||||
messages.push_back("Add class " + std::string(charname));
|
messages.push_back("Add class " + std::string(charname));
|
||||||
@@ -1629,26 +1602,8 @@ void PlayerbotMgr::OnBotLoginInternal(Player* const bot)
|
|||||||
|
|
||||||
void PlayerbotMgr::OnPlayerLogin(Player* player)
|
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
|
// set locale priority for bot texts
|
||||||
sPlayerbotTextMgr->AddLocalePriority(usedLocale);
|
sPlayerbotTextMgr->AddLocalePriority(player->GetSession()->GetSessionDbcLocale());
|
||||||
|
|
||||||
if (sPlayerbotAIConfig->selfBotLevel > 2)
|
if (sPlayerbotAIConfig->selfBotLevel > 2)
|
||||||
HandlePlayerbotCommand("self", player);
|
HandlePlayerbotCommand("self", player);
|
||||||
@@ -1656,7 +1611,7 @@ void PlayerbotMgr::OnPlayerLogin(Player* player)
|
|||||||
if (!sPlayerbotAIConfig->botAutologin)
|
if (!sPlayerbotAIConfig->botAutologin)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
uint32 accountId = session->GetAccountId();
|
uint32 accountId = player->GetSession()->GetAccountId();
|
||||||
QueryResult results = CharacterDatabase.Query("SELECT name FROM characters WHERE account = {}", accountId);
|
QueryResult results = CharacterDatabase.Query("SELECT name FROM characters WHERE account = {}", accountId);
|
||||||
if (results)
|
if (results)
|
||||||
{
|
{
|
||||||
@@ -1781,8 +1736,7 @@ PlayerbotAI* PlayerbotsMgr::GetPlayerbotAI(Player* player)
|
|||||||
{
|
{
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
// if (player->GetSession()->isLogingOut() || player->IsDuringRemoveFromWorld())
|
// if (player->GetSession()->isLogingOut() || player->IsDuringRemoveFromWorld()) {
|
||||||
// {
|
|
||||||
// return nullptr;
|
// return nullptr;
|
||||||
// }
|
// }
|
||||||
auto itr = _playerbotsAIMap.find(player->GetGUID());
|
auto itr = _playerbotsAIMap.find(player->GetGUID());
|
||||||
@@ -60,7 +60,7 @@ protected:
|
|||||||
virtual void OnBotLoginInternal(Player* const bot) = 0;
|
virtual void OnBotLoginInternal(Player* const bot) = 0;
|
||||||
|
|
||||||
PlayerBotMap playerBots;
|
PlayerBotMap playerBots;
|
||||||
static std::unordered_set<ObjectGuid> botLoading;
|
std::unordered_set<ObjectGuid> botLoading;
|
||||||
};
|
};
|
||||||
|
|
||||||
class PlayerbotMgr : public PlayerbotHolder
|
class PlayerbotMgr : public PlayerbotHolder
|
||||||
@@ -17,28 +17,14 @@ PlayerbotSecurity::PlayerbotSecurity(Player* const bot) : bot(bot)
|
|||||||
|
|
||||||
PlayerbotSecurityLevel PlayerbotSecurity::LevelFor(Player* from, DenyReason* reason, bool ignoreGroup)
|
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)
|
if (from->GetSession()->GetSecurity() >= SEC_GAMEMASTER)
|
||||||
return PLAYERBOT_SECURITY_ALLOW_ALL;
|
return PLAYERBOT_SECURITY_ALLOW_ALL;
|
||||||
|
|
||||||
PlayerbotAI* botAI = GET_PLAYERBOT_AI(bot);
|
PlayerbotAI* botAI = GET_PLAYERBOT_AI(bot);
|
||||||
if (!botAI)
|
if (!botAI)
|
||||||
{
|
{
|
||||||
if (reason)
|
|
||||||
*reason = PLAYERBOT_DENY_NONE;
|
|
||||||
|
|
||||||
return PLAYERBOT_SECURITY_DENY_ALL;
|
return PLAYERBOT_SECURITY_DENY_ALL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (botAI->IsOpposing(from))
|
if (botAI->IsOpposing(from))
|
||||||
{
|
{
|
||||||
if (reason)
|
if (reason)
|
||||||
@@ -49,7 +35,6 @@ PlayerbotSecurityLevel PlayerbotSecurity::LevelFor(Player* from, DenyReason* rea
|
|||||||
|
|
||||||
if (sPlayerbotAIConfig->IsInRandomAccountList(account))
|
if (sPlayerbotAIConfig->IsInRandomAccountList(account))
|
||||||
{
|
{
|
||||||
// (duplicate check in case of faction change)
|
|
||||||
if (botAI->IsOpposing(from))
|
if (botAI->IsOpposing(from))
|
||||||
{
|
{
|
||||||
if (reason)
|
if (reason)
|
||||||
@@ -58,17 +43,27 @@ PlayerbotSecurityLevel PlayerbotSecurity::LevelFor(Player* from, DenyReason* rea
|
|||||||
return PLAYERBOT_SECURITY_DENY_ALL;
|
return PLAYERBOT_SECURITY_DENY_ALL;
|
||||||
}
|
}
|
||||||
|
|
||||||
Group* fromGroup = from->GetGroup();
|
// if (sLFGMgr->GetState(bot->GetGUID()) != lfg::LFG_STATE_NONE)
|
||||||
Group* botGroup = bot->GetGroup();
|
// {
|
||||||
|
// 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)
|
if (reason)
|
||||||
*reason = PLAYERBOT_DENY_NOT_YOURS;
|
*reason = PLAYERBOT_DENY_NOT_YOURS;
|
||||||
|
|
||||||
return PLAYERBOT_SECURITY_TALK;
|
return PLAYERBOT_SECURITY_TALK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,34 +75,27 @@ PlayerbotSecurityLevel PlayerbotSecurity::LevelFor(Player* from, DenyReason* rea
|
|||||||
return PLAYERBOT_SECURITY_TALK;
|
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 (!bot->GetGuildId() || bot->GetGuildId() != from->GetGuildId())
|
||||||
if (levelDiff > 5)
|
|
||||||
{
|
{
|
||||||
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 botGS = (int32)botAI->GetEquipGearScore(bot/*, false, false*/);
|
||||||
int32 fromGS = static_cast<int32>(botAI->GetEquipGearScore(from));
|
int32 fromGS = (int32)botAI->GetEquipGearScore(from/*, false, false*/);
|
||||||
|
if (sPlayerbotAIConfig->gearscorecheck)
|
||||||
if (sPlayerbotAIConfig->gearscorecheck && botGS && bot->GetLevel() > 15 && botGS > fromGS)
|
|
||||||
{
|
{
|
||||||
uint32 diffPct = uint32(100 * (botGS - fromGS) / botGS);
|
if (botGS && bot->GetLevel() > 15 && botGS > fromGS &&
|
||||||
uint32 reqPct = uint32(12 * sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL) / from->GetLevel());
|
static_cast<float>(100 * (botGS - fromGS) / botGS) >=
|
||||||
|
static_cast<float>(12 * sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL) / from->GetLevel()))
|
||||||
if (diffPct >= reqPct)
|
|
||||||
{
|
{
|
||||||
if (reason)
|
if (reason)
|
||||||
*reason = PLAYERBOT_DENY_GEARSCORE;
|
*reason = PLAYERBOT_DENY_GEARSCORE;
|
||||||
|
|
||||||
return PLAYERBOT_SECURITY_TALK;
|
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
|
/*if (bot->isDead())
|
||||||
botGroup = bot->GetGroup();
|
|
||||||
if (!botGroup)
|
|
||||||
{
|
{
|
||||||
|
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)
|
if (reason)
|
||||||
*reason = PLAYERBOT_DENY_INVITE;
|
*reason = PLAYERBOT_DENY_INVITE;
|
||||||
|
|
||||||
return PLAYERBOT_SECURITY_INVITE;
|
return PLAYERBOT_SECURITY_INVITE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ignoreGroup && botGroup->IsFull())
|
if (!ignoreGroup && group->IsFull())
|
||||||
{
|
{
|
||||||
if (reason)
|
if (reason)
|
||||||
*reason = PLAYERBOT_DENY_FULL_GROUP;
|
*reason = PLAYERBOT_DENY_FULL_GROUP;
|
||||||
@@ -141,22 +147,27 @@ PlayerbotSecurityLevel PlayerbotSecurity::LevelFor(Player* from, DenyReason* rea
|
|||||||
return PLAYERBOT_SECURITY_TALK;
|
return PLAYERBOT_SECURITY_TALK;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ignoreGroup && botGroup->GetLeaderGUID() != bot->GetGUID())
|
if (!ignoreGroup && group->GetLeaderGUID() != bot->GetGUID())
|
||||||
{
|
{
|
||||||
if (reason)
|
if (reason)
|
||||||
*reason = PLAYERBOT_DENY_NOT_LEADER;
|
*reason = PLAYERBOT_DENY_NOT_LEADER;
|
||||||
|
|
||||||
return PLAYERBOT_SECURITY_TALK;
|
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)
|
if (reason)
|
||||||
*reason = PLAYERBOT_DENY_IS_LEADER;
|
*reason = PLAYERBOT_DENY_INVITE;
|
||||||
|
|
||||||
return PLAYERBOT_SECURITY_INVITE;
|
return PLAYERBOT_SECURITY_INVITE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Non-random bots: only their master has full access
|
|
||||||
if (botAI->GetMaster() == from)
|
if (botAI->GetMaster() == from)
|
||||||
return PLAYERBOT_SECURITY_ALLOW_ALL;
|
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)
|
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;
|
DenyReason reason = PLAYERBOT_DENY_NONE;
|
||||||
PlayerbotSecurityLevel realLevel = LevelFor(from, &reason, ignoreGroup);
|
PlayerbotSecurityLevel realLevel = LevelFor(from, &reason, ignoreGroup);
|
||||||
|
|
||||||
if (realLevel >= level || from == bot)
|
if (realLevel >= level || from == bot)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
@@ -183,17 +189,11 @@ bool PlayerbotSecurity::CheckLevelFor(PlayerbotSecurityLevel level, bool silent,
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
PlayerbotAI* botAI = GET_PLAYERBOT_AI(bot);
|
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;
|
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;
|
std::ostringstream out;
|
||||||
|
|
||||||
switch (realLevel)
|
switch (realLevel)
|
||||||
{
|
{
|
||||||
case PLAYERBOT_SECURITY_DENY_ALL:
|
case PLAYERBOT_SECURITY_DENY_ALL:
|
||||||
@@ -206,20 +206,19 @@ bool PlayerbotSecurity::CheckLevelFor(PlayerbotSecurityLevel level, bool silent,
|
|||||||
out << "I'll do it later";
|
out << "I'll do it later";
|
||||||
break;
|
break;
|
||||||
case PLAYERBOT_DENY_LOW_LEVEL:
|
case PLAYERBOT_DENY_LOW_LEVEL:
|
||||||
out << "You are too low level: |cffff0000" << uint32(from->GetLevel()) << "|cffffffff/|cff00ff00"
|
out << "You are too low level: |cffff0000" << (uint32)from->GetLevel() << "|cffffffff/|cff00ff00"
|
||||||
<< uint32(bot->GetLevel());
|
<< (uint32)bot->GetLevel();
|
||||||
break;
|
break;
|
||||||
case PLAYERBOT_DENY_GEARSCORE:
|
case PLAYERBOT_DENY_GEARSCORE:
|
||||||
{
|
{
|
||||||
int botGS = int(botAI->GetEquipGearScore(bot));
|
int botGS = (int)botAI->GetEquipGearScore(bot/*, false, false*/);
|
||||||
int fromGS = int(botAI->GetEquipGearScore(from));
|
int fromGS = (int)botAI->GetEquipGearScore(from/*, false, false*/);
|
||||||
int diff = (100 * (botGS - fromGS) / botGS);
|
int diff = (100 * (botGS - fromGS) / botGS);
|
||||||
int req = 12 * sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL) / from->GetLevel();
|
int req = 12 * sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL) / from->GetLevel();
|
||||||
|
|
||||||
out << "Your gearscore is too low: |cffff0000" << fromGS << "|cffffffff/|cff00ff00" << botGS
|
out << "Your gearscore is too low: |cffff0000" << fromGS << "|cffffffff/|cff00ff00" << botGS
|
||||||
<< " |cffff0000" << diff << "%|cffffffff/|cff00ff00" << req << "%";
|
<< " |cffff0000" << diff << "%|cffffffff/|cff00ff00" << req << "%";
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
case PLAYERBOT_DENY_NOT_YOURS:
|
case PLAYERBOT_DENY_NOT_YOURS:
|
||||||
out << "I have a master already";
|
out << "I have a master already";
|
||||||
break;
|
break;
|
||||||
@@ -238,10 +237,13 @@ bool PlayerbotSecurity::CheckLevelFor(PlayerbotSecurityLevel level, bool silent,
|
|||||||
case PLAYERBOT_DENY_FAR:
|
case PLAYERBOT_DENY_FAR:
|
||||||
{
|
{
|
||||||
out << "You must be closer to invite me to your group. I am in ";
|
out << "You must be closer to invite me to your group. I am in ";
|
||||||
|
|
||||||
if (AreaTableEntry const* entry = sAreaTableStore.LookupEntry(bot->GetAreaId()))
|
if (AreaTableEntry const* entry = sAreaTableStore.LookupEntry(bot->GetAreaId()))
|
||||||
|
{
|
||||||
out << " |cffffffff(|cffff0000" << entry->area_name[0] << "|cffffffff)";
|
out << " |cffffffff(|cffff0000" << entry->area_name[0] << "|cffffffff)";
|
||||||
break;
|
}
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
case PLAYERBOT_DENY_FULL_GROUP:
|
case PLAYERBOT_DENY_FULL_GROUP:
|
||||||
out << "I am in a full group. Will do it later";
|
out << "I am in a full group. Will do it later";
|
||||||
break;
|
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.";
|
out << "I am currently leading a group. I can invite you if you want.";
|
||||||
break;
|
break;
|
||||||
case PLAYERBOT_DENY_NOT_LEADER:
|
case PLAYERBOT_DENY_NOT_LEADER:
|
||||||
if (Player* leader = botAI->GetGroupLeader())
|
if (botAI->GetGroupMaster())
|
||||||
out << "I am in a group with " << leader->GetName() << ". You can ask him for invite.";
|
{
|
||||||
|
out << "I am in a group with " << botAI->GetGroupMaster()->GetName()
|
||||||
|
<< ". You can ask him for invite.";
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
out << "I am in a group with someone else. You can ask him for invite.";
|
out << "I am in a group with someone else. You can ask him for invite.";
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case PLAYERBOT_DENY_BG:
|
case PLAYERBOT_DENY_BG:
|
||||||
out << "I am in a queue for BG. Will do it later";
|
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();
|
std::string const text = out.str();
|
||||||
ObjectGuid guid = from->GetGUID();
|
ObjectGuid guid = from->GetGUID();
|
||||||
time_t lastSaid = whispers[guid][text];
|
time_t lastSaid = whispers[guid][text];
|
||||||
|
|
||||||
if (!lastSaid || (time(nullptr) - lastSaid) >= sPlayerbotAIConfig->repeatDelay / 1000)
|
if (!lastSaid || (time(nullptr) - lastSaid) >= sPlayerbotAIConfig->repeatDelay / 1000)
|
||||||
{
|
{
|
||||||
whispers[guid][text] = time(nullptr);
|
whispers[guid][text] = time(nullptr);
|
||||||
|
bot->Whisper(text, LANG_UNIVERSAL, from);
|
||||||
// Additional protection against crashes during logout
|
|
||||||
if (bot->IsInWorld() && from->IsInWorld())
|
|
||||||
bot->Whisper(text, LANG_UNIVERSAL, from);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@@ -190,29 +190,26 @@ bool PlayerbotTextMgr::GetBotText(std::string name, std::string& text, std::map<
|
|||||||
|
|
||||||
void PlayerbotTextMgr::AddLocalePriority(uint32 locale)
|
void PlayerbotTextMgr::AddLocalePriority(uint32 locale)
|
||||||
{
|
{
|
||||||
if (locale >= MAX_LOCALES)
|
if (!locale)
|
||||||
{
|
|
||||||
LOG_WARN("playerbots", "Ignoring locale {} for bot texts because it exceeds MAX_LOCALES ({})", locale, MAX_LOCALES - 1);
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
botTextLocalePriority[locale]++;
|
botTextLocalePriority[locale]++;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 PlayerbotTextMgr::GetLocalePriority()
|
uint32 PlayerbotTextMgr::GetLocalePriority()
|
||||||
{
|
{
|
||||||
|
uint32 topLocale = 0;
|
||||||
|
|
||||||
// if no real players online, reset top locale
|
// if no real players online, reset top locale
|
||||||
uint32 const activeSessions = sWorldSessionMgr->GetActiveSessionCount();
|
if (!sWorldSessionMgr->GetActiveSessionCount())
|
||||||
if (!activeSessions)
|
|
||||||
{
|
{
|
||||||
ResetLocalePriority();
|
ResetLocalePriority();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 topLocale = 0;
|
|
||||||
for (uint8 i = 0; i < MAX_LOCALES; ++i)
|
for (uint8 i = 0; i < MAX_LOCALES; ++i)
|
||||||
{
|
{
|
||||||
if (botTextLocalePriority[i] > botTextLocalePriority[topLocale])
|
if (botTextLocalePriority[i] > topLocale)
|
||||||
topLocale = i;
|
topLocale = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -25,12 +25,9 @@
|
|||||||
#include "Metric.h"
|
#include "Metric.h"
|
||||||
#include "PlayerScript.h"
|
#include "PlayerScript.h"
|
||||||
#include "PlayerbotAIConfig.h"
|
#include "PlayerbotAIConfig.h"
|
||||||
#include "PlayerbotGuildMgr.h"
|
|
||||||
#include "PlayerbotSpellRepository.h"
|
|
||||||
#include "PlayerbotWorldThreadProcessor.h"
|
|
||||||
#include "RandomPlayerbotMgr.h"
|
#include "RandomPlayerbotMgr.h"
|
||||||
#include "ScriptMgr.h"
|
#include "ScriptMgr.h"
|
||||||
#include "PlayerbotCommandScript.h"
|
#include "cs_playerbots.h"
|
||||||
#include "cmath"
|
#include "cmath"
|
||||||
#include "BattleGroundTactics.h"
|
#include "BattleGroundTactics.h"
|
||||||
|
|
||||||
@@ -84,12 +81,12 @@ public:
|
|||||||
PlayerbotsPlayerScript() : PlayerScript("PlayerbotsPlayerScript", {
|
PlayerbotsPlayerScript() : PlayerScript("PlayerbotsPlayerScript", {
|
||||||
PLAYERHOOK_ON_LOGIN,
|
PLAYERHOOK_ON_LOGIN,
|
||||||
PLAYERHOOK_ON_AFTER_UPDATE,
|
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_CRITERIA_PROGRESS,
|
||||||
PLAYERHOOK_ON_BEFORE_ACHI_COMPLETE,
|
PLAYERHOOK_ON_BEFORE_ACHI_COMPLETE,
|
||||||
PLAYERHOOK_CAN_PLAYER_USE_PRIVATE_CHAT,
|
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_GIVE_EXP,
|
||||||
PLAYERHOOK_ON_BEFORE_TELEPORT
|
PLAYERHOOK_ON_BEFORE_TELEPORT
|
||||||
}) {}
|
}) {}
|
||||||
@@ -125,49 +122,24 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OnPlayerBeforeTeleport(Player* /*player*/, uint32 /*mapid*/, float /*x*/, float /*y*/, float /*z*/, float /*orientation*/, uint32 /*options*/, Unit* /*target*/) override
|
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
|
// Only apply to bots to prevent affecting real players
|
||||||
* havent seen any proof CleanVisibilityReferences() is needed
|
if (!player || !player->GetSession()->IsBot())
|
||||||
|
|
||||||
// If the player is not safe to touch, do nothing
|
|
||||||
if (!player)
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// If same map or not in world do nothing
|
// If changing maps, proactively clean visibility references to prevent
|
||||||
if (!player->IsInWorld() || player->GetMapId() == mapid)
|
// stale pointers in other players' visibility maps during the teleport.
|
||||||
return true;
|
// This fixes a race condition where:
|
||||||
|
// 1. Bot A teleports and its visible objects start getting cleaned up
|
||||||
|
// 2. Bot B is simultaneously updating visibility and tries to access objects in Bot A's old visibility map
|
||||||
|
// 3. Those objects may already be freed, causing a segmentation fault
|
||||||
|
if (player->GetMapId() != mapid && player->IsInWorld())
|
||||||
|
{
|
||||||
|
player->GetObjectVisibilityContainer().CleanVisibilityReferences();
|
||||||
|
}
|
||||||
|
|
||||||
// If real player do nothing
|
return true; // Allow teleport to continue
|
||||||
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
|
void OnPlayerAfterUpdate(Player* player, uint32 diff) override
|
||||||
@@ -191,17 +163,14 @@ public:
|
|||||||
{
|
{
|
||||||
botAI->HandleCommand(type, msg, player);
|
botAI->HandleCommand(type, msg, player);
|
||||||
|
|
||||||
// hotfix; otherwise the server will crash when whispering logout
|
return false;
|
||||||
// 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 true;
|
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())
|
for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next())
|
||||||
{
|
{
|
||||||
@@ -213,10 +182,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)
|
if (type == CHAT_MSG_GUILD)
|
||||||
{
|
{
|
||||||
@@ -235,10 +203,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))
|
if (PlayerbotMgr* playerbotMgr = GET_PLAYERBOT_MGR(player))
|
||||||
{
|
{
|
||||||
@@ -249,13 +216,11 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
sRandomPlayerbotMgr->HandleCommand(type, msg, player);
|
sRandomPlayerbotMgr->HandleCommand(type, msg, player);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OnPlayerBeforeAchievementComplete(Player* player, AchievementEntry const* achievement) override
|
bool OnPlayerBeforeAchievementComplete(Player* player, AchievementEntry const* achievement) override
|
||||||
{
|
{
|
||||||
if ((sRandomPlayerbotMgr->IsRandomBot(player) || sRandomPlayerbotMgr->IsAddclassBot(player)) &&
|
if (sRandomPlayerbotMgr->IsRandomBot(player) && (achievement->flags == 256 || achievement->flags == 768))
|
||||||
(achievement->flags & (ACHIEVEMENT_FLAG_REALM_FIRST_REACH | ACHIEVEMENT_FLAG_REALM_FIRST_KILL)))
|
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -334,8 +299,7 @@ class PlayerbotsWorldScript : public WorldScript
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
PlayerbotsWorldScript() : WorldScript("PlayerbotsWorldScript", {
|
PlayerbotsWorldScript() : WorldScript("PlayerbotsWorldScript", {
|
||||||
WORLDHOOK_ON_BEFORE_WORLD_INITIALIZED,
|
WORLDHOOK_ON_BEFORE_WORLD_INITIALIZED
|
||||||
WORLDHOOK_ON_UPDATE
|
|
||||||
}) {}
|
}) {}
|
||||||
|
|
||||||
void OnBeforeWorldInitialized() override
|
void OnBeforeWorldInitialized() override
|
||||||
@@ -364,16 +328,6 @@ public:
|
|||||||
|
|
||||||
LOG_INFO("server.loading", ">> Loaded playerbots config in {} ms", GetMSTimeDiffToNow(oldMSTime));
|
LOG_INFO("server.loading", ">> Loaded playerbots config in {} ms", GetMSTimeDiffToNow(oldMSTime));
|
||||||
LOG_INFO("server.loading", " ");
|
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 +389,8 @@ public:
|
|||||||
|
|
||||||
void OnPlayerbotUpdate(uint32 diff) override
|
void OnPlayerbotUpdate(uint32 diff) override
|
||||||
{
|
{
|
||||||
sRandomPlayerbotMgr->UpdateSessions(); // Per-bot updates only
|
sRandomPlayerbotMgr->UpdateAI(diff);
|
||||||
|
sRandomPlayerbotMgr->UpdateSessions();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnPlayerbotUpdateSessions(Player* player) override
|
void OnPlayerbotUpdateSessions(Player* player) override
|
||||||
@@ -503,8 +458,6 @@ public:
|
|||||||
void OnBattlegroundEnd(Battleground* bg, TeamId /*winnerTeam*/) override { bgStrategies.erase(bg->GetInstanceID()); }
|
void OnBattlegroundEnd(Battleground* bg, TeamId /*winnerTeam*/) override { bgStrategies.erase(bg->GetInstanceID()); }
|
||||||
};
|
};
|
||||||
|
|
||||||
void AddPlayerbotsSecureLoginScripts();
|
|
||||||
|
|
||||||
void AddPlayerbotsScripts()
|
void AddPlayerbotsScripts()
|
||||||
{
|
{
|
||||||
new PlayerbotsDatabaseScript();
|
new PlayerbotsDatabaseScript();
|
||||||
@@ -514,7 +467,6 @@ void AddPlayerbotsScripts()
|
|||||||
new PlayerbotsWorldScript();
|
new PlayerbotsWorldScript();
|
||||||
new PlayerbotsScript();
|
new PlayerbotsScript();
|
||||||
new PlayerBotsBGScript();
|
new PlayerBotsBGScript();
|
||||||
AddPlayerbotsSecureLoginScripts();
|
|
||||||
AddPlayerbotsCommandscripts();
|
AddSC_playerbots_commandscript();
|
||||||
PlayerBotsGuildValidationScript();
|
|
||||||
}
|
}
|
||||||
@@ -982,7 +982,7 @@ void RandomItemMgr::BuildItemInfoCache()
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (proto->HasFlag(ITEM_FLAG_DEPRECATED))
|
if (proto->Flags & ITEM_FLAG_DEPRECATED)
|
||||||
{
|
{
|
||||||
itemForTest.insert(proto->ItemId);
|
itemForTest.insert(proto->ItemId);
|
||||||
continue;
|
continue;
|
||||||
@@ -1072,10 +1072,10 @@ void RandomItemMgr::BuildItemInfoCache()
|
|||||||
// cacheInfo.team = TEAM_NEUTRAL;
|
// cacheInfo.team = TEAM_NEUTRAL;
|
||||||
|
|
||||||
// // check faction
|
// // check faction
|
||||||
// if (proto->HasFlag2(ITEM_FLAG2_FACTION_HORDE))
|
// if (proto->Flags2 & ITEM_FLAG2_FACTION_HORDE)
|
||||||
// cacheInfo.team = TEAM_HORDE;
|
// cacheInfo.team = TEAM_HORDE;
|
||||||
|
|
||||||
// if (proto->HasFlag2(ITEM_FLAG2_FACTION_ALLIANCE))
|
// if (proto->Flags2 & ITEM_FLAG2_FACTION_ALLIANCE)
|
||||||
// cacheInfo.team = TEAM_ALLIANCE;
|
// cacheInfo.team = TEAM_ALLIANCE;
|
||||||
|
|
||||||
// if (cacheInfo.team == TEAM_NEUTRAL && proto->AllowableRace > 1 && proto->AllowableRace < 8388607)
|
// if (cacheInfo.team == TEAM_NEUTRAL && proto->AllowableRace > 1 && proto->AllowableRace < 8388607)
|
||||||
@@ -1099,7 +1099,7 @@ void RandomItemMgr::BuildItemInfoCache()
|
|||||||
|
|
||||||
// // check item source
|
// // check item source
|
||||||
|
|
||||||
// if (proto->HasFlag(ITEM_FLAG_NO_DISENCHANT))
|
// if (proto->Flags & ITEM_FLAG_NO_DISENCHANT)
|
||||||
// {
|
// {
|
||||||
// cacheInfo.source = ITEM_SOURCE_PVP;
|
// cacheInfo.source = ITEM_SOURCE_PVP;
|
||||||
// LOG_DEBUG("playerbots", "Item: {}, source: PvP Reward", proto->ItemId);
|
// LOG_DEBUG("playerbots", "Item: {}, source: PvP Reward", proto->ItemId);
|
||||||
@@ -1367,7 +1367,7 @@ uint32 RandomItemMgr::CalculateStatWeight(uint8 playerclass, uint8 spec, ItemTem
|
|||||||
}
|
}
|
||||||
|
|
||||||
// check item spells
|
// check item spells
|
||||||
for (auto const& spellData : proto->Spells)
|
for (const auto& spellData : proto->Spells)
|
||||||
{
|
{
|
||||||
// no spell
|
// no spell
|
||||||
if (!spellData.SpellId)
|
if (!spellData.SpellId)
|
||||||
@@ -2374,6 +2374,7 @@ void RandomItemMgr::BuildPotionCache()
|
|||||||
if (proto->Duration & 0x80000000)
|
if (proto->Duration & 0x80000000)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
|
||||||
if (proto->AllowableClass != -1)
|
if (proto->AllowableClass != -1)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@@ -2834,20 +2835,22 @@ inline bool ContainsInternal(ItemTemplate const* proto, uint32 skillId)
|
|||||||
CreatureTemplateContainer const* creatures = sObjectMgr->GetCreatureTemplates();
|
CreatureTemplateContainer const* creatures = sObjectMgr->GetCreatureTemplates();
|
||||||
for (CreatureTemplateContainer::const_iterator itr = creatures->begin(); itr != creatures->end(); ++itr)
|
for (CreatureTemplateContainer::const_iterator itr = creatures->begin(); itr != creatures->end(); ++itr)
|
||||||
{
|
{
|
||||||
Trainer::Trainer* trainer = sObjectMgr->GetTrainer(itr->first);
|
if (itr->second.trainer_type != TRAINER_TYPE_TRADESKILLS)
|
||||||
|
|
||||||
if (!trainer)
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (trainer->GetTrainerType() != Trainer::Type::Tradeskill)
|
uint32 trainerId = itr->second.Entry;
|
||||||
|
TrainerSpellData const* trainer_spells = sObjectMgr->GetNpcTrainerSpells(trainerId);
|
||||||
|
if (!trainer_spells)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
for (auto& spell : trainer->GetSpells())
|
for (TrainerSpellMap::const_iterator iter = trainer_spells->spellList.begin();
|
||||||
|
iter != trainer_spells->spellList.end(); ++iter)
|
||||||
{
|
{
|
||||||
if (spell.ReqSkillLine != skillId)
|
TrainerSpell const* tSpell = &iter->second;
|
||||||
|
if (!tSpell || tSpell->reqSkill != skillId)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (IsCraftedBy(proto, spell.SpellId))
|
if (IsCraftedBy(proto, tSpell->spell))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -11,7 +11,6 @@
|
|||||||
#include "GuildMgr.h"
|
#include "GuildMgr.h"
|
||||||
#include "PlayerbotFactory.h"
|
#include "PlayerbotFactory.h"
|
||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
#include "PlayerbotGuildMgr.h"
|
|
||||||
#include "ScriptMgr.h"
|
#include "ScriptMgr.h"
|
||||||
#include "SharedDefines.h"
|
#include "SharedDefines.h"
|
||||||
#include "SocialMgr.h"
|
#include "SocialMgr.h"
|
||||||
@@ -20,99 +19,188 @@
|
|||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
#include "GuildMgr.h"
|
#include "GuildMgr.h"
|
||||||
|
|
||||||
constexpr RandomPlayerbotFactory::NameRaceAndGender RandomPlayerbotFactory::CombineRaceAndGender(uint8 race,
|
std::map<uint8, std::vector<uint8>> RandomPlayerbotFactory::availableRaces;
|
||||||
uint8 gender)
|
|
||||||
|
constexpr RandomPlayerbotFactory::NameRaceAndGender RandomPlayerbotFactory::CombineRaceAndGender(uint8 gender,
|
||||||
|
uint8 race)
|
||||||
{
|
{
|
||||||
NameRaceAndGender baseIndex;
|
|
||||||
switch (race)
|
switch (race)
|
||||||
{
|
{
|
||||||
case RACE_ORC: baseIndex = NameRaceAndGender::OrcMale; break;
|
|
||||||
case RACE_DWARF: baseIndex = NameRaceAndGender::DwarfMale; break;
|
|
||||||
case RACE_NIGHTELF: baseIndex = NameRaceAndGender::NightelfMale; break;
|
|
||||||
case RACE_TAUREN: baseIndex = NameRaceAndGender::TaurenMale; break;
|
|
||||||
case RACE_GNOME: baseIndex = NameRaceAndGender::GnomeMale; break;
|
|
||||||
case RACE_TROLL: baseIndex = NameRaceAndGender::TrollMale; break;
|
|
||||||
case RACE_BLOODELF: baseIndex = NameRaceAndGender::BloodelfMale; break;
|
|
||||||
case RACE_DRAENEI: baseIndex = NameRaceAndGender::DraeneiMale; break;
|
|
||||||
case RACE_HUMAN:
|
case RACE_HUMAN:
|
||||||
|
return static_cast<NameRaceAndGender>(static_cast<uint8>(NameRaceAndGender::GenericMale) + gender);
|
||||||
|
case RACE_ORC:
|
||||||
|
return static_cast<NameRaceAndGender>(static_cast<uint8>(NameRaceAndGender::OrcMale) + gender);
|
||||||
|
case RACE_DWARF:
|
||||||
|
return static_cast<NameRaceAndGender>(static_cast<uint8>(NameRaceAndGender::DwarfMale) + gender);
|
||||||
|
case RACE_NIGHTELF:
|
||||||
|
return static_cast<NameRaceAndGender>(static_cast<uint8>(NameRaceAndGender::NightelfMale) + gender);
|
||||||
case RACE_UNDEAD_PLAYER:
|
case RACE_UNDEAD_PLAYER:
|
||||||
|
return static_cast<NameRaceAndGender>(static_cast<uint8>(NameRaceAndGender::GenericMale) + gender);
|
||||||
|
case RACE_TAUREN:
|
||||||
|
return static_cast<NameRaceAndGender>(static_cast<uint8>(NameRaceAndGender::TaurenMale) + gender);
|
||||||
|
case RACE_GNOME:
|
||||||
|
return static_cast<NameRaceAndGender>(static_cast<uint8>(NameRaceAndGender::GnomeMale) + gender);
|
||||||
|
case RACE_TROLL:
|
||||||
|
return static_cast<NameRaceAndGender>(static_cast<uint8>(NameRaceAndGender::TrollMale) + gender);
|
||||||
|
case RACE_DRAENEI:
|
||||||
|
return static_cast<NameRaceAndGender>(static_cast<uint8>(NameRaceAndGender::DraeneiMale) + gender);
|
||||||
|
case RACE_BLOODELF:
|
||||||
|
return static_cast<NameRaceAndGender>(static_cast<uint8>(NameRaceAndGender::BloodelfMale) + gender);
|
||||||
default:
|
default:
|
||||||
baseIndex = NameRaceAndGender::GenericMale;
|
LOG_ERROR("playerbots", "The race with ID %d does not have a naming category", race);
|
||||||
break;
|
return static_cast<NameRaceAndGender>(static_cast<uint8>(NameRaceAndGender::GenericMale) + gender);
|
||||||
}
|
}
|
||||||
|
|
||||||
return static_cast<NameRaceAndGender>(static_cast<uint8>(baseIndex) + ((gender >= GENDER_NONE) ? GENDER_MALE : gender));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RandomPlayerbotFactory::IsValidRaceClassCombination(uint8 race, uint8 cls, uint32 expansion)
|
RandomPlayerbotFactory::RandomPlayerbotFactory(uint32 accountId) : accountId(accountId)
|
||||||
{
|
{
|
||||||
// skip expansion races if not playing with expansion
|
uint32 const expansion = sWorld->getIntConfig(CONFIG_EXPANSION);
|
||||||
if (expansion < EXPANSION_THE_BURNING_CRUSADE && (race == RACE_BLOODELF || race == RACE_DRAENEI))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// skip expansion classes if not playing with expansion
|
availableRaces[CLASS_WARRIOR].push_back(RACE_HUMAN);
|
||||||
if (expansion < EXPANSION_WRATH_OF_THE_LICH_KING && cls == CLASS_DEATH_KNIGHT)
|
availableRaces[CLASS_WARRIOR].push_back(RACE_NIGHTELF);
|
||||||
return false;
|
availableRaces[CLASS_WARRIOR].push_back(RACE_GNOME);
|
||||||
|
availableRaces[CLASS_WARRIOR].push_back(RACE_DWARF);
|
||||||
|
availableRaces[CLASS_WARRIOR].push_back(RACE_ORC);
|
||||||
|
availableRaces[CLASS_WARRIOR].push_back(RACE_UNDEAD_PLAYER);
|
||||||
|
availableRaces[CLASS_WARRIOR].push_back(RACE_TAUREN);
|
||||||
|
availableRaces[CLASS_WARRIOR].push_back(RACE_TROLL);
|
||||||
|
if (expansion >= EXPANSION_THE_BURNING_CRUSADE)
|
||||||
|
{
|
||||||
|
availableRaces[CLASS_WARRIOR].push_back(RACE_DRAENEI);
|
||||||
|
}
|
||||||
|
|
||||||
PlayerInfo const* info = sObjectMgr->GetPlayerInfo(race, cls);
|
availableRaces[CLASS_PALADIN].push_back(RACE_HUMAN);
|
||||||
return info != nullptr;
|
availableRaces[CLASS_PALADIN].push_back(RACE_DWARF);
|
||||||
|
if (expansion >= EXPANSION_THE_BURNING_CRUSADE)
|
||||||
|
{
|
||||||
|
availableRaces[CLASS_PALADIN].push_back(RACE_DRAENEI);
|
||||||
|
availableRaces[CLASS_PALADIN].push_back(RACE_BLOODELF);
|
||||||
|
}
|
||||||
|
|
||||||
|
availableRaces[CLASS_ROGUE].push_back(RACE_HUMAN);
|
||||||
|
availableRaces[CLASS_ROGUE].push_back(RACE_DWARF);
|
||||||
|
availableRaces[CLASS_ROGUE].push_back(RACE_NIGHTELF);
|
||||||
|
availableRaces[CLASS_ROGUE].push_back(RACE_GNOME);
|
||||||
|
availableRaces[CLASS_ROGUE].push_back(RACE_ORC);
|
||||||
|
availableRaces[CLASS_ROGUE].push_back(RACE_UNDEAD_PLAYER);
|
||||||
|
availableRaces[CLASS_ROGUE].push_back(RACE_TROLL);
|
||||||
|
if (expansion >= EXPANSION_THE_BURNING_CRUSADE)
|
||||||
|
{
|
||||||
|
availableRaces[CLASS_ROGUE].push_back(RACE_BLOODELF);
|
||||||
|
}
|
||||||
|
|
||||||
|
availableRaces[CLASS_PRIEST].push_back(RACE_HUMAN);
|
||||||
|
availableRaces[CLASS_PRIEST].push_back(RACE_DWARF);
|
||||||
|
availableRaces[CLASS_PRIEST].push_back(RACE_NIGHTELF);
|
||||||
|
availableRaces[CLASS_PRIEST].push_back(RACE_TROLL);
|
||||||
|
availableRaces[CLASS_PRIEST].push_back(RACE_UNDEAD_PLAYER);
|
||||||
|
if (expansion >= EXPANSION_THE_BURNING_CRUSADE)
|
||||||
|
{
|
||||||
|
availableRaces[CLASS_PRIEST].push_back(RACE_DRAENEI);
|
||||||
|
availableRaces[CLASS_PRIEST].push_back(RACE_BLOODELF);
|
||||||
|
}
|
||||||
|
|
||||||
|
availableRaces[CLASS_MAGE].push_back(RACE_HUMAN);
|
||||||
|
availableRaces[CLASS_MAGE].push_back(RACE_GNOME);
|
||||||
|
availableRaces[CLASS_MAGE].push_back(RACE_UNDEAD_PLAYER);
|
||||||
|
availableRaces[CLASS_MAGE].push_back(RACE_TROLL);
|
||||||
|
if (expansion >= EXPANSION_THE_BURNING_CRUSADE)
|
||||||
|
{
|
||||||
|
availableRaces[CLASS_MAGE].push_back(RACE_DRAENEI);
|
||||||
|
availableRaces[CLASS_MAGE].push_back(RACE_BLOODELF);
|
||||||
|
}
|
||||||
|
|
||||||
|
availableRaces[CLASS_WARLOCK].push_back(RACE_HUMAN);
|
||||||
|
availableRaces[CLASS_WARLOCK].push_back(RACE_GNOME);
|
||||||
|
availableRaces[CLASS_WARLOCK].push_back(RACE_UNDEAD_PLAYER);
|
||||||
|
availableRaces[CLASS_WARLOCK].push_back(RACE_ORC);
|
||||||
|
if (expansion >= EXPANSION_THE_BURNING_CRUSADE)
|
||||||
|
{
|
||||||
|
availableRaces[CLASS_WARLOCK].push_back(RACE_BLOODELF);
|
||||||
|
}
|
||||||
|
|
||||||
|
availableRaces[CLASS_SHAMAN].push_back(RACE_ORC);
|
||||||
|
availableRaces[CLASS_SHAMAN].push_back(RACE_TAUREN);
|
||||||
|
availableRaces[CLASS_SHAMAN].push_back(RACE_TROLL);
|
||||||
|
if (expansion >= EXPANSION_THE_BURNING_CRUSADE)
|
||||||
|
{
|
||||||
|
availableRaces[CLASS_SHAMAN].push_back(RACE_DRAENEI);
|
||||||
|
}
|
||||||
|
|
||||||
|
availableRaces[CLASS_HUNTER].push_back(RACE_DWARF);
|
||||||
|
availableRaces[CLASS_HUNTER].push_back(RACE_NIGHTELF);
|
||||||
|
availableRaces[CLASS_HUNTER].push_back(RACE_ORC);
|
||||||
|
availableRaces[CLASS_HUNTER].push_back(RACE_TAUREN);
|
||||||
|
availableRaces[CLASS_HUNTER].push_back(RACE_TROLL);
|
||||||
|
if (expansion >= EXPANSION_THE_BURNING_CRUSADE)
|
||||||
|
{
|
||||||
|
availableRaces[CLASS_HUNTER].push_back(RACE_DRAENEI);
|
||||||
|
availableRaces[CLASS_HUNTER].push_back(RACE_BLOODELF);
|
||||||
|
}
|
||||||
|
|
||||||
|
availableRaces[CLASS_DRUID].push_back(RACE_NIGHTELF);
|
||||||
|
availableRaces[CLASS_DRUID].push_back(RACE_TAUREN);
|
||||||
|
|
||||||
|
if (expansion == EXPANSION_WRATH_OF_THE_LICH_KING)
|
||||||
|
{
|
||||||
|
availableRaces[CLASS_DEATH_KNIGHT].push_back(RACE_NIGHTELF);
|
||||||
|
availableRaces[CLASS_DEATH_KNIGHT].push_back(RACE_TAUREN);
|
||||||
|
availableRaces[CLASS_DEATH_KNIGHT].push_back(RACE_HUMAN);
|
||||||
|
availableRaces[CLASS_DEATH_KNIGHT].push_back(RACE_ORC);
|
||||||
|
availableRaces[CLASS_DEATH_KNIGHT].push_back(RACE_UNDEAD_PLAYER);
|
||||||
|
availableRaces[CLASS_DEATH_KNIGHT].push_back(RACE_TROLL);
|
||||||
|
availableRaces[CLASS_DEATH_KNIGHT].push_back(RACE_BLOODELF);
|
||||||
|
availableRaces[CLASS_DEATH_KNIGHT].push_back(RACE_DRAENEI);
|
||||||
|
availableRaces[CLASS_DEATH_KNIGHT].push_back(RACE_GNOME);
|
||||||
|
availableRaces[CLASS_DEATH_KNIGHT].push_back(RACE_DWARF);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Player* RandomPlayerbotFactory::CreateRandomBot(WorldSession* session, uint8 cls, std::unordered_map<NameRaceAndGender, std::vector<std::string>>& nameCache)
|
Player* RandomPlayerbotFactory::CreateRandomBot(WorldSession* session, uint8 cls, std::unordered_map<NameRaceAndGender, std::vector<std::string>>& nameCache)
|
||||||
{
|
{
|
||||||
LOG_DEBUG("playerbots", "Creating a new random bot for class: {}", cls);
|
LOG_DEBUG("playerbots", "Creating new random bot for class {}", cls);
|
||||||
|
|
||||||
const bool alliance = static_cast<bool>(urand(0, 1));
|
|
||||||
|
|
||||||
|
uint8 gender = rand() % 2 ? GENDER_MALE : GENDER_FEMALE;
|
||||||
|
bool alliance = rand() % 2 ? true : false;
|
||||||
std::vector<uint8> raceOptions;
|
std::vector<uint8> raceOptions;
|
||||||
for (uint8 race = RACE_HUMAN; race < MAX_RACES; ++race)
|
for (const auto& race : availableRaces[cls])
|
||||||
{
|
{
|
||||||
// skip disabled with config races
|
|
||||||
if ((1 << (race - 1)) & sWorld->getIntConfig(CONFIG_CHARACTER_CREATING_DISABLED_RACEMASK))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Try to get 50/50 faction distribution for random bot population balance.
|
|
||||||
// Without this check, races from the faction with more class options would dominate.
|
|
||||||
if (alliance == IsAlliance(race))
|
if (alliance == IsAlliance(race))
|
||||||
{
|
{
|
||||||
if (IsValidRaceClassCombination(race, cls, sWorld->getIntConfig(CONFIG_EXPANSION)))
|
raceOptions.push_back(race);
|
||||||
raceOptions.push_back(race);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (raceOptions.empty())
|
if (raceOptions.empty())
|
||||||
{
|
{
|
||||||
LOG_ERROR("playerbots", "No races are available for class: {}", cls);
|
LOG_ERROR("playerbots", "No races available for class: {}", cls);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
const uint8 race = raceOptions[urand(0, raceOptions.size() - 1)];
|
uint8 race = raceOptions[urand(0, raceOptions.size() - 1)];
|
||||||
const uint8 gender = urand(0, 1) ? GENDER_MALE : GENDER_FEMALE;
|
|
||||||
const auto raceAndGender = CombineRaceAndGender(race, gender);
|
const auto raceAndGender = CombineRaceAndGender(gender, race);
|
||||||
|
|
||||||
std::string name;
|
std::string name;
|
||||||
if (!nameCache.empty())
|
if (nameCache.empty())
|
||||||
|
{
|
||||||
|
name = CreateRandomBotName(raceAndGender);
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
if (nameCache[raceAndGender].empty())
|
if (nameCache[raceAndGender].empty())
|
||||||
{
|
{
|
||||||
LOG_ERROR("playerbots", "No names found for the specified race: {} and gender: {}",
|
LOG_ERROR("playerbots", "No name found for race and gender: {}", raceAndGender);
|
||||||
race, gender);
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 i = urand(0, nameCache[raceAndGender].size() - 1);
|
uint32 i = urand(0, nameCache[raceAndGender].size() - 1);
|
||||||
name = nameCache[raceAndGender][i];
|
name = nameCache[raceAndGender][i];
|
||||||
swap(nameCache[raceAndGender][i], nameCache[raceAndGender].back());
|
swap(nameCache[raceAndGender][i], nameCache[raceAndGender].back());
|
||||||
nameCache[raceAndGender].pop_back();
|
nameCache[raceAndGender].pop_back();
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
name = CreateRandomBotName(raceAndGender);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (name.empty())
|
if (name.empty())
|
||||||
{
|
{
|
||||||
LOG_ERROR("playerbots", "Failed to get a valid random bot name");
|
LOG_ERROR("playerbots", "Unable to get random bot name!");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -158,20 +246,19 @@ Player* RandomPlayerbotFactory::CreateRandomBot(WorldSession* session, uint8 cls
|
|||||||
player->CleanupsBeforeDelete();
|
player->CleanupsBeforeDelete();
|
||||||
delete player;
|
delete player;
|
||||||
|
|
||||||
LOG_ERROR("playerbots", "Unable to create random bot - name: \"{}\", race: {}, class: {}",
|
LOG_ERROR("playerbots", "Unable to create random bot for account {} - name: \"{}\"; race: {}; class: {}",
|
||||||
name.c_str(), race, cls);
|
accountId, name.c_str(), race, cls);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
player->setCinematic(2);
|
player->setCinematic(2);
|
||||||
player->SetAtLoginFlag(AT_LOGIN_NONE);
|
player->SetAtLoginFlag(AT_LOGIN_NONE);
|
||||||
|
|
||||||
if (cls == CLASS_DEATH_KNIGHT)
|
if (player->getClass() == CLASS_DEATH_KNIGHT)
|
||||||
{
|
{
|
||||||
player->learnSpell(50977, false);
|
player->learnSpell(50977, false);
|
||||||
}
|
}
|
||||||
|
LOG_DEBUG("playerbots", "Random bot created for account {} - name: \"{}\"; race: {}; class: {}", accountId,
|
||||||
LOG_DEBUG("playerbots", "Random bot created - name: \"{}\", race: {}, class: {}",
|
|
||||||
name.c_str(), race, cls);
|
name.c_str(), race, cls);
|
||||||
|
|
||||||
return player;
|
return player;
|
||||||
@@ -699,7 +786,7 @@ void RandomPlayerbotFactory::CreateRandomBots()
|
|||||||
}
|
}
|
||||||
|
|
||||||
LOG_DEBUG("playerbots", "Creating random bot characters for account: [{}/{}]", accountNumber + 1, totalAccountCount);
|
LOG_DEBUG("playerbots", "Creating random bot characters for account: [{}/{}]", accountNumber + 1, totalAccountCount);
|
||||||
RandomPlayerbotFactory factory;
|
RandomPlayerbotFactory factory(accountId);
|
||||||
|
|
||||||
WorldSession* session = new WorldSession(accountId, "", 0x0, nullptr, SEC_PLAYER, EXPANSION_WRATH_OF_THE_LICH_KING,
|
WorldSession* session = new WorldSession(accountId, "", 0x0, nullptr, SEC_PLAYER, EXPANSION_WRATH_OF_THE_LICH_KING,
|
||||||
time_t(0), LOCALE_enUS, 0, false, false, 0, true);
|
time_t(0), LOCALE_enUS, 0, false, false, 0, true);
|
||||||
@@ -711,24 +798,29 @@ void RandomPlayerbotFactory::CreateRandomBots()
|
|||||||
if (!((1 << (cls - 1)) & CLASSMASK_ALL_PLAYABLE) || !sChrClassesStore.LookupEntry(cls))
|
if (!((1 << (cls - 1)) & CLASSMASK_ALL_PLAYABLE) || !sChrClassesStore.LookupEntry(cls))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// skip disabled with config classes
|
if (bool const isClassDeathKnight = cls == CLASS_DEATH_KNIGHT;
|
||||||
if ((1 << (cls - 1)) & sWorld->getIntConfig(CONFIG_CHARACTER_CREATING_DISABLED_CLASSMASK))
|
isClassDeathKnight && sWorld->getIntConfig(CONFIG_EXPANSION) != EXPANSION_WRATH_OF_THE_LICH_KING)
|
||||||
continue;
|
|
||||||
|
|
||||||
Player* playerBot = factory.CreateRandomBot(session, cls, nameCache);
|
|
||||||
if (!playerBot)
|
|
||||||
{
|
{
|
||||||
LOG_ERROR("playerbots", "Fail to create character for account {}", accountId);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
playerBot->SaveToDB(true, false);
|
if (cls != 10)
|
||||||
sCharacterCache->AddCharacterCacheEntry(playerBot->GetGUID(), accountId, playerBot->GetName(),
|
{
|
||||||
playerBot->getGender(), playerBot->getRace(),
|
if (Player* playerBot = factory.CreateRandomBot(session, cls, nameCache))
|
||||||
playerBot->getClass(), playerBot->GetLevel());
|
{
|
||||||
playerBot->CleanupsBeforeDelete();
|
playerBot->SaveToDB(true, false);
|
||||||
delete playerBot;
|
sCharacterCache->AddCharacterCacheEntry(playerBot->GetGUID(), accountId, playerBot->GetName(),
|
||||||
bot_creation++;
|
playerBot->getGender(), playerBot->getRace(),
|
||||||
|
playerBot->getClass(), playerBot->GetLevel());
|
||||||
|
playerBot->CleanupsBeforeDelete();
|
||||||
|
delete playerBot;
|
||||||
|
bot_creation++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG_ERROR("playerbots", "Fail to create character for account {}", accountId);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -755,6 +847,144 @@ void RandomPlayerbotFactory::CreateRandomBots()
|
|||||||
sPlayerbotAIConfig->randomBotAccounts.size(), totalRandomBotChars);
|
sPlayerbotAIConfig->randomBotAccounts.size(), totalRandomBotChars);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RandomPlayerbotFactory::CreateRandomGuilds()
|
||||||
|
{
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sPlayerbotAIConfig->deleteRandomBotGuilds)
|
||||||
|
{
|
||||||
|
LOG_INFO("playerbots", "Deleting random bot guilds...");
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 guildNumber = 0;
|
||||||
|
GuidVector availableLeaders;
|
||||||
|
for (std::vector<uint32>::iterator i = randomBots.begin(); i != randomBots.end(); ++i)
|
||||||
|
{
|
||||||
|
ObjectGuid leader = ObjectGuid::Create<HighGuid::Player>(*i);
|
||||||
|
if (Guild* guild = sGuildMgr->GetGuildByLeader(leader))
|
||||||
|
{
|
||||||
|
++guildNumber;
|
||||||
|
sPlayerbotAIConfig->randomBotGuilds.push_back(guild->GetId());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Player* player = ObjectAccessor::FindPlayer(leader);
|
||||||
|
if (player && !player->GetGuildId())
|
||||||
|
availableLeaders.push_back(leader);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create up to randomBotGuildCount by counting only EFFECTIVE creations
|
||||||
|
uint32 createdThisRun = 0;
|
||||||
|
for (; guildNumber < sPlayerbotAIConfig->randomBotGuildCount; /* ++guildNumber -> done only if creation */)
|
||||||
|
{
|
||||||
|
std::string const guildName = CreateRandomGuildName();
|
||||||
|
if (guildName.empty())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (sGuildMgr->GetGuildByName(guildName))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (availableLeaders.empty())
|
||||||
|
{
|
||||||
|
LOG_ERROR("playerbots", "No leaders for random guilds available");
|
||||||
|
break; // no more leaders: we can no longer progress without distorting the counter
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 index = urand(0, availableLeaders.size() - 1);
|
||||||
|
ObjectGuid leader = availableLeaders[index];
|
||||||
|
availableLeaders.erase(availableLeaders.begin() + index); // Removes the chosen leader to avoid re-selecting it repeatedly
|
||||||
|
|
||||||
|
Player* player = ObjectAccessor::FindPlayer(leader);
|
||||||
|
if (!player)
|
||||||
|
{
|
||||||
|
LOG_ERROR("playerbots", "ObjectAccessor Cannot find player to set leader for guild {} . Skipped...",
|
||||||
|
guildName.c_str());
|
||||||
|
// we will try with other leaders in the next round (guildNumber is not incremented)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (player->GetGuildId())
|
||||||
|
{
|
||||||
|
// leader already in guild -> we don't advance the counter, we move on to the next one
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_DEBUG("playerbots", "Creating guild name='{}' leader='{}'...", guildName.c_str(), player->GetName().c_str());
|
||||||
|
|
||||||
|
Guild* guild = new Guild();
|
||||||
|
if (!guild->Create(player, guildName))
|
||||||
|
{
|
||||||
|
LOG_ERROR("playerbots", "Error creating guild [ {} ] with leader [ {} ]", guildName.c_str(),
|
||||||
|
player->GetName().c_str());
|
||||||
|
delete guild;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
sGuildMgr->AddGuild(guild);
|
||||||
|
|
||||||
|
LOG_DEBUG("playerbots", "Guild created: id={} name='{}'", guild->GetId(), guildName.c_str());
|
||||||
|
|
||||||
|
// 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>());
|
||||||
|
}
|
||||||
|
|
||||||
|
sPlayerbotAIConfig->randomBotGuilds.push_back(guild->GetId());
|
||||||
|
// The guild is only counted if it is actually created
|
||||||
|
++guildNumber;
|
||||||
|
++createdThisRun;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shows the true total and how many were created during this run
|
||||||
|
LOG_INFO("playerbots", "{} random bot guilds available (created this run: {})",
|
||||||
|
uint32(sPlayerbotAIConfig->randomBotGuilds.size()), createdThisRun);
|
||||||
|
}
|
||||||
|
|
||||||
std::string const RandomPlayerbotFactory::CreateRandomGuildName()
|
std::string const RandomPlayerbotFactory::CreateRandomGuildName()
|
||||||
{
|
{
|
||||||
std::string guildName = "";
|
std::string guildName = "";
|
||||||
@@ -44,22 +44,25 @@ public:
|
|||||||
BloodelfFemale
|
BloodelfFemale
|
||||||
};
|
};
|
||||||
|
|
||||||
static constexpr NameRaceAndGender CombineRaceAndGender(uint8 race, uint8 gender);
|
static constexpr NameRaceAndGender CombineRaceAndGender(uint8 gender, uint8 race);
|
||||||
|
|
||||||
RandomPlayerbotFactory() {};
|
RandomPlayerbotFactory(uint32 accountId);
|
||||||
virtual ~RandomPlayerbotFactory() {}
|
virtual ~RandomPlayerbotFactory() {}
|
||||||
|
|
||||||
Player* CreateRandomBot(WorldSession* session, uint8 cls, std::unordered_map<NameRaceAndGender, std::vector<std::string>>& names);
|
Player* CreateRandomBot(WorldSession* session, uint8 cls, std::unordered_map<NameRaceAndGender, std::vector<std::string>>& names);
|
||||||
static void CreateRandomBots();
|
static void CreateRandomBots();
|
||||||
|
static void CreateRandomGuilds();
|
||||||
static void CreateRandomArenaTeams(ArenaType slot, uint32 count);
|
static void CreateRandomArenaTeams(ArenaType slot, uint32 count);
|
||||||
static std::string const CreateRandomGuildName();
|
static std::string const CreateRandomGuildName();
|
||||||
static uint32 CalculateTotalAccountCount();
|
static uint32 CalculateTotalAccountCount();
|
||||||
static uint32 CalculateAvailableCharsPerAccount();
|
static uint32 CalculateAvailableCharsPerAccount();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static bool IsValidRaceClassCombination(uint8 race, uint8 class_, uint32 expansion);
|
|
||||||
std::string const CreateRandomBotName(NameRaceAndGender raceAndGender);
|
std::string const CreateRandomBotName(NameRaceAndGender raceAndGender);
|
||||||
static std::string const CreateRandomArenaTeamName();
|
static std::string const CreateRandomArenaTeamName();
|
||||||
|
|
||||||
|
uint32 accountId;
|
||||||
|
static std::map<uint8, std::vector<uint8>> availableRaces;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -26,6 +26,7 @@
|
|||||||
#include "DatabaseEnv.h"
|
#include "DatabaseEnv.h"
|
||||||
#include "Define.h"
|
#include "Define.h"
|
||||||
#include "FleeManager.h"
|
#include "FleeManager.h"
|
||||||
|
#include "GameTime.h"
|
||||||
#include "GridNotifiers.h"
|
#include "GridNotifiers.h"
|
||||||
#include "GridNotifiersImpl.h"
|
#include "GridNotifiersImpl.h"
|
||||||
#include "GuildMgr.h"
|
#include "GuildMgr.h"
|
||||||
@@ -35,7 +36,7 @@
|
|||||||
#include "NewRpgInfo.h"
|
#include "NewRpgInfo.h"
|
||||||
#include "NewRpgStrategy.h"
|
#include "NewRpgStrategy.h"
|
||||||
#include "ObjectGuid.h"
|
#include "ObjectGuid.h"
|
||||||
#include "PerfMonitor.h"
|
#include "PerformanceMonitor.h"
|
||||||
#include "Player.h"
|
#include "Player.h"
|
||||||
#include "PlayerbotAI.h"
|
#include "PlayerbotAI.h"
|
||||||
#include "PlayerbotAIConfig.h"
|
#include "PlayerbotAIConfig.h"
|
||||||
@@ -358,7 +359,7 @@ void RandomPlayerbotMgr::UpdateAIInternal(uint32 elapsed, bool /*minimal*/)
|
|||||||
if (totalPmo)
|
if (totalPmo)
|
||||||
totalPmo->finish();
|
totalPmo->finish();
|
||||||
|
|
||||||
totalPmo = sPerfMonitor->start(PERF_MON_TOTAL, "RandomPlayerbotMgr::FullTick");
|
totalPmo = sPerformanceMonitor->start(PERF_MON_TOTAL, "RandomPlayerbotMgr::FullTick");
|
||||||
|
|
||||||
if (!sPlayerbotAIConfig->randomBotAutologin || !sPlayerbotAIConfig->enabled)
|
if (!sPlayerbotAIConfig->randomBotAutologin || !sPlayerbotAIConfig->enabled)
|
||||||
return;
|
return;
|
||||||
@@ -401,7 +402,7 @@ void RandomPlayerbotMgr::UpdateAIInternal(uint32 elapsed, bool /*minimal*/)
|
|||||||
uint32 updateIntervalTurboBoost = _isBotInitializing ? 1 : sPlayerbotAIConfig->randomBotUpdateInterval;
|
uint32 updateIntervalTurboBoost = _isBotInitializing ? 1 : sPlayerbotAIConfig->randomBotUpdateInterval;
|
||||||
SetNextCheckDelay(updateIntervalTurboBoost * (onlineBotFocus + 25) * 10);
|
SetNextCheckDelay(updateIntervalTurboBoost * (onlineBotFocus + 25) * 10);
|
||||||
|
|
||||||
PerfMonitorOperation* pmo = sPerfMonitor->start(
|
PerformanceMonitorOperation* pmo = sPerformanceMonitor->start(
|
||||||
PERF_MON_TOTAL,
|
PERF_MON_TOTAL,
|
||||||
onlineBotCount < maxAllowedBotCount ? "RandomPlayerbotMgr::Login" : "RandomPlayerbotMgr::UpdateAIInternal");
|
onlineBotCount < maxAllowedBotCount ? "RandomPlayerbotMgr::Login" : "RandomPlayerbotMgr::UpdateAIInternal");
|
||||||
|
|
||||||
@@ -632,7 +633,7 @@ void RandomPlayerbotMgr::AssignAccountTypes()
|
|||||||
uint32 existingRndBotAccounts = 0;
|
uint32 existingRndBotAccounts = 0;
|
||||||
uint32 existingAddClassAccounts = 0;
|
uint32 existingAddClassAccounts = 0;
|
||||||
|
|
||||||
for (auto const& [accountId, accountType] : currentAssignments)
|
for (const auto& [accountId, accountType] : currentAssignments)
|
||||||
{
|
{
|
||||||
if (accountType == 1) existingRndBotAccounts++;
|
if (accountType == 1) existingRndBotAccounts++;
|
||||||
else if (accountType == 2) existingAddClassAccounts++;
|
else if (accountType == 2) existingAddClassAccounts++;
|
||||||
@@ -669,9 +670,9 @@ void RandomPlayerbotMgr::AssignAccountTypes()
|
|||||||
uint32 toAssign = neededAddClassAccounts - existingAddClassAccounts;
|
uint32 toAssign = neededAddClassAccounts - existingAddClassAccounts;
|
||||||
uint32 assigned = 0;
|
uint32 assigned = 0;
|
||||||
|
|
||||||
for (size_t idx = allRandomBotAccounts.size(); idx-- > 0 && assigned < toAssign;)
|
for (int i = allRandomBotAccounts.size() - 1; i >= 0 && assigned < toAssign; i--)
|
||||||
{
|
{
|
||||||
uint32 accountId = allRandomBotAccounts[idx];
|
uint32 accountId = allRandomBotAccounts[i];
|
||||||
if (currentAssignments[accountId] == 0) // Unassigned
|
if (currentAssignments[accountId] == 0) // Unassigned
|
||||||
{
|
{
|
||||||
PlayerbotsDatabase.Execute("UPDATE playerbots_account_type SET account_type = 2, assignment_date = NOW() WHERE account_id = {}", accountId);
|
PlayerbotsDatabase.Execute("UPDATE playerbots_account_type SET account_type = 2, assignment_date = NOW() WHERE account_id = {}", accountId);
|
||||||
@@ -687,7 +688,7 @@ void RandomPlayerbotMgr::AssignAccountTypes()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Populate filtered account lists with ALL accounts of each type
|
// Populate filtered account lists with ALL accounts of each type
|
||||||
for (auto const& [accountId, accountType] : currentAssignments)
|
for (const auto& [accountId, accountType] : currentAssignments)
|
||||||
{
|
{
|
||||||
if (accountType == 1) rndBotTypeAccounts.push_back(accountId);
|
if (accountType == 1) rndBotTypeAccounts.push_back(accountId);
|
||||||
else if (accountType == 2) addClassTypeAccounts.push_back(accountId);
|
else if (accountType == 2) addClassTypeAccounts.push_back(accountId);
|
||||||
@@ -797,7 +798,7 @@ uint32 RandomPlayerbotMgr::AddRandomBots()
|
|||||||
std::vector<CharacterInfo> allianceChars;
|
std::vector<CharacterInfo> allianceChars;
|
||||||
std::vector<CharacterInfo> hordeChars;
|
std::vector<CharacterInfo> hordeChars;
|
||||||
|
|
||||||
for (auto const& charInfo : allCharacters)
|
for (const auto& charInfo : allCharacters)
|
||||||
{
|
{
|
||||||
if (IsAlliance(charInfo.rRace))
|
if (IsAlliance(charInfo.rRace))
|
||||||
allianceChars.push_back(charInfo);
|
allianceChars.push_back(charInfo);
|
||||||
@@ -821,7 +822,7 @@ uint32 RandomPlayerbotMgr::AddRandomBots()
|
|||||||
uint32 add_time = sPlayerbotAIConfig->enablePeriodicOnlineOffline
|
uint32 add_time = sPlayerbotAIConfig->enablePeriodicOnlineOffline
|
||||||
? urand(sPlayerbotAIConfig->minRandomBotInWorldTime,
|
? urand(sPlayerbotAIConfig->minRandomBotInWorldTime,
|
||||||
sPlayerbotAIConfig->maxRandomBotInWorldTime)
|
sPlayerbotAIConfig->maxRandomBotInWorldTime)
|
||||||
: sPlayerbotAIConfig->permanentlyInWorldTime;
|
: sPlayerbotAIConfig->permanantlyInWorldTime;
|
||||||
|
|
||||||
SetEventValue(charInfo.guid, "add", 1, add_time);
|
SetEventValue(charInfo.guid, "add", 1, add_time);
|
||||||
SetEventValue(charInfo.guid, "logout", 0, 0);
|
SetEventValue(charInfo.guid, "logout", 0, 0);
|
||||||
@@ -831,7 +832,7 @@ uint32 RandomPlayerbotMgr::AddRandomBots()
|
|||||||
};
|
};
|
||||||
|
|
||||||
// PHASE 1: Log-in Alliance bots up to allowedAllianceCount
|
// PHASE 1: Log-in Alliance bots up to allowedAllianceCount
|
||||||
for (auto const& charInfo : allianceChars)
|
for (const auto& charInfo : allianceChars)
|
||||||
{
|
{
|
||||||
if (!allowedAllianceCount)
|
if (!allowedAllianceCount)
|
||||||
break;
|
break;
|
||||||
@@ -844,7 +845,7 @@ uint32 RandomPlayerbotMgr::AddRandomBots()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// PHASE 2: Log-in Horde bots up to maxAllowedBotCount
|
// PHASE 2: Log-in Horde bots up to maxAllowedBotCount
|
||||||
for (auto const& charInfo : hordeChars)
|
for (const auto& charInfo : hordeChars)
|
||||||
{
|
{
|
||||||
if (!maxAllowedBotCount)
|
if (!maxAllowedBotCount)
|
||||||
break;
|
break;
|
||||||
@@ -854,7 +855,7 @@ uint32 RandomPlayerbotMgr::AddRandomBots()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// PHASE 3: If maxAllowedBotCount wasn't reached, log-in more Alliance bots
|
// PHASE 3: If maxAllowedBotCount wasn't reached, log-in more Alliance bots
|
||||||
for (auto const& charInfo : allianceChars)
|
for (const auto& charInfo : allianceChars)
|
||||||
{
|
{
|
||||||
if (!maxAllowedBotCount)
|
if (!maxAllowedBotCount)
|
||||||
break;
|
break;
|
||||||
@@ -1247,7 +1248,7 @@ void RandomPlayerbotMgr::CheckBgQueue()
|
|||||||
|
|
||||||
void RandomPlayerbotMgr::LogBattlegroundInfo()
|
void RandomPlayerbotMgr::LogBattlegroundInfo()
|
||||||
{
|
{
|
||||||
for (auto const& queueTypePair : BattlegroundData)
|
for (const auto& queueTypePair : BattlegroundData)
|
||||||
{
|
{
|
||||||
uint8 queueType = queueTypePair.first;
|
uint8 queueType = queueTypePair.first;
|
||||||
|
|
||||||
@@ -1255,7 +1256,7 @@ void RandomPlayerbotMgr::LogBattlegroundInfo()
|
|||||||
|
|
||||||
if (uint8 type = BattlegroundMgr::BGArenaType(queueTypeId))
|
if (uint8 type = BattlegroundMgr::BGArenaType(queueTypeId))
|
||||||
{
|
{
|
||||||
for (auto const& bracketIdPair : queueTypePair.second)
|
for (const auto& bracketIdPair : queueTypePair.second)
|
||||||
{
|
{
|
||||||
auto& bgInfo = bracketIdPair.second;
|
auto& bgInfo = bracketIdPair.second;
|
||||||
if (bgInfo.minLevel == 0)
|
if (bgInfo.minLevel == 0)
|
||||||
@@ -1305,7 +1306,7 @@ void RandomPlayerbotMgr::LogBattlegroundInfo()
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto const& bracketIdPair : queueTypePair.second)
|
for (const auto& bracketIdPair : queueTypePair.second)
|
||||||
{
|
{
|
||||||
auto& bgInfo = bracketIdPair.second;
|
auto& bgInfo = bracketIdPair.second;
|
||||||
if (bgInfo.minLevel == 0)
|
if (bgInfo.minLevel == 0)
|
||||||
@@ -1424,7 +1425,7 @@ bool RandomPlayerbotMgr::ProcessBot(uint32 bot)
|
|||||||
LOG_DEBUG("playerbots", "Bot #{}: log out", bot);
|
LOG_DEBUG("playerbots", "Bot #{}: log out", bot);
|
||||||
|
|
||||||
SetEventValue(bot, "add", 0, 0);
|
SetEventValue(bot, "add", 0, 0);
|
||||||
currentBots.remove(bot);
|
currentBots.erase(std::remove(currentBots.begin(), currentBots.end(), bot), currentBots.end());
|
||||||
|
|
||||||
if (player)
|
if (player)
|
||||||
LogoutPlayerBot(botGUID);
|
LogoutPlayerBot(botGUID);
|
||||||
@@ -1479,10 +1480,10 @@ bool RandomPlayerbotMgr::ProcessBot(uint32 bot)
|
|||||||
if (!sRandomPlayerbotMgr->IsRandomBot(player))
|
if (!sRandomPlayerbotMgr->IsRandomBot(player))
|
||||||
update = false;
|
update = false;
|
||||||
|
|
||||||
if (player->GetGroup() && botAI->GetGroupLeader())
|
if (player->GetGroup() && botAI->GetGroupMaster())
|
||||||
{
|
{
|
||||||
PlayerbotAI* groupLeaderBotAI = GET_PLAYERBOT_AI(botAI->GetGroupLeader());
|
PlayerbotAI* groupMasterBotAI = GET_PLAYERBOT_AI(botAI->GetGroupMaster());
|
||||||
if (!groupLeaderBotAI || groupLeaderBotAI->IsRealPlayer())
|
if (!groupMasterBotAI || groupMasterBotAI->IsRealPlayer())
|
||||||
{
|
{
|
||||||
update = false;
|
update = false;
|
||||||
}
|
}
|
||||||
@@ -1654,10 +1655,6 @@ void RandomPlayerbotMgr::RandomTeleport(Player* bot, std::vector<WorldLocation>&
|
|||||||
if (bot->IsBeingTeleported() || !bot->IsInWorld())
|
if (bot->IsBeingTeleported() || !bot->IsInWorld())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// no teleport / movement update when rooted.
|
|
||||||
if (bot->IsRooted())
|
|
||||||
return;
|
|
||||||
|
|
||||||
// ignore when in queue for battle grounds.
|
// ignore when in queue for battle grounds.
|
||||||
if (bot->InBattlegroundQueue())
|
if (bot->InBattlegroundQueue())
|
||||||
return;
|
return;
|
||||||
@@ -1707,7 +1704,8 @@ void RandomPlayerbotMgr::RandomTeleport(Player* bot, std::vector<WorldLocation>&
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
PerfMonitorOperation* pmo = sPerfMonitor->start(PERF_MON_RNDBOT, "RandomTeleportByLocations");
|
|
||||||
|
PerformanceMonitorOperation* pmo = sPerformanceMonitor->start(PERF_MON_RNDBOT, "RandomTeleportByLocations");
|
||||||
|
|
||||||
std::shuffle(std::begin(tlocs), std::end(tlocs), RandomEngine::Instance());
|
std::shuffle(std::begin(tlocs), std::end(tlocs), RandomEngine::Instance());
|
||||||
for (uint32 i = 0; i < tlocs.size(); i++)
|
for (uint32 i = 0; i < tlocs.size(); i++)
|
||||||
@@ -2258,7 +2256,7 @@ void RandomPlayerbotMgr::RandomTeleportForLevel(Player* bot)
|
|||||||
// Pick a weighted city randomly, then a random banker in that city
|
// Pick a weighted city randomly, then a random banker in that city
|
||||||
// then teleport to that banker
|
// then teleport to that banker
|
||||||
CityId selectedCity = weightedCities[urand(0, weightedCities.size() - 1)];
|
CityId selectedCity = weightedCities[urand(0, weightedCities.size() - 1)];
|
||||||
auto const& bankers = cityToBankers.at(selectedCity);
|
const auto& bankers = cityToBankers.at(selectedCity);
|
||||||
uint32 selectedBankerEntry = bankers[urand(0, bankers.size() - 1)];
|
uint32 selectedBankerEntry = bankers[urand(0, bankers.size() - 1)];
|
||||||
auto locIt = bankerEntryToLocation.find(selectedBankerEntry);
|
auto locIt = bankerEntryToLocation.find(selectedBankerEntry);
|
||||||
if (locIt != bankerEntryToLocation.end())
|
if (locIt != bankerEntryToLocation.end())
|
||||||
@@ -2300,7 +2298,7 @@ void RandomPlayerbotMgr::RandomTeleport(Player* bot)
|
|||||||
if (bot->InBattleground())
|
if (bot->InBattleground())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
PerfMonitorOperation* pmo = sPerfMonitor->start(PERF_MON_RNDBOT, "RandomTeleport");
|
PerformanceMonitorOperation* pmo = sPerformanceMonitor->start(PERF_MON_RNDBOT, "RandomTeleport");
|
||||||
std::vector<WorldLocation> locs;
|
std::vector<WorldLocation> locs;
|
||||||
|
|
||||||
std::list<Unit*> targets;
|
std::list<Unit*> targets;
|
||||||
@@ -2362,7 +2360,7 @@ void RandomPlayerbotMgr::IncreaseLevel(Player* bot)
|
|||||||
if (maxLevel > sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL))
|
if (maxLevel > sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL))
|
||||||
maxLevel = sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL);
|
maxLevel = sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL);
|
||||||
|
|
||||||
PerfMonitorOperation* pmo = sPerfMonitor->start(PERF_MON_RNDBOT, "IncreaseLevel");
|
PerformanceMonitorOperation* pmo = sPerformanceMonitor->start(PERF_MON_RNDBOT, "IncreaseLevel");
|
||||||
uint32 lastLevel = GetValue(bot, "level");
|
uint32 lastLevel = GetValue(bot, "level");
|
||||||
uint8 level = bot->GetLevel() + 1;
|
uint8 level = bot->GetLevel() + 1;
|
||||||
if (level > maxLevel)
|
if (level > maxLevel)
|
||||||
@@ -2401,7 +2399,7 @@ void RandomPlayerbotMgr::RandomizeFirst(Player* bot)
|
|||||||
minLevel = std::max(minLevel, sWorld->getIntConfig(CONFIG_START_HEROIC_PLAYER_LEVEL));
|
minLevel = std::max(minLevel, sWorld->getIntConfig(CONFIG_START_HEROIC_PLAYER_LEVEL));
|
||||||
}
|
}
|
||||||
|
|
||||||
PerfMonitorOperation* pmo = sPerfMonitor->start(PERF_MON_RNDBOT, "RandomizeFirst");
|
PerformanceMonitorOperation* pmo = sPerformanceMonitor->start(PERF_MON_RNDBOT, "RandomizeFirst");
|
||||||
|
|
||||||
uint32 level;
|
uint32 level;
|
||||||
|
|
||||||
@@ -2480,7 +2478,7 @@ void RandomPlayerbotMgr::RandomizeMin(Player* bot)
|
|||||||
if (!botAI)
|
if (!botAI)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
PerfMonitorOperation* pmo = sPerfMonitor->start(PERF_MON_RNDBOT, "RandomizeMin");
|
PerformanceMonitorOperation* pmo = sPerformanceMonitor->start(PERF_MON_RNDBOT, "RandomizeMin");
|
||||||
uint32 level = sPlayerbotAIConfig->randomBotMinLevel;
|
uint32 level = sPlayerbotAIConfig->randomBotMinLevel;
|
||||||
SetValue(bot, "level", level);
|
SetValue(bot, "level", level);
|
||||||
PlayerbotFactory factory(bot, level);
|
PlayerbotFactory factory(bot, level);
|
||||||
@@ -2569,7 +2567,7 @@ void RandomPlayerbotMgr::Refresh(Player* bot)
|
|||||||
|
|
||||||
LOG_DEBUG("playerbots", "Refreshing bot {} <{}>", bot->GetGUID().ToString().c_str(), bot->GetName().c_str());
|
LOG_DEBUG("playerbots", "Refreshing bot {} <{}>", bot->GetGUID().ToString().c_str(), bot->GetName().c_str());
|
||||||
|
|
||||||
PerfMonitorOperation* pmo = sPerfMonitor->start(PERF_MON_RNDBOT, "Refresh");
|
PerformanceMonitorOperation* pmo = sPerformanceMonitor->start(PERF_MON_RNDBOT, "Refresh");
|
||||||
|
|
||||||
botAI->Reset();
|
botAI->Reset();
|
||||||
|
|
||||||
@@ -2715,73 +2713,69 @@ std::vector<uint32> RandomPlayerbotMgr::GetBgBots(uint32 bracket)
|
|||||||
return std::move(BgBots);
|
return std::move(BgBots);
|
||||||
}
|
}
|
||||||
|
|
||||||
CachedEvent* RandomPlayerbotMgr::FindEvent(uint32 bot, std::string const& event)
|
uint32 RandomPlayerbotMgr::GetEventValue(uint32 bot, std::string const event)
|
||||||
{
|
{
|
||||||
BotEventCache& cache = eventCache[bot];
|
// load all events at once on first event load
|
||||||
|
if (eventCache[bot].empty())
|
||||||
// Load once
|
|
||||||
if (!cache.loaded)
|
|
||||||
{
|
{
|
||||||
cache.events.clear();
|
|
||||||
|
|
||||||
PlayerbotsDatabasePreparedStatement* stmt =
|
PlayerbotsDatabasePreparedStatement* stmt =
|
||||||
PlayerbotsDatabase.GetPreparedStatement(PLAYERBOTS_SEL_RANDOM_BOTS_BY_OWNER_AND_BOT);
|
PlayerbotsDatabase.GetPreparedStatement(PLAYERBOTS_SEL_RANDOM_BOTS_BY_OWNER_AND_BOT);
|
||||||
stmt->SetData(0, 0);
|
stmt->SetData(0, 0);
|
||||||
stmt->SetData(1, bot);
|
stmt->SetData(1, bot);
|
||||||
|
|
||||||
if (PreparedQueryResult result = PlayerbotsDatabase.Query(stmt))
|
if (PreparedQueryResult result = PlayerbotsDatabase.Query(stmt))
|
||||||
{
|
{
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
Field* fields = result->Fetch();
|
Field* fields = result->Fetch();
|
||||||
|
std::string const eventName = fields[0].Get<std::string>();
|
||||||
|
|
||||||
CachedEvent e;
|
CachedEvent e;
|
||||||
e.value = fields[1].Get<uint32>();
|
e.value = fields[1].Get<uint32>();
|
||||||
e.lastChangeTime = fields[2].Get<uint32>();
|
e.lastChangeTime = fields[2].Get<uint32>();
|
||||||
e.validIn = fields[3].Get<uint32>();
|
e.validIn = fields[3].Get<uint32>();
|
||||||
e.data = fields[4].Get<std::string>();
|
e.data = fields[4].Get<std::string>();
|
||||||
|
eventCache[bot][eventName] = std::move(e);
|
||||||
cache.events.emplace(fields[0].Get<std::string>(), std::move(e));
|
|
||||||
} while (result->NextRow());
|
} while (result->NextRow());
|
||||||
}
|
}
|
||||||
|
|
||||||
cache.loaded = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto it = cache.events.find(event);
|
CachedEvent& e = eventCache[bot][event];
|
||||||
if (it == cache.events.end())
|
/*if (e.IsEmpty())
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
CachedEvent& e = it->second;
|
|
||||||
|
|
||||||
// remove expired events
|
|
||||||
if (e.validIn && (NowSeconds() - e.lastChangeTime) >= e.validIn && event != "specNo" && event != "specLink")
|
|
||||||
{
|
{
|
||||||
cache.events.erase(it);
|
QueryResult results = PlayerbotsDatabase.Query("SELECT `value`, `time`, validIn, `data` FROM
|
||||||
return nullptr;
|
playerbots_random_bots WHERE owner = 0 AND bot = {} AND event = {}", bot, event.c_str());
|
||||||
|
|
||||||
|
if (results)
|
||||||
|
{
|
||||||
|
Field* fields = results->Fetch();
|
||||||
|
e.value = fields[0].Get<uint32>();
|
||||||
|
e.lastChangeTime = fields[1].Get<uint32>();
|
||||||
|
e.validIn = fields[2].Get<uint32>();
|
||||||
|
e.data = fields[3].Get<std::string>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
if ((time(0) - e.lastChangeTime) >= e.validIn && event != "specNo" && event != "specLink")
|
||||||
|
e.value = 0;
|
||||||
|
|
||||||
|
return e.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string const RandomPlayerbotMgr::GetEventData(uint32 bot, std::string const event)
|
||||||
|
{
|
||||||
|
std::string data = "";
|
||||||
|
if (GetEventValue(bot, event))
|
||||||
|
{
|
||||||
|
CachedEvent e = eventCache[bot][event];
|
||||||
|
data = e.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
return &e;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 RandomPlayerbotMgr::GetEventValue(uint32 bot, std::string const& event)
|
uint32 RandomPlayerbotMgr::SetEventValue(uint32 bot, std::string const event, uint32 value, uint32 validIn,
|
||||||
{
|
std::string const data)
|
||||||
if (CachedEvent* e = FindEvent(bot, event))
|
|
||||||
return e->value;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string RandomPlayerbotMgr::GetEventData(uint32 bot, std::string const& event)
|
|
||||||
{
|
|
||||||
if (CachedEvent* e = FindEvent(bot, event))
|
|
||||||
return e->data;
|
|
||||||
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32 RandomPlayerbotMgr::SetEventValue(uint32 bot, std::string const& event, uint32 value, uint32 validIn,
|
|
||||||
std::string const& data)
|
|
||||||
{
|
{
|
||||||
PlayerbotsDatabaseTransaction trans = PlayerbotsDatabase.BeginTransaction();
|
PlayerbotsDatabaseTransaction trans = PlayerbotsDatabase.BeginTransaction();
|
||||||
|
|
||||||
@@ -2797,55 +2791,43 @@ uint32 RandomPlayerbotMgr::SetEventValue(uint32 bot, std::string const& event, u
|
|||||||
stmt = PlayerbotsDatabase.GetPreparedStatement(PLAYERBOTS_INS_RANDOM_BOTS);
|
stmt = PlayerbotsDatabase.GetPreparedStatement(PLAYERBOTS_INS_RANDOM_BOTS);
|
||||||
stmt->SetData(0, 0);
|
stmt->SetData(0, 0);
|
||||||
stmt->SetData(1, bot);
|
stmt->SetData(1, bot);
|
||||||
stmt->SetData(2, NowSeconds());
|
stmt->SetData(2, static_cast<uint32>(GameTime::GetGameTime().count()));
|
||||||
stmt->SetData(3, validIn);
|
stmt->SetData(3, validIn);
|
||||||
stmt->SetData(4, event.c_str());
|
stmt->SetData(4, event.c_str());
|
||||||
stmt->SetData(5, value);
|
stmt->SetData(5, value);
|
||||||
|
if (data != "")
|
||||||
if (!data.empty())
|
{
|
||||||
stmt->SetData(6, data.c_str());
|
stmt->SetData(6, data.c_str());
|
||||||
|
}
|
||||||
else
|
else
|
||||||
stmt->SetData(6); // NULL
|
{
|
||||||
|
stmt->SetData(6);
|
||||||
|
}
|
||||||
trans->Append(stmt);
|
trans->Append(stmt);
|
||||||
}
|
}
|
||||||
|
|
||||||
PlayerbotsDatabase.CommitTransaction(trans);
|
PlayerbotsDatabase.CommitTransaction(trans);
|
||||||
|
|
||||||
// Update in-memory cache
|
CachedEvent e(value, (uint32)time(nullptr), validIn, data);
|
||||||
BotEventCache& cache = eventCache[bot];
|
eventCache[bot][event] = std::move(e);
|
||||||
cache.loaded = true;
|
|
||||||
|
|
||||||
if (!value)
|
|
||||||
{
|
|
||||||
cache.events.erase(event);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
CachedEvent& e = cache.events[event]; // create-on-write is OK here
|
|
||||||
e.value = value;
|
|
||||||
e.lastChangeTime = NowSeconds();
|
|
||||||
e.validIn = validIn;
|
|
||||||
e.data = data;
|
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 RandomPlayerbotMgr::GetValue(uint32 bot, std::string const& type) { return GetEventValue(bot, type); }
|
uint32 RandomPlayerbotMgr::GetValue(uint32 bot, std::string const type) { return GetEventValue(bot, type); }
|
||||||
|
|
||||||
uint32 RandomPlayerbotMgr::GetValue(Player* bot, std::string const& type)
|
uint32 RandomPlayerbotMgr::GetValue(Player* bot, std::string const type)
|
||||||
{
|
{
|
||||||
return GetValue(bot->GetGUID().GetCounter(), type);
|
return GetValue(bot->GetGUID().GetCounter(), type);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string RandomPlayerbotMgr::GetData(uint32 bot, std::string const& type) { return GetEventData(bot, type); }
|
std::string const RandomPlayerbotMgr::GetData(uint32 bot, std::string const type) { return GetEventData(bot, type); }
|
||||||
|
|
||||||
void RandomPlayerbotMgr::SetValue(uint32 bot, std::string const& type, uint32 value, std::string const& data)
|
void RandomPlayerbotMgr::SetValue(uint32 bot, std::string const type, uint32 value, std::string const data)
|
||||||
{
|
{
|
||||||
SetEventValue(bot, type, value, sPlayerbotAIConfig->maxRandomBotInWorldTime, data);
|
SetEventValue(bot, type, value, sPlayerbotAIConfig->maxRandomBotInWorldTime, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RandomPlayerbotMgr::SetValue(Player* bot, std::string const& type, uint32 value, std::string const& data)
|
void RandomPlayerbotMgr::SetValue(Player* bot, std::string const type, uint32 value, std::string const data)
|
||||||
{
|
{
|
||||||
SetValue(bot->GetGUID().GetCounter(), type, value, data);
|
SetValue(bot->GetGUID().GetCounter(), type, value, data);
|
||||||
}
|
}
|
||||||
@@ -3134,7 +3116,7 @@ void RandomPlayerbotMgr::OnPlayerLogin(Player* player)
|
|||||||
void RandomPlayerbotMgr::OnPlayerLoginError(uint32 bot)
|
void RandomPlayerbotMgr::OnPlayerLoginError(uint32 bot)
|
||||||
{
|
{
|
||||||
SetEventValue(bot, "add", 0, 0);
|
SetEventValue(bot, "add", 0, 0);
|
||||||
currentBots.remove(bot);
|
currentBots.erase(std::remove(currentBots.begin(), currentBots.end(), bot), currentBots.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
Player* RandomPlayerbotMgr::GetRandomPlayer()
|
Player* RandomPlayerbotMgr::GetRandomPlayer()
|
||||||
@@ -3214,12 +3196,6 @@ void RandomPlayerbotMgr::PrintStats()
|
|||||||
lvlPerRace[bot->getRace()] += bot->GetLevel();
|
lvlPerRace[bot->getRace()] += bot->GetLevel();
|
||||||
|
|
||||||
PlayerbotAI* botAI = GET_PLAYERBOT_AI(bot);
|
PlayerbotAI* botAI = GET_PLAYERBOT_AI(bot);
|
||||||
if (!botAI)
|
|
||||||
{
|
|
||||||
LOG_ERROR("playerbots", "Player/Bot {} is registered in sRandomPlayerbotMgr playerBots and has no bot AI!", bot->GetName().c_str());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (botAI->AllowActivity())
|
if (botAI->AllowActivity())
|
||||||
++active;
|
++active;
|
||||||
|
|
||||||
@@ -3522,8 +3498,7 @@ void RandomPlayerbotMgr::Remove(Player* bot)
|
|||||||
stmt->SetData(1, owner.GetCounter());
|
stmt->SetData(1, owner.GetCounter());
|
||||||
PlayerbotsDatabase.Execute(stmt);
|
PlayerbotsDatabase.Execute(stmt);
|
||||||
|
|
||||||
uint32 botId = owner.GetCounter();
|
eventCache[owner.GetCounter()].clear();
|
||||||
eventCache.erase(botId);
|
|
||||||
|
|
||||||
LogoutPlayerBot(owner);
|
LogoutPlayerBot(owner);
|
||||||
}
|
}
|
||||||
@@ -3540,7 +3515,7 @@ CreatureData const* RandomPlayerbotMgr::GetCreatureDataByEntry(uint32 entry)
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
ObjectGuid RandomPlayerbotMgr::GetBattleMasterGUID(Player* bot, BattlegroundTypeId bgTypeId)
|
ObjectGuid const RandomPlayerbotMgr::GetBattleMasterGUID(Player* bot, BattlegroundTypeId bgTypeId)
|
||||||
{
|
{
|
||||||
ObjectGuid battleMasterGUID = ObjectGuid::Empty;
|
ObjectGuid battleMasterGUID = ObjectGuid::Empty;
|
||||||
|
|
||||||
@@ -9,7 +9,6 @@
|
|||||||
#include "NewRpgInfo.h"
|
#include "NewRpgInfo.h"
|
||||||
#include "ObjectGuid.h"
|
#include "ObjectGuid.h"
|
||||||
#include "PlayerbotMgr.h"
|
#include "PlayerbotMgr.h"
|
||||||
#include "GameTime.h"
|
|
||||||
|
|
||||||
struct BattlegroundInfo
|
struct BattlegroundInfo
|
||||||
{
|
{
|
||||||
@@ -43,23 +42,28 @@ struct BattlegroundInfo
|
|||||||
};
|
};
|
||||||
|
|
||||||
class ChatHandler;
|
class ChatHandler;
|
||||||
class PerfMonitorOperation;
|
class PerformanceMonitorOperation;
|
||||||
class WorldLocation;
|
class WorldLocation;
|
||||||
|
|
||||||
struct CachedEvent
|
class CachedEvent
|
||||||
{
|
{
|
||||||
uint32 value = 0;
|
public:
|
||||||
uint32 lastChangeTime = 0;
|
CachedEvent() : value(0), lastChangeTime(0), validIn(0), data("") {}
|
||||||
uint32 validIn = 0;
|
CachedEvent(const CachedEvent& other)
|
||||||
|
: value(other.value), lastChangeTime(other.lastChangeTime), validIn(other.validIn), data(other.data)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
CachedEvent(uint32 value, uint32 lastChangeTime, uint32 validIn, std::string const data = "")
|
||||||
|
: value(value), lastChangeTime(lastChangeTime), validIn(validIn), data(data)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsEmpty() { return !lastChangeTime; }
|
||||||
|
|
||||||
|
uint32 value;
|
||||||
|
uint32 lastChangeTime;
|
||||||
|
uint32 validIn;
|
||||||
std::string data;
|
std::string data;
|
||||||
|
|
||||||
bool IsEmpty() const { return !lastChangeTime; }
|
|
||||||
};
|
|
||||||
|
|
||||||
struct BotEventCache
|
|
||||||
{
|
|
||||||
bool loaded = false;
|
|
||||||
std::unordered_map<std::string, CachedEvent> events;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// https://gist.github.com/bradley219/5373998
|
// https://gist.github.com/bradley219/5373998
|
||||||
@@ -135,13 +139,13 @@ public:
|
|||||||
void Revive(Player* player);
|
void Revive(Player* player);
|
||||||
void ChangeStrategy(Player* player);
|
void ChangeStrategy(Player* player);
|
||||||
void ChangeStrategyOnce(Player* player);
|
void ChangeStrategyOnce(Player* player);
|
||||||
uint32 GetValue(Player* bot, std::string const& type);
|
uint32 GetValue(Player* bot, std::string const type);
|
||||||
uint32 GetValue(uint32 bot, std::string const& type);
|
uint32 GetValue(uint32 bot, std::string const type);
|
||||||
std::string GetData(uint32 bot, std::string const& type);
|
std::string const GetData(uint32 bot, std::string const type);
|
||||||
void SetValue(uint32 bot, std::string const& type, uint32 value, std::string const& data = "");
|
void SetValue(uint32 bot, std::string const type, uint32 value, std::string const data = "");
|
||||||
void SetValue(Player* bot, std::string const& type, uint32 value, std::string const& data = "");
|
void SetValue(Player* bot, std::string const type, uint32 value, std::string const data = "");
|
||||||
void Remove(Player* bot);
|
void Remove(Player* bot);
|
||||||
ObjectGuid GetBattleMasterGUID(Player* bot, BattlegroundTypeId bgTypeId);
|
ObjectGuid const GetBattleMasterGUID(Player* bot, BattlegroundTypeId bgTypeId);
|
||||||
CreatureData const* GetCreatureDataByEntry(uint32 entry);
|
CreatureData const* GetCreatureDataByEntry(uint32 entry);
|
||||||
void LoadBattleMastersCache();
|
void LoadBattleMastersCache();
|
||||||
std::map<uint32, std::map<uint32, BattlegroundInfo>> BattlegroundData;
|
std::map<uint32, std::map<uint32, BattlegroundInfo>> BattlegroundData;
|
||||||
@@ -199,11 +203,10 @@ private:
|
|||||||
bool _isBotInitializing = true;
|
bool _isBotInitializing = true;
|
||||||
bool _isBotLogging = true;
|
bool _isBotLogging = true;
|
||||||
NewRpgStatistic rpgStasticTotal;
|
NewRpgStatistic rpgStasticTotal;
|
||||||
CachedEvent* FindEvent(uint32 bot, std::string const& event);
|
uint32 GetEventValue(uint32 bot, std::string const event);
|
||||||
uint32 GetEventValue(uint32 bot, std::string const& event);
|
std::string const GetEventData(uint32 bot, std::string const event);
|
||||||
std::string GetEventData(uint32 bot, std::string const& event);
|
uint32 SetEventValue(uint32 bot, std::string const event, uint32 value, uint32 validIn,
|
||||||
uint32 SetEventValue(uint32 bot, std::string const& event, uint32 value, uint32 validIn,
|
std::string const data = "");
|
||||||
std::string const& data = "");
|
|
||||||
void GetBots();
|
void GetBots();
|
||||||
std::vector<uint32> GetBgBots(uint32 bracket);
|
std::vector<uint32> GetBgBots(uint32 bracket);
|
||||||
time_t BgCheckTimer;
|
time_t BgCheckTimer;
|
||||||
@@ -225,7 +228,7 @@ private:
|
|||||||
// std::map<uint32, std::vector<WorldLocation>> rpgLocsCache;
|
// std::map<uint32, std::vector<WorldLocation>> rpgLocsCache;
|
||||||
std::map<uint32, std::map<uint32, std::vector<WorldLocation>>> rpgLocsCacheLevel;
|
std::map<uint32, std::map<uint32, std::vector<WorldLocation>>> rpgLocsCacheLevel;
|
||||||
std::map<TeamId, std::map<BattlegroundTypeId, std::vector<uint32>>> BattleMastersCache;
|
std::map<TeamId, std::map<BattlegroundTypeId, std::vector<uint32>>> BattleMastersCache;
|
||||||
std::unordered_map<uint32, BotEventCache> eventCache;
|
std::map<uint32, std::map<std::string, CachedEvent>> eventCache;
|
||||||
std::list<uint32> currentBots;
|
std::list<uint32> currentBots;
|
||||||
uint32 bgBotsCount;
|
uint32 bgBotsCount;
|
||||||
uint32 playersLevel;
|
uint32 playersLevel;
|
||||||
@@ -235,7 +238,6 @@ private:
|
|||||||
std::vector<uint32> addClassTypeAccounts; // Accounts marked as AddClass (type 2)
|
std::vector<uint32> addClassTypeAccounts; // Accounts marked as AddClass (type 2)
|
||||||
|
|
||||||
//void ScaleBotActivity(); // Deprecated function
|
//void ScaleBotActivity(); // Deprecated function
|
||||||
static inline uint32 NowSeconds() { return static_cast<uint32>(GameTime::GetGameTime().count()); }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#define sRandomPlayerbotMgr RandomPlayerbotMgr::instance()
|
#define sRandomPlayerbotMgr RandomPlayerbotMgr::instance()
|
||||||
@@ -1,165 +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 "BloodDKStrategy.h"
|
|
||||||
|
|
||||||
#include "Playerbots.h"
|
|
||||||
|
|
||||||
class BloodDKStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
BloodDKStrategyActionNodeFactory()
|
|
||||||
{
|
|
||||||
creators["rune strike"] = &rune_strike;
|
|
||||||
creators["heart strike"] = &heart_strike;
|
|
||||||
creators["death strike"] = &death_strike;
|
|
||||||
creators["icy touch"] = &icy_touch;
|
|
||||||
creators["dark command"] = &dark_command;
|
|
||||||
creators["taunt spell"] = &dark_command;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
static ActionNode* rune_strike([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode(
|
|
||||||
"rune strike",
|
|
||||||
{
|
|
||||||
NextAction("frost presence")
|
|
||||||
},
|
|
||||||
/*A*/ {},
|
|
||||||
/*C*/ {}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
static ActionNode* icy_touch([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode(
|
|
||||||
"icy touch",
|
|
||||||
{
|
|
||||||
NextAction("frost presence")
|
|
||||||
},
|
|
||||||
/*A*/ {},
|
|
||||||
/*C*/ {}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
static ActionNode* heart_strike([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode(
|
|
||||||
"heart strike",
|
|
||||||
{
|
|
||||||
NextAction("frost presence")
|
|
||||||
},
|
|
||||||
/*A*/ {},
|
|
||||||
/*C*/ {}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ActionNode* death_strike([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode(
|
|
||||||
"death strike",
|
|
||||||
{
|
|
||||||
NextAction("frost presence")
|
|
||||||
},
|
|
||||||
/*A*/ {},
|
|
||||||
/*C*/ {}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
static ActionNode* dark_command([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode(
|
|
||||||
"dark command",
|
|
||||||
{
|
|
||||||
NextAction("frost presence")
|
|
||||||
},
|
|
||||||
/*A*/ {
|
|
||||||
NextAction("death grip")
|
|
||||||
},
|
|
||||||
/*C*/ {}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
BloodDKStrategy::BloodDKStrategy(PlayerbotAI* botAI) : GenericDKStrategy(botAI)
|
|
||||||
{
|
|
||||||
actionNodeFactories.Add(new BloodDKStrategyActionNodeFactory());
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<NextAction> BloodDKStrategy::getDefaultActions()
|
|
||||||
{
|
|
||||||
return {
|
|
||||||
NextAction("rune strike", ACTION_DEFAULT + 0.8f),
|
|
||||||
NextAction("icy touch", ACTION_DEFAULT + 0.7f),
|
|
||||||
NextAction("heart strike", ACTION_DEFAULT + 0.6f),
|
|
||||||
NextAction("blood strike", ACTION_DEFAULT + 0.5f),
|
|
||||||
NextAction("dancing rune weapon", ACTION_DEFAULT + 0.4f),
|
|
||||||
NextAction("death coil", ACTION_DEFAULT + 0.3f),
|
|
||||||
NextAction("plague strike", ACTION_DEFAULT + 0.2f),
|
|
||||||
NextAction("horn of winter", ACTION_DEFAULT + 0.1f),
|
|
||||||
NextAction("melee", ACTION_DEFAULT)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
void BloodDKStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|
||||||
{
|
|
||||||
GenericDKStrategy::InitTriggers(triggers);
|
|
||||||
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"rune strike",
|
|
||||||
{
|
|
||||||
NextAction("rune strike", ACTION_NORMAL + 3)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"blood tap",
|
|
||||||
{
|
|
||||||
NextAction("blood tap", ACTION_HIGH + 5)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"lose aggro",
|
|
||||||
{
|
|
||||||
NextAction("dark command", ACTION_HIGH + 3)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"low health",
|
|
||||||
{
|
|
||||||
NextAction("army of the dead", ACTION_HIGH + 4),
|
|
||||||
NextAction("death strike", ACTION_HIGH + 3)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"critical health",
|
|
||||||
{
|
|
||||||
NextAction("vampiric blood", ACTION_HIGH + 5)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"icy touch",
|
|
||||||
{
|
|
||||||
NextAction("icy touch", ACTION_HIGH + 2)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"plague strike",
|
|
||||||
{
|
|
||||||
NextAction("plague strike", ACTION_HIGH + 2)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,169 +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 "FrostDKStrategy.h"
|
|
||||||
|
|
||||||
#include "Playerbots.h"
|
|
||||||
|
|
||||||
class FrostDKStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
FrostDKStrategyActionNodeFactory()
|
|
||||||
{
|
|
||||||
creators["icy touch"] = &icy_touch;
|
|
||||||
creators["obliterate"] = &obliterate;
|
|
||||||
creators["howling blast"] = &howling_blast;
|
|
||||||
creators["frost strike"] = &frost_strike;
|
|
||||||
creators["rune strike"] = &rune_strike;
|
|
||||||
creators["unbreakable armor"] = &unbreakable_armor;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
static ActionNode* icy_touch([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode(
|
|
||||||
"icy touch",
|
|
||||||
/*P*/ { NextAction("blood presence") },
|
|
||||||
/*A*/ {},
|
|
||||||
/*C*/ {}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ActionNode* obliterate([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode(
|
|
||||||
"obliterate",
|
|
||||||
/*P*/ { NextAction("blood presence") },
|
|
||||||
/*A*/ {},
|
|
||||||
/*C*/ {}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ActionNode* rune_strike([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode(
|
|
||||||
"rune strike",
|
|
||||||
/*P*/ { NextAction("blood presence") },
|
|
||||||
/*A*/ { NextAction("melee") },
|
|
||||||
/*C*/ {}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ActionNode* frost_strike([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode(
|
|
||||||
"frost strike",
|
|
||||||
/*P*/ { NextAction("blood presence") },
|
|
||||||
/*A*/ {},
|
|
||||||
/*C*/ {}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ActionNode* howling_blast([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode(
|
|
||||||
"howling blast",
|
|
||||||
/*P*/ { NextAction("blood presence") },
|
|
||||||
/*A*/ {},
|
|
||||||
/*C*/ {}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
static ActionNode* unbreakable_armor([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode(
|
|
||||||
"unbreakable armor",
|
|
||||||
/*P*/ { NextAction("blood tap") },
|
|
||||||
/*A*/ {},
|
|
||||||
/*C*/ {}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
FrostDKStrategy::FrostDKStrategy(PlayerbotAI* botAI) : GenericDKStrategy(botAI)
|
|
||||||
{
|
|
||||||
actionNodeFactories.Add(new FrostDKStrategyActionNodeFactory());
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<NextAction> FrostDKStrategy::getDefaultActions()
|
|
||||||
{
|
|
||||||
return {
|
|
||||||
NextAction("obliterate", ACTION_DEFAULT + 0.7f),
|
|
||||||
NextAction("frost strike", ACTION_DEFAULT + 0.4f),
|
|
||||||
NextAction("empower rune weapon", ACTION_DEFAULT + 0.3f),
|
|
||||||
NextAction("horn of winter", ACTION_DEFAULT + 0.1f),
|
|
||||||
NextAction("melee", ACTION_DEFAULT)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
void FrostDKStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|
||||||
{
|
|
||||||
GenericDKStrategy::InitTriggers(triggers);
|
|
||||||
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"unbreakable armor",
|
|
||||||
{
|
|
||||||
NextAction("unbreakable armor", ACTION_DEFAULT + 0.6f)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"freezing fog",
|
|
||||||
{
|
|
||||||
NextAction("howling blast", ACTION_DEFAULT + 0.5f)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"high blood rune",
|
|
||||||
{
|
|
||||||
NextAction("blood strike", ACTION_DEFAULT + 0.2f)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"army of the dead",
|
|
||||||
{
|
|
||||||
NextAction("army of the dead", ACTION_HIGH + 6)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"icy touch",
|
|
||||||
{
|
|
||||||
NextAction("icy touch", ACTION_HIGH + 2)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"plague strike",
|
|
||||||
{
|
|
||||||
NextAction("plague strike", ACTION_HIGH + 2)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void FrostDKAoeStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|
||||||
{
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"medium aoe",
|
|
||||||
{
|
|
||||||
NextAction("howling blast", ACTION_HIGH + 4)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,192 +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 "UnholyDKStrategy.h"
|
|
||||||
|
|
||||||
#include "Playerbots.h"
|
|
||||||
|
|
||||||
class UnholyDKStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
UnholyDKStrategyActionNodeFactory()
|
|
||||||
{
|
|
||||||
creators["death strike"] = &death_strike;
|
|
||||||
creators["scourge strike"] = &scourge_strike;
|
|
||||||
creators["ghoul frenzy"] = &ghoul_frenzy;
|
|
||||||
creators["corpse explosion"] = &corpse_explosion;
|
|
||||||
creators["icy touch"] = &icy_touch;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
static ActionNode* death_strike([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode(
|
|
||||||
"death strike",
|
|
||||||
/*P*/ { NextAction("blood presence") },
|
|
||||||
/*A*/ {},
|
|
||||||
/*C*/ {}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
static ActionNode* ghoul_frenzy([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode(
|
|
||||||
"ghoul frenzy",
|
|
||||||
/*P*/ { NextAction("blood presence") },
|
|
||||||
/*A*/ {},
|
|
||||||
/*C*/ {}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
static ActionNode* corpse_explosion([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode(
|
|
||||||
"corpse explosion",
|
|
||||||
/*P*/ { NextAction("blood presence") },
|
|
||||||
/*A*/ {},
|
|
||||||
/*C*/ {}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ActionNode* scourge_strike([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode(
|
|
||||||
"scourge strike",
|
|
||||||
/*P*/ { NextAction("blood presence") },
|
|
||||||
/*A*/ {},
|
|
||||||
/*C*/ {}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
static ActionNode* icy_touch([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode(
|
|
||||||
"icy touch",
|
|
||||||
/*P*/ { NextAction("blood presence") },
|
|
||||||
/*A*/ {},
|
|
||||||
/*C*/ {}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
UnholyDKStrategy::UnholyDKStrategy(PlayerbotAI* botAI) : GenericDKStrategy(botAI)
|
|
||||||
{
|
|
||||||
actionNodeFactories.Add(new UnholyDKStrategyActionNodeFactory());
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<NextAction> UnholyDKStrategy::getDefaultActions()
|
|
||||||
{
|
|
||||||
return {
|
|
||||||
NextAction("death and decay", ACTION_HIGH + 5),
|
|
||||||
NextAction("summon gargoyle", ACTION_DEFAULT + 0.4f),
|
|
||||||
NextAction("horn of winter", ACTION_DEFAULT + 0.2f),
|
|
||||||
NextAction("death coil", ACTION_DEFAULT + 0.1f),
|
|
||||||
NextAction("melee", ACTION_DEFAULT)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
void UnholyDKStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|
||||||
{
|
|
||||||
GenericDKStrategy::InitTriggers(triggers);
|
|
||||||
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"death and decay cooldown",
|
|
||||||
{
|
|
||||||
NextAction("ghoul frenzy", ACTION_DEFAULT + 0.9f),
|
|
||||||
NextAction("scourge strike", ACTION_DEFAULT + 0.8f),
|
|
||||||
NextAction("icy touch", ACTION_DEFAULT + 0.7f),
|
|
||||||
NextAction("blood strike", ACTION_DEFAULT + 0.6f),
|
|
||||||
NextAction("plague strike", ACTION_DEFAULT + 0.5f),
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"dd cd and no desolation",
|
|
||||||
{
|
|
||||||
NextAction("blood strike", ACTION_DEFAULT + 0.75f)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"high frost rune",
|
|
||||||
{
|
|
||||||
NextAction("icy touch", ACTION_NORMAL + 3)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"high blood rune",
|
|
||||||
{
|
|
||||||
NextAction("blood strike", ACTION_NORMAL + 2)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"high unholy rune",
|
|
||||||
{
|
|
||||||
NextAction("plague strike", ACTION_NORMAL + 1)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("dd cd and plague strike 3s",
|
|
||||||
{
|
|
||||||
NextAction("plague strike", ACTION_HIGH + 1)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("dd cd and icy touch 3s",
|
|
||||||
{
|
|
||||||
NextAction("icy touch", ACTION_HIGH + 2)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("no rune",
|
|
||||||
{
|
|
||||||
NextAction("empower rune weapon", ACTION_HIGH + 1)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"army of the dead",
|
|
||||||
{
|
|
||||||
NextAction("army of the dead", ACTION_HIGH + 6)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("bone shield",
|
|
||||||
{
|
|
||||||
NextAction("bone shield", ACTION_HIGH + 3)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void UnholyDKAoeStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|
||||||
{
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"loot available",
|
|
||||||
{
|
|
||||||
NextAction("corpse explosion", ACTION_NORMAL + 1)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"medium aoe",
|
|
||||||
{
|
|
||||||
NextAction("death and decay", ACTION_NORMAL + 3),
|
|
||||||
NextAction("corpse explosion", ACTION_NORMAL + 3)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,256 +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 "BearTankDruidStrategy.h"
|
|
||||||
|
|
||||||
#include "Playerbots.h"
|
|
||||||
|
|
||||||
class BearTankDruidStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
BearTankDruidStrategyActionNodeFactory()
|
|
||||||
{
|
|
||||||
creators["melee"] = &melee;
|
|
||||||
creators["feral charge - bear"] = &feral_charge_bear;
|
|
||||||
creators["swipe (bear)"] = &swipe_bear;
|
|
||||||
creators["faerie fire (feral)"] = &faerie_fire_feral;
|
|
||||||
creators["bear form"] = &bear_form;
|
|
||||||
creators["dire bear form"] = &dire_bear_form;
|
|
||||||
creators["mangle (bear)"] = &mangle_bear;
|
|
||||||
creators["maul"] = &maul;
|
|
||||||
creators["bash"] = &bash;
|
|
||||||
creators["swipe"] = &swipe;
|
|
||||||
creators["lacerate"] = &lacerate;
|
|
||||||
creators["demoralizing roar"] = &demoralizing_roar;
|
|
||||||
creators["taunt spell"] = &growl;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
static ActionNode* melee([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode(
|
|
||||||
"melee",
|
|
||||||
/*P*/ { NextAction("feral charge - bear") },
|
|
||||||
/*A*/ {},
|
|
||||||
/*C*/ {}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ActionNode* feral_charge_bear([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode(
|
|
||||||
"feral charge - bear",
|
|
||||||
/*P*/ {},
|
|
||||||
/*A*/ { NextAction("reach melee") },
|
|
||||||
/*C*/ {}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ActionNode* swipe_bear([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode(
|
|
||||||
"swipe (bear)",
|
|
||||||
/*P*/ {},
|
|
||||||
/*A*/ {},
|
|
||||||
/*C*/ {}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ActionNode* faerie_fire_feral([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode(
|
|
||||||
"faerie fire (feral)",
|
|
||||||
/*P*/ { NextAction("feral charge - bear") },
|
|
||||||
/*A*/ {},
|
|
||||||
/*C*/ {}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ActionNode* bear_form([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode(
|
|
||||||
"bear form",
|
|
||||||
/*P*/ {},
|
|
||||||
/*A*/ {},
|
|
||||||
/*C*/ {}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ActionNode* dire_bear_form([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode(
|
|
||||||
"dire bear form",
|
|
||||||
/*P*/ { NextAction("caster form") },
|
|
||||||
/*A*/ { NextAction("bear form") },
|
|
||||||
/*C*/ {}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ActionNode* mangle_bear([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode(
|
|
||||||
"mangle (bear)",
|
|
||||||
/*P*/ {},
|
|
||||||
/*A*/ {},
|
|
||||||
/*C*/ {}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ActionNode* maul([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode(
|
|
||||||
"maul",
|
|
||||||
/*P*/ {},
|
|
||||||
/*A*/ { NextAction("melee") },
|
|
||||||
/*C*/ {}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ActionNode* bash([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode(
|
|
||||||
"bash",
|
|
||||||
/*P*/ {},
|
|
||||||
/*A*/ { NextAction("melee") },
|
|
||||||
/*C*/ {}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ActionNode* swipe([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode(
|
|
||||||
"swipe",
|
|
||||||
/*P*/ {},
|
|
||||||
/*A*/ { NextAction("melee") },
|
|
||||||
/*C*/ {}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ActionNode* lacerate([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode(
|
|
||||||
"lacerate",
|
|
||||||
/*P*/ {},
|
|
||||||
/*A*/ { NextAction("maul") },
|
|
||||||
/*C*/ {}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ActionNode* growl([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode(
|
|
||||||
"growl",
|
|
||||||
/*P*/ {},
|
|
||||||
/*A*/ {},
|
|
||||||
/*C*/ {}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ActionNode* demoralizing_roar([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode(
|
|
||||||
"demoralizing roar",
|
|
||||||
/*P*/ {},
|
|
||||||
/*A*/ {},
|
|
||||||
/*C*/ {}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
BearTankDruidStrategy::BearTankDruidStrategy(PlayerbotAI* botAI) : FeralDruidStrategy(botAI)
|
|
||||||
{
|
|
||||||
actionNodeFactories.Add(new BearTankDruidStrategyActionNodeFactory());
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<NextAction> BearTankDruidStrategy::getDefaultActions()
|
|
||||||
{
|
|
||||||
return {
|
|
||||||
NextAction("mangle (bear)", ACTION_DEFAULT + 0.5f),
|
|
||||||
NextAction("faerie fire (feral)", ACTION_DEFAULT + 0.4f),
|
|
||||||
NextAction("lacerate", ACTION_DEFAULT + 0.3f),
|
|
||||||
NextAction("maul", ACTION_DEFAULT + 0.2f),
|
|
||||||
NextAction("enrage", ACTION_DEFAULT + 0.1f),
|
|
||||||
NextAction("melee", ACTION_DEFAULT)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
void BearTankDruidStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|
||||||
{
|
|
||||||
FeralDruidStrategy::InitTriggers(triggers);
|
|
||||||
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"enemy out of melee",
|
|
||||||
{
|
|
||||||
NextAction("feral charge - bear", ACTION_NORMAL + 8)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"bear form",
|
|
||||||
{
|
|
||||||
NextAction("dire bear form", ACTION_HIGH + 8)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"low health",
|
|
||||||
{
|
|
||||||
NextAction("frenzied regeneration", ACTION_HIGH + 7)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"faerie fire (feral)",
|
|
||||||
{
|
|
||||||
NextAction("faerie fire (feral)", ACTION_HIGH + 7)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"lose aggro",
|
|
||||||
{
|
|
||||||
NextAction("growl", ACTION_HIGH + 8)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"medium aoe",
|
|
||||||
{
|
|
||||||
NextAction("demoralizing roar", ACTION_HIGH + 6),
|
|
||||||
NextAction("swipe (bear)", ACTION_HIGH + 6)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"light aoe",
|
|
||||||
{
|
|
||||||
NextAction("swipe (bear)", ACTION_HIGH + 5)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"bash",
|
|
||||||
{
|
|
||||||
NextAction("bash", ACTION_INTERRUPT + 2)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"bash on enemy healer",
|
|
||||||
{
|
|
||||||
NextAction("bash on enemy healer", ACTION_INTERRUPT + 1)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,254 +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 "CasterDruidStrategy.h"
|
|
||||||
|
|
||||||
#include "AiObjectContext.h"
|
|
||||||
#include "FeralDruidStrategy.h"
|
|
||||||
|
|
||||||
class CasterDruidStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
CasterDruidStrategyActionNodeFactory()
|
|
||||||
{
|
|
||||||
creators["faerie fire"] = &faerie_fire;
|
|
||||||
creators["hibernate"] = &hibernate;
|
|
||||||
creators["entangling roots"] = &entangling_roots;
|
|
||||||
creators["entangling roots on cc"] = &entangling_roots_on_cc;
|
|
||||||
creators["wrath"] = &wrath;
|
|
||||||
creators["starfall"] = &starfall;
|
|
||||||
creators["insect swarm"] = &insect_swarm;
|
|
||||||
creators["moonfire"] = &moonfire;
|
|
||||||
creators["starfire"] = &starfire;
|
|
||||||
creators["moonkin form"] = &moonkin_form;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
static ActionNode* faerie_fire([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode(
|
|
||||||
"faerie fire",
|
|
||||||
/*P*/ { NextAction("moonkin form") },
|
|
||||||
/*A*/ {},
|
|
||||||
/*C*/ {}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ActionNode* hibernate([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode(
|
|
||||||
"hibernate",
|
|
||||||
/*P*/ { NextAction("moonkin form") },
|
|
||||||
/*A*/ { NextAction("entangling roots") },
|
|
||||||
/*C*/ {}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ActionNode* entangling_roots([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode(
|
|
||||||
"entangling roots",
|
|
||||||
/*P*/ { NextAction("moonkin form") },
|
|
||||||
/*A*/ {},
|
|
||||||
/*C*/ {}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ActionNode* entangling_roots_on_cc([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode(
|
|
||||||
"entangling roots on cc",
|
|
||||||
/*P*/ { NextAction("moonkin form") },
|
|
||||||
/*A*/ {},
|
|
||||||
/*C*/ {}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ActionNode* wrath([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode(
|
|
||||||
"wrath",
|
|
||||||
/*P*/ { NextAction("moonkin form") },
|
|
||||||
/*A*/ {},
|
|
||||||
/*C*/ {}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ActionNode* starfall([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode(
|
|
||||||
"starfall",
|
|
||||||
/*P*/ { NextAction("moonkin form") },
|
|
||||||
/*A*/ {},
|
|
||||||
/*C*/ {}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ActionNode* insect_swarm([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode(
|
|
||||||
"insect swarm",
|
|
||||||
/*P*/ { NextAction("moonkin form") },
|
|
||||||
/*A*/ {},
|
|
||||||
/*C*/ {}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ActionNode* moonfire([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode(
|
|
||||||
"moonfire",
|
|
||||||
/*P*/ { NextAction("moonkin form") },
|
|
||||||
/*A*/ {},
|
|
||||||
/*C*/ {}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ActionNode* starfire([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode(
|
|
||||||
"starfire",
|
|
||||||
/*P*/ { NextAction("moonkin form") },
|
|
||||||
/*A*/ {},
|
|
||||||
/*C*/ {}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ActionNode* moonkin_form([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode(
|
|
||||||
"moonkin form",
|
|
||||||
/*P*/ { NextAction("caster form") },
|
|
||||||
/*A*/ {},
|
|
||||||
/*C*/ {}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
CasterDruidStrategy::CasterDruidStrategy(PlayerbotAI* botAI) : GenericDruidStrategy(botAI)
|
|
||||||
{
|
|
||||||
actionNodeFactories.Add(new CasterDruidStrategyActionNodeFactory());
|
|
||||||
actionNodeFactories.Add(new ShapeshiftDruidStrategyActionNodeFactory());
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<NextAction> CasterDruidStrategy::getDefaultActions()
|
|
||||||
{
|
|
||||||
return {
|
|
||||||
NextAction("starfall", ACTION_HIGH + 1.0f),
|
|
||||||
NextAction("force of nature", ACTION_DEFAULT + 1.0f),
|
|
||||||
NextAction("wrath", ACTION_DEFAULT + 0.1f),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
void CasterDruidStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|
||||||
{
|
|
||||||
GenericDruidStrategy::InitTriggers(triggers);
|
|
||||||
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"eclipse (lunar) cooldown",
|
|
||||||
{
|
|
||||||
NextAction("starfire", ACTION_DEFAULT + 0.2f)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"eclipse (solar) cooldown",
|
|
||||||
{
|
|
||||||
NextAction("wrath", ACTION_DEFAULT + 0.2f)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"insect swarm",
|
|
||||||
{
|
|
||||||
NextAction("insect swarm", ACTION_NORMAL + 5)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"moonfire",
|
|
||||||
{
|
|
||||||
NextAction("moonfire", ACTION_NORMAL + 4)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"eclipse (solar)",
|
|
||||||
{
|
|
||||||
NextAction("wrath", ACTION_NORMAL + 6)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"eclipse (lunar)",
|
|
||||||
{
|
|
||||||
NextAction("starfire", ACTION_NORMAL + 6)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"medium mana",
|
|
||||||
{
|
|
||||||
NextAction("innervate", ACTION_HIGH + 9)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"enemy too close for spell",
|
|
||||||
{
|
|
||||||
NextAction("flee", ACTION_MOVE + 9)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CasterDruidAoeStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|
||||||
{
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"hurricane channel check",
|
|
||||||
{
|
|
||||||
NextAction("cancel channel", ACTION_HIGH + 2)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"medium aoe",
|
|
||||||
{
|
|
||||||
NextAction("hurricane", ACTION_HIGH + 1)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"light aoe",
|
|
||||||
{
|
|
||||||
NextAction("insect swarm on attacker", ACTION_NORMAL + 3),
|
|
||||||
NextAction("moonfire on attacker", ACTION_NORMAL + 3)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CasterDruidDebuffStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|
||||||
{
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"faerie fire",
|
|
||||||
{
|
|
||||||
NextAction("faerie fire", ACTION_HIGH)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,314 +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 "CatDpsDruidStrategy.h"
|
|
||||||
|
|
||||||
#include "AiObjectContext.h"
|
|
||||||
|
|
||||||
class CatDpsDruidStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
CatDpsDruidStrategyActionNodeFactory()
|
|
||||||
{
|
|
||||||
creators["faerie fire (feral)"] = &faerie_fire_feral;
|
|
||||||
creators["melee"] = &melee;
|
|
||||||
creators["feral charge - cat"] = &feral_charge_cat;
|
|
||||||
creators["cat form"] = &cat_form;
|
|
||||||
creators["claw"] = &claw;
|
|
||||||
creators["mangle (cat)"] = &mangle_cat;
|
|
||||||
creators["rake"] = &rake;
|
|
||||||
creators["ferocious bite"] = &ferocious_bite;
|
|
||||||
creators["rip"] = &rip;
|
|
||||||
creators["pounce"] = &pounce;
|
|
||||||
creators["ravage"] = &ravage;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
static ActionNode* faerie_fire_feral([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode(
|
|
||||||
"faerie fire (feral)",
|
|
||||||
/*P*/ {},
|
|
||||||
/*A*/ {},
|
|
||||||
/*C*/ {}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ActionNode* melee([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode(
|
|
||||||
"melee",
|
|
||||||
/*P*/ { NextAction("feral charge - cat") },
|
|
||||||
/*A*/ {},
|
|
||||||
/*C*/ {}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ActionNode* feral_charge_cat([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode(
|
|
||||||
"feral charge - cat",
|
|
||||||
/*P*/ {},
|
|
||||||
/*A*/ { NextAction("reach melee") },
|
|
||||||
/*C*/ {}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ActionNode* cat_form([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode(
|
|
||||||
"cat form",
|
|
||||||
/*P*/ { NextAction("caster form") },
|
|
||||||
/*A*/ {},
|
|
||||||
/*C*/ {}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ActionNode* claw([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode(
|
|
||||||
"claw",
|
|
||||||
/*P*/ {},
|
|
||||||
/*A*/ { NextAction("melee") },
|
|
||||||
/*C*/ {}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ActionNode* mangle_cat([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode(
|
|
||||||
"mangle (cat)",
|
|
||||||
/*P*/ {},
|
|
||||||
/*A*/ {},
|
|
||||||
/*C*/ {}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ActionNode* rake([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode(
|
|
||||||
"rake",
|
|
||||||
/*P*/ {},
|
|
||||||
/*A*/ {},
|
|
||||||
/*C*/ {}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ActionNode* ferocious_bite([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode(
|
|
||||||
"ferocious bite",
|
|
||||||
/*P*/ {},
|
|
||||||
/*A*/ { NextAction("rip") },
|
|
||||||
/*C*/ {}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ActionNode* rip([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode(
|
|
||||||
"rip",
|
|
||||||
/*P*/ {},
|
|
||||||
/*A*/ {},
|
|
||||||
/*C*/ {}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ActionNode* pounce([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode(
|
|
||||||
"pounce",
|
|
||||||
/*P*/ {},
|
|
||||||
/*A*/ { NextAction("ravage") },
|
|
||||||
/*C*/ {}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ActionNode* ravage([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode(
|
|
||||||
"ravage",
|
|
||||||
/*P*/ {},
|
|
||||||
/*A*/ { NextAction("shred") },
|
|
||||||
/*C*/ {}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
CatDpsDruidStrategy::CatDpsDruidStrategy(PlayerbotAI* botAI) : FeralDruidStrategy(botAI)
|
|
||||||
{
|
|
||||||
actionNodeFactories.Add(new CatDpsDruidStrategyActionNodeFactory());
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<NextAction> CatDpsDruidStrategy::getDefaultActions()
|
|
||||||
{
|
|
||||||
return {
|
|
||||||
NextAction("tiger's fury", ACTION_DEFAULT + 0.1f)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
void CatDpsDruidStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|
||||||
{
|
|
||||||
FeralDruidStrategy::InitTriggers(triggers);
|
|
||||||
|
|
||||||
// Default priority
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"almost full energy available",
|
|
||||||
{
|
|
||||||
NextAction("shred", ACTION_DEFAULT + 0.4f)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"combo points not full",
|
|
||||||
{
|
|
||||||
NextAction("shred", ACTION_DEFAULT + 0.4f)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"almost full energy available",
|
|
||||||
{
|
|
||||||
NextAction("mangle (cat)", ACTION_DEFAULT + 0.3f)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"combo points not full and high energy",
|
|
||||||
{
|
|
||||||
NextAction("mangle (cat)", ACTION_DEFAULT + 0.3f)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"almost full energy available",
|
|
||||||
{
|
|
||||||
NextAction("claw", ACTION_DEFAULT + 0.2f)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"combo points not full and high energy",
|
|
||||||
{
|
|
||||||
NextAction("claw", ACTION_DEFAULT + 0.2f)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"faerie fire (feral)",
|
|
||||||
{
|
|
||||||
NextAction("faerie fire (feral)", ACTION_DEFAULT + 0.0f)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Main spell
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"cat form", {
|
|
||||||
NextAction("cat form", ACTION_HIGH + 8)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"savage roar", {
|
|
||||||
NextAction("savage roar", ACTION_HIGH + 7)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"combo points available",
|
|
||||||
{
|
|
||||||
NextAction("rip", ACTION_HIGH + 6)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"ferocious bite time",
|
|
||||||
{
|
|
||||||
NextAction("ferocious bite", ACTION_HIGH + 5)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"target with combo points almost dead",
|
|
||||||
{
|
|
||||||
NextAction("ferocious bite", ACTION_HIGH + 4)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"mangle (cat)",
|
|
||||||
{
|
|
||||||
NextAction("mangle (cat)", ACTION_HIGH + 3)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"rake",
|
|
||||||
{
|
|
||||||
NextAction("rake", ACTION_HIGH + 2)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"medium threat",
|
|
||||||
{
|
|
||||||
NextAction("cower", ACTION_HIGH + 1)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
// AOE
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"medium aoe",
|
|
||||||
{
|
|
||||||
NextAction("swipe (cat)", ACTION_HIGH + 3)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"light aoe",
|
|
||||||
{
|
|
||||||
NextAction("rake on attacker", ACTION_HIGH + 2)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
// Reach target
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"enemy out of melee",
|
|
||||||
{
|
|
||||||
NextAction("feral charge - cat", ACTION_HIGH + 9)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"enemy out of melee",
|
|
||||||
{
|
|
||||||
NextAction("dash", ACTION_HIGH + 8)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CatAoeDruidStrategy::InitTriggers(std::vector<TriggerNode*>& triggers) {}
|
|
||||||
@@ -1,194 +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 "GenericDruidNonCombatStrategy.h"
|
|
||||||
|
|
||||||
#include "Playerbots.h"
|
|
||||||
#include "AiFactory.h"
|
|
||||||
|
|
||||||
class GenericDruidNonCombatStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
GenericDruidNonCombatStrategyActionNodeFactory()
|
|
||||||
{
|
|
||||||
creators["thorns"] = þs;
|
|
||||||
creators["thorns on party"] = þs_on_party;
|
|
||||||
creators["mark of the wild"] = &mark_of_the_wild;
|
|
||||||
creators["mark of the wild on party"] = &mark_of_the_wild_on_party;
|
|
||||||
// creators["innervate"] = &innervate;
|
|
||||||
creators["regrowth_on_party"] = ®rowth_on_party;
|
|
||||||
creators["rejuvenation on party"] = &rejuvenation_on_party;
|
|
||||||
creators["remove curse on party"] = &remove_curse_on_party;
|
|
||||||
creators["abolish poison on party"] = &abolish_poison_on_party;
|
|
||||||
creators["revive"] = &revive;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
static ActionNode* thorns([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode("thorns",
|
|
||||||
/*P*/ { NextAction("caster form") },
|
|
||||||
/*A*/ {},
|
|
||||||
/*C*/ {});
|
|
||||||
}
|
|
||||||
|
|
||||||
static ActionNode* thorns_on_party([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode("thorns on party",
|
|
||||||
/*P*/ { NextAction("caster form") },
|
|
||||||
/*A*/ {},
|
|
||||||
/*C*/ {});
|
|
||||||
}
|
|
||||||
|
|
||||||
static ActionNode* mark_of_the_wild([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode("mark of the wild",
|
|
||||||
/*P*/ { NextAction("caster form") },
|
|
||||||
/*A*/ {},
|
|
||||||
/*C*/ {});
|
|
||||||
}
|
|
||||||
|
|
||||||
static ActionNode* mark_of_the_wild_on_party([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode("mark of the wild on party",
|
|
||||||
/*P*/ { NextAction("caster form") },
|
|
||||||
/*A*/ {},
|
|
||||||
/*C*/ {});
|
|
||||||
}
|
|
||||||
static ActionNode* regrowth_on_party([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode("regrowth on party",
|
|
||||||
/*P*/ { NextAction("caster form") },
|
|
||||||
/*A*/ {},
|
|
||||||
/*C*/ {});
|
|
||||||
}
|
|
||||||
static ActionNode* rejuvenation_on_party([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode("rejuvenation on party",
|
|
||||||
/*P*/ { NextAction("caster form") },
|
|
||||||
/*A*/ {},
|
|
||||||
/*C*/ {});
|
|
||||||
}
|
|
||||||
static ActionNode* remove_curse_on_party([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode("remove curse on party",
|
|
||||||
/*P*/ { NextAction("caster form") },
|
|
||||||
/*A*/ {},
|
|
||||||
/*C*/ {});
|
|
||||||
}
|
|
||||||
static ActionNode* abolish_poison_on_party([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode("abolish poison on party",
|
|
||||||
/*P*/ { NextAction("caster form") },
|
|
||||||
/*A*/ {},
|
|
||||||
/*C*/ {});
|
|
||||||
}
|
|
||||||
static ActionNode* revive([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode("revive",
|
|
||||||
/*P*/ { NextAction("caster form") },
|
|
||||||
/*A*/ {},
|
|
||||||
/*C*/ {});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
GenericDruidNonCombatStrategy::GenericDruidNonCombatStrategy(PlayerbotAI* botAI) : NonCombatStrategy(botAI)
|
|
||||||
{
|
|
||||||
actionNodeFactories.Add(new GenericDruidNonCombatStrategyActionNodeFactory());
|
|
||||||
}
|
|
||||||
|
|
||||||
void GenericDruidNonCombatStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|
||||||
{
|
|
||||||
NonCombatStrategy::InitTriggers(triggers);
|
|
||||||
|
|
||||||
triggers.push_back(new TriggerNode("mark of the wild", { NextAction("mark of the wild", 14.0f) }));
|
|
||||||
triggers.push_back(new TriggerNode("party member cure poison", { NextAction("abolish poison on party", 20.0f) }));
|
|
||||||
triggers.push_back(new TriggerNode("party member dead", { NextAction("revive", ACTION_CRITICAL_HEAL + 10) }));
|
|
||||||
|
|
||||||
triggers.push_back(new TriggerNode("often", { NextAction("apply oil", 1.0f) }));
|
|
||||||
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("party member critical health",
|
|
||||||
{
|
|
||||||
NextAction("wild growth on party", ACTION_MEDIUM_HEAL + 7),
|
|
||||||
NextAction("regrowth on party", ACTION_MEDIUM_HEAL + 6),
|
|
||||||
NextAction("rejuvenation on party", ACTION_MEDIUM_HEAL + 5),
|
|
||||||
}));
|
|
||||||
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("party member low health",
|
|
||||||
{
|
|
||||||
NextAction("wild growth on party", ACTION_MEDIUM_HEAL + 5),
|
|
||||||
NextAction("regrowth on party", ACTION_MEDIUM_HEAL + 4),
|
|
||||||
NextAction("rejuvenation on party", ACTION_MEDIUM_HEAL + 3),
|
|
||||||
}));
|
|
||||||
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("party member medium health",
|
|
||||||
{ NextAction("wild growth on party", ACTION_MEDIUM_HEAL + 3),
|
|
||||||
NextAction("regrowth on party", ACTION_MEDIUM_HEAL + 2),
|
|
||||||
NextAction("rejuvenation on party", ACTION_MEDIUM_HEAL + 1),
|
|
||||||
}));
|
|
||||||
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("party member almost full health",
|
|
||||||
{ NextAction("wild growth on party", ACTION_LIGHT_HEAL + 3), NextAction("rejuvenation on party", ACTION_LIGHT_HEAL + 2) }));
|
|
||||||
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("party member remove curse",
|
|
||||||
{ NextAction("remove curse on party", ACTION_DISPEL + 7) }));
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("new pet", { NextAction("set pet stance", 60.0f) }));
|
|
||||||
|
|
||||||
triggers.push_back(new TriggerNode("party member critical health", {
|
|
||||||
NextAction("wild growth on party", ACTION_MEDIUM_HEAL + 7),
|
|
||||||
NextAction("regrowth on party", ACTION_MEDIUM_HEAL + 6),
|
|
||||||
NextAction("rejuvenation on party", ACTION_MEDIUM_HEAL + 5),
|
|
||||||
}));
|
|
||||||
triggers.push_back(new TriggerNode("party member low health", {
|
|
||||||
NextAction("wild growth on party", ACTION_MEDIUM_HEAL + 5),
|
|
||||||
NextAction("regrowth on party", ACTION_MEDIUM_HEAL + 4),
|
|
||||||
NextAction("rejuvenation on party", ACTION_MEDIUM_HEAL + 3),
|
|
||||||
}));
|
|
||||||
triggers.push_back(new TriggerNode("party member medium health", {
|
|
||||||
NextAction("wild growth on party", ACTION_MEDIUM_HEAL + 3),
|
|
||||||
NextAction("regrowth on party", ACTION_MEDIUM_HEAL + 2),
|
|
||||||
NextAction("rejuvenation on party", ACTION_MEDIUM_HEAL + 1),
|
|
||||||
}));
|
|
||||||
triggers.push_back(new TriggerNode("party member almost full health", {
|
|
||||||
NextAction("wild growth on party", ACTION_LIGHT_HEAL + 3),
|
|
||||||
NextAction("rejuvenation on party", ACTION_LIGHT_HEAL + 2),
|
|
||||||
}));
|
|
||||||
triggers.push_back(new TriggerNode("party member remove curse", {
|
|
||||||
NextAction("remove curse on party", ACTION_DISPEL + 7),
|
|
||||||
}));
|
|
||||||
|
|
||||||
int specTab = AiFactory::GetPlayerSpecTab(botAI->GetBot());
|
|
||||||
if (specTab == 0 || specTab == 2) // Balance or Restoration
|
|
||||||
triggers.push_back(new TriggerNode("often", { NextAction("apply oil", 1.0f) }));
|
|
||||||
if (specTab == 1) // Feral
|
|
||||||
triggers.push_back(new TriggerNode("often", { NextAction("apply stone", 1.0f) }));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
GenericDruidBuffStrategy::GenericDruidBuffStrategy(PlayerbotAI* botAI) : NonCombatStrategy(botAI)
|
|
||||||
{
|
|
||||||
actionNodeFactories.Add(new GenericDruidNonCombatStrategyActionNodeFactory());
|
|
||||||
}
|
|
||||||
|
|
||||||
void GenericDruidBuffStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|
||||||
{
|
|
||||||
NonCombatStrategy::InitTriggers(triggers);
|
|
||||||
|
|
||||||
triggers.push_back(new TriggerNode("mark of the wild on party", {
|
|
||||||
NextAction("mark of the wild on party", 13.0f),
|
|
||||||
}));
|
|
||||||
triggers.push_back(new TriggerNode("thorns on main tank", {
|
|
||||||
NextAction("thorns on main tank", 11.0f),
|
|
||||||
}));
|
|
||||||
triggers.push_back(new TriggerNode("thorns", {
|
|
||||||
NextAction("thorns", 10.0f),
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
@@ -1,158 +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 "GenericDruidStrategy.h"
|
|
||||||
|
|
||||||
#include "Playerbots.h"
|
|
||||||
|
|
||||||
class GenericDruidStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
GenericDruidStrategyActionNodeFactory()
|
|
||||||
{
|
|
||||||
creators["melee"] = &melee;
|
|
||||||
creators["caster form"] = &caster_form;
|
|
||||||
creators["cure poison"] = &cure_poison;
|
|
||||||
creators["cure poison on party"] = &cure_poison_on_party;
|
|
||||||
creators["abolish poison"] = &abolish_poison;
|
|
||||||
creators["abolish poison on party"] = &abolish_poison_on_party;
|
|
||||||
creators["rebirth"] = &rebirth;
|
|
||||||
creators["entangling roots on cc"] = &entangling_roots_on_cc;
|
|
||||||
creators["innervate"] = &innervate;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
static ActionNode* melee([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode("melee",
|
|
||||||
/*P*/ {},
|
|
||||||
/*A*/ {},
|
|
||||||
/*C*/ {});
|
|
||||||
}
|
|
||||||
|
|
||||||
static ActionNode* caster_form([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode("caster form",
|
|
||||||
/*P*/ {},
|
|
||||||
/*A*/ {},
|
|
||||||
/*C*/ {});
|
|
||||||
}
|
|
||||||
|
|
||||||
static ActionNode* cure_poison([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode("cure poison",
|
|
||||||
/*P*/ {},
|
|
||||||
/*A*/ {},
|
|
||||||
/*C*/ {});
|
|
||||||
}
|
|
||||||
|
|
||||||
static ActionNode* cure_poison_on_party([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode("cure poison on party",
|
|
||||||
/*P*/ {},
|
|
||||||
/*A*/ {},
|
|
||||||
/*C*/ {});
|
|
||||||
}
|
|
||||||
|
|
||||||
static ActionNode* abolish_poison([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode("abolish poison",
|
|
||||||
/*P*/ {},
|
|
||||||
/*A*/ {},
|
|
||||||
/*C*/ {});
|
|
||||||
}
|
|
||||||
|
|
||||||
static ActionNode* abolish_poison_on_party([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode("abolish poison on party",
|
|
||||||
/*P*/ {},
|
|
||||||
/*A*/ {},
|
|
||||||
/*C*/ {});
|
|
||||||
}
|
|
||||||
|
|
||||||
static ActionNode* rebirth([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode("rebirth",
|
|
||||||
/*P*/ {},
|
|
||||||
/*A*/ {},
|
|
||||||
/*C*/ {});
|
|
||||||
}
|
|
||||||
|
|
||||||
static ActionNode* entangling_roots_on_cc([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode("entangling roots on cc",
|
|
||||||
/*P*/ { NextAction("caster form") },
|
|
||||||
/*A*/ {},
|
|
||||||
/*C*/ {});
|
|
||||||
}
|
|
||||||
|
|
||||||
static ActionNode* innervate([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode("innervate",
|
|
||||||
/*P*/ {},
|
|
||||||
/*A*/ { NextAction("mana potion") },
|
|
||||||
/*C*/ {});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
GenericDruidStrategy::GenericDruidStrategy(PlayerbotAI* botAI) : CombatStrategy(botAI)
|
|
||||||
{
|
|
||||||
actionNodeFactories.Add(new GenericDruidStrategyActionNodeFactory());
|
|
||||||
}
|
|
||||||
|
|
||||||
void GenericDruidStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|
||||||
{
|
|
||||||
CombatStrategy::InitTriggers(triggers);
|
|
||||||
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("low health", { NextAction("barkskin", ACTION_HIGH + 7) }));
|
|
||||||
|
|
||||||
triggers.push_back(new TriggerNode("combat party member dead",
|
|
||||||
{ NextAction("rebirth", ACTION_HIGH + 9) }));
|
|
||||||
triggers.push_back(new TriggerNode("being attacked",
|
|
||||||
{ NextAction("nature's grasp", ACTION_HIGH + 1) }));
|
|
||||||
triggers.push_back(new TriggerNode("new pet", { NextAction("set pet stance", 60.0f) }));
|
|
||||||
}
|
|
||||||
|
|
||||||
void DruidCureStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|
||||||
{
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("party member cure poison",
|
|
||||||
{ NextAction("abolish poison on party", ACTION_DISPEL + 1) }));
|
|
||||||
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("party member remove curse",
|
|
||||||
{ NextAction("remove curse on party", ACTION_DISPEL + 7) }));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void DruidBoostStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|
||||||
{
|
|
||||||
triggers.push_back(new TriggerNode(
|
|
||||||
"nature's swiftness", { NextAction("nature's swiftness", ACTION_HIGH + 9) }));
|
|
||||||
}
|
|
||||||
|
|
||||||
void DruidCcStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|
||||||
{
|
|
||||||
triggers.push_back(new TriggerNode(
|
|
||||||
"entangling roots", { NextAction("entangling roots on cc", ACTION_HIGH + 2) }));
|
|
||||||
triggers.push_back(new TriggerNode(
|
|
||||||
"entangling roots kite", { NextAction("entangling roots", ACTION_HIGH + 2) }));
|
|
||||||
triggers.push_back(new TriggerNode(
|
|
||||||
"hibernate", { NextAction("hibernate on cc", ACTION_HIGH + 3) }));
|
|
||||||
}
|
|
||||||
|
|
||||||
void DruidHealerDpsStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|
||||||
{
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("healer should attack",
|
|
||||||
{
|
|
||||||
NextAction("cancel tree form", ACTION_DEFAULT + 0.3f),
|
|
||||||
NextAction("moonfire", ACTION_DEFAULT + 0.2f),
|
|
||||||
NextAction("wrath", ACTION_DEFAULT + 0.1f),
|
|
||||||
NextAction("starfire", ACTION_DEFAULT),
|
|
||||||
}));
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,101 +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 "HealDruidStrategy.h"
|
|
||||||
|
|
||||||
#include "Playerbots.h"
|
|
||||||
|
|
||||||
class HealDruidStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
HealDruidStrategyActionNodeFactory() {
|
|
||||||
creators["nourish on party"] = &nourtish_on_party;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
static ActionNode* nourtish_on_party([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode("nourish on party",
|
|
||||||
/*P*/ {},
|
|
||||||
/*A*/ { NextAction("healing touch on party") },
|
|
||||||
/*C*/ {});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
HealDruidStrategy::HealDruidStrategy(PlayerbotAI* botAI) : GenericDruidStrategy(botAI)
|
|
||||||
{
|
|
||||||
actionNodeFactories.Add(new HealDruidStrategyActionNodeFactory());
|
|
||||||
}
|
|
||||||
|
|
||||||
void HealDruidStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|
||||||
{
|
|
||||||
GenericDruidStrategy::InitTriggers(triggers);
|
|
||||||
|
|
||||||
triggers.push_back(new TriggerNode(
|
|
||||||
"party member to heal out of spell range",
|
|
||||||
{ NextAction("reach party member to heal", ACTION_CRITICAL_HEAL + 9) }));
|
|
||||||
|
|
||||||
// CRITICAL
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("party member critical health",
|
|
||||||
{
|
|
||||||
NextAction("tree form", ACTION_CRITICAL_HEAL + 4.1f),
|
|
||||||
NextAction("swiftmend on party", ACTION_CRITICAL_HEAL + 4),
|
|
||||||
NextAction("regrowth on party", ACTION_CRITICAL_HEAL + 3),
|
|
||||||
NextAction("wild growth on party", ACTION_CRITICAL_HEAL + 2),
|
|
||||||
NextAction("nourish on party", ACTION_CRITICAL_HEAL + 1),
|
|
||||||
}));
|
|
||||||
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("party member critical health",
|
|
||||||
{ NextAction("nature's swiftness", ACTION_CRITICAL_HEAL + 4) }));
|
|
||||||
|
|
||||||
triggers.push_back(new TriggerNode(
|
|
||||||
"group heal setting",
|
|
||||||
{
|
|
||||||
NextAction("tree form", ACTION_MEDIUM_HEAL + 2.3f),
|
|
||||||
NextAction("wild growth on party", ACTION_MEDIUM_HEAL + 2.2f),
|
|
||||||
NextAction("rejuvenation on not full", ACTION_MEDIUM_HEAL + 2.1f),
|
|
||||||
}));
|
|
||||||
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("medium group heal setting",
|
|
||||||
{
|
|
||||||
NextAction("tree form", ACTION_CRITICAL_HEAL + 0.6f),
|
|
||||||
NextAction("tranquility", ACTION_CRITICAL_HEAL + 0.5f) }));
|
|
||||||
|
|
||||||
// LOW
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("party member low health",
|
|
||||||
{ NextAction("tree form", ACTION_MEDIUM_HEAL + 1.5f),
|
|
||||||
NextAction("wild growth on party", ACTION_MEDIUM_HEAL + 1.4f),
|
|
||||||
NextAction("regrowth on party", ACTION_MEDIUM_HEAL + 1.3f),
|
|
||||||
NextAction("swiftmend on party", ACTION_MEDIUM_HEAL + 1.2),
|
|
||||||
NextAction("nourish on party", ACTION_MEDIUM_HEAL + 1.1f),
|
|
||||||
}));
|
|
||||||
|
|
||||||
// MEDIUM
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("party member medium health",
|
|
||||||
{
|
|
||||||
NextAction("tree form", ACTION_MEDIUM_HEAL + 0.5f),
|
|
||||||
NextAction("wild growth on party", ACTION_MEDIUM_HEAL + 0.4f),
|
|
||||||
NextAction("rejuvenation on party", ACTION_MEDIUM_HEAL + 0.3f),
|
|
||||||
NextAction("regrowth on party", ACTION_MEDIUM_HEAL + 0.2f),
|
|
||||||
NextAction("nourish on party", ACTION_MEDIUM_HEAL + 0.1f) }));
|
|
||||||
|
|
||||||
// almost full
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("party member almost full health",
|
|
||||||
{ NextAction("wild growth on party", ACTION_LIGHT_HEAL + 0.3f),
|
|
||||||
NextAction("rejuvenation on party", ACTION_LIGHT_HEAL + 0.2f),
|
|
||||||
NextAction("regrowth on party", ACTION_LIGHT_HEAL + 0.1f) }));
|
|
||||||
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("medium mana", { NextAction("innervate", ACTION_HIGH + 5) }));
|
|
||||||
|
|
||||||
triggers.push_back(new TriggerNode("enemy too close for spell",
|
|
||||||
{ NextAction("flee", ACTION_MOVE + 9) }));
|
|
||||||
}
|
|
||||||
@@ -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 "OffhealDruidCatStrategy.h"
|
|
||||||
|
|
||||||
#include "Playerbots.h"
|
|
||||||
#include "Strategy.h"
|
|
||||||
|
|
||||||
class OffhealDruidCatStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
OffhealDruidCatStrategyActionNodeFactory()
|
|
||||||
{
|
|
||||||
creators["cat form"] = &cat_form;
|
|
||||||
creators["mangle (cat)"] = &mangle_cat;
|
|
||||||
creators["shred"] = &shred;
|
|
||||||
creators["rake"] = &rake;
|
|
||||||
creators["rip"] = &rip;
|
|
||||||
creators["ferocious bite"] = &ferocious_bite;
|
|
||||||
creators["savage roar"] = &savage_roar;
|
|
||||||
creators["faerie fire (feral)"] = &faerie_fire_feral;
|
|
||||||
creators["healing touch on party"] = &healing_touch_on_party;
|
|
||||||
creators["regrowth on party"] = ®rowth_on_party;
|
|
||||||
creators["rejuvenation on party"] = &rejuvenation_on_party;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
static ActionNode* cat_form([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode(
|
|
||||||
"cat form",
|
|
||||||
/*P*/ {},
|
|
||||||
/*A*/ {},
|
|
||||||
/*C*/ {}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ActionNode* mangle_cat([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode(
|
|
||||||
"mangle (cat)",
|
|
||||||
/*P*/ {},
|
|
||||||
/*A*/ {},
|
|
||||||
/*C*/ {}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ActionNode* shred([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode(
|
|
||||||
"shred",
|
|
||||||
/*P*/ {},
|
|
||||||
/*A*/ { NextAction("claw") },
|
|
||||||
/*C*/ {}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ActionNode* rake([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode(
|
|
||||||
"rake",
|
|
||||||
/*P*/ {},
|
|
||||||
/*A*/ {},
|
|
||||||
/*C*/ {}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ActionNode* rip([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode(
|
|
||||||
"rip",
|
|
||||||
/*P*/ {},
|
|
||||||
/*A*/ {},
|
|
||||||
/*C*/ {}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ActionNode* ferocious_bite([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode(
|
|
||||||
"ferocious bite",
|
|
||||||
/*P*/ {},
|
|
||||||
/*A*/ { NextAction("rip") },
|
|
||||||
/*C*/ {}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ActionNode* savage_roar([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode(
|
|
||||||
"savage roar",
|
|
||||||
/*P*/ {},
|
|
||||||
/*A*/ {},
|
|
||||||
/*C*/ {}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ActionNode* faerie_fire_feral([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode(
|
|
||||||
"faerie fire (feral)",
|
|
||||||
/*P*/ {},
|
|
||||||
/*A*/ {},
|
|
||||||
/*C*/ {}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ActionNode* healing_touch_on_party([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode(
|
|
||||||
"healing touch on party",
|
|
||||||
/*P*/ { NextAction("caster form") },
|
|
||||||
/*A*/ {},
|
|
||||||
/*C*/ { NextAction("cat form") }
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ActionNode* regrowth_on_party([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode(
|
|
||||||
"regrowth on party",
|
|
||||||
/*P*/ { NextAction("caster form") },
|
|
||||||
/*A*/ {},
|
|
||||||
/*C*/ { NextAction("cat form") }
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ActionNode* rejuvenation_on_party([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode(
|
|
||||||
"rejuvenation on party",
|
|
||||||
/*P*/ { NextAction("caster form") },
|
|
||||||
/*A*/ {},
|
|
||||||
/*C*/ { NextAction("cat form") }
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
OffhealDruidCatStrategy::OffhealDruidCatStrategy(PlayerbotAI* botAI) : FeralDruidStrategy(botAI)
|
|
||||||
{
|
|
||||||
actionNodeFactories.Add(new OffhealDruidCatStrategyActionNodeFactory());
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<NextAction> OffhealDruidCatStrategy::getDefaultActions()
|
|
||||||
{
|
|
||||||
return {
|
|
||||||
NextAction("mangle (cat)", ACTION_DEFAULT + 0.5f),
|
|
||||||
NextAction("shred", ACTION_DEFAULT + 0.4f),
|
|
||||||
NextAction("rake", ACTION_DEFAULT + 0.3f),
|
|
||||||
NextAction("melee", ACTION_DEFAULT),
|
|
||||||
NextAction("cat form", ACTION_DEFAULT - 0.1f)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
void OffhealDruidCatStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|
||||||
{
|
|
||||||
FeralDruidStrategy::InitTriggers(triggers);
|
|
||||||
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"cat form",
|
|
||||||
{
|
|
||||||
NextAction("cat form", ACTION_HIGH + 8)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"savage roar",
|
|
||||||
{
|
|
||||||
NextAction("savage roar", ACTION_HIGH + 7)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"combo points available",
|
|
||||||
{
|
|
||||||
NextAction("rip", ACTION_HIGH + 6)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"ferocious bite time",
|
|
||||||
{
|
|
||||||
NextAction("ferocious bite", ACTION_HIGH + 5)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"target with combo points almost dead",
|
|
||||||
{
|
|
||||||
NextAction("ferocious bite", ACTION_HIGH + 4)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"mangle (cat)",
|
|
||||||
{
|
|
||||||
NextAction("mangle (cat)", ACTION_HIGH + 3)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"rake",
|
|
||||||
{
|
|
||||||
NextAction("rake", ACTION_HIGH + 2)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"almost full energy available",
|
|
||||||
{
|
|
||||||
NextAction("shred", ACTION_DEFAULT + 0.4f)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"combo points not full",
|
|
||||||
{
|
|
||||||
NextAction("shred", ACTION_DEFAULT + 0.4f)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"faerie fire (feral)",
|
|
||||||
{
|
|
||||||
NextAction("faerie fire (feral)", ACTION_NORMAL)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"enemy out of melee",
|
|
||||||
{
|
|
||||||
NextAction("feral charge - cat", ACTION_HIGH + 9),
|
|
||||||
NextAction("dash", ACTION_HIGH + 8)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"medium aoe",
|
|
||||||
{
|
|
||||||
NextAction("swipe (cat)", ACTION_HIGH + 3)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"low energy",
|
|
||||||
{
|
|
||||||
NextAction("tiger's fury", ACTION_NORMAL + 1)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"party member critical health",
|
|
||||||
{
|
|
||||||
NextAction("regrowth on party", ACTION_CRITICAL_HEAL + 6),
|
|
||||||
NextAction("healing touch on party", ACTION_CRITICAL_HEAL + 5)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"party member low health",
|
|
||||||
{
|
|
||||||
NextAction("healing touch on party", ACTION_MEDIUM_HEAL + 5)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"party member medium health",
|
|
||||||
{
|
|
||||||
NextAction("rejuvenation on party", ACTION_LIGHT_HEAL + 8)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"party member to heal out of spell range",
|
|
||||||
{
|
|
||||||
NextAction("reach party member to heal", ACTION_EMERGENCY + 3)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"low mana",
|
|
||||||
{
|
|
||||||
NextAction("innervate", ACTION_HIGH + 4)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,87 +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 "BattlegroundStrategy.h"
|
|
||||||
|
|
||||||
#include "Playerbots.h"
|
|
||||||
|
|
||||||
void BGStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|
||||||
{
|
|
||||||
triggers.push_back(new TriggerNode("often", { NextAction("bg join", relevance)}));
|
|
||||||
triggers.push_back(new TriggerNode("bg invite active", { NextAction("bg status check", relevance)}));
|
|
||||||
triggers.push_back(new TriggerNode("timer", { NextAction("bg strategy check", relevance)}));
|
|
||||||
}
|
|
||||||
|
|
||||||
BGStrategy::BGStrategy(PlayerbotAI* botAI) : PassTroughStrategy(botAI) {}
|
|
||||||
|
|
||||||
void BattlegroundStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|
||||||
{
|
|
||||||
triggers.push_back(new TriggerNode("bg waiting", { NextAction("bg move to start", ACTION_BG)}));
|
|
||||||
triggers.push_back(new TriggerNode("bg active", { NextAction("bg move to objective", ACTION_BG)}));
|
|
||||||
triggers.push_back(new TriggerNode("often", { NextAction("bg check objective", ACTION_BG + 1)}));
|
|
||||||
triggers.push_back(new TriggerNode("dead", { NextAction("bg reset objective force", ACTION_EMERGENCY)}));
|
|
||||||
}
|
|
||||||
|
|
||||||
void WarsongStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|
||||||
{
|
|
||||||
triggers.push_back(new TriggerNode("bg active", { NextAction("bg check flag", ACTION_EMERGENCY )}));
|
|
||||||
triggers.push_back(new TriggerNode("enemy flagcarrier near", { NextAction("attack enemy flag carrier", ACTION_RAID + 1.0f)}));
|
|
||||||
triggers.push_back(new TriggerNode("team flagcarrier near", { NextAction("bg protect fc", ACTION_RAID)}));
|
|
||||||
triggers.push_back(new TriggerNode("often", { NextAction("bg use buff", ACTION_BG)}));
|
|
||||||
triggers.push_back(new TriggerNode("low health", { NextAction("bg use buff", ACTION_MOVE)}));
|
|
||||||
triggers.push_back(new TriggerNode("low mana", { NextAction("bg use buff", ACTION_MOVE)}));
|
|
||||||
triggers.push_back(new TriggerNode("player has flag", { NextAction("bg move to objective", ACTION_EMERGENCY)}));
|
|
||||||
triggers.push_back(new TriggerNode("timer bg", { NextAction("bg reset objective force", ACTION_EMERGENCY)}));
|
|
||||||
}
|
|
||||||
|
|
||||||
void AlteracStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|
||||||
{
|
|
||||||
triggers.push_back(new TriggerNode("alliance no snowfall gy", { NextAction("bg move to objective", ACTION_EMERGENCY)}));
|
|
||||||
triggers.push_back(new TriggerNode("timer bg", { NextAction("bg reset objective force", ACTION_EMERGENCY)}));
|
|
||||||
}
|
|
||||||
|
|
||||||
void ArathiStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|
||||||
{
|
|
||||||
triggers.push_back(new TriggerNode("bg active", { NextAction("bg check flag", ACTION_EMERGENCY)}));
|
|
||||||
triggers.push_back(new TriggerNode("often", { NextAction("bg use buff", ACTION_BG)}));
|
|
||||||
triggers.push_back(new TriggerNode("low health", { NextAction("bg use buff", ACTION_MOVE)}));
|
|
||||||
triggers.push_back(new TriggerNode("low mana", { NextAction("bg use buff", ACTION_MOVE)}));
|
|
||||||
}
|
|
||||||
|
|
||||||
void EyeStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|
||||||
{
|
|
||||||
triggers.push_back(new TriggerNode("bg active", { NextAction("bg check flag", ACTION_EMERGENCY)}));
|
|
||||||
triggers.push_back(new TriggerNode("often", { NextAction("bg use buff", ACTION_BG)}));
|
|
||||||
triggers.push_back(new TriggerNode("low health", { NextAction("bg use buff", ACTION_MOVE)}));
|
|
||||||
triggers.push_back(new TriggerNode("low mana", { NextAction("bg use buff", ACTION_MOVE)}));
|
|
||||||
triggers.push_back(new TriggerNode("enemy flagcarrier near", { NextAction("attack enemy flag carrier", ACTION_RAID)}));
|
|
||||||
triggers.push_back(new TriggerNode("player has flag",{ NextAction("bg move to objective", ACTION_EMERGENCY)}));
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO: Do Priorities
|
|
||||||
void IsleStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|
||||||
{
|
|
||||||
triggers.push_back(new TriggerNode("bg active", { NextAction("bg check flag", ACTION_MOVE)}));
|
|
||||||
triggers.push_back(new TriggerNode("timer", { NextAction("enter vehicle", ACTION_MOVE + 8.0f)}));
|
|
||||||
triggers.push_back(new TriggerNode("random", { NextAction("leave vehicle", ACTION_MOVE + 7.0f)}));
|
|
||||||
triggers.push_back(new TriggerNode("in vehicle", { NextAction("hurl boulder", ACTION_MOVE + 9.0f)}));
|
|
||||||
triggers.push_back(new TriggerNode("in vehicle", { NextAction("fire cannon", ACTION_MOVE + 9.0f)}));
|
|
||||||
triggers.push_back(new TriggerNode("in vehicle", { NextAction("napalm", ACTION_MOVE + 9.0f)}));
|
|
||||||
triggers.push_back(new TriggerNode("enemy is close", { NextAction("steam blast", ACTION_MOVE + 9.0f)}));
|
|
||||||
triggers.push_back(new TriggerNode("in vehicle", { NextAction("ram", ACTION_MOVE + 9.0f)}));
|
|
||||||
triggers.push_back(new TriggerNode("enemy is close", { NextAction("ram", ACTION_MOVE + 9.1f)}));
|
|
||||||
triggers.push_back(new TriggerNode("enemy out of melee", { NextAction("steam rush", ACTION_MOVE + 9.2f)}));
|
|
||||||
triggers.push_back(new TriggerNode("in vehicle", { NextAction("incendiary rocket", ACTION_MOVE + 9.0f)}));
|
|
||||||
triggers.push_back(new TriggerNode("in vehicle", { NextAction("rocket blast", ACTION_MOVE + 9.0f)}));
|
|
||||||
// this is bugged: it doesn't work, and stops glaive throw working (which is needed to take down gate)
|
|
||||||
// triggers.push_back(new TriggerNode("in vehicle", { NextAction("blade salvo", ACTION_MOVE + 9.0f)}));
|
|
||||||
triggers.push_back(new TriggerNode("in vehicle", { NextAction("glaive throw", ACTION_MOVE + 9.0f)}));
|
|
||||||
}
|
|
||||||
|
|
||||||
void ArenaStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|
||||||
{
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("no possible targets", { NextAction("arena tactics", ACTION_BG)}));
|
|
||||||
}
|
|
||||||
@@ -1,193 +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 "ChatCommandHandlerStrategy.h"
|
|
||||||
|
|
||||||
#include "Playerbots.h"
|
|
||||||
|
|
||||||
class ChatCommandActionNodeFactoryInternal : public NamedObjectFactory<ActionNode>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ChatCommandActionNodeFactoryInternal() { creators["tank attack chat shortcut"] = &tank_attack_chat_shortcut; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
static ActionNode* tank_attack_chat_shortcut(PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode("tank attack chat shortcut",
|
|
||||||
/*P*/ {},
|
|
||||||
/*A*/ {},
|
|
||||||
/*C*/ { NextAction("attack my target", 100.0f) });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
void ChatCommandHandlerStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|
||||||
{
|
|
||||||
PassTroughStrategy::InitTriggers(triggers);
|
|
||||||
|
|
||||||
triggers.push_back(new TriggerNode("rep", { NextAction("reputation", relevance) }));
|
|
||||||
triggers.push_back(new TriggerNode("q", { NextAction("query quest", relevance),
|
|
||||||
NextAction("query item usage", relevance) }));
|
|
||||||
triggers.push_back(new TriggerNode("add all loot", { NextAction("add all loot", relevance),
|
|
||||||
NextAction("loot", relevance) }));
|
|
||||||
triggers.push_back(new TriggerNode("u", { NextAction("use", relevance) }));
|
|
||||||
triggers.push_back(new TriggerNode("c", { NextAction("item count", relevance) }));
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("items", { NextAction("item count", relevance) }));
|
|
||||||
triggers.push_back(new TriggerNode("inv", { NextAction("item count", relevance) }));
|
|
||||||
triggers.push_back(new TriggerNode("e", { NextAction("equip", relevance) }));
|
|
||||||
triggers.push_back(new TriggerNode("ue", { NextAction("unequip", relevance) }));
|
|
||||||
triggers.push_back(new TriggerNode("t", { NextAction("trade", relevance) }));
|
|
||||||
triggers.push_back(new TriggerNode("nt", { NextAction("trade", relevance) }));
|
|
||||||
triggers.push_back(new TriggerNode("s", { NextAction("sell", relevance) }));
|
|
||||||
triggers.push_back(new TriggerNode("b", { NextAction("buy", relevance) }));
|
|
||||||
triggers.push_back(new TriggerNode("r", { NextAction("reward", relevance) }));
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("attack", { NextAction("attack my target", relevance) }));
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("accept", { NextAction("accept quest", relevance) }));
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("follow", { NextAction("follow chat shortcut", relevance) }));
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("stay", { NextAction("stay chat shortcut", relevance) }));
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("move from group", { NextAction("move from group chat shortcut", relevance) }));
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("flee", { NextAction("flee chat shortcut", relevance) }));
|
|
||||||
triggers.push_back(new TriggerNode(
|
|
||||||
"tank attack", { NextAction("tank attack chat shortcut", relevance) }));
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("grind", { NextAction("grind chat shortcut", relevance) }));
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("talk", { NextAction("gossip hello", relevance),
|
|
||||||
NextAction("talk to quest giver", relevance) }));
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("enter vehicle", { NextAction("enter vehicle", relevance) }));
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("leave vehicle", { NextAction("leave vehicle", relevance) }));
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("cast", { NextAction("cast custom spell", relevance) }));
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("castnc", { NextAction("cast custom nc spell", relevance) }));
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("revive", { NextAction("spirit healer", relevance) }));
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("runaway", { NextAction("runaway chat shortcut", relevance) }));
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("warning", { NextAction("runaway chat shortcut", relevance) }));
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("max dps", { NextAction("max dps chat shortcut", relevance) }));
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("attackers", { NextAction("tell attackers", relevance) }));
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("target", { NextAction("tell target", relevance) }));
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("ready", { NextAction("ready check", relevance) }));
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("bwl", { NextAction("bwl chat shortcut", relevance) }));
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("dps", { NextAction("tell estimated dps", relevance) }));
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("disperse", { NextAction("disperse set", relevance) }));
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("open items", { NextAction("open items", relevance) }));
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("qi", { NextAction("query item usage", relevance) }));
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("unlock items", { NextAction("unlock items", relevance) }));
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("unlock traded item", { NextAction("unlock traded item", relevance) }));
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("wipe", { NextAction("wipe", relevance) }));
|
|
||||||
triggers.push_back(new TriggerNode("tame", { NextAction("tame", relevance) }));
|
|
||||||
triggers.push_back(new TriggerNode("glyphs", { NextAction("glyphs", relevance) })); // Added for custom Glyphs
|
|
||||||
triggers.push_back(new TriggerNode("glyph equip", { NextAction("glyph equip", relevance) })); // Added for custom Glyphs
|
|
||||||
triggers.push_back(new TriggerNode("pet", { NextAction("pet", relevance) }));
|
|
||||||
triggers.push_back(new TriggerNode("pet attack", { NextAction("pet attack", relevance) }));
|
|
||||||
triggers.push_back(new TriggerNode("roll", { NextAction("roll", relevance) }));
|
|
||||||
}
|
|
||||||
|
|
||||||
ChatCommandHandlerStrategy::ChatCommandHandlerStrategy(PlayerbotAI* botAI) : PassTroughStrategy(botAI)
|
|
||||||
{
|
|
||||||
actionNodeFactories.Add(new ChatCommandActionNodeFactoryInternal());
|
|
||||||
|
|
||||||
supported.push_back("quests");
|
|
||||||
supported.push_back("stats");
|
|
||||||
supported.push_back("leave");
|
|
||||||
supported.push_back("reputation");
|
|
||||||
supported.push_back("log");
|
|
||||||
supported.push_back("los");
|
|
||||||
supported.push_back("rpg status");
|
|
||||||
supported.push_back("rpg do quest");
|
|
||||||
supported.push_back("aura");
|
|
||||||
supported.push_back("drop");
|
|
||||||
supported.push_back("share");
|
|
||||||
supported.push_back("ll");
|
|
||||||
supported.push_back("ss");
|
|
||||||
supported.push_back("release");
|
|
||||||
supported.push_back("teleport");
|
|
||||||
supported.push_back("taxi");
|
|
||||||
supported.push_back("repair");
|
|
||||||
supported.push_back("talents");
|
|
||||||
supported.push_back("spells");
|
|
||||||
supported.push_back("co");
|
|
||||||
supported.push_back("nc");
|
|
||||||
supported.push_back("de");
|
|
||||||
supported.push_back("trainer");
|
|
||||||
supported.push_back("maintenance");
|
|
||||||
supported.push_back("remove glyph");
|
|
||||||
supported.push_back("autogear");
|
|
||||||
supported.push_back("equip upgrade");
|
|
||||||
supported.push_back("chat");
|
|
||||||
supported.push_back("home");
|
|
||||||
supported.push_back("destroy");
|
|
||||||
supported.push_back("reset botAI");
|
|
||||||
supported.push_back("emote");
|
|
||||||
supported.push_back("buff");
|
|
||||||
supported.push_back("help");
|
|
||||||
supported.push_back("gb");
|
|
||||||
supported.push_back("bank");
|
|
||||||
supported.push_back("invite");
|
|
||||||
supported.push_back("lfg");
|
|
||||||
supported.push_back("spell");
|
|
||||||
supported.push_back("rti");
|
|
||||||
supported.push_back("position");
|
|
||||||
supported.push_back("summon");
|
|
||||||
supported.push_back("who");
|
|
||||||
supported.push_back("save mana");
|
|
||||||
supported.push_back("formation");
|
|
||||||
supported.push_back("stance");
|
|
||||||
supported.push_back("sendmail");
|
|
||||||
supported.push_back("mail");
|
|
||||||
supported.push_back("outfit");
|
|
||||||
supported.push_back("go");
|
|
||||||
supported.push_back("debug");
|
|
||||||
supported.push_back("cdebug");
|
|
||||||
supported.push_back("cs");
|
|
||||||
supported.push_back("wts");
|
|
||||||
supported.push_back("hire");
|
|
||||||
supported.push_back("craft");
|
|
||||||
supported.push_back("flag");
|
|
||||||
supported.push_back("range");
|
|
||||||
supported.push_back("ra");
|
|
||||||
supported.push_back("give leader");
|
|
||||||
supported.push_back("cheat");
|
|
||||||
supported.push_back("ginvite");
|
|
||||||
supported.push_back("guild promote");
|
|
||||||
supported.push_back("guild demote");
|
|
||||||
supported.push_back("guild remove");
|
|
||||||
supported.push_back("guild leave");
|
|
||||||
supported.push_back("rtsc");
|
|
||||||
supported.push_back("drink");
|
|
||||||
supported.push_back("calc");
|
|
||||||
supported.push_back("open items");
|
|
||||||
supported.push_back("qi");
|
|
||||||
supported.push_back("unlock items");
|
|
||||||
supported.push_back("unlock traded item");
|
|
||||||
supported.push_back("tame");
|
|
||||||
supported.push_back("glyphs"); // Added for custom Glyphs
|
|
||||||
supported.push_back("glyph equip"); // Added for custom Glyphs
|
|
||||||
supported.push_back("pet");
|
|
||||||
supported.push_back("pet attack");
|
|
||||||
}
|
|
||||||
@@ -1,94 +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 "CombatStrategy.h"
|
|
||||||
|
|
||||||
#include "Playerbots.h"
|
|
||||||
#include "Strategy.h"
|
|
||||||
|
|
||||||
void CombatStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|
||||||
{
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"enemy out of spell",
|
|
||||||
{
|
|
||||||
NextAction("reach spell", ACTION_HIGH)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
// drop target relevance 99 (lower than Worldpacket triggers)
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"invalid target",
|
|
||||||
{
|
|
||||||
NextAction("drop target", 99)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"mounted",
|
|
||||||
{
|
|
||||||
NextAction("check mount state", 54)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"combat stuck",
|
|
||||||
{
|
|
||||||
NextAction("reset", 1.0f)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"not facing target",
|
|
||||||
{
|
|
||||||
NextAction("set facing", ACTION_MOVE + 7)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
// The pet-attack trigger is commented out because it was forcing the bot's pet to attack, overriding stay and follow commands.
|
|
||||||
// Pets will automatically attack the bot's enemy if they are in "defensive" or "aggressive"
|
|
||||||
// stance, or if the master issues an attack command.
|
|
||||||
}
|
|
||||||
|
|
||||||
AvoidAoeStrategy::AvoidAoeStrategy(PlayerbotAI* botAI) : Strategy(botAI) {}
|
|
||||||
|
|
||||||
std::vector<NextAction> AvoidAoeStrategy::getDefaultActions()
|
|
||||||
{
|
|
||||||
return {
|
|
||||||
NextAction("avoid aoe", ACTION_EMERGENCY)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
void AvoidAoeStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void AvoidAoeStrategy::InitMultipliers(std::vector<Multiplier*>& multipliers)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
TankFaceStrategy::TankFaceStrategy(PlayerbotAI* botAI) : Strategy(botAI) {}
|
|
||||||
|
|
||||||
std::vector<NextAction> TankFaceStrategy::getDefaultActions()
|
|
||||||
{
|
|
||||||
return {
|
|
||||||
NextAction("tank face", ACTION_MOVE)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
void TankFaceStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<NextAction> CombatFormationStrategy::getDefaultActions()
|
|
||||||
{
|
|
||||||
return {
|
|
||||||
NextAction("combat formation move", ACTION_NORMAL)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,32 +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 "DeadStrategy.h"
|
|
||||||
|
|
||||||
#include "Playerbots.h"
|
|
||||||
|
|
||||||
void DeadStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|
||||||
{
|
|
||||||
PassTroughStrategy::InitTriggers(triggers);
|
|
||||||
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("often", { NextAction("auto release", relevance) }));
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("bg active", { NextAction("auto release", relevance) }));
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("dead", { NextAction("find corpse", relevance) }));
|
|
||||||
triggers.push_back(new TriggerNode(
|
|
||||||
"corpse near", { NextAction("revive from corpse", relevance - 1.0f) }));
|
|
||||||
triggers.push_back(new TriggerNode("resurrect request",
|
|
||||||
{ NextAction("accept resurrect", relevance) }));
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("falling far", { NextAction("repop", relevance + 1.f) }));
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("location stuck", { NextAction("repop", relevance + 1) }));
|
|
||||||
triggers.push_back(new TriggerNode(
|
|
||||||
"can self resurrect", { NextAction("self resurrect", relevance + 2.0f) }));
|
|
||||||
}
|
|
||||||
|
|
||||||
DeadStrategy::DeadStrategy(PlayerbotAI* botAI) : PassTroughStrategy(botAI) {}
|
|
||||||
@@ -1,35 +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 "EmoteStrategy.h"
|
|
||||||
|
|
||||||
#include "Playerbots.h"
|
|
||||||
|
|
||||||
void EmoteStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|
||||||
{
|
|
||||||
if (sPlayerbotAIConfig->randomBotEmote)
|
|
||||||
{
|
|
||||||
triggers.push_back(new TriggerNode("often", { NextAction("talk", 1.0f) }));
|
|
||||||
triggers.push_back(new TriggerNode("seldom", { NextAction("emote", 1.0f) }));
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("receive text emote", { NextAction("emote", 10.0f) }));
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("receive emote", { NextAction("emote", 10.0f) }));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sPlayerbotAIConfig->randomBotTalk)
|
|
||||||
{
|
|
||||||
triggers.push_back(new TriggerNode(
|
|
||||||
"often",
|
|
||||||
{ NextAction("suggest what to do", 10.0f), NextAction("suggest dungeon", 3.0f),
|
|
||||||
NextAction("suggest trade", 3.0f) }));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sPlayerbotAIConfig->enableGreet)
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("new player nearby", { NextAction("greet", 1.0f) }));
|
|
||||||
|
|
||||||
triggers.push_back(new TriggerNode("often", { NextAction("rpg mount anim", 1.0f) }));
|
|
||||||
}
|
|
||||||
@@ -1,16 +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 "GroupStrategy.h"
|
|
||||||
|
|
||||||
#include "Playerbots.h"
|
|
||||||
|
|
||||||
void GroupStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|
||||||
{
|
|
||||||
triggers.push_back(new TriggerNode("often", { NextAction("invite nearby", 4.0f) }));
|
|
||||||
triggers.push_back(new TriggerNode("random", { NextAction("invite guild", 4.0f) }));
|
|
||||||
triggers.push_back(new TriggerNode("random", { NextAction("leave far away", 4.0f) }));
|
|
||||||
triggers.push_back(new TriggerNode("seldom", { NextAction("reset instances", 1.0f) }));
|
|
||||||
}
|
|
||||||
@@ -1,22 +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 "GuildStrategy.h"
|
|
||||||
|
|
||||||
#include "Playerbots.h"
|
|
||||||
|
|
||||||
void GuildStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|
||||||
{
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("often", { NextAction("offer petition nearby", 4.0f) }));
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("often", { NextAction("guild manage nearby", 4.0f) }));
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("petition signed", { NextAction("turn in petition", 10.0f) }));
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("buy tabard", { NextAction("buy tabard", 10.0f) }));
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("leave large guild", { NextAction("guild leave", 4.0f) }));
|
|
||||||
}
|
|
||||||
@@ -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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "LootNonCombatStrategy.h"
|
|
||||||
|
|
||||||
#include "Playerbots.h"
|
|
||||||
|
|
||||||
void LootNonCombatStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|
||||||
{
|
|
||||||
triggers.push_back(new TriggerNode("loot available", { NextAction("loot", 6.0f) }));
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("far from loot target", { NextAction("move to loot", 7.0f) }));
|
|
||||||
triggers.push_back(new TriggerNode("can loot", { NextAction("open loot", 8.0f) }));
|
|
||||||
triggers.push_back(new TriggerNode("often", { NextAction("add all loot", 5.0f) }));
|
|
||||||
}
|
|
||||||
|
|
||||||
void GatherStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|
||||||
{
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("timer", { NextAction("add gathering loot", 5.0f) }));
|
|
||||||
}
|
|
||||||
|
|
||||||
void RevealStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|
||||||
{
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("often", { NextAction("reveal gathering item", 50.0f) }));
|
|
||||||
}
|
|
||||||
|
|
||||||
void UseBobberStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|
||||||
{
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("can use fishing bobber", { NextAction("use fishing bobber", 20.0f) }));
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("random", { NextAction("remove bobber strategy", 20.0f) }));
|
|
||||||
}
|
|
||||||
@@ -1,78 +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 "MaintenanceStrategy.h"
|
|
||||||
|
|
||||||
#include "Playerbots.h"
|
|
||||||
|
|
||||||
std::vector<NextAction> MaintenanceStrategy::getDefaultActions() { return {}; }
|
|
||||||
|
|
||||||
void MaintenanceStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|
||||||
{
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"random",
|
|
||||||
{
|
|
||||||
NextAction("clean quest log", 6.0f)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"random",
|
|
||||||
{
|
|
||||||
NextAction("use random recipe", 1.0f)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"random",
|
|
||||||
{
|
|
||||||
NextAction("disenchant random item", 1.0f)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"random",
|
|
||||||
{
|
|
||||||
NextAction("enchant random item", 1.0f)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"random",
|
|
||||||
{
|
|
||||||
NextAction("smart destroy item", 1.0f)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"move stuck",
|
|
||||||
{
|
|
||||||
NextAction("reset", 1.0f)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"random",
|
|
||||||
{
|
|
||||||
NextAction("use random quest item", 0.9f)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"random",
|
|
||||||
{
|
|
||||||
NextAction("auto share quest", 0.9f)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,65 +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 "NonCombatStrategy.h"
|
|
||||||
|
|
||||||
#include "Playerbots.h"
|
|
||||||
|
|
||||||
void NonCombatStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|
||||||
{
|
|
||||||
triggers.push_back(new TriggerNode("random", { NextAction("clean quest log", 1.0f) }));
|
|
||||||
triggers.push_back(new TriggerNode("timer", { NextAction("check mount state", 1.0f) }));
|
|
||||||
}
|
|
||||||
|
|
||||||
void CollisionStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|
||||||
{
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("collision", { NextAction("move out of collision", 2.0f) }));
|
|
||||||
}
|
|
||||||
|
|
||||||
void MountStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void WorldBuffStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|
||||||
{
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"need world buff",
|
|
||||||
{
|
|
||||||
NextAction("world buff", 1.0f)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MasterFishingStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|
||||||
{
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"very often",
|
|
||||||
{
|
|
||||||
NextAction("move near water" , 10.0f)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"very often",
|
|
||||||
{
|
|
||||||
NextAction("go fishing" , 10.0f)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"random",
|
|
||||||
{
|
|
||||||
NextAction("end master fishing", 12.0f),
|
|
||||||
NextAction("equip upgrades", 6.0f)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,171 +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 "RpgStrategy.h"
|
|
||||||
|
|
||||||
#include "Playerbots.h"
|
|
||||||
#include "RpgSubActions.h"
|
|
||||||
|
|
||||||
float RpgActionMultiplier::GetValue(Action* action)
|
|
||||||
{
|
|
||||||
if (action == nullptr)
|
|
||||||
return 1.0f;
|
|
||||||
|
|
||||||
std::string const nextAction = AI_VALUE(std::string, "next rpg action");
|
|
||||||
std::string const name = action->getName();
|
|
||||||
|
|
||||||
if (!nextAction.empty() && dynamic_cast<RpgEnabled*>(action) && name != nextAction)
|
|
||||||
return 0.0f;
|
|
||||||
|
|
||||||
return 1.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
RpgStrategy::RpgStrategy(PlayerbotAI* botAI) : Strategy(botAI) {}
|
|
||||||
|
|
||||||
std::vector<NextAction> RpgStrategy::getDefaultActions()
|
|
||||||
{
|
|
||||||
return {
|
|
||||||
NextAction("rpg", 1.0f)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
void RpgStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|
||||||
{
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"no rpg target",
|
|
||||||
{
|
|
||||||
NextAction("choose rpg target", 5.0f)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"often",
|
|
||||||
{
|
|
||||||
NextAction("move random", 1.10f)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"far from rpg target",
|
|
||||||
{
|
|
||||||
NextAction("move to rpg target", 5.0f)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Sub actions
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"rpg",
|
|
||||||
{
|
|
||||||
NextAction("rpg stay", 1.101f)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"rpg",
|
|
||||||
{
|
|
||||||
NextAction("rpg work", 1.101f)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"rpg",
|
|
||||||
{
|
|
||||||
NextAction("rpg emote", 1.101f)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"has rpg target",
|
|
||||||
{
|
|
||||||
NextAction("rpg cancel", 1.101f)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"rpg discover",
|
|
||||||
{
|
|
||||||
NextAction("rpg discover", 1.210f)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"rpg start quest",
|
|
||||||
{
|
|
||||||
NextAction("rpg start quest", 1.180f)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"rpg end quest",
|
|
||||||
{
|
|
||||||
NextAction("rpg end quest", 1.190f)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"rpg buy",
|
|
||||||
{
|
|
||||||
NextAction("rpg buy", 1.130f)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"rpg repair",
|
|
||||||
{
|
|
||||||
NextAction("rpg repair", 1.195f)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"rpg heal",
|
|
||||||
{
|
|
||||||
NextAction("rpg heal", 1.125f)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"rpg home bind",
|
|
||||||
{
|
|
||||||
NextAction("rpg home bind", 1.160f)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"rpg buy petition",
|
|
||||||
{
|
|
||||||
NextAction("rpg buy petition", 1.140f)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"rpg use",
|
|
||||||
{
|
|
||||||
NextAction("rpg use", 1.102f)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void RpgStrategy::InitMultipliers(std::vector<Multiplier*>& multipliers)
|
|
||||||
{
|
|
||||||
multipliers.push_back(new RpgActionMultiplier(botAI));
|
|
||||||
}
|
|
||||||
@@ -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 "SayStrategy.h"
|
|
||||||
|
|
||||||
#include "Playerbots.h"
|
|
||||||
|
|
||||||
void SayStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|
||||||
{
|
|
||||||
triggers.push_back(new TriggerNode("critical health",
|
|
||||||
{ NextAction("say::critical health", 99.0f) }));
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("low health", { NextAction("say::low health", 99.0f) }));
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("low mana", { NextAction("say::low mana", 99.0f) }));
|
|
||||||
triggers.push_back(new TriggerNode("tank aoe", { NextAction("say::taunt", 99.0f) }));
|
|
||||||
triggers.push_back(new TriggerNode("medium aoe", { NextAction("say::aoe", 99.0f) }));
|
|
||||||
}
|
|
||||||
@@ -1,39 +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 "StayStrategy.h"
|
|
||||||
|
|
||||||
#include "Playerbots.h"
|
|
||||||
|
|
||||||
void StayStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|
||||||
{
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"return to stay position",
|
|
||||||
{
|
|
||||||
NextAction("return to stay position", ACTION_MOVE)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<NextAction> StayStrategy::getDefaultActions()
|
|
||||||
{
|
|
||||||
return {
|
|
||||||
NextAction("stay", 1.0f)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
void SitStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|
||||||
{
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"sit",
|
|
||||||
{
|
|
||||||
NextAction("sit", 1.5f)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "TravelStrategy.h"
|
|
||||||
|
|
||||||
#include "Playerbots.h"
|
|
||||||
|
|
||||||
TravelStrategy::TravelStrategy(PlayerbotAI* botAI) : Strategy(botAI) {}
|
|
||||||
|
|
||||||
std::vector<NextAction> TravelStrategy::getDefaultActions()
|
|
||||||
{
|
|
||||||
return {
|
|
||||||
NextAction("travel", 1.0f)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
void TravelStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|
||||||
{
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"no travel target",
|
|
||||||
{
|
|
||||||
NextAction("choose travel target", 6.f)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"far from travel target",
|
|
||||||
{
|
|
||||||
NextAction("move to travel target", 1)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,99 +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 "WorldPacketHandlerStrategy.h"
|
|
||||||
|
|
||||||
void WorldPacketHandlerStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|
||||||
{
|
|
||||||
PassTroughStrategy::InitTriggers(triggers);
|
|
||||||
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("group invite", { NextAction("accept invitation", relevance) }));
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("uninvite", { NextAction("uninvite", relevance) }));
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("uninvite guid", { NextAction("uninvite", relevance) }));
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("group set leader", { /*NextAction("leader", relevance),*/ }));
|
|
||||||
triggers.push_back(new TriggerNode(
|
|
||||||
"not enough money", { NextAction("tell not enough money", relevance) }));
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("not enough reputation",
|
|
||||||
{ NextAction("tell not enough reputation", relevance) }));
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("cannot equip", { NextAction("tell cannot equip", relevance) }));
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("use game object", { NextAction("add loot", relevance),
|
|
||||||
NextAction("use meeting stone", relevance) }));
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("gossip hello", { NextAction("trainer", relevance) }));
|
|
||||||
triggers.push_back(new TriggerNode("activate taxi", { NextAction("remember taxi", relevance),
|
|
||||||
NextAction("taxi", relevance) }));
|
|
||||||
triggers.push_back(new TriggerNode("taxi done", { NextAction("taxi", relevance) }));
|
|
||||||
triggers.push_back(new TriggerNode("trade status", { NextAction("accept trade", relevance), NextAction("equip upgrades", relevance) }));
|
|
||||||
triggers.push_back(new TriggerNode("trade status extended", { NextAction("trade status extended", relevance) }));
|
|
||||||
triggers.push_back(new TriggerNode("area trigger", { NextAction("reach area trigger", relevance) }));
|
|
||||||
triggers.push_back(new TriggerNode("within area trigger", { NextAction("area trigger", relevance) }));
|
|
||||||
triggers.push_back(new TriggerNode("loot response", { NextAction("store loot", relevance) }));
|
|
||||||
triggers.push_back(new TriggerNode("item push result", { NextAction("unlock items", relevance),
|
|
||||||
NextAction("open items", relevance),
|
|
||||||
NextAction("query item usage", relevance),
|
|
||||||
NextAction("equip upgrades", relevance) }));
|
|
||||||
triggers.push_back(new TriggerNode("item push result", { NextAction("quest item push result", relevance) }));
|
|
||||||
triggers.push_back(new TriggerNode("ready check finished", { NextAction("finish ready check", relevance) }));
|
|
||||||
// triggers.push_back(new TriggerNode("often", { NextAction("security check", relevance), NextAction("check mail", relevance) }));
|
|
||||||
triggers.push_back(new TriggerNode("guild invite", { NextAction("guild accept", relevance) }));
|
|
||||||
triggers.push_back(new TriggerNode("petition offer", { NextAction("petition sign", relevance) }));
|
|
||||||
triggers.push_back(new TriggerNode("lfg proposal", { NextAction("lfg accept", relevance) }));
|
|
||||||
triggers.push_back(new TriggerNode("lfg proposal active", { NextAction("lfg accept", relevance) }));
|
|
||||||
triggers.push_back(new TriggerNode("arena team invite", { NextAction("arena team accept", relevance) }));
|
|
||||||
//triggers.push_back(new TriggerNode("no non bot players around", { NextAction("delay", relevance) }));
|
|
||||||
triggers.push_back(new TriggerNode("bg status", { NextAction("bg status", relevance) }));
|
|
||||||
triggers.push_back(new TriggerNode("xpgain", { NextAction("xp gain", relevance) }));
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("levelup", { NextAction("auto maintenance on levelup", relevance + 3) }));
|
|
||||||
// triggers.push_back(new TriggerNode("group destroyed", { NextAction("reset botAI",
|
|
||||||
// relevance) }));
|
|
||||||
triggers.push_back(new TriggerNode("group list", { NextAction("reset botAI", relevance) }));
|
|
||||||
triggers.push_back(new TriggerNode("see spell", { NextAction("see spell", relevance) }));
|
|
||||||
triggers.push_back(new TriggerNode("release spirit", { NextAction("release", relevance) }));
|
|
||||||
triggers.push_back(new TriggerNode("revive from corpse", { NextAction("revive from corpse", relevance) }));
|
|
||||||
triggers.push_back(new TriggerNode("master loot roll", { NextAction("master loot roll", relevance) }));
|
|
||||||
|
|
||||||
// quest ?
|
|
||||||
//triggers.push_back(new TriggerNode("quest confirm", { NextAction("quest confirm", relevance) }));
|
|
||||||
triggers.push_back(new TriggerNode("questgiver quest details", { NextAction("turn in query quest", relevance) }));
|
|
||||||
|
|
||||||
// loot roll
|
|
||||||
triggers.push_back(new TriggerNode("very often", { NextAction("loot roll", relevance) }));
|
|
||||||
}
|
|
||||||
|
|
||||||
WorldPacketHandlerStrategy::WorldPacketHandlerStrategy(PlayerbotAI* botAI) : PassTroughStrategy(botAI)
|
|
||||||
{
|
|
||||||
supported.push_back("loot roll");
|
|
||||||
supported.push_back("check mount state");
|
|
||||||
supported.push_back("party command");
|
|
||||||
supported.push_back("ready check");
|
|
||||||
supported.push_back("uninvite");
|
|
||||||
supported.push_back("lfg role check");
|
|
||||||
supported.push_back("lfg teleport");
|
|
||||||
supported.push_back("random bot update");
|
|
||||||
supported.push_back("inventory change failure");
|
|
||||||
supported.push_back("bg status");
|
|
||||||
|
|
||||||
// quests
|
|
||||||
supported.push_back("quest update add kill");
|
|
||||||
// supported.push_back("quest update add item");
|
|
||||||
supported.push_back("quest update failed");
|
|
||||||
supported.push_back("quest update failed timer");
|
|
||||||
supported.push_back("quest update complete");
|
|
||||||
supported.push_back("confirm quest");
|
|
||||||
}
|
|
||||||
|
|
||||||
void ReadyCheckStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|
||||||
{
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("timer", { NextAction("ready check", relevance) }));
|
|
||||||
}
|
|
||||||
@@ -1,65 +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 "GenericHunterNonCombatStrategy.h"
|
|
||||||
|
|
||||||
#include "Playerbots.h"
|
|
||||||
|
|
||||||
class GenericHunterNonCombatStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
GenericHunterNonCombatStrategyActionNodeFactory()
|
|
||||||
{
|
|
||||||
creators["rapid fire"] = &rapid_fire;
|
|
||||||
creators["boost"] = &rapid_fire;
|
|
||||||
creators["aspect of the pack"] = &aspect_of_the_pack;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
static ActionNode* rapid_fire([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode("rapid fire",
|
|
||||||
/*P*/ {},
|
|
||||||
/*A*/ { NextAction("readiness")},
|
|
||||||
/*C*/ {});
|
|
||||||
}
|
|
||||||
|
|
||||||
static ActionNode* aspect_of_the_pack([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode("aspect of the pack",
|
|
||||||
/*P*/ {},
|
|
||||||
/*A*/ { NextAction("aspect of the cheetah")},
|
|
||||||
/*C*/ {});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
GenericHunterNonCombatStrategy::GenericHunterNonCombatStrategy(PlayerbotAI* botAI) : NonCombatStrategy(botAI)
|
|
||||||
{
|
|
||||||
actionNodeFactories.Add(new GenericHunterNonCombatStrategyActionNodeFactory());
|
|
||||||
}
|
|
||||||
|
|
||||||
void GenericHunterNonCombatStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|
||||||
{
|
|
||||||
NonCombatStrategy::InitTriggers(triggers);
|
|
||||||
|
|
||||||
triggers.push_back(new TriggerNode("trueshot aura", { NextAction("trueshot aura", 2.0f)}));
|
|
||||||
triggers.push_back(new TriggerNode("often", {
|
|
||||||
NextAction("apply stone", 1.0f),
|
|
||||||
NextAction("apply oil", 1.0f),
|
|
||||||
}));
|
|
||||||
triggers.push_back(new TriggerNode("low ammo", { NextAction("say::low ammo", ACTION_NORMAL)}));
|
|
||||||
triggers.push_back(new TriggerNode("no track", { NextAction("track humanoids", ACTION_NORMAL)}));
|
|
||||||
triggers.push_back(new TriggerNode("no ammo", { NextAction("equip upgrades", ACTION_HIGH + 1)}));
|
|
||||||
}
|
|
||||||
|
|
||||||
void HunterPetStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|
||||||
{
|
|
||||||
triggers.push_back(new TriggerNode("no pet", { NextAction("call pet", 60.0f)}));
|
|
||||||
triggers.push_back(new TriggerNode("has pet", { NextAction("toggle pet spell", 60.0f)}));
|
|
||||||
triggers.push_back(new TriggerNode("new pet", { NextAction("set pet stance", 60.0f)}));
|
|
||||||
triggers.push_back(new TriggerNode("pet not happy", { NextAction("feed pet", 60.0f)}));
|
|
||||||
triggers.push_back(new TriggerNode("hunters pet medium health", { NextAction("mend pet", 60.0f)}));
|
|
||||||
triggers.push_back(new TriggerNode("hunters pet dead", { NextAction("revive pet", 60.0f)}));
|
|
||||||
}
|
|
||||||
@@ -1,157 +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 "GenericHunterStrategy.h"
|
|
||||||
|
|
||||||
#include "Playerbots.h"
|
|
||||||
#include "Strategy.h"
|
|
||||||
|
|
||||||
class GenericHunterStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
GenericHunterStrategyActionNodeFactory()
|
|
||||||
{
|
|
||||||
creators["rapid fire"] = &rapid_fire;
|
|
||||||
creators["boost"] = &rapid_fire;
|
|
||||||
creators["aspect of the pack"] = &aspect_of_the_pack;
|
|
||||||
creators["aspect of the dragonhawk"] = &aspect_of_the_dragonhawk;
|
|
||||||
creators["feign death"] = &feign_death;
|
|
||||||
creators["wing clip"] = &wing_clip;
|
|
||||||
creators["mongoose bite"] = &mongoose_bite;
|
|
||||||
creators["raptor strike"] = &raptor_strike;
|
|
||||||
creators["explosive trap"] = &explosive_trap;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
static ActionNode* rapid_fire([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode("rapid fire",
|
|
||||||
/*P*/ {},
|
|
||||||
/*A*/ { NextAction("readiness") },
|
|
||||||
/*C*/ {});
|
|
||||||
}
|
|
||||||
|
|
||||||
static ActionNode* aspect_of_the_pack([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode("aspect of the pack",
|
|
||||||
/*P*/ {},
|
|
||||||
/*A*/ { NextAction("aspect of the cheetah") },
|
|
||||||
/*C*/ {});
|
|
||||||
}
|
|
||||||
|
|
||||||
static ActionNode* aspect_of_the_dragonhawk([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode("aspect of the dragonhawk",
|
|
||||||
/*P*/ {},
|
|
||||||
/*A*/ { NextAction("aspect of the hawk") },
|
|
||||||
/*C*/ {});
|
|
||||||
}
|
|
||||||
|
|
||||||
static ActionNode* feign_death([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode("feign death",
|
|
||||||
/*P*/ {},
|
|
||||||
/*A*/ {},
|
|
||||||
/*C*/ {});
|
|
||||||
}
|
|
||||||
|
|
||||||
static ActionNode* wing_clip([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode("wing clip",
|
|
||||||
/*P*/ {},
|
|
||||||
// /*A*/ { NextAction("mongoose bite") },
|
|
||||||
{},
|
|
||||||
/*C*/ {});
|
|
||||||
}
|
|
||||||
|
|
||||||
static ActionNode* mongoose_bite([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode("mongoose bite",
|
|
||||||
/*P*/ {},
|
|
||||||
/*A*/ { NextAction("raptor strike") },
|
|
||||||
/*C*/ {});
|
|
||||||
}
|
|
||||||
|
|
||||||
static ActionNode* raptor_strike([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode("raptor strike",
|
|
||||||
/*P*/ { NextAction("melee") },
|
|
||||||
/*A*/ {},
|
|
||||||
/*C*/ {});
|
|
||||||
}
|
|
||||||
|
|
||||||
static ActionNode* explosive_trap([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode("explosive trap",
|
|
||||||
/*P*/ {},
|
|
||||||
/*A*/ { NextAction("immolation trap") },
|
|
||||||
/*C*/ {});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
GenericHunterStrategy::GenericHunterStrategy(PlayerbotAI* botAI) : CombatStrategy(botAI)
|
|
||||||
{
|
|
||||||
actionNodeFactories.Add(new GenericHunterStrategyActionNodeFactory());
|
|
||||||
}
|
|
||||||
|
|
||||||
void GenericHunterStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|
||||||
{
|
|
||||||
CombatStrategy::InitTriggers(triggers);
|
|
||||||
|
|
||||||
// Mark/Ammo/Mana Triggers
|
|
||||||
triggers.push_back(new TriggerNode("no ammo", { NextAction("equip upgrades", 30.0f) }));
|
|
||||||
triggers.push_back(new TriggerNode("hunter's mark", { NextAction("hunter's mark", 29.5f) }));
|
|
||||||
triggers.push_back(new TriggerNode("rapid fire", { NextAction("rapid fire", 29.0f) }));
|
|
||||||
triggers.push_back(new TriggerNode("aspect of the viper", { NextAction("aspect of the viper", 28.0f) }));
|
|
||||||
triggers.push_back(new TriggerNode("aspect of the hawk", { NextAction("aspect of the dragonhawk", 27.5f) }));
|
|
||||||
|
|
||||||
// Aggro/Threat/Defensive Triggers
|
|
||||||
triggers.push_back(new TriggerNode("has aggro", { NextAction("concussive shot", 20.0f) }));
|
|
||||||
triggers.push_back(new TriggerNode("low tank threat", { NextAction("misdirection on main tank", 27.0f) }));
|
|
||||||
triggers.push_back(new TriggerNode("low health", { NextAction("deterrence", 35.0f) }));
|
|
||||||
triggers.push_back(new TriggerNode("concussive shot on snare target", { NextAction("concussive shot", 20.0f) }));
|
|
||||||
triggers.push_back(new TriggerNode("medium threat", { NextAction("feign death", 35.0f) }));
|
|
||||||
triggers.push_back(new TriggerNode("hunters pet medium health", { NextAction("mend pet", 22.0f) }));
|
|
||||||
triggers.push_back(new TriggerNode("hunters pet low health", { NextAction("mend pet", 21.0f) }));
|
|
||||||
|
|
||||||
// Dispel Triggers
|
|
||||||
triggers.push_back(new TriggerNode("tranquilizing shot enrage", { NextAction("tranquilizing shot", 61.0f) }));
|
|
||||||
triggers.push_back(new TriggerNode("tranquilizing shot magic", { NextAction("tranquilizing shot", 61.0f) }));
|
|
||||||
|
|
||||||
// Ranged-based Triggers
|
|
||||||
triggers.push_back(new TriggerNode("enemy within melee", {
|
|
||||||
NextAction("explosive trap", 37.0f),
|
|
||||||
NextAction("mongoose bite", 22.0f),
|
|
||||||
NextAction("wing clip", 21.0f) }));
|
|
||||||
|
|
||||||
triggers.push_back(new TriggerNode("enemy too close for auto shot", {
|
|
||||||
NextAction("disengage", 35.0f),
|
|
||||||
NextAction("flee", 34.0f) }));
|
|
||||||
}
|
|
||||||
|
|
||||||
// ===== AoE Strategy, 2/3+ enemies =====
|
|
||||||
AoEHunterStrategy::AoEHunterStrategy(PlayerbotAI* botAI) : CombatStrategy(botAI) {}
|
|
||||||
|
|
||||||
void AoEHunterStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|
||||||
{
|
|
||||||
triggers.push_back(new TriggerNode("volley channel check", { NextAction("cancel channel", 23.0f) }));
|
|
||||||
triggers.push_back(new TriggerNode("medium aoe", { NextAction("volley", 22.0f) }));
|
|
||||||
triggers.push_back(new TriggerNode("light aoe", { NextAction("multi-shot", 21.0f) }));
|
|
||||||
}
|
|
||||||
|
|
||||||
void HunterBoostStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void HunterCcStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|
||||||
{
|
|
||||||
triggers.push_back(new TriggerNode("scare beast", { NextAction("scare beast on cc", 23.0f) }));
|
|
||||||
triggers.push_back(new TriggerNode("freezing trap", { NextAction("freezing trap on cc", 23.0f) }));
|
|
||||||
}
|
|
||||||
|
|
||||||
void HunterTrapWeaveStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|
||||||
{
|
|
||||||
triggers.push_back(new TriggerNode("immolation trap no cd", { NextAction("reach melee", 23.0f) }));
|
|
||||||
}
|
|
||||||
@@ -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 "SurvivalHunterStrategy.h"
|
|
||||||
#include "Playerbots.h"
|
|
||||||
|
|
||||||
// ===== Action Node Factory =====
|
|
||||||
class SurvivalHunterStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
SurvivalHunterStrategyActionNodeFactory()
|
|
||||||
{
|
|
||||||
creators["auto shot"] = &auto_shot;
|
|
||||||
creators["kill command"] = &kill_command;
|
|
||||||
creators["kill shot"] = &kill_shot;
|
|
||||||
creators["explosive shot"] = &explosive_shot;
|
|
||||||
creators["black arrow"] = &black_arrow;
|
|
||||||
creators["viper sting"] = &viper_sting;
|
|
||||||
creators["serpent sting"] = serpent_sting;
|
|
||||||
creators["aimed shot"] = &aimed_shot;
|
|
||||||
creators["arcane shot"] = &arcane_shot;
|
|
||||||
creators["steady shot"] = &steady_shot;
|
|
||||||
creators["multi-shot"] = &multi_shot;
|
|
||||||
creators["volley"] = &volley;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
static ActionNode* auto_shot(PlayerbotAI*) { return new ActionNode("auto shot", {}, {}, {}); }
|
|
||||||
static ActionNode* kill_command(PlayerbotAI*) { return new ActionNode("kill command", {}, {}, {}); }
|
|
||||||
static ActionNode* kill_shot(PlayerbotAI*) { return new ActionNode("kill shot", {}, {}, {}); }
|
|
||||||
static ActionNode* explosive_shot(PlayerbotAI*) { return new ActionNode("explosive shot", {}, {}, {}); }
|
|
||||||
static ActionNode* black_arrow(PlayerbotAI*) { return new ActionNode("black arrow", {}, {}, {}); }
|
|
||||||
static ActionNode* viper_sting(PlayerbotAI*) { return new ActionNode("viper sting", {}, {}, {}); }
|
|
||||||
static ActionNode* serpent_sting(PlayerbotAI*) { return new ActionNode("serpent sting", {}, {}, {}); }
|
|
||||||
static ActionNode* aimed_shot(PlayerbotAI*) { return new ActionNode("aimed shot", {}, {}, {}); }
|
|
||||||
static ActionNode* arcane_shot(PlayerbotAI*) { return new ActionNode("arcane shot", {}, {}, {}); }
|
|
||||||
static ActionNode* steady_shot(PlayerbotAI*) { return new ActionNode("steady shot", {}, {}, {}); }
|
|
||||||
static ActionNode* multi_shot(PlayerbotAI*) { return new ActionNode("multi shot", {}, {}, {}); }
|
|
||||||
static ActionNode* volley(PlayerbotAI*) { return new ActionNode("volley", {}, {}, {}); }
|
|
||||||
};
|
|
||||||
|
|
||||||
// ===== Single Target Strategy =====
|
|
||||||
SurvivalHunterStrategy::SurvivalHunterStrategy(PlayerbotAI* botAI) : GenericHunterStrategy(botAI)
|
|
||||||
{
|
|
||||||
actionNodeFactories.Add(new SurvivalHunterStrategyActionNodeFactory());
|
|
||||||
}
|
|
||||||
|
|
||||||
// ===== Default Actions =====
|
|
||||||
std::vector<NextAction> SurvivalHunterStrategy::getDefaultActions()
|
|
||||||
{
|
|
||||||
return {
|
|
||||||
NextAction("kill command", 5.9f),
|
|
||||||
NextAction("kill shot", 5.8f),
|
|
||||||
NextAction("explosive shot", 5.7f),
|
|
||||||
NextAction("black arrow", 5.6f),
|
|
||||||
NextAction("serpent sting", 5.5f),
|
|
||||||
NextAction("aimed shot", 5.4f),
|
|
||||||
NextAction("arcane shot", 5.3f),
|
|
||||||
NextAction("steady shot", 5.2f),
|
|
||||||
NextAction("auto shot", 5.1f)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// ===== Trigger Initialization ===
|
|
||||||
void SurvivalHunterStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|
||||||
{
|
|
||||||
GenericHunterStrategy::InitTriggers(triggers);
|
|
||||||
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"lock and load",
|
|
||||||
{
|
|
||||||
NextAction("explosive shot rank 4", 28.0f)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"lock and load",
|
|
||||||
{
|
|
||||||
NextAction("explosive shot rank 3", 27.5f)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"lock and load",
|
|
||||||
{
|
|
||||||
NextAction("explosive shot rank 2", 27.0f)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"lock and load",
|
|
||||||
{
|
|
||||||
NextAction("explosive shot rank 1", 26.5f)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"kill command",
|
|
||||||
{
|
|
||||||
NextAction("kill command", 18.5f)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"target critical health",
|
|
||||||
{
|
|
||||||
NextAction("kill shot", 18.0f)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"explosive shot",
|
|
||||||
{
|
|
||||||
NextAction("explosive shot", 17.5f)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"black arrow",
|
|
||||||
{
|
|
||||||
NextAction("black arrow", 16.5f)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"low mana",
|
|
||||||
{
|
|
||||||
NextAction("viper sting", 16.0f)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"no stings",
|
|
||||||
{
|
|
||||||
NextAction("serpent sting", 15.5f)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"serpent sting on attacker",
|
|
||||||
{
|
|
||||||
NextAction("serpent sting on attacker", 15.0f)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,142 +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 "FrostMageStrategy.h"
|
|
||||||
|
|
||||||
#include "Playerbots.h"
|
|
||||||
|
|
||||||
// ===== Action Node Factory =====
|
|
||||||
class FrostMageStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
FrostMageStrategyActionNodeFactory()
|
|
||||||
{
|
|
||||||
creators["cold snap"] = &cold_snap;
|
|
||||||
creators["ice barrier"] = &ice_barrier;
|
|
||||||
creators["summon water elemental"] = &summon_water_elemental;
|
|
||||||
creators["deep freeze"] = &deep_freeze;
|
|
||||||
creators["icy veins"] = &icy_veins;
|
|
||||||
creators["frostbolt"] = &frostbolt;
|
|
||||||
creators["ice lance"] = &ice_lance;
|
|
||||||
creators["fire blast"] = &fire_blast;
|
|
||||||
creators["fireball"] = &fireball;
|
|
||||||
creators["frostfire bolt"] = &frostfire_bolt;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
static ActionNode* cold_snap(PlayerbotAI*) { return new ActionNode("cold snap", {}, {}, {}); }
|
|
||||||
static ActionNode* ice_barrier(PlayerbotAI*) { return new ActionNode("ice barrier", {}, {}, {}); }
|
|
||||||
static ActionNode* summon_water_elemental(PlayerbotAI*) { return new ActionNode("summon water elemental", {}, {}, {}); }
|
|
||||||
static ActionNode* deep_freeze(PlayerbotAI*) { return new ActionNode("deep freeze", {}, {}, {}); }
|
|
||||||
static ActionNode* icy_veins(PlayerbotAI*) { return new ActionNode("icy veins", {}, {}, {}); }
|
|
||||||
static ActionNode* frostbolt(PlayerbotAI*) { return new ActionNode("frostbolt", {}, {}, {}); }
|
|
||||||
static ActionNode* ice_lance(PlayerbotAI*) { return new ActionNode("ice lance", {}, {}, {}); }
|
|
||||||
static ActionNode* fire_blast(PlayerbotAI*) { return new ActionNode("fire blast", {}, {}, {}); }
|
|
||||||
static ActionNode* fireball(PlayerbotAI*) { return new ActionNode("fireball", {}, {}, {}); }
|
|
||||||
static ActionNode* frostfire_bolt(PlayerbotAI*) { return new ActionNode("frostfire bolt", {}, {}, {}); }
|
|
||||||
};
|
|
||||||
|
|
||||||
// ===== Single Target Strategy =====
|
|
||||||
FrostMageStrategy::FrostMageStrategy(PlayerbotAI* botAI) : GenericMageStrategy(botAI)
|
|
||||||
{
|
|
||||||
actionNodeFactories.Add(new FrostMageStrategyActionNodeFactory());
|
|
||||||
}
|
|
||||||
|
|
||||||
// ===== Default Actions =====
|
|
||||||
std::vector<NextAction> FrostMageStrategy::getDefaultActions()
|
|
||||||
{
|
|
||||||
return {
|
|
||||||
NextAction("frostbolt", 5.4f),
|
|
||||||
NextAction("ice lance", 5.3f), // cast during movement
|
|
||||||
NextAction("fire blast", 5.2f), // cast during movement if ice lance is not learned
|
|
||||||
NextAction("shoot", 5.1f),
|
|
||||||
NextAction("fireball", 5.0f)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// ===== Trigger Initialization ===
|
|
||||||
void FrostMageStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|
||||||
{
|
|
||||||
GenericMageStrategy::InitTriggers(triggers);
|
|
||||||
|
|
||||||
// Pet/Defensive triggers
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"no pet",
|
|
||||||
{
|
|
||||||
NextAction("summon water elemental", 30.0f)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"has pet",
|
|
||||||
{
|
|
||||||
NextAction("toggle pet spell", 60.0f)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"new pet",
|
|
||||||
{
|
|
||||||
NextAction("set pet stance", 60.0f)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"medium health",
|
|
||||||
{
|
|
||||||
NextAction("ice barrier", 29.0f)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"being attacked",
|
|
||||||
{
|
|
||||||
NextAction("ice barrier", 29.0f)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Proc/Freeze triggers
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"brain freeze",
|
|
||||||
{
|
|
||||||
NextAction("frostfire bolt", 19.5f)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"fingers of frost",
|
|
||||||
{
|
|
||||||
NextAction("deep freeze", 19.0f),
|
|
||||||
NextAction("frostbolt", 18.0f)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"frostbite on target",
|
|
||||||
{
|
|
||||||
NextAction("deep freeze", 19.0f),
|
|
||||||
NextAction("frostbolt", 18.0f)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"frost nova on target",
|
|
||||||
{
|
|
||||||
NextAction("deep freeze", 19.0f),
|
|
||||||
NextAction("frostbolt", 18.0f)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user