Compare commits

..

3 Commits

Author SHA1 Message Date
bash
0952beec73 tesy 2026-02-01 22:32:43 +01:00
bash
b01a830cc8 Merge branch 'master' of https://github.com/mod-playerbots/mod-playerbots 2026-02-01 22:31:38 +01:00
bash
78f5f01207 fix 2026-02-01 22:25:17 +01:00
372 changed files with 6526 additions and 22163 deletions

View File

@@ -1,16 +1,13 @@
name: Enforce test-staging → master
name: Enforce test-staging → main
on:
pull_request:
types: [opened, synchronize, reopened, edited]
branches:
- master
- test-staging
- main
jobs:
require-test-staging:
runs-on: ubuntu-22.04
if: github.event.pull_request.base.ref == 'master'
steps:
- name: Ensure PR source is test-staging
run: |

View File

@@ -2,9 +2,9 @@ name: Codestyle
on:
push:
branches: [ "master", "test-staging" ]
branches: [ "master" ]
pull_request:
branches: [ "master", "test-staging" ]
branches: [ "master" ]
concurrency:
group: "codestyle-${{ github.event.pull_request.number }}"

View File

@@ -6,6 +6,10 @@ on:
- reopened
- synchronize
- ready_for_review
paths:
- src/**
- "!README.md"
- "!docs/**"
concurrency:
group: "codestyle-cppcheck-${{ github.event.pull_request.number }}"
@@ -18,27 +22,13 @@ jobs:
if: github.event.pull_request.draft == false
steps:
- uses: actions/checkout@v4
- uses: dorny/paths-filter@v3
id: filter
with:
filters: |
cpp:
- 'src/**'
- '!README.md'
- '!docs/**'
- name: Setup python
if: steps.filter.outputs.cpp == 'true'
uses: actions/setup-python@v5
with:
python-version: '3.10'
- name: AzerothCore codestyle
if: steps.filter.outputs.cpp == 'true'
run: python ./apps/codestyle/codestyle-cpp.py
- name: C++ Advanced
if: steps.filter.outputs.cpp == 'true'
run: |
sudo apt update -y
sudo apt install -y cppcheck

View File

@@ -2,9 +2,9 @@ name: ubuntu-build
on:
push:
branches: [ "master", "test-staging" ]
branches: [ "master" ]
pull_request:
branches: [ "master", "test-staging" ]
branches: [ "master" ]
concurrency:
group: "core-build-${{ github.event.pull_request.number }}"

View File

@@ -1,9 +1,9 @@
name: macos-build
on:
push:
branches: [ "master", "test-staging" ]
branches: [ "master" ]
pull_request:
branches: [ "master", "test-staging" ]
branches: [ "master" ]
concurrency:
group: "macos-build-${{ github.event.pull_request.number }}"

View File

@@ -1,9 +1,9 @@
name: windows-build
on:
push:
branches: [ "master", "test-staging" ]
branches: [ "master" ]
pull_request:
branches: [ "master", "test-staging" ]
branches: [ "master" ]
concurrency:
group: "windows-build-${{ github.event.pull_request.number }}"

View File

@@ -1,103 +1,127 @@
<!--
Thank you for contributing to mod-playerbots, please make sure that you...
1. Submit your PR to the test-staging branch, not master.
2. Read the guidelines below before submitting.
3. Don't delete parts of this template.
# Pull Request
DESIGN PHILOSOPHY: We prioritize STABILITY, PERFORMANCE, AND PREDICTABILITY over behavioral realism.
Describe what this change does and why it is needed...
Every action and decision executes PER BOT AND PER TRIGGER. Small increases in logic complexity scale
poorly across thousands of bots and negatively affect all. We prioritize a stable system over a smarter
one. Bots don't need to behave perfectly; believable behavior is the goal, not human simulation.
Default behavior must be cheap in processing; expensive behavior must be opt-in.
---
Before submitting, make sure your changes aligns with these principles.
-->
## Design Philosophy
## Pull Request Description
<!-- Describe what this change does and why it is needed -->
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
<!--
If your PR is very minimal (comment typo, wrong ID reference, etc), and it is very obvious it will not have
any impact on performance, you may skip these question. If necessary, a maintainer may ask you for them later.
-->
<!-- Please answer the following: -->
- Describe the **minimum logic** required to achieve the intended behavior.
- Describe the **processing cost** when this logic executes across many bots.
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, number of bots, specific configuration).
- Expected behavior and how to verify it.
-->
- 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
## Impact Assessment
<!-- As a generic test, before and after measure of pmon (playerbot pmon tick) can help you here. -->
- Does this change increase per-bot/per-tick processing or risk scaling poorly with thousands of bots?
- [ ] No, not at all
- [ ] Minimal impact (**explain below**)
- [ ] Moderate impact (**explain below**)
- 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
- Does this change add new decision branches or increase maintenance complexity?
---
## AI Assistance
- Was AI assistance (e.g. ChatGPT or similar tools) used while working on this change?
- [ ] No
- [ ] Yes (**explain below**)
## Messages to Translate
<!--
Bot messages have to be translatable, but you don't need to do the translations here. You only need to make sure
the message is in a translatable format, and list in the table the message_key and the default English message.
Search for GetBotTextOrDefault in the codebase for examples.
-->
Does this change add bot messages to translate?
- [ ] No
- [ ] Yes (**list messages in the table**)
| Message key | Default message |
| --------------- | ------------------ |
| | |
| | |
## AI Assistance
<!--
AI assistance is allowed, but all submitted code must be fully understood, reviewed, and owned by the contributor.
We expect contributors to be honest about what they do and do not understand.
-->
Was AI assistance used while working on this change?
- [ ] No
- [ ] Yes (**explain below**)
<!--
If yes, please specify:
- Purpose of usage (e.g. brainstorming, refactoring, documentation, code generation).
- Which parts of the change were influenced or generated, and whether it was thoroughly reviewed.
-->
- 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 (Conf comments, WiKi commands).
- [ ] 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 else that's helpful to review or test your pull request. -->
Anything that significantly improves realism at the cost of stability or performance should be carefully discussed
before merging.

View File

@@ -8,7 +8,7 @@
<div align="center">
<img src="banner.png" alt="Playerbots Banner" width="700px">
<img src="icon.png" alt="Playerbots Icon" width="700px">
</div>
<div align="center">

View File

@@ -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开发做出贡献的个人表示诚挚的感谢。您的奉献和努力对塑造这个项目至关重要我们对您的贡献表示感谢。

Binary file not shown.

Before

Width:  |  Height:  |  Size: 204 KiB

View File

@@ -192,12 +192,9 @@ AiPlayerbot.AutoInitOnly = 0
# Default: 1.0 (same with the player)
AiPlayerbot.AutoInitEquipLevelLimitRatio = 1.0
#
# AllowLearnTrainerSpells
# Description: Allow the bot to learn trainers' spells as long as it has the money.
# Default: 1 - (Enabled)
# 0 - (Disabled)
AiPlayerbot.AllowLearnTrainerSpells = 1
# 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
#
#
@@ -561,52 +558,11 @@ AiPlayerbot.AutoGearScoreLimit = 0
# "mana" (bots have infinite mana)
# "power" (bots have infinite energy, rage, and runic power)
# "taxi" (bots may use all flight paths, though they will not actually learn them)
# "raid" (bots use cheats implemented into raid strategies (currently only for SSC and Ulduar))
# "raid" (bots use cheats implemented into raid strategies (currently only for Ulduar))
# To use multiple cheats, separate them by commas below (e.g., to enable all, use "gold,health,mana,power,raid,taxi")
# Default: food, taxi, and raid are enabled
AiPlayerbot.BotCheats = "food,taxi,raid"
# List of attunement quests (comma-separated list of quest IDs) that are automatically completed for all bots.
# While mod-playerbots does not restore removed attunement requirements, although other mods, such as mod-individual-progression, may do so.
# This is meant to exclude bots from such requirements.
#
# Default:
# Caverns of Time - Part 1
# - 10279, To The Master's Lair
# - 10277, The Caverns of Time
#
# Caverns of Time - Part 2 (Escape from Durnholde Keep)
# - 10282, Old Hillsbrad
# - 10283, Taretha's Diversion
# - 10284, Escape from Durnholde
# - 10285, Return to Andormu
#
# Caverns of Time - Part 2 (The Black Morass)
# - 10296, The Black Morass
# - 10297, The Opening of the Dark Portal
# - 10298, Hero of the Brood
#
# Magister's Terrace Attunement
# - 11481, Crisis at the Sunwell
# - 11482, Duty Calls
# - 11488, Magisters' Terrace
# - 11490, The Scryer's Scryer
# - 11492, Hard to Kill
#
# Serpentshrine Cavern
# - 10901, The Cudgel of Kar'desh
#
# The Eye
# - 10888, Trial of the Naaru: Magtheridon
#
# Mount Hyjal
# - 10445, The Vials of Eternity
#
# Black Temple
# - 10985, A Distraction for Akama
#
AiPlayerbot.AttunementQuests = 10279,10277,10282,10283,10284,10285,10296,10297,10298,11481,11482,11488,11490,11492,10901,10888,10445,10985
#
#
#
@@ -809,10 +765,6 @@ AiPlayerbot.LimitGearExpansion = 1
# Set between 0 (0%) and 1 (100%)
AiPlayerbot.RandomGearLoweringChance = 0
# Unobtainable or unusable items (comma-separated list of item IDs)
# Default: Chilton Wand (12468), Totem of the Earthen Ring (46978)
AiPlayerbot.UnobtainableItems = 12468,46978
# Randombots check player's gearscore level and deny the group invitation if it's too low
# Default: 0 (disabled)
AiPlayerbot.GearScoreCheck = 0
@@ -1038,7 +990,7 @@ AiPlayerbot.ZoneBracket.3433 = 10,22
AiPlayerbot.ZoneBracket.3525 = 10,21
# Classic WoW - High-level zones:
# Duskwood (Zone ID: 10 Default Min,Max: 19,33)
# Deadwind Pass (Zone ID: 10 Default Min,Max: 19,33)
# Wetlands (Zone ID: 11 Default Min,Max: 21,30)
# Redridge Mountains (Zone ID: 44 Default Min,Max: 16,28)
# Hillsbrad Foothills (Zone ID: 267 Default Min,Max: 20,34)

File diff suppressed because it is too large Load Diff

View File

@@ -1,104 +0,0 @@
-- #########################################################
-- Playerbots - Add PVP / Arena texts for TellPvpAction
-- Localized for all WotLK locales (koKR, frFR, deDE, zhCN,
-- zhTW, esES, esMX, ruRU)
-- #########################################################
DELETE FROM ai_playerbot_texts WHERE name IN ('pvp_currency', 'pvp_arena_team', 'pvp_no_arena_team');
DELETE FROM ai_playerbot_texts_chance WHERE name IN ('pvp_currency', 'pvp_arena_team', 'pvp_no_arena_team');
-- ---------------------------------------------------------
-- pvp_currency
-- [PVP] Arena points: %arena_points | Honor Points: %honor_points
-- ---------------------------------------------------------
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 (
1737,
'pvp_currency',
'[PVP] Arena points: %arena_points | Honor Points: %honor_points',
0, 0,
-- koKR
'[PVP] 투기장 점수: %arena_points | 명예 점수: %honor_points',
-- frFR
'[PVP] Points d''arène : %arena_points | Points d''honneur : %honor_points',
-- deDE
'[PVP] Arenapunkte: %arena_points | Ehrenpunkte: %honor_points',
-- zhCN
'[PVP] 竞技场点数:%arena_points | 荣誉点数:%honor_points',
-- zhTW
'[PVP] 競技場點數:%arena_points | 榮譽點數:%honor_points',
-- esES
'[PVP] Puntos de arena: %arena_points | Puntos de honor: %honor_points',
-- esMX
'[PVP] Puntos de arena: %arena_points | Puntos de honor: %honor_points',
-- ruRU
'[PVP] Очки арены: %arena_points | Очки чести: %honor_points');
INSERT INTO ai_playerbot_texts_chance (name, probability) VALUES ('pvp_currency', 100);
-- ---------------------------------------------------------
-- pvp_arena_team
-- [PVP] %bracket: <%team_name> (rating %team_rating)
-- ---------------------------------------------------------
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 (
1738,
'pvp_arena_team',
'[PVP] %bracket: <%team_name> (rating %team_rating)',
0, 0,
-- koKR
'[PVP] %bracket: <%team_name> (평점 %team_rating)',
-- frFR
'[PVP] %bracket : <%team_name> (cote %team_rating)',
-- deDE
'[PVP] %bracket: <%team_name> (Wertung %team_rating)',
-- zhCN
'[PVP] %bracket: <%team_name> (评分 %team_rating)',
-- zhTW
'[PVP] %bracket: <%team_name> (評分 %team_rating)',
-- esES
'[PVP] %bracket: <%team_name> (índice %team_rating)',
-- esMX
'[PVP] %bracket: <%team_name> (índice %team_rating)',
-- ruRU
'[PVP] %bracket: <%team_name> (рейтинг %team_rating)');
INSERT INTO ai_playerbot_texts_chance (name, probability) VALUES ('pvp_arena_team', 100);
-- ---------------------------------------------------------
-- pvp_no_arena_team
-- [PVP] I have no Arena Team.
-- ---------------------------------------------------------
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 (
1739,
'pvp_no_arena_team',
'[PVP] I have no Arena Team.',
0, 0,
-- koKR
'[PVP] 투기장 팀이 없습니다.',
-- frFR
'[PVP] Je n''ai aucune équipe d''arène.',
-- deDE
'[PVP] Ich habe kein Arenateam.',
-- zhCN
'[PVP] 我没有竞技场战队。',
-- zhTW
'[PVP] 我沒有競技場隊伍。',
-- esES
'[PVP] No tengo equipo de arena.',
-- esMX
'[PVP] No tengo equipo de arena.',
-- ruRU
'[PVP] У меня нет команды арены.');
INSERT INTO ai_playerbot_texts_chance (name, probability) VALUES ('pvp_no_arena_team', 100);

View File

@@ -1 +0,0 @@
UPDATE `ai_playerbot_texts` SET `text_loc3`='%s, du hörst den triefenden Sarkasmus in meinem text nicht' WHERE `id`=1353;

BIN
icon.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 125 KiB

After

Width:  |  Height:  |  Size: 204 KiB

View File

@@ -125,7 +125,6 @@ public:
creators["runaway"] = &ActionContext::runaway;
creators["stay"] = &ActionContext::stay;
creators["sit"] = &ActionContext::sit;
creators["aggressive target"] = &ActionContext::aggressive_target;
creators["attack anything"] = &ActionContext::attack_anything;
creators["attack least hp target"] = &ActionContext::attack_least_hp_target;
creators["attack enemy player"] = &ActionContext::attack_enemy_player;
@@ -316,7 +315,6 @@ private:
static Action* suggest_what_to_do(PlayerbotAI* botAI) { return new SuggestWhatToDoAction(botAI); }
static Action* suggest_trade(PlayerbotAI* botAI) { return new SuggestTradeAction(botAI); }
static Action* suggest_dungeon(PlayerbotAI* botAI) { return new SuggestDungeonAction(botAI); }
static Action* aggressive_target(PlayerbotAI* botAI) { return new AggressiveTargetAction(botAI); }
static Action* attack_anything(PlayerbotAI* botAI) { return new AttackAnythingAction(botAI); }
static Action* attack_least_hp_target(PlayerbotAI* botAI) { return new AttackLeastHpTargetAction(botAI); }
static Action* attack_enemy_player(PlayerbotAI* botAI) { return new AttackEnemyPlayerAction(botAI); }

View File

@@ -6,9 +6,9 @@
#include "AcceptBattlegroundInvitationAction.h"
#include "Event.h"
#include "PlayerbotAI.h"
#include "Playerbots.h"
bool AcceptBgInvitationAction::Execute(Event /*event*/)
bool AcceptBgInvitationAction::Execute(Event event)
{
uint8 type = 0; // arenatype if arena
uint8 unk2 = 0; // unk, can be 0x0 (may be if was invited?) and 0x1
@@ -18,9 +18,9 @@ bool AcceptBgInvitationAction::Execute(Event /*event*/)
WorldPacket packet(CMSG_BATTLEFIELD_PORT, 20);
packet << type << unk2 << (uint32)bgTypeId_ << unk << action;
// packet << bgTypeId_ << action;
bot->GetSession()->HandleBattleFieldPortOpcode(packet);
botAI->ResetStrategies();
return true;
}

View File

@@ -22,7 +22,7 @@ bool AddLootAction::Execute(Event event)
return AI_VALUE(LootObjectStack*, "available loot")->Add(guid);
}
bool AddAllLootAction::Execute(Event /*event*/)
bool AddAllLootAction::Execute(Event event)
{
bool added = false;

View File

@@ -58,7 +58,7 @@ bool ReachAreaTriggerAction::Execute(Event event)
return true;
}
bool AreaTriggerAction::Execute(Event /*event*/)
bool AreaTriggerAction::Execute(Event event)
{
LastMovement& movement = context->GetValue<LastMovement&>("last area trigger")->Get();

View File

@@ -1,20 +1,19 @@
#include "AutoMaintenanceOnLevelupAction.h"
#include "SpellMgr.h"
#include "GuildMgr.h"
#include "PlayerbotAIConfig.h"
#include "PlayerbotFactory.h"
#include "Playerbots.h"
#include "RandomPlayerbotMgr.h"
#include "SharedDefines.h"
#include "BroadcastHelper.h"
bool AutoMaintenanceOnLevelupAction::Execute(Event /*event*/)
bool AutoMaintenanceOnLevelupAction::Execute(Event event)
{
AutoPickTalents();
AutoLearnSpell();
AutoUpgradeEquip();
AutoTeleportForLevel();
return true;
}

View File

@@ -13,8 +13,9 @@
#include "PlayerbotAI.h"
#include "Playerbots.h"
#include "PositionValue.h"
#include "UpdateTime.h"
bool BGJoinAction::Execute(Event /*event*/)
bool BGJoinAction::Execute(Event event)
{
uint32 queueType = AI_VALUE(uint32, "bg type");
if (!queueType) // force join to fill bg
@@ -24,6 +25,8 @@ bool BGJoinAction::Execute(Event /*event*/)
BattlegroundQueueTypeId queueTypeId = (BattlegroundQueueTypeId)bgList[urand(0, bgList.size() - 1)];
BattlegroundTypeId bgTypeId = BattlegroundMgr::BGTemplateId(queueTypeId);
BattlegroundBracketId bracketId;
bool isArena = false;
bool isRated = false;
Battleground* bg = sBattlegroundMgr->GetBattlegroundTemplate(bgTypeId);
@@ -35,8 +38,12 @@ bool BGJoinAction::Execute(Event /*event*/)
if (!pvpDiff)
return false;
bracketId = pvpDiff->GetBracketId();
if (ArenaType type = ArenaType(BattlegroundMgr::BGArenaType(queueTypeId)))
{
isArena = true;
std::vector<uint32>::iterator i = find(ratedList.begin(), ratedList.end(), queueTypeId);
if (i != ratedList.end())
isRated = true;
@@ -402,6 +409,8 @@ bool BGJoinAction::JoinQueue(uint32 type)
bracketId = pvpDiff->GetBracketId();
uint32 BracketSize = bg->GetMaxPlayersPerTeam() * 2;
uint32 TeamSize = bg->GetMaxPlayersPerTeam();
TeamId teamId = bot->GetTeamId();
// check if already in queue
@@ -478,6 +487,8 @@ bool BGJoinAction::JoinQueue(uint32 type)
if (isArena)
{
isArena = true;
BracketSize = type * 2;
TeamSize = type;
isRated = botAI->GetAiObjectContext()->GetValue<uint32>("arena type")->Get();
if (joinAsGroup)
@@ -642,7 +653,7 @@ bool FreeBGJoinAction::shouldJoinBg(BattlegroundQueueTypeId queueTypeId, Battleg
return false;
}
bool BGLeaveAction::Execute(Event /*event*/)
bool BGLeaveAction::Execute(Event event)
{
if (!(bot->InBattlegroundQueue() || bot->InBattleground()))
return false;
@@ -1053,7 +1064,7 @@ bool BGStatusAction::Execute(Event event)
return true;
}
bool BGStatusCheckAction::Execute(Event /*event*/)
bool BGStatusCheckAction::Execute(Event event)
{
if (bot->IsBeingTeleported())
return false;
@@ -1069,7 +1080,7 @@ bool BGStatusCheckAction::Execute(Event /*event*/)
bool BGStatusCheckAction::isUseful() { return bot->InBattlegroundQueue(); }
bool BGStrategyCheckAction::Execute(Event /*event*/)
bool BGStrategyCheckAction::Execute(Event event)
{
bool inside_bg = bot->InBattleground() && bot->GetBattleground();
;

View File

@@ -1557,7 +1557,7 @@ bool BGTactics::eyJumpDown()
//
// actual bg tactics below
//
bool BGTactics::Execute(Event /*event*/)
bool BGTactics::Execute(Event event)
{
Battleground* bg = bot->GetBattleground();
if (!bg)
@@ -2497,6 +2497,7 @@ bool BGTactics::selectObjective(bool reset)
EYBotStrategy strategyHorde = static_cast<EYBotStrategy>(GetBotStrategyForTeam(bg, TEAM_HORDE));
EYBotStrategy strategyAlliance = static_cast<EYBotStrategy>(GetBotStrategyForTeam(bg, TEAM_ALLIANCE));
EYBotStrategy strategy = (team == TEAM_ALLIANCE) ? strategyAlliance : strategyHorde;
EYBotStrategy enemyStrategy = (team == TEAM_ALLIANCE) ? strategyHorde : strategyAlliance;
auto IsOwned = [&](uint32 nodeId) -> bool
{ return eyeOfTheStormBG->GetCapturePointInfo(nodeId)._ownerTeamId == team; };
@@ -3230,6 +3231,7 @@ bool BGTactics::selectObjectiveWp(std::vector<BattleBotPath*> const& vPaths)
if (bgType == BATTLEGROUND_RB)
bgType = bg->GetBgTypeID(true);
PositionMap& posMap = context->GetValue<PositionMap&>("position")->Get();
PositionInfo pos = context->GetValue<PositionMap&>("position")->Get()["bg objective"];
if (!pos.isSet())
return false;
@@ -4247,7 +4249,7 @@ bool BGTactics::IsLockedInsideKeep()
return false;
}
bool ArenaTactics::Execute(Event /*event*/)
bool ArenaTactics::Execute(Event event)
{
if (!bot->InBattleground())
{

View File

@@ -18,7 +18,7 @@ bool BossFireResistanceAction::isUseful()
return bossFireResistanceTrigger.IsActive();
}
bool BossFireResistanceAction::Execute(Event /*event*/)
bool BossFireResistanceAction::Execute(Event event)
{
PaladinFireResistanceStrategy paladinFireResistanceStrategy(botAI);
botAI->ChangeStrategy(ADD_STRATEGY_CHAR + paladinFireResistanceStrategy.getName(), BotState::BOT_STATE_COMBAT);
@@ -32,7 +32,7 @@ bool BossFrostResistanceAction::isUseful()
return bossFrostResistanceTrigger.IsActive();
}
bool BossFrostResistanceAction::Execute(Event /*event*/)
bool BossFrostResistanceAction::Execute(Event event)
{
PaladinFrostResistanceStrategy paladinFrostResistanceStrategy(botAI);
botAI->ChangeStrategy(ADD_STRATEGY_CHAR + paladinFrostResistanceStrategy.getName(), BotState::BOT_STATE_COMBAT);
@@ -46,7 +46,7 @@ bool BossNatureResistanceAction::isUseful()
return bossNatureResistanceTrigger.IsActive();
}
bool BossNatureResistanceAction::Execute(Event /*event*/)
bool BossNatureResistanceAction::Execute(Event event)
{
HunterNatureResistanceStrategy hunterNatureResistanceStrategy(botAI);
botAI->ChangeStrategy(ADD_STRATEGY_CHAR + hunterNatureResistanceStrategy.getName(), BotState::BOT_STATE_COMBAT);
@@ -60,7 +60,7 @@ bool BossShadowResistanceAction::isUseful()
return bossShadowResistanceTrigger.IsActive();
}
bool BossShadowResistanceAction::Execute(Event /*event*/)
bool BossShadowResistanceAction::Execute(Event event)
{
PaladinShadowResistanceStrategy paladinShadowResistanceStrategy(botAI);
botAI->ChangeStrategy(ADD_STRATEGY_CHAR + paladinShadowResistanceStrategy.getName(), BotState::BOT_STATE_COMBAT);

View File

@@ -175,7 +175,7 @@ bool BuyAction::Execute(Event event)
if (needMoneyFor == NeedMoneyFor::gear)
{
botAI->DoSpecificAction("equip upgrades packet action");
botAI->DoSpecificAction("equip upgrades");
}
}
}
@@ -206,7 +206,7 @@ bool BuyAction::Execute(Event event)
if (usage == ITEM_USAGE_REPLACE || usage == ITEM_USAGE_EQUIP ||
usage == ITEM_USAGE_BAD_EQUIP || usage == ITEM_USAGE_BROKEN_EQUIP)
{
botAI->DoSpecificAction("equip upgrades packet action");
botAI->DoSpecificAction("equip upgrades");
break;
}
}

View File

@@ -7,14 +7,12 @@
#include "Player.h"
#include "PlayerbotAI.h"
bool CancelChannelAction::Execute(Event /*event*/)
bool CancelChannelAction::Execute(Event event)
{
if (bot->GetCurrentSpell(CURRENT_CHANNELED_SPELL))
{
bot->InterruptSpell(CURRENT_CHANNELED_SPELL);
return true;
}
return false;
}

View File

@@ -334,7 +334,7 @@ bool CastRandomSpellAction::castSpell(uint32 spellId, WorldObject* wo)
return botAI->CastSpell(spellId, wo->GetPositionX(), wo->GetPositionY(), wo->GetPositionZ());
}
bool DisEnchantRandomItemAction::Execute(Event /*event*/)
bool DisEnchantRandomItemAction::Execute(Event event)
{
std::vector<Item*> items =
AI_VALUE2(std::vector<Item*>, "inventory items", "usage " + std::to_string(ITEM_USAGE_DISENCHANT));

View File

@@ -10,9 +10,9 @@
#include "Event.h"
#include "PlayerbotAIConfig.h"
#include "PlayerbotFactory.h"
#include "Playerbots.h"
#include "AiObjectContext.h"
#include "Log.h"
#include "RandomPlayerbotMgr.h"
bool ChangeTalentsAction::Execute(Event event)
{
@@ -184,7 +184,7 @@ std::string ChangeTalentsAction::SpecApply(std::string param)
// // }
// // }
// return ret;
// return std::move(ret);
// }
// std::vector<TalentPath*> ChangeTalentsAction::getPremadePaths(TalentSpec* oldSpec)
@@ -201,7 +201,7 @@ std::string ChangeTalentsAction::SpecApply(std::string param)
// // }
// // }
// return ret;
// return std::move(ret);
// }
// TalentPath* ChangeTalentsAction::getPremadePath(uint32 id)
@@ -368,11 +368,11 @@ std::string ChangeTalentsAction::SpecApply(std::string param)
// return nullptr;
// }
bool AutoSetTalentsAction::Execute(Event /*event*/)
bool AutoSetTalentsAction::Execute(Event event)
{
std::ostringstream out;
if (!PlayerbotAIConfig::instance().autoPickTalents || !RandomPlayerbotMgr::instance().IsRandomBot(bot))
if (!sPlayerbotAIConfig.autoPickTalents || !sRandomPlayerbotMgr.IsRandomBot(bot))
return false;
if (bot->GetFreeTalentPoints() <= 0)

View File

@@ -42,7 +42,7 @@ void PositionsResetAction::SetStayPosition(float x, float y, float z)
posMap["stay"] = pos;
}
bool FollowChatShortcutAction::Execute(Event /*event*/)
bool FollowChatShortcutAction::Execute(Event event)
{
Player* master = GetMaster();
if (!master)
@@ -68,7 +68,9 @@ bool FollowChatShortcutAction::Execute(Event /*event*/)
std::string const target = formation->GetTargetName();
bool moved = false;
if (!target.empty())
{
moved = Follow(AI_VALUE(Unit*, target));
}
else
{
WorldLocation loc = formation->GetLocation();
@@ -81,7 +83,9 @@ bool FollowChatShortcutAction::Execute(Event /*event*/)
}
if (Pet* pet = bot->GetPet())
{
botAI->PetFollow();
}
if (moved)
{
@@ -112,7 +116,7 @@ bool FollowChatShortcutAction::Execute(Event /*event*/)
return true;
}
bool StayChatShortcutAction::Execute(Event /*event*/)
bool StayChatShortcutAction::Execute(Event event)
{
Player* master = GetMaster();
if (!master)
@@ -129,7 +133,7 @@ bool StayChatShortcutAction::Execute(Event /*event*/)
return true;
}
bool MoveFromGroupChatShortcutAction::Execute(Event /*event*/)
bool MoveFromGroupChatShortcutAction::Execute(Event event)
{
Player* master = GetMaster();
if (!master)
@@ -144,7 +148,7 @@ bool MoveFromGroupChatShortcutAction::Execute(Event /*event*/)
return true;
}
bool FleeChatShortcutAction::Execute(Event /*event*/)
bool FleeChatShortcutAction::Execute(Event event)
{
Player* master = GetMaster();
if (!master)
@@ -167,7 +171,7 @@ bool FleeChatShortcutAction::Execute(Event /*event*/)
return true;
}
bool GoawayChatShortcutAction::Execute(Event /*event*/)
bool GoawayChatShortcutAction::Execute(Event event)
{
Player* master = GetMaster();
if (!master)
@@ -184,7 +188,7 @@ bool GoawayChatShortcutAction::Execute(Event /*event*/)
return true;
}
bool GrindChatShortcutAction::Execute(Event /*event*/)
bool GrindChatShortcutAction::Execute(Event event)
{
Player* master = GetMaster();
if (!master)
@@ -200,7 +204,7 @@ bool GrindChatShortcutAction::Execute(Event /*event*/)
return true;
}
bool TankAttackChatShortcutAction::Execute(Event /*event*/)
bool TankAttackChatShortcutAction::Execute(Event event)
{
Player* master = GetMaster();
if (!master)
@@ -220,7 +224,7 @@ bool TankAttackChatShortcutAction::Execute(Event /*event*/)
return true;
}
bool MaxDpsChatShortcutAction::Execute(Event /*event*/)
bool MaxDpsChatShortcutAction::Execute(Event event)
{
Player* master = GetMaster();
if (!master)
@@ -237,21 +241,7 @@ 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*/)
bool BwlChatShortcutAction::Execute(Event event)
{
Player* master = GetMaster();
if (!master)

View File

@@ -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:

View File

@@ -7,10 +7,9 @@
#include "Event.h"
#include "GuildTaskMgr.h"
#include "PlayerbotAIConfig.h"
#include "PlayerbotAI.h"
#include "Playerbots.h"
bool CheckMailAction::Execute(Event /*event*/)
bool CheckMailAction::Execute(Event event)
{
WorldPacket p;
bot->GetSession()->HandleQueryNextMailTime(p);
@@ -29,7 +28,7 @@ bool CheckMailAction::Execute(Event /*event*/)
continue;
uint32 account = owner->GetSession()->GetAccountId();
if (PlayerbotAIConfig::instance().IsInRandomAccountList(account))
if (sPlayerbotAIConfig.IsInRandomAccountList(account))
continue;
ProcessMail(mail, owner, trans);

View File

@@ -55,6 +55,63 @@ MountData CollectMountData(const Player* bot)
return data;
}
bool CheckMountStateAction::isUseful()
{
// Not useful when:
if (botAI->IsInVehicle() || bot->isDead() || bot->HasUnitState(UNIT_STATE_IN_FLIGHT) ||
!bot->IsOutdoors() || bot->InArena())
return false;
master = GetMaster();
// Get shapeshift states, only applicable when there's a master
if (master)
{
botInShapeshiftForm = bot->GetShapeshiftForm();
masterInShapeshiftForm = master->GetShapeshiftForm();
}
// Not useful when in combat and not currently mounted / travel formed
if ((bot->IsInCombat() || botAI->GetState() == BOT_STATE_COMBAT) &&
!bot->IsMounted() && botInShapeshiftForm != FORM_TRAVEL && botInShapeshiftForm != FORM_FLIGHT && botInShapeshiftForm != FORM_FLIGHT_EPIC)
return false;
// In addition to checking IsOutdoors, also check whether bot is clipping below floor slightly because that will
// cause bot to falsly indicate they are outdoors. This fixes bug where bot tries to mount indoors (which seems
// to mostly be an issue in tunnels of WSG and AV)
float posZ = bot->GetPositionZ();
float groundLevel = bot->GetMapWaterOrGroundLevel(bot->GetPositionX(), bot->GetPositionY(), posZ);
if (!bot->IsMounted() && !bot->HasWaterWalkAura() && posZ < groundLevel)
return false;
// Not useful when bot does not have mount strat and is not currently mounted
if (!GET_PLAYERBOT_AI(bot)->HasStrategy("mount", BOT_STATE_NON_COMBAT) && !bot->IsMounted())
return false;
// Not useful when level lower than minimum required
if (bot->GetLevel() < sPlayerbotAIConfig.useGroundMountAtMinLevel)
return false;
// Allow mounting while transformed only if the form allows it
if (bot->HasAuraType(SPELL_AURA_TRANSFORM) && bot->IsInDisallowedMountForm())
return false;
// BG Logic
if (bot->InBattleground())
{
// Do not use when carrying BG Flags
if (bot->HasAura(BG_WS_SPELL_WARSONG_FLAG) || bot->HasAura(BG_WS_SPELL_SILVERWING_FLAG) || bot->HasAura(BG_EY_NETHERSTORM_FLAG_SPELL))
return false;
// Only mount if BG starts in less than 30 sec
if (Battleground* bg = bot->GetBattleground())
if (bg->GetStatus() == STATUS_WAIT_JOIN && bg->GetStartDelayTime() > BG_START_DELAY_30S)
return false;
}
return true;
}
bool CheckMountStateAction::Execute(Event /*event*/)
{
// Determine if there are no attackers
@@ -125,63 +182,6 @@ bool CheckMountStateAction::Execute(Event /*event*/)
return false;
}
bool CheckMountStateAction::isUseful()
{
// Not useful when:
if (botAI->IsInVehicle() || bot->isDead() || bot->HasUnitState(UNIT_STATE_IN_FLIGHT) ||
!bot->IsOutdoors() || bot->InArena())
return false;
master = GetMaster();
// Get shapeshift states, only applicable when there's a master
if (master)
{
botInShapeshiftForm = bot->GetShapeshiftForm();
masterInShapeshiftForm = master->GetShapeshiftForm();
}
// Not useful when in combat and not currently mounted / travel formed
if ((bot->IsInCombat() || botAI->GetState() == BOT_STATE_COMBAT) &&
!bot->IsMounted() && botInShapeshiftForm != FORM_TRAVEL && botInShapeshiftForm != FORM_FLIGHT && botInShapeshiftForm != FORM_FLIGHT_EPIC)
return false;
// In addition to checking IsOutdoors, also check whether bot is clipping below floor slightly because that will
// cause bot to falsly indicate they are outdoors. This fixes bug where bot tries to mount indoors (which seems
// to mostly be an issue in tunnels of WSG and AV)
float posZ = bot->GetPositionZ();
float groundLevel = bot->GetMapWaterOrGroundLevel(bot->GetPositionX(), bot->GetPositionY(), posZ);
if (!bot->IsMounted() && !bot->HasWaterWalkAura() && posZ < groundLevel)
return false;
// Not useful when bot does not have mount strat and is not currently mounted
if (!GET_PLAYERBOT_AI(bot)->HasStrategy("mount", BOT_STATE_NON_COMBAT) && !bot->IsMounted())
return false;
// Not useful when level lower than minimum required
if (bot->GetLevel() < sPlayerbotAIConfig.useGroundMountAtMinLevel)
return false;
// Allow mounting while transformed only if the form allows it
if (bot->HasAuraType(SPELL_AURA_TRANSFORM) && bot->IsInDisallowedMountForm())
return false;
// BG Logic
if (bot->InBattleground())
{
// Do not use when carrying BG Flags
if (bot->HasAura(BG_WS_SPELL_WARSONG_FLAG) || bot->HasAura(BG_WS_SPELL_SILVERWING_FLAG) || bot->HasAura(BG_EY_NETHERSTORM_FLAG_SPELL))
return false;
// Only mount if BG starts in less than 30 sec
if (Battleground* bg = bot->GetBattleground())
if (bg->GetStatus() == STATUS_WAIT_JOIN && bg->GetStartDelayTime() > BG_START_DELAY_30S)
return false;
}
return true;
}
bool CheckMountStateAction::Mount()
{
// Remove current Shapeshift if need be

View File

@@ -6,15 +6,12 @@
#include "CheckValuesAction.h"
#include "Event.h"
#include "Playerbots.h"
#include "ServerFacade.h"
#include "PlayerbotAI.h"
#include "TravelNode.h"
#include "AiObjectContext.h"
CheckValuesAction::CheckValuesAction(PlayerbotAI* botAI) : Action(botAI, "check values") {}
bool CheckValuesAction::Execute(Event /*event*/)
bool CheckValuesAction::Execute(Event event)
{
if (botAI->HasStrategy("debug move", BOT_STATE_NON_COMBAT))
{

View File

@@ -6,6 +6,7 @@
#include <random>
#include "ChooseRpgTargetAction.h"
#include "BattlegroundMgr.h"
#include "BudgetValues.h"
#include "ChatHelper.h"
#include "Event.h"
@@ -13,6 +14,7 @@
#include "GuildCreateActions.h"
#include "Playerbots.h"
#include "RpgSubActions.h"
#include "Util.h"
#include "ServerFacade.h"
#include "PossibleRpgTargetsValue.h"
@@ -110,8 +112,9 @@ float ChooseRpgTargetAction::getMaxRelevance(GuidPosition guidP)
return floor((maxRelevance - 1.0) * 1000.0f);
}
bool ChooseRpgTargetAction::Execute(Event /*event*/)
bool ChooseRpgTargetAction::Execute(Event event)
{
//TravelTarget* travelTarget = AI_VALUE(TravelTarget*, "travel target"); //not used, line marked for removal.
Player* master = botAI->GetMaster();
GuidPosition masterRpgTarget;
if (master && master != bot && GET_PLAYERBOT_AI(master) && master->GetMapId() == bot->GetMapId() && !master->IsBeingTeleported())
@@ -123,6 +126,7 @@ bool ChooseRpgTargetAction::Execute(Event /*event*/)
master = nullptr;
std::unordered_map<ObjectGuid, uint32> targets;
// uint32 num = 0; //not used, line marked for removal.
GuidVector possibleTargets = AI_VALUE(GuidVector, "possible rpg targets");
GuidVector possibleObjects = AI_VALUE(GuidVector, "nearest game objects no los");
GuidVector possiblePlayers = AI_VALUE(GuidVector, "nearest friendly players");
@@ -316,7 +320,7 @@ bool ChooseRpgTargetAction::isFollowValid(Player* bot, WorldPosition pos)
inDungeon = true;
if (realMaster && realMaster->IsInWorld() && realMaster->GetMap()->IsDungeon() &&
(realMaster->GetMapId() != pos.GetMapId()))
(realMaster->GetMapId() != pos.getMapId()))
return false;
}
@@ -330,7 +334,7 @@ bool ChooseRpgTargetAction::isFollowValid(Player* bot, WorldPosition pos)
return false;
Formation* formation = AI_VALUE(Formation*, "formation");
float distance = groupLeader->GetDistance2d(pos.GetPositionX(), pos.GetPositionY());
float distance = groupLeader->GetDistance2d(pos.getX(), pos.getY());
if (!botAI->HasActivePlayerMaster() && distance < 50.0f)
{

View File

@@ -30,15 +30,38 @@ bool AttackEnemyFlagCarrierAction::isUseful()
PlayerHasFlag::IsCapturingFlag(bot);
}
bool AggressiveTargetAction::isUseful()
bool AttackAnythingAction::isUseful()
{
if (!bot || !botAI) // Prevents invalid accesses
return false;
if (!botAI->AllowActivity(GRIND_ACTIVITY)) // Bot cannot be active
return false;
if (botAI->HasStrategy("stay", BOT_STATE_NON_COMBAT))
return false;
if (bot->IsInCombat())
return false;
Unit* target = GetTarget();
if (!target || !target->IsInWorld()) // Checks if the target is valid and in the world
return false;
std::string const name = std::string(target->GetName());
if (!name.empty() &&
(name.find("Dummy") != std::string::npos ||
name.find("Charge Target") != std::string::npos ||
name.find("Melee Target") != std::string::npos ||
name.find("Ranged Target") != std::string::npos))
{
return false;
}
return true;
}
bool DropTargetAction::Execute(Event /*event*/)
bool DropTargetAction::Execute(Event event)
{
Unit* target = context->GetValue<Unit*>("current target")->Get();
if (target && target->isDead())
@@ -104,38 +127,7 @@ bool AttackAnythingAction::Execute(Event event)
return result;
}
bool AttackAnythingAction::isUseful()
{
if (!bot || !botAI) // Prevents invalid accesses
return false;
if (!botAI->AllowActivity(GRIND_ACTIVITY)) // Bot cannot be active
return false;
if (botAI->HasStrategy("stay", BOT_STATE_NON_COMBAT))
return false;
if (bot->IsInCombat())
return false;
Unit* target = GetTarget();
if (!target || !target->IsInWorld()) // Checks if the target is valid and in the world
return false;
std::string const name = std::string(target->GetName());
if (!name.empty() &&
(name.find("Dummy") != std::string::npos ||
name.find("Charge Target") != std::string::npos ||
name.find("Melee Target") != std::string::npos ||
name.find("Ranged Target") != std::string::npos))
{
return false;
}
return true;
}
bool AttackAnythingAction::isPossible() { return GetTarget() && AttackAction::isPossible(); }
bool AttackAnythingAction::isPossible() { return AttackAction::isPossible() && GetTarget(); }
bool DpsAssistAction::isUseful()
{
@@ -145,7 +137,7 @@ bool DpsAssistAction::isUseful()
return true;
}
bool AttackRtiTargetAction::Execute(Event /*event*/)
bool AttackRtiTargetAction::Execute(Event event)
{
Unit* rtiTarget = AI_VALUE(Unit*, "rti target");

View File

@@ -35,15 +35,6 @@ public:
std::string const GetTargetName() override { return "tank target"; }
};
class AggressiveTargetAction : public AttackAction
{
public:
AggressiveTargetAction(PlayerbotAI* botAI) : AttackAction(botAI, "aggressive target") {}
std::string const GetTargetName() override { return "aggressive target"; }
bool isUseful() override;
};
class AttackAnythingAction : public AttackAction
{
public:

View File

@@ -9,7 +9,7 @@
#include "LootObjectStack.h"
#include "Playerbots.h"
bool ChooseTravelTargetAction::Execute(Event /*event*/)
bool ChooseTravelTargetAction::Execute(Event event)
{
// Player* requester = event.getOwner() ? event.getOwner() : GetMaster(); //not used, line marked for removal.
@@ -232,6 +232,15 @@ void ChooseTravelTargetAction::ReportTravelTarget(TravelTarget* newTarget, Trave
QuestTravelDestination* QuestDestination = (QuestTravelDestination*)destination;
Quest const* quest = QuestDestination->GetQuestTemplate();
WorldPosition botLocation(bot);
CreatureTemplate const* cInfo = nullptr;
GameObjectTemplate const* gInfo = nullptr;
if (destination->getEntry() > 0)
cInfo = sObjectMgr->GetCreatureTemplate(destination->getEntry());
else
gInfo = sObjectMgr->GetGameObjectTemplate(destination->getEntry() * -1);
std::string Sub;
if (newTarget->isGroupCopy())
@@ -814,6 +823,10 @@ char* strstri(char const* haystack, char const* needle);
TravelDestination* ChooseTravelTargetAction::FindDestination(Player* bot, std::string const name, bool zones, bool npcs, bool quests, bool mobs, bool bosses)
{
PlayerbotAI* botAI = GET_PLAYERBOT_AI(bot);
// AiObjectContext* context = botAI->GetAiObjectContext(); //not used, line marked for removal.
std::vector<TravelDestination*> dests;
//Quests

View File

@@ -7,11 +7,7 @@
#include "ChooseTravelTargetAction.h"
#include "MapMgr.h"
#include "TravelMgr.h"
#include "Player.h"
#include "PlayerbotAI.h"
#include "SpellMgr.h"
#include "Spell.h"
#include "Playerbots.h"
bool DebugAction::Execute(Event event)
{
@@ -32,8 +28,8 @@ bool DebugAction::Execute(Event event)
uint32 areaId = 0;
uint32 zoneId = 0;
sMapMgr->GetZoneAndAreaId(PHASEMASK_NORMAL, zoneId, areaId, pos.GetMapId(), pos.GetPositionX(), pos.GetPositionY(),
pos.GetPositionZ());
sMapMgr->GetZoneAndAreaId(PHASEMASK_NORMAL, zoneId, areaId, pos.getMapId(), pos.getX(), pos.getY(),
pos.getZ());
std::ostringstream out;
out << zoneId << "," << areaId << "," << (pos.getAreaName().empty() ? "none" : pos.getAreaName()) << ",";
@@ -302,7 +298,7 @@ bool DebugAction::Execute(Event event)
for (auto p : ppath)
{
Creature* wpCreature =
bot->SummonCreature(1, p.GetPositionX(), p.GetPositionY(), p.GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 20000.0f);
bot->SummonCreature(1, p.getX(), p.getY(), p.getZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 20000.0f);
// addAura(246, wpCreature);
units.push_back(wpCreature->GetGUID());
@@ -329,11 +325,11 @@ bool DebugAction::Execute(Event event)
WorldPosition botPos(bot);
WorldPosition botPos1 = botPos;
botPos.setX(botPos.GetPositionX() + cos(ang) * dist);
botPos.setY(botPos.GetPositionY() + sin(ang) * dist);
botPos.setX(botPos.getX() + cos(ang) * dist);
botPos.setY(botPos.getY() + sin(ang) * dist);
botPos.setZ(botPos.getHeight() + 2);
Creature* wpCreature = bot->SummonCreature(2334, botPos.GetPositionX(), botPos.GetPositionY(), botPos.GetPositionZ(), 0,
Creature* wpCreature = bot->SummonCreature(2334, botPos.getX(), botPos.getY(), botPos.getZ(), 0,
TEMPSUMMON_TIMED_DESPAWN, 10000.0f);
FakeSpell(spellEffect, wpCreature, wpCreature, prev->GetGUID(), {}, {}, botPos, botPos);
@@ -356,11 +352,11 @@ bool DebugAction::Execute(Event event)
WorldPosition botPos(bot);
WorldPosition botPos1 = botPos;
botPos.setX(botPos.GetPositionX() + cos(ang) * dist);
botPos.setY(botPos.GetPositionY() + sin(ang) * dist);
botPos.setX(botPos.getX() + cos(ang) * dist);
botPos.setY(botPos.getY() + sin(ang) * dist);
botPos.setZ(botPos.getHeight() + 2);
Creature* wpCreature = bot->SummonCreature(2334, botPos.GetPositionX(), botPos.GetPositionY(), botPos.GetPositionZ(), 0,
Creature* wpCreature = bot->SummonCreature(2334, botPos.getX(), botPos.getY(), botPos.getZ(), 0,
TEMPSUMMON_TIMED_DESPAWN, 10000.0f);
if (wpCreature)
@@ -387,11 +383,11 @@ bool DebugAction::Execute(Event event)
WorldPosition botPos(bot);
WorldPosition botPos1 = botPos;
botPos.setX(botPos.GetPositionX() + cos(ang) * dist);
botPos.setY(botPos.GetPositionY() + sin(ang) * dist);
botPos.setX(botPos.getX() + cos(ang) * dist);
botPos.setY(botPos.getY() + sin(ang) * dist);
botPos.setZ(botPos.getHeight() + 2);
Creature* wpCreature = bot->SummonCreature(2334, botPos.GetPositionX(), botPos.GetPositionY(), botPos.GetPositionZ(), 0,
Creature* wpCreature = bot->SummonCreature(2334, botPos.getX(), botPos.getY(), botPos.getZ(), 0,
TEMPSUMMON_TIMED_DESPAWN, 5000.0f + i * 100.0f);
wpCreature->SetObjectScale(0.5f);
@@ -415,11 +411,11 @@ bool DebugAction::Execute(Event event)
WorldPosition botPos(bot);
botPos.setX(botPos.GetPositionX() + cos(ang) * dist);
botPos.setY(botPos.GetPositionY() + sin(ang) * dist);
botPos.setX(botPos.getX() + cos(ang) * dist);
botPos.setY(botPos.getY() + sin(ang) * dist);
botPos.setZ(botPos.getHeight() + 2);
Creature* wpCreature = bot->SummonCreature(2334, botPos.GetPositionX(), botPos.GetPositionY(), botPos.GetPositionZ(), 0,
Creature* wpCreature = bot->SummonCreature(2334, botPos.getX(), botPos.getY(), botPos.getZ(), 0,
TEMPSUMMON_TIMED_DESPAWN, 10000.0f);
units.push_back(wpCreature->GetGUID());
@@ -484,13 +480,13 @@ bool DebugAction::Execute(Event event)
uint32 effect = dx + dy * 10 + spellEffect * 100;
WorldPosition botPos(bot);
botPos.setX(botPos.GetPositionX() + (dx - 5) * 5);
botPos.setY(botPos.GetPositionY() + (dy - 5) * 5);
botPos.setX(botPos.getX() + (dx - 5) * 5);
botPos.setY(botPos.getY() + (dy - 5) * 5);
botPos.setZ(botPos.getHeight());
Creature* wpCreature =
bot->SummonCreature((dy == 0 && (dx == 0 || dx == 2)) ? 6 : 2, botPos.GetPositionX(), botPos.GetPositionY(),
botPos.GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 10000.0f);
bot->SummonCreature((dy == 0 && (dx == 0 || dx == 2)) ? 6 : 2, botPos.getX(), botPos.getY(),
botPos.getZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 10000.0f);
if (wpCreature)
{
@@ -516,12 +512,12 @@ bool DebugAction::Execute(Event event)
uint32 effect = dx + dy * 10 + spellEffect * 100;
WorldPosition botPos(bot);
botPos.setX(botPos.GetPositionX() + (dx - 5) * 5);
botPos.setY(botPos.GetPositionY() + (dy - 5) * 5);
botPos.setX(botPos.getX() + (dx - 5) * 5);
botPos.setY(botPos.getY() + (dy - 5) * 5);
botPos.setZ(botPos.getHeight());
bot->SummonCreature(effect, botPos.GetPositionX(), botPos.GetPositionY(), botPos.GetPositionZ(), 0,
TEMPSUMMON_TIMED_DESPAWN, 10000.0f);
Creature* wpCreature = bot->SummonCreature(effect, botPos.getX(), botPos.getY(), botPos.getZ(), 0,
TEMPSUMMON_TIMED_DESPAWN, 10000.0f);
}
}
return true;
@@ -536,8 +532,8 @@ bool DebugAction::Execute(Event event)
uint32 effect = dx + dy * 10 + spellEffect * 100;
WorldPosition botPos(bot);
botPos.setX(botPos.GetPositionX() + (dx - 5) * 5);
botPos.setY(botPos.GetPositionY() + (dy - 5) * 5);
botPos.setX(botPos.getX() + (dx - 5) * 5);
botPos.setY(botPos.getY() + (dy - 5) * 5);
botPos.setZ(botPos.getHeight());
FakeSpell(effect, bot, nullptr, ObjectGuid::Empty, {}, {}, botPos, botPos, true);
@@ -556,11 +552,11 @@ bool DebugAction::Execute(Event event)
uint32 effect = dx + dy * 10 + spellEffect * 100;
WorldPosition botPos(bot);
botPos.setX(botPos.GetPositionX() + (dx - 5) * 5);
botPos.setY(botPos.GetPositionY() + (dy - 5) * 5);
botPos.setX(botPos.getX() + (dx - 5) * 5);
botPos.setY(botPos.getY() + (dy - 5) * 5);
botPos.setZ(botPos.getHeight());
Creature* wpCreature = bot->SummonCreature(2334, botPos.GetPositionX(), botPos.GetPositionY(), botPos.GetPositionZ(), 0,
Creature* wpCreature = bot->SummonCreature(2334, botPos.getX(), botPos.getY(), botPos.getZ(), 0,
TEMPSUMMON_TIMED_DESPAWN, 10000.0f);
if (wpCreature)
@@ -572,7 +568,7 @@ bool DebugAction::Execute(Event event)
// wpCreature->SendMessageToSet(&data, true);
datMap.push_back(data);
// wpCreature->MonsterMoveWithSpeed(botPos.GetPositionX(), botPos.GetPositionY() + 80, botPos.GetPositionZ(), 8.0f, true,
// wpCreature->MonsterMoveWithSpeed(botPos.getX(), botPos.getY() + 80, botPos.getZ(), 8.0f, true,
// true);
}
}
@@ -604,13 +600,13 @@ bool DebugAction::Execute(Event event)
uint32 effect = dx + dy * 10 + spellEffect * 100;
WorldPosition botPos(bot);
botPos.setX(botPos.GetPositionX() + (dx - 5) * 5);
botPos.setY(botPos.GetPositionY() + (dy - 5) * 5);
botPos.setX(botPos.getX() + (dx - 5) * 5);
botPos.setY(botPos.getY() + (dy - 5) * 5);
botPos.setZ(botPos.getHeight());
Creature* wpCreature =
bot->SummonCreature((dy == 0 && (dx == 0 || dx == 2)) ? 6 : 2, botPos.GetPositionX(), botPos.GetPositionY(),
botPos.GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 10000.0f);
bot->SummonCreature((dy == 0 && (dx == 0 || dx == 2)) ? 6 : 2, botPos.getX(), botPos.getY(),
botPos.getZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 10000.0f);
if (wpCreature)
{
@@ -650,12 +646,12 @@ bool DebugAction::Execute(Event event)
uint32 effect = dx + dy * 10 + spellEffect * 100;
WorldPosition botPos(bot);
botPos.setX(botPos.GetPositionX() + (dx - 5) * 5);
botPos.setY(botPos.GetPositionY() + (dy - 5) * 5);
botPos.setX(botPos.getX() + (dx - 5) * 5);
botPos.setY(botPos.getY() + (dy - 5) * 5);
botPos.setZ(botPos.getHeight());
wpCreature = bot->SummonCreature((dy == 0 && (dx == 0 || dx == 2)) ? 6 : 2, botPos.GetPositionX(),
botPos.GetPositionY(), botPos.GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 10000.0f);
wpCreature = bot->SummonCreature((dy == 0 && (dx == 0 || dx == 2)) ? 6 : 2, botPos.getX(),
botPos.getY(), botPos.getZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 10000.0f);
if (wpCreature && lCreature)
{
@@ -679,11 +675,11 @@ bool DebugAction::Execute(Event event)
uint32 effect = dx + dy * 10 + spellEffect * 100;
WorldPosition botPos(bot);
botPos.setX(botPos.GetPositionX() + (dx - 5) * 5);
botPos.setY(botPos.GetPositionY() + (dy - 5) * 5);
botPos.setX(botPos.getX() + (dx - 5) * 5);
botPos.setY(botPos.getY() + (dy - 5) * 5);
botPos.setZ(botPos.getHeight());
wpCreature = bot->SummonCreature(2334, botPos.GetPositionX(), botPos.GetPositionY(), botPos.GetPositionZ(), 0,
wpCreature = bot->SummonCreature(2334, botPos.getX(), botPos.getY(), botPos.getZ(), 0,
TEMPSUMMON_TIMED_DESPAWN, 10000.0f);
if (wpCreature)
@@ -712,11 +708,11 @@ bool DebugAction::Execute(Event event)
{
WorldPosition botPos(bot);
botPos.setX(botPos.GetPositionX() + (dx - 5) * 5);
botPos.setY(botPos.GetPositionY() + (dy - 5) * 5);
botPos.setX(botPos.getX() + (dx - 5) * 5);
botPos.setY(botPos.getY() + (dy - 5) * 5);
botPos.setZ(botPos.getHeight());
Creature* wpCreature = bot->SummonCreature(2334, botPos.GetPositionX(), botPos.GetPositionY(), botPos.GetPositionZ(), 0,
Creature* wpCreature = bot->SummonCreature(2334, botPos.getX(), botPos.getY(), botPos.getZ(), 0,
TEMPSUMMON_TIMED_DESPAWN, 10000.0f);
all_targets.push_back(wpCreature->GetGUID());
@@ -792,11 +788,11 @@ bool DebugAction::Execute(Event event)
{
WorldPosition botPos(bot);
botPos.setX(botPos.GetPositionX() + (dx - 5) * 5);
botPos.setY(botPos.GetPositionY() + (dy - 5) * 5);
botPos.setX(botPos.getX() + (dx - 5) * 5);
botPos.setY(botPos.getY() + (dy - 5) * 5);
botPos.setZ(botPos.getHeight());
Creature* wpCreature = bot->SummonCreature(2334, botPos.GetPositionX(), botPos.GetPositionY(), botPos.GetPositionZ(), 0,
Creature* wpCreature = bot->SummonCreature(2334, botPos.getX(), botPos.getY(), botPos.getZ(), 0,
TEMPSUMMON_TIMED_DESPAWN, 10000.0f);
all_targets.push_back(wpCreature->GetGUID());
@@ -872,13 +868,13 @@ bool DebugAction::Execute(Event event)
uint32 effect = dx + dy * 10 + soundEffects * 100;
WorldPosition botPos(bot);
botPos.setX(botPos.GetPositionX() + (dx - 5) * 5);
botPos.setY(botPos.GetPositionY() + (dy - 5) * 5);
botPos.setX(botPos.getX() + (dx - 5) * 5);
botPos.setY(botPos.getY() + (dy - 5) * 5);
botPos.setZ(botPos.getHeight());
Creature* wpCreature =
bot->SummonCreature((dy == 0 && (dx == 0 || dx == 2)) ? 6 : 2, botPos.GetPositionX(), botPos.GetPositionY(),
botPos.GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 10000.0f);
bot->SummonCreature((dy == 0 && (dx == 0 || dx == 2)) ? 6 : 2, botPos.getX(), botPos.getY(),
botPos.getZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 10000.0f);
wpCreature->PlayDistanceSound(effect);
}
@@ -968,7 +964,7 @@ void DebugAction::FakeSpell(uint32 spellId, Unit* truecaster, Unit* caster, Obje
m_targets.SetDst(dest);
if ((spellInfo && spellInfo->Targets & TARGET_FLAG_SOURCE_LOCATION) || forceDest)
m_targets.SetSrc(source.GetPositionX(), source.GetPositionY(), source.GetPositionZ());
m_targets.SetSrc(source.getX(), source.getY(), source.getZ());
if (!forceDest && target)
if (!spellInfo ||

View File

@@ -6,19 +6,15 @@
#include "DelayAction.h"
#include "Event.h"
#include "PlayerbotAI.h"
#include "PlayerbotAIConfig.h"
#include "Playerbots.h"
bool DelayAction::Execute(Event /*event*/)
bool DelayAction::Execute(Event event)
{
const uint32 delay = PlayerbotAIConfig::instance().passiveDelay + PlayerbotAIConfig::instance().globalCoolDown;
uint32 delay = sPlayerbotAIConfig.passiveDelay + sPlayerbotAIConfig.globalCoolDown;
botAI->SetNextCheckDelay(delay);
return true;
}
bool DelayAction::isUseful()
{
return !botAI->AllowActivity(ALL_ACTIVITY);
}
bool DelayAction::isUseful() { return !botAI->AllowActivity(ALL_ACTIVITY); }

View File

@@ -39,7 +39,7 @@ void DestroyItemAction::DestroyItem(FindItemVisitor* visitor)
bool SmartDestroyItemAction::isUseful() { return !botAI->HasActivePlayerMaster(); }
bool SmartDestroyItemAction::Execute(Event /*event*/)
bool SmartDestroyItemAction::Execute(Event event)
{
uint8 bagSpace = AI_VALUE(uint8, "bag space");

View File

@@ -6,6 +6,7 @@
#include "EmoteAction.h"
#include "Event.h"
#include "PlayerbotTextMgr.h"
#include "Playerbots.h"
#include "ServerFacade.h"
@@ -786,7 +787,7 @@ bool EmoteAction::isUseful()
return time(nullptr) >= lastEmote;
}
bool TalkAction::Execute(Event /*event*/)
bool TalkAction::Execute(Event event)
{
Unit* target = botAI->GetUnit(AI_VALUE(ObjectGuid, "talk target"));
if (!target)

View File

@@ -85,8 +85,8 @@ void EquipAction::EquipItem(Item* item)
if (itemProto->Class == ITEM_CLASS_CONTAINER)
{
// Attempt to equip as a bag
Bag* pBag = reinterpret_cast<Bag*>(item);
uint8 newBagSlot = GetSmallestBagSlot();
if (newBagSlot > 0)
{
uint16 src = ((bagIndex << 8) | slot);
@@ -328,48 +328,12 @@ void EquipAction::EquipItem(Item* item)
botAI->TellMaster(out);
}
ItemIds EquipAction::SelectInventoryItemsToEquip()
{
CollectItemsVisitor visitor;
IterateItems(&visitor, ITERATE_ITEMS_IN_BAGS);
ItemIds items;
for (auto i = visitor.items.begin(); i != visitor.items.end(); ++i)
{
Item* item = *i;
if (!item)
continue;
ItemTemplate const* itemTemplate = item->GetTemplate();
if (!itemTemplate)
continue;
//TODO Expand to Glyphs and Gems, that can be placed in equipment
//Pre-filter non-equipable items
if (itemTemplate->InventoryType == INVTYPE_NON_EQUIP)
continue;
int32 randomProperty = item->GetItemRandomPropertyId();
uint32 itemId = item->GetTemplate()->ItemId;
std::string itemUsageParam;
if (randomProperty != 0)
itemUsageParam = std::to_string(itemId) + "," + std::to_string(randomProperty);
else
itemUsageParam = std::to_string(itemId);
ItemUsage usage = AI_VALUE2(ItemUsage, "item upgrade", itemUsageParam);
if (usage == ITEM_USAGE_EQUIP || usage == ITEM_USAGE_REPLACE || usage == ITEM_USAGE_BAD_EQUIP)
items.insert(itemId);
}
return items;
}
bool EquipUpgradesPacketAction::Execute(Event event)
bool EquipUpgradesAction::Execute(Event event)
{
if (!sPlayerbotAIConfig.autoEquipUpgradeLoot && !sRandomPlayerbotMgr.IsRandomBot(bot))
return false;
std::string const source = event.GetSource();
if (source == "trade status")
if (event.GetSource() == "trade status")
{
WorldPacket p(event.getPacket());
p.rpos(0);
@@ -380,7 +344,7 @@ bool EquipUpgradesPacketAction::Execute(Event event)
return false;
}
else if (source == "item push result")
if (event.GetSource() == "item push result")
{
WorldPacket p(event.getPacket());
p.rpos(0);
@@ -397,18 +361,72 @@ bool EquipUpgradesPacketAction::Execute(Event event)
p >> itemId;
ItemTemplate const* item = sObjectMgr->GetItemTemplate(itemId);
if (item->InventoryType == INVTYPE_NON_EQUIP)
if (item->Class == ITEM_CLASS_TRADE_GOODS && item->SubClass == ITEM_SUBCLASS_MEAT)
return false;
}
ItemIds items = SelectInventoryItemsToEquip();
CollectItemsVisitor visitor;
IterateItems(&visitor, ITERATE_ITEMS_IN_BAGS);
ItemIds items;
for (auto i = visitor.items.begin(); i != visitor.items.end(); ++i)
{
Item* item = *i;
if (!item)
break;
int32 randomProperty = item->GetItemRandomPropertyId();
uint32 itemId = item->GetTemplate()->ItemId;
std::string itemUsageParam;
if (randomProperty != 0)
{
itemUsageParam = std::to_string(itemId) + "," + std::to_string(randomProperty);
}
else
{
itemUsageParam = std::to_string(itemId);
}
ItemUsage usage = AI_VALUE2(ItemUsage, "item usage", itemUsageParam);
if (usage == ITEM_USAGE_EQUIP || usage == ITEM_USAGE_REPLACE || usage == ITEM_USAGE_BAD_EQUIP)
{
items.insert(itemId);
}
}
EquipItems(items);
return true;
}
bool EquipUpgradeAction::Execute(Event /*event*/)
bool EquipUpgradeAction::Execute(Event event)
{
ItemIds items = SelectInventoryItemsToEquip();
CollectItemsVisitor visitor;
IterateItems(&visitor, ITERATE_ITEMS_IN_BAGS);
ItemIds items;
for (auto i = visitor.items.begin(); i != visitor.items.end(); ++i)
{
Item* item = *i;
if (!item)
break;
int32 randomProperty = item->GetItemRandomPropertyId();
uint32 itemId = item->GetTemplate()->ItemId;
std::string itemUsageParam;
if (randomProperty != 0)
{
itemUsageParam = std::to_string(itemId) + "," + std::to_string(randomProperty);
}
else
{
itemUsageParam = std::to_string(itemId);
}
ItemUsage usage = AI_VALUE2(ItemUsage, "item usage", itemUsageParam);
if (usage == ITEM_USAGE_EQUIP || usage == ITEM_USAGE_REPLACE || usage == ITEM_USAGE_BAD_EQUIP)
{
items.insert(itemId);
}
}
EquipItems(items);
return true;
}

View File

@@ -8,7 +8,6 @@
#include "ChatHelper.h"
#include "InventoryAction.h"
#include "Item.h"
class FindItemVisitor;
class Item;
@@ -21,7 +20,6 @@ public:
bool Execute(Event event) override;
void EquipItems(ItemIds ids);
ItemIds SelectInventoryItemsToEquip();
private:
void EquipItem(FindItemVisitor* visitor);
@@ -29,10 +27,10 @@ private:
void EquipItem(Item* item);
};
class EquipUpgradesPacketAction : public EquipAction
class EquipUpgradesAction : public EquipAction
{
public:
explicit EquipUpgradesPacketAction(PlayerbotAI* botAI, std::string const name = "equip upgrades packet action") : EquipAction(botAI, name) {}
EquipUpgradesAction(PlayerbotAI* botAI, std::string const name = "equip upgrades") : EquipAction(botAI, name) {}
bool Execute(Event event) override;
};
@@ -40,7 +38,7 @@ public:
class EquipUpgradeAction : public EquipAction
{
public:
explicit EquipUpgradeAction(PlayerbotAI* botAI, std::string const name = "equip upgrade") : EquipAction(botAI, name) {}
EquipUpgradeAction(PlayerbotAI* botAI, std::string const name = "equip upgrade") : EquipAction(botAI, name) {}
bool Execute(Event event) override;
};

View File

@@ -246,7 +246,7 @@ WorldPosition FindFishingHole(PlayerbotAI* botAI)
return WorldPosition();
}
bool MoveNearWaterAction::Execute(Event /*event*/)
bool MoveNearWaterAction::Execute(Event event)
{
WorldPosition landSpot = AI_VALUE(WorldPosition, "fishing spot");
if (landSpot.IsValid())
@@ -262,7 +262,7 @@ bool MoveNearWaterAction::isUseful()
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;
bot->GetExactDist(&pos) < 0.1f;
}
@@ -292,6 +292,7 @@ bool MoveNearWaterAction::isPossible()
// 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())
{
@@ -322,6 +323,7 @@ bool MoveNearWaterAction::isPossible()
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);
@@ -334,7 +336,7 @@ bool MoveNearWaterAction::isPossible()
return false;
}
bool EquipFishingPoleAction::Execute(Event /*event*/)
bool EquipFishingPoleAction::Execute(Event event)
{
if (!_pole)
return false;
@@ -461,7 +463,7 @@ bool UseBobberAction::isUseful()
return AI_VALUE(bool, "can use fishing bobber");
}
bool UseBobberAction::Execute(Event /*event*/)
bool UseBobberAction::Execute(Event event)
{
GuidVector gos = AI_VALUE(GuidVector, "nearest game objects no los");
for (auto const& guid : gos)
@@ -483,7 +485,7 @@ bool UseBobberAction::Execute(Event /*event*/)
return false;
}
bool EndMasterFishingAction::Execute(Event /*event*/)
bool EndMasterFishingAction::Execute(Event event)
{
botAI->ChangeStrategy("-master fishing", BOT_STATE_NON_COMBAT);
return true;
@@ -501,7 +503,7 @@ bool EndMasterFishingAction::isUseful()
return !nearWater.IsValid();
}
bool RemoveBobberStrategyAction::Execute(Event /*event*/)
bool RemoveBobberStrategyAction::Execute(Event event)
{
botAI->ChangeStrategy("-use bobber", BOT_STATE_NON_COMBAT);
return true;

View File

@@ -7,24 +7,22 @@
#define _PLAYERBOT_FISHINGACTION_H
#include "Action.h"
#include "Event.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);
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") {}
FishingAction(PlayerbotAI* botAI) : Action(botAI, "go fishing"){}
bool Execute(Event event) override;
bool isUseful() override;
};
@@ -33,10 +31,8 @@ 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;
};
@@ -44,8 +40,7 @@ private:
class MoveNearWaterAction : public MovementAction
{
public:
MoveNearWaterAction(PlayerbotAI* botAI) : MovementAction(botAI, "move near water") {}
MoveNearWaterAction(PlayerbotAI* botAI): MovementAction(botAI, "move near water") {}
bool Execute(Event event) override;
bool isUseful() override;
bool isPossible() override;
@@ -55,7 +50,6 @@ class UseBobberAction : public Action
{
public:
UseBobberAction(PlayerbotAI* botAI) : Action(botAI, "use fishing bobber") {}
bool Execute(Event event) override;
bool isUseful() override;
};
@@ -64,7 +58,6 @@ class EndMasterFishingAction : public Action
{
public:
EndMasterFishingAction(PlayerbotAI* botAI) : Action(botAI, "end master fishing") {}
bool Execute(Event event) override;
bool isUseful() override;
};
@@ -73,8 +66,6 @@ class RemoveBobberStrategyAction : public Action
{
public:
RemoveBobberStrategyAction(PlayerbotAI* botAI) : Action(botAI, "remove bobber strategy") {}
bool Execute(Event event) override;
};
#endif

View File

@@ -5,14 +5,17 @@
#include "FollowActions.h"
#include <cstddef>
#include "Event.h"
#include "Formations.h"
#include "LastMovementValue.h"
#include "PlayerbotAI.h"
#include "Playerbots.h"
#include "ServerFacade.h"
#include "SharedDefines.h"
bool FollowAction::Execute(Event /*event*/)
bool FollowAction::Execute(Event event)
{
Formation* formation = AI_VALUE(Formation*, "formation");
std::string const target = formation->GetTargetName();
@@ -113,7 +116,7 @@ bool FollowAction::CanDeadFollow(Unit* target)
return true;
}
bool FleeToGroupLeaderAction::Execute(Event /*event*/)
bool FleeToGroupLeaderAction::Execute(Event event)
{
Unit* fTarget = AI_VALUE(Unit*, "group leader");
bool canFollow = Follow(fTarget);

View File

@@ -11,6 +11,8 @@
#include "CreatureAI.h"
#include "Playerbots.h"
#include "CharmInfo.h"
#include "SharedDefines.h"
#include "ObjectGuid.h"
#include "SpellMgr.h"
#include "SpellInfo.h"
#include <vector>
@@ -52,7 +54,7 @@ bool MeleeAction::isUseful()
return true;
}
bool TogglePetSpellAutoCastAction::Execute(Event /*event*/)
bool TogglePetSpellAutoCastAction::Execute(Event event)
{
Pet* pet = bot->GetPet();
if (!pet)
@@ -117,7 +119,7 @@ bool TogglePetSpellAutoCastAction::Execute(Event /*event*/)
return toggled;
}
bool PetAttackAction::Execute(Event /*event*/)
bool PetAttackAction::Execute(Event event)
{
Guardian* pet = bot->GetGuardianPet();
if (!pet)

View File

@@ -17,17 +17,19 @@
#include "WorldPacket.h"
#include "Group.h"
#include "Chat.h"
#include "Language.h"
#include "GenericBuffUtils.h"
#include "PlayerbotAI.h"
using ai::buff::MakeAuraQualifierForBuff;
using ai::buff::UpgradeToGroupIfAppropriate;
CastSpellAction::CastSpellAction(PlayerbotAI* botAI, std::string const spell)
: Action(botAI, spell), range(botAI->GetRange("spell")), spell(spell)
{
}
bool CastSpellAction::Execute(Event /*event*/)
bool CastSpellAction::Execute(Event event)
{
if (spell == "conjure food" || spell == "conjure water")
{
@@ -76,35 +78,6 @@ bool CastSpellAction::Execute(Event /*event*/)
return botAI->CastSpell(spell, GetTarget());
}
bool CastSpellAction::isUseful()
{
if (botAI->IsInVehicle() && !botAI->IsInVehicle(false, false, true))
return false;
if (spell == "mount" && !bot->IsMounted() && !bot->IsInCombat())
return true;
if (spell == "mount" && bot->IsInCombat())
{
bot->Dismount();
return false;
}
Unit* spellTarget = GetTarget();
if (!spellTarget)
return false;
if (!spellTarget->IsInWorld() || spellTarget->GetMapId() != bot->GetMapId())
return false;
// float combatReach = bot->GetCombatReach() + target->GetCombatReach();
// if (!botAI->IsRanged(bot))
// combatReach += 4.0f / 3.0f;
return AI_VALUE2(bool, "spell cast useful", spell);
// && ServerFacade::instance().GetDistance2d(bot, target) <= (range + combatReach);
}
bool CastSpellAction::isPossible()
{
if (botAI->IsInVehicle() && !botAI->IsInVehicle(false, false, true))
@@ -133,6 +106,36 @@ bool CastSpellAction::isPossible()
return botAI->CanCastSpell(spell, GetTarget());
}
bool CastSpellAction::isUseful()
{
if (botAI->IsInVehicle() && !botAI->IsInVehicle(false, false, true))
return false;
if (spell == "mount" && !bot->IsMounted() && !bot->IsInCombat())
return true;
if (spell == "mount" && bot->IsInCombat())
{
bot->Dismount();
return false;
}
Unit* spellTarget = GetTarget();
if (!spellTarget)
return false;
if (!spellTarget->IsInWorld() || spellTarget->GetMapId() != bot->GetMapId())
return false;
// float combatReach = bot->GetCombatReach() + spellTarget->GetCombatReach();
// if (!botAI->IsRanged(bot))
// combatReach += 4.0f / 3.0f;
return spellTarget &&
AI_VALUE2(bool, "spell cast useful",
spell); // && ServerFacade::instance().GetDistance2d(bot, spellTarget) <= (range + combatReach);
}
CastMeleeSpellAction::CastMeleeSpellAction(PlayerbotAI* botAI, std::string const spell) : CastSpellAction(botAI, spell)
{
range = ATTACK_DISTANCE;
@@ -230,7 +233,7 @@ Value<Unit*>* BuffOnPartyAction::GetTargetValue()
return context->GetValue<Unit*>("party member without aura", MakeAuraQualifierForBuff(spell));
}
bool BuffOnPartyAction::Execute(Event /*event*/)
bool BuffOnPartyAction::Execute(Event event)
{
std::string castName = spell; // default = mono
@@ -287,7 +290,7 @@ Value<Unit*>* CastSnareSpellAction::GetTargetValue() { return context->GetValue<
Value<Unit*>* CastCrowdControlSpellAction::GetTargetValue() { return context->GetValue<Unit*>("cc target", getName()); }
bool CastCrowdControlSpellAction::Execute(Event /*event*/) { return botAI->CastSpell(getName(), GetTarget()); }
bool CastCrowdControlSpellAction::Execute(Event event) { return botAI->CastSpell(getName(), GetTarget()); }
bool CastCrowdControlSpellAction::isPossible() { return botAI->CanCastSpell(getName(), GetTarget()); }
@@ -305,13 +308,13 @@ bool CastVehicleSpellAction::isPossible()
bool CastVehicleSpellAction::isUseful() { return botAI->IsInVehicle(false, true); }
bool CastVehicleSpellAction::Execute(Event /*event*/)
bool CastVehicleSpellAction::Execute(Event event)
{
uint32 spellId = AI_VALUE2(uint32, "vehicle spell id", spell);
return botAI->CastVehicleSpell(spellId, GetTarget());
}
bool UseTrinketAction::Execute(Event /*event*/)
bool UseTrinketAction::Execute(Event event)
{
Item* trinket1 = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_TRINKET1);

View File

@@ -23,8 +23,8 @@ public:
std::string const GetTargetName() override { return "current target"; };
bool Execute(Event event) override;
bool isUseful() override;
bool isPossible() override;
bool isUseful() override;
ActionThreatType getThreatType() override { return ActionThreatType::Single; }
std::vector<NextAction> getPrerequisites() override

View File

@@ -11,7 +11,7 @@
std::vector<std::string> split(std::string const s, char delim);
bool GiveItemAction::Execute(Event /*event*/)
bool GiveItemAction::Execute(Event event)
{
Unit* target = GetTarget();
if (!target)
@@ -28,6 +28,7 @@ bool GiveItemAction::Execute(Event /*event*/)
if (receiverAi->GetAiObjectContext()->GetValue<uint32>("item count", item)->Get())
return true;
bool moved = false;
std::vector<Item*> items = InventoryAction::parseItems(item, ITERATE_ITEMS_IN_BAGS);
for (Item* item : items)
{
@@ -41,6 +42,7 @@ bool GiveItemAction::Execute(Event /*event*/)
bot->MoveItemFromInventory(item->GetBagSlot(), item->GetSlot(), true);
item->SetOwnerGUID(target->GetGUID());
receiver->MoveItemToInventory(dest, item, true);
moved = true;
std::ostringstream out;
out << "Got " << chat->FormatItem(item->GetTemplate(), item->GetCount()) << " from " << bot->GetName();

View File

@@ -10,7 +10,7 @@
GreetAction::GreetAction(PlayerbotAI* botAI) : Action(botAI, "greet") {}
bool GreetAction::Execute(Event /*event*/)
bool GreetAction::Execute(Event event)
{
ObjectGuid guid = AI_VALUE(ObjectGuid, "new player nearby");
if (!guid || !guid.IsPlayer())

View File

@@ -6,8 +6,7 @@
#include "GuildBankAction.h"
#include "GuildMgr.h"
#include "PlayerbotAI.h"
#include "AiObjectContext.h"
#include "Playerbots.h"
bool GuildBankAction::Execute(Event event)
{

View File

@@ -12,11 +12,12 @@
#include "Playerbots.h"
#include "RandomPlayerbotFactory.h"
#include "ServerFacade.h"
#include "SharedDefines.h"
#include "SharedDefines.h" // GOLD
bool BuyPetitionAction::Execute(Event /*event*/)
bool BuyPetitionAction::Execute(Event event)
{
GuidVector vendors = botAI->GetAiObjectContext()->GetValue<GuidVector>("nearest npcs")->Get();
bool vendored = false, result = false;
for (GuidVector::iterator i = vendors.begin(); i != vendors.end(); ++i)
{
ObjectGuid vendorguid = *i;
@@ -96,6 +97,7 @@ bool BuyPetitionAction::canBuyPetition(Player* bot)
bool PetitionOfferAction::Execute(Event event)
{
uint32 petitionEntry = 5863; // GUILD_CHARTER
std::vector<Item*> petitions = AI_VALUE2(std::vector<Item*>, "inventory items", chat->FormatQItem(5863));
if (petitions.empty())
@@ -150,7 +152,7 @@ bool PetitionOfferAction::Execute(Event event)
bool PetitionOfferAction::isUseful() { return !bot->GetGuildId(); }
bool PetitionOfferNearbyAction::Execute(Event /*event*/)
bool PetitionOfferNearbyAction::Execute(Event event)
{
uint32 found = 0;
@@ -207,9 +209,10 @@ bool PetitionOfferNearbyAction::isUseful()
AI_VALUE(uint8, "petition signs") < sWorld->getIntConfig(CONFIG_MIN_PETITION_SIGNS);
}
bool PetitionTurnInAction::Execute(Event /*event*/)
bool PetitionTurnInAction::Execute(Event event)
{
GuidVector vendors = botAI->GetAiObjectContext()->GetValue<GuidVector>("nearest npcs")->Get();
bool vendored = false, result = false;
std::vector<Item*> petitions = AI_VALUE2(std::vector<Item*>, "inventory items", chat->FormatQItem(5863));
if (petitions.empty())
@@ -294,7 +297,7 @@ bool PetitionTurnInAction::isUseful()
!context->GetValue<TravelTarget*>("travel target")->Get()->isTraveling();
}
bool BuyTabardAction::Execute(Event /*event*/)
bool BuyTabardAction::Execute(Event event)
{
bool canBuy = botAI->DoSpecificAction("buy", Event("buy tabard", "Hitem:5976:"));
if (canBuy && AI_VALUE2(uint32, "item count", chat->FormatQItem(5976)))

View File

@@ -128,7 +128,7 @@ bool GuildRemoveAction::PlayerIsValid(Player* member)
return member->GetGuildId() == bot->GetGuildId() && GetRankId(bot) < GetRankId(member);
};
bool GuildManageNearbyAction::Execute(Event /*event*/)
bool GuildManageNearbyAction::Execute(Event event)
{
uint32 found = 0;
@@ -149,6 +149,7 @@ bool GuildManageNearbyAction::Execute(Event /*event*/)
// Promote or demote nearby members based on chance.
if (player->GetGuildId() && player->GetGuildId() == bot->GetGuildId())
{
Guild::Member* member = guild->GetMember(player->GetGUID());
uint32 dCount = AI_VALUE(uint32, "death count");
if (!urand(0, 30) && dCount < 2 && guild->GetRankRights(botMember->GetRankId()) & GR_RIGHT_PROMOTE)

View File

@@ -7,13 +7,13 @@
#include "ChatActionContext.h"
#include "Event.h"
#include "AiObjectContext.h"
#include "Playerbots.h"
HelpAction::HelpAction(PlayerbotAI* botAI) : Action(botAI, "help") { chatContext = new ChatActionContext(); }
HelpAction::~HelpAction() { delete chatContext; }
bool HelpAction::Execute(Event /*event*/)
bool HelpAction::Execute(Event event)
{
TellChatCommands();
TellStrategies();

View File

@@ -6,16 +6,15 @@
#include "HireAction.h"
#include "Event.h"
#include "RandomPlayerbotMgr.h"
#include "PlayerbotAI.h"
#include "Playerbots.h"
bool HireAction::Execute(Event /*event*/)
bool HireAction::Execute(Event event)
{
Player* master = GetMaster();
if (!master)
return false;
if (!RandomPlayerbotMgr::instance().IsRandomBot(bot))
if (!sRandomPlayerbotMgr.IsRandomBot(bot))
return false;
uint32 account = master->GetSession()->GetAccountId();
@@ -40,7 +39,7 @@ bool HireAction::Execute(Event /*event*/)
return false;
}
uint32 discount = RandomPlayerbotMgr::instance().GetTradeDiscount(bot, master);
uint32 discount = sRandomPlayerbotMgr.GetTradeDiscount(bot, master);
uint32 m = 1 + (bot->GetLevel() / 10);
uint32 moneyReq = m * 5000 * bot->GetLevel();
if (discount < moneyReq)
@@ -55,7 +54,7 @@ bool HireAction::Execute(Event /*event*/)
botAI->TellMaster("I will join you at your next relogin");
bot->SetMoney(moneyReq);
RandomPlayerbotMgr::instance().Remove(bot);
sRandomPlayerbotMgr.Remove(bot);
CharacterDatabase.Execute("UPDATE characters SET account = {} WHERE guid = {}", account,
bot->GetGUID().GetCounter());

View File

@@ -10,7 +10,7 @@
ImbueWithPoisonAction::ImbueWithPoisonAction(PlayerbotAI* botAI) : Action(botAI, "apply poison") {}
bool ImbueWithPoisonAction::Execute(Event /*event*/)
bool ImbueWithPoisonAction::Execute(Event event)
{
if (bot->IsInCombat())
return false;
@@ -103,7 +103,7 @@ bool ImbueWithPoisonAction::Execute(Event /*event*/)
// Search and apply stone to weapons
ImbueWithStoneAction::ImbueWithStoneAction(PlayerbotAI* botAI) : Action(botAI, "apply stone") {}
bool ImbueWithStoneAction::Execute(Event /*event*/)
bool ImbueWithStoneAction::Execute(Event event)
{
if (bot->IsInCombat())
return false;
@@ -148,7 +148,7 @@ bool ImbueWithStoneAction::Execute(Event /*event*/)
// Search and apply oil to weapons
ImbueWithOilAction::ImbueWithOilAction(PlayerbotAI* botAI) : Action(botAI, "apply oil") {}
bool ImbueWithOilAction::Execute(Event /*event*/)
bool ImbueWithOilAction::Execute(Event event)
{
if (bot->IsInCombat())
return false;
@@ -201,7 +201,7 @@ static const uint32 uPrioritizedHealingItemIds[19] = {
TryEmergencyAction::TryEmergencyAction(PlayerbotAI* botAI) : Action(botAI, "try emergency") {}
bool TryEmergencyAction::Execute(Event /*event*/)
bool TryEmergencyAction::Execute(Event event)
{
// Do not use consumable if bot can heal self
if ((botAI->IsHeal(bot)) && (bot->GetPowerPct(POWER_MANA) > 20))

View File

@@ -351,7 +351,9 @@ uint32 InventoryAction::GetItemCount(FindItemVisitor* visitor, IterateItemsMask
std::vector<Item*>& items = visitor->GetResult();
for (Item* item : items)
{
count += item->GetCount();
}
return count;
}

View File

@@ -8,6 +8,7 @@
#include "BroadcastHelper.h"
#include "Event.h"
#include "GuildMgr.h"
#include "Log.h"
#include "PlayerbotOperations.h"
#include "Playerbots.h"
#include "PlayerbotWorldThreadProcessor.h"
@@ -43,7 +44,7 @@ bool InviteToGroupAction::Invite(Player* inviter, Player* player)
return true;
}
bool InviteNearbyToGroupAction::Execute(Event /*event*/)
bool InviteNearbyToGroupAction::Execute(Event event)
{
GuidVector nearGuids = botAI->GetAiObjectContext()->GetValue<GuidVector>("nearest friendly players")->Get();
for (auto& i : nearGuids)
@@ -61,7 +62,7 @@ bool InviteNearbyToGroupAction::Execute(Event /*event*/)
if (player->GetGroup())
continue;
if (!PlayerbotAIConfig::instance().randomBotInvitePlayer && GET_PLAYERBOT_AI(player)->IsRealPlayer())
if (!sPlayerbotAIConfig.randomBotInvitePlayer && GET_PLAYERBOT_AI(player)->IsRealPlayer())
continue;
Group* group = bot->GetGroup();
@@ -87,7 +88,7 @@ bool InviteNearbyToGroupAction::Execute(Event /*event*/)
if (abs(int32(player->GetLevel() - bot->GetLevel())) > 2)
continue;
if (ServerFacade::instance().GetDistance2d(bot, player) > PlayerbotAIConfig::instance().sightDistance)
if (ServerFacade::instance().GetDistance2d(bot, player) > sPlayerbotAIConfig.sightDistance)
continue;
// When inviting the 5th member of the group convert to raid for future invites.
@@ -98,7 +99,7 @@ bool InviteNearbyToGroupAction::Execute(Event /*event*/)
PlayerbotWorldThreadProcessor::instance().QueueOperation(std::move(convertOp));
}
if (PlayerbotAIConfig::instance().inviteChat && RandomPlayerbotMgr::instance().IsRandomBot(bot))
if (sPlayerbotAIConfig.inviteChat && sRandomPlayerbotMgr.IsRandomBot(bot))
{
std::map<std::string, std::string> placeholders;
placeholders["%player"] = player->GetName();
@@ -119,7 +120,7 @@ bool InviteNearbyToGroupAction::Execute(Event /*event*/)
bool InviteNearbyToGroupAction::isUseful()
{
if (!PlayerbotAIConfig::instance().randomBotGroupNearby)
if (!sPlayerbotAIConfig.randomBotGroupNearby)
return false;
if (bot->InBattleground())
@@ -165,8 +166,10 @@ std::vector<Player*> InviteGuildToGroupAction::getGuildMembers()
return worker.GetResult();
}
bool InviteGuildToGroupAction::Execute(Event /*event*/)
bool InviteGuildToGroupAction::Execute(Event event)
{
Guild* guild = sGuildMgr->GetGuildById(bot->GetGuildId());
for (auto& member : getGuildMembers())
{
Player* player = member;
@@ -183,7 +186,7 @@ bool InviteGuildToGroupAction::Execute(Event /*event*/)
if (player->isDND())
continue;
if (!PlayerbotAIConfig::instance().randomBotInvitePlayer && GET_PLAYERBOT_AI(player)->IsRealPlayer())
if (!sPlayerbotAIConfig.randomBotInvitePlayer && GET_PLAYERBOT_AI(player)->IsRealPlayer())
continue;
if (player->IsBeingTeleported())
@@ -218,7 +221,7 @@ bool InviteGuildToGroupAction::Execute(Event /*event*/)
player->GetLevel() + 5) // Do not invite members that too low level or risk dragging them to deadly places.
continue;
if (!playerAi && ServerFacade::instance().GetDistance2d(bot, player) > PlayerbotAIConfig::instance().sightDistance)
if (!playerAi && ServerFacade::instance().GetDistance2d(bot, player) > sPlayerbotAIConfig.sightDistance)
continue;
Group* group = bot->GetGroup();
@@ -230,8 +233,8 @@ bool InviteGuildToGroupAction::Execute(Event /*event*/)
PlayerbotWorldThreadProcessor::instance().QueueOperation(std::move(convertOp));
}
if (PlayerbotAIConfig::instance().inviteChat &&
(RandomPlayerbotMgr::instance().IsRandomBot(bot) || !botAI->HasActivePlayerMaster()))
if (sPlayerbotAIConfig.inviteChat &&
(sRandomPlayerbotMgr.IsRandomBot(bot) || !botAI->HasActivePlayerMaster()))
{
BroadcastHelper::BroadcastGuildGroupOrRaidInvite(botAI, bot, player, group);
}

View File

@@ -92,7 +92,7 @@ bool LeaveGroupAction::Leave()
return true;
}
bool LeaveFarAwayAction::Execute(Event /*event*/)
bool LeaveFarAwayAction::Execute(Event event)
{
// allow bot to leave party when they want
return Leave();

View File

@@ -8,11 +8,11 @@
#include "AiFactory.h"
#include "ItemVisitors.h"
#include "LFGMgr.h"
#include "LFGPackets.h"
#include "Opcodes.h"
#include "Playerbots.h"
#include "World.h"
#include "WorldPacket.h"
#include "RandomPlayerbotMgr.h"
using namespace lfg;
@@ -20,7 +20,7 @@ bool LfgJoinAction::Execute(Event event) { return JoinLFG(); }
uint32 LfgJoinAction::GetRoles()
{
if (!RandomPlayerbotMgr::instance().IsRandomBot(bot))
if (!sRandomPlayerbotMgr.IsRandomBot(bot))
{
if (botAI->IsTank(bot))
return PLAYER_ROLE_TANK;
@@ -101,7 +101,7 @@ bool LfgJoinAction::JoinLFG()
LfgDungeonSet list;
std::vector<uint32> selected;
std::vector<uint32> dungeons = RandomPlayerbotMgr::instance().LfgDungeons[bot->GetTeamId()];
std::vector<uint32> dungeons = sRandomPlayerbotMgr.LfgDungeons[bot->GetTeamId()];
if (!dungeons.size())
return false;
@@ -170,7 +170,7 @@ bool LfgJoinAction::JoinLFG()
return true;
}
bool LfgRoleCheckAction::Execute(Event /*event*/)
bool LfgRoleCheckAction::Execute(Event event)
{
if (Group* group = bot->GetGroup())
{
@@ -216,9 +216,9 @@ bool LfgAcceptAction::Execute(Event event)
*packet << id << true;
bot->GetSession()->QueuePacket(packet);
if (RandomPlayerbotMgr::instance().IsRandomBot(bot) && !bot->GetGroup())
if (sRandomPlayerbotMgr.IsRandomBot(bot) && !bot->GetGroup())
{
RandomPlayerbotMgr::instance().Refresh(bot);
sRandomPlayerbotMgr.Refresh(bot);
botAI->ResetStrategies();
}
@@ -251,9 +251,9 @@ bool LfgAcceptAction::Execute(Event event)
*packet << id << true;
bot->GetSession()->QueuePacket(packet);
if (RandomPlayerbotMgr::instance().IsRandomBot(bot) && !bot->GetGroup())
if (sRandomPlayerbotMgr.IsRandomBot(bot) && !bot->GetGroup())
{
RandomPlayerbotMgr::instance().Refresh(bot);
sRandomPlayerbotMgr.Refresh(bot);
botAI->ResetStrategies();
}
@@ -265,7 +265,7 @@ bool LfgAcceptAction::Execute(Event event)
return false;
}
bool LfgLeaveAction::Execute(Event /*event*/)
bool LfgLeaveAction::Execute(Event event)
{
// Don't leave if lfg strategy enabled
// if (botAI->HasStrategy("lfg", BOT_STATE_NON_COMBAT))
@@ -337,7 +337,7 @@ bool LfgJoinAction::isUseful()
if (bot->isDead())
return false;
if (!RandomPlayerbotMgr::instance().IsRandomBot(bot))
if (!sRandomPlayerbotMgr.IsRandomBot(bot))
return false;
Map* map = bot->GetMap();

View File

@@ -13,7 +13,7 @@
#include "PlayerbotAIConfig.h"
#include "Playerbots.h"
bool LootRollAction::Execute(Event /*event*/)
bool LootRollAction::Execute(Event event)
{
Group* group = bot->GetGroup();
if (!group)
@@ -27,6 +27,7 @@ bool LootRollAction::Execute(Event /*event*/)
continue;
}
ObjectGuid guid = roll->itemGUID;
uint32 slot = roll->itemSlot;
uint32 itemId = roll->itemid;
int32 randomProperty = 0;
if (roll->itemRandomPropId)
@@ -89,8 +90,6 @@ bool LootRollAction::Execute(Event /*event*/)
}
else if (sPlayerbotAIConfig.lootRollLevel == 1)
{
// Level 1 = "greed" mode: bots greed on useful items but never need
// Only downgrade NEED to GREED, preserve GREED votes as-is
if (vote == NEED)
{
if (RollUniqueCheck(proto, bot))
@@ -102,6 +101,10 @@ bool LootRollAction::Execute(Event /*event*/)
vote = GREED;
}
}
else if (vote == GREED)
{
vote = PASS;
}
}
switch (group->GetLootMethod())
{
@@ -183,6 +186,7 @@ bool MasterLootRollAction::Execute(Event event)
if (!group)
return false;
RollVote vote = CalculateRollVote(proto);
group->CountRollVote(bot->GetGUID(), creatureGuid, CalculateRollVote(proto));
return true;

View File

@@ -16,6 +16,7 @@ bool LootStrategyAction::Execute(Event event)
{
std::string const strategy = event.getParam();
LootObjectStack* lootItems = AI_VALUE(LootObjectStack*, "available loot");
std::set<uint32>& alwaysLootItems = AI_VALUE(std::set<uint32>&, "always loot list");
Value<LootStrategy*>* lootStrategy = context->GetValue<LootStrategy*>("loot strategy");

View File

@@ -134,7 +134,7 @@ public:
private:
bool CheckBagSpace(Player* bot)
{
uint32 totalused = 0;
uint32 totalused = 0, total = 16;
for (uint8 slot = INVENTORY_SLOT_ITEM_START; slot < INVENTORY_SLOT_ITEM_END; slot++)
if (bot->GetItemByPos(INVENTORY_SLOT_BAG_0, slot))
++totalused;

View File

@@ -11,16 +11,20 @@
#include "LastMovementValue.h"
#include "Playerbots.h"
bool MoveToRpgTargetAction::Execute(Event /*event*/)
bool MoveToRpgTargetAction::Execute(Event event)
{
GuidPosition guidP = AI_VALUE(GuidPosition, "rpg target");
Unit* unit = botAI->GetUnit(guidP);
if (unit && !unit->IsInWorld())
{
return false;
}
GameObject* go = botAI->GetGameObject(guidP);
if (go && !go->IsInWorld())
{
return false;
}
Player* player = guidP.GetPlayer();
WorldObject* wo = nullptr;
if (unit)

View File

@@ -7,9 +7,10 @@
#include "ChooseRpgTargetAction.h"
#include "LootObjectStack.h"
#include "PathGenerator.h"
#include "Playerbots.h"
bool MoveToTravelTargetAction::Execute(Event /*event*/)
bool MoveToTravelTargetAction::Execute(Event event)
{
TravelTarget* target = AI_VALUE(TravelTarget*, "travel target");

View File

@@ -15,6 +15,7 @@
#include "FleeManager.h"
#include "G3D/Vector3.h"
#include "GameObject.h"
#include "Geometry.h"
#include "LastMovementValue.h"
#include "LootObjectStack.h"
#include "Map.h"
@@ -35,7 +36,9 @@
#include "SpellAuraEffects.h"
#include "SpellInfo.h"
#include "Stances.h"
#include "TargetedMovementGenerator.h"
#include "Timer.h"
#include "Transport.h"
#include "Unit.h"
#include "Vehicle.h"
#include "WaypointMovementGenerator.h"
@@ -64,14 +67,18 @@ bool MovementAction::JumpTo(uint32 mapId, float x, float y, float z, MovementPri
{
UpdateMovementState();
if (!IsMovingAllowed(mapId, x, y, z))
{
return false;
}
if (IsDuplicateMove(mapId, x, y, z))
{
return false;
}
if (IsWaitingForLastMove(priority))
{
return false;
}
float botZ = bot->GetPositionZ();
float speed = bot->GetSpeed(MOVE_RUN);
MotionMaster& mm = *bot->GetMotionMaster();
mm.Clear();
@@ -93,6 +100,9 @@ bool MovementAction::MoveNear(WorldObject* target, float distance, MovementPrior
distance += target->GetCombatReach();
float x = target->GetPositionX();
float y = target->GetPositionY();
float z = target->GetPositionZ();
float followAngle = GetFollowAngle();
for (float angle = followAngle; angle <= followAngle + static_cast<float>(2 * M_PI);
@@ -110,6 +120,7 @@ bool MovementAction::MoveNear(WorldObject* target, float distance, MovementPrior
return true;
}
// botAI->TellError("All paths not in LOS");
return false;
}
@@ -118,6 +129,9 @@ bool MovementAction::MoveToLOS(WorldObject* target, bool ranged)
if (!target)
return false;
// std::ostringstream out; out << "Moving to LOS!";
// bot->Say(out.str(), LANG_UNIVERSAL);
float x = target->GetPositionX();
float y = target->GetPositionY();
float z = target->GetPositionZ();
@@ -250,6 +264,7 @@ bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle,
// bot->CastStop();
// botAI->InterruptSpell();
// }
G3D::Vector3 endP = path.back();
DoMovePoint(bot, x, y, z, generatePath, backwards);
float delay = 1000.0f * MoveDelay(distance, backwards);
if (lessDelay)
@@ -355,7 +370,7 @@ bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle,
// {
// movePosition = endPosition;
// if (startPosition.GetMapId() != endPosition.GetMapId() || totalDistance > maxDist)
// if (startPosition.getMapId() != endPosition.getMapId() || totalDistance > maxDist)
// {
// if (!TravelNodeMap::instance().getNodes().empty() && !bot->InBattleground())
// {
@@ -406,7 +421,7 @@ bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle,
// {
// //Use standard PathGenerator to find a route.
// PathGenerator path(mover);
// path.CalculatePath(movePosition.GetPositionX(), movePosition.GetPositionY(), movePosition.GetPositionZ(), false);
// path.CalculatePath(movePosition.getX(), movePosition.getY(), movePosition.getZ(), false);
// PathType type = path.GetPathType();
// Movement::PointsArray const& points = path.GetPath();
// movePath.addPath(startPosition.fromPointsArray(points));
@@ -470,8 +485,8 @@ bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle,
// else
// {
// LOG_DEBUG("playerbots", "!entry");
// return bot->TeleportTo(movePosition.GetMapId(), movePosition.GetPositionX(), movePosition.GetPositionY(),
// movePosition.GetPositionZ(), movePosition.GetOrientation(), 0);
// return bot->TeleportTo(movePosition.getMapId(), movePosition.getX(), movePosition.getY(),
// movePosition.getZ(), movePosition.getO(), 0);
// }
// }
@@ -548,14 +563,14 @@ bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle,
// AI_VALUE(LastMovement&, "last movement").setPath(movePath);
// if (!movePosition || movePosition.GetMapId() != bot->GetMapId())
// if (!movePosition || movePosition.getMapId() != bot->GetMapId())
// {
// movePath.clear();
// AI_VALUE(LastMovement&, "last movement").setPath(movePath);
// if (botAI->HasStrategy("debug move", BOT_STATE_NON_COMBAT))
// botAI->TellMasterNoFacing("No point. Rebuilding.");
// LOG_DEBUG("playerbots", "!movePosition || movePosition.GetMapId() != bot->GetMapId()");
// LOG_DEBUG("playerbots", "!movePosition || movePosition.getMapId() != bot->GetMapId()");
// return false;
// }
@@ -594,15 +609,15 @@ bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle,
// float cz = z;
// for (auto i : movePath.getPath())
// {
// CreateWp(bot, i.point.GetPositionX(), i.point.GetPositionY(), i.point.GetPositionZ(), 0.f, 2334);
// CreateWp(bot, i.point.getX(), i.point.getY(), i.point.getZ(), 0.f, 2334);
// cx = i.point.GetPositionX();
// cy = i.point.GetPositionY();
// cz = i.point.GetPositionZ();
// cx = i.point.getX();
// cy = i.point.getY();
// cz = i.point.getZ();
// }
// }
// else
// CreateWp(bot, movePosition.GetPositionX(), movePosition.GetPositionY(), movePosition.GetPositionZ(), 0, 2334, true);
// CreateWp(bot, movePosition.getX(), movePosition.getY(), movePosition.getZ(), 0, 2334, true);
// }
// //Log bot movement
@@ -619,8 +634,8 @@ bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle,
// sPlayerbotAIConfig.log("bot_movement.csv", out.str().c_str());
// }
// // LOG_DEBUG("playerbots", "({}, {}) -> ({}, {})", startPosition.GetPositionX(), startPosition.GetPositionY(),
// movePosition.GetPositionX(), movePosition.GetPositionY()); if (!react)
// // LOG_DEBUG("playerbots", "({}, {}) -> ({}, {})", startPosition.getX(), startPosition.getY(),
// movePosition.getX(), movePosition.getY()); if (!react)
// if (totalDistance > maxDist)
// WaitForReach(startPosition.distance(movePosition) - 10.0f);
// else
@@ -656,7 +671,7 @@ bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle,
// // else
// // {
// // mover->GetMotionMaster()->GetDestination(x, y, z);
// // if (movePosition.distance(WorldPosition(movePosition.GetMapId(), x, y, z, 0)) > minDist)
// // if (movePosition.distance(WorldPosition(movePosition.getMapId(), x, y, z, 0)) > minDist)
// // {
// // mover->StopMoving();
// // mover->GetMotionMaster()->Clear();
@@ -670,8 +685,8 @@ bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle,
// AI_VALUE(LastMovement&, "last movement").nextTeleport = now +
// (time_t)MoveDelay(startPosition.distance(movePosition)); LOG_DEBUG("playerbots", "totalDistance > maxDist &&
// !detailedMove && !botAI->HasPlayerNearby(&movePosition)"); return bot->TeleportTo(movePosition.GetMapId(),
// movePosition.GetPositionX(), movePosition.GetPositionY(), movePosition.GetPositionZ(), startPosition.getAngleTo(movePosition));
// !detailedMove && !botAI->HasPlayerNearby(&movePosition)"); return bot->TeleportTo(movePosition.getMapId(),
// movePosition.getX(), movePosition.getY(), movePosition.getZ(), startPosition.getAngleTo(movePosition));
// }
// // walk if master walks and is close
@@ -693,9 +708,9 @@ bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle,
// if (!bot->HasAuraType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED) && !bot->HasAuraType(SPELL_AURA_FLY))
// {
// bot->SetWalk(masterWalking);
// bot->GetMotionMaster()->MovePoint(movePosition.GetMapId(), movePosition.GetPositionX(), movePosition.GetPositionY(),
// movePosition.GetPositionZ(), generatePath); WaitForReach(startPosition.distance(movePosition));
// // LOG_DEBUG("playerbots", "Movepoint to ({}, {})", movePosition.GetPositionX(), movePosition.GetPositionY());
// bot->GetMotionMaster()->MovePoint(movePosition.getMapId(), movePosition.getX(), movePosition.getY(),
// movePosition.getZ(), generatePath); WaitForReach(startPosition.distance(movePosition));
// // LOG_DEBUG("playerbots", "Movepoint to ({}, {})", movePosition.getX(), movePosition.getY());
// }
// else
// {
@@ -741,9 +756,9 @@ bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle,
// }
// }
// bot->GetMotionMaster()->MovePoint(movePosition.GetMapId(), Position(movePosition.GetPositionX(), movePosition.GetPositionY(),
// movePosition.GetPositionZ(), 0.f)); WaitForReach(startPosition.distance(movePosition)); LOG_DEBUG("playerbots",
// "Movepoint to ({}, {})", movePosition.GetPositionX(), movePosition.GetPositionY());
// bot->GetMotionMaster()->MovePoint(movePosition.getMapId(), Position(movePosition.getX(), movePosition.getY(),
// movePosition.getZ(), 0.f)); WaitForReach(startPosition.distance(movePosition)); LOG_DEBUG("playerbots",
// "Movepoint to ({}, {})", movePosition.getX(), movePosition.getY());
// }
// AI_VALUE(LastMovement&, "last movement").setShort(movePosition);
@@ -764,6 +779,8 @@ bool MovementAction::MoveTo(WorldObject* target, float distance, MovementPriorit
float by = bot->GetPositionY();
float bz = bot->GetPositionZ();
float tx = target->GetPositionX();
float ty = target->GetPositionY();
float tz = target->GetPositionZ();
float distanceToTarget = bot->GetDistance(target);
@@ -795,6 +812,10 @@ bool MovementAction::ReachCombatTo(Unit* target, float distance)
if (!IsMovingAllowed(target))
return false;
float bx = bot->GetPositionX();
float by = bot->GetPositionY();
float bz = bot->GetPositionZ();
float tx = target->GetPositionX();
float ty = target->GetPositionY();
float tz = target->GetPositionZ();
@@ -854,11 +875,6 @@ float MovementAction::GetFollowAngle()
if (!group)
return 0.0f;
// Prevent bots with orphaned raid groups from dividing by 0, which freezes the server.
uint32 memberCount = group->GetMembersCount();
if (memberCount <= 1)
return 0.0f;
uint32 index = 1;
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
{
@@ -866,7 +882,7 @@ float MovementAction::GetFollowAngle()
continue;
if (ref->GetSource() == bot)
return 2 * M_PI / (memberCount - 1) * index;
return 2 * M_PI / (group->GetMembersCount() - 1) * index;
++index;
}
@@ -937,70 +953,68 @@ bool MovementAction::Follow(Unit* target, float distance) { return Follow(target
void MovementAction::UpdateMovementState()
{
const bool isCurrentlyRestricted = // see if the bot is currently slowed, rooted, or otherwise unable to move
bot->HasUnitState(UNIT_STATE_LOST_CONTROL) || bot->IsRooted() || bot->isFrozen() || bot->IsPolymorphed();
const bool isCurrentlyRestricted = // see if the bot is currently slowed, rooted, or otherwise unable to move
bot->HasUnitState(UNIT_STATE_LOST_CONTROL) ||
bot->IsRooted() ||
bot->isFrozen() ||
bot->IsPolymorphed();
// no update movement flags while movement is current restricted.
if (!isCurrentlyRestricted && bot->IsAlive())
{
// state flags
const auto master = botAI ? botAI->GetMaster() : nullptr;
const auto liquidState = bot->GetLiquidData().Status;
const auto master = botAI ? botAI->GetMaster() : nullptr; // real player or not
const bool masterIsFlying = master ? master->HasUnitMovementFlag(MOVEMENTFLAG_FLYING) : true;
const bool masterIsSwimming = master ? master->HasUnitMovementFlag(MOVEMENTFLAG_SWIMMING) : true;
const auto liquidState = bot->GetLiquidData().Status; // default LIQUID_MAP_NO_WATER
const float gZ = bot->GetMapWaterOrGroundLevel(bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ());
const bool onGroundZ = bot->GetPositionZ() < gZ + 1.f;
const bool canSwim = liquidState == LIQUID_MAP_IN_WATER || liquidState == LIQUID_MAP_UNDER_WATER;
const bool canFly = bot->HasIncreaseMountedFlightSpeedAura() || bot->HasFlyAura();
const bool canWaterWalk = bot->HasWaterWalkAura();
const bool isMasterFlying = master ? master->HasUnitMovementFlag(MOVEMENTFLAG_FLYING) : true;
const bool isMasterSwimming = master ? master->HasUnitMovementFlag(MOVEMENTFLAG_SWIMMING) : true;
const bool wantsToFly = bot->HasIncreaseMountedFlightSpeedAura() || bot->HasFlyAura();
const bool isFlying = bot->HasUnitMovementFlag(MOVEMENTFLAG_FLYING);
const bool isSwimming = bot->HasUnitMovementFlag(MOVEMENTFLAG_SWIMMING);
const bool isWaterArea = liquidState != LIQUID_MAP_NO_WATER;
const bool isUnderWater = liquidState == LIQUID_MAP_UNDER_WATER;
const bool isInWater = liquidState == LIQUID_MAP_IN_WATER;
const bool isWaterWalking = bot->HasUnitMovementFlag(MOVEMENTFLAG_WATERWALKING);
const bool isSwimming = bot->HasUnitMovementFlag(MOVEMENTFLAG_SWIMMING);
const bool wantsToWaterWalk = bot->HasWaterWalkAura();
const bool wantsToSwim = isInWater || isUnderWater;
const bool onGroundZ = (bot->GetPositionZ() < gZ + 1.f) && !isWaterArea;
bool movementFlagsUpdated = false;
// handle water (fragile logic do not alter without testing every detail, animation and transition)
if (liquidState != LIQUID_MAP_NO_WATER && !isFlying)
// handle water state
if (isWaterArea && !isFlying)
{
if (canWaterWalk && !isMasterSwimming && !isWaterWalking)
// water walking
if (wantsToWaterWalk && !isWaterWalking && !masterIsSwimming)
{
bot->SetSwim(false);
bot->RemoveUnitMovementFlag(MOVEMENTFLAG_SWIMMING);
bot->AddUnitMovementFlag(MOVEMENTFLAG_WATERWALKING);
movementFlagsUpdated = true;
}
else if ((!canWaterWalk || isMasterSwimming) && isWaterWalking)
// swimming
else if (wantsToSwim && !isSwimming && masterIsSwimming)
{
bot->RemoveUnitMovementFlag(MOVEMENTFLAG_WATERWALKING);
if (canSwim)
bot->SetSwim(true);
movementFlagsUpdated = true;
}
else if (!canSwim && isSwimming)
{
bot->SetSwim(false);
bot->AddUnitMovementFlag(MOVEMENTFLAG_SWIMMING);
movementFlagsUpdated = true;
}
}
// reset when not around water while swimming or water walking
if (liquidState == LIQUID_MAP_NO_WATER && (isSwimming || isWaterWalking))
else if (isSwimming || isWaterWalking)
{
bot->SetSwim(false);
// reset water flags
bot->RemoveUnitMovementFlag(MOVEMENTFLAG_SWIMMING);
bot->RemoveUnitMovementFlag(MOVEMENTFLAG_WATERWALKING);
movementFlagsUpdated = true;
}
// handle flying
if ((canFly && !isFlying) && isMasterFlying)
// handle flying state
if (wantsToFly && !isFlying && masterIsFlying)
{
bot->AddUnitMovementFlag(MOVEMENTFLAG_CAN_FLY);
bot->AddUnitMovementFlag(MOVEMENTFLAG_DISABLE_GRAVITY);
bot->AddUnitMovementFlag(MOVEMENTFLAG_FLYING);
// required for transition and state monitoring.
if (MotionMaster* mm = bot->GetMotionMaster())
mm->MoveTakeoff(0, {bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ() + 1.F}, 0.F, true);
movementFlagsUpdated = true;
}
else if ((!canFly && !isWaterWalking && isFlying) || (!isMasterFlying && isFlying && onGroundZ))
else if ((!wantsToFly || onGroundZ) && isFlying)
{
bot->RemoveUnitMovementFlag(MOVEMENTFLAG_CAN_FLY);
bot->RemoveUnitMovementFlag(MOVEMENTFLAG_DISABLE_GRAVITY);
@@ -1008,16 +1022,15 @@ void MovementAction::UpdateMovementState()
movementFlagsUpdated = true;
}
// detect if movement/CC restrictions have been ended, refresh movement state for animations.
// detect if movement restrictions have been lifted, CC just ended.
if (wasMovementRestricted)
movementFlagsUpdated = true;
movementFlagsUpdated = true; // refresh movement state to ensure animations play correctly
// movement flags should only be updated between state changes, if not it will break certain effects.
if (movementFlagsUpdated)
bot->SendMovementFlagUpdate();
}
// Save current state for the next check
// Save current state for the next check
wasMovementRestricted = isCurrentlyRestricted;
// Temporary speed increase in group
@@ -1177,7 +1190,7 @@ bool MovementAction::Follow(Unit* target, float distance, float angle)
WorldPosition cPos(corpse);
if (botPos.fDist(cPos) > sPlayerbotAIConfig.spellDistance)
return MoveTo(cPos.GetMapId(), cPos.GetPositionX(), cPos.GetPositionY(), cPos.GetPositionZ());
return MoveTo(cPos.getMapId(), cPos.getX(), cPos.getY(), cPos.getZ());
}
}
@@ -1204,7 +1217,7 @@ bool MovementAction::Follow(Unit* target, float distance, float angle)
if ((lDist * 1.5 < tDist && ang < static_cast<float>(M_PI) / 2) ||
target->HasUnitState(UNIT_STATE_IN_FLIGHT))
{
return MoveTo(longMove.GetMapId(), longMove.GetPositionX(), longMove.GetPositionY(), longMove.GetPositionZ());
return MoveTo(longMove.getMapId(), longMove.getX(), longMove.getY(), longMove.getZ());
}
}
}
@@ -1404,6 +1417,7 @@ bool MovementAction::Flee(Unit* target)
if (botAI->IsTank(player))
{
float distanceToTank = ServerFacade::instance().GetDistance2d(bot, player);
float distanceToTarget = ServerFacade::instance().GetDistance2d(bot, target);
if (distanceToTank < fleeDistance)
{
fleeTarget = player;
@@ -1424,6 +1438,8 @@ bool MovementAction::Flee(Unit* target)
else // bot is not targeted, try to flee dps/healers
{
bool isHealer = botAI->IsHeal(bot);
bool isDps = !isHealer && !botAI->IsTank(bot);
bool isTank = botAI->IsTank(bot);
bool needHealer = !isHealer && AI_VALUE2(uint8, "health", "self target") < 50;
bool isRanged = botAI->IsRanged(bot);
@@ -1797,11 +1813,12 @@ void MovementAction::DoMovePoint(Unit* unit, float x, float y, float z, bool gen
if (!mm)
return;
// bot water collision correction
if (unit->HasUnitMovementFlag(MOVEMENTFLAG_WATERWALKING) && unit->HasWaterWalkAura())
// enable water walking
if (unit->HasUnitMovementFlag(MOVEMENTFLAG_WATERWALKING))
{
float gZ = unit->GetMapWaterOrGroundLevel(unit->GetPositionX(), unit->GetPositionY(), unit->GetPositionZ());
unit->UpdatePosition(unit->GetPositionX(), unit->GetPositionY(), gZ, false);
// z = gZ; no overwrite Z axe otherwise you cant steer the bots into swimming when water walking.
}
mm->Clear();
@@ -1827,7 +1844,7 @@ void MovementAction::DoMovePoint(Unit* unit, float x, float y, float z, bool gen
}
}
bool FleeAction::Execute(Event /*event*/)
bool FleeAction::Execute(Event event)
{
return MoveAway(AI_VALUE(Unit*, "current target"), sPlayerbotAIConfig.fleeDistance, true);
}
@@ -1835,8 +1852,9 @@ bool FleeAction::Execute(Event /*event*/)
bool FleeAction::isUseful()
{
if (bot->GetCurrentSpell(CURRENT_CHANNELED_SPELL) != nullptr)
{
return false;
}
Unit* target = AI_VALUE(Unit*, "current target");
if (target && target->IsInWorld() && !bot->IsWithinMeleeRange(target))
return false;
@@ -1844,10 +1862,12 @@ bool FleeAction::isUseful()
return true;
}
bool FleeWithPetAction::Execute(Event /*event*/)
bool FleeWithPetAction::Execute(Event event)
{
if (Pet* pet = bot->GetPet())
{
botAI->PetFollow();
}
return Flee(AI_VALUE(Unit*, "current target"));
}
@@ -1855,14 +1875,15 @@ bool FleeWithPetAction::Execute(Event /*event*/)
bool AvoidAoeAction::isUseful()
{
if (getMSTime() - moveInterval < lastMoveTimer)
{
return false;
}
GuidVector traps = AI_VALUE(GuidVector, "nearest trap with damage");
GuidVector triggers = AI_VALUE(GuidVector, "possible triggers");
return AI_VALUE(Aura*, "area debuff") || !traps.empty() || !triggers.empty();
}
bool AvoidAoeAction::Execute(Event /*event*/)
bool AvoidAoeAction::Execute(Event event)
{
// Case #1: Aura with dynamic object (e.g. rain of fire)
if (AvoidAuraWithDynamicObj())
@@ -2286,15 +2307,17 @@ bool MovementAction::CheckLastFlee(float curAngle, std::list<FleeInfo>& infoList
bool CombatFormationMoveAction::isUseful()
{
if (getMSTime() - moveInterval < lastMoveTimer)
{
return false;
}
if (bot->GetCurrentSpell(CURRENT_CHANNELED_SPELL) != nullptr)
{
return false;
}
return true;
}
bool CombatFormationMoveAction::Execute(Event /*event*/)
bool CombatFormationMoveAction::Execute(Event event)
{
float dis = AI_VALUE(float, "disperse distance");
if (dis <= 0.0f || (!bot->IsInCombat() && botAI->HasStrategy("stay", BotState::BOT_STATE_NON_COMBAT)) ||
@@ -2425,7 +2448,7 @@ Player* CombatFormationMoveAction::NearestGroupMember(float dis)
return result;
}
bool TankFaceAction::Execute(Event /*event*/)
bool TankFaceAction::Execute(Event event)
{
Unit* target = AI_VALUE(Unit*, "current target");
if (!target)
@@ -2509,7 +2532,7 @@ bool RearFlankAction::isUseful()
return inFront || inRear;
}
bool RearFlankAction::Execute(Event /*event*/)
bool RearFlankAction::Execute(Event event)
{
Unit* target = AI_VALUE(Unit*, "current target");
if (!target)
@@ -2620,9 +2643,9 @@ bool DisperseSetAction::Execute(Event event)
return true;
}
bool RunAwayAction::Execute(Event /*event*/) { return Flee(AI_VALUE(Unit*, "group leader")); }
bool RunAwayAction::Execute(Event event) { return Flee(AI_VALUE(Unit*, "group leader")); }
bool MoveToLootAction::Execute(Event /*event*/)
bool MoveToLootAction::Execute(Event event)
{
LootObject loot = AI_VALUE(LootObject, "loot target");
if (!loot.IsLootPossible(bot))
@@ -2631,7 +2654,7 @@ bool MoveToLootAction::Execute(Event /*event*/)
return MoveNear(loot.GetWorldObject(bot), sPlayerbotAIConfig.contactDistance);
}
bool MoveOutOfEnemyContactAction::Execute(Event /*event*/)
bool MoveOutOfEnemyContactAction::Execute(Event event)
{
Unit* target = AI_VALUE(Unit*, "current target");
if (!target)
@@ -2642,7 +2665,7 @@ bool MoveOutOfEnemyContactAction::Execute(Event /*event*/)
bool MoveOutOfEnemyContactAction::isUseful() { return AI_VALUE2(bool, "inside target", "current target"); }
bool SetFacingTargetAction::Execute(Event /*event*/)
bool SetFacingTargetAction::Execute(Event event)
{
Unit* target = AI_VALUE(Unit*, "current target");
if (!target)
@@ -2668,7 +2691,7 @@ bool SetFacingTargetAction::isPossible()
return true;
}
bool SetBehindTargetAction::Execute(Event /*event*/)
bool SetBehindTargetAction::Execute(Event event)
{
Unit* target = AI_VALUE(Unit*, "current target");
if (!target)
@@ -2728,7 +2751,7 @@ bool SetBehindTargetAction::Execute(Event /*event*/)
false, true, MovementPriority::MOVEMENT_COMBAT);
}
bool MoveOutOfCollisionAction::Execute(Event /*event*/)
bool MoveOutOfCollisionAction::Execute(Event event)
{
float angle = M_PI * 2000 / frand(1.f, 1000.f);
float distance = sPlayerbotAIConfig.followDistance;
@@ -2746,7 +2769,7 @@ bool MoveOutOfCollisionAction::isUseful()
botAI->GetAiObjectContext()->GetValue<GuidVector>("nearest friendly players")->Get().size() < 15;
}
bool MoveRandomAction::Execute(Event /*event*/)
bool MoveRandomAction::Execute(Event event)
{
float distance = sPlayerbotAIConfig.tooCloseDistance + urand(10, 30);
@@ -2759,7 +2782,9 @@ bool MoveRandomAction::Execute(Event /*event*/)
float angle = (float)rand_norm() * static_cast<float>(M_PI);
x += urand(0, distance) * cos(angle);
y += urand(0, distance) * sin(angle);
float ox = x;
float oy = y;
float oz = z;
if (!bot->GetMap()->CheckCollisionAndGetValidCoords(bot, bot->GetPositionX(), bot->GetPositionY(),
bot->GetPositionZ(), x, y, z))
continue;
@@ -2776,9 +2801,9 @@ bool MoveRandomAction::Execute(Event /*event*/)
bool MoveRandomAction::isUseful() { return !AI_VALUE(GuidPosition, "rpg target"); }
bool MoveInsideAction::Execute(Event /*event*/) { return MoveInside(bot->GetMapId(), x, y, bot->GetPositionZ(), distance); }
bool MoveInsideAction::Execute(Event event) { return MoveInside(bot->GetMapId(), x, y, bot->GetPositionZ(), distance); }
bool RotateAroundTheCenterPointAction::Execute(Event /*event*/)
bool RotateAroundTheCenterPointAction::Execute(Event event)
{
uint32 next_point = GetCurrWaypoint();
if (MoveTo(bot->GetMapId(), waypoints[next_point].first, waypoints[next_point].second, bot->GetPositionZ(), false,
@@ -2798,9 +2823,10 @@ bool MoveFromGroupAction::Execute(Event event)
return MoveFromGroup(distance);
}
bool MoveAwayFromCreatureAction::Execute(Event /*event*/)
bool MoveAwayFromCreatureAction::Execute(Event event)
{
GuidVector targets = AI_VALUE(GuidVector, "nearest npcs");
Creature* nearestCreature = bot->FindNearestCreature(creatureId, range, alive);
// Find all creatures with the specified Id
std::vector<Unit*> creatures;
@@ -2878,12 +2904,16 @@ bool MoveAwayFromCreatureAction::Execute(Event /*event*/)
bool MoveAwayFromCreatureAction::isPossible() { return bot->CanFreeMove(); }
bool MoveAwayFromPlayerWithDebuffAction::Execute(Event /*event*/)
bool MoveAwayFromPlayerWithDebuffAction::Execute(Event event)
{
Group* const group = bot->GetGroup();
Player* closestPlayer = nullptr;
float minDistance = 0.0f;
Group* group = bot->GetGroup();
if (!group)
{
return false;
}
std::vector<Player*> debuffedPlayers;

View File

@@ -332,6 +332,7 @@ public:
private:
uint32 spellId;
float range;
bool alive;
};
#endif

View File

@@ -49,16 +49,18 @@ bool DrinkAction::Execute(Event event)
bool DrinkAction::isUseful()
{
return UseItemAction::isUseful() && AI_VALUE2(bool, "has mana", "self target") &&
AI_VALUE2(uint8, "mana", "self target") < 100;
return UseItemAction::isUseful() &&
AI_VALUE2(bool, "has mana", "self target") &&
AI_VALUE2(uint8, "mana", "self target") < 100;
}
bool DrinkAction::isPossible()
{
return !bot->IsInCombat() && !bot->IsMounted() &&
!botAI->HasAnyAuraOf(GetTarget(), "dire bear form", "bear form", "cat form", "travel form", "aquatic form",
"flight form", "swift flight form", nullptr) &&
(botAI->HasCheat(BotCheatMask::food) || UseItemAction::isPossible());
return !bot->IsInCombat() &&
!bot->IsMounted() &&
!botAI->HasAnyAuraOf(GetTarget(), "dire bear form", "bear form", "cat form", "travel form",
"aquatic form","flight form", "swift flight form", nullptr) &&
(botAI->HasCheat(BotCheatMask::food) || UseItemAction::isPossible());
}
bool EatAction::Execute(Event event)
@@ -100,12 +102,17 @@ bool EatAction::Execute(Event event)
return UseItemAction::Execute(event);
}
bool EatAction::isUseful() { return UseItemAction::isUseful() && AI_VALUE2(uint8, "health", "self target") < 100; }
bool EatAction::isUseful()
{
return UseItemAction::isUseful() &&
AI_VALUE2(uint8, "health", "self target") < 100;
}
bool EatAction::isPossible()
{
return !bot->IsInCombat() && !bot->IsMounted() &&
!botAI->HasAnyAuraOf(GetTarget(), "dire bear form", "bear form", "cat form", "travel form", "aquatic form",
"flight form", "swift flight form", nullptr) &&
(botAI->HasCheat(BotCheatMask::food) || UseItemAction::isPossible());
return !bot->IsInCombat() &&
!bot->IsMounted() &&
!botAI->HasAnyAuraOf(GetTarget(), "dire bear form", "bear form", "cat form", "travel form",
"aquatic form","flight form", "swift flight form", nullptr) &&
(botAI->HasCheat(BotCheatMask::food) || UseItemAction::isPossible());
}

View File

@@ -7,7 +7,7 @@
#include "LootObjectStack.h"
#include "AiObjectContext.h"
bool OpenItemAction::Execute(Event /*event*/)
bool OpenItemAction::Execute(Event event)
{
bool foundOpenable = false;

View File

@@ -7,9 +7,10 @@
#include "Event.h"
#include "PlayerbotOperations.h"
#include "Playerbots.h"
#include "PlayerbotWorldThreadProcessor.h"
bool PassLeadershipToMasterAction::Execute(Event /*event*/)
bool PassLeadershipToMasterAction::Execute(Event event)
{
if (Player* master = GetMaster())
if (master && master != bot && bot->GetGroup() && bot->GetGroup()->IsMember(master->GetGUID()))

View File

@@ -9,6 +9,8 @@
#include <string>
#include "Action.h"
#include "PlayerbotFactory.h"
#include "Unit.h"
class PlayerbotAI;
@@ -20,6 +22,7 @@ public:
bool Execute(Event event) override;
private:
bool warningEnabled = true;
std::string defaultCmd;
};

View File

@@ -102,7 +102,7 @@ bool PositionAction::Execute(Event event)
return false;
}
bool MoveToPositionAction::Execute(Event /*event*/)
bool MoveToPositionAction::Execute(Event event)
{
PositionInfo pos = context->GetValue<PositionMap&>("position")->Get()[qualifier];
if (!pos.isSet())
@@ -123,7 +123,7 @@ bool MoveToPositionAction::isUseful()
return pos.isSet() && distance > sPlayerbotAIConfig.followDistance && distance < sPlayerbotAIConfig.reactDistance;
}
bool SetReturnPositionAction::Execute(Event /*event*/)
bool SetReturnPositionAction::Execute(Event event)
{
PositionMap& posMap = context->GetValue<PositionMap&>("position")->Get();
PositionInfo returnPos = posMap["return"];

View File

@@ -7,7 +7,7 @@
#include "ChatHelper.h"
#include "Event.h"
#include "PlayerbotAI.h"
#include "Playerbots.h"
void QueryQuestAction::TellObjective(std::string const name, uint32 available, uint32 required)
{
@@ -16,6 +16,7 @@ void QueryQuestAction::TellObjective(std::string const name, uint32 available, u
bool QueryQuestAction::Execute(Event event)
{
Player* requester = event.getOwner() ? event.getOwner() : GetMaster();
Player* bot = botAI->GetBot();
WorldPosition botPos(bot);
WorldPosition* ptr_botpos = &botPos;

View File

@@ -5,7 +5,6 @@
#include "QuestAction.h"
#include <sstream>
#include <algorithm>
#include "Chat.h"
#include "ChatHelper.h"
@@ -117,8 +116,7 @@ bool QuestAction::CompleteQuest(Player* player, uint32 entry)
player->CastedCreatureOrGO(creature, ObjectGuid(), spell_id);
}
}*/
/*else*/
if (creature > 0)
/*else*/ if (creature > 0)
{
if (CreatureTemplate const* cInfo = sObjectMgr->GetCreatureTemplate(creature))
for (uint16 z = 0; z < creaturecount; ++z)
@@ -352,6 +350,7 @@ bool QuestUpdateAddItemAction::Execute(Event event)
uint32 itemId, count;
p >> itemId >> count;
Player* requester = event.getOwner() ? event.getOwner() : GetMaster();
auto const* itemPrototype = sObjectMgr->GetItemTemplate(itemId);
if (itemPrototype)
{
@@ -406,6 +405,8 @@ bool QuestItemPushResultAction::Execute(Event event)
if (!quest)
return false;
const QuestStatusData& q_status = bot->getQuestStatusMap().at(questId);
for (int i = 0; i < QUEST_ITEM_OBJECTIVES_COUNT; i++)
{
uint32 itemId = quest->RequiredItemId[i];
@@ -431,7 +432,7 @@ bool QuestItemPushResultAction::Execute(Event event)
return false;
}
bool QuestUpdateFailedAction::Execute(Event /*event*/)
bool QuestUpdateFailedAction::Execute(Event event)
{
//opcode SMSG_QUESTUPDATE_FAILED is never sent...(yet?)
return false;
@@ -445,6 +446,8 @@ bool QuestUpdateFailedTimerAction::Execute(Event event)
uint32 questId;
p >> questId;
Player* requester = event.getOwner() ? event.getOwner() : GetMaster();
Quest const* qInfo = sObjectMgr->GetQuestTemplate(questId);
if (qInfo)

View File

@@ -8,7 +8,7 @@
#include "Event.h"
#include "Playerbots.h"
bool RandomBotUpdateAction::Execute(Event /*event*/)
bool RandomBotUpdateAction::Execute(Event event)
{
if (!sRandomPlayerbotMgr.IsRandomBot(bot))
return false;

View File

@@ -10,7 +10,7 @@
#include "Playerbots.h"
#include "ServerFacade.h"
bool ReachTargetAction::Execute(Event /*event*/) { return ReachCombatTo(AI_VALUE(Unit*, GetTargetName()), distance); }
bool ReachTargetAction::Execute(Event event) { return ReachCombatTo(AI_VALUE(Unit*, GetTargetName()), distance); }
bool ReachTargetAction::isUseful()
{

View File

@@ -78,7 +78,7 @@ void ReleaseSpiritAction::LogRelease(const std::string& releaseMsg, bool isAutoR
}
// AutoReleaseSpiritAction implementation
bool AutoReleaseSpiritAction::Execute(Event /*event*/)
bool AutoReleaseSpiritAction::Execute(Event event)
{
IncrementDeathCount();
bot->DurabilityRepairAll(false, 1.0f, false);
@@ -214,7 +214,7 @@ bool AutoReleaseSpiritAction::ShouldDelayBattlegroundRelease() const
return true;
}
bool RepopAction::Execute(Event /*event*/)
bool RepopAction::Execute(Event event)
{
const GraveyardStruct* graveyard = GetGrave(
AI_VALUE(uint32, "death count") > 10 ||
@@ -250,7 +250,7 @@ void RepopAction::PerformGraveyardTeleport(const GraveyardStruct* graveyard) con
}
// SelfResurrectAction implementation for Warlock's Soulstone Resurrection/Shaman's Reincarnation
bool SelfResurrectAction::Execute(Event /*event*/)
bool SelfResurrectAction::Execute(Event event)
{
if (!bot->IsAlive() && bot->GetUInt32Value(PLAYER_SELF_RES_SPELL))
{

View File

@@ -7,7 +7,7 @@
#include "Event.h"
#include "LastMovementValue.h"
#include "AiObjectContext.h"
#include "Playerbots.h"
bool RememberTaxiAction::Execute(Event event)
{
@@ -28,7 +28,7 @@ bool RememberTaxiAction::Execute(Event event)
case CMSG_ACTIVATETAXIEXPRESS:
{
ObjectGuid guid;
uint32 node_count;
uint32 node_count, totalcost;
p >> guid >> node_count;
LastMovement& movement = context->GetValue<LastMovement&>("last taxi")->Get();

View File

@@ -9,7 +9,7 @@
#include "Event.h"
#include "Playerbots.h"
bool RepairAllAction::Execute(Event /*event*/)
bool RepairAllAction::Execute(Event event)
{
GuidVector npcs = AI_VALUE(GuidVector, "nearest npcs");
for (ObjectGuid const guid : npcs)

View File

@@ -5,16 +5,14 @@
#include "ResetInstancesAction.h"
#include "PlayerbotAI.h"
#include "Playerbots.h"
#include "InstancePackets.h"
bool ResetInstancesAction::Execute(Event /*event*/)
bool ResetInstancesAction::Execute(Event event)
{
WorldPacket packet(CMSG_RESET_INSTANCES, 0);
WorldPackets::Instance::ResetInstances resetInstance(std::move(packet));
bot->GetSession()->HandleResetInstancesOpcode(resetInstance);
bot->GetSession()->HandleResetInstancesOpcode(packet);
botAI->TellMaster("Resetting all instances");
return true;
}

View File

@@ -10,11 +10,11 @@
#include "Event.h"
#include "GridNotifiers.h"
#include "GridNotifiersImpl.h"
#include "PlayerbotAI.h"
#include "Playerbots.h"
#include "ServerFacade.h"
#include "NearestGameObjects.h"
bool RevealGatheringItemAction::Execute(Event /*event*/)
bool RevealGatheringItemAction::Execute(Event event)
{
if (!bot->GetGroup())
return false;

View File

@@ -9,6 +9,7 @@
#include "FleeManager.h"
#include "GameGraveyard.h"
#include "MapMgr.h"
#include "PlayerbotFactory.h"
#include "Playerbots.h"
#include "RandomPlayerbotMgr.h"
#include "ServerFacade.h"
@@ -73,7 +74,7 @@ bool ReviveFromCorpseAction::Execute(Event event)
return true;
}
bool FindCorpseAction::Execute(Event /*event*/)
bool FindCorpseAction::Execute(Event event)
{
if (bot->InBattleground())
return false;
@@ -149,7 +150,7 @@ bool FindCorpseAction::Execute(Event /*event*/)
{
float rx, ry, rz;
if (manager.CalculateDestination(&rx, &ry, &rz))
moveToPos = WorldPosition(moveToPos.GetMapId(), rx, ry, rz, 0.0);
moveToPos = WorldPosition(moveToPos.getMapId(), rx, ry, rz, 0.0);
else if (!moveToPos.GetReachableRandomPointOnGround(bot, reclaimDist, urand(0, 1)))
moveToPos = corpsePos;
}
@@ -169,7 +170,7 @@ bool FindCorpseAction::Execute(Event /*event*/)
{
bot->GetMotionMaster()->Clear();
bot->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_TELEPORTED | AURA_INTERRUPT_FLAG_CHANGE_MAP);
bot->TeleportTo(moveToPos.GetMapId(), moveToPos.GetPositionX(), moveToPos.GetPositionY(), moveToPos.GetPositionZ(), 0);
bot->TeleportTo(moveToPos.getMapId(), moveToPos.getX(), moveToPos.getY(), moveToPos.getZ(), 0);
}
moved = true;
@@ -183,7 +184,7 @@ bool FindCorpseAction::Execute(Event /*event*/)
if (deadTime < 10 * MINUTE && dCount < 5) // Look for corpse up to 30 minutes.
{
moved =
MoveTo(moveToPos.GetMapId(), moveToPos.GetPositionX(), moveToPos.GetPositionY(), moveToPos.GetPositionZ(), false, false);
MoveTo(moveToPos.getMapId(), moveToPos.getX(), moveToPos.getY(), moveToPos.getZ(), false, false);
}
if (!moved)
@@ -236,10 +237,10 @@ GraveyardStruct const* SpiritHealerAction::GetGrave(bool startZone)
{
uint32 areaId = 0;
uint32 zoneId = 0;
sMapMgr->GetZoneAndAreaId(bot->GetPhaseMask(), zoneId, areaId, travelPos.GetMapId(), travelPos.GetPositionX(),
travelPos.GetPositionY(), travelPos.GetPositionZ());
ClosestGrave = sGraveyard->GetClosestGraveyard(travelPos.GetMapId(), travelPos.GetPositionX(), travelPos.GetPositionY(),
travelPos.GetPositionZ(), bot->GetTeamId(), areaId, zoneId,
sMapMgr->GetZoneAndAreaId(bot->GetPhaseMask(), zoneId, areaId, travelPos.getMapId(), travelPos.getX(),
travelPos.getY(), travelPos.getZ());
ClosestGrave = sGraveyard->GetClosestGraveyard(travelPos.getMapId(), travelPos.getX(), travelPos.getY(),
travelPos.getZ(), bot->GetTeamId(), areaId, zoneId,
bot->getClass() == CLASS_DEATH_KNIGHT);
if (ClosestGrave)
@@ -292,7 +293,7 @@ GraveyardStruct const* SpiritHealerAction::GetGrave(bool startZone)
return ClosestGrave;
}
bool SpiritHealerAction::Execute(Event /*event*/)
bool SpiritHealerAction::Execute(Event event)
{
Corpse* corpse = bot->GetCorpse();
if (!corpse)

View File

@@ -7,6 +7,7 @@
#include <random>
#include "BattlegroundMgr.h"
#include "ChatHelper.h"
#include "EmoteAction.h"
#include "Event.h"
@@ -15,7 +16,7 @@
#include "ServerFacade.h"
#include "RpgSubActions.h"
bool RpgAction::Execute(Event /*event*/)
bool RpgAction::Execute(Event event)
{
GuidPosition guidP = AI_VALUE(GuidPosition, "rpg target");
if (!guidP && botAI->GetMaster())
@@ -84,7 +85,7 @@ bool RpgAction::SetNextRpgAction()
isChecked = true;
Action* action = botAI->GetAiObjectContext()->GetAction(nextAction.getName());
if (!dynamic_cast<RpgEnabled*>(action) || !action->isUseful() || !action->isPossible())
if (!dynamic_cast<RpgEnabled*>(action) || !action->isPossible() || !action->isUseful())
continue;
actions.push_back(action);

View File

@@ -5,7 +5,6 @@
#include "RpgSubActions.h"
#include "BudgetValues.h"
#include "ChooseRpgTargetAction.h"
#include "EmoteAction.h"
#include "Formations.h"
@@ -52,15 +51,10 @@ GuidPosition RpgHelper::guidP() { return AI_VALUE(GuidPosition, "rpg target"); }
ObjectGuid RpgHelper::guid() { return (ObjectGuid)guidP(); }
bool RpgHelper::InRange()
{
GuidPosition targetGuid = guidP();
if (!targetGuid)
return false;
return bot->GetExactDist2dSq(targetGuid.GetPositionX(), targetGuid.GetPositionY()) <
INTERACTION_DISTANCE * INTERACTION_DISTANCE;
}
bool RpgHelper::InRange()
{
return guidP() ? (guidP().sqDistance2d(bot) < INTERACTION_DISTANCE * INTERACTION_DISTANCE) : false;
}
void RpgHelper::setFacingTo(GuidPosition guidPosition)
{
@@ -105,7 +99,7 @@ Event RpgSubAction::ActionEvent(Event event) { return event; }
bool RpgStayAction::isUseful() { return rpg->InRange() && !botAI->HasRealPlayerMaster(); }
bool RpgStayAction::Execute(Event /*event*/)
bool RpgStayAction::Execute(Event event)
{
bot->PlayerTalkClass->SendCloseGossip();
@@ -115,7 +109,7 @@ bool RpgStayAction::Execute(Event /*event*/)
bool RpgWorkAction::isUseful() { return rpg->InRange() && !botAI->HasRealPlayerMaster(); }
bool RpgWorkAction::Execute(Event /*event*/)
bool RpgWorkAction::Execute(Event event)
{
bot->HandleEmoteCommand(EMOTE_STATE_USE_STANDING);
rpg->AfterExecute();
@@ -124,7 +118,7 @@ bool RpgWorkAction::Execute(Event /*event*/)
bool RpgEmoteAction::isUseful() { return rpg->InRange() && !botAI->HasRealPlayerMaster(); }
bool RpgEmoteAction::Execute(Event /*event*/)
bool RpgEmoteAction::Execute(Event event)
{
uint32 type = TalkAction::GetRandomEmote(rpg->guidP().GetUnit());
@@ -139,7 +133,7 @@ bool RpgEmoteAction::Execute(Event /*event*/)
return true;
}
bool RpgCancelAction::Execute(Event /*event*/)
bool RpgCancelAction::Execute(Event event)
{
RESET_AI_VALUE(GuidPosition, "rpg target");
rpg->OnExecute("");
@@ -148,7 +142,7 @@ bool RpgCancelAction::Execute(Event /*event*/)
bool RpgTaxiAction::isUseful() { return rpg->InRange() && !botAI->HasRealPlayerMaster(); }
bool RpgTaxiAction::Execute(Event /*event*/)
bool RpgTaxiAction::Execute(Event event)
{
GuidPosition guidP = rpg->guidP();
@@ -156,7 +150,7 @@ bool RpgTaxiAction::Execute(Event /*event*/)
bot->GetSession()->HandleCancelMountAuraOpcode(emptyPacket);
uint32 node =
sObjectMgr->GetNearestTaxiNode(guidP.GetPositionX(), guidP.GetPositionY(), guidP.GetPositionZ(), guidP.GetMapId(), bot->GetTeamId());
sObjectMgr->GetNearestTaxiNode(guidP.getX(), guidP.getY(), guidP.getZ(), guidP.getMapId(), bot->GetTeamId());
std::vector<uint32> nodes;
for (uint32 i = 0; i < sTaxiPathStore.GetNumRows(); ++i)
@@ -209,12 +203,12 @@ bool RpgTaxiAction::Execute(Event /*event*/)
return true;
}
bool RpgDiscoverAction::Execute(Event /*event*/)
bool RpgDiscoverAction::Execute(Event event)
{
GuidPosition guidP = rpg->guidP();
uint32 node =
sObjectMgr->GetNearestTaxiNode(guidP.GetPositionX(), guidP.GetPositionY(), guidP.GetPositionZ(), guidP.GetMapId(), bot->GetTeamId());
sObjectMgr->GetNearestTaxiNode(guidP.getX(), guidP.getY(), guidP.getZ(), guidP.getMapId(), bot->GetTeamId());
if (!node)
return false;
@@ -228,7 +222,7 @@ bool RpgDiscoverAction::Execute(Event /*event*/)
std::string const RpgStartQuestAction::ActionName() { return "accept all quests"; }
Event RpgStartQuestAction::ActionEvent(Event /*event*/)
Event RpgStartQuestAction::ActionEvent(Event event)
{
WorldPacket p(CMSG_QUESTGIVER_ACCEPT_QUEST);
p << rpg->guid();
@@ -238,7 +232,7 @@ Event RpgStartQuestAction::ActionEvent(Event /*event*/)
std::string const RpgEndQuestAction::ActionName() { return "talk to quest giver"; }
Event RpgEndQuestAction::ActionEvent(Event /*event*/)
Event RpgEndQuestAction::ActionEvent(Event event)
{
WorldPacket p(CMSG_QUESTGIVER_COMPLETE_QUEST);
p << rpg->guid();
@@ -248,71 +242,17 @@ Event RpgEndQuestAction::ActionEvent(Event /*event*/)
std::string const RpgBuyAction::ActionName() { return "buy"; }
Event RpgBuyAction::ActionEvent(Event /*event*/) { return Event("rpg action", "vendor"); }
Event RpgBuyAction::ActionEvent(Event event) { return Event("rpg action", "vendor"); }
std::string const RpgSellAction::ActionName() { return "sell"; }
Event RpgSellAction::ActionEvent(Event /*event*/) { return Event("rpg action", "vendor"); }
Event RpgSellAction::ActionEvent(Event event) { return Event("rpg action", "vendor"); }
std::string const RpgRepairAction::ActionName() { return "repair"; }
bool RpgTrainAction::isUseful()
{
if (!rpg->InRange())
return false;
Creature* creature = rpg->guidP().GetCreature();
if (!creature)
return false;
if (!creature->IsInWorld() || creature->IsDuringRemoveFromWorld() || !creature->IsAlive())
return false;
return true;
}
bool RpgTrainAction::isPossible()
{
GuidPosition gp = rpg->guidP();
CreatureTemplate const* cinfo = gp.GetCreatureTemplate();
if (!cinfo)
return false;
Trainer::Trainer* trainer = sObjectMgr->GetTrainer(cinfo->Entry);
if (!trainer)
return false;
if (!trainer->IsTrainerValidForPlayer(bot))
return false;
FactionTemplateEntry const* factionTemplate = sFactionTemplateStore.LookupEntry(cinfo->faction);
float reputationDiscount = bot->GetReputationPriceDiscount(factionTemplate);
uint32 currentGold = AI_VALUE2(uint32, "free money for", (uint32)NeedMoneyFor::spells);
for (auto& spell : trainer->GetSpells())
{
Trainer::Spell const* trainerSpell = trainer->GetSpell(spell.SpellId);
if (!trainerSpell)
continue;
if (!trainer->CanTeachSpell(bot, trainerSpell))
continue;
if (currentGold < static_cast<uint32>(floor(trainerSpell->MoneyCost * reputationDiscount)))
continue;
// we only check if at least one spell can be learned from the trainer;
// otherwise, the train action should not be allowed
return true;
}
return false;
}
std::string const RpgTrainAction::ActionName() { return "trainer"; }
bool RpgHealAction::Execute(Event /*event*/)
bool RpgHealAction::Execute(Event event)
{
bool retVal = false;
@@ -347,21 +287,21 @@ std::string const RpgBuyPetitionAction::ActionName() { return "buy petition"; }
std::string const RpgUseAction::ActionName() { return "use"; }
Event RpgUseAction::ActionEvent(Event /*event*/)
Event RpgUseAction::ActionEvent(Event event)
{
return Event("rpg action", chat->FormatWorldobject(rpg->guidP().GetWorldObject()));
}
std::string const RpgSpellAction::ActionName() { return "cast random spell"; }
Event RpgSpellAction::ActionEvent(Event /*event*/)
Event RpgSpellAction::ActionEvent(Event event)
{
return Event("rpg action", chat->FormatWorldobject(rpg->guidP().GetWorldObject()));
}
std::string const RpgCraftAction::ActionName() { return "craft random item"; }
Event RpgCraftAction::ActionEvent(Event /*event*/)
Event RpgCraftAction::ActionEvent(Event event)
{
return Event("rpg action", chat->FormatWorldobject(rpg->guidP().GetWorldObject()));
}
@@ -401,7 +341,7 @@ std::vector<Item*> RpgTradeUsefulAction::CanGiveItems(GuidPosition guidPosition)
return giveItems;
}
bool RpgTradeUsefulAction::Execute(Event /*event*/)
bool RpgTradeUsefulAction::Execute(Event event)
{
GuidPosition guidP = AI_VALUE(GuidPosition, "rpg target");
@@ -476,7 +416,7 @@ bool RpgDuelAction::isUseful()
return true;
}
bool RpgDuelAction::Execute(Event /*event*/)
bool RpgDuelAction::Execute(Event event)
{
GuidPosition guidP = AI_VALUE(GuidPosition, "rpg target");
@@ -494,7 +434,7 @@ bool RpgMountAnimAction::isUseful()
return AI_VALUE2(bool, "mounted", "self target") && !AI_VALUE2(bool, "moving", "self target");
}
bool RpgMountAnimAction::Execute(Event /*event*/)
bool RpgMountAnimAction::Execute(Event event)
{
WorldPacket p;
bot->GetSession()->HandleMountSpecialAnimOpcode(p);

View File

@@ -165,9 +165,6 @@ class RpgTrainAction : public RpgSubAction
public:
RpgTrainAction(PlayerbotAI* botAI, std::string const name = "rpg train") : RpgSubAction(botAI, name) {}
bool isPossible() override;
bool isUseful() override;
private:
std::string const ActionName() override;
};

View File

@@ -55,7 +55,7 @@ void RtiAction::AppendRti(std::ostringstream& out, std::string const type)
out << " (" << target->GetName() << ")";
}
bool MarkRtiAction::Execute(Event /*event*/)
bool MarkRtiAction::Execute(Event event)
{
Group* group = bot->GetGroup();
if (!group)

View File

@@ -80,9 +80,8 @@ bool RTSCAction::Execute(Event event)
SET_AI_VALUE2(WorldPosition, "RTSC saved location", locationName, spellPosition);
Creature* wpCreature =
bot->SummonCreature(15631, spellPosition.GetPositionX(), spellPosition.GetPositionY(),
spellPosition.GetPositionZ(), spellPosition.GetOrientation(), TEMPSUMMON_TIMED_DESPAWN,
2000.0f);
bot->SummonCreature(15631, spellPosition.getX(), spellPosition.getY(), spellPosition.getZ(),
spellPosition.getO(), TEMPSUMMON_TIMED_DESPAWN, 2000.0f);
wpCreature->SetObjectScale(0.5f);
return true;
@@ -111,9 +110,8 @@ bool RTSCAction::Execute(Event event)
if (spellPosition)
{
Creature* wpCreature =
bot->SummonCreature(15631, spellPosition.GetPositionX(), spellPosition.GetPositionY(),
spellPosition.GetPositionZ(), spellPosition.GetOrientation(),
TEMPSUMMON_TIMED_DESPAWN, 2000.0f);
bot->SummonCreature(15631, spellPosition.getX(), spellPosition.getY(), spellPosition.getZ(),
spellPosition.getO(), TEMPSUMMON_TIMED_DESPAWN, 2000.0f);
wpCreature->SetObjectScale(0.5f);
}

View File

@@ -9,7 +9,9 @@
#include <regex>
#include <string>
#include "ChannelMgr.h"
#include "Event.h"
#include "GuildMgr.h"
#include "PlayerbotTextMgr.h"
#include "Playerbots.h"
@@ -54,7 +56,7 @@ static const std::unordered_set<std::string> noReplyMsgStarts = {"e ", "accept "
SayAction::SayAction(PlayerbotAI* botAI) : Action(botAI, "say"), Qualified() {}
bool SayAction::Execute(Event /*event*/)
bool SayAction::Execute(Event event)
{
std::string text = "";
std::map<std::string, std::string> placeholders;
@@ -90,6 +92,7 @@ bool SayAction::Execute(Event /*event*/)
}
// set delay before next say
time_t lastSaid = AI_VALUE2(time_t, "last said", qualifier);
uint32 nextTime = time(nullptr) + urand(1, 30);
botAI->GetAiObjectContext()->GetValue<time_t>("last said", qualifier)->Set(nextTime);
@@ -156,6 +159,7 @@ bool SayAction::isUseful()
void ChatReplyAction::ChatReplyDo(Player* bot, uint32& type, uint32& guid1, uint32& guid2, std::string& msg, std::string& chanName, std::string& name)
{
ChatReplyType replyType = REPLY_NOT_UNDERSTAND; // default not understand
std::string respondsText = "";
// if we're just commanding bots around, don't respond...

View File

@@ -10,13 +10,11 @@
bool SecurityCheckAction::isUseful()
{
return RandomPlayerbotMgr::instance().IsRandomBot(bot)
&& botAI->GetMaster()
&& botAI->GetMaster()->GetSession()->GetSecurity() < SEC_GAMEMASTER
&& !GET_PLAYERBOT_AI(botAI->GetMaster());
return sRandomPlayerbotMgr.IsRandomBot(bot) && botAI->GetMaster() &&
botAI->GetMaster()->GetSession()->GetSecurity() < SEC_GAMEMASTER && !GET_PLAYERBOT_AI(botAI->GetMaster());
}
bool SecurityCheckAction::Execute(Event /*event*/)
bool SecurityCheckAction::Execute(Event event)
{
if (Group* group = bot->GetGroup())
{

View File

@@ -7,6 +7,7 @@
#include "Event.h"
#include "Formations.h"
#include "PathGenerator.h"
#include "Playerbots.h"
#include "RTSCValues.h"
#include "RtscAction.h"
@@ -133,8 +134,8 @@ bool SeeSpellAction::Execute(Event event)
SET_AI_VALUE2(WorldPosition, "RTSC saved location", locationName, spellPosition);
Creature* wpCreature =
bot->SummonCreature(15631, spellPosition.GetPositionX(), spellPosition.GetPositionY(), spellPosition.GetPositionZ(),
spellPosition.GetOrientation(), TEMPSUMMON_TIMED_DESPAWN, 2000.0f);
bot->SummonCreature(15631, spellPosition.getX(), spellPosition.getY(), spellPosition.getZ(),
spellPosition.getO(), TEMPSUMMON_TIMED_DESPAWN, 2000.0f);
wpCreature->SetObjectScale(0.5f);
RESET_AI_VALUE(std::string, "RTSC next spell action");
@@ -166,14 +167,14 @@ bool SeeSpellAction::MoveToSpell(WorldPosition& spellPosition, bool inFormation)
PositionMap& posMap = AI_VALUE(PositionMap&, "position");
PositionInfo stayPosition = posMap["stay"];
stayPosition.Set(spellPosition.GetPositionX(), spellPosition.GetPositionY(), spellPosition.GetPositionZ(), spellPosition.GetMapId());
stayPosition.Set(spellPosition.getX(), spellPosition.getY(), spellPosition.getZ(), spellPosition.getMapId());
posMap["stay"] = stayPosition;
}
if (bot->IsWithinLOS(spellPosition.GetPositionX(), spellPosition.GetPositionY(), spellPosition.GetPositionZ()))
return MoveNear(spellPosition.GetMapId(), spellPosition.GetPositionX(), spellPosition.GetPositionY(), spellPosition.GetPositionZ(), 0);
if (bot->IsWithinLOS(spellPosition.getX(), spellPosition.getY(), spellPosition.getZ()))
return MoveNear(spellPosition.getMapId(), spellPosition.getX(), spellPosition.getY(), spellPosition.getZ(), 0);
return MoveTo(spellPosition.GetMapId(), spellPosition.GetPositionX(), spellPosition.GetPositionY(), spellPosition.GetPositionZ(), false,
return MoveTo(spellPosition.getMapId(), spellPosition.getX(), spellPosition.getY(), spellPosition.getZ(), false,
false);
}

View File

@@ -49,7 +49,9 @@ bool SetCraftAction::Execute(Event event)
if (skillSpells.empty())
{
for (SkillLineAbilityEntry const* skillLine : sSkillLineAbilityStore)
{
skillSpells[skillLine->Spell] = skillLine;
}
}
data.required.clear();
@@ -66,8 +68,7 @@ bool SetCraftAction::Execute(Event event)
if (!spellInfo)
continue;
SkillLineAbilityEntry const* skillLine = skillSpells[spellId];
if (skillLine != nullptr)
if (SkillLineAbilityEntry const* skillLine = skillSpells[spellId])
{
for (uint8 i = 0; i < 3; ++i)
{
@@ -77,7 +78,9 @@ bool SetCraftAction::Execute(Event event)
for (uint32 x = 0; x < MAX_SPELL_REAGENTS; ++x)
{
if (spellInfo->Reagent[x] <= 0)
{
continue;
}
uint32 itemid = spellInfo->Reagent[x];
uint32 reagentsRequired = spellInfo->ReagentCount[x];
@@ -129,8 +132,9 @@ void SetCraftAction::TellCraft()
if (ItemTemplate const* reagent = sObjectMgr->GetItemTemplate(item))
{
if (first)
{
first = false;
}
else
out << ", ";
@@ -138,7 +142,9 @@ void SetCraftAction::TellCraft()
uint32 given = data.obtained[item];
if (given)
{
out << "|cffffff00(x" << given << " given)|r ";
}
}
}

View File

@@ -8,7 +8,7 @@
#include "Event.h"
#include "Playerbots.h"
bool SetHomeAction::Execute(Event /*event*/)
bool SetHomeAction::Execute(Event event)
{
Player* master = GetMaster();
@@ -26,10 +26,20 @@ bool SetHomeAction::Execute(Event /*event*/)
if (Unit* unit = botAI->GetUnit(selection))
if (unit->HasNpcFlag(UNIT_NPC_FLAG_INNKEEPER))
{
Creature* creature = botAI->GetCreature(selection);
bot->GetSession()->SendBindPoint(creature);
botAI->TellMaster("This inn is my new home");
return true;
if (isRpgAction)
{
Creature* creature = botAI->GetCreature(selection);
bot->GetSession()->SendBindPoint(creature);
botAI->TellMaster("This inn is my new home");
return true;
}
else
{
Creature* creature = botAI->GetCreature(selection);
bot->GetSession()->SendBindPoint(creature);
botAI->TellMaster("This inn is my new home");
return true;
}
}
GuidVector npcs = AI_VALUE(GuidVector, "nearest npcs");

View File

@@ -40,8 +40,9 @@ bool ShareQuestAction::Execute(Event event)
return false;
}
bool AutoShareQuestAction::Execute(Event /*event*/)
bool AutoShareQuestAction::Execute(Event event)
{
Player* requester = event.getOwner() ? event.getOwner() : GetMaster();
bool shared = false;
for (uint8 slot = 0; slot < MAX_QUEST_LOG_SIZE; ++slot)

View File

@@ -7,9 +7,9 @@
#include "ChatHelper.h"
#include "Event.h"
#include "PlayerbotAI.h"
#include "Playerbots.h"
bool StatsAction::Execute(Event /*event*/)
bool StatsAction::Execute(Event event)
{
std::ostringstream out;

View File

@@ -39,7 +39,7 @@ bool StayActionBase::Stay()
return true;
}
bool StayAction::Execute(Event /*event*/) { return Stay(); }
bool StayAction::Execute(Event event) { return Stay(); }
bool StayAction::isUseful()
{
@@ -47,8 +47,11 @@ bool StayAction::isUseful()
PositionInfo stayPosition = AI_VALUE(PositionMap&, "position")["stay"];
if (stayPosition.isSet())
{
const float distance = bot->GetDistance(stayPosition.x, stayPosition.y, stayPosition.z);
if (sPlayerbotAIConfig.followDistance)
{
return false;
}
}
// move from group takes priority over stay as it's added and removed automatically
@@ -61,7 +64,7 @@ bool StayAction::isUseful()
return AI_VALUE2(bool, "moving", "self target");
}
bool SitAction::Execute(Event /*event*/)
bool SitAction::Execute(Event event)
{
if (bot->isMoving())
return false;

View File

@@ -7,19 +7,25 @@
#include "SuggestWhatToDoAction.h"
#include "ServerFacade.h"
#include "ChannelMgr.h"
#include "Event.h"
#include "ItemVisitors.h"
#include "AiFactory.h"
#include "ChatHelper.h"
#include "Playerbots.h"
#include "PlayerbotTextMgr.h"
#include "Config.h"
#include "BroadcastHelper.h"
#include "AiFactory.h"
#include "ChannelMgr.h"
#include "ChatHelper.h"
#include "Config.h"
#include "Event.h"
#include "GuildMgr.h"
#include "ItemVisitors.h"
#include "PlayerbotTextMgr.h"
#include "Playerbots.h"
#include "ServerFacade.h"
#include "Channel.h"
enum eTalkType
{
@@ -56,13 +62,14 @@ bool SuggestWhatToDoAction::isUseful()
return (time(0) - lastSaid) > 30;
}
bool SuggestWhatToDoAction::Execute(Event /*event*/)
bool SuggestWhatToDoAction::Execute(Event event)
{
uint32 index = rand() % suggestions.size();
auto fnct_ptr = suggestions[index];
fnct_ptr();
std::string const qualifier = "suggest what to do";
time_t lastSaid = AI_VALUE2(time_t, "last said", qualifier);
botAI->GetAiObjectContext()->GetValue<time_t>("last said", qualifier)->Set(time(nullptr) + urand(1, 60));
return true;
@@ -220,7 +227,7 @@ void SuggestWhatToDoAction::thunderfury()
class FindTradeItemsVisitor : public IterateItemsVisitor
{
public:
FindTradeItemsVisitor(uint32 quality) : IterateItemsVisitor(), quality(quality) {}
FindTradeItemsVisitor(uint32 quality) : quality(quality), IterateItemsVisitor() {}
bool Visit(Item* item) override
{
@@ -251,7 +258,7 @@ private:
SuggestDungeonAction::SuggestDungeonAction(PlayerbotAI* botAI) : SuggestWhatToDoAction(botAI, "suggest dungeon") {}
bool SuggestDungeonAction::Execute(Event /*event*/)
bool SuggestDungeonAction::Execute(Event event)
{
// TODO: use PlayerbotDungeonRepository::instance()
@@ -318,7 +325,7 @@ bool SuggestDungeonAction::Execute(Event /*event*/)
SuggestTradeAction::SuggestTradeAction(PlayerbotAI* botAI) : SuggestWhatToDoAction(botAI, "suggest trade") {}
bool SuggestTradeAction::Execute(Event /*event*/)
bool SuggestTradeAction::Execute(Event event)
{
uint32 quality = urand(0, 100);
if (quality > 95)

View File

@@ -231,6 +231,7 @@ void TalkToQuestGiverAction::AskToSelectReward(Quest const* quest, std::ostrings
for (uint8 i = 0; i < quest->GetRewChoiceItemsCount(); ++i)
{
ItemTemplate const* item = sObjectMgr->GetItemTemplate(quest->RewardChoiceItemId[i]);
ItemUsage usage = AI_VALUE2(ItemUsage, "item usage", quest->RewardChoiceItemId[i]);
if (!forEquip || BestRewards(quest).count(i) > 0)
{
@@ -247,6 +248,7 @@ bool TurnInQueryQuestAction::Execute(Event event)
WorldPacket pakcet = event.getPacket();
ObjectGuid guid;
uint32 questId;
ObjectGuid unk1;
pakcet >> guid >> questId;
Object* object =
ObjectAccessor::GetObjectByTypeMask(*bot, guid, TYPEMASK_UNIT | TYPEMASK_GAMEOBJECT | TYPEMASK_ITEM);

View File

@@ -6,10 +6,12 @@
#include "TameAction.h"
#include <algorithm>
#include <cctype>
#include <iomanip>
#include <random>
#include <set>
#include <sstream>
#include "DBCStructure.h"
#include "Log.h"
#include "ObjectMgr.h"
#include "Pet.h"
#include "Player.h"
@@ -51,6 +53,7 @@ bool TameAction::Execute(Event event)
{
std::set<std::string> normalFamilies;
std::set<std::string> exoticFamilies;
Player* bot = botAI->GetBot();
// Loop over all creature templates and collect tameable families
CreatureTemplateContainer const* creatures = sObjectMgr->GetCreatureTemplates();

View File

@@ -31,14 +31,8 @@ bool TaxiAction::Execute(Event event)
GuidVector units = *context->GetValue<GuidVector>("nearest npcs");
for (ObjectGuid const guid : units)
{
Creature* npc = ObjectAccessor::GetCreature(*bot, guid);
if (!npc || !npc->IsAlive())
continue;
if (!(npc->GetNpcFlags() & UNIT_NPC_FLAG_FLIGHTMASTER))
continue;
if (bot->GetDistance(npc) > sPlayerbotAIConfig.farDistance)
Creature* npc = bot->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_FLIGHTMASTER);
if (!npc)
continue;
uint32 curloc = sObjectMgr->GetNearestTaxiNode(npc->GetPositionX(), npc->GetPositionY(), npc->GetPositionZ(),
@@ -56,17 +50,21 @@ bool TaxiAction::Execute(Event event)
}
}
// stagger bot takeoff
uint32 delayMin = sConfigMgr->GetOption<uint32>("AiPlayerbot.BotTaxiDelayMinMs", 350u, false);
uint32 delayMax = sConfigMgr->GetOption<uint32>("AiPlayerbot.BotTaxiDelayMaxMs", 5000u, false);
uint32 gapMs = sConfigMgr->GetOption<uint32>("AiPlayerbot.BotTaxiGapMs", 200u, false);
uint32 gapJitterMs = sConfigMgr->GetOption<uint32>("AiPlayerbot.BotTaxiGapJitterMs", 100u, false);
// Only for follower bots
if (botAI->HasRealPlayerMaster())
{
uint32 index = botAI->GetGroupSlotIndex(bot);
uint32 delay = sPlayerbotAIConfig.botTaxiDelayMin +
index * sPlayerbotAIConfig.botTaxiGapMs +
urand(0, sPlayerbotAIConfig.botTaxiGapJitterMs);
uint32 delay = delayMin + index * gapMs + urand(0, gapJitterMs);
delay = std::min(delay, sPlayerbotAIConfig.botTaxiDelayMax);
delay = std::min(delay, delayMax);
// Store the NPC's GUID so we can re-acquire the pointer later
// Store the npcs GUID so we can re-acquire the pointer later
ObjectGuid npcGuid = npc->GetGUID();
// schedule the take-off

View File

@@ -7,12 +7,9 @@
#include "Event.h"
#include "LastMovementValue.h"
#include "AiObjectContext.h"
#include "PlayerbotAI.h"
#include "SpellMgr.h"
#include "Spell.h"
#include "Playerbots.h"
bool TeleportAction::Execute(Event /*event*/)
bool TeleportAction::Execute(Event event)
{
/*
// List of allowed portal entries (you can populate this dynamically)
@@ -77,7 +74,7 @@ bool TeleportAction::Execute(Event /*event*/)
continue;
uint32 spellId = goInfo->spellcaster.spellId;
SpellInfo const* spellInfo = SpellMgr::instance()->GetSpellInfo(spellId);
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
if (!spellInfo || !spellInfo->HasEffect(SPELL_EFFECT_TELEPORT_UNITS))
continue;

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