mirror of
https://github.com/mod-playerbots/mod-playerbots.git
synced 2026-02-02 02:13:47 +00:00
Compare commits
67 Commits
5f697e806e
...
test/buid
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f0dc6de606 | ||
|
|
8c2a27b9fe | ||
|
|
8e316cd321 | ||
|
|
cafb95e7bd | ||
|
|
8529654f8f | ||
|
|
6ee1684e9b | ||
|
|
9546363d41 | ||
|
|
00d19dbf9c | ||
|
|
caae524a0a | ||
|
|
13fff46fa0 | ||
|
|
a92886032c | ||
|
|
f5711dc6f7 | ||
|
|
43e8e31980 | ||
|
|
c59a02ed89 | ||
|
|
7abd836971 | ||
|
|
5365ba86b5 | ||
|
|
378254af3f | ||
|
|
3d467ce3bb | ||
|
|
3e21563669 | ||
|
|
bf456ee07f | ||
|
|
a5bd0b9a41 | ||
|
|
34bab48dd4 | ||
|
|
41c53365ae | ||
|
|
fd07e02a8a | ||
|
|
6cf7f1aaef | ||
|
|
9f54d7e702 | ||
|
|
aeaaee15da | ||
|
|
a1137dbddc | ||
|
|
2eb98c3233 | ||
|
|
29613e29b7 | ||
|
|
e2c203a35e | ||
|
|
1b1ed18a23 | ||
|
|
2ab73c1fd5 | ||
|
|
6b97c379ba | ||
|
|
965d300203 | ||
|
|
dc55ecfd9c | ||
|
|
59d6eb139e | ||
|
|
00171a8c82 | ||
|
|
02e8465a3b | ||
|
|
f53a8704eb | ||
|
|
e5525958c8 | ||
|
|
9ae457d069 | ||
|
|
c9e98a6b4e | ||
|
|
3d9623f119 | ||
|
|
c9cc4324d3 | ||
|
|
b13fb7d12a | ||
|
|
962fdeb3d1 | ||
|
|
83c6977de5 | ||
|
|
686fe513b2 | ||
|
|
61402e83a1 | ||
|
|
b16789fa54 | ||
|
|
8f638b6a66 | ||
|
|
33f5e733dc | ||
|
|
9917863ca1 | ||
|
|
2317652d72 | ||
|
|
1fcd6c5cda | ||
|
|
88016789ba | ||
|
|
6be860c967 | ||
|
|
9971622093 | ||
|
|
895df9b197 | ||
|
|
467b63b840 | ||
|
|
66f5f597bb | ||
|
|
cafbd4681e | ||
|
|
f5c84ee7ff | ||
|
|
b6f882886d | ||
|
|
c1222da8b0 | ||
|
|
00cb177c86 |
19
.github/workflows/check_pr_source.yml
vendored
Normal file
19
.github/workflows/check_pr_source.yml
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
name: Enforce test-staging → main
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
require-test-staging:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Ensure PR source is test-staging
|
||||
run: |
|
||||
echo "Base: ${{ github.event.pull_request.base.ref }}"
|
||||
echo "Head: ${{ github.event.pull_request.head.ref }}"
|
||||
if [ "${{ github.event.pull_request.head.ref }}" != "test-staging" ]; then
|
||||
echo "✖ Pull request must come from test-staging"
|
||||
exit 1
|
||||
fi
|
||||
6
.github/workflows/windows_build.yml
vendored
6
.github/workflows/windows_build.yml
vendored
@@ -25,21 +25,25 @@ jobs:
|
||||
with:
|
||||
repository: 'mod-playerbots/azerothcore-wotlk'
|
||||
ref: 'Playerbot'
|
||||
path: 'ac'
|
||||
- name: Checkout Playerbot Module
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
repository: 'mod-playerbots/mod-playerbots'
|
||||
path: 'modules/mod-playerbots'
|
||||
#path: 'modules/mod-playerbots'
|
||||
path: ac/modules/mod-playerbots
|
||||
- name: ccache
|
||||
uses: hendrikmuhs/ccache-action@v1.2.13
|
||||
- name: Configure OS
|
||||
shell: bash
|
||||
working-directory: ac
|
||||
env:
|
||||
CONTINUOUS_INTEGRATION: true
|
||||
run: |
|
||||
./acore.sh install-deps
|
||||
- name: Build
|
||||
shell: bash
|
||||
working-directory: ac
|
||||
run: |
|
||||
export CTOOLS_BUILD=all
|
||||
./acore.sh compiler build
|
||||
|
||||
127
PULL_REQUEST_TEMPLATE.md
Normal file
127
PULL_REQUEST_TEMPLATE.md
Normal file
@@ -0,0 +1,127 @@
|
||||
# Pull Request
|
||||
|
||||
Describe what this change does and why it is needed...
|
||||
|
||||
---
|
||||
|
||||
## Design Philosophy
|
||||
|
||||
We prioritize **stability, performance, and predictability** over behavioral realism.
|
||||
Complex player-mimicking logic is intentionally limited due to its negative impact on scalability, maintainability, and
|
||||
long-term robustness.
|
||||
|
||||
Excessive processing overhead can lead to server hiccups, increased CPU usage, and degraded performance for all
|
||||
participants. Because every action and
|
||||
decision tree is executed **per bot and per trigger**, even small increases in logic complexity can scale poorly and
|
||||
negatively affect both players and
|
||||
world (random) bots. Bots are not expected to behave perfectly, and perfect simulation of human decision-making is not a
|
||||
project goal. Increased behavioral
|
||||
realism often introduces disproportionate cost, reduced predictability, and significantly higher maintenance overhead.
|
||||
|
||||
Every additional branch of logic increases long-term responsibility. All decision paths must be tested, validated, and
|
||||
maintained continuously as the system evolves.
|
||||
If advanced or AI-intensive behavior is introduced, the **default configuration must remain the lightweight decision
|
||||
model**. More complex behavior should only be
|
||||
available as an **explicit opt-in option**, clearly documented as having a measurable performance cost.
|
||||
|
||||
Principles:
|
||||
|
||||
- **Stability before intelligence**
|
||||
A stable system is always preferred over a smarter one.
|
||||
|
||||
- **Performance is a shared resource**
|
||||
Any increase in bot cost affects all players and all bots.
|
||||
|
||||
- **Simple logic scales better than smart logic**
|
||||
Predictable behavior under load is more valuable than perfect decisions.
|
||||
|
||||
- **Complexity must justify itself**
|
||||
If a feature cannot clearly explain its cost, it should not exist.
|
||||
|
||||
- **Defaults must be cheap**
|
||||
Expensive behavior must always be optional and clearly communicated.
|
||||
|
||||
- **Bots should look reasonable, not perfect**
|
||||
The goal is believable behavior, not human simulation.
|
||||
|
||||
Before submitting, confirm that this change aligns with those principles.
|
||||
|
||||
---
|
||||
|
||||
## Feature Evaluation
|
||||
|
||||
Please answer the following:
|
||||
|
||||
- Describe the **minimum logic** required to achieve the intended behavior?
|
||||
- Describe the **cheapest implementation** that produces an acceptable result?
|
||||
- Describe the **runtime cost** when this logic executes across many bots?
|
||||
|
||||
---
|
||||
|
||||
## How to Test the Changes
|
||||
|
||||
- Step-by-step instructions to test the change
|
||||
- Any required setup (e.g. multiple players, bots, specific configuration)
|
||||
- Expected behavior and how to verify it
|
||||
|
||||
## Complexity & Impact
|
||||
|
||||
- Does this change add new decision branches?
|
||||
- [ ] No
|
||||
- [ ] Yes (**explain below**)
|
||||
|
||||
- Does this change increase per-bot or per-tick processing?
|
||||
- [ ] No
|
||||
- [ ] Yes (**describe and justify impact**)
|
||||
|
||||
- Could this logic scale poorly under load?
|
||||
- [ ] No
|
||||
- [ ] Yes (**explain why**)
|
||||
|
||||
---
|
||||
|
||||
## Defaults & Configuration
|
||||
|
||||
- Does this change modify default bot behavior?
|
||||
- [ ] No
|
||||
- [ ] Yes (**explain why**)
|
||||
|
||||
If this introduces more advanced or AI-heavy logic:
|
||||
|
||||
- [ ] Lightweight mode remains the default
|
||||
- [ ] More complex behavior is optional and thereby configurable
|
||||
|
||||
---
|
||||
|
||||
## AI Assistance
|
||||
|
||||
- Was AI assistance (e.g. ChatGPT or similar tools) used while working on this change?
|
||||
- [ ] No
|
||||
- [ ] Yes (**explain below**)
|
||||
|
||||
If yes, please specify:
|
||||
|
||||
- AI tool or model used (e.g. ChatGPT, GPT-4, Claude, etc.)
|
||||
- Purpose of usage (e.g. brainstorming, refactoring, documentation, code generation)
|
||||
- Which parts of the change were influenced or generated
|
||||
- Whether the result was manually reviewed and adapted
|
||||
|
||||
AI assistance is allowed, but all submitted code must be fully understood, reviewed, and owned by the contributor.
|
||||
Any AI-influenced changes must be verified against existing CORE and PB logic. We expect contributors to be honest
|
||||
about what they do and do not understand.
|
||||
|
||||
---
|
||||
|
||||
## Final Checklist
|
||||
|
||||
- [ ] Stability is not compromised
|
||||
- [ ] Performance impact is understood, tested, and acceptable
|
||||
- [ ] Added logic complexity is justified and explained
|
||||
- [ ] Documentation updated if needed
|
||||
|
||||
---
|
||||
|
||||
## Notes for Reviewers
|
||||
|
||||
Anything that significantly improves realism at the cost of stability or performance should be carefully discussed
|
||||
before merging.
|
||||
71
README_CN.md
71
README_CN.md
@@ -1,71 +0,0 @@
|
||||
[English](README.md) | [Español](README_ES.md) | [中文](README_CN.md)
|
||||
|
||||
# 玩家机器人模块
|
||||
|
||||
欢迎使用AzerothCore的玩家机器人模块,这是一个基于IKE3玩家机器人的正在进行中的项目。这些玩家机器人利用实际的玩家数据,使您能够与您自己的替身进行交互,组建队伍,升级角色等等。
|
||||
|
||||
如果您遇到任何错误或出现崩溃,请您将它们报告为GitHub问题。您宝贵的反馈将帮助我们协作改进和增强这个项目。
|
||||
|
||||
## 安装
|
||||
|
||||
请注意,此模块需要对AzerothCore进行特定的自定义更改。为了确保兼容性,您必须使用我fork的自定义分支来编译它,可以在这里找到:[mod-playerbots/azerothcore-wotlk/tree/Playerbot](https://github.com/mod-playerbots/azerothcore-wotlk/tree/Playerbot)。
|
||||
|
||||
要安装此模块,请参考AzerothCore Wiki的详细说明:[AzerothCore安装指南](https://www.azerothcore.org/wiki/installation)。
|
||||
|
||||
我们提供了一个简单的方法来克隆该模块:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/mod-playerbots/azerothcore-wotlk.git --branch=Playerbot
|
||||
cd azerothcore-wotlk/modules
|
||||
git clone https://github.com/mod-playerbots/mod-playerbots.git --branch=master
|
||||
```
|
||||
|
||||
## 快速开始与文档
|
||||
|
||||
要快速开始并了解一系列命令,您可以参考ike3原版playerbots的手册。该模块提供了大部分基本命令。您可以在此找到文档:[IKE3 Playerbots 文档](https://ike3.github.io/mangosbot-docs/)。请注意,在我们的模块中,您需要将文档中所有的 `.bot` 替换为 `.playerbot bot`。
|
||||
|
||||
请注意,由于项目仍在开发中,新添加的命令的文档目前尚不完善。
|
||||
|
||||
## 进展
|
||||
|
||||
该模块主要强调以下关键功能,并在这些领域实施了改进:
|
||||
|
||||
- **世界中的机器人(随机机器人):** 我们增强了随机机器人的行为,使它们更接近真实玩家的表现,从而创建了更真实的玩家服务器环境。
|
||||
|
||||
- **团队副本中的机器人:** 我们赋予机器人征服具有挑战性的团队副本内容的能力,通过为各种Boss实施特定策略,使团队副本更加吸引人。此外,我们增强了机器人在DPS、治疗和坦克等各种角色中的能力,确保它们有效地为团队的成功做出贡献。
|
||||
|
||||
- **战场中的机器人:** 机器人现在能够与真实玩家一起积极参与战场,为这些PvP场景增添了深度和刺激。
|
||||
|
||||
- **与机器人的交互:** 我们改进了真实玩家和机器人之间的交互,使玩家能够在与机器人伙伴合作时完成任务并升级多个角色。
|
||||
|
||||
- **玩家进阶路径:** 我们设计了一个改进的玩家进阶路径,辅以机器人,为玩家提供了一种替代且引人入胜的游戏体验。
|
||||
|
||||
- **稳定性:** 我们的努力主要集中在增强使用Playerbots模块时AzerothCore的整体稳定性。这些改进旨在防止服务器崩溃,并确保所有用户都能获得更流畅的体验。
|
||||
|
||||
- **配置:** 我们引入了一系列可配置的选项,以满足不同需求的玩家,从而提供更个性化的体验。
|
||||
|
||||
值得注意的是,随着我们继续改进项目,还有大量工作需要完成。我们欢迎每个人以不同的方式做出贡献。
|
||||
|
||||
## 插件
|
||||
|
||||
为了更好地控制机器人并简化命令的使用,您还可以使用我们的插件:[Unbot Addon](https://github.com/liyunfan1223/unbot-addon)。目前,该插件仅对简体中文客户端提供更好的支持。
|
||||
|
||||
## 常见问题
|
||||
|
||||
**机器人无法释放技能**
|
||||
|
||||
- 请确保必要的英文DBC文件(enUS)存在。
|
||||
|
||||
**编译错误**
|
||||
|
||||
- 我们支持Ubuntu、Windows和macOS。
|
||||
|
||||
- 我们建立了持续集成工作流。您可以在[GitHub Actions](https://github.com/mod-playerbots/mod-playerbots/actions)中查看构建状态。
|
||||
|
||||
- 如果最新的构建状态失败,请恢复到上一个提交。我们将尽快解决此问题。
|
||||
|
||||
## 致谢
|
||||
|
||||
该模块的代码来自[ZhengPeiRu21/mod-playerbots](https://github.com/ZhengPeiRu21/mod-playerbots)和[celguar/mangosbot-bots](https://github.com/celguar/mangosbot-bots)。我们衷心感谢@ZhengPeiRu21和@celguar对维护该模块的持续努力。
|
||||
|
||||
我们还要向所有为playerbot开发做出贡献的个人表示诚挚的感谢。您的奉献和努力对塑造这个项目至关重要,我们对您的贡献表示感谢。
|
||||
@@ -3,8 +3,9 @@
|
||||
##################################################
|
||||
|
||||
# Overview
|
||||
# "Randombot": randomly generated bots that log in separately from players and populate the world. Depending on settings, randombots may automatically grind, quest, and upgrade equipment and can be invited to groups and given commands.
|
||||
# "Altbot": characters created on player accounts, which may be logged in by the player and invited to groups and given commands like randombots. Depending on settings, altbots can be limited to characters on the active player's account or in the active player's guild.
|
||||
# "Randombot": randomly generated bots that log in separately from players and populate the world. Randombots may automatically grind, quest, level up, and upgrade equipment and can be invited to groups and given commands.
|
||||
# "AddClass bot": bots from the AddClassAccountPoolSize accounts. They are used for quickly adding a leveled and geared bot of any class to your party. They are recommended for a quick formation of a party.
|
||||
# "Altbot": characters created on player accounts, which may be logged in by the player and invited to groups and given commands like randombots. They are best suited for long-progression playthroughs.
|
||||
# Information about commands to control bots and set their strategies can be found on the wiki at https://github.com/mod-playerbots/mod-playerbots/wiki/Playerbot-Commands.
|
||||
|
||||
####################################################################################################
|
||||
@@ -21,10 +22,11 @@
|
||||
# THRESHOLDS
|
||||
# QUESTS
|
||||
# COMBAT
|
||||
# PALADIN BUFFS STRATEGIES
|
||||
# GREATER BUFFS STRATEGIES
|
||||
# CHEATS
|
||||
# SPELLS
|
||||
# FLIGHTPATH
|
||||
# PROFESSIONS
|
||||
# RANDOMBOT-SPECIFIC SETTINGS
|
||||
# GENERAL
|
||||
# LEVELS
|
||||
@@ -44,7 +46,7 @@
|
||||
# HUNTER
|
||||
# ROGUE
|
||||
# PRIEST
|
||||
# DEATHKNIGHT
|
||||
# DEATH KNIGHT
|
||||
# SHAMAN
|
||||
# MAGE
|
||||
# WARLOCK
|
||||
@@ -55,7 +57,7 @@
|
||||
# HUNTER
|
||||
# ROGUE
|
||||
# PRIEST
|
||||
# DEATHKNIGHT
|
||||
# DEATH KNIGHT
|
||||
# SHAMAN
|
||||
# MAGE
|
||||
# WARLOCK
|
||||
@@ -90,17 +92,20 @@ AiPlayerbot.MinRandomBots = 500
|
||||
AiPlayerbot.MaxRandomBots = 500
|
||||
|
||||
# Randombot accounts
|
||||
# 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)
|
||||
# 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)
|
||||
# Default: 0 (automatic)
|
||||
AiPlayerbot.RandomBotAccountCount = 0
|
||||
|
||||
# Delete all randombot accounts
|
||||
# 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.
|
||||
# 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.
|
||||
AiPlayerbot.DeleteRandomBotAccounts = 0
|
||||
|
||||
# Disable randombots when no real players are logged in
|
||||
# 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 log out 300 seconds (default) after all real players log out
|
||||
# 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
|
||||
AiPlayerbot.DisabledWithoutRealPlayer = 0
|
||||
AiPlayerbot.DisabledWithoutRealPlayerLoginDelay = 30
|
||||
AiPlayerbot.DisabledWithoutRealPlayerLogoutDelay = 300
|
||||
@@ -152,7 +157,8 @@ AiPlayerbot.AllowGuildBots = 1
|
||||
AiPlayerbot.AllowTrustedAccountBots = 1
|
||||
|
||||
# Randombots will create guilds with nearby randombots
|
||||
# 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)
|
||||
# Note: currently, randombots will not invite more bots after a guild is created,
|
||||
# meaning randombot guilds will have only the 10 initial randombots needed to sign the charter
|
||||
# Default: 0 (disabled)
|
||||
AiPlayerbot.RandomBotGuildNearby = 0
|
||||
|
||||
@@ -186,7 +192,8 @@ AiPlayerbot.AutoInitOnly = 0
|
||||
# Default: 1.0 (same with the player)
|
||||
AiPlayerbot.AutoInitEquipLevelLimitRatio = 1.0
|
||||
|
||||
# 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)
|
||||
# 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
|
||||
AiPlayerbot.AutoTrainSpells = yes
|
||||
|
||||
#
|
||||
@@ -263,7 +270,7 @@ AiPlayerbot.UseFastFlyMountAtMinLevel = 70
|
||||
AiPlayerbot.RandomBotShowHelmet = 1
|
||||
AiPlayerbot.RandomBotShowCloak = 1
|
||||
|
||||
# Randombots and altbots automatically equip upgrades (bots will equip any item obtained from looting or a quest if they are sufficient upgrades)
|
||||
# Toggles whether altbots will automatically equip items in their inventory that are sufficient upgrades
|
||||
# Default: 1 (enabled)
|
||||
AiPlayerbot.AutoEquipUpgradeLoot = 1
|
||||
|
||||
@@ -311,7 +318,8 @@ AiPlayerbot.GlobalCooldown = 500
|
||||
# Max wait time when moving
|
||||
AiPlayerbot.MaxWaitForMove = 5000
|
||||
|
||||
# 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)
|
||||
# Enable/disable use of MoveSplinePath for bot movement
|
||||
# Disabling will result in more erratic movement but is required for stuns, snares, and roots to work on bots
|
||||
# Default: 0 - MoveSplinePath enabled
|
||||
# 1 - MoveSplinePath disabled in BG/Arena only
|
||||
# 2 - MoveSplinePath disabled everywhere
|
||||
@@ -405,10 +413,11 @@ AiPlayerbot.HighMana = 65
|
||||
#
|
||||
#
|
||||
|
||||
# Bots pick their quest rewards (yes = picks the most useful item, no = list all rewards, ask = pick useful item and lists if multiple)
|
||||
# Bots pick their quest rewards
|
||||
# yes = picks the most useful item, no = list all rewards, ask = pick useful item and lists if multiple
|
||||
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)
|
||||
AiPlayerbot.SyncQuestWithPlayer = 1
|
||||
|
||||
@@ -433,7 +442,7 @@ AiPlayerbot.DropObsoleteQuests = 1
|
||||
# Auto add dungeon/raid strategies when entering the instance if implemented
|
||||
AiPlayerbot.ApplyInstanceStrategies = 1
|
||||
|
||||
# Enable auto avoid aoe strategy (experimental)
|
||||
# Enable auto avoid aoe strategy
|
||||
# Default: 1 (enabled)
|
||||
AiPlayerbot.AutoAvoidAoe = 1
|
||||
|
||||
@@ -460,7 +469,7 @@ AiPlayerbot.FleeingEnabled = 1
|
||||
####################################################################################################
|
||||
|
||||
####################################################################################################
|
||||
# PALADIN BUFFS STRATEGIES
|
||||
# GREATER BUFFS STRATEGIES
|
||||
#
|
||||
#
|
||||
|
||||
@@ -483,12 +492,13 @@ AiPlayerbot.RPWarningCooldown = 30
|
||||
#
|
||||
|
||||
# Enable/Disable maintenance command
|
||||
# Learn all available spells and skills, refresh consumables, repair, enchant equipment and socket gems 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)
|
||||
AiPlayerbot.MaintenanceCommand = 1
|
||||
|
||||
# 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)
|
||||
AiPlayerbot.AltMaintenanceAmmo = 1
|
||||
AiPlayerbot.AltMaintenanceFood = 1
|
||||
@@ -500,6 +510,7 @@ AiPlayerbot.AltMaintenanceBags = 1
|
||||
AiPlayerbot.AltMaintenanceMounts = 1
|
||||
AiPlayerbot.AltMaintenanceSkills = 1
|
||||
|
||||
# "Special Spells" consist of any spells listed in AiPlayerbot.RandomBotSpellIds and Death Gate for Death Knights
|
||||
AiPlayerbot.AltMaintenanceClassSpells = 1
|
||||
AiPlayerbot.AltMaintenanceAvailableSpells = 1
|
||||
AiPlayerbot.AltMaintenanceSpecialSpells = 1
|
||||
@@ -514,8 +525,8 @@ AiPlayerbot.AltMaintenanceReputation = 1
|
||||
AiPlayerbot.AltMaintenanceAttunementQuests = 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)
|
||||
AiPlayerbot.AutoGearCommand = 1
|
||||
|
||||
@@ -533,8 +544,8 @@ AiPlayerbot.AutoGearQualityLimit = 3
|
||||
# Max iLVL Phase 1(MC, Ony, ZG) = 78 | Phase 2(BWL) = 83 | Phase 2.5(AQ40) = 88 | Phase 3(Naxx40) = 92
|
||||
# TBC
|
||||
# Max iLVL Tier 4 = 120 | Tier 5 = 133 | Tier 6 = 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
|
||||
# Max iLVL Phase 1(Kara, Gruul, Mag) = 125 | Phase 2(SSC, TK, ZA) = 141 | Phase 3(Hyjal, BT) = 156 | Phase 4(Sunwell) = 164
|
||||
# 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 Phase 1(Naxx) = 224 | Phase 2(Ulduar) = 245 | Phase 3(ToC) = 258 | Phase 4(ICC) = 290
|
||||
# Default: 0 (no limit)
|
||||
@@ -579,6 +590,30 @@ 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 #
|
||||
@@ -635,7 +670,7 @@ AiPlayerbot.DisableDeathKnightLogin = 0
|
||||
# Default: 0 (disabled)
|
||||
AiPlayerbot.LimitTalentsExpansion = 0
|
||||
|
||||
# Configure randombots and addClass bot trading (0: Disabled, 1: Enabled, 2: Only Buy, 3: Only Sell)
|
||||
# Configure randombot trading (0: Disabled, 1: Enabled, 2: Only Buy, 3: Only Sell)
|
||||
# Default: 1 (enabled)
|
||||
AiPlayerbot.EnableRandomBotTrading = 1
|
||||
|
||||
@@ -700,8 +735,8 @@ AiPlayerbot.RandomGearQualityLimit = 3
|
||||
# Max iLVL Phase 1(MC, Ony, ZG) = 78 | Phase 2(BWL) = 83 | Phase 2.5(AQ40) = 88 | Phase 3(Naxx40) = 92
|
||||
# TBC
|
||||
# Max iLVL Tier 4 = 120 | Tier 5 = 133 | Tier 6 = 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
|
||||
# Max iLVL Phase 1(Kara, Gruul, Mag) = 125 | Phase 2(SSC, TK, ZA) = 141 | Phase 3(Hyjal, BT) = 156 | Phase 4(Sunwell) = 164
|
||||
# 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 Phase 1(Naxx) = 224 | Phase 2(Ulduar) = 245 | Phase 3(ToC) = 258 | Phase 4(ICC) = 290
|
||||
# Default: 0 (no limit)
|
||||
@@ -711,7 +746,8 @@ AiPlayerbot.RandomGearScoreLimit = 0
|
||||
# Default: 1 (enabled)
|
||||
AiPlayerbot.IncrementalGearInit = 1
|
||||
|
||||
# Set minimum level of bots that will enchant their equipment (if greater than RandomBotMaxlevel, bots will not enchant equipment)
|
||||
# Set minimum level of bots that will enchant and socket gems into their equipment with maintenance
|
||||
# If greater than RandomBotMaxlevel, bots will not automatically enchant equipment or socket gems
|
||||
# Default: 60
|
||||
AiPlayerbot.MinEnchantingBotLevel = 60
|
||||
|
||||
@@ -863,13 +899,15 @@ AiPlayerbot.OpenGoSpell = 6477
|
||||
#
|
||||
|
||||
# Additional randombot 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.
|
||||
# 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.
|
||||
# Example: "+threat,-potions"
|
||||
AiPlayerbot.RandomBotCombatStrategies = ""
|
||||
AiPlayerbot.RandomBotNonCombatStrategies = ""
|
||||
|
||||
# Additional altbot 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.
|
||||
# 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.
|
||||
AiPlayerbot.CombatStrategies = ""
|
||||
AiPlayerbot.NonCombatStrategies = ""
|
||||
|
||||
@@ -1455,7 +1493,7 @@ AiPlayerbot.PremadeSpecLink.5.5.80 = 50332031003--005323241223112003102311351
|
||||
####################################################################################################
|
||||
|
||||
####################################################################################################
|
||||
# DEATHKNIGHT
|
||||
# DEATH KNIGHT
|
||||
#
|
||||
#
|
||||
|
||||
@@ -1586,7 +1624,7 @@ AiPlayerbot.PremadeSpecLink.9.1.60 = -003203301135112530135201051
|
||||
AiPlayerbot.PremadeSpecLink.9.1.70 = -003203301135112530135201051-55
|
||||
AiPlayerbot.PremadeSpecLink.9.1.80 = -003203301135112530135221351-55000005
|
||||
AiPlayerbot.PremadeSpecName.9.2 = destro pve
|
||||
AiPlayerbot.PremadeSpecGlyph.9.2 = 45785,43390,50077,43394,43393,42454
|
||||
AiPlayerbot.PremadeSpecGlyph.9.2 = 45785,43390,42454,43394,43393,45785
|
||||
AiPlayerbot.PremadeSpecLink.9.2.60 = --05203215200231051305031151
|
||||
AiPlayerbot.PremadeSpecLink.9.2.80 = 23-0302-05203215220331051335231351
|
||||
AiPlayerbot.PremadeSpecName.9.3 = affli pvp
|
||||
@@ -1778,7 +1816,7 @@ AiPlayerbot.RandomClassSpecIndex.5.2 = 2
|
||||
####################################################################################################
|
||||
|
||||
####################################################################################################
|
||||
# DEATHKNIGHT
|
||||
# DEATH KNIGHT
|
||||
#
|
||||
#
|
||||
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
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);
|
||||
@@ -46,7 +46,6 @@
|
||||
#include "OutfitAction.h"
|
||||
#include "PositionAction.h"
|
||||
#include "DropQuestAction.h"
|
||||
#include "RaidNaxxActions.h"
|
||||
#include "RandomBotUpdateAction.h"
|
||||
#include "ReachTargetActions.h"
|
||||
#include "ReleaseSpiritAction.h"
|
||||
@@ -64,6 +63,7 @@
|
||||
#include "WorldBuffAction.h"
|
||||
#include "XpGainAction.h"
|
||||
#include "NewRpgAction.h"
|
||||
#include "FishingAction.h"
|
||||
#include "CancelChannelAction.h"
|
||||
|
||||
class PlayerbotAI;
|
||||
@@ -191,6 +191,11 @@ public:
|
||||
creators["buy tabard"] = &ActionContext::buy_tabard;
|
||||
creators["guild manage nearby"] = &ActionContext::guild_manage_nearby;
|
||||
creators["clean quest log"] = &ActionContext::clean_quest_log;
|
||||
creators["move near water"] = &ActionContext::move_near_water;
|
||||
creators["go fishing"] = &ActionContext::go_fishing;
|
||||
creators["use fishing bobber"] = &ActionContext::use_fishing_bobber;
|
||||
creators["end master fishing"] = &ActionContext::end_master_fishing;
|
||||
creators["remove bobber strategy"] = &ActionContext::remove_bobber_strategy;
|
||||
creators["roll"] = &ActionContext::roll_action;
|
||||
creators["cancel channel"] = &ActionContext::cancel_channel;
|
||||
|
||||
@@ -380,6 +385,11 @@ private:
|
||||
static Action* buy_tabard(PlayerbotAI* botAI) { return new BuyTabardAction(botAI); }
|
||||
static Action* guild_manage_nearby(PlayerbotAI* botAI) { return new GuildManageNearbyAction(botAI); }
|
||||
static Action* clean_quest_log(PlayerbotAI* botAI) { return new CleanQuestLogAction(botAI); }
|
||||
static Action* move_near_water(PlayerbotAI* botAI) { return new MoveNearWaterAction(botAI); }
|
||||
static Action* go_fishing(PlayerbotAI* botAI) { return new FishingAction(botAI);}
|
||||
static Action* use_fishing_bobber(PlayerbotAI* botAI) { return new UseBobberAction(botAI);}
|
||||
static Action* end_master_fishing(PlayerbotAI* botAI) { return new EndMasterFishingAction(botAI); }
|
||||
static Action* remove_bobber_strategy(PlayerbotAI* botAI) { return new RemoveBobberStrategyAction(botAI); }
|
||||
static Action* roll_action(PlayerbotAI* botAI) { return new RollAction(botAI); }
|
||||
|
||||
// BG Tactics
|
||||
@@ -46,10 +46,10 @@ bool AcceptInvitationAction::Execute(Event event)
|
||||
if (!bot->GetGroup() || !bot->GetGroup()->IsMember(inviter->GetGUID()))
|
||||
return false;
|
||||
|
||||
if (sRandomPlayerbotMgr->IsRandomBot(bot))
|
||||
if (sRandomPlayerbotMgr.IsRandomBot(bot))
|
||||
botAI->SetMaster(inviter);
|
||||
// else
|
||||
// sPlayerbotDbStore->Save(botAI);
|
||||
// PlayerbotRepository::instance().Save(botAI);
|
||||
|
||||
botAI->ResetStrategies();
|
||||
botAI->ChangeStrategy("+follow,-lfg,-bg", BOT_STATE_NON_COMBAT);
|
||||
@@ -57,9 +57,9 @@ bool AcceptInvitationAction::Execute(Event event)
|
||||
|
||||
botAI->TellMaster("Hello");
|
||||
|
||||
if (sPlayerbotAIConfig->summonWhenGroup && bot->GetDistance(inviter) > sPlayerbotAIConfig->sightDistance)
|
||||
if (sPlayerbotAIConfig.summonWhenGroup && bot->GetDistance(inviter) > sPlayerbotAIConfig.sightDistance)
|
||||
{
|
||||
Teleport(inviter, bot);
|
||||
Teleport(inviter, bot, true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -23,7 +23,5 @@ bool AcceptResurrectAction::Execute(Event event)
|
||||
packet << uint8(1); // accept
|
||||
bot->GetSession()->HandleResurrectResponseOpcode(packet); // queue the packet to get around race condition
|
||||
|
||||
botAI->ChangeEngine(BOT_STATE_NON_COMBAT);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -50,7 +50,7 @@ bool ReachAreaTriggerAction::Execute(Event event)
|
||||
/*forceDestination*/ false);
|
||||
|
||||
float distance = bot->GetDistance(at->x, at->y, at->z);
|
||||
float delay = 1000.0f * distance / bot->GetSpeed(MOVE_RUN) + sPlayerbotAIConfig->reactDelay;
|
||||
float delay = 1000.0f * distance / bot->GetSpeed(MOVE_RUN) + sPlayerbotAIConfig.reactDelay;
|
||||
botAI->TellError("Wait for me");
|
||||
botAI->SetNextCheckDelay(delay);
|
||||
context->GetValue<LastMovement&>("last area trigger")->Get().lastAreaTrigger = triggerId;
|
||||
@@ -15,20 +15,19 @@
|
||||
#include "SharedDefines.h"
|
||||
#include "Unit.h"
|
||||
|
||||
bool AttackAction::Execute(Event event)
|
||||
bool AttackAction::Execute(Event /*event*/)
|
||||
{
|
||||
Unit* target = GetTarget();
|
||||
if (!target)
|
||||
return false;
|
||||
|
||||
if (!target->IsInWorld())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return Attack(target);
|
||||
}
|
||||
|
||||
bool AttackMyTargetAction::Execute(Event event)
|
||||
bool AttackMyTargetAction::Execute(Event /*event*/)
|
||||
{
|
||||
Player* master = GetMaster();
|
||||
if (!master)
|
||||
@@ -51,7 +50,7 @@ bool AttackMyTargetAction::Execute(Event event)
|
||||
return result;
|
||||
}
|
||||
|
||||
bool AttackAction::Attack(Unit* target, bool with_pet /*true*/)
|
||||
bool AttackAction::Attack(Unit* target, bool /*with_pet*/ /*true*/)
|
||||
{
|
||||
Unit* oldTarget = context->GetValue<Unit*>("current target")->Get();
|
||||
bool shouldMelee = bot->IsWithinMeleeRange(target) || botAI->IsMelee(bot);
|
||||
@@ -81,13 +80,15 @@ bool AttackAction::Attack(Unit* target, bool with_pet /*true*/)
|
||||
{
|
||||
if (verbose)
|
||||
botAI->TellError(std::string(target->GetName()) + " is no longer in the world.");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if bot OR target is in prohibited zone/area
|
||||
// Check if bot OR target is in prohibited zone/area (skip for duels)
|
||||
if ((target->IsPlayer() || target->IsPet()) &&
|
||||
(sPlayerbotAIConfig->IsPvpProhibited(bot->GetZoneId(), bot->GetAreaId()) ||
|
||||
sPlayerbotAIConfig->IsPvpProhibited(target->GetZoneId(), target->GetAreaId())))
|
||||
(!bot->duel || bot->duel->Opponent != target) &&
|
||||
(sPlayerbotAIConfig.IsPvpProhibited(bot->GetZoneId(), bot->GetAreaId()) ||
|
||||
sPlayerbotAIConfig.IsPvpProhibited(target->GetZoneId(), target->GetAreaId())))
|
||||
{
|
||||
if (verbose)
|
||||
botAI->TellError("I cannot attack other players in PvP prohibited areas.");
|
||||
@@ -99,6 +100,7 @@ bool AttackAction::Attack(Unit* target, bool with_pet /*true*/)
|
||||
{
|
||||
if (verbose)
|
||||
botAI->TellError(std::string(target->GetName()) + " is friendly to me.");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -106,6 +108,7 @@ bool AttackAction::Attack(Unit* target, bool with_pet /*true*/)
|
||||
{
|
||||
if (verbose)
|
||||
botAI->TellError(std::string(target->GetName()) + " is dead.");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -113,6 +116,7 @@ bool AttackAction::Attack(Unit* target, bool with_pet /*true*/)
|
||||
{
|
||||
if (verbose)
|
||||
botAI->TellError(std::string(target->GetName()) + " is not in my sight.");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -120,6 +124,7 @@ bool AttackAction::Attack(Unit* target, bool with_pet /*true*/)
|
||||
{
|
||||
if (verbose)
|
||||
botAI->TellError("I am already attacking " + std::string(target->GetName()) + ".");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -154,10 +159,9 @@ bool AttackAction::Attack(Unit* target, bool with_pet /*true*/)
|
||||
bot->StopMoving();
|
||||
}
|
||||
|
||||
if (IsMovingAllowed() && !bot->HasInArc(CAST_ANGLE_IN_FRONT, target))
|
||||
{
|
||||
sServerFacade->SetFacingTo(bot, target);
|
||||
}
|
||||
if (botAI->CanMove() && !bot->HasInArc(CAST_ANGLE_IN_FRONT, target))
|
||||
ServerFacade::instance().SetFacingTo(bot, target);
|
||||
|
||||
botAI->ChangeEngine(BOT_STATE_COMBAT);
|
||||
|
||||
bot->Attack(target, shouldMelee);
|
||||
@@ -187,4 +191,4 @@ bool AttackAction::Attack(Unit* target, bool with_pet /*true*/)
|
||||
|
||||
bool AttackDuelOpponentAction::isUseful() { return AI_VALUE(Unit*, "duel target"); }
|
||||
|
||||
bool AttackDuelOpponentAction::Execute(Event event) { return Attack(AI_VALUE(Unit*, "duel target")); }
|
||||
bool AttackDuelOpponentAction::Execute(Event /*event*/) { return Attack(AI_VALUE(Unit*, "duel target")); }
|
||||
@@ -19,7 +19,7 @@ bool AutoMaintenanceOnLevelupAction::Execute(Event event)
|
||||
|
||||
void AutoMaintenanceOnLevelupAction::AutoTeleportForLevel()
|
||||
{
|
||||
if (!sPlayerbotAIConfig->autoTeleportForLevel || !sRandomPlayerbotMgr->IsRandomBot(bot))
|
||||
if (!sPlayerbotAIConfig.autoTeleportForLevel || !sRandomPlayerbotMgr.IsRandomBot(bot))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -27,13 +27,13 @@ void AutoMaintenanceOnLevelupAction::AutoTeleportForLevel()
|
||||
{
|
||||
return;
|
||||
}
|
||||
sRandomPlayerbotMgr->RandomTeleportForLevel(bot);
|
||||
sRandomPlayerbotMgr.RandomTeleportForLevel(bot);
|
||||
return;
|
||||
}
|
||||
|
||||
void AutoMaintenanceOnLevelupAction::AutoPickTalents()
|
||||
{
|
||||
if (!sPlayerbotAIConfig->autoPickTalents || !sRandomPlayerbotMgr->IsRandomBot(bot))
|
||||
if (!sPlayerbotAIConfig.autoPickTalents || !sRandomPlayerbotMgr.IsRandomBot(bot))
|
||||
return;
|
||||
|
||||
if (bot->GetFreeTalentPoints() <= 0)
|
||||
@@ -65,46 +65,89 @@ void AutoMaintenanceOnLevelupAction::AutoLearnSpell()
|
||||
void AutoMaintenanceOnLevelupAction::LearnSpells(std::ostringstream* out)
|
||||
{
|
||||
BroadcastHelper::BroadcastLevelup(botAI, bot);
|
||||
if (sPlayerbotAIConfig->autoLearnTrainerSpells && sRandomPlayerbotMgr->IsRandomBot(bot))
|
||||
if (sPlayerbotAIConfig.autoLearnTrainerSpells && sRandomPlayerbotMgr.IsRandomBot(bot))
|
||||
LearnTrainerSpells(out);
|
||||
|
||||
if (sPlayerbotAIConfig->autoLearnQuestSpells && sRandomPlayerbotMgr->IsRandomBot(bot))
|
||||
if (sPlayerbotAIConfig.autoLearnQuestSpells && sRandomPlayerbotMgr.IsRandomBot(bot))
|
||||
LearnQuestSpells(out);
|
||||
}
|
||||
|
||||
void AutoMaintenanceOnLevelupAction::LearnTrainerSpells(std::ostringstream* out)
|
||||
{
|
||||
PlayerbotFactory factory(bot, bot->GetLevel());
|
||||
factory.InitSkills();
|
||||
factory.InitClassSpells();
|
||||
factory.InitAvailableSpells();
|
||||
factory.InitSkills();
|
||||
factory.InitPet();
|
||||
}
|
||||
|
||||
void AutoMaintenanceOnLevelupAction::LearnQuestSpells(std::ostringstream* out)
|
||||
{
|
||||
// CreatureTemplate const* co = sCreatureStorage.LookupEntry<CreatureTemplate>(id);
|
||||
ObjectMgr::QuestMap const& questTemplates = sObjectMgr->GetQuestTemplates();
|
||||
for (ObjectMgr::QuestMap::const_iterator i = questTemplates.begin(); i != questTemplates.end(); ++i)
|
||||
{
|
||||
//uint32 questId = i->first; //not used, line marked for removal.
|
||||
Quest const* quest = i->second;
|
||||
|
||||
if (!quest->GetRequiredClasses() || quest->IsRepeatable() || quest->GetMinLevel() < 10)
|
||||
// only process class-specific quests to learn class-related spells, cuz
|
||||
// we don't want all these bunch of entries to be handled!
|
||||
if (!quest->GetRequiredClasses())
|
||||
continue;
|
||||
|
||||
if (!bot->SatisfyQuestClass(quest, false) || quest->GetMinLevel() > bot->GetLevel() ||
|
||||
!bot->SatisfyQuestRace(quest, false))
|
||||
// skip quests that are repeatable, too low level, or above bots' level
|
||||
if (quest->IsRepeatable() || quest->GetMinLevel() < 10 || quest->GetMinLevel() > bot->GetLevel())
|
||||
continue;
|
||||
|
||||
if (quest->GetRewSpellCast() > 0)
|
||||
// skip if bot doesnt satisfy class, race, or skill requirements
|
||||
if (!bot->SatisfyQuestClass(quest, false) || !bot->SatisfyQuestRace(quest, false) ||
|
||||
!bot->SatisfyQuestSkill(quest, false))
|
||||
continue;
|
||||
|
||||
// use the same logic and impl from Player::learnQuestRewardedSpells
|
||||
|
||||
int32 spellId = quest->GetRewSpellCast();
|
||||
if (!spellId)
|
||||
continue;
|
||||
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
|
||||
if (!spellInfo)
|
||||
continue;
|
||||
|
||||
// xinef: find effect with learn spell and check if we have this spell
|
||||
bool found = false;
|
||||
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
|
||||
{
|
||||
LearnSpell(quest->GetRewSpellCast(), out);
|
||||
if (spellInfo->Effects[i].Effect == SPELL_EFFECT_LEARN_SPELL && spellInfo->Effects[i].TriggerSpell &&
|
||||
!bot->HasSpell(spellInfo->Effects[i].TriggerSpell))
|
||||
{
|
||||
// pusywizard: don't re-add profession specialties!
|
||||
if (SpellInfo const* triggeredInfo = sSpellMgr->GetSpellInfo(spellInfo->Effects[i].TriggerSpell))
|
||||
if (triggeredInfo->Effects[0].Effect == SPELL_EFFECT_TRADE_SKILL)
|
||||
break; // pussywizard: break and not cast the spell (found is false)
|
||||
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (quest->GetRewSpell() > 0)
|
||||
|
||||
// xinef: we know the spell, continue
|
||||
if (!found)
|
||||
continue;
|
||||
|
||||
bot->CastSpell(bot, spellId, true);
|
||||
|
||||
// Check if RewardDisplaySpell is set to output the proper spell learned
|
||||
// after processing quests. Output the original RewardSpell otherwise.
|
||||
uint32 rewSpellId = quest->GetRewSpell();
|
||||
if (rewSpellId)
|
||||
{
|
||||
LearnSpell(quest->GetRewSpell(), out);
|
||||
if (SpellInfo const* rewSpellInfo = sSpellMgr->GetSpellInfo(rewSpellId))
|
||||
{
|
||||
*out << FormatSpell(rewSpellInfo) << ", ";
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
*out << FormatSpell(spellInfo) << ", ";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,42 +164,9 @@ std::string const AutoMaintenanceOnLevelupAction::FormatSpell(SpellInfo const* s
|
||||
return out.str();
|
||||
}
|
||||
|
||||
void AutoMaintenanceOnLevelupAction::LearnSpell(uint32 spellId, std::ostringstream* out)
|
||||
{
|
||||
SpellInfo const* proto = sSpellMgr->GetSpellInfo(spellId);
|
||||
if (!proto)
|
||||
return;
|
||||
|
||||
bool learned = false;
|
||||
for (uint8 j = 0; j < 3; ++j)
|
||||
{
|
||||
if (proto->Effects[j].Effect == SPELL_EFFECT_LEARN_SPELL)
|
||||
{
|
||||
uint32 learnedSpell = proto->Effects[j].TriggerSpell;
|
||||
|
||||
if (!bot->HasSpell(learnedSpell))
|
||||
{
|
||||
bot->learnSpell(learnedSpell);
|
||||
*out << FormatSpell(sSpellMgr->GetSpellInfo(learnedSpell)) << ", ";
|
||||
}
|
||||
|
||||
learned = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!learned)
|
||||
{
|
||||
if (!bot->HasSpell(spellId))
|
||||
{
|
||||
bot->learnSpell(spellId);
|
||||
*out << FormatSpell(proto) << ", ";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AutoMaintenanceOnLevelupAction::AutoUpgradeEquip()
|
||||
{
|
||||
if (!sPlayerbotAIConfig->autoUpgradeEquip || !sRandomPlayerbotMgr->IsRandomBot(bot))
|
||||
if (!sPlayerbotAIConfig.autoUpgradeEquip || !sRandomPlayerbotMgr.IsRandomBot(bot))
|
||||
return;
|
||||
|
||||
PlayerbotFactory factory(bot, bot->GetLevel());
|
||||
@@ -170,9 +180,9 @@ void AutoMaintenanceOnLevelupAction::AutoUpgradeEquip()
|
||||
factory.InitConsumables();
|
||||
factory.InitPotions();
|
||||
|
||||
if (!sPlayerbotAIConfig->equipmentPersistence || bot->GetLevel() < sPlayerbotAIConfig->equipmentPersistenceLevel)
|
||||
if (!sPlayerbotAIConfig.equipmentPersistence || bot->GetLevel() < sPlayerbotAIConfig.equipmentPersistenceLevel)
|
||||
{
|
||||
if (sPlayerbotAIConfig->incrementalGearInit)
|
||||
if (sPlayerbotAIConfig.incrementalGearInit)
|
||||
factory.InitEquipment(true);
|
||||
}
|
||||
}
|
||||
@@ -28,7 +28,6 @@ protected:
|
||||
void LearnSpells(std::ostringstream* out);
|
||||
void LearnTrainerSpells(std::ostringstream* out);
|
||||
void LearnQuestSpells(std::ostringstream* out);
|
||||
void LearnSpell(uint32 spellId, std::ostringstream* out);
|
||||
std::string const FormatSpell(SpellInfo const* sInfo);
|
||||
};
|
||||
|
||||
@@ -89,7 +89,7 @@ bool BGJoinAction::gatherArenaTeam(ArenaType type)
|
||||
// continue;
|
||||
|
||||
if (offline)
|
||||
sRandomPlayerbotMgr->AddPlayerBot(itr->Guid, 0);
|
||||
sRandomPlayerbotMgr.AddPlayerBot(itr->Guid, 0);
|
||||
|
||||
if (member)
|
||||
{
|
||||
@@ -100,7 +100,7 @@ bool BGJoinAction::gatherArenaTeam(ArenaType type)
|
||||
if (member->GetGroup() && memberBotAI->HasRealPlayerMaster())
|
||||
continue;
|
||||
|
||||
if (!sPlayerbotAIConfig->IsInRandomAccountList(member->GetSession()->GetAccountId()))
|
||||
if (!sPlayerbotAIConfig.IsInRandomAccountList(member->GetSession()->GetAccountId()))
|
||||
continue;
|
||||
|
||||
if (member->IsInCombat())
|
||||
@@ -250,13 +250,13 @@ bool BGJoinAction::shouldJoinBg(BattlegroundQueueTypeId queueTypeId, Battlegroun
|
||||
TeamSize = (uint32)type;
|
||||
|
||||
// Check if bots should join Rated Arena (Only captains can queue)
|
||||
uint32 ratedArenaBotCount = sRandomPlayerbotMgr->BattlegroundData[queueTypeId][bracketId].ratedArenaBotCount;
|
||||
uint32 ratedArenaBotCount = sRandomPlayerbotMgr.BattlegroundData[queueTypeId][bracketId].ratedArenaBotCount;
|
||||
uint32 ratedArenaPlayerCount =
|
||||
sRandomPlayerbotMgr->BattlegroundData[queueTypeId][bracketId].ratedArenaPlayerCount;
|
||||
sRandomPlayerbotMgr.BattlegroundData[queueTypeId][bracketId].ratedArenaPlayerCount;
|
||||
uint32 ratedArenaInstanceCount =
|
||||
sRandomPlayerbotMgr->BattlegroundData[queueTypeId][bracketId].ratedArenaInstanceCount;
|
||||
sRandomPlayerbotMgr.BattlegroundData[queueTypeId][bracketId].ratedArenaInstanceCount;
|
||||
uint32 activeRatedArenaQueue =
|
||||
sRandomPlayerbotMgr->BattlegroundData[queueTypeId][bracketId].activeRatedArenaQueue;
|
||||
sRandomPlayerbotMgr.BattlegroundData[queueTypeId][bracketId].activeRatedArenaQueue;
|
||||
|
||||
bool isRated = (ratedArenaBotCount + ratedArenaPlayerCount) <
|
||||
(BracketSize * (activeRatedArenaQueue + ratedArenaInstanceCount));
|
||||
@@ -265,7 +265,7 @@ bool BGJoinAction::shouldJoinBg(BattlegroundQueueTypeId queueTypeId, Battlegroun
|
||||
{
|
||||
if (sArenaTeamMgr->GetArenaTeamByCaptain(bot->GetGUID(), type))
|
||||
{
|
||||
sRandomPlayerbotMgr->BattlegroundData[queueTypeId][bracketId].ratedArenaBotCount += TeamSize;
|
||||
sRandomPlayerbotMgr.BattlegroundData[queueTypeId][bracketId].ratedArenaBotCount += TeamSize;
|
||||
ratedList.push_back(queueTypeId);
|
||||
return true;
|
||||
}
|
||||
@@ -274,13 +274,13 @@ bool BGJoinAction::shouldJoinBg(BattlegroundQueueTypeId queueTypeId, Battlegroun
|
||||
// Check if bots should join Skirmish Arena
|
||||
// We have extra bots queue because same faction can vs each other but can't be in the same group.
|
||||
uint32 skirmishArenaBotCount =
|
||||
sRandomPlayerbotMgr->BattlegroundData[queueTypeId][bracketId].skirmishArenaBotCount;
|
||||
sRandomPlayerbotMgr.BattlegroundData[queueTypeId][bracketId].skirmishArenaBotCount;
|
||||
uint32 skirmishArenaPlayerCount =
|
||||
sRandomPlayerbotMgr->BattlegroundData[queueTypeId][bracketId].skirmishArenaPlayerCount;
|
||||
sRandomPlayerbotMgr.BattlegroundData[queueTypeId][bracketId].skirmishArenaPlayerCount;
|
||||
uint32 skirmishArenaInstanceCount =
|
||||
sRandomPlayerbotMgr->BattlegroundData[queueTypeId][bracketId].skirmishArenaInstanceCount;
|
||||
sRandomPlayerbotMgr.BattlegroundData[queueTypeId][bracketId].skirmishArenaInstanceCount;
|
||||
uint32 activeSkirmishArenaQueue =
|
||||
sRandomPlayerbotMgr->BattlegroundData[queueTypeId][bracketId].activeSkirmishArenaQueue;
|
||||
sRandomPlayerbotMgr.BattlegroundData[queueTypeId][bracketId].activeSkirmishArenaQueue;
|
||||
uint32 maxRequiredSkirmishBots = BracketSize * (activeSkirmishArenaQueue + skirmishArenaInstanceCount);
|
||||
if (maxRequiredSkirmishBots != 0)
|
||||
maxRequiredSkirmishBots = maxRequiredSkirmishBots + TeamSize;
|
||||
@@ -294,12 +294,12 @@ bool BGJoinAction::shouldJoinBg(BattlegroundQueueTypeId queueTypeId, Battlegroun
|
||||
}
|
||||
|
||||
// Check if bots should join Battleground
|
||||
uint32 bgAllianceBotCount = sRandomPlayerbotMgr->BattlegroundData[queueTypeId][bracketId].bgAllianceBotCount;
|
||||
uint32 bgAlliancePlayerCount = sRandomPlayerbotMgr->BattlegroundData[queueTypeId][bracketId].bgAlliancePlayerCount;
|
||||
uint32 bgHordeBotCount = sRandomPlayerbotMgr->BattlegroundData[queueTypeId][bracketId].bgHordeBotCount;
|
||||
uint32 bgHordePlayerCount = sRandomPlayerbotMgr->BattlegroundData[queueTypeId][bracketId].bgHordePlayerCount;
|
||||
uint32 activeBgQueue = sRandomPlayerbotMgr->BattlegroundData[queueTypeId][bracketId].activeBgQueue;
|
||||
uint32 bgInstanceCount = sRandomPlayerbotMgr->BattlegroundData[queueTypeId][bracketId].bgInstanceCount;
|
||||
uint32 bgAllianceBotCount = sRandomPlayerbotMgr.BattlegroundData[queueTypeId][bracketId].bgAllianceBotCount;
|
||||
uint32 bgAlliancePlayerCount = sRandomPlayerbotMgr.BattlegroundData[queueTypeId][bracketId].bgAlliancePlayerCount;
|
||||
uint32 bgHordeBotCount = sRandomPlayerbotMgr.BattlegroundData[queueTypeId][bracketId].bgHordeBotCount;
|
||||
uint32 bgHordePlayerCount = sRandomPlayerbotMgr.BattlegroundData[queueTypeId][bracketId].bgHordePlayerCount;
|
||||
uint32 activeBgQueue = sRandomPlayerbotMgr.BattlegroundData[queueTypeId][bracketId].activeBgQueue;
|
||||
uint32 bgInstanceCount = sRandomPlayerbotMgr.BattlegroundData[queueTypeId][bracketId].bgInstanceCount;
|
||||
|
||||
if (teamId == TEAM_ALLIANCE)
|
||||
{
|
||||
@@ -318,7 +318,7 @@ bool BGJoinAction::shouldJoinBg(BattlegroundQueueTypeId queueTypeId, Battlegroun
|
||||
bool BGJoinAction::isUseful()
|
||||
{
|
||||
// do not try if BG bots disabled
|
||||
if (!sPlayerbotAIConfig->randomBotJoinBG)
|
||||
if (!sPlayerbotAIConfig.randomBotJoinBG)
|
||||
return false;
|
||||
|
||||
// can't queue while in BG/Arena
|
||||
@@ -440,7 +440,7 @@ bool BGJoinAction::JoinQueue(uint32 type)
|
||||
|
||||
// get battlemaster
|
||||
// Unit* unit = botAI->GetUnit(AI_VALUE2(CreatureData const*, "bg master", bgTypeId));
|
||||
Unit* unit = botAI->GetUnit(sRandomPlayerbotMgr->GetBattleMasterGUID(bot, bgTypeId));
|
||||
Unit* unit = botAI->GetUnit(sRandomPlayerbotMgr.GetBattleMasterGUID(bot, bgTypeId));
|
||||
if (!unit && isArena)
|
||||
{
|
||||
botAI->GetAiObjectContext()->GetValue<uint32>("bg type")->Set(0);
|
||||
@@ -450,7 +450,7 @@ bool BGJoinAction::JoinQueue(uint32 type)
|
||||
|
||||
// This breaks groups as refresh includes a remove from group function call.
|
||||
// refresh food/regs
|
||||
// sRandomPlayerbotMgr->Refresh(bot);
|
||||
// sRandomPlayerbotMgr.Refresh(bot);
|
||||
|
||||
bool joinAsGroup = bot->GetGroup() && bot->GetGroup()->GetLeaderGUID() == bot->GetGUID();
|
||||
|
||||
@@ -523,23 +523,23 @@ bool BGJoinAction::JoinQueue(uint32 type)
|
||||
{
|
||||
if (!isRated)
|
||||
{
|
||||
sRandomPlayerbotMgr->BattlegroundData[queueTypeId][bracketId].skirmishArenaBotCount++;
|
||||
sRandomPlayerbotMgr.BattlegroundData[queueTypeId][bracketId].skirmishArenaBotCount++;
|
||||
}
|
||||
}
|
||||
else if (!joinAsGroup)
|
||||
{
|
||||
if (teamId == TEAM_ALLIANCE)
|
||||
sRandomPlayerbotMgr->BattlegroundData[queueTypeId][bracketId].bgAllianceBotCount++;
|
||||
sRandomPlayerbotMgr.BattlegroundData[queueTypeId][bracketId].bgAllianceBotCount++;
|
||||
else
|
||||
sRandomPlayerbotMgr->BattlegroundData[queueTypeId][bracketId].bgHordeBotCount++;
|
||||
sRandomPlayerbotMgr.BattlegroundData[queueTypeId][bracketId].bgHordeBotCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (teamId == TEAM_ALLIANCE)
|
||||
sRandomPlayerbotMgr->BattlegroundData[queueTypeId][bracketId].bgAllianceBotCount +=
|
||||
sRandomPlayerbotMgr.BattlegroundData[queueTypeId][bracketId].bgAllianceBotCount +=
|
||||
bot->GetGroup()->GetMembersCount();
|
||||
else
|
||||
sRandomPlayerbotMgr->BattlegroundData[queueTypeId][bracketId].bgHordeBotCount +=
|
||||
sRandomPlayerbotMgr.BattlegroundData[queueTypeId][bracketId].bgHordeBotCount +=
|
||||
bot->GetGroup()->GetMembersCount();
|
||||
}
|
||||
|
||||
@@ -588,13 +588,13 @@ bool FreeBGJoinAction::shouldJoinBg(BattlegroundQueueTypeId queueTypeId, Battleg
|
||||
TeamSize = (uint32)type;
|
||||
|
||||
// Check if bots should join Rated Arena (Only captains can queue)
|
||||
uint32 ratedArenaBotCount = sRandomPlayerbotMgr->BattlegroundData[queueTypeId][bracketId].ratedArenaBotCount;
|
||||
uint32 ratedArenaBotCount = sRandomPlayerbotMgr.BattlegroundData[queueTypeId][bracketId].ratedArenaBotCount;
|
||||
uint32 ratedArenaPlayerCount =
|
||||
sRandomPlayerbotMgr->BattlegroundData[queueTypeId][bracketId].ratedArenaPlayerCount;
|
||||
sRandomPlayerbotMgr.BattlegroundData[queueTypeId][bracketId].ratedArenaPlayerCount;
|
||||
uint32 ratedArenaInstanceCount =
|
||||
sRandomPlayerbotMgr->BattlegroundData[queueTypeId][bracketId].ratedArenaInstanceCount;
|
||||
sRandomPlayerbotMgr.BattlegroundData[queueTypeId][bracketId].ratedArenaInstanceCount;
|
||||
uint32 activeRatedArenaQueue =
|
||||
sRandomPlayerbotMgr->BattlegroundData[queueTypeId][bracketId].activeRatedArenaQueue;
|
||||
sRandomPlayerbotMgr.BattlegroundData[queueTypeId][bracketId].activeRatedArenaQueue;
|
||||
|
||||
bool isRated = (ratedArenaBotCount + ratedArenaPlayerCount) <
|
||||
(BracketSize * (activeRatedArenaQueue + ratedArenaInstanceCount));
|
||||
@@ -603,7 +603,7 @@ bool FreeBGJoinAction::shouldJoinBg(BattlegroundQueueTypeId queueTypeId, Battleg
|
||||
{
|
||||
if (sArenaTeamMgr->GetArenaTeamByCaptain(bot->GetGUID(), type))
|
||||
{
|
||||
sRandomPlayerbotMgr->BattlegroundData[queueTypeId][bracketId].ratedArenaBotCount += TeamSize;
|
||||
sRandomPlayerbotMgr.BattlegroundData[queueTypeId][bracketId].ratedArenaBotCount += TeamSize;
|
||||
ratedList.push_back(queueTypeId);
|
||||
return true;
|
||||
}
|
||||
@@ -612,13 +612,13 @@ bool FreeBGJoinAction::shouldJoinBg(BattlegroundQueueTypeId queueTypeId, Battleg
|
||||
// Check if bots should join Skirmish Arena
|
||||
// We have extra bots queue because same faction can vs each other but can't be in the same group.
|
||||
uint32 skirmishArenaBotCount =
|
||||
sRandomPlayerbotMgr->BattlegroundData[queueTypeId][bracketId].skirmishArenaBotCount;
|
||||
sRandomPlayerbotMgr.BattlegroundData[queueTypeId][bracketId].skirmishArenaBotCount;
|
||||
uint32 skirmishArenaPlayerCount =
|
||||
sRandomPlayerbotMgr->BattlegroundData[queueTypeId][bracketId].skirmishArenaPlayerCount;
|
||||
sRandomPlayerbotMgr.BattlegroundData[queueTypeId][bracketId].skirmishArenaPlayerCount;
|
||||
uint32 skirmishArenaInstanceCount =
|
||||
sRandomPlayerbotMgr->BattlegroundData[queueTypeId][bracketId].skirmishArenaInstanceCount;
|
||||
sRandomPlayerbotMgr.BattlegroundData[queueTypeId][bracketId].skirmishArenaInstanceCount;
|
||||
uint32 activeSkirmishArenaQueue =
|
||||
sRandomPlayerbotMgr->BattlegroundData[queueTypeId][bracketId].activeSkirmishArenaQueue;
|
||||
sRandomPlayerbotMgr.BattlegroundData[queueTypeId][bracketId].activeSkirmishArenaQueue;
|
||||
uint32 maxRequiredSkirmishBots = BracketSize * (activeSkirmishArenaQueue + skirmishArenaInstanceCount);
|
||||
if (maxRequiredSkirmishBots != 0)
|
||||
maxRequiredSkirmishBots = maxRequiredSkirmishBots + TeamSize;
|
||||
@@ -632,12 +632,12 @@ bool FreeBGJoinAction::shouldJoinBg(BattlegroundQueueTypeId queueTypeId, Battleg
|
||||
}
|
||||
|
||||
// Check if bots should join Battleground
|
||||
uint32 bgAllianceBotCount = sRandomPlayerbotMgr->BattlegroundData[queueTypeId][bracketId].bgAllianceBotCount;
|
||||
uint32 bgAlliancePlayerCount = sRandomPlayerbotMgr->BattlegroundData[queueTypeId][bracketId].bgAlliancePlayerCount;
|
||||
uint32 bgHordeBotCount = sRandomPlayerbotMgr->BattlegroundData[queueTypeId][bracketId].bgHordeBotCount;
|
||||
uint32 bgHordePlayerCount = sRandomPlayerbotMgr->BattlegroundData[queueTypeId][bracketId].bgHordePlayerCount;
|
||||
uint32 activeBgQueue = sRandomPlayerbotMgr->BattlegroundData[queueTypeId][bracketId].activeBgQueue;
|
||||
uint32 bgInstanceCount = sRandomPlayerbotMgr->BattlegroundData[queueTypeId][bracketId].bgInstanceCount;
|
||||
uint32 bgAllianceBotCount = sRandomPlayerbotMgr.BattlegroundData[queueTypeId][bracketId].bgAllianceBotCount;
|
||||
uint32 bgAlliancePlayerCount = sRandomPlayerbotMgr.BattlegroundData[queueTypeId][bracketId].bgAlliancePlayerCount;
|
||||
uint32 bgHordeBotCount = sRandomPlayerbotMgr.BattlegroundData[queueTypeId][bracketId].bgHordeBotCount;
|
||||
uint32 bgHordePlayerCount = sRandomPlayerbotMgr.BattlegroundData[queueTypeId][bracketId].bgHordePlayerCount;
|
||||
uint32 activeBgQueue = sRandomPlayerbotMgr.BattlegroundData[queueTypeId][bracketId].activeBgQueue;
|
||||
uint32 bgInstanceCount = sRandomPlayerbotMgr.BattlegroundData[queueTypeId][bracketId].bgInstanceCount;
|
||||
|
||||
if (teamId == TEAM_ALLIANCE)
|
||||
{
|
||||
@@ -670,7 +670,7 @@ bool BGLeaveAction::Execute(Event event)
|
||||
uint16 unk = 0x1F90;
|
||||
uint8 unk2 = 0x0;
|
||||
bool isArena = false;
|
||||
bool IsRandomBot = sRandomPlayerbotMgr->IsRandomBot(bot);
|
||||
bool IsRandomBot = sRandomPlayerbotMgr.IsRandomBot(bot);
|
||||
|
||||
ArenaType arenaType = ArenaType(BattlegroundMgr::BGArenaType(queueTypeId));
|
||||
if (arenaType)
|
||||
@@ -709,7 +709,7 @@ bool BGStatusAction::LeaveBG(PlayerbotAI* botAI)
|
||||
if (!bg)
|
||||
return false;
|
||||
bool isArena = bg->isArena();
|
||||
bool isRandomBot = sRandomPlayerbotMgr->IsRandomBot(bot);
|
||||
bool isRandomBot = sRandomPlayerbotMgr.IsRandomBot(bot);
|
||||
|
||||
if (isRandomBot)
|
||||
botAI->SetMaster(nullptr);
|
||||
@@ -805,7 +805,7 @@ bool BGStatusAction::Execute(Event event)
|
||||
break;
|
||||
}
|
||||
|
||||
bool IsRandomBot = sRandomPlayerbotMgr->IsRandomBot(bot);
|
||||
bool IsRandomBot = sRandomPlayerbotMgr.IsRandomBot(bot);
|
||||
BattlegroundQueueTypeId queueTypeId = bot->GetBattlegroundQueueTypeId(QueueSlot);
|
||||
BattlegroundTypeId _bgTypeId = BattlegroundMgr::BGTemplateId(queueTypeId);
|
||||
if (!queueTypeId)
|
||||
@@ -958,10 +958,10 @@ bool BGStatusAction::Execute(Event event)
|
||||
//TeamId teamId = bot->GetTeamId(); //not used, line marked for removal.
|
||||
bool realPlayers = false;
|
||||
if (isRated)
|
||||
realPlayers = sRandomPlayerbotMgr->BattlegroundData[queueTypeId][bracketId].ratedArenaPlayerCount > 0;
|
||||
realPlayers = sRandomPlayerbotMgr.BattlegroundData[queueTypeId][bracketId].ratedArenaPlayerCount > 0;
|
||||
else
|
||||
realPlayers =
|
||||
sRandomPlayerbotMgr->BattlegroundData[queueTypeId][bracketId].skirmishArenaPlayerCount > 0;
|
||||
sRandomPlayerbotMgr.BattlegroundData[queueTypeId][bracketId].skirmishArenaPlayerCount > 0;
|
||||
|
||||
if (realPlayers)
|
||||
return false;
|
||||
@@ -1276,7 +1276,7 @@ static std::pair<uint32, uint32> IC_AttackObjectives[] = {
|
||||
// useful commands for fixing BG bugs and checking waypoints/paths
|
||||
bool BGTactics::HandleConsoleCommand(ChatHandler* handler, char const* args)
|
||||
{
|
||||
if (!sPlayerbotAIConfig->enabled)
|
||||
if (!sPlayerbotAIConfig.enabled)
|
||||
{
|
||||
handler->PSendSysMessage("|cffff0000Playerbot system is currently disabled!");
|
||||
return true;
|
||||
@@ -2219,7 +2219,7 @@ bool BGTactics::selectObjective(bool reset)
|
||||
if (urand(0, 99) < 20 && teamFC)
|
||||
{
|
||||
target.Relocate(teamFC->GetPositionX(), teamFC->GetPositionY(), teamFC->GetPositionZ());
|
||||
if (sServerFacade->GetDistance2d(bot, teamFC) < 33.0f)
|
||||
if (ServerFacade::instance().GetDistance2d(bot, teamFC) < 33.0f)
|
||||
Follow(teamFC);
|
||||
}
|
||||
else
|
||||
@@ -2227,8 +2227,8 @@ bool BGTactics::selectObjective(bool reset)
|
||||
}
|
||||
// Graveyard Camping if in lead
|
||||
else if (!hasFlag && role < 8 &&
|
||||
(team == TEAM_ALLIANCE && allianceScore == 2 && hordeScore == 0) ||
|
||||
(team == TEAM_HORDE && hordeScore == 2 && allianceScore == 0))
|
||||
((team == TEAM_ALLIANCE && allianceScore == 2 && hordeScore == 0) ||
|
||||
(team == TEAM_HORDE && hordeScore == 2 && allianceScore == 0)))
|
||||
{
|
||||
if (team == TEAM_ALLIANCE)
|
||||
SetSafePos(WS_GY_CAMPING_HORDE, 10.0f);
|
||||
@@ -2263,7 +2263,7 @@ bool BGTactics::selectObjective(bool reset)
|
||||
if (urand(0, 99) < 70)
|
||||
{
|
||||
target.Relocate(teamFC->GetPositionX(), teamFC->GetPositionY(), teamFC->GetPositionZ());
|
||||
if (sServerFacade->GetDistance2d(bot, teamFC) < 33.0f)
|
||||
if (ServerFacade::instance().GetDistance2d(bot, teamFC) < 33.0f)
|
||||
Follow(teamFC);
|
||||
}
|
||||
}
|
||||
@@ -2284,7 +2284,7 @@ bool BGTactics::selectObjective(bool reset)
|
||||
{
|
||||
// Assist own FC if not pursuing enemy FC
|
||||
target.Relocate(teamFC->GetPositionX(), teamFC->GetPositionY(), teamFC->GetPositionZ());
|
||||
if (sServerFacade->GetDistance2d(bot, teamFC) < 33.0f)
|
||||
if (ServerFacade::instance().GetDistance2d(bot, teamFC) < 33.0f)
|
||||
Follow(teamFC);
|
||||
}
|
||||
else if (urand(0, 99) < 5)
|
||||
@@ -3197,11 +3197,11 @@ bool BGTactics::moveToObjective(bool ignoreDist)
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!ignoreDist && sServerFacade->IsDistanceGreaterThan(sServerFacade->GetDistance2d(bot, pos.x, pos.y), 100.0f))
|
||||
if (!ignoreDist && ServerFacade::instance().IsDistanceGreaterThan(ServerFacade::instance().GetDistance2d(bot, pos.x, pos.y), 100.0f))
|
||||
{
|
||||
// std::ostringstream out;
|
||||
// out << "It is too far away! " << pos.x << ", " << pos.y << ", Distance: " <<
|
||||
// sServerFacade->GetDistance2d(bot, pos.x, pos.y); bot->Say(out.str(), LANG_UNIVERSAL);
|
||||
// ServerFacade::instance().GetDistance2d(bot, pos.x, pos.y); bot->Say(out.str(), LANG_UNIVERSAL);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -3213,7 +3213,7 @@ bool BGTactics::moveToObjective(bool ignoreDist)
|
||||
}
|
||||
|
||||
// std::ostringstream out; out << "Moving to objective " << pos.x << ", " << pos.y << ", Distance: " <<
|
||||
// sServerFacade->GetDistance2d(bot, pos.x, pos.y); bot->Say(out.str(), LANG_UNIVERSAL);
|
||||
// ServerFacade::instance().GetDistance2d(bot, pos.x, pos.y); bot->Say(out.str(), LANG_UNIVERSAL);
|
||||
|
||||
// dont increase from 1.5 will cause bugs with horde capping AV towers
|
||||
return MoveNear(bot->GetMapId(), pos.x, pos.y, pos.z, 1.5f);
|
||||
@@ -3433,7 +3433,7 @@ bool BGTactics::moveToObjectiveWp(BattleBotPath* const& currentPath, uint32 curr
|
||||
// out << "WP: ";
|
||||
// reverse ? out << currPoint << " <<< -> " << nPoint : out << currPoint << ">>> ->" << nPoint;
|
||||
// out << ", " << nextPoint.x << ", " << nextPoint.y << " Path Size: " << currentPath->size() << ", Dist: " <<
|
||||
// sServerFacade->GetDistance2d(bot, nextPoint.x, nextPoint.y); bot->Say(out.str(), LANG_UNIVERSAL);
|
||||
// ServerFacade::instance().GetDistance2d(bot, nextPoint.x, nextPoint.y); bot->Say(out.str(), LANG_UNIVERSAL);
|
||||
|
||||
return MoveTo(bot->GetMapId(), nextPoint.x + frand(-2, 2), nextPoint.y + frand(-2, 2), nextPoint.z);
|
||||
}
|
||||
@@ -4039,9 +4039,9 @@ bool BGTactics::useBuff()
|
||||
if (closeObjects.empty())
|
||||
return false;
|
||||
|
||||
bool needRegen = bot->GetHealthPct() < sPlayerbotAIConfig->mediumHealth ||
|
||||
bool needRegen = bot->GetHealthPct() < sPlayerbotAIConfig.mediumHealth ||
|
||||
(AI_VALUE2(bool, "has mana", "self target") &&
|
||||
AI_VALUE2(uint8, "mana", "self target") < sPlayerbotAIConfig->mediumMana);
|
||||
AI_VALUE2(uint8, "mana", "self target") < sPlayerbotAIConfig.mediumMana);
|
||||
bool needSpeed = (bgType != BATTLEGROUND_WS || bot->HasAura(BG_WS_SPELL_WARSONG_FLAG) ||
|
||||
bot->HasAura(BG_WS_SPELL_SILVERWING_FLAG) || bot->HasAura(BG_EY_NETHERSTORM_FLAG_SPELL)) ||
|
||||
!(teamFlagTaken() || flagTaken());
|
||||
@@ -4057,7 +4057,7 @@ bool BGTactics::useBuff()
|
||||
continue;
|
||||
|
||||
// use speed buff only if close
|
||||
if (sServerFacade->IsDistanceGreaterThan(sServerFacade->GetDistance2d(bot, go),
|
||||
if (ServerFacade::instance().IsDistanceGreaterThan(ServerFacade::instance().GetDistance2d(bot, go),
|
||||
go->GetEntry() == Buff_Entries[0] ? 20.0f : 50.0f))
|
||||
continue;
|
||||
|
||||
@@ -4107,7 +4107,7 @@ uint32 BGTactics::getPlayersInArea(TeamId teamId, Position point, float range, b
|
||||
if (!combat && player->IsInCombat())
|
||||
continue;
|
||||
|
||||
if (sServerFacade->GetDistance2d(player, point.GetPositionX(), point.GetPositionY()) < range)
|
||||
if (ServerFacade::instance().GetDistance2d(player, point.GetPositionX(), point.GetPositionY()) < range)
|
||||
++defCount;
|
||||
}
|
||||
}
|
||||
@@ -4191,9 +4191,9 @@ bool BGTactics::IsLockedInsideKeep()
|
||||
// get closest portal
|
||||
if (bot->GetTeamId() == TEAM_ALLIANCE && go->GetEntry() == GO_TELEPORTER_4)
|
||||
{
|
||||
float tempDist = sServerFacade->GetDistance2d(bot, go->GetPositionX(), go->GetPositionY());
|
||||
float tempDist = ServerFacade::instance().GetDistance2d(bot, go->GetPositionX(), go->GetPositionY());
|
||||
|
||||
if (sServerFacade->IsDistanceLessThan(tempDist, closestDistance))
|
||||
if (ServerFacade::instance().IsDistanceLessThan(tempDist, closestDistance))
|
||||
{
|
||||
closestDistance = tempDist;
|
||||
closestPortal = go;
|
||||
@@ -4204,9 +4204,9 @@ bool BGTactics::IsLockedInsideKeep()
|
||||
// get closest portal
|
||||
if (bot->GetTeamId() == TEAM_HORDE && go->GetEntry() == GO_TELEPORTER_2)
|
||||
{
|
||||
float tempDist = sServerFacade->GetDistance2d(bot, go->GetPositionX(), go->GetPositionY());
|
||||
float tempDist = ServerFacade::instance().GetDistance2d(bot, go->GetPositionX(), go->GetPositionY());
|
||||
|
||||
if (sServerFacade->IsDistanceLessThan(tempDist, closestDistance))
|
||||
if (ServerFacade::instance().IsDistanceLessThan(tempDist, closestDistance))
|
||||
{
|
||||
closestDistance = tempDist;
|
||||
closestPortal = go;
|
||||
@@ -4253,7 +4253,7 @@ bool ArenaTactics::Execute(Event event)
|
||||
{
|
||||
if (!bot->InBattleground())
|
||||
{
|
||||
bool IsRandomBot = sRandomPlayerbotMgr->IsRandomBot(bot->GetGUID().GetCounter());
|
||||
bool IsRandomBot = sRandomPlayerbotMgr.IsRandomBot(bot->GetGUID().GetCounter());
|
||||
botAI->ChangeStrategy("-arena", BOT_STATE_COMBAT);
|
||||
botAI->ChangeStrategy("-arena", BOT_STATE_NON_COMBAT);
|
||||
botAI->ResetStrategies(!IsRandomBot);
|
||||
@@ -224,42 +224,36 @@ bool BuyAction::Execute(Event event)
|
||||
|
||||
bool BuyAction::BuyItem(VendorItemData const* tItems, ObjectGuid vendorguid, ItemTemplate const* proto)
|
||||
{
|
||||
uint32 oldCount = AI_VALUE2(uint32, "item count", proto->Name1);
|
||||
|
||||
if (!tItems)
|
||||
if (!tItems || !proto)
|
||||
return false;
|
||||
|
||||
uint32 itemId = proto->ItemId;
|
||||
for (uint32 slot = 0; slot < tItems->GetItemCount(); slot++)
|
||||
uint32 oldCount = bot->GetItemCount(itemId, false);
|
||||
|
||||
for (uint32 slot = 0; slot < tItems->GetItemCount(); ++slot)
|
||||
{
|
||||
if (tItems->GetItem(slot)->item == itemId)
|
||||
if (tItems->GetItem(slot)->item != itemId)
|
||||
continue;
|
||||
|
||||
uint32 botMoney = bot->GetMoney();
|
||||
if (botAI->HasCheat(BotCheatMask::gold))
|
||||
bot->SetMoney(10000000);
|
||||
|
||||
bot->BuyItemFromVendorSlot(vendorguid, slot, itemId, 1, NULL_BAG, NULL_SLOT);
|
||||
|
||||
if (botAI->HasCheat(BotCheatMask::gold))
|
||||
bot->SetMoney(botMoney);
|
||||
|
||||
uint32 newCount = bot->GetItemCount(itemId, false);
|
||||
if (newCount > oldCount)
|
||||
{
|
||||
uint32 botMoney = bot->GetMoney();
|
||||
if (botAI->HasCheat(BotCheatMask::gold))
|
||||
{
|
||||
bot->SetMoney(10000000);
|
||||
}
|
||||
|
||||
bot->BuyItemFromVendorSlot(vendorguid, slot, itemId, 1, NULL_BAG, NULL_SLOT);
|
||||
|
||||
if (botAI->HasCheat(BotCheatMask::gold))
|
||||
{
|
||||
bot->SetMoney(botMoney);
|
||||
}
|
||||
|
||||
if (oldCount <
|
||||
AI_VALUE2(
|
||||
uint32, "item count",
|
||||
proto->Name1)) // BuyItem Always returns false (unless unique) so we have to check the item counts.
|
||||
{
|
||||
std::ostringstream out;
|
||||
out << "Buying " << ChatHelper::FormatItem(proto);
|
||||
botAI->TellMaster(out.str());
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
std::ostringstream out;
|
||||
out << "Buying " << ChatHelper::FormatItem(proto);
|
||||
botAI->TellMaster(out.str());
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -130,10 +130,10 @@ bool CastCustomSpellAction::Execute(Event event)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (target != bot && !bot->HasInArc(CAST_ANGLE_IN_FRONT, target, sPlayerbotAIConfig->sightDistance))
|
||||
if (target != bot && !bot->HasInArc(CAST_ANGLE_IN_FRONT, target, sPlayerbotAIConfig.sightDistance))
|
||||
{
|
||||
sServerFacade->SetFacingTo(bot, target);
|
||||
botAI->SetNextCheckDelay(sPlayerbotAIConfig->reactDelay);
|
||||
ServerFacade::instance().SetFacingTo(bot, target);
|
||||
botAI->SetNextCheckDelay(sPlayerbotAIConfig.reactDelay);
|
||||
|
||||
msg << "cast " << text;
|
||||
botAI->HandleCommand(CHAT_MSG_WHISPER, msg.str(), master);
|
||||
@@ -286,7 +286,7 @@ bool CastRandomSpellAction::Execute(Event event)
|
||||
|
||||
if (isCast)
|
||||
{
|
||||
if (MultiCast && ((wo && bot->HasInArc(CAST_ANGLE_IN_FRONT, wo, sPlayerbotAIConfig->sightDistance))))
|
||||
if (MultiCast && ((wo && bot->HasInArc(CAST_ANGLE_IN_FRONT, wo, sPlayerbotAIConfig.sightDistance))))
|
||||
{
|
||||
std::ostringstream cmd;
|
||||
cmd << "castnc " << chat->FormatWorldobject(wo) + " " << spellId << " " << 19;
|
||||
@@ -6,7 +6,7 @@
|
||||
#include "ChangeStrategyAction.h"
|
||||
|
||||
#include "Event.h"
|
||||
#include "PlayerbotDbStore.h"
|
||||
#include "PlayerbotRepository.h"
|
||||
#include "Playerbots.h"
|
||||
|
||||
bool ChangeCombatStrategyAction::Execute(Event event)
|
||||
@@ -24,7 +24,7 @@ bool ChangeCombatStrategyAction::Execute(Event event)
|
||||
case '+':
|
||||
case '-':
|
||||
case '~':
|
||||
sPlayerbotDbStore->Save(botAI);
|
||||
PlayerbotRepository::instance().Save(botAI);
|
||||
break;
|
||||
case '?':
|
||||
break;
|
||||
@@ -40,7 +40,7 @@ bool ChangeNonCombatStrategyAction::Execute(Event event)
|
||||
std::string const text = event.getParam();
|
||||
|
||||
uint32 account = bot->GetSession()->GetAccountId();
|
||||
if (sPlayerbotAIConfig->IsInRandomAccountList(account) && botAI->GetMaster() &&
|
||||
if (sPlayerbotAIConfig.IsInRandomAccountList(account) && botAI->GetMaster() &&
|
||||
botAI->GetMaster()->GetSession()->GetSecurity() < SEC_GAMEMASTER)
|
||||
{
|
||||
if (text.find("loot") != std::string::npos || text.find("gather") != std::string::npos)
|
||||
@@ -62,7 +62,7 @@ bool ChangeNonCombatStrategyAction::Execute(Event event)
|
||||
case '+':
|
||||
case '-':
|
||||
case '~':
|
||||
sPlayerbotDbStore->Save(botAI);
|
||||
PlayerbotRepository::instance().Save(botAI);
|
||||
break;
|
||||
case '?':
|
||||
break;
|
||||
@@ -110,20 +110,20 @@ std::string ChangeTalentsAction::SpecList()
|
||||
std::ostringstream out;
|
||||
for (int specNo = 0; specNo < MAX_SPECNO; ++specNo)
|
||||
{
|
||||
if (sPlayerbotAIConfig->premadeSpecName[cls][specNo].size() == 0)
|
||||
if (sPlayerbotAIConfig.premadeSpecName[cls][specNo].size() == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
specFound++;
|
||||
std::ostringstream out;
|
||||
std::vector<std::vector<uint32>> parsed = sPlayerbotAIConfig->parsedSpecLinkOrder[cls][specNo][80];
|
||||
std::vector<std::vector<uint32>> parsed = sPlayerbotAIConfig.parsedSpecLinkOrder[cls][specNo][80];
|
||||
std::unordered_map<int, int> tabCount;
|
||||
tabCount[0] = tabCount[1] = tabCount[2] = 0;
|
||||
for (auto& item : parsed)
|
||||
{
|
||||
tabCount[item[0]] += item[3];
|
||||
}
|
||||
out << specFound << ". " << sPlayerbotAIConfig->premadeSpecName[cls][specNo] << " (";
|
||||
out << specFound << ". " << sPlayerbotAIConfig.premadeSpecName[cls][specNo] << " (";
|
||||
out << tabCount[0] << "-" << tabCount[1] << "-" << tabCount[2] << ")";
|
||||
botAI->TellMasterNoFacing(out.str());
|
||||
}
|
||||
@@ -137,11 +137,11 @@ std::string ChangeTalentsAction::SpecPick(std::string param)
|
||||
// int specFound = 0; //not used, line marked for removal.
|
||||
for (int specNo = 0; specNo < MAX_SPECNO; ++specNo)
|
||||
{
|
||||
if (sPlayerbotAIConfig->premadeSpecName[cls][specNo].size() == 0)
|
||||
if (sPlayerbotAIConfig.premadeSpecName[cls][specNo].size() == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (sPlayerbotAIConfig->premadeSpecName[cls][specNo] == param)
|
||||
if (sPlayerbotAIConfig.premadeSpecName[cls][specNo] == param)
|
||||
{
|
||||
PlayerbotFactory::InitTalentsBySpecNo(bot, specNo, true);
|
||||
|
||||
@@ -149,7 +149,7 @@ std::string ChangeTalentsAction::SpecPick(std::string param)
|
||||
factory.InitGlyphs(false);
|
||||
|
||||
std::ostringstream out;
|
||||
out << "Picking " << sPlayerbotAIConfig->premadeSpecName[cls][specNo];
|
||||
out << "Picking " << sPlayerbotAIConfig.premadeSpecName[cls][specNo];
|
||||
return out.str();
|
||||
}
|
||||
}
|
||||
@@ -176,7 +176,7 @@ std::string ChangeTalentsAction::SpecApply(std::string param)
|
||||
// std::vector<TalentPath*> ChangeTalentsAction::getPremadePaths(std::string const findName)
|
||||
// {
|
||||
// std::vector<TalentPath*> ret;
|
||||
// // for (auto& path : sPlayerbotAIConfig->classSpecs[bot->getClass()].talentPath)
|
||||
// // for (auto& path : sPlayerbotAIConfig.classSpecs[bot->getClass()].talentPath)
|
||||
// // {
|
||||
// // if (findName.empty() || path.name.find(findName) != std::string::npos)
|
||||
// // {
|
||||
@@ -191,7 +191,7 @@ std::string ChangeTalentsAction::SpecApply(std::string param)
|
||||
// {
|
||||
// std::vector<TalentPath*> ret;
|
||||
|
||||
// // for (auto& path : sPlayerbotAIConfig->classSpecs[bot->getClass()].talentPath)
|
||||
// // for (auto& path : sPlayerbotAIConfig.classSpecs[bot->getClass()].talentPath)
|
||||
// // {
|
||||
// // TalentSpec newSpec = *GetBestPremadeSpec(path.id);
|
||||
// // newSpec.CropTalents(bot->GetLevel());
|
||||
@@ -206,7 +206,7 @@ std::string ChangeTalentsAction::SpecApply(std::string param)
|
||||
|
||||
// TalentPath* ChangeTalentsAction::getPremadePath(uint32 id)
|
||||
// {
|
||||
// // for (auto& path : sPlayerbotAIConfig->classSpecs[bot->getClass()].talentPath)
|
||||
// // for (auto& path : sPlayerbotAIConfig.classSpecs[bot->getClass()].talentPath)
|
||||
// // {
|
||||
// // if (id == path.id)
|
||||
// // {
|
||||
@@ -214,7 +214,7 @@ std::string ChangeTalentsAction::SpecApply(std::string param)
|
||||
// // }
|
||||
// // }
|
||||
|
||||
// // return &sPlayerbotAIConfig->classSpecs[bot->getClass()].talentPath[0];
|
||||
// // return &sPlayerbotAIConfig.classSpecs[bot->getClass()].talentPath[0];
|
||||
// return nullptr;
|
||||
// }
|
||||
|
||||
@@ -270,9 +270,9 @@ std::string ChangeTalentsAction::SpecApply(std::string param)
|
||||
// return false;
|
||||
// }
|
||||
|
||||
// uint32 specNo = sRandomPlayerbotMgr->GetValue(bot->GetGUID().GetCounter(), "specNo");
|
||||
// uint32 specNo = sRandomPlayerbotMgr.GetValue(bot->GetGUID().GetCounter(), "specNo");
|
||||
// uint32 specId = specNo - 1;
|
||||
// std::string specLink = sRandomPlayerbotMgr->GetData(bot->GetGUID().GetCounter(), "specLink");
|
||||
// std::string specLink = sRandomPlayerbotMgr.GetData(bot->GetGUID().GetCounter(), "specLink");
|
||||
|
||||
// //Continue the current spec
|
||||
// if (specNo > 0)
|
||||
@@ -319,15 +319,15 @@ std::string ChangeTalentsAction::SpecApply(std::string param)
|
||||
// specId = -1;
|
||||
// // specLink = "";
|
||||
// }
|
||||
// else if (paths.size() > 1 && false/*!sPlayerbotAIConfig->autoPickTalents*/ &&
|
||||
// !sRandomPlayerbotMgr->IsRandomBot(bot))
|
||||
// else if (paths.size() > 1 && false/*!sPlayerbotAIConfig.autoPickTalents*/ &&
|
||||
// !sRandomPlayerbotMgr.IsRandomBot(bot))
|
||||
// {
|
||||
// *out << "Found multiple specs: ";
|
||||
// listPremadePaths(paths, out);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// specId = PickPremadePath(paths, sRandomPlayerbotMgr->IsRandomBot(bot))->id;
|
||||
// specId = PickPremadePath(paths, sRandomPlayerbotMgr.IsRandomBot(bot))->id;
|
||||
// TalentSpec newSpec = *GetBestPremadeSpec(specId);
|
||||
// specLink = newSpec.GetTalentLink();
|
||||
// newSpec.CropTalents(bot->GetLevel());
|
||||
@@ -341,12 +341,12 @@ std::string ChangeTalentsAction::SpecApply(std::string param)
|
||||
// }
|
||||
// }
|
||||
|
||||
// sRandomPlayerbotMgr->SetValue(bot->GetGUID().GetCounter(), "specNo", specId + 1);
|
||||
// sRandomPlayerbotMgr.SetValue(bot->GetGUID().GetCounter(), "specNo", specId + 1);
|
||||
|
||||
// if (!specLink.empty() && specId == -1)
|
||||
// sRandomPlayerbotMgr->SetValue(bot->GetGUID().GetCounter(), "specLink", 1, specLink);
|
||||
// sRandomPlayerbotMgr.SetValue(bot->GetGUID().GetCounter(), "specLink", 1, specLink);
|
||||
// else
|
||||
// sRandomPlayerbotMgr->SetValue(bot->GetGUID().GetCounter(), "specLink", 0);
|
||||
// sRandomPlayerbotMgr.SetValue(bot->GetGUID().GetCounter(), "specLink", 0);
|
||||
|
||||
// return (specNo == 0) ? false : true;
|
||||
// }
|
||||
@@ -364,7 +364,7 @@ std::string ChangeTalentsAction::SpecApply(std::string param)
|
||||
// if (path->talentSpec.size())
|
||||
// return &path->talentSpec.back();
|
||||
|
||||
// // return &sPlayerbotAIConfig->classSpecs[bot->getClassMask()].baseSpec;
|
||||
// // return &sPlayerbotAIConfig.classSpecs[bot->getClassMask()].baseSpec;
|
||||
// return nullptr;
|
||||
// }
|
||||
|
||||
@@ -372,7 +372,7 @@ bool AutoSetTalentsAction::Execute(Event event)
|
||||
{
|
||||
std::ostringstream out;
|
||||
|
||||
if (!sPlayerbotAIConfig->autoPickTalents || !sRandomPlayerbotMgr->IsRandomBot(bot))
|
||||
if (!sPlayerbotAIConfig.autoPickTalents || !sRandomPlayerbotMgr.IsRandomBot(bot))
|
||||
return false;
|
||||
|
||||
if (bot->GetFreeTalentPoints() <= 0)
|
||||
@@ -96,7 +96,7 @@ bool FollowChatShortcutAction::Execute(Event event)
|
||||
|
||||
/* Default mechanics takes care of this now.
|
||||
if (bot->GetMapId() != master->GetMapId() || (master && bot->GetDistance(master) >
|
||||
sPlayerbotAIConfig->sightDistance))
|
||||
sPlayerbotAIConfig.sightDistance))
|
||||
{
|
||||
if (bot->isDead())
|
||||
{
|
||||
@@ -161,7 +161,7 @@ bool FleeChatShortcutAction::Execute(Event event)
|
||||
ResetReturnPosition();
|
||||
ResetStayPosition();
|
||||
|
||||
if (bot->GetMapId() != master->GetMapId() || bot->GetDistance(master) > sPlayerbotAIConfig->sightDistance)
|
||||
if (bot->GetMapId() != master->GetMapId() || bot->GetDistance(master) > sPlayerbotAIConfig.sightDistance)
|
||||
{
|
||||
botAI->TellError("I will not flee with you - too far away");
|
||||
return true;
|
||||
@@ -241,20 +241,6 @@ bool MaxDpsChatShortcutAction::Execute(Event event)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NaxxChatShortcutAction::Execute(Event event)
|
||||
{
|
||||
Player* master = GetMaster();
|
||||
if (!master)
|
||||
return false;
|
||||
|
||||
botAI->Reset();
|
||||
botAI->ChangeStrategy("+naxx", BOT_STATE_NON_COMBAT);
|
||||
botAI->ChangeStrategy("+naxx", BOT_STATE_COMBAT);
|
||||
botAI->TellMasterNoFacing("Add Naxx Strategies!");
|
||||
// bot->Say("Add Naxx Strategies!", LANG_UNIVERSAL);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BwlChatShortcutAction::Execute(Event event)
|
||||
{
|
||||
Player* master = GetMaster();
|
||||
@@ -85,13 +85,6 @@ public:
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class NaxxChatShortcutAction : public Action
|
||||
{
|
||||
public:
|
||||
NaxxChatShortcutAction(PlayerbotAI* ai) : Action(ai, "naxx chat shortcut") {}
|
||||
virtual bool Execute(Event event);
|
||||
};
|
||||
|
||||
class BwlChatShortcutAction : public Action
|
||||
{
|
||||
public:
|
||||
@@ -86,7 +86,7 @@ void CheatAction::ListCheats()
|
||||
for (int i = 0; i < log2((uint32)BotCheatMask::maxMask); i++)
|
||||
{
|
||||
BotCheatMask cheatMask = BotCheatMask(1 << i);
|
||||
if ((uint32)cheatMask & (uint32)sPlayerbotAIConfig->botCheatMask)
|
||||
if ((uint32)cheatMask & (uint32)sPlayerbotAIConfig.botCheatMask)
|
||||
out << "[conf:" << GetCheatName(BotCheatMask(cheatMask)) << "]";
|
||||
else if (botAI->HasCheat(cheatMask))
|
||||
out << "[" << GetCheatName(BotCheatMask(cheatMask)) << "]";
|
||||
@@ -28,7 +28,7 @@ bool CheckMailAction::Execute(Event event)
|
||||
continue;
|
||||
|
||||
uint32 account = owner->GetSession()->GetAccountId();
|
||||
if (sPlayerbotAIConfig->IsInRandomAccountList(account))
|
||||
if (sPlayerbotAIConfig.IsInRandomAccountList(account))
|
||||
continue;
|
||||
|
||||
ProcessMail(mail, owner, trans);
|
||||
@@ -80,7 +80,7 @@ void CheckMailAction::ProcessMail(Mail* mail, Player* owner, CharacterDatabaseTr
|
||||
if (!item)
|
||||
continue;
|
||||
|
||||
if (!sGuildTaskMgr->CheckItemTask(i->item_template, item->GetCount(), owner, bot, true))
|
||||
if (!GuildTaskMgr::instance().CheckItemTask(i->item_template, item->GetCount(), owner, bot, true))
|
||||
{
|
||||
std::ostringstream body;
|
||||
body << "Hello, " << owner->GetName() << ",\n";
|
||||
@@ -89,7 +89,7 @@ bool CheckMountStateAction::isUseful()
|
||||
return false;
|
||||
|
||||
// Not useful when level lower than minimum required
|
||||
if (bot->GetLevel() < sPlayerbotAIConfig->useGroundMountAtMinLevel)
|
||||
if (bot->GetLevel() < sPlayerbotAIConfig.useGroundMountAtMinLevel)
|
||||
return false;
|
||||
|
||||
// Allow mounting while transformed only if the form allows it
|
||||
@@ -402,7 +402,7 @@ float CheckMountStateAction::CalculateDismountDistance() const
|
||||
// Warrior bots should dismount far enough to charge (because it's important for generating some initial rage),
|
||||
// a real player would be riding toward enemy mashing the charge key but the bots won't cast charge while mounted.
|
||||
bool isMelee = PlayerbotAI::IsMelee(bot);
|
||||
float dismountDistance = isMelee ? sPlayerbotAIConfig->meleeDistance + 2.0f : sPlayerbotAIConfig->spellDistance + 2.0f;
|
||||
float dismountDistance = isMelee ? sPlayerbotAIConfig.meleeDistance + 2.0f : sPlayerbotAIConfig.spellDistance + 2.0f;
|
||||
return bot->getClass() == CLASS_WARRIOR ? std::max(18.0f, dismountDistance) : dismountDistance;
|
||||
}
|
||||
|
||||
@@ -413,7 +413,7 @@ float CheckMountStateAction::CalculateMountDistance() const
|
||||
// seconds:
|
||||
// 21 / 7 = 21 / 14 + 1.5 = 3 (7 = dismounted speed 14 = epic-mount speed 1.5 = mount-spell cast time)
|
||||
bool isMelee = PlayerbotAI::IsMelee(bot);
|
||||
float baseDistance = isMelee ? sPlayerbotAIConfig->meleeDistance + 10.0f : sPlayerbotAIConfig->spellDistance + 10.0f;
|
||||
float baseDistance = isMelee ? sPlayerbotAIConfig.meleeDistance + 10.0f : sPlayerbotAIConfig.spellDistance + 10.0f;
|
||||
return std::max(21.0f, baseDistance);
|
||||
}
|
||||
|
||||
@@ -440,7 +440,7 @@ int32 CheckMountStateAction::CalculateMasterMountSpeed(Player* master, const Mou
|
||||
int32 ridingSkill = bot->GetPureSkillValue(SKILL_RIDING);
|
||||
int32 botLevel = bot->GetLevel();
|
||||
|
||||
if (ridingSkill <= 75 && botLevel < static_cast<int32>(sPlayerbotAIConfig->useFastGroundMountAtMinLevel))
|
||||
if (ridingSkill <= 75 && botLevel < static_cast<int32>(sPlayerbotAIConfig.useFastGroundMountAtMinLevel))
|
||||
return 59;
|
||||
|
||||
// If there is a master and bot not in BG, use master's aura effects.
|
||||
@@ -20,7 +20,7 @@ bool CheckValuesAction::Execute(Event event)
|
||||
|
||||
if (botAI->HasStrategy("map", BOT_STATE_NON_COMBAT) || botAI->HasStrategy("map full", BOT_STATE_NON_COMBAT))
|
||||
{
|
||||
sTravelNodeMap->manageNodes(bot, botAI->HasStrategy("map full", BOT_STATE_NON_COMBAT));
|
||||
TravelNodeMap::instance().manageNodes(bot, botAI->HasStrategy("map full", BOT_STATE_NON_COMBAT));
|
||||
}
|
||||
|
||||
GuidVector possible_targets = *context->GetValue<GuidVector>("possible targets");
|
||||
@@ -78,20 +78,17 @@ float ChooseRpgTargetAction::getMaxRelevance(GuidPosition guidP)
|
||||
if (!trigger->IsActive())
|
||||
continue;
|
||||
|
||||
NextAction** nextActions = triggerNode->getHandlers();
|
||||
std::vector<NextAction> nextActions = triggerNode->getHandlers();
|
||||
|
||||
bool isRpg = false;
|
||||
|
||||
for (int32 i = 0; i < NextAction::size(nextActions); i++)
|
||||
for (NextAction nextAction : nextActions)
|
||||
{
|
||||
NextAction* nextAction = nextActions[i];
|
||||
|
||||
Action* action = botAI->GetAiObjectContext()->GetAction(nextAction->getName());
|
||||
Action* action = botAI->GetAiObjectContext()->GetAction(nextAction.getName());
|
||||
|
||||
if (dynamic_cast<RpgEnabled*>(action))
|
||||
isRpg = true;
|
||||
}
|
||||
NextAction::destroy(nextActions);
|
||||
|
||||
if (isRpg)
|
||||
{
|
||||
@@ -251,7 +248,7 @@ bool ChooseRpgTargetAction::Execute(Event event)
|
||||
}
|
||||
|
||||
std::mt19937 gen(time(0));
|
||||
sTravelMgr->weighted_shuffle(guidps.begin(), guidps.end(), relevances.begin(), relevances.end(), gen);
|
||||
TravelMgr::instance().weighted_shuffle(guidps.begin(), guidps.end(), relevances.begin(), relevances.end(), gen);
|
||||
|
||||
GuidPosition guidP(guidps.front());
|
||||
if (!guidP)
|
||||
@@ -282,7 +279,7 @@ bool ChooseRpgTargetAction::isUseful()
|
||||
|
||||
GuidPosition guidP = AI_VALUE(GuidPosition, "rpg target");
|
||||
|
||||
if (guidP && guidP.distance(bot) < sPlayerbotAIConfig->reactDistance * 2)
|
||||
if (guidP && guidP.distance(bot) < sPlayerbotAIConfig.reactDistance * 2)
|
||||
return false;
|
||||
|
||||
// TravelTarget* travelTarget = AI_VALUE(TravelTarget*, "travel target"); //not used, line marked for removal.
|
||||
@@ -333,7 +330,7 @@ bool ChooseRpgTargetAction::isFollowValid(Player* bot, WorldPosition pos)
|
||||
if (!botAI->HasStrategy("follow", BOT_STATE_NON_COMBAT))
|
||||
return true;
|
||||
|
||||
if (bot->GetDistance(groupLeader) > sPlayerbotAIConfig->rpgDistance * 2)
|
||||
if (bot->GetDistance(groupLeader) > sPlayerbotAIConfig.rpgDistance * 2)
|
||||
return false;
|
||||
|
||||
Formation* formation = AI_VALUE(Formation*, "formation");
|
||||
@@ -343,7 +340,7 @@ bool ChooseRpgTargetAction::isFollowValid(Player* bot, WorldPosition pos)
|
||||
{
|
||||
Player* player = groupLeader;
|
||||
if (groupLeader && !groupLeader->isMoving() ||
|
||||
PAI_VALUE(WorldPosition, "last long move").distance(pos) < sPlayerbotAIConfig->reactDistance)
|
||||
PAI_VALUE(WorldPosition, "last long move").distance(pos) < sPlayerbotAIConfig.reactDistance)
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "LootObjectStack.h"
|
||||
#include "NewRpgStrategy.h"
|
||||
#include "Playerbots.h"
|
||||
#include "RtiTargetValue.h"
|
||||
#include "PossibleRpgTargetsValue.h"
|
||||
#include "PvpTriggers.h"
|
||||
#include "ServerFacade.h"
|
||||
@@ -19,13 +20,13 @@ bool AttackEnemyPlayerAction::isUseful()
|
||||
if (PlayerHasFlag::IsCapturingFlag(bot))
|
||||
return false;
|
||||
|
||||
return !sPlayerbotAIConfig->IsPvpProhibited(bot->GetZoneId(), bot->GetAreaId());
|
||||
return !sPlayerbotAIConfig.IsPvpProhibited(bot->GetZoneId(), bot->GetAreaId());
|
||||
}
|
||||
|
||||
bool AttackEnemyFlagCarrierAction::isUseful()
|
||||
{
|
||||
Unit* target = context->GetValue<Unit*>("enemy flag carrier")->Get();
|
||||
return target && sServerFacade->IsDistanceLessOrEqualThan(sServerFacade->GetDistance2d(bot, target), 100.0f) &&
|
||||
return target && ServerFacade::instance().IsDistanceLessOrEqualThan(ServerFacade::instance().GetDistance2d(bot, target), 100.0f) &&
|
||||
PlayerHasFlag::IsCapturingFlag(bot);
|
||||
}
|
||||
|
||||
@@ -87,9 +88,7 @@ bool DropTargetAction::Execute(Event event)
|
||||
{
|
||||
Spell const* spell = bot->GetCurrentSpell(CURRENT_AUTOREPEAT_SPELL); // Get the current spell being cast by the bot
|
||||
if (spell && spell->m_spellInfo->Id == 75) //Check spell is not nullptr before accessing m_spellInfo
|
||||
{
|
||||
bot->InterruptSpell(CURRENT_AUTOREPEAT_SPELL); // Interrupt Auto Shot
|
||||
}
|
||||
}
|
||||
bot->AttackStop();
|
||||
|
||||
@@ -142,6 +141,23 @@ bool AttackRtiTargetAction::Execute(Event event)
|
||||
{
|
||||
Unit* rtiTarget = AI_VALUE(Unit*, "rti target");
|
||||
|
||||
// Fallback: if the "rti target" value did not resolve a valid unit yet,
|
||||
// try to resolve the raid icon directly from the group.
|
||||
if (!rtiTarget)
|
||||
{
|
||||
if (Group* group = bot->GetGroup())
|
||||
{
|
||||
std::string const rti = AI_VALUE(std::string, "rti");
|
||||
int32 const index = RtiTargetValue::GetRtiIndex(rti);
|
||||
if (index >= 0)
|
||||
{
|
||||
ObjectGuid const guid = group->GetTargetIcon(index);
|
||||
if (!guid.IsEmpty())
|
||||
rtiTarget = botAI->GetUnit(guid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (rtiTarget && rtiTarget->IsInWorld() && rtiTarget->GetMapId() == bot->GetMapId())
|
||||
{
|
||||
botAI->GetAiObjectContext()->GetValue<GuidVector>("prioritized targets")->Set({rtiTarget->GetGUID()});
|
||||
@@ -153,9 +169,7 @@ bool AttackRtiTargetAction::Execute(Event event)
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
botAI->TellError("I dont see my rti attack target");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -366,7 +366,7 @@ bool ChooseTravelTargetAction::getBestDestination(std::vector<TravelDestination*
|
||||
|
||||
WorldPosition botLocation(bot);
|
||||
std::vector<WorldPosition*> availablePoints =
|
||||
sTravelMgr->getNextPoint(&botLocation, *activePoints); // Pick a good point.
|
||||
TravelMgr::instance().getNextPoint(&botLocation, *activePoints); // Pick a good point.
|
||||
|
||||
if (availablePoints.empty()) // No points available.
|
||||
return false;
|
||||
@@ -488,7 +488,7 @@ bool ChooseTravelTargetAction::SetQuestTarget(TravelTarget* target, bool onlyCom
|
||||
if (newQuests)
|
||||
{
|
||||
// Prefer new quests near the player at lower levels.
|
||||
activeDestinations = sTravelMgr->getQuestTravelDestinations(bot, -1, true, false, 400 + bot->GetLevel() * 10);
|
||||
activeDestinations = TravelMgr::instance().getQuestTravelDestinations(bot, -1, true, false, 400 + bot->GetLevel() * 10);
|
||||
}
|
||||
if (activeQuests || completedQuests)
|
||||
{
|
||||
@@ -510,7 +510,7 @@ bool ChooseTravelTargetAction::SetQuestTarget(TravelTarget* target, bool onlyCom
|
||||
continue;
|
||||
|
||||
//Find quest takers or objectives
|
||||
std::vector<TravelDestination*> questDestinations = sTravelMgr->getQuestTravelDestinations(bot, questId, true, false, 0);
|
||||
std::vector<TravelDestination*> questDestinations = TravelMgr::instance().getQuestTravelDestinations(bot, questId, true, false, 0);
|
||||
|
||||
if (onlyClassQuest && activeDestinations.size() && questDestinations.size()) //Only do class quests if we have any.
|
||||
{
|
||||
@@ -525,7 +525,7 @@ bool ChooseTravelTargetAction::SetQuestTarget(TravelTarget* target, bool onlyCom
|
||||
}
|
||||
}
|
||||
if (newQuests && activeDestinations.empty())
|
||||
activeDestinations = sTravelMgr->getQuestTravelDestinations(bot, -1, true, false); //If we really don't find any new quests look futher away.
|
||||
activeDestinations = TravelMgr::instance().getQuestTravelDestinations(bot, -1, true, false); //If we really don't find any new quests look futher away.
|
||||
|
||||
if (botAI->HasStrategy("debug travel", BotState::BOT_STATE_NON_COMBAT))
|
||||
botAI->TellMasterNoFacing(std::to_string(activeDestinations.size()) + " quest destinations found.");
|
||||
@@ -547,7 +547,7 @@ bool ChooseTravelTargetAction::SetNewQuestTarget(TravelTarget* target)
|
||||
|
||||
// Find quest givers.
|
||||
std::vector<TravelDestination*> TravelDestinations =
|
||||
sTravelMgr->getQuestTravelDestinations(bot, -1, botAI->HasRealPlayerMaster());
|
||||
TravelMgr::instance().getQuestTravelDestinations(bot, -1, botAI->HasRealPlayerMaster());
|
||||
|
||||
activeDestinations.insert(activeDestinations.end(), TravelDestinations.begin(), TravelDestinations.end());
|
||||
|
||||
@@ -576,7 +576,7 @@ bool ChooseTravelTargetAction::SetRpgTarget(TravelTarget* target)
|
||||
|
||||
// Find rpg npcs
|
||||
std::vector<TravelDestination*> TravelDestinations =
|
||||
sTravelMgr->getRpgTravelDestinations(bot, botAI->HasRealPlayerMaster());
|
||||
TravelMgr::instance().getRpgTravelDestinations(bot, botAI->HasRealPlayerMaster());
|
||||
|
||||
activeDestinations.insert(activeDestinations.end(), TravelDestinations.begin(), TravelDestinations.end());
|
||||
|
||||
@@ -605,7 +605,7 @@ bool ChooseTravelTargetAction::SetGrindTarget(TravelTarget* target)
|
||||
|
||||
// Find grind mobs.
|
||||
std::vector<TravelDestination*> TravelDestinations =
|
||||
sTravelMgr->getGrindTravelDestinations(bot, botAI->HasRealPlayerMaster());
|
||||
TravelMgr::instance().getGrindTravelDestinations(bot, botAI->HasRealPlayerMaster());
|
||||
|
||||
activeDestinations.insert(activeDestinations.end(), TravelDestinations.begin(), TravelDestinations.end());
|
||||
|
||||
@@ -634,7 +634,7 @@ bool ChooseTravelTargetAction::SetBossTarget(TravelTarget* target)
|
||||
|
||||
// Find boss mobs.
|
||||
std::vector<TravelDestination*> TravelDestinations =
|
||||
sTravelMgr->getBossTravelDestinations(bot, botAI->HasRealPlayerMaster());
|
||||
TravelMgr::instance().getBossTravelDestinations(bot, botAI->HasRealPlayerMaster());
|
||||
|
||||
activeDestinations.insert(activeDestinations.end(), TravelDestinations.begin(), TravelDestinations.end());
|
||||
|
||||
@@ -662,7 +662,7 @@ bool ChooseTravelTargetAction::SetExploreTarget(TravelTarget* target)
|
||||
WorldPosition botLocation(bot);
|
||||
|
||||
// Find quest givers.
|
||||
std::vector<TravelDestination*> TravelDestinations = sTravelMgr->getExploreTravelDestinations(bot, true, true);
|
||||
std::vector<TravelDestination*> TravelDestinations = TravelMgr::instance().getExploreTravelDestinations(bot, true, true);
|
||||
|
||||
activeDestinations.insert(activeDestinations.end(), TravelDestinations.begin(), TravelDestinations.end());
|
||||
/*
|
||||
@@ -681,7 +681,7 @@ bool ChooseTravelTargetAction::SetExploreTarget(TravelTarget* target)
|
||||
|
||||
if (activePoints.empty())
|
||||
{
|
||||
TravelDestinations = sTravelMgr->getExploreTravelDestinations(bot, botAI->HasRealPlayerMaster());
|
||||
TravelDestinations = TravelMgr::instance().getExploreTravelDestinations(bot, botAI->HasRealPlayerMaster());
|
||||
|
||||
for (auto& activeTarget : activeDestinations)
|
||||
{
|
||||
@@ -710,7 +710,7 @@ bool ChooseTravelTargetAction::SetNpcFlagTarget(TravelTarget* target, std::vecto
|
||||
|
||||
std::vector<TravelDestination*> dests;
|
||||
|
||||
for (auto& d : sTravelMgr->getRpgTravelDestinations(bot, true, true))
|
||||
for (auto& d : TravelMgr::instance().getRpgTravelDestinations(bot, true, true))
|
||||
{
|
||||
if (!d->getEntry())
|
||||
continue;
|
||||
@@ -813,7 +813,7 @@ std::vector<TravelDestination*> TravelMgr::getBossTravelDestinations(Player* bot
|
||||
|
||||
bool ChooseTravelTargetAction::SetNullTarget(TravelTarget* target)
|
||||
{
|
||||
target->setTarget(sTravelMgr->nullTravelDestination, sTravelMgr->nullWorldPosition, true);
|
||||
target->setTarget(TravelMgr::instance().nullTravelDestination, TravelMgr::instance().nullWorldPosition, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -832,7 +832,7 @@ TravelDestination* ChooseTravelTargetAction::FindDestination(Player* bot, std::s
|
||||
//Quests
|
||||
if (quests)
|
||||
{
|
||||
for (auto& d : sTravelMgr->getQuestTravelDestinations(bot, 0, true, true))
|
||||
for (auto& d : TravelMgr::instance().getQuestTravelDestinations(bot, 0, true, true))
|
||||
{
|
||||
if (strstri(d->getTitle().c_str(), name.c_str()))
|
||||
dests.push_back(d);
|
||||
@@ -842,7 +842,7 @@ TravelDestination* ChooseTravelTargetAction::FindDestination(Player* bot, std::s
|
||||
//Zones
|
||||
if (zones)
|
||||
{
|
||||
for (auto& d : sTravelMgr->getExploreTravelDestinations(bot, true, true))
|
||||
for (auto& d : TravelMgr::instance().getExploreTravelDestinations(bot, true, true))
|
||||
{
|
||||
if (strstri(d->getTitle().c_str(), name.c_str()))
|
||||
dests.push_back(d);
|
||||
@@ -852,7 +852,7 @@ TravelDestination* ChooseTravelTargetAction::FindDestination(Player* bot, std::s
|
||||
//Npcs
|
||||
if (npcs)
|
||||
{
|
||||
for (auto& d : sTravelMgr->getRpgTravelDestinations(bot, true, true))
|
||||
for (auto& d : TravelMgr::instance().getRpgTravelDestinations(bot, true, true))
|
||||
{
|
||||
if (strstri(d->getTitle().c_str(), name.c_str()))
|
||||
dests.push_back(d);
|
||||
@@ -862,7 +862,7 @@ TravelDestination* ChooseTravelTargetAction::FindDestination(Player* bot, std::s
|
||||
//Mobs
|
||||
if (mobs)
|
||||
{
|
||||
for (auto& d : sTravelMgr->getGrindTravelDestinations(bot, true, true, 5000.0f))
|
||||
for (auto& d : TravelMgr::instance().getGrindTravelDestinations(bot, true, true, 5000.0f))
|
||||
{
|
||||
if (strstri(d->getTitle().c_str(), name.c_str()))
|
||||
dests.push_back(d);
|
||||
@@ -872,7 +872,7 @@ TravelDestination* ChooseTravelTargetAction::FindDestination(Player* bot, std::s
|
||||
//Bosses
|
||||
if (bosses)
|
||||
{
|
||||
for (auto& d : sTravelMgr->getBossTravelDestinations(bot, true, true))
|
||||
for (auto& d : TravelMgr::instance().getBossTravelDestinations(bot, true, true))
|
||||
{
|
||||
if (strstri(d->getTitle().c_str(), name.c_str()))
|
||||
dests.push_back(d);
|
||||
@@ -25,7 +25,7 @@ bool SwitchToMeleeAction::isUseful()
|
||||
return botAI->HasStrategy("ranged", BOT_STATE_COMBAT) &&
|
||||
((bot->IsInCombat() && target &&
|
||||
(target->GetVictim() == bot && (!bot->GetGroup() || lastFlee) &&
|
||||
sServerFacade->IsDistanceLessOrEqualThan(AI_VALUE2(float, "distance", "current target"), 8.0f))) ||
|
||||
ServerFacade::instance().IsDistanceLessOrEqualThan(AI_VALUE2(float, "distance", "current target"), 8.0f))) ||
|
||||
(!bot->IsInCombat()));
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ bool SwitchToRangedAction::isUseful()
|
||||
return botAI->HasStrategy("close", BOT_STATE_COMBAT) && hasAmmo &&
|
||||
((bot->IsInCombat() && target &&
|
||||
((target->GetVictim() != bot || target->GetTarget() != bot->GetGUID()) ||
|
||||
sServerFacade->IsDistanceGreaterThan(AI_VALUE2(float, "distance", "current target"), 8.0f))) ||
|
||||
ServerFacade::instance().IsDistanceGreaterThan(AI_VALUE2(float, "distance", "current target"), 8.0f))) ||
|
||||
(!bot->IsInCombat()));
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ bool DebugAction::Execute(Event event)
|
||||
|
||||
if (text == "scan")
|
||||
{
|
||||
sPlayerbotAIConfig->openLog("scan.csv", "w");
|
||||
sPlayerbotAIConfig.openLog("scan.csv", "w");
|
||||
|
||||
uint32 i = 0;
|
||||
for (auto p : WorldPosition().getCreaturesNear())
|
||||
@@ -36,15 +36,15 @@ bool DebugAction::Execute(Event event)
|
||||
|
||||
pos.printWKT(out);
|
||||
|
||||
sPlayerbotAIConfig->log("scan.csv", out.str().c_str());
|
||||
sPlayerbotAIConfig.log("scan.csv", out.str().c_str());
|
||||
|
||||
if (zoneId == 0 && areaId == 0)
|
||||
{
|
||||
sPlayerbotAIConfig->log("x", out.str().c_str());
|
||||
sPlayerbotAIConfig.log("x", out.str().c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
sPlayerbotAIConfig->log("y", out.str().c_str());
|
||||
sPlayerbotAIConfig.log("y", out.str().c_str());
|
||||
}
|
||||
|
||||
i = zoneId;
|
||||
@@ -53,8 +53,8 @@ bool DebugAction::Execute(Event event)
|
||||
}
|
||||
else if (text.find("printmap") != std::string::npos)
|
||||
{
|
||||
sTravelNodeMap->printMap();
|
||||
sTravelNodeMap->printNodeStore();
|
||||
TravelNodeMap::instance().printMap();
|
||||
TravelNodeMap::instance().printNodeStore();
|
||||
return true;
|
||||
}
|
||||
else if (text.find("travel ") != std::string::npos)
|
||||
@@ -72,7 +72,7 @@ bool DebugAction::Execute(Event event)
|
||||
return false;
|
||||
|
||||
std::vector<WorldPosition> beginPath, endPath;
|
||||
TravelNodeRoute route = sTravelNodeMap->getRoute(botPos, *points.front(), beginPath, bot);
|
||||
TravelNodeRoute route = TravelNodeMap::instance().getRoute(botPos, *points.front(), beginPath, bot);
|
||||
|
||||
std::ostringstream out;
|
||||
out << "Traveling to " << dest->getTitle() << ": ";
|
||||
@@ -108,7 +108,7 @@ bool DebugAction::Execute(Event event)
|
||||
|
||||
out << quest->GetTitle() << ": ";
|
||||
|
||||
QuestContainer* cont = sTravelMgr->quests[questId];
|
||||
QuestContainer* cont = TravelMgr::instance().quests[questId];
|
||||
|
||||
for (auto g : cont->questGivers)
|
||||
{
|
||||
@@ -135,11 +135,11 @@ bool DebugAction::Execute(Event event)
|
||||
else if (text.find("quest") != std::string::npos)
|
||||
{
|
||||
std::ostringstream out;
|
||||
out << sTravelMgr->quests.size() << " quests ";
|
||||
out << TravelMgr::instance().quests.size() << " quests ";
|
||||
|
||||
uint32 noT = 0, noG = 0, noO = 0;
|
||||
|
||||
for (auto q : sTravelMgr->quests)
|
||||
for (auto q : TravelMgr::instance().quests)
|
||||
{
|
||||
if (q.second->questGivers.empty())
|
||||
noG++;
|
||||
@@ -164,7 +164,7 @@ bool DebugAction::Execute(Event event)
|
||||
|
||||
// uint32 noT = 0, noG = 0, noO = 0; //not used, line marked for removal.
|
||||
|
||||
for (auto q : sTravelMgr->quests)
|
||||
for (auto q : TravelMgr::instance().quests)
|
||||
{
|
||||
Quest const* quest = sObjectMgr->GetQuestTemplate(q.first);
|
||||
|
||||
@@ -194,16 +194,16 @@ bool DebugAction::Execute(Event event)
|
||||
|
||||
std::string const name = "USER:" + text.substr(9);
|
||||
|
||||
/* TravelNode* startNode = */ sTravelNodeMap->addNode(pos, name, false, false); // startNode not used, but addNode as side effect, fragment marked for removal.
|
||||
/* TravelNode* startNode = */ TravelNodeMap::instance().addNode(pos, name, false, false); // startNode not used, but addNode as side effect, fragment marked for removal.
|
||||
|
||||
for (auto& endNode : sTravelNodeMap->getNodes(pos, 2000))
|
||||
for (auto& endNode : TravelNodeMap::instance().getNodes(pos, 2000))
|
||||
{
|
||||
endNode->setLinked(false);
|
||||
}
|
||||
|
||||
botAI->TellMasterNoFacing("Node " + name + " created.");
|
||||
|
||||
sTravelNodeMap->setHasToGen();
|
||||
TravelNodeMap::instance().setHasToGen();
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -211,7 +211,7 @@ bool DebugAction::Execute(Event event)
|
||||
{
|
||||
WorldPosition pos(bot);
|
||||
|
||||
TravelNode* startNode = sTravelNodeMap->getNode(pos, nullptr, 50);
|
||||
TravelNode* startNode = TravelNodeMap::instance().getNode(pos, nullptr, 50);
|
||||
|
||||
if (!startNode)
|
||||
return false;
|
||||
@@ -221,24 +221,24 @@ bool DebugAction::Execute(Event event)
|
||||
botAI->TellMasterNoFacing("Node can not be removed.");
|
||||
}
|
||||
|
||||
sTravelNodeMap->m_nMapMtx.lock();
|
||||
sTravelNodeMap->removeNode(startNode);
|
||||
TravelNodeMap::instance().m_nMapMtx.lock();
|
||||
TravelNodeMap::instance().removeNode(startNode);
|
||||
botAI->TellMasterNoFacing("Node removed.");
|
||||
sTravelNodeMap->m_nMapMtx.unlock();
|
||||
TravelNodeMap::instance().m_nMapMtx.unlock();
|
||||
|
||||
sTravelNodeMap->setHasToGen();
|
||||
TravelNodeMap::instance().setHasToGen();
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (text.find("reset node") != std::string::npos)
|
||||
{
|
||||
for (auto& node : sTravelNodeMap->getNodes())
|
||||
for (auto& node : TravelNodeMap::instance().getNodes())
|
||||
node->setLinked(false);
|
||||
return true;
|
||||
}
|
||||
else if (text.find("reset path") != std::string::npos)
|
||||
{
|
||||
for (auto& node : sTravelNodeMap->getNodes())
|
||||
for (auto& node : TravelNodeMap::instance().getNodes())
|
||||
for (auto& path : *node->getLinks())
|
||||
node->removeLinkTo(path.first, true);
|
||||
return true;
|
||||
@@ -246,23 +246,23 @@ bool DebugAction::Execute(Event event)
|
||||
else if (text.find("gen node") != std::string::npos)
|
||||
{
|
||||
// Pathfinder
|
||||
sTravelNodeMap->generateNodes();
|
||||
TravelNodeMap::instance().generateNodes();
|
||||
return true;
|
||||
}
|
||||
else if (text.find("gen path") != std::string::npos)
|
||||
{
|
||||
sTravelNodeMap->generatePaths();
|
||||
TravelNodeMap::instance().generatePaths();
|
||||
return true;
|
||||
}
|
||||
else if (text.find("crop path") != std::string::npos)
|
||||
{
|
||||
sTravelNodeMap->removeUselessPaths();
|
||||
TravelNodeMap::instance().removeUselessPaths();
|
||||
return true;
|
||||
}
|
||||
else if (text.find("save node") != std::string::npos)
|
||||
{
|
||||
sTravelNodeMap->printNodeStore();
|
||||
sTravelNodeMap->saveNodeStore();
|
||||
TravelNodeMap::instance().printNodeStore();
|
||||
TravelNodeMap::instance().saveNodeStore();
|
||||
return true;
|
||||
}
|
||||
else if (text.find("load node") != std::string::npos)
|
||||
@@ -270,8 +270,8 @@ bool DebugAction::Execute(Event event)
|
||||
std::thread t(
|
||||
[]
|
||||
{
|
||||
sTravelNodeMap->removeNodes();
|
||||
sTravelNodeMap->loadNodeStore();
|
||||
TravelNodeMap::instance().removeNodes();
|
||||
TravelNodeMap::instance().loadNodeStore();
|
||||
});
|
||||
|
||||
t.detach();
|
||||
@@ -282,7 +282,7 @@ bool DebugAction::Execute(Event event)
|
||||
{
|
||||
WorldPosition pos(bot);
|
||||
|
||||
std::vector<TravelNode*> nodes = sTravelNodeMap->getNodes(pos, 500);
|
||||
std::vector<TravelNode*> nodes = TravelNodeMap::instance().getNodes(pos, 500);
|
||||
|
||||
for (auto& node : nodes)
|
||||
{
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
bool DelayAction::Execute(Event event)
|
||||
{
|
||||
uint32 delay = sPlayerbotAIConfig->passiveDelay + sPlayerbotAIConfig->globalCoolDown;
|
||||
uint32 delay = sPlayerbotAIConfig.passiveDelay + sPlayerbotAIConfig.globalCoolDown;
|
||||
|
||||
botAI->SetNextCheckDelay(delay);
|
||||
|
||||
@@ -67,7 +67,7 @@ bool CleanQuestLogAction::Execute(Event event)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!sPlayerbotAIConfig->dropObsoleteQuests)
|
||||
if (!sPlayerbotAIConfig.dropObsoleteQuests)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -88,7 +88,7 @@ void EmoteActionBase::InitEmotes()
|
||||
|
||||
bool EmoteActionBase::Emote(Unit* target, uint32 type, bool textEmote)
|
||||
{
|
||||
if (target && !bot->HasInArc(static_cast<float>(M_PI), target, sPlayerbotAIConfig->sightDistance))
|
||||
if (target && !bot->HasInArc(static_cast<float>(M_PI), target, sPlayerbotAIConfig.sightDistance))
|
||||
bot->SetFacingToObject(target);
|
||||
|
||||
ObjectGuid oldSelection = bot->GetTarget();
|
||||
@@ -100,7 +100,7 @@ bool EmoteActionBase::Emote(Unit* target, uint32 type, bool textEmote)
|
||||
if (player)
|
||||
{
|
||||
PlayerbotAI* playerBotAI = GET_PLAYERBOT_AI(player);
|
||||
if (playerBotAI && !player->HasInArc(static_cast<float>(M_PI), bot, sPlayerbotAIConfig->sightDistance))
|
||||
if (playerBotAI && !player->HasInArc(static_cast<float>(M_PI), bot, sPlayerbotAIConfig.sightDistance))
|
||||
{
|
||||
player->SetFacingToObject(bot);
|
||||
}
|
||||
@@ -133,7 +133,7 @@ Unit* EmoteActionBase::GetTarget()
|
||||
for (GuidVector::iterator i = nfp.begin(); i != nfp.end(); ++i)
|
||||
{
|
||||
Unit* unit = botAI->GetUnit(*i);
|
||||
if (unit && sServerFacade->GetDistance2d(bot, unit) < sPlayerbotAIConfig->tooCloseDistance)
|
||||
if (unit && ServerFacade::instance().GetDistance2d(bot, unit) < sPlayerbotAIConfig.tooCloseDistance)
|
||||
targets.push_back(unit);
|
||||
}
|
||||
|
||||
@@ -618,8 +618,8 @@ bool EmoteActionBase::ReceiveEmote(Player* source, uint32 emote, bool verbal)
|
||||
break;
|
||||
}
|
||||
|
||||
if (source && !bot->isMoving() && !bot->HasInArc(static_cast<float>(M_PI), source, sPlayerbotAIConfig->farDistance))
|
||||
sServerFacade->SetFacingTo(bot, source);
|
||||
if (source && !bot->isMoving() && !bot->HasInArc(static_cast<float>(M_PI), source, sPlayerbotAIConfig.farDistance))
|
||||
ServerFacade::instance().SetFacingTo(bot, source);
|
||||
|
||||
if (verbal)
|
||||
{
|
||||
@@ -689,7 +689,7 @@ bool EmoteAction::Execute(Event event)
|
||||
p >> emoteId >> source;
|
||||
|
||||
pSource = ObjectAccessor::FindPlayer(source);
|
||||
if (pSource && pSource != bot && sServerFacade->GetDistance2d(bot, pSource) < sPlayerbotAIConfig->farDistance &&
|
||||
if (pSource && pSource != bot && ServerFacade::instance().GetDistance2d(bot, pSource) < sPlayerbotAIConfig.farDistance &&
|
||||
emoteId != EMOTE_ONESHOT_NONE)
|
||||
{
|
||||
if ((pSource->GetGUID() != bot->GetGUID()) &&
|
||||
@@ -737,7 +737,7 @@ bool EmoteAction::Execute(Event event)
|
||||
// time_t lastEmote = AI_VALUE2(time_t, "last emote", qualifier); //not used, line marked for removal.
|
||||
botAI->GetAiObjectContext()
|
||||
->GetValue<time_t>("last emote", qualifier)
|
||||
->Set(time(nullptr) + urand(1000, sPlayerbotAIConfig->repeatDelay) / 1000);
|
||||
->Set(time(nullptr) + urand(1000, sPlayerbotAIConfig.repeatDelay) / 1000);
|
||||
param = qualifier;
|
||||
}
|
||||
|
||||
@@ -330,7 +330,7 @@ void EquipAction::EquipItem(Item* item)
|
||||
|
||||
bool EquipUpgradesAction::Execute(Event event)
|
||||
{
|
||||
if (!sPlayerbotAIConfig->autoEquipUpgradeLoot && !sRandomPlayerbotMgr->IsRandomBot(bot))
|
||||
if (!sPlayerbotAIConfig.autoEquipUpgradeLoot && !sRandomPlayerbotMgr.IsRandomBot(bot))
|
||||
return false;
|
||||
|
||||
if (event.GetSource() == "trade status")
|
||||
@@ -344,6 +344,27 @@ bool EquipUpgradesAction::Execute(Event event)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (event.GetSource() == "item push result")
|
||||
{
|
||||
WorldPacket p(event.getPacket());
|
||||
p.rpos(0);
|
||||
ObjectGuid playerGuid;
|
||||
uint32 received, created, sendChatMessage, itemSlot, itemId;
|
||||
uint8 bagSlot;
|
||||
|
||||
p >> playerGuid;
|
||||
p >> received;
|
||||
p >> created;
|
||||
p >> sendChatMessage;
|
||||
p >> bagSlot;
|
||||
p >> itemSlot;
|
||||
p >> itemId;
|
||||
|
||||
ItemTemplate const* item = sObjectMgr->GetItemTemplate(itemId);
|
||||
if (item->Class == ITEM_CLASS_TRADE_GOODS && item->SubClass == ITEM_SUBCLASS_MEAT)
|
||||
return false;
|
||||
}
|
||||
|
||||
CollectItemsVisitor visitor;
|
||||
IterateItems(&visitor, ITERATE_ITEMS_IN_BAGS);
|
||||
|
||||
510
src/Ai/Base/Actions/FishingAction.cpp
Normal file
510
src/Ai/Base/Actions/FishingAction.cpp
Normal file
@@ -0,0 +1,510 @@
|
||||
/*
|
||||
* 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 = PlayerbotTextMgr::instance().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;
|
||||
}
|
||||
71
src/Ai/Base/Actions/FishingAction.h
Normal file
71
src/Ai/Base/Actions/FishingAction.h
Normal file
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* 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
|
||||
@@ -44,7 +44,7 @@ bool FollowAction::Execute(Event event)
|
||||
// botAI->PetFollow();
|
||||
// }
|
||||
// if (moved)
|
||||
// botAI->SetNextCheckDelay(sPlayerbotAIConfig->reactDelay);
|
||||
// botAI->SetNextCheckDelay(sPlayerbotAIConfig.reactDelay);
|
||||
|
||||
return moved;
|
||||
}
|
||||
@@ -97,8 +97,10 @@ bool FollowAction::isUseful()
|
||||
|
||||
distance = bot->GetDistance(loc.GetPositionX(), loc.GetPositionY(), loc.GetPositionZ());
|
||||
}
|
||||
if (botAI->HasStrategy("master fishing", BOT_STATE_NON_COMBAT))
|
||||
return ServerFacade::instance().IsDistanceGreaterThan(distance, sPlayerbotAIConfig.fishingDistanceFromMaster);
|
||||
|
||||
return sServerFacade->IsDistanceGreaterThan(distance, formation->GetMaxDistance());
|
||||
return ServerFacade::instance().IsDistanceGreaterThan(distance, formation->GetMaxDistance());
|
||||
}
|
||||
|
||||
bool FollowAction::CanDeadFollow(Unit* target)
|
||||
@@ -128,7 +130,7 @@ bool FleeToGroupLeaderAction::Execute(Event event)
|
||||
WorldPosition bosPos(bot);
|
||||
float distance = bosPos.fDist(targetPos);
|
||||
|
||||
if (distance < sPlayerbotAIConfig->reactDistance * 3)
|
||||
if (distance < sPlayerbotAIConfig.reactDistance * 3)
|
||||
{
|
||||
if (!urand(0, 3))
|
||||
botAI->TellMaster("I am close, wait for me!");
|
||||
@@ -113,7 +113,7 @@ bool TogglePetSpellAutoCastAction::Execute(Event event)
|
||||
}
|
||||
|
||||
// Debug message if pet spells have been toggled and debug is enabled
|
||||
if (toggled && sPlayerbotAIConfig->petChatCommandDebug == 1)
|
||||
if (toggled && sPlayerbotAIConfig.petChatCommandDebug == 1)
|
||||
botAI->TellMaster("Pet autocast spells have been toggled.");
|
||||
|
||||
return toggled;
|
||||
@@ -185,7 +185,7 @@ bool SetPetStanceAction::Execute(Event /*event*/)
|
||||
}
|
||||
|
||||
// Get the default pet stance from the configuration
|
||||
int32 stance = sPlayerbotAIConfig->defaultPetStance;
|
||||
int32 stance = sPlayerbotAIConfig.defaultPetStance;
|
||||
ReactStates react = REACT_DEFENSIVE;
|
||||
std::string stanceText = "defensive (from config, fallback)";
|
||||
|
||||
@@ -221,7 +221,7 @@ bool SetPetStanceAction::Execute(Event /*event*/)
|
||||
}
|
||||
|
||||
// If debug is enabled in config, inform the master of the new stance
|
||||
if (sPlayerbotAIConfig->petChatCommandDebug == 1)
|
||||
if (sPlayerbotAIConfig.petChatCommandDebug == 1)
|
||||
botAI->TellMaster("Pet stance set to " + stanceText + " (applied to all pets/guardians).");
|
||||
|
||||
return true;
|
||||
@@ -87,7 +87,7 @@ namespace ai::buff
|
||||
{
|
||||
std::string castName = baseName;
|
||||
Group* g = bot->GetGroup();
|
||||
if (!g || g->GetMembersCount() < static_cast<uint32>(sPlayerbotAIConfig->minBotsForGreaterBuff))
|
||||
if (!g || g->GetMembersCount() < static_cast<uint32>(sPlayerbotAIConfig.minBotsForGreaterBuff))
|
||||
return castName; // Group too small: stay in solo mode
|
||||
|
||||
if (std::string const groupName = GroupVariantFor(baseName); !groupName.empty())
|
||||
@@ -114,7 +114,7 @@ namespace ai::buff
|
||||
time_t now = std::time(nullptr);
|
||||
uint32 botLow = static_cast<uint32>(bot->GetGUID().GetCounter());
|
||||
time_t& last = s_lastWarn[ std::make_pair(botLow, groupName) ];
|
||||
if (!last || now - last >= sPlayerbotAIConfig->rpWarningCooldown) // Configurable anti-spam
|
||||
if (!last || now - last >= sPlayerbotAIConfig.rpWarningCooldown) // Configurable anti-spam
|
||||
{
|
||||
// DB Key choice in regard of the buff
|
||||
std::string key;
|
||||
@@ -132,7 +132,7 @@ namespace ai::buff
|
||||
placeholders["%group_spell"] = groupName;
|
||||
placeholders["%base_spell"] = baseName;
|
||||
|
||||
std::string announceText = sPlayerbotTextMgr->GetBotTextOrDefault(key,
|
||||
std::string announceText = PlayerbotTextMgr::instance().GetBotTextOrDefault(key,
|
||||
"Out of components for %group_spell. Using %base_spell!", placeholders);
|
||||
|
||||
announce(announceText);
|
||||
@@ -82,7 +82,7 @@ bool CastSpellAction::isPossible()
|
||||
{
|
||||
if (botAI->IsInVehicle() && !botAI->IsInVehicle(false, false, true))
|
||||
{
|
||||
if (!sPlayerbotAIConfig->logInGroupOnly || (bot->GetGroup() && botAI->HasRealPlayerMaster()))
|
||||
if (!sPlayerbotAIConfig.logInGroupOnly || (bot->GetGroup() && botAI->HasRealPlayerMaster()))
|
||||
{
|
||||
LOG_DEBUG("playerbots", "Can cast spell failed. Vehicle. - bot name: {}", bot->GetName());
|
||||
}
|
||||
@@ -94,7 +94,7 @@ bool CastSpellAction::isPossible()
|
||||
|
||||
if (spell == "mount" && bot->IsInCombat())
|
||||
{
|
||||
if (!sPlayerbotAIConfig->logInGroupOnly || (bot->GetGroup() && botAI->HasRealPlayerMaster()))
|
||||
if (!sPlayerbotAIConfig.logInGroupOnly || (bot->GetGroup() && botAI->HasRealPlayerMaster()))
|
||||
{
|
||||
LOG_DEBUG("playerbots", "Can cast spell failed. Mount. - bot name: {}", bot->GetName());
|
||||
}
|
||||
@@ -133,7 +133,7 @@ bool CastSpellAction::isUseful()
|
||||
|
||||
return spellTarget &&
|
||||
AI_VALUE2(bool, "spell cast useful",
|
||||
spell); // && sServerFacade->GetDistance2d(bot, spellTarget) <= (range + combatReach);
|
||||
spell); // && ServerFacade::instance().GetDistance2d(bot, spellTarget) <= (range + combatReach);
|
||||
}
|
||||
|
||||
CastMeleeSpellAction::CastMeleeSpellAction(PlayerbotAI* botAI, std::string const spell) : CastSpellAction(botAI, spell)
|
||||
@@ -265,11 +265,6 @@ CastShootAction::CastShootAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "s
|
||||
}
|
||||
}
|
||||
|
||||
NextAction** CastSpellAction::getPrerequisites()
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Value<Unit*>* CastDebuffSpellOnAttackerAction::GetTargetValue()
|
||||
{
|
||||
return context->GetValue<Unit*>("attacker without aura", spell);
|
||||
@@ -27,7 +27,11 @@ public:
|
||||
bool isUseful() override;
|
||||
ActionThreatType getThreatType() override { return ActionThreatType::Single; }
|
||||
|
||||
NextAction** getPrerequisites() override;
|
||||
std::vector<NextAction> getPrerequisites() override
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
std::string const getSpell() { return spell; }
|
||||
|
||||
protected:
|
||||
@@ -193,10 +197,12 @@ public:
|
||||
ResurrectPartyMemberAction(PlayerbotAI* botAI, std::string const spell) : CastSpellAction(botAI, spell) {}
|
||||
|
||||
std::string const GetTargetName() override { return "party member to resurrect"; }
|
||||
NextAction** getPrerequisites() override
|
||||
std::vector<NextAction> getPrerequisites() override
|
||||
{
|
||||
return NextAction::merge(NextAction::array(0, new NextAction("reach party member to resurrect"), NULL),
|
||||
Action::getPrerequisites());
|
||||
return NextAction::merge(
|
||||
{ NextAction("reach party member to resurrect") },
|
||||
Action::getPrerequisites()
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -64,7 +64,7 @@ Unit* GiveItemAction::GetTarget() { return AI_VALUE2(Unit*, "party member withou
|
||||
|
||||
bool GiveItemAction::isUseful()
|
||||
{
|
||||
return GetTarget() && AI_VALUE2(uint8, "mana", "self target") > sPlayerbotAIConfig->lowMana;
|
||||
return GetTarget() && AI_VALUE2(uint8, "mana", "self target") > sPlayerbotAIConfig.lowMana;
|
||||
}
|
||||
|
||||
Unit* GiveFoodAction::GetTarget() { return AI_VALUE(Unit*, "party member without food"); }
|
||||
@@ -74,7 +74,7 @@ bool GiveFoodAction::isUseful()
|
||||
if (!GetTarget())
|
||||
return false;
|
||||
|
||||
bool isRandomBot = GetTarget()->IsPlayer() && sRandomPlayerbotMgr->IsRandomBot((Player*)GetTarget());
|
||||
bool isRandomBot = GetTarget()->IsPlayer() && sRandomPlayerbotMgr.IsRandomBot((Player*)GetTarget());
|
||||
|
||||
return !isRandomBot || (isRandomBot && !botAI->HasCheat(BotCheatMask::food));
|
||||
}
|
||||
@@ -86,7 +86,7 @@ bool GiveWaterAction::isUseful()
|
||||
if (!GetTarget())
|
||||
return false;
|
||||
|
||||
bool isRandomBot = GetTarget()->IsPlayer() && sRandomPlayerbotMgr->IsRandomBot((Player*)GetTarget());
|
||||
bool isRandomBot = GetTarget()->IsPlayer() && sRandomPlayerbotMgr.IsRandomBot((Player*)GetTarget());
|
||||
|
||||
return !isRandomBot || (isRandomBot && !botAI->HasCheat(BotCheatMask::food));
|
||||
}
|
||||
@@ -61,7 +61,7 @@ bool GoAction::Execute(Event event)
|
||||
else
|
||||
{
|
||||
botAI->TellMasterNoFacing("Clearing travel target");
|
||||
target->setTarget(sTravelMgr->nullTravelDestination, sTravelMgr->nullWorldPosition);
|
||||
target->setTarget(TravelMgr::instance().nullTravelDestination, TravelMgr::instance().nullWorldPosition);
|
||||
target->setForced(false);
|
||||
return true;
|
||||
}
|
||||
@@ -75,8 +75,8 @@ bool GoAction::Execute(Event event)
|
||||
if (GameObject* go = botAI->GetGameObject(guid))
|
||||
if (go->isSpawned())
|
||||
{
|
||||
if (sServerFacade->IsDistanceGreaterThan(sServerFacade->GetDistance2d(bot, go),
|
||||
sPlayerbotAIConfig->reactDistance))
|
||||
if (ServerFacade::instance().IsDistanceGreaterThan(ServerFacade::instance().GetDistance2d(bot, go),
|
||||
sPlayerbotAIConfig.reactDistance))
|
||||
{
|
||||
botAI->TellError("It is too far away");
|
||||
return false;
|
||||
@@ -86,7 +86,7 @@ bool GoAction::Execute(Event event)
|
||||
out << "Moving to " << ChatHelper::FormatGameobject(go);
|
||||
botAI->TellMasterNoFacing(out.str());
|
||||
return MoveNear(bot->GetMapId(), go->GetPositionX(), go->GetPositionY(), go->GetPositionZ() + 0.5f,
|
||||
sPlayerbotAIConfig->followDistance);
|
||||
sPlayerbotAIConfig.followDistance);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
@@ -106,7 +106,7 @@ bool GoAction::Execute(Event event)
|
||||
out << "Moving to " << unit->GetName();
|
||||
botAI->TellMasterNoFacing(out.str());
|
||||
return MoveNear(bot->GetMapId(), unit->GetPositionX(), unit->GetPositionY(),
|
||||
unit->GetPositionZ() + 0.5f, sPlayerbotAIConfig->followDistance);
|
||||
unit->GetPositionZ() + 0.5f, sPlayerbotAIConfig.followDistance);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,8 +176,8 @@ bool GoAction::Execute(Event event)
|
||||
float z = bot->GetPositionZ();
|
||||
bot->UpdateAllowedPositionZ(x, y, z);
|
||||
|
||||
if (sServerFacade->IsDistanceGreaterThan(sServerFacade->GetDistance2d(bot, x, y),
|
||||
sPlayerbotAIConfig->reactDistance))
|
||||
if (ServerFacade::instance().IsDistanceGreaterThan(ServerFacade::instance().GetDistance2d(bot, x, y),
|
||||
sPlayerbotAIConfig.reactDistance))
|
||||
{
|
||||
botAI->TellMaster("It is too far away");
|
||||
return false;
|
||||
@@ -203,14 +203,14 @@ bool GoAction::Execute(Event event)
|
||||
out << "Moving to " << x1 << "," << y1;
|
||||
botAI->TellMasterNoFacing(out.str());
|
||||
|
||||
return MoveNear(bot->GetMapId(), x, y, z + 0.5f, sPlayerbotAIConfig->followDistance);
|
||||
return MoveNear(bot->GetMapId(), x, y, z + 0.5f, sPlayerbotAIConfig.followDistance);
|
||||
}
|
||||
|
||||
PositionInfo pos = context->GetValue<PositionMap&>("position")->Get()[param];
|
||||
if (pos.isSet())
|
||||
{
|
||||
if (sServerFacade->IsDistanceGreaterThan(sServerFacade->GetDistance2d(bot, pos.x, pos.y),
|
||||
sPlayerbotAIConfig->reactDistance))
|
||||
if (ServerFacade::instance().IsDistanceGreaterThan(ServerFacade::instance().GetDistance2d(bot, pos.x, pos.y),
|
||||
sPlayerbotAIConfig.reactDistance))
|
||||
{
|
||||
botAI->TellError("It is too far away");
|
||||
return false;
|
||||
@@ -219,7 +219,7 @@ bool GoAction::Execute(Event event)
|
||||
std::ostringstream out;
|
||||
out << "Moving to position " << param;
|
||||
botAI->TellMasterNoFacing(out.str());
|
||||
return MoveNear(bot->GetMapId(), pos.x, pos.y, pos.z + 0.5f, sPlayerbotAIConfig->followDistance);
|
||||
return MoveNear(bot->GetMapId(), pos.x, pos.y, pos.z + 0.5f, sPlayerbotAIConfig.followDistance);
|
||||
}
|
||||
|
||||
botAI->TellMaster("Whisper 'go x,y', 'go [game object]', 'go unit' or 'go position' and I will go there");
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user