mirror of
https://github.com/mod-playerbots/mod-playerbots.git
synced 2026-01-25 22:46:25 +00:00
Compare commits
1 Commits
hermensbas
...
hermensbas
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5c9451b73f |
6
.github/workflows/windows_build.yml
vendored
6
.github/workflows/windows_build.yml
vendored
@@ -25,25 +25,21 @@ jobs:
|
||||
with:
|
||||
repository: 'mod-playerbots/azerothcore-wotlk'
|
||||
ref: 'Playerbot'
|
||||
path: 'ac'
|
||||
- name: Checkout Playerbot Module
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
repository: 'mod-playerbots/mod-playerbots'
|
||||
#path: 'modules/mod-playerbots'
|
||||
path: ac/modules/mod-playerbots
|
||||
path: 'modules/mod-playerbots'
|
||||
- name: ccache
|
||||
uses: hendrikmuhs/ccache-action@v1.2.13
|
||||
- name: Configure OS
|
||||
shell: bash
|
||||
working-directory: ac
|
||||
env:
|
||||
CONTINUOUS_INTEGRATION: true
|
||||
run: |
|
||||
./acore.sh install-deps
|
||||
- name: Build
|
||||
shell: bash
|
||||
working-directory: ac
|
||||
run: |
|
||||
export CTOOLS_BUILD=all
|
||||
./acore.sh compiler build
|
||||
|
||||
@@ -1,126 +0,0 @@
|
||||
# Pull Request
|
||||
|
||||
Describe what this change does and why it is needed...
|
||||
|
||||
---
|
||||
|
||||
## Design Philosophy
|
||||
|
||||
We prioritize **stability, performance, and predictability** over behavioral realism.
|
||||
Complex player-mimicking logic is intentionally limited due to its negative impact on scalability, maintainability, and
|
||||
long-term robustness.
|
||||
|
||||
Excessive processing overhead can lead to server hiccups, increased CPU usage, and degraded performance for all
|
||||
participants. Because every action and
|
||||
decision tree is executed **per bot and per trigger**, even small increases in logic complexity can scale poorly and
|
||||
negatively affect both players and
|
||||
world (random) bots. Bots are not expected to behave perfectly, and perfect simulation of human decision-making is not a
|
||||
project goal. Increased behavioral
|
||||
realism often introduces disproportionate cost, reduced predictability, and significantly higher maintenance overhead.
|
||||
|
||||
Every additional branch of logic increases long-term responsibility. All decision paths must be tested, validated, and
|
||||
maintained continuously as the system evolves.
|
||||
If advanced or AI-intensive behavior is introduced, the **default configuration must remain the lightweight decision
|
||||
model**. More complex behavior should only be
|
||||
available as an **explicit opt-in option**, clearly documented as having a measurable performance cost.
|
||||
|
||||
Principles:
|
||||
|
||||
- **Stability before intelligence**
|
||||
A stable system is always preferred over a smarter one.
|
||||
|
||||
- **Performance is a shared resource**
|
||||
Any increase in bot cost affects all players and all bots.
|
||||
|
||||
- **Simple logic scales better than smart logic**
|
||||
Predictable behavior under load is more valuable than perfect decisions.
|
||||
|
||||
- **Complexity must justify itself**
|
||||
If a feature cannot clearly explain its cost, it should not exist.
|
||||
|
||||
- **Defaults must be cheap**
|
||||
Expensive behavior must always be optional and clearly communicated.
|
||||
|
||||
- **Bots should look reasonable, not perfect**
|
||||
The goal is believable behavior, not human simulation.
|
||||
|
||||
Before submitting, confirm that this change aligns with those principles.
|
||||
|
||||
---
|
||||
|
||||
## Feature Evaluation
|
||||
|
||||
Please answer the following:
|
||||
|
||||
- Describe the **minimum logic** required to achieve the intended behavior?
|
||||
- Describe the **cheapest implementation** that produces an acceptable result?
|
||||
- Describe the **runtime cost** when this logic executes across many bots?
|
||||
|
||||
---
|
||||
|
||||
## How to Test the Changes
|
||||
|
||||
- Step-by-step instructions to test the change
|
||||
- Any required setup (e.g. multiple players, bots, specific configuration)
|
||||
- Expected behavior and how to verify it
|
||||
|
||||
## Complexity & Impact
|
||||
|
||||
- Does this change add new decision branches?
|
||||
- [ ] No
|
||||
- [ ] Yes (**explain below**)
|
||||
|
||||
- Does this change increase per-bot or per-tick processing?
|
||||
- [ ] No
|
||||
- [ ] Yes (**describe and justify impact**)
|
||||
|
||||
- Could this logic scale poorly under load?
|
||||
- [ ] No
|
||||
- [ ] Yes (**explain why**)
|
||||
|
||||
---
|
||||
|
||||
## Defaults & Configuration
|
||||
|
||||
- Does this change modify default bot behavior?
|
||||
- [ ] No
|
||||
- [ ] Yes (**explain why**)
|
||||
|
||||
If this introduces more advanced or AI-heavy logic:
|
||||
|
||||
- [ ] Lightweight mode remains the default
|
||||
- [ ] More complex behavior is optional and thereby configurable
|
||||
|
||||
---
|
||||
|
||||
## AI Assistance
|
||||
|
||||
- Was AI assistance (e.g. ChatGPT or similar tools) used while working on this change?
|
||||
- [ ] No
|
||||
- [ ] Yes (**explain below**)
|
||||
|
||||
If yes, please specify:
|
||||
|
||||
- AI tool or model used (e.g. ChatGPT, GPT-4, Claude, etc.)
|
||||
- Purpose of usage (e.g. brainstorming, refactoring, documentation, code generation)
|
||||
- Which parts of the change were influenced or generated
|
||||
- Whether the result was manually reviewed and adapted
|
||||
|
||||
AI assistance is allowed, but all submitted code must be fully understood, reviewed, and owned by the contributor.
|
||||
Any AI-influenced changes must be verified against existing CORE and PB logic. We expect contributors to be honest
|
||||
about what they do and do not understand.
|
||||
---
|
||||
|
||||
## Final Checklist
|
||||
|
||||
- [ ] Stability is not compromised
|
||||
- [ ] Performance impact is understood, tested, and acceptable
|
||||
- [ ] Added logic complexity is justified and explained
|
||||
- [ ] Documentation updated if needed
|
||||
|
||||
---
|
||||
|
||||
## Notes for Reviewers
|
||||
|
||||
Anything that significantly improves realism at the cost of stability or performance should be carefully discussed
|
||||
before merging.
|
||||
@@ -3,9 +3,8 @@
|
||||
##################################################
|
||||
|
||||
# Overview
|
||||
# "Randombot": randomly generated bots that log in separately from players and populate the world. Randombots may automatically grind, quest, level up, and upgrade equipment and can be invited to groups and given commands.
|
||||
# "AddClass bot": bots from the AddClassAccountPoolSize accounts. They are used for quickly adding a leveled and geared bot of any class to your party. They are recommended for a quick formation of a party.
|
||||
# "Altbot": characters created on player accounts, which may be logged in by the player and invited to groups and given commands like randombots. They are best suited for long-progression playthroughs.
|
||||
# "Randombot": randomly generated bots that log in separately from players and populate the world. Depending on settings, randombots may automatically grind, quest, and upgrade equipment and can be invited to groups and given commands.
|
||||
# "Altbot": characters created on player accounts, which may be logged in by the player and invited to groups and given commands like randombots. Depending on settings, altbots can be limited to characters on the active player's account or in the active player's guild.
|
||||
# Information about commands to control bots and set their strategies can be found on the wiki at https://github.com/mod-playerbots/mod-playerbots/wiki/Playerbot-Commands.
|
||||
|
||||
####################################################################################################
|
||||
@@ -22,11 +21,10 @@
|
||||
# THRESHOLDS
|
||||
# QUESTS
|
||||
# COMBAT
|
||||
# GREATER BUFFS STRATEGIES
|
||||
# PALADIN BUFFS STRATEGIES
|
||||
# CHEATS
|
||||
# SPELLS
|
||||
# FLIGHTPATH
|
||||
# PROFESSIONS
|
||||
# RANDOMBOT-SPECIFIC SETTINGS
|
||||
# GENERAL
|
||||
# LEVELS
|
||||
@@ -46,7 +44,7 @@
|
||||
# HUNTER
|
||||
# ROGUE
|
||||
# PRIEST
|
||||
# DEATH KNIGHT
|
||||
# DEATHKNIGHT
|
||||
# SHAMAN
|
||||
# MAGE
|
||||
# WARLOCK
|
||||
@@ -57,7 +55,7 @@
|
||||
# HUNTER
|
||||
# ROGUE
|
||||
# PRIEST
|
||||
# DEATH KNIGHT
|
||||
# DEATHKNIGHT
|
||||
# SHAMAN
|
||||
# MAGE
|
||||
# WARLOCK
|
||||
@@ -92,20 +90,17 @@ AiPlayerbot.MinRandomBots = 500
|
||||
AiPlayerbot.MaxRandomBots = 500
|
||||
|
||||
# Randombot accounts
|
||||
# If you are not using any expansion at all, you may have to set this manually, in which case please
|
||||
# ensure that RandomBotAccountCount is at least greater than (MaxRandomBots / 10 + AddClassAccountPoolSize)
|
||||
# If you are not using any expansion at all, you may have to set this manually, in which case please ensure that RandomBotAccountCount is at least greater than (MaxRandomBots / 10 + AddClassAccountPoolSize)
|
||||
# Default: 0 (automatic)
|
||||
AiPlayerbot.RandomBotAccountCount = 0
|
||||
|
||||
# Delete all randombot accounts
|
||||
# To apply this, set the number to 1 and run the Worldserver. Once deletion is complete, if you would
|
||||
# like to recreate randombots, set the number back to 0 and rerun the Worldserver.
|
||||
# To apply this, set the number to 1 and run the Worldserver. Once deletion is complete, if you would like to recreate randombots, set the number back to 0 and rerun the Worldserver.
|
||||
AiPlayerbot.DeleteRandomBotAccounts = 0
|
||||
|
||||
# Disable randombots when no real players are logged in
|
||||
# Default: 0 (randombots will login when server starts)
|
||||
# If enabled, randombots will only log in 30 seconds (default) after a real player logs in, and will
|
||||
# log out 300 seconds (default) after all real players log out
|
||||
# If enabled, randombots will only log in 30 seconds (default) after a real player logs in, and will log out 300 seconds (default) after all real players log out
|
||||
AiPlayerbot.DisabledWithoutRealPlayer = 0
|
||||
AiPlayerbot.DisabledWithoutRealPlayerLoginDelay = 30
|
||||
AiPlayerbot.DisabledWithoutRealPlayerLogoutDelay = 300
|
||||
@@ -157,8 +152,7 @@ AiPlayerbot.AllowGuildBots = 1
|
||||
AiPlayerbot.AllowTrustedAccountBots = 1
|
||||
|
||||
# Randombots will create guilds with nearby randombots
|
||||
# Note: currently, randombots will not invite more bots after a guild is created,
|
||||
# meaning randombot guilds will have only the 10 initial randombots needed to sign the charter
|
||||
# Note: currently, randombots will not invite more bots after a guild is created (i.e., randombot guilds will have only the 10 initial randombots needed to sign the charter)
|
||||
# Default: 0 (disabled)
|
||||
AiPlayerbot.RandomBotGuildNearby = 0
|
||||
|
||||
@@ -192,8 +186,7 @@ AiPlayerbot.AutoInitOnly = 0
|
||||
# Default: 1.0 (same with the player)
|
||||
AiPlayerbot.AutoInitEquipLevelLimitRatio = 1.0
|
||||
|
||||
# Bot automatically trains spells when talking to trainer
|
||||
# yes = train all available spells as long as the bot has the money, free = auto trains with no money cost, no = only list spells
|
||||
# Bot automatically trains spells when talking to trainer (yes = train all available spells as long as the bot has the money, free = auto trains with no money cost, no = only list spells)
|
||||
AiPlayerbot.AutoTrainSpells = yes
|
||||
|
||||
#
|
||||
@@ -270,7 +263,7 @@ AiPlayerbot.UseFastFlyMountAtMinLevel = 70
|
||||
AiPlayerbot.RandomBotShowHelmet = 1
|
||||
AiPlayerbot.RandomBotShowCloak = 1
|
||||
|
||||
# Toggles whether altbots will automatically equip items in their inventory that are sufficient upgrades
|
||||
# Randombots and altbots automatically equip upgrades (bots will equip any item obtained from looting or a quest if they are sufficient upgrades)
|
||||
# Default: 1 (enabled)
|
||||
AiPlayerbot.AutoEquipUpgradeLoot = 1
|
||||
|
||||
@@ -318,8 +311,7 @@ AiPlayerbot.GlobalCooldown = 500
|
||||
# Max wait time when moving
|
||||
AiPlayerbot.MaxWaitForMove = 5000
|
||||
|
||||
# Enable/disable use of MoveSplinePath for bot movement
|
||||
# Disabling will result in more erratic movement but is required for stuns, snares, and roots to work on bots
|
||||
# Disable use of MoveSplinePath for bot movement, will result in more erratic bot movement but means stun/snare/root/etc will work on bots (they wont reliably work when MoveSplinePath is enabled, though slowing effects still work ok)
|
||||
# Default: 0 - MoveSplinePath enabled
|
||||
# 1 - MoveSplinePath disabled in BG/Arena only
|
||||
# 2 - MoveSplinePath disabled everywhere
|
||||
@@ -413,11 +405,10 @@ AiPlayerbot.HighMana = 65
|
||||
#
|
||||
#
|
||||
|
||||
# Bots pick their quest rewards
|
||||
# yes = picks the most useful item, no = list all rewards, ask = pick useful item and lists if multiple
|
||||
# Bots pick their quest rewards (yes = picks the most useful item, no = list all rewards, ask = pick useful item and lists if multiple)
|
||||
AiPlayerbot.AutoPickReward = yes
|
||||
|
||||
# Sync quests with player (bots will complete quests the moment you hand them in and will not loot quest items.)
|
||||
# Sync quests with player (Bots will complete quests the moment you hand them in and will not loot quest items.)
|
||||
# Default: 1 (enabled)
|
||||
AiPlayerbot.SyncQuestWithPlayer = 1
|
||||
|
||||
@@ -442,7 +433,7 @@ AiPlayerbot.DropObsoleteQuests = 1
|
||||
# Auto add dungeon/raid strategies when entering the instance if implemented
|
||||
AiPlayerbot.ApplyInstanceStrategies = 1
|
||||
|
||||
# Enable auto avoid aoe strategy
|
||||
# Enable auto avoid aoe strategy (experimental)
|
||||
# Default: 1 (enabled)
|
||||
AiPlayerbot.AutoAvoidAoe = 1
|
||||
|
||||
@@ -469,7 +460,7 @@ AiPlayerbot.FleeingEnabled = 1
|
||||
####################################################################################################
|
||||
|
||||
####################################################################################################
|
||||
# GREATER BUFFS STRATEGIES
|
||||
# PALADIN BUFFS STRATEGIES
|
||||
#
|
||||
#
|
||||
|
||||
@@ -492,13 +483,12 @@ AiPlayerbot.RPWarningCooldown = 30
|
||||
#
|
||||
|
||||
# Enable/Disable maintenance command
|
||||
# Learn all available spells and skills, assign talent points, refresh consumables, repair, enchant equipment, socket gems, etc.
|
||||
# Applies if bot's level is above AiPlayerbot.MinEnchantingBotLevel
|
||||
# Learn all available spells and skills, refresh consumables, repair, enchant equipment and socket gems if bot's level is above AiPlayerbot.MinEnchantingBotLevel
|
||||
# Default: 1 (enabled)
|
||||
AiPlayerbot.MaintenanceCommand = 1
|
||||
|
||||
# Enable/Disable specific maintenance command functionality for alt bots
|
||||
# Disable to prevent players from giving free bags, spells, skill levels, etc. to their alt bots
|
||||
# Disable to prevent players from giving free bags, spells, skill levels etc to their alt bots
|
||||
# Default: 1 (enabled)
|
||||
AiPlayerbot.AltMaintenanceAmmo = 1
|
||||
AiPlayerbot.AltMaintenanceFood = 1
|
||||
@@ -510,7 +500,6 @@ AiPlayerbot.AltMaintenanceBags = 1
|
||||
AiPlayerbot.AltMaintenanceMounts = 1
|
||||
AiPlayerbot.AltMaintenanceSkills = 1
|
||||
|
||||
# "Special Spells" consist of any spells listed in AiPlayerbot.RandomBotSpellIds and Death Gate for Death Knights
|
||||
AiPlayerbot.AltMaintenanceClassSpells = 1
|
||||
AiPlayerbot.AltMaintenanceAvailableSpells = 1
|
||||
AiPlayerbot.AltMaintenanceSpecialSpells = 1
|
||||
@@ -525,8 +514,8 @@ AiPlayerbot.AltMaintenanceReputation = 1
|
||||
AiPlayerbot.AltMaintenanceAttunementQuests = 1
|
||||
AiPlayerbot.AltMaintenanceKeyring = 1
|
||||
|
||||
# Enable/Disable autogear command, which automatically upgrades bots' gear
|
||||
# The quality is limited by AutoGearQualityLimit and AutoGearScoreLimit
|
||||
|
||||
# Enable/Disable autogear command, which automatically upgrades bots' gear; the quality is limited by AutoGearQualityLimit and AutoGearScoreLimit
|
||||
# Default: 1 (enabled)
|
||||
AiPlayerbot.AutoGearCommand = 1
|
||||
|
||||
@@ -590,30 +579,6 @@ AiPlayerbot.BotTaxiGapJitterMs = 100
|
||||
#
|
||||
####################################################################################################
|
||||
|
||||
####################################################################################################
|
||||
# PROFESSIONS
|
||||
# Note: Random bots currently do not get professions
|
||||
#
|
||||
|
||||
# Automatically adds the 'master fishing' strategy to bots that have the fishing skill when the bots master fishes.
|
||||
# Default: 1 (Enabled)
|
||||
AiPlayerbot.EnableFishingWithMaster = 1
|
||||
|
||||
# Distance from itself (in yards) that a bot with a master will search for water to fish
|
||||
AiPlayerbot.FishingDistanceFromMaster = 10.0
|
||||
|
||||
# Distance from itself (in yards) that a bot without a master will search for water to fish
|
||||
# Currently not relevant since masterless bots will not fish
|
||||
AiPlayerbot.FishingDistance = 40.0
|
||||
|
||||
# Distance from water (in yards) beyond which a bot will remove the 'master fishing' strategy
|
||||
AiPlayerbot.EndFishingWithMaster = 30.0
|
||||
|
||||
#
|
||||
#
|
||||
#
|
||||
####################################################################################################
|
||||
|
||||
#######################################
|
||||
# #
|
||||
# RANDOMBOT-SPECIFIC SETTINGS #
|
||||
@@ -670,7 +635,7 @@ AiPlayerbot.DisableDeathKnightLogin = 0
|
||||
# Default: 0 (disabled)
|
||||
AiPlayerbot.LimitTalentsExpansion = 0
|
||||
|
||||
# Configure randombot trading (0: Disabled, 1: Enabled, 2: Only Buy, 3: Only Sell)
|
||||
# Configure randombots and addClass bot trading (0: Disabled, 1: Enabled, 2: Only Buy, 3: Only Sell)
|
||||
# Default: 1 (enabled)
|
||||
AiPlayerbot.EnableRandomBotTrading = 1
|
||||
|
||||
@@ -735,7 +700,7 @@ AiPlayerbot.RandomGearQualityLimit = 3
|
||||
# Max iLVL Phase 1(MC, Ony, ZG) = 78 | Phase 2(BWL) = 83 | Phase 2.5(AQ40) = 88 | Phase 3(Naxx40) = 92
|
||||
# TBC
|
||||
# Max iLVL Tier 4 = 120 | Tier 5 = 133 | Tier 6 = 164
|
||||
# Max iLVL Phase 1(Kara, Gruul, Mag) = 125 | Phase 2(SSC, TK, ZA) = 141 | Phase 3(Hyjal, BT) = 156 | Phase 4(Sunwell) = 164
|
||||
# Max iLVL Phase 1(Kara, Gruul, Mag) = 125 | Phase 1.5(ZA) = 138 | Phase 2(SC, TK) = 141 | Phase 3(Hyjal, BT) = 156 | Phase 4(Sunwell) = 164
|
||||
# Wotlk
|
||||
# Max iLVL Tier 7(10/25) = 200/213 | Tier 8(10/25) = 225/232 | Tier 9(10/25) = 232/245 | Tier 10(10/25/HC) = 251/264/290
|
||||
# Max iLVL Phase 1(Naxx) = 224 | Phase 2(Ulduar) = 245 | Phase 3(ToC) = 258 | Phase 4(ICC) = 290
|
||||
@@ -746,8 +711,7 @@ AiPlayerbot.RandomGearScoreLimit = 0
|
||||
# Default: 1 (enabled)
|
||||
AiPlayerbot.IncrementalGearInit = 1
|
||||
|
||||
# Set minimum level of bots that will enchant and socket gems into their equipment with maintenance
|
||||
# If greater than RandomBotMaxlevel, bots will not automatically enchant equipment or socket gems
|
||||
# Set minimum level of bots that will enchant their equipment (if greater than RandomBotMaxlevel, bots will not enchant equipment)
|
||||
# Default: 60
|
||||
AiPlayerbot.MinEnchantingBotLevel = 60
|
||||
|
||||
@@ -899,15 +863,13 @@ AiPlayerbot.OpenGoSpell = 6477
|
||||
#
|
||||
|
||||
# Additional randombot strategies
|
||||
# Strategies added here are applied to all randombots, in addition (or subtraction) to spec/role-based default strategies.
|
||||
# These rules are processed after the defaults.
|
||||
# Strategies added here are applied to all randombots, in addition (or subtraction) to spec/role-based default strategies. These rules are processed after the defaults.
|
||||
# Example: "+threat,-potions"
|
||||
AiPlayerbot.RandomBotCombatStrategies = ""
|
||||
AiPlayerbot.RandomBotNonCombatStrategies = ""
|
||||
|
||||
# Additional altbot strategies
|
||||
# Strategies added here are applied to all altbots, in addition (or subtraction) to spec/role-based default strategies.
|
||||
# These rules are processed after the defaults.
|
||||
# Strategies added here are applied to all altbots, in addition (or subtraction) to spec/role-based default strategies. These rules are processed after the defaults.
|
||||
AiPlayerbot.CombatStrategies = ""
|
||||
AiPlayerbot.NonCombatStrategies = ""
|
||||
|
||||
@@ -1493,7 +1455,7 @@ AiPlayerbot.PremadeSpecLink.5.5.80 = 50332031003--005323241223112003102311351
|
||||
####################################################################################################
|
||||
|
||||
####################################################################################################
|
||||
# DEATH KNIGHT
|
||||
# DEATHKNIGHT
|
||||
#
|
||||
#
|
||||
|
||||
@@ -1816,7 +1778,7 @@ AiPlayerbot.RandomClassSpecIndex.5.2 = 2
|
||||
####################################################################################################
|
||||
|
||||
####################################################################################################
|
||||
# DEATH KNIGHT
|
||||
# DEATHKNIGHT
|
||||
#
|
||||
#
|
||||
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
DELETE FROM ai_playerbot_texts WHERE name IN ('no_fishing_pole_error');
|
||||
DELETE FROM ai_playerbot_texts_chance WHERE name IN ('no_fishing_pole_error');
|
||||
|
||||
INSERT INTO ai_playerbot_texts (id, name, text, say_type, reply_type, text_loc1, text_loc2, text_loc3, text_loc4, text_loc5, text_loc6, text_loc7, text_loc8) VALUES
|
||||
(1736, 'no_fishing_pole_error', "I don't have a Fishing Pole", 0, 0,
|
||||
"낚싯대가 없습니다",
|
||||
"Je n’ai pas de canne à pêche",
|
||||
"Ich habe keine Angelrute",
|
||||
"我沒有釣魚竿",
|
||||
"我没有钓鱼竿",
|
||||
"No tengo una caña de pescar",
|
||||
"No tengo una caña de pescar",
|
||||
"У меня нет удочки");
|
||||
|
||||
INSERT INTO ai_playerbot_texts_chance (name, probability) VALUES ('no_fishing_pole_error', 100);
|
||||
@@ -1,510 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "FishingAction.h"
|
||||
#include "FishValues.h"
|
||||
#include "Event.h"
|
||||
|
||||
#include "GridNotifiers.h"
|
||||
#include "GridNotifiersImpl.h"
|
||||
#include "ItemPackets.h"
|
||||
#include "LastMovementValue.h"
|
||||
#include "Map.h"
|
||||
#include "MovementActions.h"
|
||||
#include "Object.h"
|
||||
#include "PlayerbotAI.h"
|
||||
#include "PlayerbotTextMgr.h"
|
||||
#include "Playerbots.h"
|
||||
#include "Position.h"
|
||||
|
||||
uint32 const FISHING_SPELL = 7620;
|
||||
uint32 const FISHING_POLE = 6256;
|
||||
uint32 const FISHING_BOBBER = 35591;
|
||||
float const MIN_DISTANCE_TO_WATER = 10.0f; // Minimum spell distance
|
||||
float const MAX_DISTANCE_TO_WATER = 20.0f; // Maximum spell distance
|
||||
float const HEIGHT_ABOVE_WATER_TOLERANCE = 1.0f; // Can stand in up to 1 unit of water and still fish.
|
||||
float const SEARCH_INCREMENT = 2.5f;
|
||||
float const HEIGHT_SEARCH_BUFFER = 10.0f; // Height buffer to prevent potentially missing the model the bot is standing on.
|
||||
float const SEARCH_LAND_BUFFER = 0.5f;
|
||||
uint32 const FISHING_LOCATION_TIMEOUT = 180000; //Three minutes
|
||||
|
||||
static bool IsFishingPole(Item* const item)
|
||||
{
|
||||
if (!item)
|
||||
return false;
|
||||
const ItemTemplate* proto = item->GetTemplate();
|
||||
return proto && proto->Class == ITEM_CLASS_WEAPON &&
|
||||
proto->SubClass == ITEM_SUBCLASS_WEAPON_FISHING_POLE;
|
||||
}
|
||||
|
||||
float HasFishableWaterOrLand(float x, float y, float z, Map* map, uint32 phaseMask, bool checkForLand=false)
|
||||
{
|
||||
if (!map)
|
||||
return INVALID_HEIGHT;
|
||||
|
||||
LiquidData const& liq = map->GetLiquidData(phaseMask, x, y, z+HEIGHT_ABOVE_WATER_TOLERANCE, DEFAULT_COLLISION_HEIGHT, MAP_ALL_LIQUIDS);
|
||||
float ground = map->GetHeight(phaseMask, x, y, z + HEIGHT_SEARCH_BUFFER, true);
|
||||
if (liq.Entry == MAP_LIQUID_TYPE_NO_WATER)
|
||||
{
|
||||
if (checkForLand)
|
||||
return ground;
|
||||
return INVALID_HEIGHT;
|
||||
}
|
||||
if (checkForLand)
|
||||
{
|
||||
if (ground > liq.Level - HEIGHT_ABOVE_WATER_TOLERANCE)
|
||||
return ground;
|
||||
return INVALID_HEIGHT;
|
||||
}
|
||||
|
||||
if (liq.Level + HEIGHT_ABOVE_WATER_TOLERANCE > ground)
|
||||
{
|
||||
if (abs(liq.DepthLevel) < 0.5f) // too shallow to fish in.
|
||||
return INVALID_HEIGHT;
|
||||
return liq.Level;
|
||||
}
|
||||
return INVALID_HEIGHT;
|
||||
}
|
||||
|
||||
bool HasLosToWater(Player* bot, float wx, float wy, float waterZ)
|
||||
{
|
||||
float z = bot->GetCollisionHeight() + bot->GetPositionZ();
|
||||
return bot->GetMap()->isInLineOfSight(
|
||||
bot->GetPositionX(), bot->GetPositionY(), z,
|
||||
wx, wy, waterZ,
|
||||
bot->GetPhaseMask(),
|
||||
LINEOFSIGHT_ALL_CHECKS,
|
||||
VMAP::ModelIgnoreFlags::Nothing);
|
||||
}
|
||||
|
||||
WorldPosition FindLandFromPosition(PlayerbotAI* botAI, float startDistance, float endDistance, float increment, float orientation, WorldPosition targetPos, float fishingSearchWindow, bool checkLOS = true)
|
||||
{
|
||||
Player* bot = botAI->GetBot();
|
||||
Map* map = bot->GetMap();
|
||||
uint32 phaseMask = bot->GetPhaseMask();
|
||||
Player* master = botAI->GetMaster();
|
||||
|
||||
float targetX = targetPos.GetPositionX();
|
||||
float targetY = targetPos.GetPositionY();
|
||||
float targetZ = targetPos.GetPositionZ();
|
||||
|
||||
for (float dist = startDistance; dist <= endDistance; dist += increment)
|
||||
{
|
||||
//step backwards from position to bot to find edge of shore.
|
||||
float checkX = targetX - dist * cos(orientation);
|
||||
float checkY = targetY - dist * sin(orientation);
|
||||
|
||||
float groundZ = map->GetHeight(phaseMask, checkX, checkY, targetZ + HEIGHT_SEARCH_BUFFER, true);
|
||||
|
||||
if (groundZ == INVALID_HEIGHT)
|
||||
continue;
|
||||
|
||||
LiquidData const& liq = map->GetLiquidData(phaseMask, checkX, checkY, targetZ, DEFAULT_COLLISION_HEIGHT, MAP_ALL_LIQUIDS);
|
||||
if (liq.Entry == MAP_LIQUID_TYPE_NO_WATER || groundZ > liq.DepthLevel + HEIGHT_ABOVE_WATER_TOLERANCE)
|
||||
{
|
||||
if (checkLOS)
|
||||
{
|
||||
bool hasLOS = map->isInLineOfSight(checkX, checkY, groundZ, targetX, targetY, targetZ, phaseMask, LINEOFSIGHT_ALL_CHECKS, VMAP::ModelIgnoreFlags::Nothing);
|
||||
if (!hasLOS)
|
||||
continue;
|
||||
}
|
||||
// Add a distance check for the position to prevent the bot from moving out of range to the master.
|
||||
if (master && botAI->HasStrategy("follow", BOT_STATE_NON_COMBAT) && master->GetDistance(checkX, checkY, groundZ) > fishingSearchWindow - SEARCH_LAND_BUFFER)
|
||||
continue;
|
||||
|
||||
return WorldPosition(bot->GetMapId(), checkX, checkY, groundZ);
|
||||
}
|
||||
}
|
||||
|
||||
return WorldPosition();
|
||||
}
|
||||
|
||||
WorldPosition FindLandRadialFromPosition (PlayerbotAI* botAI, WorldPosition targetPos, float startDistance, float endDistance, float increment, float fishingSearchWindow, int angles = 16)
|
||||
{
|
||||
Player* bot = botAI->GetBot();
|
||||
const int numDirections = angles;
|
||||
std::vector<WorldPosition> boundaryPoints;
|
||||
Player* master = botAI->GetMaster();
|
||||
if (!master)
|
||||
return WorldPosition();
|
||||
|
||||
Map* map = bot->GetMap();
|
||||
uint32 phaseMask = bot->GetPhaseMask();
|
||||
|
||||
float targetX = targetPos.GetPositionX();
|
||||
float targetY = targetPos.GetPositionY();
|
||||
float targetZ = targetPos.GetPositionZ();
|
||||
|
||||
for (float dist = startDistance; dist <= endDistance; dist += increment)
|
||||
{
|
||||
for (int i = 0; i < numDirections; ++i)
|
||||
{
|
||||
float angle = (2.0f * M_PI * i) / numDirections;
|
||||
float checkX = targetX - cos(angle) * dist;
|
||||
float checkY = targetY - sin(angle) * dist;
|
||||
|
||||
float groundZ = HasFishableWaterOrLand(checkX, checkY, targetZ, map, phaseMask, true);
|
||||
|
||||
if (groundZ == INVALID_HEIGHT)
|
||||
continue;
|
||||
|
||||
if (map->isInLineOfSight(checkX, checkY, groundZ, targetX, targetY, targetZ, phaseMask, LINEOFSIGHT_ALL_CHECKS, VMAP::ModelIgnoreFlags::Nothing) && master->GetDistance(checkX, checkY, groundZ) > fishingSearchWindow - SEARCH_LAND_BUFFER)
|
||||
continue;
|
||||
|
||||
boundaryPoints.emplace_back(WorldPosition(bot->GetMapId(), checkX, checkY, groundZ));
|
||||
}
|
||||
|
||||
if (!boundaryPoints.empty())
|
||||
break;
|
||||
}
|
||||
|
||||
if (boundaryPoints.empty())
|
||||
return WorldPosition();
|
||||
|
||||
if (boundaryPoints.size() == 1)
|
||||
return boundaryPoints[0];
|
||||
|
||||
float minDistance = FLT_MAX;
|
||||
WorldLocation closestPoint = WorldPosition();
|
||||
for (auto const& pos : boundaryPoints)
|
||||
{
|
||||
float distance = bot->GetExactDist2d(&pos);
|
||||
if (distance < minDistance)
|
||||
{
|
||||
minDistance = distance;
|
||||
closestPoint = pos;
|
||||
}
|
||||
}
|
||||
return closestPoint;
|
||||
}
|
||||
|
||||
WorldPosition FindWaterRadial(Player* bot, float x, float y, float z, Map* map, uint32 phaseMask, float minDistance, float maxDistance, float increment, bool checkLOS, int numDirections)
|
||||
{
|
||||
std::vector<WorldPosition> boundaryPoints;
|
||||
|
||||
float dist = minDistance;
|
||||
while (dist <= maxDistance)
|
||||
{
|
||||
for (int i = 0; i < numDirections; ++i)
|
||||
{
|
||||
float angle = (2.0f * M_PI * i) / numDirections;
|
||||
float checkX = x + cos(angle) * dist;
|
||||
float checkY = y + sin(angle) * dist;
|
||||
|
||||
float waterZ = HasFishableWaterOrLand(checkX, checkY, z, map, phaseMask);
|
||||
|
||||
if (waterZ == INVALID_HEIGHT)
|
||||
continue;
|
||||
|
||||
if (checkLOS && !HasLosToWater(bot, checkX, checkY, waterZ))
|
||||
continue;
|
||||
|
||||
boundaryPoints.emplace_back(WorldPosition(bot->GetMapId(), checkX, checkY, waterZ));
|
||||
}
|
||||
|
||||
if (!boundaryPoints.empty())
|
||||
break;
|
||||
|
||||
dist += increment;
|
||||
}
|
||||
|
||||
if (boundaryPoints.empty())
|
||||
return WorldPosition();
|
||||
|
||||
if (boundaryPoints.size() == 1)
|
||||
return boundaryPoints[0];
|
||||
// return the central point in the identified positions in to try to be perpendicular to the shore.
|
||||
return boundaryPoints[boundaryPoints.size() / 2];
|
||||
}
|
||||
|
||||
WorldPosition FindFishingHole(PlayerbotAI* botAI)
|
||||
{
|
||||
Player* player = botAI->GetBot();
|
||||
GuidVector gos = PAI_VALUE(GuidVector, "nearest game objects no los");
|
||||
GameObject* nearestFishingHole = nullptr;
|
||||
float minDist = std::numeric_limits<float>::max();
|
||||
for (auto const& guid : gos)
|
||||
{
|
||||
GameObject* go = botAI->GetGameObject(guid);
|
||||
if (!go)
|
||||
continue;
|
||||
if (go->GetGoType() == GAMEOBJECT_TYPE_FISHINGHOLE)
|
||||
{
|
||||
float dist = player->GetDistance2d(go);
|
||||
if (dist < minDist)
|
||||
{
|
||||
minDist = dist;
|
||||
nearestFishingHole = go;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (nearestFishingHole)
|
||||
return WorldPosition(nearestFishingHole->GetMapId(), nearestFishingHole->GetPositionX(), nearestFishingHole->GetPositionY(), nearestFishingHole->GetPositionZ());
|
||||
|
||||
return WorldPosition();
|
||||
}
|
||||
|
||||
bool MoveNearWaterAction::Execute(Event event)
|
||||
{
|
||||
WorldPosition landSpot = AI_VALUE(WorldPosition, "fishing spot");
|
||||
if (landSpot.IsValid())
|
||||
return MoveTo(landSpot.GetMapId(), landSpot.GetPositionX(), landSpot.GetPositionY(), landSpot.GetPositionZ());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MoveNearWaterAction::isUseful()
|
||||
{
|
||||
if (!AI_VALUE(bool, "can fish"))
|
||||
return false;
|
||||
FishingSpotValue* fishingSpotValueObject = (FishingSpotValue*)context->GetValue<WorldPosition>("fishing spot");
|
||||
WorldPosition pos = fishingSpotValueObject->Get();
|
||||
return !pos.IsValid() || fishingSpotValueObject->IsStale(FISHING_LOCATION_TIMEOUT) ||
|
||||
bot->GetExactDist(&pos) < 0.1f;
|
||||
|
||||
}
|
||||
|
||||
bool MoveNearWaterAction::isPossible()
|
||||
{
|
||||
Player* master = botAI->GetMaster();
|
||||
float fishingSearchWindow;
|
||||
|
||||
if (master)
|
||||
fishingSearchWindow = sPlayerbotAIConfig->fishingDistanceFromMaster;
|
||||
else
|
||||
fishingSearchWindow = sPlayerbotAIConfig->fishingDistance;
|
||||
|
||||
WorldPosition fishingHole = FindFishingHole(botAI);
|
||||
|
||||
if (fishingHole.IsValid())
|
||||
{
|
||||
float distance = bot->GetExactDist2d(&fishingHole);
|
||||
bool hasLOS = bot->IsWithinLOS(fishingHole.GetPositionX(), fishingHole.GetPositionY(), fishingHole.GetPositionZ());
|
||||
// Water spot is in range, and we have LOS to it. Set bot position to fishing spot and do not move
|
||||
if (distance >= MIN_DISTANCE_TO_WATER &&
|
||||
distance <= MAX_DISTANCE_TO_WATER && hasLOS)
|
||||
{
|
||||
SET_AI_VALUE(WorldPosition, "fishing spot", WorldPosition(WorldPosition(bot->GetMapId(), bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ())));
|
||||
return false;
|
||||
}
|
||||
// Water spot is out of range, lets look for a spot to move to for the fishing hole.
|
||||
if (distance > MAX_DISTANCE_TO_WATER || distance < MIN_DISTANCE_TO_WATER)
|
||||
{
|
||||
float angle = bot->GetAngle(fishingHole.GetPositionX(), fishingHole.GetPositionY());
|
||||
WorldPosition landSpot = FindLandRadialFromPosition(botAI, fishingHole, MIN_DISTANCE_TO_WATER, MAX_DISTANCE_TO_WATER, SEARCH_INCREMENT, fishingSearchWindow, 32);
|
||||
if (landSpot.IsValid())
|
||||
{
|
||||
SET_AI_VALUE(WorldPosition, "fishing spot", landSpot);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Can the bot fish from current position?
|
||||
WorldPosition waterAtCurrentPos =
|
||||
FindWaterRadial(bot, bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ(), bot->GetMap(),
|
||||
bot->GetPhaseMask(), MIN_DISTANCE_TO_WATER, MAX_DISTANCE_TO_WATER, SEARCH_INCREMENT, true);
|
||||
if (waterAtCurrentPos.IsValid())
|
||||
{
|
||||
SET_AI_VALUE(WorldPosition, "fishing spot",
|
||||
WorldPosition(WorldPosition(bot->GetMapId(), bot->GetPositionX(), bot->GetPositionY(),
|
||||
bot->GetPositionZ())));
|
||||
return false;
|
||||
}
|
||||
// Lets find some water where we can fish.
|
||||
WorldPosition water = FindWaterRadial(
|
||||
bot, bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ(),
|
||||
bot->GetMap(), bot->GetPhaseMask(),
|
||||
MIN_DISTANCE_TO_WATER,
|
||||
fishingSearchWindow + MAX_DISTANCE_TO_WATER,
|
||||
SEARCH_INCREMENT, false);
|
||||
|
||||
if (!water.IsValid())
|
||||
return false;
|
||||
|
||||
bool hasLOS = bot->IsWithinLOS(water.GetPositionX(), water.GetPositionY(), water.GetPositionZ());
|
||||
float angle = bot->GetAngle(water.GetPositionX(), water.GetPositionY());
|
||||
WorldPosition landSpot =
|
||||
FindLandFromPosition(botAI, 0.0f, MAX_DISTANCE_TO_WATER, 1.0f, angle, water, fishingSearchWindow, false);
|
||||
|
||||
if (landSpot.IsValid())
|
||||
{
|
||||
SET_AI_VALUE(WorldPosition, "fishing spot", landSpot);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool EquipFishingPoleAction::Execute(Event event)
|
||||
{
|
||||
if (!_pole)
|
||||
return false;
|
||||
|
||||
WorldPacket eqPacket(CMSG_AUTOEQUIP_ITEM_SLOT, 2);
|
||||
eqPacket << _pole->GetGUID() << uint8(EQUIPMENT_SLOT_MAINHAND);
|
||||
WorldPackets::Item::AutoEquipItemSlot nicePacket(std::move(eqPacket));
|
||||
nicePacket.Read();
|
||||
bot->GetSession()->HandleAutoEquipItemSlotOpcode(nicePacket);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EquipFishingPoleAction::isUseful()
|
||||
{
|
||||
Item* mainHand = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND);
|
||||
if (IsFishingPole(mainHand))
|
||||
return false;
|
||||
|
||||
for (uint8 slot = INVENTORY_SLOT_ITEM_START; slot < INVENTORY_SLOT_ITEM_END; ++slot)
|
||||
{
|
||||
if (Item* item = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, slot))
|
||||
{
|
||||
if (IsFishingPole(item))
|
||||
{
|
||||
_pole = item;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (uint8 bag = INVENTORY_SLOT_BAG_START; bag < INVENTORY_SLOT_BAG_END; ++bag)
|
||||
{
|
||||
if (Bag* pBag = bot->GetBagByPos(bag))
|
||||
{
|
||||
for (uint32 j = 0; j < pBag->GetBagSize(); ++j)
|
||||
{
|
||||
if (Item* item = pBag->GetItemByPos(j))
|
||||
{
|
||||
if (IsFishingPole(item))
|
||||
{
|
||||
_pole = item;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (sRandomPlayerbotMgr->IsRandomBot(bot))
|
||||
{
|
||||
bot->StoreNewItemInBestSlots(FISHING_POLE, 1); // Try to get a fishing pole
|
||||
return true;
|
||||
}
|
||||
|
||||
Player* master = botAI->GetMaster();
|
||||
if (!master)
|
||||
return false;
|
||||
|
||||
std::string masterName = master->GetName();
|
||||
std::string text = sPlayerbotTextMgr->GetBotTextOrDefault(
|
||||
"no_fishing_pole_error", "I don't have a Fishing Pole",{});
|
||||
botAI->Whisper(text, masterName);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FishingAction::Execute(Event event)
|
||||
{
|
||||
WorldPosition target = WorldPosition();
|
||||
WorldPosition fishingHole = FindFishingHole(botAI);
|
||||
if (fishingHole.IsValid())
|
||||
{
|
||||
Position pos = fishingHole;
|
||||
float distance = bot->GetExactDist2d(&pos);
|
||||
bool hasLOS = bot->IsWithinLOS(fishingHole.GetPositionX(), fishingHole.GetPositionY(), fishingHole.GetPositionZ());
|
||||
if (distance < MAX_DISTANCE_TO_WATER &&
|
||||
distance > MIN_DISTANCE_TO_WATER && hasLOS)
|
||||
target = fishingHole;
|
||||
}
|
||||
if (!target.IsValid())
|
||||
{
|
||||
target = FindWaterRadial(bot, bot->GetPositionX(), bot->GetPositionY(),
|
||||
bot->GetPositionZ(), bot->GetMap(), bot->GetPhaseMask(),
|
||||
MIN_DISTANCE_TO_WATER, MAX_DISTANCE_TO_WATER, SEARCH_INCREMENT, true, 32);
|
||||
if (!target.IsValid())
|
||||
return false;
|
||||
}
|
||||
Position pos = target;
|
||||
|
||||
if (!bot->HasInArc(1.0, &pos, 1.0))
|
||||
{
|
||||
float angle = bot->GetAngle(pos.GetPositionX(), pos.GetPositionY());
|
||||
bot->SetOrientation(angle);
|
||||
if (!bot->IsRooted())
|
||||
bot->SendMovementFlagUpdate();
|
||||
}
|
||||
|
||||
EquipFishingPoleAction equipAction(botAI);
|
||||
if (equipAction.isUseful())
|
||||
return equipAction.Execute(event);
|
||||
|
||||
botAI->CastSpell(FISHING_SPELL, bot);
|
||||
botAI->ChangeStrategy("+use bobber", BOT_STATE_NON_COMBAT);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FishingAction::isUseful()
|
||||
{
|
||||
if (!AI_VALUE(bool, "can fish"))
|
||||
return false;
|
||||
|
||||
FishingSpotValue* fishingSpotValueObject = (FishingSpotValue*)context->GetValue<WorldPosition>("fishing spot");
|
||||
WorldPosition pos = fishingSpotValueObject->Get();
|
||||
|
||||
if (!pos.IsValid() || fishingSpotValueObject->IsStale(FISHING_LOCATION_TIMEOUT))
|
||||
return false;
|
||||
|
||||
return bot->GetExactDist(&pos) < 0.1f;
|
||||
}
|
||||
|
||||
bool UseBobberAction::isUseful()
|
||||
{
|
||||
return AI_VALUE(bool, "can use fishing bobber");
|
||||
}
|
||||
|
||||
bool UseBobberAction::Execute(Event event)
|
||||
{
|
||||
GuidVector gos = AI_VALUE(GuidVector, "nearest game objects no los");
|
||||
for (auto const& guid : gos)
|
||||
{
|
||||
if (GameObject* go = botAI->GetGameObject(guid))
|
||||
{
|
||||
if (go->GetEntry() != FISHING_BOBBER)
|
||||
continue;
|
||||
if (go->GetOwnerGUID() != bot->GetGUID())
|
||||
continue;
|
||||
if (go->getLootState() == GO_READY)
|
||||
{
|
||||
go->Use(bot);
|
||||
botAI->ChangeStrategy("-use bobber", BOT_STATE_NON_COMBAT);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool EndMasterFishingAction::Execute(Event event)
|
||||
{
|
||||
botAI->ChangeStrategy("-master fishing", BOT_STATE_NON_COMBAT);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EndMasterFishingAction::isUseful()
|
||||
{
|
||||
FishingSpotValue* fishingSpotValueObject = (FishingSpotValue*)context->GetValue<WorldPosition>("fishing spot");
|
||||
WorldPosition pos = fishingSpotValueObject->Get();
|
||||
if (pos.IsValid() && !fishingSpotValueObject->IsStale(FISHING_LOCATION_TIMEOUT) && pos == bot->GetPosition())
|
||||
return false;
|
||||
|
||||
WorldPosition nearWater = FindWaterRadial(bot, bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ(),
|
||||
bot->GetMap(), bot->GetPhaseMask(), MIN_DISTANCE_TO_WATER, sPlayerbotAIConfig->endFishingWithMaster, 10.0f);
|
||||
return !nearWater.IsValid();
|
||||
}
|
||||
|
||||
bool RemoveBobberStrategyAction::Execute(Event event)
|
||||
{
|
||||
botAI->ChangeStrategy("-use bobber", BOT_STATE_NON_COMBAT);
|
||||
return true;
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#ifndef _PLAYERBOT_FISHINGACTION_H
|
||||
#define _PLAYERBOT_FISHINGACTION_H
|
||||
|
||||
#include "Action.h"
|
||||
#include "MovementActions.h"
|
||||
#include "Event.h"
|
||||
#include "Playerbots.h"
|
||||
|
||||
extern const uint32 FISHING_SPELL;
|
||||
extern const uint32 FISHING_POLE;
|
||||
extern const uint32 FISHING_BOBBER;
|
||||
|
||||
WorldPosition FindWaterRadial(Player* bot, float x, float y, float z, Map* map, uint32 phaseMask, float minDistance, float maxDistance, float increment, bool checkLOS=false, int numDirections = 16);
|
||||
|
||||
class PlayerbotAI;
|
||||
|
||||
class FishingAction : public Action
|
||||
{
|
||||
public:
|
||||
FishingAction(PlayerbotAI* botAI) : Action(botAI, "go fishing"){}
|
||||
bool Execute(Event event) override;
|
||||
bool isUseful() override;
|
||||
};
|
||||
|
||||
class EquipFishingPoleAction : public Action
|
||||
{
|
||||
public:
|
||||
EquipFishingPoleAction(PlayerbotAI* botAI) : Action(botAI, "equip fishing pole") {}
|
||||
bool Execute(Event event) override;
|
||||
bool isUseful() override;
|
||||
private:
|
||||
Item* _pole = nullptr;
|
||||
};
|
||||
|
||||
class MoveNearWaterAction : public MovementAction
|
||||
{
|
||||
public:
|
||||
MoveNearWaterAction(PlayerbotAI* botAI): MovementAction(botAI, "move near water") {}
|
||||
bool Execute(Event event) override;
|
||||
bool isUseful() override;
|
||||
bool isPossible() override;
|
||||
};
|
||||
|
||||
class UseBobberAction : public Action
|
||||
{
|
||||
public:
|
||||
UseBobberAction(PlayerbotAI* botAI) : Action(botAI, "use fishing bobber") {}
|
||||
bool Execute(Event event) override;
|
||||
bool isUseful() override;
|
||||
};
|
||||
|
||||
class EndMasterFishingAction : public Action
|
||||
{
|
||||
public:
|
||||
EndMasterFishingAction(PlayerbotAI* botAI) : Action(botAI, "end master fishing") {}
|
||||
bool Execute(Event event) override;
|
||||
bool isUseful() override;
|
||||
};
|
||||
|
||||
class RemoveBobberStrategyAction : public Action
|
||||
{
|
||||
public:
|
||||
RemoveBobberStrategyAction(PlayerbotAI* botAI) : Action(botAI, "remove bobber strategy") {}
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
#endif
|
||||
@@ -1,87 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "BattlegroundStrategy.h"
|
||||
|
||||
#include "Playerbots.h"
|
||||
|
||||
void BGStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(new TriggerNode("often", { NextAction("bg join", relevance)}));
|
||||
triggers.push_back(new TriggerNode("bg invite active", { NextAction("bg status check", relevance)}));
|
||||
triggers.push_back(new TriggerNode("timer", { NextAction("bg strategy check", relevance)}));
|
||||
}
|
||||
|
||||
BGStrategy::BGStrategy(PlayerbotAI* botAI) : PassTroughStrategy(botAI) {}
|
||||
|
||||
void BattlegroundStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(new TriggerNode("bg waiting", { NextAction("bg move to start", ACTION_BG)}));
|
||||
triggers.push_back(new TriggerNode("bg active", { NextAction("bg move to objective", ACTION_BG)}));
|
||||
triggers.push_back(new TriggerNode("often", { NextAction("bg check objective", ACTION_BG + 1)}));
|
||||
triggers.push_back(new TriggerNode("dead", { NextAction("bg reset objective force", ACTION_EMERGENCY)}));
|
||||
}
|
||||
|
||||
void WarsongStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(new TriggerNode("bg active", { NextAction("bg check flag", ACTION_EMERGENCY )}));
|
||||
triggers.push_back(new TriggerNode("enemy flagcarrier near", { NextAction("attack enemy flag carrier", ACTION_RAID + 1.0f)}));
|
||||
triggers.push_back(new TriggerNode("team flagcarrier near", { NextAction("bg protect fc", ACTION_RAID)}));
|
||||
triggers.push_back(new TriggerNode("often", { NextAction("bg use buff", ACTION_BG)}));
|
||||
triggers.push_back(new TriggerNode("low health", { NextAction("bg use buff", ACTION_MOVE)}));
|
||||
triggers.push_back(new TriggerNode("low mana", { NextAction("bg use buff", ACTION_MOVE)}));
|
||||
triggers.push_back(new TriggerNode("player has flag", { NextAction("bg move to objective", ACTION_EMERGENCY)}));
|
||||
triggers.push_back(new TriggerNode("timer bg", { NextAction("bg reset objective force", ACTION_EMERGENCY)}));
|
||||
}
|
||||
|
||||
void AlteracStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(new TriggerNode("alliance no snowfall gy", { NextAction("bg move to objective", ACTION_EMERGENCY)}));
|
||||
triggers.push_back(new TriggerNode("timer bg", { NextAction("bg reset objective force", ACTION_EMERGENCY)}));
|
||||
}
|
||||
|
||||
void ArathiStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(new TriggerNode("bg active", { NextAction("bg check flag", ACTION_EMERGENCY)}));
|
||||
triggers.push_back(new TriggerNode("often", { NextAction("bg use buff", ACTION_BG)}));
|
||||
triggers.push_back(new TriggerNode("low health", { NextAction("bg use buff", ACTION_MOVE)}));
|
||||
triggers.push_back(new TriggerNode("low mana", { NextAction("bg use buff", ACTION_MOVE)}));
|
||||
}
|
||||
|
||||
void EyeStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(new TriggerNode("bg active", { NextAction("bg check flag", ACTION_EMERGENCY)}));
|
||||
triggers.push_back(new TriggerNode("often", { NextAction("bg use buff", ACTION_BG)}));
|
||||
triggers.push_back(new TriggerNode("low health", { NextAction("bg use buff", ACTION_MOVE)}));
|
||||
triggers.push_back(new TriggerNode("low mana", { NextAction("bg use buff", ACTION_MOVE)}));
|
||||
triggers.push_back(new TriggerNode("enemy flagcarrier near", { NextAction("attack enemy flag carrier", ACTION_RAID)}));
|
||||
triggers.push_back(new TriggerNode("player has flag",{ NextAction("bg move to objective", ACTION_EMERGENCY)}));
|
||||
}
|
||||
|
||||
//TODO: Do Priorities
|
||||
void IsleStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(new TriggerNode("bg active", { NextAction("bg check flag", ACTION_MOVE)}));
|
||||
triggers.push_back(new TriggerNode("timer", { NextAction("enter vehicle", ACTION_MOVE + 8.0f)}));
|
||||
triggers.push_back(new TriggerNode("random", { NextAction("leave vehicle", ACTION_MOVE + 7.0f)}));
|
||||
triggers.push_back(new TriggerNode("in vehicle", { NextAction("hurl boulder", ACTION_MOVE + 9.0f)}));
|
||||
triggers.push_back(new TriggerNode("in vehicle", { NextAction("fire cannon", ACTION_MOVE + 9.0f)}));
|
||||
triggers.push_back(new TriggerNode("in vehicle", { NextAction("napalm", ACTION_MOVE + 9.0f)}));
|
||||
triggers.push_back(new TriggerNode("enemy is close", { NextAction("steam blast", ACTION_MOVE + 9.0f)}));
|
||||
triggers.push_back(new TriggerNode("in vehicle", { NextAction("ram", ACTION_MOVE + 9.0f)}));
|
||||
triggers.push_back(new TriggerNode("enemy is close", { NextAction("ram", ACTION_MOVE + 9.1f)}));
|
||||
triggers.push_back(new TriggerNode("enemy out of melee", { NextAction("steam rush", ACTION_MOVE + 9.2f)}));
|
||||
triggers.push_back(new TriggerNode("in vehicle", { NextAction("incendiary rocket", ACTION_MOVE + 9.0f)}));
|
||||
triggers.push_back(new TriggerNode("in vehicle", { NextAction("rocket blast", ACTION_MOVE + 9.0f)}));
|
||||
// this is bugged: it doesn't work, and stops glaive throw working (which is needed to take down gate)
|
||||
// triggers.push_back(new TriggerNode("in vehicle", { NextAction("blade salvo", ACTION_MOVE + 9.0f)}));
|
||||
triggers.push_back(new TriggerNode("in vehicle", { NextAction("glaive throw", ACTION_MOVE + 9.0f)}));
|
||||
}
|
||||
|
||||
void ArenaStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(
|
||||
new TriggerNode("no possible targets", { NextAction("arena tactics", ACTION_BG)}));
|
||||
}
|
||||
@@ -1,193 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "ChatCommandHandlerStrategy.h"
|
||||
|
||||
#include "Playerbots.h"
|
||||
|
||||
class ChatCommandActionNodeFactoryInternal : public NamedObjectFactory<ActionNode>
|
||||
{
|
||||
public:
|
||||
ChatCommandActionNodeFactoryInternal() { creators["tank attack chat shortcut"] = &tank_attack_chat_shortcut; }
|
||||
|
||||
private:
|
||||
static ActionNode* tank_attack_chat_shortcut(PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode("tank attack chat shortcut",
|
||||
/*P*/ {},
|
||||
/*A*/ {},
|
||||
/*C*/ { NextAction("attack my target", 100.0f) });
|
||||
}
|
||||
};
|
||||
|
||||
void ChatCommandHandlerStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
PassTroughStrategy::InitTriggers(triggers);
|
||||
|
||||
triggers.push_back(new TriggerNode("rep", { NextAction("reputation", relevance) }));
|
||||
triggers.push_back(new TriggerNode("q", { NextAction("query quest", relevance),
|
||||
NextAction("query item usage", relevance) }));
|
||||
triggers.push_back(new TriggerNode("add all loot", { NextAction("add all loot", relevance),
|
||||
NextAction("loot", relevance) }));
|
||||
triggers.push_back(new TriggerNode("u", { NextAction("use", relevance) }));
|
||||
triggers.push_back(new TriggerNode("c", { NextAction("item count", relevance) }));
|
||||
triggers.push_back(
|
||||
new TriggerNode("items", { NextAction("item count", relevance) }));
|
||||
triggers.push_back(new TriggerNode("inv", { NextAction("item count", relevance) }));
|
||||
triggers.push_back(new TriggerNode("e", { NextAction("equip", relevance) }));
|
||||
triggers.push_back(new TriggerNode("ue", { NextAction("unequip", relevance) }));
|
||||
triggers.push_back(new TriggerNode("t", { NextAction("trade", relevance) }));
|
||||
triggers.push_back(new TriggerNode("nt", { NextAction("trade", relevance) }));
|
||||
triggers.push_back(new TriggerNode("s", { NextAction("sell", relevance) }));
|
||||
triggers.push_back(new TriggerNode("b", { NextAction("buy", relevance) }));
|
||||
triggers.push_back(new TriggerNode("r", { NextAction("reward", relevance) }));
|
||||
triggers.push_back(
|
||||
new TriggerNode("attack", { NextAction("attack my target", relevance) }));
|
||||
triggers.push_back(
|
||||
new TriggerNode("accept", { NextAction("accept quest", relevance) }));
|
||||
triggers.push_back(
|
||||
new TriggerNode("follow", { NextAction("follow chat shortcut", relevance) }));
|
||||
triggers.push_back(
|
||||
new TriggerNode("stay", { NextAction("stay chat shortcut", relevance) }));
|
||||
triggers.push_back(
|
||||
new TriggerNode("move from group", { NextAction("move from group chat shortcut", relevance) }));
|
||||
triggers.push_back(
|
||||
new TriggerNode("flee", { NextAction("flee chat shortcut", relevance) }));
|
||||
triggers.push_back(new TriggerNode(
|
||||
"tank attack", { NextAction("tank attack chat shortcut", relevance) }));
|
||||
triggers.push_back(
|
||||
new TriggerNode("grind", { NextAction("grind chat shortcut", relevance) }));
|
||||
triggers.push_back(
|
||||
new TriggerNode("talk", { NextAction("gossip hello", relevance),
|
||||
NextAction("talk to quest giver", relevance) }));
|
||||
triggers.push_back(
|
||||
new TriggerNode("enter vehicle", { NextAction("enter vehicle", relevance) }));
|
||||
triggers.push_back(
|
||||
new TriggerNode("leave vehicle", { NextAction("leave vehicle", relevance) }));
|
||||
triggers.push_back(
|
||||
new TriggerNode("cast", { NextAction("cast custom spell", relevance) }));
|
||||
triggers.push_back(
|
||||
new TriggerNode("castnc", { NextAction("cast custom nc spell", relevance) }));
|
||||
triggers.push_back(
|
||||
new TriggerNode("revive", { NextAction("spirit healer", relevance) }));
|
||||
triggers.push_back(
|
||||
new TriggerNode("runaway", { NextAction("runaway chat shortcut", relevance) }));
|
||||
triggers.push_back(
|
||||
new TriggerNode("warning", { NextAction("runaway chat shortcut", relevance) }));
|
||||
triggers.push_back(
|
||||
new TriggerNode("max dps", { NextAction("max dps chat shortcut", relevance) }));
|
||||
triggers.push_back(
|
||||
new TriggerNode("attackers", { NextAction("tell attackers", relevance) }));
|
||||
triggers.push_back(
|
||||
new TriggerNode("target", { NextAction("tell target", relevance) }));
|
||||
triggers.push_back(
|
||||
new TriggerNode("ready", { NextAction("ready check", relevance) }));
|
||||
triggers.push_back(
|
||||
new TriggerNode("bwl", { NextAction("bwl chat shortcut", relevance) }));
|
||||
triggers.push_back(
|
||||
new TriggerNode("dps", { NextAction("tell estimated dps", relevance) }));
|
||||
triggers.push_back(
|
||||
new TriggerNode("disperse", { NextAction("disperse set", relevance) }));
|
||||
triggers.push_back(
|
||||
new TriggerNode("open items", { NextAction("open items", relevance) }));
|
||||
triggers.push_back(
|
||||
new TriggerNode("qi", { NextAction("query item usage", relevance) }));
|
||||
triggers.push_back(
|
||||
new TriggerNode("unlock items", { NextAction("unlock items", relevance) }));
|
||||
triggers.push_back(
|
||||
new TriggerNode("unlock traded item", { NextAction("unlock traded item", relevance) }));
|
||||
triggers.push_back(
|
||||
new TriggerNode("wipe", { NextAction("wipe", relevance) }));
|
||||
triggers.push_back(new TriggerNode("tame", { NextAction("tame", relevance) }));
|
||||
triggers.push_back(new TriggerNode("glyphs", { NextAction("glyphs", relevance) })); // Added for custom Glyphs
|
||||
triggers.push_back(new TriggerNode("glyph equip", { NextAction("glyph equip", relevance) })); // Added for custom Glyphs
|
||||
triggers.push_back(new TriggerNode("pet", { NextAction("pet", relevance) }));
|
||||
triggers.push_back(new TriggerNode("pet attack", { NextAction("pet attack", relevance) }));
|
||||
triggers.push_back(new TriggerNode("roll", { NextAction("roll", relevance) }));
|
||||
}
|
||||
|
||||
ChatCommandHandlerStrategy::ChatCommandHandlerStrategy(PlayerbotAI* botAI) : PassTroughStrategy(botAI)
|
||||
{
|
||||
actionNodeFactories.Add(new ChatCommandActionNodeFactoryInternal());
|
||||
|
||||
supported.push_back("quests");
|
||||
supported.push_back("stats");
|
||||
supported.push_back("leave");
|
||||
supported.push_back("reputation");
|
||||
supported.push_back("log");
|
||||
supported.push_back("los");
|
||||
supported.push_back("rpg status");
|
||||
supported.push_back("rpg do quest");
|
||||
supported.push_back("aura");
|
||||
supported.push_back("drop");
|
||||
supported.push_back("share");
|
||||
supported.push_back("ll");
|
||||
supported.push_back("ss");
|
||||
supported.push_back("release");
|
||||
supported.push_back("teleport");
|
||||
supported.push_back("taxi");
|
||||
supported.push_back("repair");
|
||||
supported.push_back("talents");
|
||||
supported.push_back("spells");
|
||||
supported.push_back("co");
|
||||
supported.push_back("nc");
|
||||
supported.push_back("de");
|
||||
supported.push_back("trainer");
|
||||
supported.push_back("maintenance");
|
||||
supported.push_back("remove glyph");
|
||||
supported.push_back("autogear");
|
||||
supported.push_back("equip upgrade");
|
||||
supported.push_back("chat");
|
||||
supported.push_back("home");
|
||||
supported.push_back("destroy");
|
||||
supported.push_back("reset botAI");
|
||||
supported.push_back("emote");
|
||||
supported.push_back("buff");
|
||||
supported.push_back("help");
|
||||
supported.push_back("gb");
|
||||
supported.push_back("bank");
|
||||
supported.push_back("invite");
|
||||
supported.push_back("lfg");
|
||||
supported.push_back("spell");
|
||||
supported.push_back("rti");
|
||||
supported.push_back("position");
|
||||
supported.push_back("summon");
|
||||
supported.push_back("who");
|
||||
supported.push_back("save mana");
|
||||
supported.push_back("formation");
|
||||
supported.push_back("stance");
|
||||
supported.push_back("sendmail");
|
||||
supported.push_back("mail");
|
||||
supported.push_back("outfit");
|
||||
supported.push_back("go");
|
||||
supported.push_back("debug");
|
||||
supported.push_back("cdebug");
|
||||
supported.push_back("cs");
|
||||
supported.push_back("wts");
|
||||
supported.push_back("hire");
|
||||
supported.push_back("craft");
|
||||
supported.push_back("flag");
|
||||
supported.push_back("range");
|
||||
supported.push_back("ra");
|
||||
supported.push_back("give leader");
|
||||
supported.push_back("cheat");
|
||||
supported.push_back("ginvite");
|
||||
supported.push_back("guild promote");
|
||||
supported.push_back("guild demote");
|
||||
supported.push_back("guild remove");
|
||||
supported.push_back("guild leave");
|
||||
supported.push_back("rtsc");
|
||||
supported.push_back("drink");
|
||||
supported.push_back("calc");
|
||||
supported.push_back("open items");
|
||||
supported.push_back("qi");
|
||||
supported.push_back("unlock items");
|
||||
supported.push_back("unlock traded item");
|
||||
supported.push_back("tame");
|
||||
supported.push_back("glyphs"); // Added for custom Glyphs
|
||||
supported.push_back("glyph equip"); // Added for custom Glyphs
|
||||
supported.push_back("pet");
|
||||
supported.push_back("pet attack");
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "CombatStrategy.h"
|
||||
|
||||
#include "Playerbots.h"
|
||||
#include "Strategy.h"
|
||||
|
||||
void CombatStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"enemy out of spell",
|
||||
{
|
||||
NextAction("reach spell", ACTION_HIGH)
|
||||
}
|
||||
)
|
||||
);
|
||||
// drop target relevance 99 (lower than Worldpacket triggers)
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"invalid target",
|
||||
{
|
||||
NextAction("drop target", 99)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"mounted",
|
||||
{
|
||||
NextAction("check mount state", 54)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"combat stuck",
|
||||
{
|
||||
NextAction("reset", 1.0f)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"not facing target",
|
||||
{
|
||||
NextAction("set facing", ACTION_MOVE + 7)
|
||||
}
|
||||
)
|
||||
);
|
||||
// The pet-attack trigger is commented out because it was forcing the bot's pet to attack, overriding stay and follow commands.
|
||||
// Pets will automatically attack the bot's enemy if they are in "defensive" or "aggressive"
|
||||
// stance, or if the master issues an attack command.
|
||||
}
|
||||
|
||||
AvoidAoeStrategy::AvoidAoeStrategy(PlayerbotAI* botAI) : Strategy(botAI) {}
|
||||
|
||||
std::vector<NextAction> AvoidAoeStrategy::getDefaultActions()
|
||||
{
|
||||
return {
|
||||
NextAction("avoid aoe", ACTION_EMERGENCY)
|
||||
};
|
||||
}
|
||||
|
||||
void AvoidAoeStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
}
|
||||
|
||||
void AvoidAoeStrategy::InitMultipliers(std::vector<Multiplier*>& multipliers)
|
||||
{
|
||||
}
|
||||
|
||||
TankFaceStrategy::TankFaceStrategy(PlayerbotAI* botAI) : Strategy(botAI) {}
|
||||
|
||||
std::vector<NextAction> TankFaceStrategy::getDefaultActions()
|
||||
{
|
||||
return {
|
||||
NextAction("tank face", ACTION_MOVE)
|
||||
};
|
||||
}
|
||||
|
||||
void TankFaceStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
}
|
||||
|
||||
std::vector<NextAction> CombatFormationStrategy::getDefaultActions()
|
||||
{
|
||||
return {
|
||||
NextAction("combat formation move", ACTION_NORMAL)
|
||||
};
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "DeadStrategy.h"
|
||||
|
||||
#include "Playerbots.h"
|
||||
|
||||
void DeadStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
PassTroughStrategy::InitTriggers(triggers);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode("often", { NextAction("auto release", relevance) }));
|
||||
triggers.push_back(
|
||||
new TriggerNode("bg active", { NextAction("auto release", relevance) }));
|
||||
triggers.push_back(
|
||||
new TriggerNode("dead", { NextAction("find corpse", relevance) }));
|
||||
triggers.push_back(new TriggerNode(
|
||||
"corpse near", { NextAction("revive from corpse", relevance - 1.0f) }));
|
||||
triggers.push_back(new TriggerNode("resurrect request",
|
||||
{ NextAction("accept resurrect", relevance) }));
|
||||
triggers.push_back(
|
||||
new TriggerNode("falling far", { NextAction("repop", relevance + 1.f) }));
|
||||
triggers.push_back(
|
||||
new TriggerNode("location stuck", { NextAction("repop", relevance + 1) }));
|
||||
triggers.push_back(new TriggerNode(
|
||||
"can self resurrect", { NextAction("self resurrect", relevance + 2.0f) }));
|
||||
}
|
||||
|
||||
DeadStrategy::DeadStrategy(PlayerbotAI* botAI) : PassTroughStrategy(botAI) {}
|
||||
@@ -1,35 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "EmoteStrategy.h"
|
||||
|
||||
#include "Playerbots.h"
|
||||
|
||||
void EmoteStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
if (sPlayerbotAIConfig->randomBotEmote)
|
||||
{
|
||||
triggers.push_back(new TriggerNode("often", { NextAction("talk", 1.0f) }));
|
||||
triggers.push_back(new TriggerNode("seldom", { NextAction("emote", 1.0f) }));
|
||||
triggers.push_back(
|
||||
new TriggerNode("receive text emote", { NextAction("emote", 10.0f) }));
|
||||
triggers.push_back(
|
||||
new TriggerNode("receive emote", { NextAction("emote", 10.0f) }));
|
||||
}
|
||||
|
||||
if (sPlayerbotAIConfig->randomBotTalk)
|
||||
{
|
||||
triggers.push_back(new TriggerNode(
|
||||
"often",
|
||||
{ NextAction("suggest what to do", 10.0f), NextAction("suggest dungeon", 3.0f),
|
||||
NextAction("suggest trade", 3.0f) }));
|
||||
}
|
||||
|
||||
if (sPlayerbotAIConfig->enableGreet)
|
||||
triggers.push_back(
|
||||
new TriggerNode("new player nearby", { NextAction("greet", 1.0f) }));
|
||||
|
||||
triggers.push_back(new TriggerNode("often", { NextAction("rpg mount anim", 1.0f) }));
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "GroupStrategy.h"
|
||||
|
||||
#include "Playerbots.h"
|
||||
|
||||
void GroupStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(new TriggerNode("often", { NextAction("invite nearby", 4.0f) }));
|
||||
triggers.push_back(new TriggerNode("random", { NextAction("invite guild", 4.0f) }));
|
||||
triggers.push_back(new TriggerNode("random", { NextAction("leave far away", 4.0f) }));
|
||||
triggers.push_back(new TriggerNode("seldom", { NextAction("reset instances", 1.0f) }));
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "GuildStrategy.h"
|
||||
|
||||
#include "Playerbots.h"
|
||||
|
||||
void GuildStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(
|
||||
new TriggerNode("often", { NextAction("offer petition nearby", 4.0f) }));
|
||||
triggers.push_back(
|
||||
new TriggerNode("often", { NextAction("guild manage nearby", 4.0f) }));
|
||||
triggers.push_back(
|
||||
new TriggerNode("petition signed", { NextAction("turn in petition", 10.0f) }));
|
||||
triggers.push_back(
|
||||
new TriggerNode("buy tabard", { NextAction("buy tabard", 10.0f) }));
|
||||
triggers.push_back(
|
||||
new TriggerNode("leave large guild", { NextAction("guild leave", 4.0f) }));
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "LootNonCombatStrategy.h"
|
||||
|
||||
#include "Playerbots.h"
|
||||
|
||||
void LootNonCombatStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(new TriggerNode("loot available", { NextAction("loot", 6.0f) }));
|
||||
triggers.push_back(
|
||||
new TriggerNode("far from loot target", { NextAction("move to loot", 7.0f) }));
|
||||
triggers.push_back(new TriggerNode("can loot", { NextAction("open loot", 8.0f) }));
|
||||
triggers.push_back(new TriggerNode("often", { NextAction("add all loot", 5.0f) }));
|
||||
}
|
||||
|
||||
void GatherStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(
|
||||
new TriggerNode("timer", { NextAction("add gathering loot", 5.0f) }));
|
||||
}
|
||||
|
||||
void RevealStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(
|
||||
new TriggerNode("often", { NextAction("reveal gathering item", 50.0f) }));
|
||||
}
|
||||
|
||||
void UseBobberStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(
|
||||
new TriggerNode("can use fishing bobber", { NextAction("use fishing bobber", 20.0f) }));
|
||||
triggers.push_back(
|
||||
new TriggerNode("random", { NextAction("remove bobber strategy", 20.0f) }));
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "MaintenanceStrategy.h"
|
||||
|
||||
#include "Playerbots.h"
|
||||
|
||||
std::vector<NextAction> MaintenanceStrategy::getDefaultActions() { return {}; }
|
||||
|
||||
void MaintenanceStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"random",
|
||||
{
|
||||
NextAction("clean quest log", 6.0f)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"random",
|
||||
{
|
||||
NextAction("use random recipe", 1.0f)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"random",
|
||||
{
|
||||
NextAction("disenchant random item", 1.0f)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"random",
|
||||
{
|
||||
NextAction("enchant random item", 1.0f)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"random",
|
||||
{
|
||||
NextAction("smart destroy item", 1.0f)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"move stuck",
|
||||
{
|
||||
NextAction("reset", 1.0f)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"random",
|
||||
{
|
||||
NextAction("use random quest item", 0.9f)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"random",
|
||||
{
|
||||
NextAction("auto share quest", 0.9f)
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "NonCombatStrategy.h"
|
||||
|
||||
#include "Playerbots.h"
|
||||
|
||||
void NonCombatStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(new TriggerNode("random", { NextAction("clean quest log", 1.0f) }));
|
||||
triggers.push_back(new TriggerNode("timer", { NextAction("check mount state", 1.0f) }));
|
||||
}
|
||||
|
||||
void CollisionStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(
|
||||
new TriggerNode("collision", { NextAction("move out of collision", 2.0f) }));
|
||||
}
|
||||
|
||||
void MountStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
}
|
||||
|
||||
void WorldBuffStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"need world buff",
|
||||
{
|
||||
NextAction("world buff", 1.0f)
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
void MasterFishingStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"very often",
|
||||
{
|
||||
NextAction("move near water" , 10.0f)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"very often",
|
||||
{
|
||||
NextAction("go fishing" , 10.0f)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"random",
|
||||
{
|
||||
NextAction("end master fishing", 12.0f),
|
||||
NextAction("equip upgrades", 6.0f)
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -1,171 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "RpgStrategy.h"
|
||||
|
||||
#include "Playerbots.h"
|
||||
#include "RpgSubActions.h"
|
||||
|
||||
float RpgActionMultiplier::GetValue(Action* action)
|
||||
{
|
||||
if (action == nullptr)
|
||||
return 1.0f;
|
||||
|
||||
std::string const nextAction = AI_VALUE(std::string, "next rpg action");
|
||||
std::string const name = action->getName();
|
||||
|
||||
if (!nextAction.empty() && dynamic_cast<RpgEnabled*>(action) && name != nextAction)
|
||||
return 0.0f;
|
||||
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
RpgStrategy::RpgStrategy(PlayerbotAI* botAI) : Strategy(botAI) {}
|
||||
|
||||
std::vector<NextAction> RpgStrategy::getDefaultActions()
|
||||
{
|
||||
return {
|
||||
NextAction("rpg", 1.0f)
|
||||
};
|
||||
}
|
||||
|
||||
void RpgStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"no rpg target",
|
||||
{
|
||||
NextAction("choose rpg target", 5.0f)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"often",
|
||||
{
|
||||
NextAction("move random", 1.10f)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"far from rpg target",
|
||||
{
|
||||
NextAction("move to rpg target", 5.0f)
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
// Sub actions
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"rpg",
|
||||
{
|
||||
NextAction("rpg stay", 1.101f)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"rpg",
|
||||
{
|
||||
NextAction("rpg work", 1.101f)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"rpg",
|
||||
{
|
||||
NextAction("rpg emote", 1.101f)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"has rpg target",
|
||||
{
|
||||
NextAction("rpg cancel", 1.101f)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"rpg discover",
|
||||
{
|
||||
NextAction("rpg discover", 1.210f)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"rpg start quest",
|
||||
{
|
||||
NextAction("rpg start quest", 1.180f)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"rpg end quest",
|
||||
{
|
||||
NextAction("rpg end quest", 1.190f)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"rpg buy",
|
||||
{
|
||||
NextAction("rpg buy", 1.130f)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"rpg repair",
|
||||
{
|
||||
NextAction("rpg repair", 1.195f)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"rpg heal",
|
||||
{
|
||||
NextAction("rpg heal", 1.125f)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"rpg home bind",
|
||||
{
|
||||
NextAction("rpg home bind", 1.160f)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"rpg buy petition",
|
||||
{
|
||||
NextAction("rpg buy petition", 1.140f)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"rpg use",
|
||||
{
|
||||
NextAction("rpg use", 1.102f)
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
void RpgStrategy::InitMultipliers(std::vector<Multiplier*>& multipliers)
|
||||
{
|
||||
multipliers.push_back(new RpgActionMultiplier(botAI));
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "SayStrategy.h"
|
||||
|
||||
#include "Playerbots.h"
|
||||
|
||||
void SayStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(new TriggerNode("critical health",
|
||||
{ NextAction("say::critical health", 99.0f) }));
|
||||
triggers.push_back(
|
||||
new TriggerNode("low health", { NextAction("say::low health", 99.0f) }));
|
||||
triggers.push_back(
|
||||
new TriggerNode("low mana", { NextAction("say::low mana", 99.0f) }));
|
||||
triggers.push_back(new TriggerNode("tank aoe", { NextAction("say::taunt", 99.0f) }));
|
||||
triggers.push_back(new TriggerNode("medium aoe", { NextAction("say::aoe", 99.0f) }));
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "StayStrategy.h"
|
||||
|
||||
#include "Playerbots.h"
|
||||
|
||||
void StayStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"return to stay position",
|
||||
{
|
||||
NextAction("return to stay position", ACTION_MOVE)
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
std::vector<NextAction> StayStrategy::getDefaultActions()
|
||||
{
|
||||
return {
|
||||
NextAction("stay", 1.0f)
|
||||
};
|
||||
}
|
||||
|
||||
void SitStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"sit",
|
||||
{
|
||||
NextAction("sit", 1.5f)
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "TravelStrategy.h"
|
||||
|
||||
#include "Playerbots.h"
|
||||
|
||||
TravelStrategy::TravelStrategy(PlayerbotAI* botAI) : Strategy(botAI) {}
|
||||
|
||||
std::vector<NextAction> TravelStrategy::getDefaultActions()
|
||||
{
|
||||
return {
|
||||
NextAction("travel", 1.0f)
|
||||
};
|
||||
}
|
||||
|
||||
void TravelStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"no travel target",
|
||||
{
|
||||
NextAction("choose travel target", 6.f)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"far from travel target",
|
||||
{
|
||||
NextAction("move to travel target", 1)
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -1,99 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "WorldPacketHandlerStrategy.h"
|
||||
|
||||
void WorldPacketHandlerStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
PassTroughStrategy::InitTriggers(triggers);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode("group invite", { NextAction("accept invitation", relevance) }));
|
||||
triggers.push_back(
|
||||
new TriggerNode("uninvite", { NextAction("uninvite", relevance) }));
|
||||
triggers.push_back(
|
||||
new TriggerNode("uninvite guid", { NextAction("uninvite", relevance) }));
|
||||
triggers.push_back(
|
||||
new TriggerNode("group set leader", { /*NextAction("leader", relevance),*/ }));
|
||||
triggers.push_back(new TriggerNode(
|
||||
"not enough money", { NextAction("tell not enough money", relevance) }));
|
||||
triggers.push_back(
|
||||
new TriggerNode("not enough reputation",
|
||||
{ NextAction("tell not enough reputation", relevance) }));
|
||||
triggers.push_back(
|
||||
new TriggerNode("cannot equip", { NextAction("tell cannot equip", relevance) }));
|
||||
triggers.push_back(
|
||||
new TriggerNode("use game object", { NextAction("add loot", relevance),
|
||||
NextAction("use meeting stone", relevance) }));
|
||||
triggers.push_back(
|
||||
new TriggerNode("gossip hello", { NextAction("trainer", relevance) }));
|
||||
triggers.push_back(new TriggerNode("activate taxi", { NextAction("remember taxi", relevance),
|
||||
NextAction("taxi", relevance) }));
|
||||
triggers.push_back(new TriggerNode("taxi done", { NextAction("taxi", relevance) }));
|
||||
triggers.push_back(new TriggerNode("trade status", { NextAction("accept trade", relevance), NextAction("equip upgrades", relevance) }));
|
||||
triggers.push_back(new TriggerNode("trade status extended", { NextAction("trade status extended", relevance) }));
|
||||
triggers.push_back(new TriggerNode("area trigger", { NextAction("reach area trigger", relevance) }));
|
||||
triggers.push_back(new TriggerNode("within area trigger", { NextAction("area trigger", relevance) }));
|
||||
triggers.push_back(new TriggerNode("loot response", { NextAction("store loot", relevance) }));
|
||||
triggers.push_back(new TriggerNode("item push result", { NextAction("unlock items", relevance),
|
||||
NextAction("open items", relevance),
|
||||
NextAction("query item usage", relevance),
|
||||
NextAction("equip upgrades", relevance) }));
|
||||
triggers.push_back(new TriggerNode("item push result", { NextAction("quest item push result", relevance) }));
|
||||
triggers.push_back(new TriggerNode("ready check finished", { NextAction("finish ready check", relevance) }));
|
||||
// triggers.push_back(new TriggerNode("often", { NextAction("security check", relevance), NextAction("check mail", relevance) }));
|
||||
triggers.push_back(new TriggerNode("guild invite", { NextAction("guild accept", relevance) }));
|
||||
triggers.push_back(new TriggerNode("petition offer", { NextAction("petition sign", relevance) }));
|
||||
triggers.push_back(new TriggerNode("lfg proposal", { NextAction("lfg accept", relevance) }));
|
||||
triggers.push_back(new TriggerNode("lfg proposal active", { NextAction("lfg accept", relevance) }));
|
||||
triggers.push_back(new TriggerNode("arena team invite", { NextAction("arena team accept", relevance) }));
|
||||
//triggers.push_back(new TriggerNode("no non bot players around", { NextAction("delay", relevance) }));
|
||||
triggers.push_back(new TriggerNode("bg status", { NextAction("bg status", relevance) }));
|
||||
triggers.push_back(new TriggerNode("xpgain", { NextAction("xp gain", relevance) }));
|
||||
triggers.push_back(
|
||||
new TriggerNode("levelup", { NextAction("auto maintenance on levelup", relevance + 3) }));
|
||||
// triggers.push_back(new TriggerNode("group destroyed", { NextAction("reset botAI",
|
||||
// relevance) }));
|
||||
triggers.push_back(new TriggerNode("group list", { NextAction("reset botAI", relevance) }));
|
||||
triggers.push_back(new TriggerNode("see spell", { NextAction("see spell", relevance) }));
|
||||
triggers.push_back(new TriggerNode("release spirit", { NextAction("release", relevance) }));
|
||||
triggers.push_back(new TriggerNode("revive from corpse", { NextAction("revive from corpse", relevance) }));
|
||||
triggers.push_back(new TriggerNode("master loot roll", { NextAction("master loot roll", relevance) }));
|
||||
|
||||
// quest ?
|
||||
//triggers.push_back(new TriggerNode("quest confirm", { NextAction("quest confirm", relevance) }));
|
||||
triggers.push_back(new TriggerNode("questgiver quest details", { NextAction("turn in query quest", relevance) }));
|
||||
|
||||
// loot roll
|
||||
triggers.push_back(new TriggerNode("very often", { NextAction("loot roll", relevance) }));
|
||||
}
|
||||
|
||||
WorldPacketHandlerStrategy::WorldPacketHandlerStrategy(PlayerbotAI* botAI) : PassTroughStrategy(botAI)
|
||||
{
|
||||
supported.push_back("loot roll");
|
||||
supported.push_back("check mount state");
|
||||
supported.push_back("party command");
|
||||
supported.push_back("ready check");
|
||||
supported.push_back("uninvite");
|
||||
supported.push_back("lfg role check");
|
||||
supported.push_back("lfg teleport");
|
||||
supported.push_back("random bot update");
|
||||
supported.push_back("inventory change failure");
|
||||
supported.push_back("bg status");
|
||||
|
||||
// quests
|
||||
supported.push_back("quest update add kill");
|
||||
// supported.push_back("quest update add item");
|
||||
supported.push_back("quest update failed");
|
||||
supported.push_back("quest update failed timer");
|
||||
supported.push_back("quest update complete");
|
||||
supported.push_back("confirm quest");
|
||||
}
|
||||
|
||||
void ReadyCheckStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(
|
||||
new TriggerNode("timer", { NextAction("ready check", relevance) }));
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "FishingTriggers.h"
|
||||
#include "Playerbots.h"
|
||||
|
||||
bool CanFishTrigger::IsActive() { return AI_VALUE(bool, "can fish"); }
|
||||
|
||||
bool CanUseFishingBobberTrigger::IsActive() { return AI_VALUE(bool, "can use fishing bobber");}
|
||||
@@ -1,25 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#ifndef _PLAYERBOT_FISHING_TRIGGER_H
|
||||
#define _PLAYERBOT_FISHING_TRIGGER_H
|
||||
|
||||
#include "GenericTriggers.h"
|
||||
|
||||
class CanFishTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
CanFishTrigger(PlayerbotAI* ai) : Trigger(ai, "can fish") {};
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class CanUseFishingBobberTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
CanUseFishingBobberTrigger(PlayerbotAI* ai) : Trigger(ai, "can use fishing bobber") {};
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,55 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "FishValues.h"
|
||||
#include "PlayerbotAI.h"
|
||||
#include "RandomPlayerbotMgr.h"
|
||||
#include "Map.h"
|
||||
#include "Spell.h"
|
||||
#include "FishingAction.h"
|
||||
|
||||
bool CanFishValue::Calculate()
|
||||
{
|
||||
int32 SkillFishing = bot->GetSkillValue(SKILL_FISHING);
|
||||
|
||||
if (SkillFishing == 0)
|
||||
return false;
|
||||
|
||||
if (bot->isSwimming())
|
||||
return false;
|
||||
|
||||
if (bot->IsInCombat())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CanUseFishingBobberValue::Calculate()
|
||||
{
|
||||
GuidVector gos = AI_VALUE(GuidVector, "nearest game objects no los");
|
||||
for (auto const& guid : gos)
|
||||
{
|
||||
if (GameObject* go = botAI->GetGameObject(guid))
|
||||
{
|
||||
if (go->GetEntry() != FISHING_BOBBER)
|
||||
continue;
|
||||
if (go->GetOwnerGUID() != bot->GetGUID())
|
||||
continue;
|
||||
|
||||
if (go->getLootState() == GO_READY)
|
||||
return true;
|
||||
|
||||
// Not ready yet → delay next check
|
||||
time_t bobberActiveTime = go->GetRespawnTime() - FISHING_BOBBER_READY_TIME;
|
||||
if (bobberActiveTime > time(0))
|
||||
botAI->SetNextCheckDelay((bobberActiveTime - time(0)) * IN_MILLISECONDS + 500);
|
||||
else
|
||||
botAI->SetNextCheckDelay(1000);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#ifndef _PLAYERBOT_FISHVALUES_H
|
||||
#define _PLAYERBOT_FISHVALUES_H
|
||||
|
||||
#include "Value.h"
|
||||
#include "TravelMgr.h"
|
||||
#include "NamedObjectContext.h"
|
||||
|
||||
class PlayerbotAI;
|
||||
|
||||
class CanFishValue : public BoolCalculatedValue
|
||||
{
|
||||
public:
|
||||
CanFishValue(PlayerbotAI* botAI) : BoolCalculatedValue(botAI, "can fish") {};
|
||||
bool Calculate() override;
|
||||
};
|
||||
|
||||
class CanUseFishingBobberValue : public BoolCalculatedValue
|
||||
{
|
||||
public:
|
||||
CanUseFishingBobberValue(PlayerbotAI* botAI) : BoolCalculatedValue(botAI, "can use fishing bobber") {};
|
||||
bool Calculate() override;
|
||||
};
|
||||
|
||||
class FishingSpotValue : public ManualSetValue<WorldPosition>
|
||||
{
|
||||
public:
|
||||
FishingSpotValue(PlayerbotAI* botAI, WorldPosition const& pos = WorldPosition(), std::string const& name = "fishing spot")
|
||||
: ManualSetValue<WorldPosition>(botAI, pos, name) {}
|
||||
|
||||
void Set(WorldPosition val) override
|
||||
{
|
||||
value = val;
|
||||
_setTime = getMSTime();
|
||||
}
|
||||
uint32 lastUpdated() const {return _setTime;}
|
||||
bool IsStale(uint32 maxDuration) const { return getMSTime() - _setTime > maxDuration; }
|
||||
|
||||
private:
|
||||
uint32 _setTime = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,165 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "BloodDKStrategy.h"
|
||||
|
||||
#include "Playerbots.h"
|
||||
|
||||
class BloodDKStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
|
||||
{
|
||||
public:
|
||||
BloodDKStrategyActionNodeFactory()
|
||||
{
|
||||
creators["rune strike"] = &rune_strike;
|
||||
creators["heart strike"] = &heart_strike;
|
||||
creators["death strike"] = &death_strike;
|
||||
creators["icy touch"] = &icy_touch;
|
||||
creators["dark command"] = &dark_command;
|
||||
creators["taunt spell"] = &dark_command;
|
||||
}
|
||||
|
||||
private:
|
||||
static ActionNode* rune_strike([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"rune strike",
|
||||
{
|
||||
NextAction("frost presence")
|
||||
},
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
static ActionNode* icy_touch([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"icy touch",
|
||||
{
|
||||
NextAction("frost presence")
|
||||
},
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
static ActionNode* heart_strike([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"heart strike",
|
||||
{
|
||||
NextAction("frost presence")
|
||||
},
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* death_strike([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"death strike",
|
||||
{
|
||||
NextAction("frost presence")
|
||||
},
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
static ActionNode* dark_command([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"dark command",
|
||||
{
|
||||
NextAction("frost presence")
|
||||
},
|
||||
/*A*/ {
|
||||
NextAction("death grip")
|
||||
},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
BloodDKStrategy::BloodDKStrategy(PlayerbotAI* botAI) : GenericDKStrategy(botAI)
|
||||
{
|
||||
actionNodeFactories.Add(new BloodDKStrategyActionNodeFactory());
|
||||
}
|
||||
|
||||
std::vector<NextAction> BloodDKStrategy::getDefaultActions()
|
||||
{
|
||||
return {
|
||||
NextAction("rune strike", ACTION_DEFAULT + 0.8f),
|
||||
NextAction("icy touch", ACTION_DEFAULT + 0.7f),
|
||||
NextAction("heart strike", ACTION_DEFAULT + 0.6f),
|
||||
NextAction("blood strike", ACTION_DEFAULT + 0.5f),
|
||||
NextAction("dancing rune weapon", ACTION_DEFAULT + 0.4f),
|
||||
NextAction("death coil", ACTION_DEFAULT + 0.3f),
|
||||
NextAction("plague strike", ACTION_DEFAULT + 0.2f),
|
||||
NextAction("horn of winter", ACTION_DEFAULT + 0.1f),
|
||||
NextAction("melee", ACTION_DEFAULT)
|
||||
};
|
||||
}
|
||||
|
||||
void BloodDKStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
GenericDKStrategy::InitTriggers(triggers);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"rune strike",
|
||||
{
|
||||
NextAction("rune strike", ACTION_NORMAL + 3)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"blood tap",
|
||||
{
|
||||
NextAction("blood tap", ACTION_HIGH + 5)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"lose aggro",
|
||||
{
|
||||
NextAction("dark command", ACTION_HIGH + 3)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"low health",
|
||||
{
|
||||
NextAction("army of the dead", ACTION_HIGH + 4),
|
||||
NextAction("death strike", ACTION_HIGH + 3)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"critical health",
|
||||
{
|
||||
NextAction("vampiric blood", ACTION_HIGH + 5)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"icy touch",
|
||||
{
|
||||
NextAction("icy touch", ACTION_HIGH + 2)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"plague strike",
|
||||
{
|
||||
NextAction("plague strike", ACTION_HIGH + 2)
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -1,169 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "FrostDKStrategy.h"
|
||||
|
||||
#include "Playerbots.h"
|
||||
|
||||
class FrostDKStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
|
||||
{
|
||||
public:
|
||||
FrostDKStrategyActionNodeFactory()
|
||||
{
|
||||
creators["icy touch"] = &icy_touch;
|
||||
creators["obliterate"] = &obliterate;
|
||||
creators["howling blast"] = &howling_blast;
|
||||
creators["frost strike"] = &frost_strike;
|
||||
creators["rune strike"] = &rune_strike;
|
||||
creators["unbreakable armor"] = &unbreakable_armor;
|
||||
}
|
||||
|
||||
private:
|
||||
static ActionNode* icy_touch([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"icy touch",
|
||||
/*P*/ { NextAction("blood presence") },
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* obliterate([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"obliterate",
|
||||
/*P*/ { NextAction("blood presence") },
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* rune_strike([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"rune strike",
|
||||
/*P*/ { NextAction("blood presence") },
|
||||
/*A*/ { NextAction("melee") },
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* frost_strike([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"frost strike",
|
||||
/*P*/ { NextAction("blood presence") },
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* howling_blast([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"howling blast",
|
||||
/*P*/ { NextAction("blood presence") },
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
static ActionNode* unbreakable_armor([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"unbreakable armor",
|
||||
/*P*/ { NextAction("blood tap") },
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
FrostDKStrategy::FrostDKStrategy(PlayerbotAI* botAI) : GenericDKStrategy(botAI)
|
||||
{
|
||||
actionNodeFactories.Add(new FrostDKStrategyActionNodeFactory());
|
||||
}
|
||||
|
||||
std::vector<NextAction> FrostDKStrategy::getDefaultActions()
|
||||
{
|
||||
return {
|
||||
NextAction("obliterate", ACTION_DEFAULT + 0.7f),
|
||||
NextAction("frost strike", ACTION_DEFAULT + 0.4f),
|
||||
NextAction("empower rune weapon", ACTION_DEFAULT + 0.3f),
|
||||
NextAction("horn of winter", ACTION_DEFAULT + 0.1f),
|
||||
NextAction("melee", ACTION_DEFAULT)
|
||||
};
|
||||
}
|
||||
|
||||
void FrostDKStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
GenericDKStrategy::InitTriggers(triggers);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"unbreakable armor",
|
||||
{
|
||||
NextAction("unbreakable armor", ACTION_DEFAULT + 0.6f)
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"freezing fog",
|
||||
{
|
||||
NextAction("howling blast", ACTION_DEFAULT + 0.5f)
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"high blood rune",
|
||||
{
|
||||
NextAction("blood strike", ACTION_DEFAULT + 0.2f)
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"army of the dead",
|
||||
{
|
||||
NextAction("army of the dead", ACTION_HIGH + 6)
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"icy touch",
|
||||
{
|
||||
NextAction("icy touch", ACTION_HIGH + 2)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"plague strike",
|
||||
{
|
||||
NextAction("plague strike", ACTION_HIGH + 2)
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
void FrostDKAoeStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"medium aoe",
|
||||
{
|
||||
NextAction("howling blast", ACTION_HIGH + 4)
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -1,192 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "UnholyDKStrategy.h"
|
||||
|
||||
#include "Playerbots.h"
|
||||
|
||||
class UnholyDKStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
|
||||
{
|
||||
public:
|
||||
UnholyDKStrategyActionNodeFactory()
|
||||
{
|
||||
creators["death strike"] = &death_strike;
|
||||
creators["scourge strike"] = &scourge_strike;
|
||||
creators["ghoul frenzy"] = &ghoul_frenzy;
|
||||
creators["corpse explosion"] = &corpse_explosion;
|
||||
creators["icy touch"] = &icy_touch;
|
||||
}
|
||||
|
||||
private:
|
||||
static ActionNode* death_strike([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"death strike",
|
||||
/*P*/ { NextAction("blood presence") },
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
static ActionNode* ghoul_frenzy([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"ghoul frenzy",
|
||||
/*P*/ { NextAction("blood presence") },
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
static ActionNode* corpse_explosion([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"corpse explosion",
|
||||
/*P*/ { NextAction("blood presence") },
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* scourge_strike([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"scourge strike",
|
||||
/*P*/ { NextAction("blood presence") },
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
static ActionNode* icy_touch([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"icy touch",
|
||||
/*P*/ { NextAction("blood presence") },
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
UnholyDKStrategy::UnholyDKStrategy(PlayerbotAI* botAI) : GenericDKStrategy(botAI)
|
||||
{
|
||||
actionNodeFactories.Add(new UnholyDKStrategyActionNodeFactory());
|
||||
}
|
||||
|
||||
std::vector<NextAction> UnholyDKStrategy::getDefaultActions()
|
||||
{
|
||||
return {
|
||||
NextAction("death and decay", ACTION_HIGH + 5),
|
||||
NextAction("summon gargoyle", ACTION_DEFAULT + 0.4f),
|
||||
NextAction("horn of winter", ACTION_DEFAULT + 0.2f),
|
||||
NextAction("death coil", ACTION_DEFAULT + 0.1f),
|
||||
NextAction("melee", ACTION_DEFAULT)
|
||||
};
|
||||
}
|
||||
|
||||
void UnholyDKStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
GenericDKStrategy::InitTriggers(triggers);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"death and decay cooldown",
|
||||
{
|
||||
NextAction("ghoul frenzy", ACTION_DEFAULT + 0.9f),
|
||||
NextAction("scourge strike", ACTION_DEFAULT + 0.8f),
|
||||
NextAction("icy touch", ACTION_DEFAULT + 0.7f),
|
||||
NextAction("blood strike", ACTION_DEFAULT + 0.6f),
|
||||
NextAction("plague strike", ACTION_DEFAULT + 0.5f),
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"dd cd and no desolation",
|
||||
{
|
||||
NextAction("blood strike", ACTION_DEFAULT + 0.75f)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"high frost rune",
|
||||
{
|
||||
NextAction("icy touch", ACTION_NORMAL + 3)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"high blood rune",
|
||||
{
|
||||
NextAction("blood strike", ACTION_NORMAL + 2)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"high unholy rune",
|
||||
{
|
||||
NextAction("plague strike", ACTION_NORMAL + 1)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode("dd cd and plague strike 3s",
|
||||
{
|
||||
NextAction("plague strike", ACTION_HIGH + 1)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode("dd cd and icy touch 3s",
|
||||
{
|
||||
NextAction("icy touch", ACTION_HIGH + 2)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode("no rune",
|
||||
{
|
||||
NextAction("empower rune weapon", ACTION_HIGH + 1)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"army of the dead",
|
||||
{
|
||||
NextAction("army of the dead", ACTION_HIGH + 6)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode("bone shield",
|
||||
{
|
||||
NextAction("bone shield", ACTION_HIGH + 3)
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
void UnholyDKAoeStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"loot available",
|
||||
{
|
||||
NextAction("corpse explosion", ACTION_NORMAL + 1)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"medium aoe",
|
||||
{
|
||||
NextAction("death and decay", ACTION_NORMAL + 3),
|
||||
NextAction("corpse explosion", ACTION_NORMAL + 3)
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -1,256 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "BearTankDruidStrategy.h"
|
||||
|
||||
#include "Playerbots.h"
|
||||
|
||||
class BearTankDruidStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
|
||||
{
|
||||
public:
|
||||
BearTankDruidStrategyActionNodeFactory()
|
||||
{
|
||||
creators["melee"] = &melee;
|
||||
creators["feral charge - bear"] = &feral_charge_bear;
|
||||
creators["swipe (bear)"] = &swipe_bear;
|
||||
creators["faerie fire (feral)"] = &faerie_fire_feral;
|
||||
creators["bear form"] = &bear_form;
|
||||
creators["dire bear form"] = &dire_bear_form;
|
||||
creators["mangle (bear)"] = &mangle_bear;
|
||||
creators["maul"] = &maul;
|
||||
creators["bash"] = &bash;
|
||||
creators["swipe"] = &swipe;
|
||||
creators["lacerate"] = &lacerate;
|
||||
creators["demoralizing roar"] = &demoralizing_roar;
|
||||
creators["taunt spell"] = &growl;
|
||||
}
|
||||
|
||||
private:
|
||||
static ActionNode* melee([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"melee",
|
||||
/*P*/ { NextAction("feral charge - bear") },
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* feral_charge_bear([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"feral charge - bear",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("reach melee") },
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* swipe_bear([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"swipe (bear)",
|
||||
/*P*/ {},
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* faerie_fire_feral([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"faerie fire (feral)",
|
||||
/*P*/ { NextAction("feral charge - bear") },
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* bear_form([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"bear form",
|
||||
/*P*/ {},
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* dire_bear_form([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"dire bear form",
|
||||
/*P*/ { NextAction("caster form") },
|
||||
/*A*/ { NextAction("bear form") },
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* mangle_bear([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"mangle (bear)",
|
||||
/*P*/ {},
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* maul([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"maul",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("melee") },
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* bash([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"bash",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("melee") },
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* swipe([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"swipe",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("melee") },
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* lacerate([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"lacerate",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("maul") },
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* growl([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"growl",
|
||||
/*P*/ {},
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* demoralizing_roar([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"demoralizing roar",
|
||||
/*P*/ {},
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
BearTankDruidStrategy::BearTankDruidStrategy(PlayerbotAI* botAI) : FeralDruidStrategy(botAI)
|
||||
{
|
||||
actionNodeFactories.Add(new BearTankDruidStrategyActionNodeFactory());
|
||||
}
|
||||
|
||||
std::vector<NextAction> BearTankDruidStrategy::getDefaultActions()
|
||||
{
|
||||
return {
|
||||
NextAction("mangle (bear)", ACTION_DEFAULT + 0.5f),
|
||||
NextAction("faerie fire (feral)", ACTION_DEFAULT + 0.4f),
|
||||
NextAction("lacerate", ACTION_DEFAULT + 0.3f),
|
||||
NextAction("maul", ACTION_DEFAULT + 0.2f),
|
||||
NextAction("enrage", ACTION_DEFAULT + 0.1f),
|
||||
NextAction("melee", ACTION_DEFAULT)
|
||||
};
|
||||
}
|
||||
|
||||
void BearTankDruidStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
FeralDruidStrategy::InitTriggers(triggers);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"enemy out of melee",
|
||||
{
|
||||
NextAction("feral charge - bear", ACTION_NORMAL + 8)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"bear form",
|
||||
{
|
||||
NextAction("dire bear form", ACTION_HIGH + 8)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"low health",
|
||||
{
|
||||
NextAction("frenzied regeneration", ACTION_HIGH + 7)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"faerie fire (feral)",
|
||||
{
|
||||
NextAction("faerie fire (feral)", ACTION_HIGH + 7)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"lose aggro",
|
||||
{
|
||||
NextAction("growl", ACTION_HIGH + 8)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"medium aoe",
|
||||
{
|
||||
NextAction("demoralizing roar", ACTION_HIGH + 6),
|
||||
NextAction("swipe (bear)", ACTION_HIGH + 6)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"light aoe",
|
||||
{
|
||||
NextAction("swipe (bear)", ACTION_HIGH + 5)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"bash",
|
||||
{
|
||||
NextAction("bash", ACTION_INTERRUPT + 2)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"bash on enemy healer",
|
||||
{
|
||||
NextAction("bash on enemy healer", ACTION_INTERRUPT + 1)
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -1,254 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "CasterDruidStrategy.h"
|
||||
|
||||
#include "AiObjectContext.h"
|
||||
#include "FeralDruidStrategy.h"
|
||||
|
||||
class CasterDruidStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
|
||||
{
|
||||
public:
|
||||
CasterDruidStrategyActionNodeFactory()
|
||||
{
|
||||
creators["faerie fire"] = &faerie_fire;
|
||||
creators["hibernate"] = &hibernate;
|
||||
creators["entangling roots"] = &entangling_roots;
|
||||
creators["entangling roots on cc"] = &entangling_roots_on_cc;
|
||||
creators["wrath"] = &wrath;
|
||||
creators["starfall"] = &starfall;
|
||||
creators["insect swarm"] = &insect_swarm;
|
||||
creators["moonfire"] = &moonfire;
|
||||
creators["starfire"] = &starfire;
|
||||
creators["moonkin form"] = &moonkin_form;
|
||||
}
|
||||
|
||||
private:
|
||||
static ActionNode* faerie_fire([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"faerie fire",
|
||||
/*P*/ { NextAction("moonkin form") },
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* hibernate([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"hibernate",
|
||||
/*P*/ { NextAction("moonkin form") },
|
||||
/*A*/ { NextAction("entangling roots") },
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* entangling_roots([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"entangling roots",
|
||||
/*P*/ { NextAction("moonkin form") },
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* entangling_roots_on_cc([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"entangling roots on cc",
|
||||
/*P*/ { NextAction("moonkin form") },
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* wrath([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"wrath",
|
||||
/*P*/ { NextAction("moonkin form") },
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* starfall([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"starfall",
|
||||
/*P*/ { NextAction("moonkin form") },
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* insect_swarm([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"insect swarm",
|
||||
/*P*/ { NextAction("moonkin form") },
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* moonfire([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"moonfire",
|
||||
/*P*/ { NextAction("moonkin form") },
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* starfire([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"starfire",
|
||||
/*P*/ { NextAction("moonkin form") },
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* moonkin_form([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"moonkin form",
|
||||
/*P*/ { NextAction("caster form") },
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
CasterDruidStrategy::CasterDruidStrategy(PlayerbotAI* botAI) : GenericDruidStrategy(botAI)
|
||||
{
|
||||
actionNodeFactories.Add(new CasterDruidStrategyActionNodeFactory());
|
||||
actionNodeFactories.Add(new ShapeshiftDruidStrategyActionNodeFactory());
|
||||
}
|
||||
|
||||
std::vector<NextAction> CasterDruidStrategy::getDefaultActions()
|
||||
{
|
||||
return {
|
||||
NextAction("starfall", ACTION_HIGH + 1.0f),
|
||||
NextAction("force of nature", ACTION_DEFAULT + 1.0f),
|
||||
NextAction("wrath", ACTION_DEFAULT + 0.1f),
|
||||
};
|
||||
}
|
||||
|
||||
void CasterDruidStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
GenericDruidStrategy::InitTriggers(triggers);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"eclipse (lunar) cooldown",
|
||||
{
|
||||
NextAction("starfire", ACTION_DEFAULT + 0.2f)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"eclipse (solar) cooldown",
|
||||
{
|
||||
NextAction("wrath", ACTION_DEFAULT + 0.2f)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"insect swarm",
|
||||
{
|
||||
NextAction("insect swarm", ACTION_NORMAL + 5)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"moonfire",
|
||||
{
|
||||
NextAction("moonfire", ACTION_NORMAL + 4)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"eclipse (solar)",
|
||||
{
|
||||
NextAction("wrath", ACTION_NORMAL + 6)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"eclipse (lunar)",
|
||||
{
|
||||
NextAction("starfire", ACTION_NORMAL + 6)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"medium mana",
|
||||
{
|
||||
NextAction("innervate", ACTION_HIGH + 9)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"enemy too close for spell",
|
||||
{
|
||||
NextAction("flee", ACTION_MOVE + 9)
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
void CasterDruidAoeStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"hurricane channel check",
|
||||
{
|
||||
NextAction("cancel channel", ACTION_HIGH + 2)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"medium aoe",
|
||||
{
|
||||
NextAction("hurricane", ACTION_HIGH + 1)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"light aoe",
|
||||
{
|
||||
NextAction("insect swarm on attacker", ACTION_NORMAL + 3),
|
||||
NextAction("moonfire on attacker", ACTION_NORMAL + 3)
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
void CasterDruidDebuffStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"faerie fire",
|
||||
{
|
||||
NextAction("faerie fire", ACTION_HIGH)
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -1,314 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "CatDpsDruidStrategy.h"
|
||||
|
||||
#include "AiObjectContext.h"
|
||||
|
||||
class CatDpsDruidStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
|
||||
{
|
||||
public:
|
||||
CatDpsDruidStrategyActionNodeFactory()
|
||||
{
|
||||
creators["faerie fire (feral)"] = &faerie_fire_feral;
|
||||
creators["melee"] = &melee;
|
||||
creators["feral charge - cat"] = &feral_charge_cat;
|
||||
creators["cat form"] = &cat_form;
|
||||
creators["claw"] = &claw;
|
||||
creators["mangle (cat)"] = &mangle_cat;
|
||||
creators["rake"] = &rake;
|
||||
creators["ferocious bite"] = &ferocious_bite;
|
||||
creators["rip"] = &rip;
|
||||
creators["pounce"] = &pounce;
|
||||
creators["ravage"] = &ravage;
|
||||
}
|
||||
|
||||
private:
|
||||
static ActionNode* faerie_fire_feral([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"faerie fire (feral)",
|
||||
/*P*/ {},
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* melee([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"melee",
|
||||
/*P*/ { NextAction("feral charge - cat") },
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* feral_charge_cat([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"feral charge - cat",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("reach melee") },
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* cat_form([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"cat form",
|
||||
/*P*/ { NextAction("caster form") },
|
||||
/*A*/ { NextAction("bear form") },
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* claw([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"claw",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("melee") },
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* mangle_cat([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"mangle (cat)",
|
||||
/*P*/ {},
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* rake([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"rake",
|
||||
/*P*/ {},
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* ferocious_bite([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"ferocious bite",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("rip") },
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* rip([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"rip",
|
||||
/*P*/ {},
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* pounce([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"pounce",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("ravage") },
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* ravage([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"ravage",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("shred") },
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
CatDpsDruidStrategy::CatDpsDruidStrategy(PlayerbotAI* botAI) : FeralDruidStrategy(botAI)
|
||||
{
|
||||
actionNodeFactories.Add(new CatDpsDruidStrategyActionNodeFactory());
|
||||
}
|
||||
|
||||
std::vector<NextAction> CatDpsDruidStrategy::getDefaultActions()
|
||||
{
|
||||
return {
|
||||
NextAction("tiger's fury", ACTION_DEFAULT + 0.1f)
|
||||
};
|
||||
}
|
||||
|
||||
void CatDpsDruidStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
FeralDruidStrategy::InitTriggers(triggers);
|
||||
|
||||
// Default priority
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"almost full energy available",
|
||||
{
|
||||
NextAction("shred", ACTION_DEFAULT + 0.4f)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"combo points not full",
|
||||
{
|
||||
NextAction("shred", ACTION_DEFAULT + 0.4f)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"almost full energy available",
|
||||
{
|
||||
NextAction("mangle (cat)", ACTION_DEFAULT + 0.3f)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"combo points not full and high energy",
|
||||
{
|
||||
NextAction("mangle (cat)", ACTION_DEFAULT + 0.3f)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"almost full energy available",
|
||||
{
|
||||
NextAction("claw", ACTION_DEFAULT + 0.2f)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"combo points not full and high energy",
|
||||
{
|
||||
NextAction("claw", ACTION_DEFAULT + 0.2f)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"faerie fire (feral)",
|
||||
{
|
||||
NextAction("faerie fire (feral)", ACTION_DEFAULT + 0.0f)
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
// Main spell
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"cat form", {
|
||||
NextAction("cat form", ACTION_HIGH + 8)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"savage roar", {
|
||||
NextAction("savage roar", ACTION_HIGH + 7)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"combo points available",
|
||||
{
|
||||
NextAction("rip", ACTION_HIGH + 6)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"ferocious bite time",
|
||||
{
|
||||
NextAction("ferocious bite", ACTION_HIGH + 5)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"target with combo points almost dead",
|
||||
{
|
||||
NextAction("ferocious bite", ACTION_HIGH + 4)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"mangle (cat)",
|
||||
{
|
||||
NextAction("mangle (cat)", ACTION_HIGH + 3)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"rake",
|
||||
{
|
||||
NextAction("rake", ACTION_HIGH + 2)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"medium threat",
|
||||
{
|
||||
NextAction("cower", ACTION_HIGH + 1)
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
// AOE
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"medium aoe",
|
||||
{
|
||||
NextAction("swipe (cat)", ACTION_HIGH + 3)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"light aoe",
|
||||
{
|
||||
NextAction("rake on attacker", ACTION_HIGH + 2)
|
||||
}
|
||||
)
|
||||
);
|
||||
// Reach target
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"enemy out of melee",
|
||||
{
|
||||
NextAction("feral charge - cat", ACTION_HIGH + 9)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"enemy out of melee",
|
||||
{
|
||||
NextAction("dash", ACTION_HIGH + 8)
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
void CatAoeDruidStrategy::InitTriggers(std::vector<TriggerNode*>& triggers) {}
|
||||
@@ -1,194 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "GenericDruidNonCombatStrategy.h"
|
||||
|
||||
#include "Playerbots.h"
|
||||
#include "AiFactory.h"
|
||||
|
||||
class GenericDruidNonCombatStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
|
||||
{
|
||||
public:
|
||||
GenericDruidNonCombatStrategyActionNodeFactory()
|
||||
{
|
||||
creators["thorns"] = þs;
|
||||
creators["thorns on party"] = þs_on_party;
|
||||
creators["mark of the wild"] = &mark_of_the_wild;
|
||||
creators["mark of the wild on party"] = &mark_of_the_wild_on_party;
|
||||
// creators["innervate"] = &innervate;
|
||||
creators["regrowth_on_party"] = ®rowth_on_party;
|
||||
creators["rejuvenation on party"] = &rejuvenation_on_party;
|
||||
creators["remove curse on party"] = &remove_curse_on_party;
|
||||
creators["abolish poison on party"] = &abolish_poison_on_party;
|
||||
creators["revive"] = &revive;
|
||||
}
|
||||
|
||||
private:
|
||||
static ActionNode* thorns([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode("thorns",
|
||||
/*P*/ { NextAction("caster form") },
|
||||
/*A*/ {},
|
||||
/*C*/ {});
|
||||
}
|
||||
|
||||
static ActionNode* thorns_on_party([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode("thorns on party",
|
||||
/*P*/ { NextAction("caster form") },
|
||||
/*A*/ {},
|
||||
/*C*/ {});
|
||||
}
|
||||
|
||||
static ActionNode* mark_of_the_wild([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode("mark of the wild",
|
||||
/*P*/ { NextAction("caster form") },
|
||||
/*A*/ {},
|
||||
/*C*/ {});
|
||||
}
|
||||
|
||||
static ActionNode* mark_of_the_wild_on_party([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode("mark of the wild on party",
|
||||
/*P*/ { NextAction("caster form") },
|
||||
/*A*/ {},
|
||||
/*C*/ {});
|
||||
}
|
||||
static ActionNode* regrowth_on_party([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode("regrowth on party",
|
||||
/*P*/ { NextAction("caster form") },
|
||||
/*A*/ {},
|
||||
/*C*/ {});
|
||||
}
|
||||
static ActionNode* rejuvenation_on_party([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode("rejuvenation on party",
|
||||
/*P*/ { NextAction("caster form") },
|
||||
/*A*/ {},
|
||||
/*C*/ {});
|
||||
}
|
||||
static ActionNode* remove_curse_on_party([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode("remove curse on party",
|
||||
/*P*/ { NextAction("caster form") },
|
||||
/*A*/ {},
|
||||
/*C*/ {});
|
||||
}
|
||||
static ActionNode* abolish_poison_on_party([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode("abolish poison on party",
|
||||
/*P*/ { NextAction("caster form") },
|
||||
/*A*/ {},
|
||||
/*C*/ {});
|
||||
}
|
||||
static ActionNode* revive([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode("revive",
|
||||
/*P*/ { NextAction("caster form") },
|
||||
/*A*/ {},
|
||||
/*C*/ {});
|
||||
}
|
||||
};
|
||||
|
||||
GenericDruidNonCombatStrategy::GenericDruidNonCombatStrategy(PlayerbotAI* botAI) : NonCombatStrategy(botAI)
|
||||
{
|
||||
actionNodeFactories.Add(new GenericDruidNonCombatStrategyActionNodeFactory());
|
||||
}
|
||||
|
||||
void GenericDruidNonCombatStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
NonCombatStrategy::InitTriggers(triggers);
|
||||
|
||||
triggers.push_back(new TriggerNode("mark of the wild", { NextAction("mark of the wild", 14.0f) }));
|
||||
triggers.push_back(new TriggerNode("party member cure poison", { NextAction("abolish poison on party", 20.0f) }));
|
||||
triggers.push_back(new TriggerNode("party member dead", { NextAction("revive", ACTION_CRITICAL_HEAL + 10) }));
|
||||
|
||||
triggers.push_back(new TriggerNode("often", { NextAction("apply oil", 1.0f) }));
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode("party member critical health",
|
||||
{
|
||||
NextAction("wild growth on party", ACTION_MEDIUM_HEAL + 7),
|
||||
NextAction("regrowth on party", ACTION_MEDIUM_HEAL + 6),
|
||||
NextAction("rejuvenation on party", ACTION_MEDIUM_HEAL + 5),
|
||||
}));
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode("party member low health",
|
||||
{
|
||||
NextAction("wild growth on party", ACTION_MEDIUM_HEAL + 5),
|
||||
NextAction("regrowth on party", ACTION_MEDIUM_HEAL + 4),
|
||||
NextAction("rejuvenation on party", ACTION_MEDIUM_HEAL + 3),
|
||||
}));
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode("party member medium health",
|
||||
{ NextAction("wild growth on party", ACTION_MEDIUM_HEAL + 3),
|
||||
NextAction("regrowth on party", ACTION_MEDIUM_HEAL + 2),
|
||||
NextAction("rejuvenation on party", ACTION_MEDIUM_HEAL + 1),
|
||||
}));
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode("party member almost full health",
|
||||
{ NextAction("wild growth on party", ACTION_LIGHT_HEAL + 3), NextAction("rejuvenation on party", ACTION_LIGHT_HEAL + 2) }));
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode("party member remove curse",
|
||||
{ NextAction("remove curse on party", ACTION_DISPEL + 7) }));
|
||||
triggers.push_back(
|
||||
new TriggerNode("new pet", { NextAction("set pet stance", 60.0f) }));
|
||||
|
||||
triggers.push_back(new TriggerNode("party member critical health", {
|
||||
NextAction("wild growth on party", ACTION_MEDIUM_HEAL + 7),
|
||||
NextAction("regrowth on party", ACTION_MEDIUM_HEAL + 6),
|
||||
NextAction("rejuvenation on party", ACTION_MEDIUM_HEAL + 5),
|
||||
}));
|
||||
triggers.push_back(new TriggerNode("party member low health", {
|
||||
NextAction("wild growth on party", ACTION_MEDIUM_HEAL + 5),
|
||||
NextAction("regrowth on party", ACTION_MEDIUM_HEAL + 4),
|
||||
NextAction("rejuvenation on party", ACTION_MEDIUM_HEAL + 3),
|
||||
}));
|
||||
triggers.push_back(new TriggerNode("party member medium health", {
|
||||
NextAction("wild growth on party", ACTION_MEDIUM_HEAL + 3),
|
||||
NextAction("regrowth on party", ACTION_MEDIUM_HEAL + 2),
|
||||
NextAction("rejuvenation on party", ACTION_MEDIUM_HEAL + 1),
|
||||
}));
|
||||
triggers.push_back(new TriggerNode("party member almost full health", {
|
||||
NextAction("wild growth on party", ACTION_LIGHT_HEAL + 3),
|
||||
NextAction("rejuvenation on party", ACTION_LIGHT_HEAL + 2),
|
||||
}));
|
||||
triggers.push_back(new TriggerNode("party member remove curse", {
|
||||
NextAction("remove curse on party", ACTION_DISPEL + 7),
|
||||
}));
|
||||
|
||||
int specTab = AiFactory::GetPlayerSpecTab(botAI->GetBot());
|
||||
if (specTab == 0 || specTab == 2) // Balance or Restoration
|
||||
triggers.push_back(new TriggerNode("often", { NextAction("apply oil", 1.0f) }));
|
||||
if (specTab == 1) // Feral
|
||||
triggers.push_back(new TriggerNode("often", { NextAction("apply stone", 1.0f) }));
|
||||
|
||||
}
|
||||
|
||||
GenericDruidBuffStrategy::GenericDruidBuffStrategy(PlayerbotAI* botAI) : NonCombatStrategy(botAI)
|
||||
{
|
||||
actionNodeFactories.Add(new GenericDruidNonCombatStrategyActionNodeFactory());
|
||||
}
|
||||
|
||||
void GenericDruidBuffStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
NonCombatStrategy::InitTriggers(triggers);
|
||||
|
||||
triggers.push_back(new TriggerNode("mark of the wild on party", {
|
||||
NextAction("mark of the wild on party", 13.0f),
|
||||
}));
|
||||
triggers.push_back(new TriggerNode("thorns on main tank", {
|
||||
NextAction("thorns on main tank", 11.0f),
|
||||
}));
|
||||
triggers.push_back(new TriggerNode("thorns", {
|
||||
NextAction("thorns", 10.0f),
|
||||
}));
|
||||
}
|
||||
@@ -1,158 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "GenericDruidStrategy.h"
|
||||
|
||||
#include "Playerbots.h"
|
||||
|
||||
class GenericDruidStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
|
||||
{
|
||||
public:
|
||||
GenericDruidStrategyActionNodeFactory()
|
||||
{
|
||||
creators["melee"] = &melee;
|
||||
creators["caster form"] = &caster_form;
|
||||
creators["cure poison"] = &cure_poison;
|
||||
creators["cure poison on party"] = &cure_poison_on_party;
|
||||
creators["abolish poison"] = &abolish_poison;
|
||||
creators["abolish poison on party"] = &abolish_poison_on_party;
|
||||
creators["rebirth"] = &rebirth;
|
||||
creators["entangling roots on cc"] = &entangling_roots_on_cc;
|
||||
creators["innervate"] = &innervate;
|
||||
}
|
||||
|
||||
private:
|
||||
static ActionNode* melee([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode("melee",
|
||||
/*P*/ {},
|
||||
/*A*/ {},
|
||||
/*C*/ {});
|
||||
}
|
||||
|
||||
static ActionNode* caster_form([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode("caster form",
|
||||
/*P*/ {},
|
||||
/*A*/ {},
|
||||
/*C*/ {});
|
||||
}
|
||||
|
||||
static ActionNode* cure_poison([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode("cure poison",
|
||||
/*P*/ {},
|
||||
/*A*/ {},
|
||||
/*C*/ {});
|
||||
}
|
||||
|
||||
static ActionNode* cure_poison_on_party([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode("cure poison on party",
|
||||
/*P*/ {},
|
||||
/*A*/ {},
|
||||
/*C*/ {});
|
||||
}
|
||||
|
||||
static ActionNode* abolish_poison([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode("abolish poison",
|
||||
/*P*/ {},
|
||||
/*A*/ {},
|
||||
/*C*/ {});
|
||||
}
|
||||
|
||||
static ActionNode* abolish_poison_on_party([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode("abolish poison on party",
|
||||
/*P*/ {},
|
||||
/*A*/ {},
|
||||
/*C*/ {});
|
||||
}
|
||||
|
||||
static ActionNode* rebirth([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode("rebirth",
|
||||
/*P*/ {},
|
||||
/*A*/ {},
|
||||
/*C*/ {});
|
||||
}
|
||||
|
||||
static ActionNode* entangling_roots_on_cc([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode("entangling roots on cc",
|
||||
/*P*/ { NextAction("caster form") },
|
||||
/*A*/ {},
|
||||
/*C*/ {});
|
||||
}
|
||||
|
||||
static ActionNode* innervate([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode("innervate",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("mana potion") },
|
||||
/*C*/ {});
|
||||
}
|
||||
};
|
||||
|
||||
GenericDruidStrategy::GenericDruidStrategy(PlayerbotAI* botAI) : CombatStrategy(botAI)
|
||||
{
|
||||
actionNodeFactories.Add(new GenericDruidStrategyActionNodeFactory());
|
||||
}
|
||||
|
||||
void GenericDruidStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
CombatStrategy::InitTriggers(triggers);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode("low health", { NextAction("barkskin", ACTION_HIGH + 7) }));
|
||||
|
||||
triggers.push_back(new TriggerNode("combat party member dead",
|
||||
{ NextAction("rebirth", ACTION_HIGH + 9) }));
|
||||
triggers.push_back(new TriggerNode("being attacked",
|
||||
{ NextAction("nature's grasp", ACTION_HIGH + 1) }));
|
||||
triggers.push_back(new TriggerNode("new pet", { NextAction("set pet stance", 60.0f) }));
|
||||
}
|
||||
|
||||
void DruidCureStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(
|
||||
new TriggerNode("party member cure poison",
|
||||
{ NextAction("abolish poison on party", ACTION_DISPEL + 1) }));
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode("party member remove curse",
|
||||
{ NextAction("remove curse on party", ACTION_DISPEL + 7) }));
|
||||
|
||||
}
|
||||
|
||||
void DruidBoostStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(new TriggerNode(
|
||||
"nature's swiftness", { NextAction("nature's swiftness", ACTION_HIGH + 9) }));
|
||||
}
|
||||
|
||||
void DruidCcStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(new TriggerNode(
|
||||
"entangling roots", { NextAction("entangling roots on cc", ACTION_HIGH + 2) }));
|
||||
triggers.push_back(new TriggerNode(
|
||||
"entangling roots kite", { NextAction("entangling roots", ACTION_HIGH + 2) }));
|
||||
triggers.push_back(new TriggerNode(
|
||||
"hibernate", { NextAction("hibernate on cc", ACTION_HIGH + 3) }));
|
||||
}
|
||||
|
||||
void DruidHealerDpsStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(
|
||||
new TriggerNode("healer should attack",
|
||||
{
|
||||
NextAction("cancel tree form", ACTION_DEFAULT + 0.3f),
|
||||
NextAction("moonfire", ACTION_DEFAULT + 0.2f),
|
||||
NextAction("wrath", ACTION_DEFAULT + 0.1f),
|
||||
NextAction("starfire", ACTION_DEFAULT),
|
||||
}));
|
||||
|
||||
}
|
||||
@@ -1,101 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "HealDruidStrategy.h"
|
||||
|
||||
#include "Playerbots.h"
|
||||
|
||||
class HealDruidStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
|
||||
{
|
||||
public:
|
||||
HealDruidStrategyActionNodeFactory() {
|
||||
creators["nourish on party"] = &nourtish_on_party;
|
||||
}
|
||||
|
||||
private:
|
||||
static ActionNode* nourtish_on_party([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode("nourish on party",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("healing touch on party") },
|
||||
/*C*/ {});
|
||||
}
|
||||
};
|
||||
|
||||
HealDruidStrategy::HealDruidStrategy(PlayerbotAI* botAI) : GenericDruidStrategy(botAI)
|
||||
{
|
||||
actionNodeFactories.Add(new HealDruidStrategyActionNodeFactory());
|
||||
}
|
||||
|
||||
void HealDruidStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
GenericDruidStrategy::InitTriggers(triggers);
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"party member to heal out of spell range",
|
||||
{ NextAction("reach party member to heal", ACTION_CRITICAL_HEAL + 9) }));
|
||||
|
||||
// CRITICAL
|
||||
triggers.push_back(
|
||||
new TriggerNode("party member critical health",
|
||||
{
|
||||
NextAction("tree form", ACTION_CRITICAL_HEAL + 4.1f),
|
||||
NextAction("swiftmend on party", ACTION_CRITICAL_HEAL + 4),
|
||||
NextAction("regrowth on party", ACTION_CRITICAL_HEAL + 3),
|
||||
NextAction("wild growth on party", ACTION_CRITICAL_HEAL + 2),
|
||||
NextAction("nourish on party", ACTION_CRITICAL_HEAL + 1),
|
||||
}));
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode("party member critical health",
|
||||
{ NextAction("nature's swiftness", ACTION_CRITICAL_HEAL + 4) }));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"group heal setting",
|
||||
{
|
||||
NextAction("tree form", ACTION_MEDIUM_HEAL + 2.3f),
|
||||
NextAction("wild growth on party", ACTION_MEDIUM_HEAL + 2.2f),
|
||||
NextAction("rejuvenation on not full", ACTION_MEDIUM_HEAL + 2.1f),
|
||||
}));
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode("medium group heal setting",
|
||||
{
|
||||
NextAction("tree form", ACTION_CRITICAL_HEAL + 0.6f),
|
||||
NextAction("tranquility", ACTION_CRITICAL_HEAL + 0.5f) }));
|
||||
|
||||
// LOW
|
||||
triggers.push_back(
|
||||
new TriggerNode("party member low health",
|
||||
{ NextAction("tree form", ACTION_MEDIUM_HEAL + 1.5f),
|
||||
NextAction("wild growth on party", ACTION_MEDIUM_HEAL + 1.4f),
|
||||
NextAction("regrowth on party", ACTION_MEDIUM_HEAL + 1.3f),
|
||||
NextAction("swiftmend on party", ACTION_MEDIUM_HEAL + 1.2),
|
||||
NextAction("nourish on party", ACTION_MEDIUM_HEAL + 1.1f),
|
||||
}));
|
||||
|
||||
// MEDIUM
|
||||
triggers.push_back(
|
||||
new TriggerNode("party member medium health",
|
||||
{
|
||||
NextAction("tree form", ACTION_MEDIUM_HEAL + 0.5f),
|
||||
NextAction("wild growth on party", ACTION_MEDIUM_HEAL + 0.4f),
|
||||
NextAction("rejuvenation on party", ACTION_MEDIUM_HEAL + 0.3f),
|
||||
NextAction("regrowth on party", ACTION_MEDIUM_HEAL + 0.2f),
|
||||
NextAction("nourish on party", ACTION_MEDIUM_HEAL + 0.1f) }));
|
||||
|
||||
// almost full
|
||||
triggers.push_back(
|
||||
new TriggerNode("party member almost full health",
|
||||
{ NextAction("wild growth on party", ACTION_LIGHT_HEAL + 0.3f),
|
||||
NextAction("rejuvenation on party", ACTION_LIGHT_HEAL + 0.2f),
|
||||
NextAction("regrowth on party", ACTION_LIGHT_HEAL + 0.1f) }));
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode("medium mana", { NextAction("innervate", ACTION_HIGH + 5) }));
|
||||
|
||||
triggers.push_back(new TriggerNode("enemy too close for spell",
|
||||
{ NextAction("flee", ACTION_MOVE + 9) }));
|
||||
}
|
||||
@@ -1,307 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "OffhealDruidCatStrategy.h"
|
||||
|
||||
#include "Playerbots.h"
|
||||
#include "Strategy.h"
|
||||
|
||||
class OffhealDruidCatStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
|
||||
{
|
||||
public:
|
||||
OffhealDruidCatStrategyActionNodeFactory()
|
||||
{
|
||||
creators["cat form"] = &cat_form;
|
||||
creators["mangle (cat)"] = &mangle_cat;
|
||||
creators["shred"] = &shred;
|
||||
creators["rake"] = &rake;
|
||||
creators["rip"] = &rip;
|
||||
creators["ferocious bite"] = &ferocious_bite;
|
||||
creators["savage roar"] = &savage_roar;
|
||||
creators["faerie fire (feral)"] = &faerie_fire_feral;
|
||||
creators["healing touch on party"] = &healing_touch_on_party;
|
||||
creators["regrowth on party"] = ®rowth_on_party;
|
||||
creators["rejuvenation on party"] = &rejuvenation_on_party;
|
||||
}
|
||||
|
||||
private:
|
||||
static ActionNode* cat_form([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"cat form",
|
||||
/*P*/ {},
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* mangle_cat([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"mangle (cat)",
|
||||
/*P*/ {},
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* shred([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"shred",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("claw") },
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* rake([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"rake",
|
||||
/*P*/ {},
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* rip([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"rip",
|
||||
/*P*/ {},
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* ferocious_bite([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"ferocious bite",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("rip") },
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* savage_roar([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"savage roar",
|
||||
/*P*/ {},
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* faerie_fire_feral([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"faerie fire (feral)",
|
||||
/*P*/ {},
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* healing_touch_on_party([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"healing touch on party",
|
||||
/*P*/ { NextAction("caster form") },
|
||||
/*A*/ {},
|
||||
/*C*/ { NextAction("cat form") }
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* regrowth_on_party([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"regrowth on party",
|
||||
/*P*/ { NextAction("caster form") },
|
||||
/*A*/ {},
|
||||
/*C*/ { NextAction("cat form") }
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* rejuvenation_on_party([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"rejuvenation on party",
|
||||
/*P*/ { NextAction("caster form") },
|
||||
/*A*/ {},
|
||||
/*C*/ { NextAction("cat form") }
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
OffhealDruidCatStrategy::OffhealDruidCatStrategy(PlayerbotAI* botAI) : FeralDruidStrategy(botAI)
|
||||
{
|
||||
actionNodeFactories.Add(new OffhealDruidCatStrategyActionNodeFactory());
|
||||
}
|
||||
|
||||
std::vector<NextAction> OffhealDruidCatStrategy::getDefaultActions()
|
||||
{
|
||||
return {
|
||||
NextAction("mangle (cat)", ACTION_DEFAULT + 0.5f),
|
||||
NextAction("shred", ACTION_DEFAULT + 0.4f),
|
||||
NextAction("rake", ACTION_DEFAULT + 0.3f),
|
||||
NextAction("melee", ACTION_DEFAULT),
|
||||
NextAction("cat form", ACTION_DEFAULT - 0.1f)
|
||||
};
|
||||
}
|
||||
|
||||
void OffhealDruidCatStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
FeralDruidStrategy::InitTriggers(triggers);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"cat form",
|
||||
{
|
||||
NextAction("cat form", ACTION_HIGH + 8)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"savage roar",
|
||||
{
|
||||
NextAction("savage roar", ACTION_HIGH + 7)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"combo points available",
|
||||
{
|
||||
NextAction("rip", ACTION_HIGH + 6)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"ferocious bite time",
|
||||
{
|
||||
NextAction("ferocious bite", ACTION_HIGH + 5)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"target with combo points almost dead",
|
||||
{
|
||||
NextAction("ferocious bite", ACTION_HIGH + 4)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"mangle (cat)",
|
||||
{
|
||||
NextAction("mangle (cat)", ACTION_HIGH + 3)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"rake",
|
||||
{
|
||||
NextAction("rake", ACTION_HIGH + 2)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"almost full energy available",
|
||||
{
|
||||
NextAction("shred", ACTION_DEFAULT + 0.4f)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"combo points not full",
|
||||
{
|
||||
NextAction("shred", ACTION_DEFAULT + 0.4f)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"faerie fire (feral)",
|
||||
{
|
||||
NextAction("faerie fire (feral)", ACTION_NORMAL)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"enemy out of melee",
|
||||
{
|
||||
NextAction("feral charge - cat", ACTION_HIGH + 9),
|
||||
NextAction("dash", ACTION_HIGH + 8)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"medium aoe",
|
||||
{
|
||||
NextAction("swipe (cat)", ACTION_HIGH + 3)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"low energy",
|
||||
{
|
||||
NextAction("tiger's fury", ACTION_NORMAL + 1)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"party member critical health",
|
||||
{
|
||||
NextAction("regrowth on party", ACTION_CRITICAL_HEAL + 6),
|
||||
NextAction("healing touch on party", ACTION_CRITICAL_HEAL + 5)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"party member low health",
|
||||
{
|
||||
NextAction("healing touch on party", ACTION_MEDIUM_HEAL + 5)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"party member medium health",
|
||||
{
|
||||
NextAction("rejuvenation on party", ACTION_LIGHT_HEAL + 8)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"party member to heal out of spell range",
|
||||
{
|
||||
NextAction("reach party member to heal", ACTION_EMERGENCY + 3)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"low mana",
|
||||
{
|
||||
NextAction("innervate", ACTION_HIGH + 4)
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "GenericHunterNonCombatStrategy.h"
|
||||
|
||||
#include "Playerbots.h"
|
||||
|
||||
class GenericHunterNonCombatStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
|
||||
{
|
||||
public:
|
||||
GenericHunterNonCombatStrategyActionNodeFactory()
|
||||
{
|
||||
creators["rapid fire"] = &rapid_fire;
|
||||
creators["boost"] = &rapid_fire;
|
||||
creators["aspect of the pack"] = &aspect_of_the_pack;
|
||||
}
|
||||
|
||||
private:
|
||||
static ActionNode* rapid_fire([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode("rapid fire",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("readiness")},
|
||||
/*C*/ {});
|
||||
}
|
||||
|
||||
static ActionNode* aspect_of_the_pack([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode("aspect of the pack",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("aspect of the cheetah")},
|
||||
/*C*/ {});
|
||||
}
|
||||
};
|
||||
|
||||
GenericHunterNonCombatStrategy::GenericHunterNonCombatStrategy(PlayerbotAI* botAI) : NonCombatStrategy(botAI)
|
||||
{
|
||||
actionNodeFactories.Add(new GenericHunterNonCombatStrategyActionNodeFactory());
|
||||
}
|
||||
|
||||
void GenericHunterNonCombatStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
NonCombatStrategy::InitTriggers(triggers);
|
||||
|
||||
triggers.push_back(new TriggerNode("trueshot aura", { NextAction("trueshot aura", 2.0f)}));
|
||||
triggers.push_back(new TriggerNode("often", {
|
||||
NextAction("apply stone", 1.0f),
|
||||
NextAction("apply oil", 1.0f),
|
||||
}));
|
||||
triggers.push_back(new TriggerNode("low ammo", { NextAction("say::low ammo", ACTION_NORMAL)}));
|
||||
triggers.push_back(new TriggerNode("no track", { NextAction("track humanoids", ACTION_NORMAL)}));
|
||||
triggers.push_back(new TriggerNode("no ammo", { NextAction("equip upgrades", ACTION_HIGH + 1)}));
|
||||
}
|
||||
|
||||
void HunterPetStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(new TriggerNode("no pet", { NextAction("call pet", 60.0f)}));
|
||||
triggers.push_back(new TriggerNode("has pet", { NextAction("toggle pet spell", 60.0f)}));
|
||||
triggers.push_back(new TriggerNode("new pet", { NextAction("set pet stance", 60.0f)}));
|
||||
triggers.push_back(new TriggerNode("pet not happy", { NextAction("feed pet", 60.0f)}));
|
||||
triggers.push_back(new TriggerNode("hunters pet medium health", { NextAction("mend pet", 60.0f)}));
|
||||
triggers.push_back(new TriggerNode("hunters pet dead", { NextAction("revive pet", 60.0f)}));
|
||||
}
|
||||
@@ -1,157 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "GenericHunterStrategy.h"
|
||||
|
||||
#include "Playerbots.h"
|
||||
#include "Strategy.h"
|
||||
|
||||
class GenericHunterStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
|
||||
{
|
||||
public:
|
||||
GenericHunterStrategyActionNodeFactory()
|
||||
{
|
||||
creators["rapid fire"] = &rapid_fire;
|
||||
creators["boost"] = &rapid_fire;
|
||||
creators["aspect of the pack"] = &aspect_of_the_pack;
|
||||
creators["aspect of the dragonhawk"] = &aspect_of_the_dragonhawk;
|
||||
creators["feign death"] = &feign_death;
|
||||
creators["wing clip"] = &wing_clip;
|
||||
creators["mongoose bite"] = &mongoose_bite;
|
||||
creators["raptor strike"] = &raptor_strike;
|
||||
creators["explosive trap"] = &explosive_trap;
|
||||
}
|
||||
|
||||
private:
|
||||
static ActionNode* rapid_fire([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode("rapid fire",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("readiness") },
|
||||
/*C*/ {});
|
||||
}
|
||||
|
||||
static ActionNode* aspect_of_the_pack([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode("aspect of the pack",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("aspect of the cheetah") },
|
||||
/*C*/ {});
|
||||
}
|
||||
|
||||
static ActionNode* aspect_of_the_dragonhawk([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode("aspect of the dragonhawk",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("aspect of the hawk") },
|
||||
/*C*/ {});
|
||||
}
|
||||
|
||||
static ActionNode* feign_death([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode("feign death",
|
||||
/*P*/ {},
|
||||
/*A*/ {},
|
||||
/*C*/ {});
|
||||
}
|
||||
|
||||
static ActionNode* wing_clip([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode("wing clip",
|
||||
/*P*/ {},
|
||||
// /*A*/ { NextAction("mongoose bite") },
|
||||
{},
|
||||
/*C*/ {});
|
||||
}
|
||||
|
||||
static ActionNode* mongoose_bite([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode("mongoose bite",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("raptor strike") },
|
||||
/*C*/ {});
|
||||
}
|
||||
|
||||
static ActionNode* raptor_strike([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode("raptor strike",
|
||||
/*P*/ { NextAction("melee") },
|
||||
/*A*/ {},
|
||||
/*C*/ {});
|
||||
}
|
||||
|
||||
static ActionNode* explosive_trap([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode("explosive trap",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("immolation trap") },
|
||||
/*C*/ {});
|
||||
}
|
||||
};
|
||||
|
||||
GenericHunterStrategy::GenericHunterStrategy(PlayerbotAI* botAI) : CombatStrategy(botAI)
|
||||
{
|
||||
actionNodeFactories.Add(new GenericHunterStrategyActionNodeFactory());
|
||||
}
|
||||
|
||||
void GenericHunterStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
CombatStrategy::InitTriggers(triggers);
|
||||
|
||||
// Mark/Ammo/Mana Triggers
|
||||
triggers.push_back(new TriggerNode("no ammo", { NextAction("equip upgrades", 30.0f) }));
|
||||
triggers.push_back(new TriggerNode("hunter's mark", { NextAction("hunter's mark", 29.5f) }));
|
||||
triggers.push_back(new TriggerNode("rapid fire", { NextAction("rapid fire", 29.0f) }));
|
||||
triggers.push_back(new TriggerNode("aspect of the viper", { NextAction("aspect of the viper", 28.0f) }));
|
||||
triggers.push_back(new TriggerNode("aspect of the hawk", { NextAction("aspect of the dragonhawk", 27.5f) }));
|
||||
|
||||
// Aggro/Threat/Defensive Triggers
|
||||
triggers.push_back(new TriggerNode("has aggro", { NextAction("concussive shot", 20.0f) }));
|
||||
triggers.push_back(new TriggerNode("low tank threat", { NextAction("misdirection on main tank", 27.0f) }));
|
||||
triggers.push_back(new TriggerNode("low health", { NextAction("deterrence", 35.0f) }));
|
||||
triggers.push_back(new TriggerNode("concussive shot on snare target", { NextAction("concussive shot", 20.0f) }));
|
||||
triggers.push_back(new TriggerNode("medium threat", { NextAction("feign death", 35.0f) }));
|
||||
triggers.push_back(new TriggerNode("hunters pet medium health", { NextAction("mend pet", 22.0f) }));
|
||||
triggers.push_back(new TriggerNode("hunters pet low health", { NextAction("mend pet", 21.0f) }));
|
||||
|
||||
// Dispel Triggers
|
||||
triggers.push_back(new TriggerNode("tranquilizing shot enrage", { NextAction("tranquilizing shot", 61.0f) }));
|
||||
triggers.push_back(new TriggerNode("tranquilizing shot magic", { NextAction("tranquilizing shot", 61.0f) }));
|
||||
|
||||
// Ranged-based Triggers
|
||||
triggers.push_back(new TriggerNode("enemy within melee", {
|
||||
NextAction("explosive trap", 37.0f),
|
||||
NextAction("mongoose bite", 22.0f),
|
||||
NextAction("wing clip", 21.0f) }));
|
||||
|
||||
triggers.push_back(new TriggerNode("enemy too close for auto shot", {
|
||||
NextAction("disengage", 35.0f),
|
||||
NextAction("flee", 34.0f) }));
|
||||
}
|
||||
|
||||
// ===== AoE Strategy, 2/3+ enemies =====
|
||||
AoEHunterStrategy::AoEHunterStrategy(PlayerbotAI* botAI) : CombatStrategy(botAI) {}
|
||||
|
||||
void AoEHunterStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(new TriggerNode("volley channel check", { NextAction("cancel channel", 23.0f) }));
|
||||
triggers.push_back(new TriggerNode("medium aoe", { NextAction("volley", 22.0f) }));
|
||||
triggers.push_back(new TriggerNode("light aoe", { NextAction("multi-shot", 21.0f) }));
|
||||
}
|
||||
|
||||
void HunterBoostStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
}
|
||||
|
||||
void HunterCcStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(new TriggerNode("scare beast", { NextAction("scare beast on cc", 23.0f) }));
|
||||
triggers.push_back(new TriggerNode("freezing trap", { NextAction("freezing trap on cc", 23.0f) }));
|
||||
}
|
||||
|
||||
void HunterTrapWeaveStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(new TriggerNode("immolation trap no cd", { NextAction("reach melee", 23.0f) }));
|
||||
}
|
||||
@@ -1,159 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "SurvivalHunterStrategy.h"
|
||||
#include "Playerbots.h"
|
||||
|
||||
// ===== Action Node Factory =====
|
||||
class SurvivalHunterStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
|
||||
{
|
||||
public:
|
||||
SurvivalHunterStrategyActionNodeFactory()
|
||||
{
|
||||
creators["auto shot"] = &auto_shot;
|
||||
creators["kill command"] = &kill_command;
|
||||
creators["kill shot"] = &kill_shot;
|
||||
creators["explosive shot"] = &explosive_shot;
|
||||
creators["black arrow"] = &black_arrow;
|
||||
creators["viper sting"] = &viper_sting;
|
||||
creators["serpent sting"] = serpent_sting;
|
||||
creators["aimed shot"] = &aimed_shot;
|
||||
creators["arcane shot"] = &arcane_shot;
|
||||
creators["steady shot"] = &steady_shot;
|
||||
creators["multi-shot"] = &multi_shot;
|
||||
creators["volley"] = &volley;
|
||||
}
|
||||
|
||||
private:
|
||||
static ActionNode* auto_shot(PlayerbotAI*) { return new ActionNode("auto shot", {}, {}, {}); }
|
||||
static ActionNode* kill_command(PlayerbotAI*) { return new ActionNode("kill command", {}, {}, {}); }
|
||||
static ActionNode* kill_shot(PlayerbotAI*) { return new ActionNode("kill shot", {}, {}, {}); }
|
||||
static ActionNode* explosive_shot(PlayerbotAI*) { return new ActionNode("explosive shot", {}, {}, {}); }
|
||||
static ActionNode* black_arrow(PlayerbotAI*) { return new ActionNode("black arrow", {}, {}, {}); }
|
||||
static ActionNode* viper_sting(PlayerbotAI*) { return new ActionNode("viper sting", {}, {}, {}); }
|
||||
static ActionNode* serpent_sting(PlayerbotAI*) { return new ActionNode("serpent sting", {}, {}, {}); }
|
||||
static ActionNode* aimed_shot(PlayerbotAI*) { return new ActionNode("aimed shot", {}, {}, {}); }
|
||||
static ActionNode* arcane_shot(PlayerbotAI*) { return new ActionNode("arcane shot", {}, {}, {}); }
|
||||
static ActionNode* steady_shot(PlayerbotAI*) { return new ActionNode("steady shot", {}, {}, {}); }
|
||||
static ActionNode* multi_shot(PlayerbotAI*) { return new ActionNode("multi shot", {}, {}, {}); }
|
||||
static ActionNode* volley(PlayerbotAI*) { return new ActionNode("volley", {}, {}, {}); }
|
||||
};
|
||||
|
||||
// ===== Single Target Strategy =====
|
||||
SurvivalHunterStrategy::SurvivalHunterStrategy(PlayerbotAI* botAI) : GenericHunterStrategy(botAI)
|
||||
{
|
||||
actionNodeFactories.Add(new SurvivalHunterStrategyActionNodeFactory());
|
||||
}
|
||||
|
||||
// ===== Default Actions =====
|
||||
std::vector<NextAction> SurvivalHunterStrategy::getDefaultActions()
|
||||
{
|
||||
return {
|
||||
NextAction("kill command", 5.9f),
|
||||
NextAction("kill shot", 5.8f),
|
||||
NextAction("explosive shot", 5.7f),
|
||||
NextAction("black arrow", 5.6f),
|
||||
NextAction("serpent sting", 5.5f),
|
||||
NextAction("aimed shot", 5.4f),
|
||||
NextAction("arcane shot", 5.3f),
|
||||
NextAction("steady shot", 5.2f),
|
||||
NextAction("auto shot", 5.1f)
|
||||
};
|
||||
}
|
||||
|
||||
// ===== Trigger Initialization ===
|
||||
void SurvivalHunterStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
GenericHunterStrategy::InitTriggers(triggers);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"lock and load",
|
||||
{
|
||||
NextAction("explosive shot rank 4", 28.0f)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"lock and load",
|
||||
{
|
||||
NextAction("explosive shot rank 3", 27.5f)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"lock and load",
|
||||
{
|
||||
NextAction("explosive shot rank 2", 27.0f)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"lock and load",
|
||||
{
|
||||
NextAction("explosive shot rank 1", 26.5f)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"kill command",
|
||||
{
|
||||
NextAction("kill command", 18.5f)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"target critical health",
|
||||
{
|
||||
NextAction("kill shot", 18.0f)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"explosive shot",
|
||||
{
|
||||
NextAction("explosive shot", 17.5f)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"black arrow",
|
||||
{
|
||||
NextAction("black arrow", 16.5f)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"low mana",
|
||||
{
|
||||
NextAction("viper sting", 16.0f)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"no stings",
|
||||
{
|
||||
NextAction("serpent sting", 15.5f)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"serpent sting on attacker",
|
||||
{
|
||||
NextAction("serpent sting on attacker", 15.0f)
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -1,142 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "FrostMageStrategy.h"
|
||||
|
||||
#include "Playerbots.h"
|
||||
|
||||
// ===== Action Node Factory =====
|
||||
class FrostMageStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
|
||||
{
|
||||
public:
|
||||
FrostMageStrategyActionNodeFactory()
|
||||
{
|
||||
creators["cold snap"] = &cold_snap;
|
||||
creators["ice barrier"] = &ice_barrier;
|
||||
creators["summon water elemental"] = &summon_water_elemental;
|
||||
creators["deep freeze"] = &deep_freeze;
|
||||
creators["icy veins"] = &icy_veins;
|
||||
creators["frostbolt"] = &frostbolt;
|
||||
creators["ice lance"] = &ice_lance;
|
||||
creators["fire blast"] = &fire_blast;
|
||||
creators["fireball"] = &fireball;
|
||||
creators["frostfire bolt"] = &frostfire_bolt;
|
||||
}
|
||||
|
||||
private:
|
||||
static ActionNode* cold_snap(PlayerbotAI*) { return new ActionNode("cold snap", {}, {}, {}); }
|
||||
static ActionNode* ice_barrier(PlayerbotAI*) { return new ActionNode("ice barrier", {}, {}, {}); }
|
||||
static ActionNode* summon_water_elemental(PlayerbotAI*) { return new ActionNode("summon water elemental", {}, {}, {}); }
|
||||
static ActionNode* deep_freeze(PlayerbotAI*) { return new ActionNode("deep freeze", {}, {}, {}); }
|
||||
static ActionNode* icy_veins(PlayerbotAI*) { return new ActionNode("icy veins", {}, {}, {}); }
|
||||
static ActionNode* frostbolt(PlayerbotAI*) { return new ActionNode("frostbolt", {}, {}, {}); }
|
||||
static ActionNode* ice_lance(PlayerbotAI*) { return new ActionNode("ice lance", {}, {}, {}); }
|
||||
static ActionNode* fire_blast(PlayerbotAI*) { return new ActionNode("fire blast", {}, {}, {}); }
|
||||
static ActionNode* fireball(PlayerbotAI*) { return new ActionNode("fireball", {}, {}, {}); }
|
||||
static ActionNode* frostfire_bolt(PlayerbotAI*) { return new ActionNode("frostfire bolt", {}, {}, {}); }
|
||||
};
|
||||
|
||||
// ===== Single Target Strategy =====
|
||||
FrostMageStrategy::FrostMageStrategy(PlayerbotAI* botAI) : GenericMageStrategy(botAI)
|
||||
{
|
||||
actionNodeFactories.Add(new FrostMageStrategyActionNodeFactory());
|
||||
}
|
||||
|
||||
// ===== Default Actions =====
|
||||
std::vector<NextAction> FrostMageStrategy::getDefaultActions()
|
||||
{
|
||||
return {
|
||||
NextAction("frostbolt", 5.4f),
|
||||
NextAction("ice lance", 5.3f), // cast during movement
|
||||
NextAction("fire blast", 5.2f), // cast during movement if ice lance is not learned
|
||||
NextAction("shoot", 5.1f),
|
||||
NextAction("fireball", 5.0f)
|
||||
};
|
||||
}
|
||||
|
||||
// ===== Trigger Initialization ===
|
||||
void FrostMageStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
GenericMageStrategy::InitTriggers(triggers);
|
||||
|
||||
// Pet/Defensive triggers
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"no pet",
|
||||
{
|
||||
NextAction("summon water elemental", 30.0f)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"has pet",
|
||||
{
|
||||
NextAction("toggle pet spell", 60.0f)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"new pet",
|
||||
{
|
||||
NextAction("set pet stance", 60.0f)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"medium health",
|
||||
{
|
||||
NextAction("ice barrier", 29.0f)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"being attacked",
|
||||
{
|
||||
NextAction("ice barrier", 29.0f)
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
// Proc/Freeze triggers
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"brain freeze",
|
||||
{
|
||||
NextAction("frostfire bolt", 19.5f)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"fingers of frost",
|
||||
{
|
||||
NextAction("deep freeze", 19.0f),
|
||||
NextAction("frostbolt", 18.0f)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"frostbite on target",
|
||||
{
|
||||
NextAction("deep freeze", 19.0f),
|
||||
NextAction("frostbolt", 18.0f)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"frost nova on target",
|
||||
{
|
||||
NextAction("deep freeze", 19.0f),
|
||||
NextAction("frostbolt", 18.0f)
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -1,278 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "GenericMageStrategy.h"
|
||||
#include "AiFactory.h"
|
||||
#include "Playerbots.h"
|
||||
#include "RangedCombatStrategy.h"
|
||||
|
||||
class GenericMageStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
|
||||
{
|
||||
public:
|
||||
GenericMageStrategyActionNodeFactory()
|
||||
{
|
||||
creators["frostbolt"] = &frostbolt;
|
||||
creators["frostfire bolt"] = &frostfire_bolt;
|
||||
creators["ice lance"] = &ice_lance;
|
||||
creators["fire blast"] = &fire_blast;
|
||||
creators["scorch"] = &scorch;
|
||||
creators["frost nova"] = &frost_nova;
|
||||
creators["cone of cold"] = &cone_of_cold;
|
||||
creators["icy veins"] = &icy_veins;
|
||||
creators["combustion"] = &combustion;
|
||||
creators["evocation"] = &evocation;
|
||||
creators["dragon's breath"] = &dragons_breath;
|
||||
creators["blast wave"] = &blast_wave;
|
||||
creators["remove curse"] = &remove_curse;
|
||||
creators["remove curse on party"] = &remove_curse_on_party;
|
||||
creators["fireball"] = &fireball;
|
||||
}
|
||||
|
||||
private:
|
||||
static ActionNode* frostbolt([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode("frostbolt",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("shoot") },
|
||||
/*C*/ {});
|
||||
}
|
||||
|
||||
static ActionNode* frostfire_bolt([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode("frostfire bolt",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("fireball") },
|
||||
/*C*/ {});
|
||||
}
|
||||
|
||||
static ActionNode* ice_lance([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode("ice lance",
|
||||
/*P*/ {},
|
||||
/*A*/ {},
|
||||
/*C*/ {});
|
||||
}
|
||||
|
||||
static ActionNode* fire_blast([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode("fire blast",
|
||||
/*P*/ {},
|
||||
/*A*/ {},
|
||||
/*C*/ {});
|
||||
}
|
||||
|
||||
static ActionNode* scorch([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode("scorch",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("shoot") },
|
||||
/*C*/ {});
|
||||
}
|
||||
|
||||
static ActionNode* frost_nova([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode("frost nova",
|
||||
/*P*/ {},
|
||||
/*A*/ {},
|
||||
/*C*/ {});
|
||||
}
|
||||
|
||||
static ActionNode* cone_of_cold([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode("cone of cold",
|
||||
/*P*/ {},
|
||||
/*A*/ {},
|
||||
/*C*/ {});
|
||||
}
|
||||
|
||||
static ActionNode* icy_veins([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode("icy veins",
|
||||
/*P*/ {},
|
||||
/*A*/ {},
|
||||
/*C*/ {});
|
||||
}
|
||||
|
||||
static ActionNode* combustion([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode("combustion",
|
||||
/*P*/ {},
|
||||
/*A*/ {},
|
||||
/*C*/ {});
|
||||
}
|
||||
|
||||
static ActionNode* evocation([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode("evocation",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("mana potion") },
|
||||
/*C*/ {});
|
||||
}
|
||||
|
||||
static ActionNode* dragons_breath([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode("dragon's breath",
|
||||
/*P*/ {},
|
||||
/*A*/ {},
|
||||
/*C*/ {});
|
||||
}
|
||||
|
||||
static ActionNode* blast_wave([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode("blast wave",
|
||||
/*P*/ {},
|
||||
/*A*/ {},
|
||||
/*C*/ {});
|
||||
}
|
||||
|
||||
static ActionNode* remove_curse([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode("remove curse",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("remove lesser curse") },
|
||||
/*C*/ {});
|
||||
}
|
||||
|
||||
static ActionNode* remove_curse_on_party([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode("remove curse on party",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("remove lesser curse on party") },
|
||||
/*C*/ {});
|
||||
}
|
||||
static ActionNode* fireball([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode("fireball",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("shoot") },
|
||||
/*C*/ {});
|
||||
}
|
||||
};
|
||||
|
||||
GenericMageStrategy::GenericMageStrategy(PlayerbotAI* botAI) : RangedCombatStrategy(botAI)
|
||||
{
|
||||
actionNodeFactories.Add(new GenericMageStrategyActionNodeFactory());
|
||||
}
|
||||
|
||||
void GenericMageStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
RangedCombatStrategy::InitTriggers(triggers);
|
||||
|
||||
// Threat Triggers
|
||||
triggers.push_back(new TriggerNode("high threat", { NextAction("mirror image", 60.0f) }));
|
||||
triggers.push_back(new TriggerNode("medium threat", { NextAction("invisibility", 30.0f) }));
|
||||
|
||||
// Defensive Triggers
|
||||
triggers.push_back(new TriggerNode("critical health", { NextAction("ice block", 90.0f) }));
|
||||
triggers.push_back(new TriggerNode("low health", { NextAction("mana shield", 85.0f) }));
|
||||
triggers.push_back(new TriggerNode("fire ward", { NextAction("fire ward", 90.0f) }));
|
||||
triggers.push_back(new TriggerNode("frost ward", { NextAction("frost ward", 90.0f) }));
|
||||
triggers.push_back(new TriggerNode("enemy is close and no firestarter strategy", { NextAction("frost nova", 50.0f) }));
|
||||
triggers.push_back(new TriggerNode("enemy too close for spell and no firestarter strategy", { NextAction("blink back", 35.0f) }));
|
||||
|
||||
// Mana Threshold Triggers
|
||||
Player* bot = botAI->GetBot();
|
||||
if (bot->HasSpell(42985)) // Mana Sapphire
|
||||
triggers.push_back(new TriggerNode("high mana", { NextAction("use mana sapphire", 90.0f) }));
|
||||
else if (bot->HasSpell(27101)) // Mana Emerald
|
||||
triggers.push_back(new TriggerNode("high mana", { NextAction("use mana emerald", 90.0f) }));
|
||||
else if (bot->HasSpell(10054)) // Mana Ruby
|
||||
triggers.push_back(new TriggerNode("high mana", { NextAction("use mana ruby", 90.0f) }));
|
||||
else if (bot->HasSpell(10053)) // Mana Citrine
|
||||
triggers.push_back(new TriggerNode("high mana", { NextAction("use mana citrine", 90.0f) }));
|
||||
else if (bot->HasSpell(3552)) // Mana Jade
|
||||
triggers.push_back(new TriggerNode("high mana", { NextAction("use mana jade", 90.0f) }));
|
||||
else if (bot->HasSpell(759)) // Mana Agate
|
||||
triggers.push_back(new TriggerNode("high mana", { NextAction("use mana agate", 90.0f) }));
|
||||
|
||||
triggers.push_back(new TriggerNode("medium mana", { NextAction("mana potion", 90.0f) }));
|
||||
triggers.push_back(new TriggerNode("low mana", { NextAction("evocation", 90.0f) }));
|
||||
|
||||
// Counterspell / Spellsteal Triggers
|
||||
triggers.push_back(new TriggerNode("spellsteal", { NextAction("spellsteal", 40.0f) }));
|
||||
triggers.push_back(new TriggerNode("counterspell on enemy healer", { NextAction("counterspell on enemy healer", 40.0f) }));
|
||||
}
|
||||
|
||||
void MageCureStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(new TriggerNode("remove curse", { NextAction("remove curse", 41.0f) }));
|
||||
triggers.push_back(new TriggerNode("remove curse on party", { NextAction("remove curse on party", 40.0f) }));
|
||||
}
|
||||
|
||||
void MageBoostStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
Player* bot = botAI->GetBot();
|
||||
int tab = AiFactory::GetPlayerSpecTab(bot);
|
||||
|
||||
if (tab == 0) // Arcane
|
||||
{
|
||||
triggers.push_back(new TriggerNode("arcane power", { NextAction("arcane power", 29.0f) }));
|
||||
triggers.push_back(new TriggerNode("icy veins", { NextAction("icy veins", 28.5f) }));
|
||||
triggers.push_back(new TriggerNode("mirror image", { NextAction("mirror image", 28.0f) }));
|
||||
}
|
||||
else if (tab == 1)
|
||||
{
|
||||
if (bot->HasSpell(44614) /*Frostfire Bolt*/ && bot->HasAura(15047) /*Ice Shards*/)
|
||||
{ // Frostfire
|
||||
triggers.push_back(new TriggerNode("combustion", { NextAction("combustion", 18.0f) }));
|
||||
triggers.push_back(new TriggerNode("icy veins", { NextAction("icy veins", 17.5f) }));
|
||||
triggers.push_back(new TriggerNode("mirror image", { NextAction("mirror image", 17.0f) }));
|
||||
}
|
||||
else
|
||||
{ // Fire
|
||||
triggers.push_back(new TriggerNode("combustion", { NextAction("combustion", 18.0f) }));
|
||||
triggers.push_back(new TriggerNode("mirror image", { NextAction("mirror image", 17.5f) }));
|
||||
}
|
||||
}
|
||||
else if (tab == 2) // Frost
|
||||
{
|
||||
triggers.push_back(new TriggerNode("cold snap", { NextAction("cold snap", 28.0f) }));
|
||||
triggers.push_back(new TriggerNode("icy veins", { NextAction("icy veins", 27.5f) }));
|
||||
triggers.push_back(new TriggerNode("mirror image", { NextAction("mirror image", 26.0f) }));
|
||||
}
|
||||
}
|
||||
|
||||
void MageCcStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(new TriggerNode("polymorph", { NextAction("polymorph", 30.0f) }));
|
||||
}
|
||||
|
||||
void MageAoeStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(new TriggerNode("blizzard channel check", { NextAction("cancel channel", 26.0f) }));
|
||||
|
||||
Player* bot = botAI->GetBot();
|
||||
int tab = AiFactory::GetPlayerSpecTab(bot);
|
||||
|
||||
if (tab == 0) // Arcane
|
||||
{
|
||||
triggers.push_back(new TriggerNode("flamestrike active and medium aoe", { NextAction("blizzard", 24.0f) }));
|
||||
triggers.push_back(new TriggerNode("medium aoe", {
|
||||
NextAction("flamestrike", 23.0f),
|
||||
NextAction("blizzard", 22.0f) }));
|
||||
triggers.push_back(new TriggerNode("light aoe", { NextAction("arcane explosion", 21.0f) }));
|
||||
}
|
||||
else if (tab == 1) // Fire and Frostfire
|
||||
{
|
||||
triggers.push_back(
|
||||
new TriggerNode("medium aoe", {
|
||||
NextAction("dragon's breath", 39.0f),
|
||||
NextAction("blast wave", 38.0f),
|
||||
NextAction("flamestrike", 23.0f),
|
||||
NextAction("blizzard", 22.0f) }));
|
||||
|
||||
triggers.push_back(new TriggerNode("flamestrike active and medium aoe", { NextAction("blizzard", 24.0f) }));
|
||||
triggers.push_back(new TriggerNode("firestarter", { NextAction("flamestrike", 40.0f) }));
|
||||
triggers.push_back(new TriggerNode("living bomb on attackers", { NextAction("living bomb on attackers", 21.0f) }));
|
||||
}
|
||||
else if (tab == 2) // Frost
|
||||
{
|
||||
triggers.push_back(new TriggerNode("flamestrike active and medium aoe", { NextAction("blizzard", 24.0f) }));
|
||||
triggers.push_back(new TriggerNode("medium aoe", {
|
||||
NextAction("flamestrike", 23.0f),
|
||||
NextAction("blizzard", 22.0f) }));
|
||||
triggers.push_back(new TriggerNode("light aoe", { NextAction("cone of cold", 21.0f) }));
|
||||
}
|
||||
}
|
||||
@@ -1,212 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "DpsPaladinStrategy.h"
|
||||
|
||||
#include "Playerbots.h"
|
||||
#include "Strategy.h"
|
||||
|
||||
class DpsPaladinStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
|
||||
{
|
||||
public:
|
||||
DpsPaladinStrategyActionNodeFactory()
|
||||
{
|
||||
creators["sanctity aura"] = &sanctity_aura;
|
||||
creators["retribution aura"] = &retribution_aura;
|
||||
creators["seal of corruption"] = &seal_of_corruption;
|
||||
creators["seal of vengeance"] = &seal_of_vengeance;
|
||||
creators["seal of command"] = &seal_of_command;
|
||||
creators["blessing of might"] = &blessing_of_might;
|
||||
creators["crusader strike"] = &crusader_strike;
|
||||
creators["repentance"] = &repentance;
|
||||
creators["repentance on enemy healer"] = &repentance_on_enemy_healer;
|
||||
creators["repentance on snare target"] = &repentance_on_snare_target;
|
||||
creators["repentance of shield"] = &repentance_or_shield;
|
||||
}
|
||||
|
||||
private:
|
||||
static ActionNode* seal_of_corruption([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"seal of corruption",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("seal of vengeance") },
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* seal_of_vengeance([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"seal of vengeance",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("seal of command") },
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* seal_of_command([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"seal of command",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("seal of righteousness") },
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* blessing_of_might([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"blessing of might",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("blessing of kings") },
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* crusader_strike([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"crusader strike",
|
||||
/*P*/ {},
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* repentance([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"repentance",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("hammer of justice") },
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* repentance_on_enemy_healer([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"repentance on enemy healer",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("hammer of justice on enemy healer") },
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* repentance_on_snare_target([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"repentance on snare target",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("hammer of justice on snare target") },
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* sanctity_aura([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"sanctity aura",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("retribution aura") },
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* retribution_aura([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"retribution aura",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("devotion aura") },
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* repentance_or_shield([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"repentance",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("divine shield") },
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
DpsPaladinStrategy::DpsPaladinStrategy(PlayerbotAI* botAI) : GenericPaladinStrategy(botAI)
|
||||
{
|
||||
actionNodeFactories.Add(new DpsPaladinStrategyActionNodeFactory());
|
||||
}
|
||||
|
||||
std::vector<NextAction> DpsPaladinStrategy::getDefaultActions()
|
||||
{
|
||||
return {
|
||||
NextAction("hammer of wrath", ACTION_DEFAULT + 0.6f),
|
||||
NextAction("judgement of wisdom", ACTION_DEFAULT + 0.5f),
|
||||
NextAction("crusader strike", ACTION_DEFAULT + 0.4f),
|
||||
NextAction("divine storm", ACTION_DEFAULT + 0.3f),
|
||||
NextAction("consecration", ACTION_DEFAULT + 0.1f),
|
||||
NextAction("melee", ACTION_DEFAULT)
|
||||
};
|
||||
}
|
||||
|
||||
void DpsPaladinStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
GenericPaladinStrategy::InitTriggers(triggers);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"art of war",
|
||||
{
|
||||
NextAction("exorcism", ACTION_DEFAULT + 0.2f)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"seal",
|
||||
{
|
||||
NextAction("seal of corruption", ACTION_HIGH)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"low mana",
|
||||
{
|
||||
NextAction("seal of wisdom", ACTION_HIGH + 5)
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"avenging wrath",
|
||||
{
|
||||
NextAction("avenging wrath", ACTION_HIGH + 2)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"medium aoe",
|
||||
{
|
||||
NextAction("divine storm", ACTION_HIGH + 4),
|
||||
NextAction("consecration", ACTION_HIGH + 3)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"enemy out of melee",
|
||||
{
|
||||
NextAction("reach melee", ACTION_HIGH + 1)
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "GenericPaladinStrategy.h"
|
||||
|
||||
#include "GenericPaladinStrategyActionNodeFactory.h"
|
||||
#include "Playerbots.h"
|
||||
|
||||
GenericPaladinStrategy::GenericPaladinStrategy(PlayerbotAI* botAI) : CombatStrategy(botAI)
|
||||
{
|
||||
actionNodeFactories.Add(new GenericPaladinStrategyActionNodeFactory());
|
||||
}
|
||||
|
||||
void GenericPaladinStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
CombatStrategy::InitTriggers(triggers);
|
||||
|
||||
triggers.push_back(new TriggerNode("critical health", { NextAction("divine shield",
|
||||
ACTION_HIGH + 5) }));
|
||||
triggers.push_back(
|
||||
new TriggerNode("hammer of justice interrupt",
|
||||
{ NextAction("hammer of justice", ACTION_INTERRUPT) }));
|
||||
triggers.push_back(new TriggerNode(
|
||||
"hammer of justice on enemy healer",
|
||||
{ NextAction("hammer of justice on enemy healer", ACTION_INTERRUPT) }));
|
||||
triggers.push_back(new TriggerNode(
|
||||
"hammer of justice on snare target",
|
||||
{ NextAction("hammer of justice on snare target", ACTION_INTERRUPT) }));
|
||||
triggers.push_back(new TriggerNode(
|
||||
"critical health", { NextAction("lay on hands", ACTION_EMERGENCY) }));
|
||||
triggers.push_back(
|
||||
new TriggerNode("party member critical health",
|
||||
{ NextAction("lay on hands on party", ACTION_EMERGENCY + 1) }));
|
||||
triggers.push_back(new TriggerNode(
|
||||
"protect party member",
|
||||
{ NextAction("blessing of protection on party", ACTION_EMERGENCY + 2) }));
|
||||
triggers.push_back(
|
||||
new TriggerNode("high mana", { NextAction("divine plea", ACTION_HIGH) }));
|
||||
}
|
||||
|
||||
void PaladinCureStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(new TriggerNode(
|
||||
"cleanse cure disease", { NextAction("cleanse disease", ACTION_DISPEL + 2) }));
|
||||
triggers.push_back(
|
||||
new TriggerNode("cleanse party member cure disease",
|
||||
{ NextAction("cleanse disease on party", ACTION_DISPEL + 1) }));
|
||||
triggers.push_back(new TriggerNode(
|
||||
"cleanse cure poison", { NextAction("cleanse poison", ACTION_DISPEL + 2) }));
|
||||
triggers.push_back(
|
||||
new TriggerNode("cleanse party member cure poison",
|
||||
{ NextAction("cleanse poison on party", ACTION_DISPEL + 1) }));
|
||||
triggers.push_back(new TriggerNode(
|
||||
"cleanse cure magic", { NextAction("cleanse magic", ACTION_DISPEL + 2) }));
|
||||
triggers.push_back(
|
||||
new TriggerNode("cleanse party member cure magic",
|
||||
{ NextAction("cleanse magic on party", ACTION_DISPEL + 1) }));
|
||||
}
|
||||
|
||||
void PaladinBoostStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
|
||||
// triggers.push_back(new TriggerNode("divine favor", { NextAction("divine favor",
|
||||
// ACTION_HIGH + 1) }));
|
||||
}
|
||||
|
||||
void PaladinCcStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(
|
||||
new TriggerNode("turn undead", { NextAction("turn undead", ACTION_HIGH + 1) }));
|
||||
}
|
||||
|
||||
void PaladinHealerDpsStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(
|
||||
new TriggerNode("healer should attack",
|
||||
{
|
||||
NextAction("hammer of wrath", ACTION_DEFAULT + 0.6f),
|
||||
NextAction("holy shock", ACTION_DEFAULT + 0.5f),
|
||||
NextAction("shield of righteousness", ACTION_DEFAULT + 0.4f),
|
||||
NextAction("judgement of light", ACTION_DEFAULT + 0.3f),
|
||||
NextAction("consecration", ACTION_DEFAULT + 0.2f),
|
||||
NextAction("exorcism", ACTION_DEFAULT+ 0.1f),
|
||||
}));
|
||||
}
|
||||
@@ -1,124 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "HealPaladinStrategy.h"
|
||||
|
||||
#include "Playerbots.h"
|
||||
#include "Strategy.h"
|
||||
|
||||
class HealPaladinStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
|
||||
{
|
||||
};
|
||||
|
||||
HealPaladinStrategy::HealPaladinStrategy(PlayerbotAI* botAI) : GenericPaladinStrategy(botAI)
|
||||
{
|
||||
actionNodeFactories.Add(new HealPaladinStrategyActionNodeFactory());
|
||||
}
|
||||
|
||||
std::vector<NextAction> HealPaladinStrategy::getDefaultActions()
|
||||
{
|
||||
return { NextAction("judgement of light", ACTION_DEFAULT) };
|
||||
}
|
||||
|
||||
void HealPaladinStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
GenericPaladinStrategy::InitTriggers(triggers);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"seal",
|
||||
{
|
||||
NextAction("seal of wisdom", ACTION_HIGH)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"medium mana",
|
||||
{
|
||||
NextAction("divine illumination", ACTION_HIGH + 2)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"low mana",
|
||||
{
|
||||
NextAction("divine favor", ACTION_HIGH + 1)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"party member to heal out of spell range",
|
||||
{
|
||||
NextAction("reach party member to heal", ACTION_EMERGENCY + 3)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"medium group heal setting",
|
||||
{
|
||||
NextAction("divine sacrifice", ACTION_CRITICAL_HEAL + 5),
|
||||
NextAction("avenging wrath", ACTION_HIGH + 4),
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"party member critical health",
|
||||
{
|
||||
NextAction("holy shock on party", ACTION_CRITICAL_HEAL + 6),
|
||||
NextAction("divine sacrifice", ACTION_CRITICAL_HEAL + 5),
|
||||
NextAction("holy light on party", ACTION_CRITICAL_HEAL + 4)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"party member low health",
|
||||
{
|
||||
NextAction("holy light on party", ACTION_MEDIUM_HEAL + 5)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"party member medium health",
|
||||
{
|
||||
NextAction("holy light on party", ACTION_LIGHT_HEAL + 9),
|
||||
NextAction("flash of light on party", ACTION_LIGHT_HEAL + 8)
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"party member almost full health",
|
||||
{
|
||||
NextAction("flash of light on party", ACTION_LIGHT_HEAL + 3)
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"beacon of light on main tank",
|
||||
{
|
||||
NextAction("beacon of light on main tank", ACTION_CRITICAL_HEAL + 7)
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"sacred shield on main tank",
|
||||
{
|
||||
NextAction("sacred shield on main tank", ACTION_CRITICAL_HEAL + 6)
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -1,243 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "OffhealRetPaladinStrategy.h"
|
||||
|
||||
#include "Playerbots.h"
|
||||
#include "Strategy.h"
|
||||
|
||||
class OffhealRetPaladinStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
|
||||
{
|
||||
public:
|
||||
OffhealRetPaladinStrategyActionNodeFactory()
|
||||
{
|
||||
creators["retribution aura"] = &retribution_aura;
|
||||
creators["seal of corruption"] = &seal_of_corruption;
|
||||
creators["seal of vengeance"] = &seal_of_vengeance;
|
||||
creators["seal of command"] = &seal_of_command;
|
||||
creators["blessing of might"] = &blessing_of_might;
|
||||
creators["crusader strike"] = &crusader_strike;
|
||||
creators["divine plea"] = &divine_plea;
|
||||
}
|
||||
|
||||
private:
|
||||
static ActionNode* retribution_aura([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"retribution aura",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("devotion aura") },
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* seal_of_corruption([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"seal of corruption",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("seal of vengeance") },
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* seal_of_vengeance([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"seal of vengeance",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("seal of command") },
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* seal_of_command([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"seal of command",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("seal of righteousness") },
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* blessing_of_might([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"blessing of might",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("blessing of kings") },
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* crusader_strike([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"crusader strike",
|
||||
/*P*/ {},
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* divine_plea([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"divine plea",
|
||||
/*P*/ {},
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
OffhealRetPaladinStrategy::OffhealRetPaladinStrategy(PlayerbotAI* botAI) : GenericPaladinStrategy(botAI)
|
||||
{
|
||||
actionNodeFactories.Add(new OffhealRetPaladinStrategyActionNodeFactory());
|
||||
}
|
||||
|
||||
std::vector<NextAction> OffhealRetPaladinStrategy::getDefaultActions()
|
||||
{
|
||||
return {
|
||||
NextAction("hammer of wrath", ACTION_DEFAULT + 0.6f),
|
||||
NextAction("judgement of wisdom", ACTION_DEFAULT + 0.5f),
|
||||
NextAction("crusader strike", ACTION_DEFAULT + 0.4f),
|
||||
NextAction("divine storm", ACTION_DEFAULT + 0.3f),
|
||||
NextAction("melee", ACTION_DEFAULT)
|
||||
};
|
||||
}
|
||||
|
||||
void OffhealRetPaladinStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
GenericPaladinStrategy::InitTriggers(triggers);
|
||||
|
||||
// Damage Triggers
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"seal",
|
||||
{
|
||||
NextAction("seal of corruption", ACTION_HIGH)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"low mana",
|
||||
{
|
||||
NextAction("seal of wisdom", ACTION_HIGH + 5),
|
||||
NextAction("divine plea", ACTION_HIGH + 4)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"art of war",
|
||||
{
|
||||
NextAction("exorcism", ACTION_HIGH + 1)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"avenging wrath",
|
||||
{
|
||||
NextAction("avenging wrath", ACTION_HIGH + 2)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"medium aoe",
|
||||
{
|
||||
NextAction("divine storm", ACTION_HIGH + 4),
|
||||
NextAction("consecration", ACTION_HIGH + 3)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"enemy out of melee",
|
||||
{
|
||||
NextAction("reach melee", ACTION_HIGH + 1)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"retribution aura",
|
||||
{
|
||||
NextAction("retribution aura", ACTION_NORMAL)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"blessing of might",
|
||||
{
|
||||
NextAction("blessing of might", ACTION_NORMAL + 1)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"low health",
|
||||
{
|
||||
NextAction("holy light", ACTION_CRITICAL_HEAL + 2)
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
// Healing Triggers
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"party member critical health",
|
||||
{
|
||||
NextAction("holy shock on party", ACTION_CRITICAL_HEAL + 6),
|
||||
NextAction("holy light on party", ACTION_CRITICAL_HEAL + 4)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"party member low health",
|
||||
{
|
||||
NextAction("holy light on party", ACTION_MEDIUM_HEAL + 5)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"party member medium health",
|
||||
{
|
||||
NextAction("flash of light on party", ACTION_LIGHT_HEAL + 8)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"party member almost full health",
|
||||
{
|
||||
NextAction("flash of light on party", ACTION_LIGHT_HEAL + 3)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"party member to heal out of spell range",
|
||||
{
|
||||
NextAction("reach party member to heal", ACTION_EMERGENCY + 3)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"beacon of light on main tank",
|
||||
{
|
||||
NextAction("beacon of light on main tank", ACTION_CRITICAL_HEAL + 7)
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -1,201 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "TankPaladinStrategy.h"
|
||||
|
||||
#include "Playerbots.h"
|
||||
|
||||
class TankPaladinStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
|
||||
{
|
||||
public:
|
||||
TankPaladinStrategyActionNodeFactory()
|
||||
{
|
||||
creators["seal of corruption"] = &seal_of_corruption;
|
||||
creators["seal of vengeance"] = &seal_of_vengeance;
|
||||
creators["seal of command"] = &seal_of_command;
|
||||
creators["hand of reckoning"] = &hand_of_reckoning;
|
||||
creators["taunt spell"] = &hand_of_reckoning;
|
||||
}
|
||||
|
||||
private:
|
||||
static ActionNode* seal_of_command([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"seal of command",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("seal of corruption") },
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
static ActionNode* seal_of_corruption([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"seal of corruption",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("seal of vengeance") },
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* seal_of_vengeance([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"seal of vengeance",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("seal of righteousness") },
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* hand_of_reckoning([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"hand of reckoning",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("righteous defense") },
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
TankPaladinStrategy::TankPaladinStrategy(PlayerbotAI* botAI) : GenericPaladinStrategy(botAI)
|
||||
{
|
||||
actionNodeFactories.Add(new TankPaladinStrategyActionNodeFactory());
|
||||
}
|
||||
|
||||
std::vector<NextAction> TankPaladinStrategy::getDefaultActions()
|
||||
{
|
||||
return {
|
||||
NextAction("shield of righteousness", ACTION_DEFAULT + 0.6f),
|
||||
NextAction("hammer of the righteous", ACTION_DEFAULT + 0.5f),
|
||||
NextAction("judgement of wisdom", ACTION_DEFAULT + 0.4f),
|
||||
NextAction("melee", ACTION_DEFAULT)
|
||||
};
|
||||
}
|
||||
|
||||
void TankPaladinStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
GenericPaladinStrategy::InitTriggers(triggers);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"seal",
|
||||
{
|
||||
NextAction("seal of corruption", ACTION_HIGH)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"low mana",
|
||||
{
|
||||
NextAction("seal of wisdom", ACTION_HIGH + 9)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(new TriggerNode(
|
||||
"light aoe",
|
||||
{
|
||||
NextAction("avenger's shield", ACTION_HIGH + 5)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"medium aoe",
|
||||
{
|
||||
NextAction("consecration", ACTION_HIGH + 7),
|
||||
NextAction("avenger's shield", ACTION_HIGH + 6)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"lose aggro",
|
||||
{
|
||||
NextAction("hand of reckoning", ACTION_HIGH + 7)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"medium health",
|
||||
{ NextAction("holy shield", ACTION_HIGH + 4)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"low health",
|
||||
{
|
||||
NextAction("holy shield", ACTION_HIGH + 4)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"critical health",
|
||||
{
|
||||
NextAction("holy shield", ACTION_HIGH + 4)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"avenging wrath",
|
||||
{
|
||||
NextAction("avenging wrath", ACTION_HIGH + 2)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"target critical health",
|
||||
{
|
||||
NextAction("hammer of wrath", ACTION_CRITICAL_HEAL)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"righteous fury",
|
||||
{
|
||||
NextAction("righteous fury", ACTION_HIGH + 8)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"medium group heal setting",
|
||||
{
|
||||
NextAction("divine sacrifice", ACTION_HIGH + 5)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"enough mana",
|
||||
{
|
||||
NextAction("consecration", ACTION_HIGH + 4)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"not facing target",
|
||||
{
|
||||
NextAction("set facing", ACTION_NORMAL + 7)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"enemy out of melee",
|
||||
{
|
||||
NextAction("reach melee", ACTION_HIGH + 1)
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "GenericPriestStrategy.h"
|
||||
|
||||
#include "GenericPriestStrategyActionNodeFactory.h"
|
||||
#include "HealPriestStrategy.h"
|
||||
#include "Playerbots.h"
|
||||
|
||||
GenericPriestStrategy::GenericPriestStrategy(PlayerbotAI* botAI) : RangedCombatStrategy(botAI)
|
||||
{
|
||||
actionNodeFactories.Add(new GenericPriestStrategyActionNodeFactory());
|
||||
}
|
||||
|
||||
void GenericPriestStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
CombatStrategy::InitTriggers(triggers);
|
||||
|
||||
triggers.push_back(new TriggerNode("medium threat", { NextAction("fade", 55.0f) }));
|
||||
triggers.push_back(new TriggerNode("critical health", { NextAction("desperate prayer",
|
||||
ACTION_HIGH + 5) }));
|
||||
triggers.push_back(new TriggerNode(
|
||||
"critical health", { NextAction("power word: shield", ACTION_NORMAL) }));
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode("low health", { NextAction("power word: shield", ACTION_HIGH) }));
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode("medium mana",
|
||||
{
|
||||
NextAction("shadowfiend", ACTION_HIGH + 2),
|
||||
NextAction("inner focus", ACTION_HIGH + 1) }));
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode("low mana", { NextAction("hymn of hope", ACTION_HIGH) }));
|
||||
|
||||
triggers.push_back(new TriggerNode("enemy too close for spell",
|
||||
{ NextAction("flee", ACTION_MOVE + 9) }));
|
||||
triggers.push_back(new TriggerNode("often", { NextAction("apply oil", 1.0f) }));
|
||||
triggers.push_back(new TriggerNode("being attacked",
|
||||
{ NextAction("power word: shield", ACTION_HIGH + 1) }));
|
||||
triggers.push_back(new TriggerNode("new pet", { NextAction("set pet stance", 60.0f) }));
|
||||
}
|
||||
|
||||
PriestCureStrategy::PriestCureStrategy(PlayerbotAI* botAI) : Strategy(botAI)
|
||||
{
|
||||
actionNodeFactories.Add(new CurePriestStrategyActionNodeFactory());
|
||||
}
|
||||
|
||||
void PriestCureStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(
|
||||
new TriggerNode("dispel magic", { NextAction("dispel magic", 41.0f) }));
|
||||
triggers.push_back(new TriggerNode("dispel magic on party",
|
||||
{ NextAction("dispel magic on party", 40.0f) }));
|
||||
triggers.push_back(
|
||||
new TriggerNode("cure disease", { NextAction("abolish disease", 31.0f) }));
|
||||
triggers.push_back(new TriggerNode(
|
||||
"party member cure disease", { NextAction("abolish disease on party", 30.0f) }));
|
||||
}
|
||||
|
||||
void PriestBoostStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(
|
||||
new TriggerNode("power infusion", { NextAction("power infusion", 41.0f) }));
|
||||
triggers.push_back(new TriggerNode("boost", { NextAction("shadowfiend", 20.0f) }));
|
||||
}
|
||||
|
||||
void PriestCcStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(
|
||||
new TriggerNode("shackle undead", { NextAction("shackle undead", 31.0f) }));
|
||||
}
|
||||
|
||||
void PriestHealerDpsStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(
|
||||
new TriggerNode("healer should attack",
|
||||
{
|
||||
NextAction("shadow word: pain", ACTION_DEFAULT + 0.5f),
|
||||
NextAction("holy fire", ACTION_DEFAULT + 0.4f),
|
||||
NextAction("smite", ACTION_DEFAULT + 0.3f),
|
||||
NextAction("mind blast", ACTION_DEFAULT + 0.2f),
|
||||
NextAction("shoot", ACTION_DEFAULT) }));
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode("medium aoe and healer should attack",
|
||||
{
|
||||
NextAction("mind sear", ACTION_DEFAULT + 0.5f) }));
|
||||
}
|
||||
@@ -1,257 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#ifndef _PLAYERBOT_GENERICPRIESTSTRATEGYACTIONNODEFACTORY_H
|
||||
#define _PLAYERBOT_GENERICPRIESTSTRATEGYACTIONNODEFACTORY_H
|
||||
|
||||
#include "Action.h"
|
||||
#include "NamedObjectContext.h"
|
||||
|
||||
class GenericPriestStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
|
||||
{
|
||||
public:
|
||||
GenericPriestStrategyActionNodeFactory()
|
||||
{
|
||||
creators["inner fire"] = &inner_fire;
|
||||
creators["holy nova"] = &holy_nova;
|
||||
creators["power word: fortitude"] = &power_word_fortitude;
|
||||
creators["power word: fortitude on party"] = &power_word_fortitude_on_party;
|
||||
creators["divine spirit"] = &divine_spirit;
|
||||
creators["divine spirit on party"] = &divine_spirit_on_party;
|
||||
creators["power word: shield"] = &power_word_shield;
|
||||
// creators["power word: shield on party"] = &power_word_shield_on_party;
|
||||
creators["renew"] = &renew;
|
||||
creators["renew on party"] = &renew_on_party;
|
||||
creators["greater heal"] = &greater_heal;
|
||||
creators["greater heal on party"] = &greater_heal_on_party;
|
||||
creators["heal"] = &heal;
|
||||
creators["heal on party"] = &heal_on_party;
|
||||
creators["lesser heal"] = &lesser_heal;
|
||||
creators["lesser heal on party"] = &lesser_heal_on_party;
|
||||
creators["flash heal"] = &flash_heal;
|
||||
creators["flash heal on party"] = &flash_heal_on_party;
|
||||
creators["psychic scream"] = &psychic_scream;
|
||||
// creators["fade"] = &fade;
|
||||
creators["shadowfiend"] = &shadowfiend;
|
||||
}
|
||||
|
||||
private:
|
||||
static ActionNode* inner_fire([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"inner fire",
|
||||
/*P*/ { NextAction("remove shadowform") },
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
static ActionNode* holy_nova([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"holy nova",
|
||||
/*P*/ { NextAction("remove shadowform") },
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
static ActionNode* power_word_fortitude([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"power word: fortitude",
|
||||
/*P*/ { NextAction("remove shadowform") },
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
static ActionNode* power_word_fortitude_on_party([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"power word: fortitude on party",
|
||||
/*P*/ { NextAction("remove shadowform") },
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
static ActionNode* divine_spirit([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"divine spirit",
|
||||
/*P*/ { NextAction("remove shadowform") },
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
static ActionNode* divine_spirit_on_party([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"divine spirit on party",
|
||||
/*P*/ { NextAction("remove shadowform") },
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
static ActionNode* power_word_shield([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"power word: shield",
|
||||
/*P*/ { NextAction("remove shadowform") },
|
||||
// /*A*/ { NextAction("renew", 50.0f) },
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
static ActionNode* power_word_shield_on_party([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"power word: shield on party",
|
||||
/*P*/ { NextAction("remove shadowform") },
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
static ActionNode* renew([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"renew",
|
||||
/*P*/ { NextAction("remove shadowform") },
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
static ActionNode* renew_on_party([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"renew on party",
|
||||
/*P*/ { NextAction("remove shadowform") },
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
static ActionNode* greater_heal([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"greater heal",
|
||||
/*P*/ { NextAction("remove shadowform") },
|
||||
/*A*/ { NextAction("heal") },
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
static ActionNode* greater_heal_on_party([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"greater heal on party",
|
||||
/*P*/ { NextAction("remove shadowform") },
|
||||
/*A*/ { NextAction("heal on party") },
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
static ActionNode* heal([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"heal",
|
||||
/*P*/ { NextAction("remove shadowform") },
|
||||
/*A*/ { NextAction("lesser heal") },
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
static ActionNode* heal_on_party([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"heal on party",
|
||||
/*P*/ { NextAction("remove shadowform") },
|
||||
/*A*/ { NextAction("lesser heal on party") },
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
static ActionNode* lesser_heal([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"lesser heal",
|
||||
/*P*/ { NextAction("remove shadowform") },
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
static ActionNode* lesser_heal_on_party([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"lesser heal on party",
|
||||
/*P*/ { NextAction("remove shadowform") },
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
static ActionNode* flash_heal([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"flash heal",
|
||||
/*P*/ { NextAction("remove shadowform") },
|
||||
/*A*/ { NextAction("greater heal") },
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
static ActionNode* flash_heal_on_party([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"flash heal on party",
|
||||
/*P*/ { NextAction("remove shadowform") },
|
||||
/*A*/ { NextAction("greater heal on party") },
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
static ActionNode* psychic_scream([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"psychic scream",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("fade") },
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* shadowfiend([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"shadowfiend",
|
||||
/*P*/ {},
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
class CurePriestStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
|
||||
{
|
||||
public:
|
||||
CurePriestStrategyActionNodeFactory()
|
||||
{
|
||||
creators["abolish disease"] = &abolish_disease;
|
||||
creators["abolish disease on party"] = &abolish_disease_on_party;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
static ActionNode* abolish_disease([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"abolish disease",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("cure disease") },
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* abolish_disease_on_party([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"abolish disease on party",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("cure disease on party") },
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,119 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "HealPriestStrategy.h"
|
||||
|
||||
#include "GenericPriestStrategyActionNodeFactory.h"
|
||||
#include "Playerbots.h"
|
||||
|
||||
HealPriestStrategy::HealPriestStrategy(PlayerbotAI* botAI) : GenericPriestStrategy(botAI)
|
||||
{
|
||||
actionNodeFactories.Add(new GenericPriestStrategyActionNodeFactory());
|
||||
}
|
||||
|
||||
std::vector<NextAction> HealPriestStrategy::getDefaultActions()
|
||||
{
|
||||
return {
|
||||
NextAction("shoot", ACTION_DEFAULT)
|
||||
};
|
||||
}
|
||||
|
||||
void HealPriestStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
GenericPriestStrategy::InitTriggers(triggers);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"group heal setting",
|
||||
{
|
||||
NextAction("prayer of mending on party", ACTION_MEDIUM_HEAL + 8),
|
||||
NextAction("power word: shield on not full", ACTION_MEDIUM_HEAL + 7)
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"medium group heal setting",
|
||||
{
|
||||
NextAction("divine hymn", ACTION_CRITICAL_HEAL + 7),
|
||||
NextAction("prayer of mending on party", ACTION_CRITICAL_HEAL + 6),
|
||||
NextAction("power word: shield on not full", ACTION_CRITICAL_HEAL + 5),
|
||||
NextAction("prayer of healing on party", ACTION_CRITICAL_HEAL + 4)
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"party member critical health",
|
||||
{
|
||||
NextAction("power word: shield on party", ACTION_CRITICAL_HEAL + 5),
|
||||
NextAction("penance on party", ACTION_CRITICAL_HEAL + 4),
|
||||
NextAction("prayer of mending on party", ACTION_CRITICAL_HEAL + 3),
|
||||
NextAction("flash heal on party", ACTION_CRITICAL_HEAL + 2)
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"party member low health",
|
||||
{
|
||||
NextAction("power word: shield on party", ACTION_MEDIUM_HEAL + 4),
|
||||
NextAction("prayer of mending on party", ACTION_MEDIUM_HEAL + 3),
|
||||
NextAction("penance on party", ACTION_MEDIUM_HEAL + 2),
|
||||
NextAction("flash heal on party", ACTION_MEDIUM_HEAL + 0)
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"party member medium health",
|
||||
{
|
||||
NextAction("power word: shield on party", ACTION_LIGHT_HEAL + 9),
|
||||
NextAction("prayer of mending on party", ACTION_LIGHT_HEAL + 7),
|
||||
NextAction("penance on party", ACTION_LIGHT_HEAL + 6),
|
||||
NextAction("flash heal on party", ACTION_LIGHT_HEAL + 5)
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"party member almost full health",
|
||||
{
|
||||
NextAction("prayer of mending on party", ACTION_LIGHT_HEAL + 2),
|
||||
NextAction("renew on party", ACTION_LIGHT_HEAL + 1)
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"party member to heal out of spell range",
|
||||
{
|
||||
NextAction("reach party member to heal", ACTION_CRITICAL_HEAL + 10)
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"critical health", {
|
||||
NextAction("pain suppression", ACTION_EMERGENCY + 1)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"protect party member",
|
||||
{
|
||||
NextAction("pain suppression on party", ACTION_EMERGENCY)
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -1,170 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "HolyPriestStrategy.h"
|
||||
|
||||
#include "Playerbots.h"
|
||||
|
||||
class HolyPriestStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
|
||||
{
|
||||
public:
|
||||
HolyPriestStrategyActionNodeFactory() { creators["smite"] = &smite; }
|
||||
|
||||
private:
|
||||
static ActionNode* smite([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"smite",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("shoot") },
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
HolyPriestStrategy::HolyPriestStrategy(PlayerbotAI* botAI) : HealPriestStrategy(botAI)
|
||||
{
|
||||
actionNodeFactories.Add(new HolyPriestStrategyActionNodeFactory());
|
||||
}
|
||||
|
||||
std::vector<NextAction> HolyPriestStrategy::getDefaultActions()
|
||||
{
|
||||
return {
|
||||
NextAction("smite", ACTION_DEFAULT + 0.2f),
|
||||
NextAction("mana burn", ACTION_DEFAULT + 0.1f),
|
||||
NextAction("starshards", ACTION_DEFAULT)
|
||||
};
|
||||
}
|
||||
|
||||
void HolyPriestStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
HealPriestStrategy::InitTriggers(triggers);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"holy fire",
|
||||
{
|
||||
NextAction("holy fire", ACTION_NORMAL + 9)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"shadowfiend",
|
||||
{
|
||||
NextAction("shadowfiend", ACTION_HIGH)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"medium mana",
|
||||
{
|
||||
NextAction("shadowfiend", ACTION_HIGH)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"low mana",
|
||||
{
|
||||
NextAction("mana burn", ACTION_HIGH)
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
HolyHealPriestStrategy::HolyHealPriestStrategy(PlayerbotAI* botAI) : GenericPriestStrategy(botAI)
|
||||
{
|
||||
actionNodeFactories.Add(new GenericPriestStrategyActionNodeFactory());
|
||||
}
|
||||
|
||||
std::vector<NextAction> HolyHealPriestStrategy::getDefaultActions()
|
||||
{
|
||||
return { NextAction("shoot", ACTION_DEFAULT) };
|
||||
}
|
||||
|
||||
void HolyHealPriestStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
GenericPriestStrategy::InitTriggers(triggers);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"group heal setting",
|
||||
{
|
||||
NextAction("prayer of mending on party", ACTION_MEDIUM_HEAL + 9),
|
||||
NextAction("circle of healing on party", ACTION_MEDIUM_HEAL + 8)
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"medium group heal setting",
|
||||
{
|
||||
NextAction("divine hymn", ACTION_CRITICAL_HEAL + 7),
|
||||
NextAction("prayer of mending on party", ACTION_CRITICAL_HEAL + 6),
|
||||
NextAction("circle of healing on party", ACTION_CRITICAL_HEAL + 5),
|
||||
NextAction("prayer of healing on party", ACTION_CRITICAL_HEAL + 4)
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"party member critical health",
|
||||
{
|
||||
NextAction("guardian spirit on party", ACTION_CRITICAL_HEAL + 6),
|
||||
NextAction("power word: shield on party", ACTION_CRITICAL_HEAL + 5),
|
||||
NextAction("prayer of mending on party", ACTION_CRITICAL_HEAL + 3),
|
||||
NextAction("greater heal on party", ACTION_MEDIUM_HEAL + 2),
|
||||
NextAction("flash heal on party", ACTION_CRITICAL_HEAL + 1),
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"party member low health",
|
||||
{
|
||||
NextAction("circle of healing on party", ACTION_MEDIUM_HEAL + 4),
|
||||
NextAction("prayer of mending on party", ACTION_MEDIUM_HEAL + 3),
|
||||
NextAction("greater heal on party", ACTION_MEDIUM_HEAL + 2),
|
||||
NextAction("flash heal on party", ACTION_MEDIUM_HEAL + 1)
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"party member medium health",
|
||||
{
|
||||
NextAction("circle of healing on party", ACTION_LIGHT_HEAL + 7),
|
||||
NextAction("prayer of mending on party", ACTION_LIGHT_HEAL + 6),
|
||||
NextAction("greater heal on party", ACTION_MEDIUM_HEAL + 5),
|
||||
NextAction("flash heal on party", ACTION_LIGHT_HEAL + 4),
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"party member almost full health",
|
||||
{
|
||||
NextAction("renew on party", ACTION_LIGHT_HEAL + 2),
|
||||
NextAction("prayer of mending on party", ACTION_LIGHT_HEAL + 1),
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"party member to heal out of spell range",
|
||||
{
|
||||
NextAction("reach party member to heal", ACTION_CRITICAL_HEAL + 10)
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "PriestNonCombatStrategy.h"
|
||||
|
||||
#include "Playerbots.h"
|
||||
#include "PriestNonCombatStrategyActionNodeFactory.h"
|
||||
|
||||
PriestNonCombatStrategy::PriestNonCombatStrategy(PlayerbotAI* botAI) : NonCombatStrategy(botAI)
|
||||
{
|
||||
actionNodeFactories.Add(new PriestNonCombatStrategyActionNodeFactory());
|
||||
}
|
||||
|
||||
void PriestNonCombatStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
NonCombatStrategy::InitTriggers(triggers);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode("inner fire",{ NextAction("inner fire", 10.0f) }));
|
||||
triggers.push_back(new TriggerNode(
|
||||
"party member dead",{ NextAction("remove shadowform", ACTION_CRITICAL_HEAL + 11),
|
||||
NextAction("resurrection", ACTION_CRITICAL_HEAL + 10) }));
|
||||
triggers.push_back(new TriggerNode("often",{ NextAction("apply oil", 1.0f) }));
|
||||
triggers.push_back(
|
||||
new TriggerNode("party member critical health",
|
||||
{ NextAction("renew on party", ACTION_CRITICAL_HEAL + 3),
|
||||
NextAction("penance on party", ACTION_CRITICAL_HEAL + 2),
|
||||
NextAction("greater heal on party", ACTION_CRITICAL_HEAL + 1) }));
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode("party member low health",
|
||||
{ NextAction("renew on party", ACTION_MEDIUM_HEAL + 3),
|
||||
NextAction("penance on party", ACTION_MEDIUM_HEAL + 2),
|
||||
NextAction("greater heal on party", ACTION_MEDIUM_HEAL + 1) }));
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode("party member medium health",
|
||||
{ NextAction("renew on party", ACTION_LIGHT_HEAL + 9),
|
||||
NextAction("penance on party", ACTION_LIGHT_HEAL + 8) }));
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode("party member almost full health",
|
||||
{ NextAction("renew on party", ACTION_LIGHT_HEAL + 3) }));
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode("group heal setting",{ NextAction("circle of healing on party", 27.0f) }));
|
||||
triggers.push_back(new TriggerNode("new pet",
|
||||
{ NextAction("set pet stance", 10.0f) }));
|
||||
}
|
||||
|
||||
void PriestBuffStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
NonCombatStrategy::InitTriggers(triggers);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode("prayer of fortitude on party",
|
||||
{ NextAction("prayer of fortitude on party", 12.0f) }));
|
||||
triggers.push_back(
|
||||
new TriggerNode("prayer of spirit on party",
|
||||
{ NextAction("prayer of spirit on party", 14.0f) }));
|
||||
triggers.push_back(
|
||||
new TriggerNode("power word: fortitude on party",
|
||||
{ NextAction("power word: fortitude on party", 11.0f) }));
|
||||
triggers.push_back(new TriggerNode("divine spirit on party",
|
||||
{ NextAction("divine spirit on party", 13.0f) }));
|
||||
}
|
||||
|
||||
void PriestShadowResistanceStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
NonCombatStrategy::InitTriggers(triggers);
|
||||
|
||||
triggers.push_back(new TriggerNode("shadow protection",
|
||||
{ NextAction("shadow protection", 12.0f) }));
|
||||
triggers.push_back(
|
||||
new TriggerNode("shadow protection on party",
|
||||
{ NextAction("shadow protection on party", 11.0f) }));
|
||||
}
|
||||
@@ -1,142 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "ShadowPriestStrategy.h"
|
||||
|
||||
#include "Playerbots.h"
|
||||
#include "ShadowPriestStrategyActionNodeFactory.h"
|
||||
|
||||
ShadowPriestStrategy::ShadowPriestStrategy(PlayerbotAI* botAI) : GenericPriestStrategy(botAI)
|
||||
{
|
||||
actionNodeFactories.Add(new ShadowPriestStrategyActionNodeFactory());
|
||||
}
|
||||
|
||||
std::vector<NextAction> ShadowPriestStrategy::getDefaultActions()
|
||||
{
|
||||
return {
|
||||
NextAction("mind blast", ACTION_DEFAULT + 0.3f),
|
||||
NextAction("mind flay", ACTION_DEFAULT + 0.2f),
|
||||
NextAction("shadow word: death", ACTION_DEFAULT + 0.1f), // cast during movement
|
||||
NextAction("shoot", ACTION_DEFAULT)
|
||||
};
|
||||
}
|
||||
|
||||
void ShadowPriestStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
GenericPriestStrategy::InitTriggers(triggers);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"shadowform",
|
||||
{
|
||||
NextAction("shadowform", ACTION_HIGH)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"low mana",
|
||||
{
|
||||
NextAction("dispersion", ACTION_HIGH + 5)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"critical health",
|
||||
{
|
||||
NextAction("dispersion", ACTION_HIGH + 5)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"vampiric embrace",
|
||||
{
|
||||
NextAction("vampiric embrace", 16.0f)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"silence",
|
||||
{
|
||||
NextAction("silence", ACTION_INTERRUPT + 1)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"silence on enemy healer",
|
||||
{
|
||||
NextAction("silence on enemy healer", ACTION_INTERRUPT)
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
void ShadowPriestAoeStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"shadow word: pain on attacker",
|
||||
{
|
||||
NextAction("shadow word: pain on attacker", ACTION_NORMAL + 5)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"vampiric touch on attacker",
|
||||
{
|
||||
NextAction("vampiric touch on attacker", ACTION_NORMAL + 4)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"mind sear channel check",
|
||||
{
|
||||
NextAction("cancel channel", ACTION_HIGH + 5)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"medium aoe",
|
||||
{
|
||||
NextAction("mind sear", ACTION_HIGH + 4)
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
void ShadowPriestDebuffStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"vampiric touch",
|
||||
{
|
||||
NextAction("vampiric touch", ACTION_HIGH + 3)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"devouring plague",
|
||||
{
|
||||
NextAction("devouring plague", ACTION_HIGH + 2)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"shadow word: pain",
|
||||
{
|
||||
NextAction("shadow word: pain", ACTION_HIGH + 1)
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -1,212 +0,0 @@
|
||||
|
||||
#include "AssassinationRogueStrategy.h"
|
||||
|
||||
#include "Playerbots.h"
|
||||
|
||||
class AssassinationRogueStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
|
||||
{
|
||||
public:
|
||||
AssassinationRogueStrategyActionNodeFactory()
|
||||
{
|
||||
creators["mutilate"] = &mutilate;
|
||||
creators["envenom"] = &envenom;
|
||||
creators["backstab"] = &backstab;
|
||||
creators["rupture"] = &rupture;
|
||||
}
|
||||
|
||||
private:
|
||||
static ActionNode* mutilate([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"mutilate",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("backstab") },
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
static ActionNode* envenom([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"envenom",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("rupture") },
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
static ActionNode* backstab([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"backstab",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("sinister strike") },
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
static ActionNode* rupture([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"rupture",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("eviscerate") },
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
AssassinationRogueStrategy::AssassinationRogueStrategy(PlayerbotAI* ai) : MeleeCombatStrategy(ai)
|
||||
{
|
||||
actionNodeFactories.Add(new AssassinationRogueStrategyActionNodeFactory());
|
||||
}
|
||||
|
||||
std::vector<NextAction> AssassinationRogueStrategy::getDefaultActions()
|
||||
{
|
||||
return {
|
||||
NextAction("melee", ACTION_DEFAULT)
|
||||
};
|
||||
}
|
||||
|
||||
void AssassinationRogueStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
MeleeCombatStrategy::InitTriggers(triggers);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"high energy available",
|
||||
{
|
||||
NextAction("garrote", ACTION_HIGH + 7),
|
||||
NextAction("ambush", ACTION_HIGH + 6)
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"high energy available",
|
||||
{
|
||||
NextAction("mutilate", ACTION_NORMAL + 3)
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"hunger for blood",
|
||||
{
|
||||
NextAction("hunger for blood", ACTION_HIGH + 6),
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"slice and dice",
|
||||
{
|
||||
NextAction("slice and dice", ACTION_HIGH + 5),
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"combo points 3 available",
|
||||
{
|
||||
NextAction("envenom", ACTION_HIGH + 5),
|
||||
NextAction("eviscerate", ACTION_HIGH + 3)
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"target with combo points almost dead",
|
||||
{
|
||||
NextAction("envenom", ACTION_HIGH + 4),
|
||||
NextAction("eviscerate", ACTION_HIGH + 2)
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"expose armor",
|
||||
{
|
||||
NextAction("expose armor", ACTION_HIGH + 3),
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"medium threat",
|
||||
{
|
||||
NextAction("vanish", ACTION_HIGH),
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"low health",
|
||||
{
|
||||
NextAction("evasion", ACTION_HIGH + 9),
|
||||
NextAction("feint", ACTION_HIGH + 8)
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"critical health",
|
||||
{
|
||||
NextAction("cloak of shadows", ACTION_HIGH + 7)
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"kick",
|
||||
{
|
||||
NextAction("kick", ACTION_INTERRUPT + 2),
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"kick on enemy healer",
|
||||
{
|
||||
NextAction("kick on enemy healer", ACTION_INTERRUPT + 1),
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"medium aoe",
|
||||
{
|
||||
NextAction("fan of knives", ACTION_NORMAL + 5),
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"low tank threat",
|
||||
{
|
||||
NextAction("tricks of the trade on main tank", ACTION_HIGH + 7),
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"enemy out of melee",
|
||||
{
|
||||
NextAction("stealth", ACTION_HIGH + 3),
|
||||
NextAction("sprint", ACTION_HIGH + 2),
|
||||
NextAction("reach melee", ACTION_HIGH + 1),
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -1,466 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "DpsRogueStrategy.h"
|
||||
|
||||
#include "Playerbots.h"
|
||||
|
||||
class DpsRogueStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
|
||||
{
|
||||
public:
|
||||
DpsRogueStrategyActionNodeFactory()
|
||||
{
|
||||
creators["mutilate"] = &mutilate;
|
||||
creators["sinister strike"] = &sinister_strike;
|
||||
creators["kick"] = &kick;
|
||||
creators["kidney shot"] = &kidney_shot;
|
||||
creators["backstab"] = &backstab;
|
||||
creators["melee"] = &melee;
|
||||
creators["rupture"] = &rupture;
|
||||
}
|
||||
|
||||
private:
|
||||
static ActionNode* melee([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"melee",
|
||||
/*P*/ {},
|
||||
/*A*/ {
|
||||
NextAction("mutilate") },
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
static ActionNode* mutilate([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"mutilate",
|
||||
/*P*/ {},
|
||||
/*A*/ {
|
||||
NextAction("sinister strike") },
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
static ActionNode* sinister_strike([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"sinister strike",
|
||||
/*P*/ {},
|
||||
/*A*/ {
|
||||
NextAction("melee") },
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
static ActionNode* kick([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"kick",
|
||||
/*P*/ {},
|
||||
/*A*/ {
|
||||
NextAction("kidney shot") },
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
static ActionNode* kidney_shot([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"kidney shot",
|
||||
/*P*/ {},
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
static ActionNode* backstab([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"backstab",
|
||||
/*P*/ {},
|
||||
/*A*/ {
|
||||
NextAction("mutilate") },
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
static ActionNode* rupture([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"rupture",
|
||||
/*P*/ {},
|
||||
/*A*/ {
|
||||
NextAction("eviscerate") },
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
DpsRogueStrategy::DpsRogueStrategy(PlayerbotAI* botAI) : MeleeCombatStrategy(botAI)
|
||||
{
|
||||
actionNodeFactories.Add(new DpsRogueStrategyActionNodeFactory());
|
||||
}
|
||||
|
||||
std::vector<NextAction> DpsRogueStrategy::getDefaultActions()
|
||||
{
|
||||
return {
|
||||
NextAction("killing spree", ACTION_DEFAULT + 0.1f),
|
||||
NextAction("melee", ACTION_DEFAULT)
|
||||
};
|
||||
}
|
||||
|
||||
void DpsRogueStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
MeleeCombatStrategy::InitTriggers(triggers);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"high energy available",
|
||||
{
|
||||
NextAction("garrote", ACTION_HIGH + 7),
|
||||
NextAction("ambush", ACTION_HIGH + 6)
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"high energy available",
|
||||
{
|
||||
NextAction("sinister strike", ACTION_NORMAL + 3)
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"slice and dice",
|
||||
{
|
||||
NextAction("slice and dice", ACTION_HIGH + 2)
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"combo points available",
|
||||
{
|
||||
NextAction("rupture", ACTION_HIGH + 1),
|
||||
NextAction("eviscerate", ACTION_HIGH)
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"target with combo points almost dead",
|
||||
{
|
||||
NextAction("eviscerate", ACTION_HIGH + 2)
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"medium threat",
|
||||
{
|
||||
NextAction("vanish", ACTION_HIGH)
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"low health",
|
||||
{
|
||||
NextAction("evasion", ACTION_HIGH + 9),
|
||||
NextAction("feint", ACTION_HIGH + 8)
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"critical health",
|
||||
{
|
||||
NextAction("cloak of shadows", ACTION_HIGH + 7)
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"kick",
|
||||
{
|
||||
NextAction("kick", ACTION_INTERRUPT + 2)
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"kick on enemy healer",
|
||||
{
|
||||
NextAction("kick on enemy healer", ACTION_INTERRUPT + 1)
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"light aoe",
|
||||
{
|
||||
NextAction("blade flurry", ACTION_HIGH + 3)
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"blade flurry",
|
||||
{
|
||||
NextAction("blade flurry", ACTION_HIGH + 2)
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"enemy out of melee",
|
||||
{
|
||||
NextAction("stealth", ACTION_HIGH + 3),
|
||||
NextAction("sprint", ACTION_HIGH + 2),
|
||||
NextAction("reach melee", ACTION_HIGH + 1)
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"expose armor",
|
||||
{
|
||||
NextAction("expose armor", ACTION_HIGH + 3)
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"low tank threat",
|
||||
{
|
||||
NextAction("tricks of the trade on main tank", ACTION_HIGH + 7)
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
class StealthedRogueStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
|
||||
{
|
||||
public:
|
||||
StealthedRogueStrategyActionNodeFactory()
|
||||
{
|
||||
creators["ambush"] = &ambush;
|
||||
creators["cheap shot"] = &cheap_shot;
|
||||
creators["garrote"] = &garrote;
|
||||
creators["sap"] = &sap;
|
||||
creators["sinister strike"] = &sinister_strike;
|
||||
}
|
||||
|
||||
private:
|
||||
static ActionNode* ambush([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"ambush",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("garrote") },
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* cheap_shot([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"cheap shot",
|
||||
/*P*/ {},
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* garrote([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"garrote",
|
||||
/*P*/ {},
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* sap([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"sap",
|
||||
/*P*/ {},
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* sinister_strike([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"sinister strike",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("cheap shot") },
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
StealthedRogueStrategy::StealthedRogueStrategy(PlayerbotAI* botAI) : Strategy(botAI)
|
||||
{
|
||||
actionNodeFactories.Add(new StealthedRogueStrategyActionNodeFactory());
|
||||
}
|
||||
|
||||
std::vector<NextAction> StealthedRogueStrategy::getDefaultActions()
|
||||
{
|
||||
return {
|
||||
NextAction("ambush", ACTION_NORMAL + 4),
|
||||
NextAction("backstab", ACTION_NORMAL + 3),
|
||||
NextAction("cheap shot", ACTION_NORMAL + 2),
|
||||
NextAction("sinister strike", ACTION_NORMAL + 1),
|
||||
NextAction("melee", ACTION_NORMAL)
|
||||
};
|
||||
}
|
||||
|
||||
void StealthedRogueStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"combo points available",
|
||||
{
|
||||
NextAction("eviscerate", ACTION_HIGH)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"kick",
|
||||
{
|
||||
NextAction("cheap shot", ACTION_INTERRUPT)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"kick on enemy healer",
|
||||
{
|
||||
NextAction("cheap shot", ACTION_INTERRUPT)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"behind target",
|
||||
{
|
||||
NextAction("ambush", ACTION_HIGH)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"not behind target",
|
||||
{
|
||||
NextAction("cheap shot", ACTION_HIGH)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"enemy flagcarrier near",
|
||||
{
|
||||
NextAction("sprint", ACTION_EMERGENCY + 1)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"unstealth",
|
||||
{
|
||||
NextAction("unstealth", ACTION_NORMAL)
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"no stealth",
|
||||
{
|
||||
NextAction("check stealth", ACTION_EMERGENCY)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"sprint",
|
||||
{
|
||||
NextAction("sprint", ACTION_INTERRUPT)
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
void StealthStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"stealth",
|
||||
{
|
||||
NextAction("stealth", ACTION_INTERRUPT)
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
void RogueAoeStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"light aoe",
|
||||
{
|
||||
NextAction("blade flurry", ACTION_HIGH)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"medium aoe",
|
||||
{
|
||||
NextAction("fan of knives", ACTION_NORMAL + 5)
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
void RogueBoostStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"adrenaline rush",
|
||||
{
|
||||
NextAction("adrenaline rush", ACTION_HIGH + 2)
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
void RogueCcStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"sap",
|
||||
{
|
||||
NextAction("stealth", ACTION_INTERRUPT),
|
||||
NextAction("sap", ACTION_INTERRUPT)
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -1,149 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "EnhancementShamanStrategy.h"
|
||||
|
||||
#include "Playerbots.h"
|
||||
|
||||
// ===== Action Node Factory =====
|
||||
class EnhancementShamanStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
|
||||
{
|
||||
public:
|
||||
EnhancementShamanStrategyActionNodeFactory()
|
||||
{
|
||||
creators["stormstrike"] = &stormstrike;
|
||||
creators["lava lash"] = &lava_lash;
|
||||
creators["feral spirit"] = &feral_spirit;
|
||||
creators["lightning bolt"] = &lightning_bolt;
|
||||
creators["earth shock"] = &earth_shock;
|
||||
creators["flame shock"] = &flame_shock;
|
||||
creators["shamanistic rage"] = &shamanistic_rage;
|
||||
creators["call of the elements"] = &call_of_the_elements;
|
||||
creators["lightning shield"] = &lightning_shield;
|
||||
}
|
||||
|
||||
private:
|
||||
static ActionNode* stormstrike(PlayerbotAI*) { return new ActionNode("stormstrike", {}, {}, {}); }
|
||||
static ActionNode* lava_lash([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"lava lash",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("melee") },
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
static ActionNode* feral_spirit(PlayerbotAI*) { return new ActionNode("feral spirit", {}, {}, {}); }
|
||||
static ActionNode* lightning_bolt(PlayerbotAI*) { return new ActionNode("lightning bolt", {}, {}, {}); }
|
||||
static ActionNode* earth_shock(PlayerbotAI*) { return new ActionNode("earth shock", {}, {}, {}); }
|
||||
static ActionNode* flame_shock(PlayerbotAI*) { return new ActionNode("flame shock", {}, {}, {}); }
|
||||
static ActionNode* shamanistic_rage(PlayerbotAI*) { return new ActionNode("shamanistic rage", {}, {}, {}); }
|
||||
static ActionNode* call_of_the_elements(PlayerbotAI*) { return new ActionNode("call of the elements", {}, {}, {}); }
|
||||
static ActionNode* lightning_shield(PlayerbotAI*) { return new ActionNode("lightning shield", {}, {}, {}); }
|
||||
};
|
||||
|
||||
// ===== Single Target Strategy =====
|
||||
EnhancementShamanStrategy::EnhancementShamanStrategy(PlayerbotAI* botAI) : GenericShamanStrategy(botAI)
|
||||
{
|
||||
actionNodeFactories.Add(new EnhancementShamanStrategyActionNodeFactory());
|
||||
}
|
||||
|
||||
// ===== Default Actions =====
|
||||
std::vector<NextAction> EnhancementShamanStrategy::getDefaultActions()
|
||||
{
|
||||
return {
|
||||
NextAction("stormstrike", 5.5f),
|
||||
NextAction("feral spirit", 5.4f),
|
||||
NextAction("earth shock", 5.3f),
|
||||
NextAction("lava lash", 5.2f),
|
||||
NextAction("melee", 5.0f)
|
||||
};
|
||||
}
|
||||
|
||||
// ===== Trigger Initialization ===
|
||||
void EnhancementShamanStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
GenericShamanStrategy::InitTriggers(triggers);
|
||||
|
||||
// Totem Trigger
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"call of the elements and enemy within melee",
|
||||
{
|
||||
NextAction("call of the elements", 60.0f)
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
// Spirit Walk Trigger
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"spirit walk ready",
|
||||
{
|
||||
NextAction("spirit walk", 50.0f)
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
// Damage Triggers
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"enemy out of melee",
|
||||
{
|
||||
NextAction("reach melee", 40.0f)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"maelstrom weapon 5",
|
||||
{
|
||||
NextAction("lightning bolt", 20.0f)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"maelstrom weapon 4",
|
||||
{
|
||||
NextAction("lightning bolt", 19.5f)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"flame shock",
|
||||
{
|
||||
NextAction("flame shock", 19.0f)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"lightning shield",
|
||||
{
|
||||
NextAction("lightning shield", 18.5f)
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
// Health/Mana Triggers
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"medium mana",
|
||||
{
|
||||
NextAction("shamanistic rage", 23.0f)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"low health",
|
||||
{
|
||||
NextAction("shamanistic rage", 23.0f)
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -1,126 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "ShamanNonCombatStrategy.h"
|
||||
#include "AiFactory.h"
|
||||
#include "Strategy.h"
|
||||
#include "Playerbots.h"
|
||||
|
||||
class ShamanNonCombatStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
|
||||
{
|
||||
public:
|
||||
ShamanNonCombatStrategyActionNodeFactory()
|
||||
{
|
||||
creators["flametongue weapon"] = &flametongue_weapon;
|
||||
creators["frostbrand weapon"] = &frostbrand_weapon;
|
||||
creators["windfury weapon"] = &windfury_weapon;
|
||||
creators["earthliving weapon"] = &earthliving_weapon;
|
||||
creators["wind shear"] = &wind_shear;
|
||||
creators["purge"] = &purge;
|
||||
}
|
||||
|
||||
private:
|
||||
static ActionNode* flametongue_weapon([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode("flametongue weapon",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("rockbiter weapon") },
|
||||
/*C*/ {});
|
||||
}
|
||||
static ActionNode* frostbrand_weapon([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode("frostbrand weapon",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("flametongue weapon") },
|
||||
/*C*/ {});
|
||||
}
|
||||
static ActionNode* windfury_weapon([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode("windfury weapon",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("flametongue weapon") },
|
||||
/*C*/ {});
|
||||
}
|
||||
static ActionNode* earthliving_weapon([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode("earthliving weapon",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("flametongue weapon") },
|
||||
/*C*/ {});
|
||||
}
|
||||
static ActionNode* wind_shear(PlayerbotAI*) { return new ActionNode("wind shear", {}, {}, {}); }
|
||||
static ActionNode* purge(PlayerbotAI*) { return new ActionNode("purge", {}, {}, {}); }
|
||||
};
|
||||
|
||||
ShamanNonCombatStrategy::ShamanNonCombatStrategy(PlayerbotAI* botAI) : NonCombatStrategy(botAI)
|
||||
{
|
||||
actionNodeFactories.Add(new ShamanNonCombatStrategyActionNodeFactory());
|
||||
}
|
||||
|
||||
void ShamanNonCombatStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
NonCombatStrategy::InitTriggers(triggers);
|
||||
|
||||
// Totemic Recall
|
||||
triggers.push_back(new TriggerNode("totemic recall", { NextAction("totemic recall", 60.0f), }));
|
||||
|
||||
// Healing/Resurrect Triggers
|
||||
triggers.push_back(new TriggerNode("party member dead", { NextAction("ancestral spirit", ACTION_CRITICAL_HEAL + 10), }));
|
||||
triggers.push_back(new TriggerNode("party member critical health", {
|
||||
NextAction("riptide on party", 31.0f),
|
||||
NextAction("healing wave on party", 30.0f) }));
|
||||
triggers.push_back(new TriggerNode("party member low health",{
|
||||
NextAction("riptide on party", 29.0f),
|
||||
NextAction("healing wave on party", 28.0f) }));
|
||||
triggers.push_back(new TriggerNode("party member medium health",{
|
||||
NextAction("riptide on party", 27.0f),
|
||||
NextAction("healing wave on party", 26.0f) }));
|
||||
triggers.push_back(new TriggerNode("party member almost full health",{
|
||||
NextAction("riptide on party", 25.0f),
|
||||
NextAction("lesser healing wave on party", 24.0f) }));
|
||||
triggers.push_back(new TriggerNode("group heal setting",{ NextAction("chain heal on party", 27.0f) }));
|
||||
|
||||
// Cure Triggers
|
||||
triggers.push_back(new TriggerNode("cure poison", { NextAction("cure poison", 21.0f), }));
|
||||
triggers.push_back(new TriggerNode("party member cure poison", { NextAction("cure poison on party", 21.0f), }));
|
||||
triggers.push_back(new TriggerNode("cure disease", { NextAction("cure disease", 31.0f), }));
|
||||
triggers.push_back(new TriggerNode("party member cure disease", { NextAction("cure disease on party", 30.0f), }));
|
||||
|
||||
// Out of Combat Buff Triggers
|
||||
Player* bot = botAI->GetBot();
|
||||
int tab = AiFactory::GetPlayerSpecTab(bot);
|
||||
|
||||
if (tab == 0) // Elemental
|
||||
{
|
||||
triggers.push_back(new TriggerNode("main hand weapon no imbue", { NextAction("flametongue weapon", 22.0f), }));
|
||||
triggers.push_back(new TriggerNode("water shield", { NextAction("water shield", 21.0f), }));
|
||||
}
|
||||
else if (tab == 1) // Enhancement
|
||||
{
|
||||
triggers.push_back(new TriggerNode("main hand weapon no imbue", { NextAction("windfury weapon", 22.0f), }));
|
||||
triggers.push_back(new TriggerNode("off hand weapon no imbue", { NextAction("flametongue weapon", 21.0f), }));
|
||||
triggers.push_back(new TriggerNode("lightning shield", { NextAction("lightning shield", 20.0f), }));
|
||||
}
|
||||
else if (tab == 2) // Restoration
|
||||
{
|
||||
triggers.push_back(new TriggerNode("main hand weapon no imbue",{ NextAction("earthliving weapon", 22.0f), }));
|
||||
triggers.push_back(new TriggerNode("water shield", { NextAction("water shield", 20.0f), }));
|
||||
}
|
||||
|
||||
// Buff Triggers while swimming
|
||||
triggers.push_back(new TriggerNode("water breathing", { NextAction("water breathing", 12.0f), }));
|
||||
triggers.push_back(new TriggerNode("water walking", { NextAction("water walking", 12.0f), }));
|
||||
triggers.push_back(new TriggerNode("water breathing on party", { NextAction("water breathing on party", 11.0f), }));
|
||||
triggers.push_back(new TriggerNode("water walking on party", { NextAction("water walking on party", 11.0f), }));
|
||||
|
||||
// Pet Triggers
|
||||
triggers.push_back(new TriggerNode("has pet", { NextAction("toggle pet spell", 60.0f), }));
|
||||
triggers.push_back(new TriggerNode("new pet", { NextAction("set pet stance", 65.0f), }));
|
||||
}
|
||||
|
||||
void ShamanNonCombatStrategy::InitMultipliers(std::vector<Multiplier*>& multipliers)
|
||||
{
|
||||
NonCombatStrategy::InitMultipliers(multipliers);
|
||||
}
|
||||
@@ -1,261 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "GenericWarlockStrategy.h"
|
||||
#include "Strategy.h"
|
||||
#include "Playerbots.h"
|
||||
|
||||
class GenericWarlockStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
|
||||
{
|
||||
public:
|
||||
GenericWarlockStrategyActionNodeFactory()
|
||||
{
|
||||
creators["banish on cc"] = &banish_on_cc;
|
||||
creators["fear on cc"] = &fear_on_cc;
|
||||
creators["spell lock"] = &spell_lock;
|
||||
creators["devour magic purge"] = &devour_magic_purge;
|
||||
creators["devour magic cleanse"] = &devour_magic_cleanse;
|
||||
}
|
||||
|
||||
private:
|
||||
static ActionNode* banish_on_cc(PlayerbotAI*) { return new ActionNode("banish on cc", {}, {}, {}); }
|
||||
static ActionNode* fear_on_cc(PlayerbotAI*) { return new ActionNode("fear on cc", {}, {}, {}); }
|
||||
static ActionNode* spell_lock(PlayerbotAI*) { return new ActionNode("spell lock", {}, {}, {}); }
|
||||
static ActionNode* devour_magic_purge(PlayerbotAI*) { return new ActionNode("devour magic purge", {}, {}, {}); }
|
||||
static ActionNode* devour_magic_cleanse(PlayerbotAI*) { return new ActionNode("devour magic cleanse", {}, {}, {}); }
|
||||
};
|
||||
|
||||
GenericWarlockStrategy::GenericWarlockStrategy(PlayerbotAI* botAI) : CombatStrategy(botAI)
|
||||
{
|
||||
actionNodeFactories.Add(new GenericWarlockStrategyActionNodeFactory());
|
||||
}
|
||||
|
||||
std::vector<NextAction> GenericWarlockStrategy::getDefaultActions()
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
void GenericWarlockStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
CombatStrategy::InitTriggers(triggers);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"low mana",
|
||||
{
|
||||
NextAction("life tap", 95.0f)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"medium threat",
|
||||
{
|
||||
NextAction("soulshatter", 55.0f)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"spell lock",
|
||||
{
|
||||
NextAction("spell lock", 40.0f)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"no soul shard",
|
||||
{
|
||||
NextAction("create soul shard", 60.0f)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"too many soul shards",
|
||||
{
|
||||
NextAction("destroy soul shard", 60.0f)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"devour magic purge",
|
||||
{
|
||||
NextAction("devour magic purge", 50.0f)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"devour magic cleanse",
|
||||
{
|
||||
NextAction("devour magic cleanse", 50.0f)
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// ===== AoE Strategy, 3+ enemies =====
|
||||
|
||||
void AoEWarlockStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"medium aoe",
|
||||
{
|
||||
NextAction("immolation aura", 26.0f),
|
||||
NextAction("shadowfury", 23.0f),
|
||||
NextAction("shadowflame", 22.5f),
|
||||
NextAction("seed of corruption on attacker", 22.0f),
|
||||
NextAction("seed of corruption", 21.5f),
|
||||
NextAction("rain of fire", 21.0f)
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode("rain of fire channel check",
|
||||
{
|
||||
NextAction("cancel channel", 21.5f)
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
void WarlockBoostStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
// Placeholder for future boost triggers
|
||||
}
|
||||
|
||||
void WarlockPetStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
// Placeholder for future pet triggers
|
||||
}
|
||||
|
||||
void WarlockCcStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"banish",
|
||||
{
|
||||
NextAction("banish on cc", 33.0f)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"fear",
|
||||
{
|
||||
NextAction("fear on cc", 32.0f)
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Combat strategy for using Curse of Agony
|
||||
// Enabled by default for the Affliction spec
|
||||
// To enable, type "co +curse of agony"
|
||||
// To disable, type "co -curse of agony"
|
||||
void WarlockCurseOfAgonyStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"curse of agony on attacker",
|
||||
{
|
||||
NextAction("curse of agony on attacker", 18.5f)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"curse of agony",
|
||||
{
|
||||
NextAction("curse of agony", 17.0f)
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Combat strategy for using Curse of the Elements
|
||||
// Enabled by default for the Destruction spec
|
||||
// To enable, type "co +curse of elements"
|
||||
// To disable, type "co -curse of elements"
|
||||
void WarlockCurseOfTheElementsStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"curse of the elements",
|
||||
{
|
||||
NextAction("curse of the elements", 29.0f)
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Combat strategy for using Curse of Doom
|
||||
// Disabled by default
|
||||
// To enable, type "co +curse of doom"
|
||||
// To disable, type "co -curse of doom"
|
||||
void WarlockCurseOfDoomStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"curse of doom",
|
||||
{
|
||||
NextAction("curse of doom", 29.0f)
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Combat strategy for using Curse of Exhaustion
|
||||
// Disabled by default
|
||||
// To enable, type "co +curse of exhaustion"
|
||||
// To disable, type "co -curse of exhaustion"
|
||||
void WarlockCurseOfExhaustionStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"curse of exhaustion",
|
||||
{
|
||||
NextAction("curse of exhaustion", 29.0f)
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Combat strategy for using Curse of Tongues
|
||||
// Disabled by default
|
||||
// To enable, type "co +curse of tongues"
|
||||
// To disable, type "co -curse of tongues"
|
||||
void WarlockCurseOfTonguesStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"curse of tongues",
|
||||
{
|
||||
NextAction("curse of tongues", 29.0f)
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Combat strategy for using Curse of Weakness
|
||||
// Disabled by default
|
||||
// To enable, type "co +curse of weakness"
|
||||
// To disable, type "co -curse of weakness"
|
||||
void WarlockCurseOfWeaknessStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"curse of weakness",
|
||||
{
|
||||
NextAction("curse of weakness", 29.0f)
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -1,294 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "ArmsWarriorStrategy.h"
|
||||
|
||||
#include "Playerbots.h"
|
||||
|
||||
class ArmsWarriorStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
|
||||
{
|
||||
public:
|
||||
ArmsWarriorStrategyActionNodeFactory()
|
||||
{
|
||||
creators["charge"] = &charge;
|
||||
creators["death wish"] = &death_wish;
|
||||
creators["piercing howl"] = &piercing_howl;
|
||||
creators["mocking blow"] = &mocking_blow;
|
||||
creators["heroic strike"] = &heroic_strike;
|
||||
creators["enraged regeneration"] = &enraged_regeneration;
|
||||
creators["retaliation"] = &retaliation;
|
||||
creators["shattering throw"] = &shattering_throw;
|
||||
}
|
||||
|
||||
private:
|
||||
static ActionNode* charge(PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"charge",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("reach melee") },
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* death_wish(PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"death wish",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("bloodrage") },
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* piercing_howl(PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"piercing howl",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("mocking blow") },
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* mocking_blow(PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"mocking blow",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("hamstring") },
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* heroic_strike(PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"heroic strike",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("melee") },
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* enraged_regeneration(PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"enraged regeneration",
|
||||
/*P*/ {},
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* retaliation(PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"retaliation",
|
||||
/*P*/ {},
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* shattering_throw(PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"shattering throw",
|
||||
/*P*/ {},
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
ArmsWarriorStrategy::ArmsWarriorStrategy(PlayerbotAI* botAI) : GenericWarriorStrategy(botAI)
|
||||
{
|
||||
actionNodeFactories.Add(new ArmsWarriorStrategyActionNodeFactory());
|
||||
}
|
||||
|
||||
std::vector<NextAction> ArmsWarriorStrategy::getDefaultActions()
|
||||
{
|
||||
return {
|
||||
NextAction("bladestorm", ACTION_DEFAULT + 0.2f),
|
||||
NextAction("mortal strike", ACTION_DEFAULT + 0.1f),
|
||||
NextAction("melee", ACTION_DEFAULT)
|
||||
};
|
||||
}
|
||||
void ArmsWarriorStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
GenericWarriorStrategy::InitTriggers(triggers);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"enemy out of melee",
|
||||
{
|
||||
NextAction("charge", ACTION_MOVE + 10)
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"battle stance",
|
||||
{
|
||||
NextAction("battle stance", ACTION_HIGH + 10)
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"battle shout",
|
||||
{
|
||||
NextAction("battle shout", ACTION_HIGH + 9)
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"rend",
|
||||
{
|
||||
NextAction("rend", ACTION_HIGH + 8)
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"rend on attacker",
|
||||
{
|
||||
NextAction("rend on attacker", ACTION_HIGH + 8)
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"mortal strike",
|
||||
{
|
||||
NextAction("mortal strike", ACTION_HIGH + 3)
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"target critical health",
|
||||
{
|
||||
NextAction("execute", ACTION_HIGH + 5)
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"sudden death",
|
||||
{
|
||||
NextAction("execute", ACTION_HIGH + 5)
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"hamstring",
|
||||
{
|
||||
NextAction("piercing howl", ACTION_HIGH)
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"overpower",
|
||||
{
|
||||
NextAction("overpower", ACTION_HIGH + 4)
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"taste for blood",
|
||||
{
|
||||
NextAction("overpower", ACTION_HIGH + 4)
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"victory rush",
|
||||
{
|
||||
NextAction("victory rush", ACTION_INTERRUPT)
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"high rage available",
|
||||
{
|
||||
NextAction("heroic strike", ACTION_HIGH),
|
||||
NextAction("slam", ACTION_HIGH + 1)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"bloodrage",
|
||||
{
|
||||
NextAction("bloodrage", ACTION_HIGH + 2)
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"death wish",
|
||||
{
|
||||
NextAction("death wish", ACTION_HIGH + 2)
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"critical health",
|
||||
{
|
||||
NextAction("intimidating shout", ACTION_EMERGENCY)
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"medium health",
|
||||
{
|
||||
NextAction("enraged regeneration", ACTION_EMERGENCY)
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"almost full health",
|
||||
{
|
||||
NextAction("retaliation", ACTION_EMERGENCY + 1)
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"shattering throw trigger",
|
||||
{
|
||||
NextAction("shattering throw", ACTION_INTERRUPT + 1)
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -1,206 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "FuryWarriorStrategy.h"
|
||||
|
||||
#include "Playerbots.h"
|
||||
|
||||
class FuryWarriorStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
|
||||
{
|
||||
public:
|
||||
FuryWarriorStrategyActionNodeFactory()
|
||||
{
|
||||
creators["charge"] = &charge;
|
||||
creators["intercept"] = &intercept;
|
||||
creators["piercing howl"] = &piercing_howl;
|
||||
creators["pummel"] = &pummel;
|
||||
creators["enraged regeneration"] = &enraged_regeneration;
|
||||
}
|
||||
|
||||
private:
|
||||
static ActionNode* charge(PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"charge",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("intercept" )},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* intercept(PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"intercept",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("reach melee" )},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* piercing_howl(PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"piercing howl",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("hamstring" )},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* pummel(PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"pummel",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("intercept" )},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* enraged_regeneration(PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"enraged regeneration",
|
||||
/*P*/ {},
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
FuryWarriorStrategy::FuryWarriorStrategy(PlayerbotAI* botAI) : GenericWarriorStrategy(botAI)
|
||||
{
|
||||
actionNodeFactories.Add(new FuryWarriorStrategyActionNodeFactory());
|
||||
}
|
||||
|
||||
std::vector<NextAction> FuryWarriorStrategy::getDefaultActions()
|
||||
{
|
||||
return {
|
||||
NextAction("bloodthirst", ACTION_DEFAULT + 0.5f),
|
||||
NextAction("whirlwind", ACTION_DEFAULT + 0.4f),
|
||||
NextAction("sunder armor", ACTION_DEFAULT + 0.3f),
|
||||
NextAction("execute", ACTION_DEFAULT + 0.2f),
|
||||
NextAction("melee", ACTION_DEFAULT)
|
||||
};
|
||||
}
|
||||
|
||||
void FuryWarriorStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
GenericWarriorStrategy::InitTriggers(triggers);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"enemy out of melee",
|
||||
{
|
||||
NextAction("charge", ACTION_MOVE + 9)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"berserker stance", {
|
||||
NextAction("berserker stance", ACTION_HIGH + 9)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"battle shout",
|
||||
{
|
||||
NextAction("battle shout", ACTION_HIGH + 8)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"pummel on enemy healer",
|
||||
{
|
||||
NextAction("pummel on enemy healer", ACTION_INTERRUPT)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"pummel",
|
||||
{
|
||||
NextAction("pummel", ACTION_INTERRUPT)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"victory rush",
|
||||
{
|
||||
NextAction("victory rush", ACTION_INTERRUPT)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"bloodthirst",
|
||||
{
|
||||
NextAction("bloodthirst", ACTION_HIGH + 7)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"whirlwind",
|
||||
{
|
||||
NextAction("whirlwind", ACTION_HIGH + 6)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"instant slam",
|
||||
{
|
||||
NextAction("slam", ACTION_HIGH + 5)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"bloodrage",
|
||||
{
|
||||
NextAction("bloodrage", ACTION_HIGH + 2)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"medium rage available",
|
||||
{
|
||||
NextAction("heroic strike", ACTION_DEFAULT + 0.1f)
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"death wish",
|
||||
{
|
||||
NextAction("death wish", ACTION_HIGH)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"recklessness",
|
||||
{
|
||||
NextAction("recklessness", ACTION_HIGH)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"critical health",
|
||||
{
|
||||
NextAction("enraged regeneration", ACTION_EMERGENCY)
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "GenericWarriorStrategy.h"
|
||||
|
||||
#include "Playerbots.h"
|
||||
|
||||
GenericWarriorStrategy::GenericWarriorStrategy(PlayerbotAI* botAI) : CombatStrategy(botAI)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void GenericWarriorStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
CombatStrategy::InitTriggers(triggers);
|
||||
triggers.push_back(new TriggerNode(
|
||||
"enemy out of melee", { NextAction("reach melee", ACTION_HIGH + 1) }));
|
||||
}
|
||||
|
||||
class WarrirorAoeStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
|
||||
{
|
||||
public:
|
||||
WarrirorAoeStrategyActionNodeFactory()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
};
|
||||
|
||||
WarrirorAoeStrategy::WarrirorAoeStrategy(PlayerbotAI* botAI) : CombatStrategy(botAI)
|
||||
{
|
||||
actionNodeFactories.Add(new WarrirorAoeStrategyActionNodeFactory());
|
||||
}
|
||||
|
||||
void WarrirorAoeStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(new TriggerNode(
|
||||
"light aoe", { NextAction("sweeping strikes", ACTION_HIGH + 7),
|
||||
NextAction("bladestorm", ACTION_HIGH + 6),
|
||||
NextAction("thunder clap", ACTION_HIGH + 5),
|
||||
NextAction("shockwave", ACTION_HIGH + 4),
|
||||
NextAction("demoralizing shout without life time check", ACTION_HIGH + 1),
|
||||
NextAction("cleave", ACTION_HIGH) }));
|
||||
triggers.push_back(
|
||||
new TriggerNode("shockwave on snare target",
|
||||
{ NextAction("shockwave on snare target", ACTION_HIGH + 5) }));
|
||||
|
||||
}
|
||||
@@ -1,236 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#ifndef _PLAYERBOT_GENERICWARRIORSTRATEGY_H
|
||||
#define _PLAYERBOT_GENERICWARRIORSTRATEGY_H
|
||||
|
||||
#include "CombatStrategy.h"
|
||||
|
||||
class PlayerbotAI;
|
||||
|
||||
// Stance requirements
|
||||
class WarriorStanceRequirementActionNodeFactory : public NamedObjectFactory<ActionNode>
|
||||
{
|
||||
public:
|
||||
WarriorStanceRequirementActionNodeFactory()
|
||||
{
|
||||
// battle only
|
||||
creators["charge"] = &charge;
|
||||
creators["mocking blow"] = &mocking_blow;
|
||||
creators["overpower"] = &overpower;
|
||||
creators["retaliation"] = &retaliation;
|
||||
creators["shattering throw"] = &shattering_throw;
|
||||
|
||||
// temp
|
||||
creators["mortal strike"] = &mortal_strike;
|
||||
|
||||
// berserker only
|
||||
creators["berserker rage"] = &berserker_rage;
|
||||
creators["recklessness"] = &recklessness;
|
||||
creators["whirlwind"] = &whirlwind;
|
||||
creators["pummel"] = &pummel;
|
||||
creators["intercept"] = &intercept;
|
||||
|
||||
// defensive only
|
||||
creators["taunt"] = &taunt;
|
||||
creators["revenge"] = &revenge;
|
||||
creators["shield block"] = &shield_block;
|
||||
creators["disarm"] = &disarm;
|
||||
creators["shield wall"] = &shield_wall;
|
||||
creators["intervene"] = &intervene;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
static ActionNode* charge([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"charge",
|
||||
/*P*/ { NextAction("battle stance") },
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* mocking_blow([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"mocking blow",
|
||||
/*P*/ { NextAction("battle stance") },
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* overpower([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"overpower",
|
||||
/*P*/ { NextAction("battle stance") },
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* berserker_rage([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"berserker rage",
|
||||
/*P*/ { NextAction("berserker stance") },
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* recklessness([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"recklessness",
|
||||
/*P*/ { NextAction("berserker stance") },
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* whirlwind([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"whirlwind",
|
||||
/*P*/ { NextAction("berserker stance") },
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* pummel([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"pummel",
|
||||
/*P*/ { NextAction("berserker stance") },
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* intercept([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"intercept",
|
||||
/*P*/ { NextAction("berserker stance") },
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* taunt([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"taunt",
|
||||
/*P*/ { NextAction("defensive stance") },
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* revenge([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"revenge",
|
||||
/*P*/ { NextAction("defensive stance") },
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* shield_block([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"shield block",
|
||||
/*P*/ { NextAction("defensive stance") },
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* disarm([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"disarm",
|
||||
/*P*/ { NextAction("defensive stance") },
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* shield_wall([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"shield wall",
|
||||
/*P*/ { NextAction("defensive stance") },
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* intervene([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"intervene",
|
||||
/*P*/ { NextAction("defensive stance") },
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* mortal_strike([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"mortal strike",
|
||||
/*P*/ { NextAction("battle stance") },
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* retaliation([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"retaliation",
|
||||
/*P*/ { NextAction("battle stance") },
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* shattering_throw([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"shattering throw",
|
||||
/*P*/ { NextAction("battle stance") },
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
class GenericWarriorStrategy : public CombatStrategy
|
||||
{
|
||||
public:
|
||||
GenericWarriorStrategy(PlayerbotAI* botAI);
|
||||
|
||||
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
|
||||
std::string const getName() override { return "warrior"; }
|
||||
};
|
||||
|
||||
class WarrirorAoeStrategy : public CombatStrategy
|
||||
{
|
||||
public:
|
||||
WarrirorAoeStrategy(PlayerbotAI* botAI);
|
||||
|
||||
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
|
||||
std::string const getName() override { return "aoe"; }
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,369 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "TankWarriorStrategy.h"
|
||||
|
||||
#include "Playerbots.h"
|
||||
|
||||
class TankWarriorStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
|
||||
{
|
||||
public:
|
||||
TankWarriorStrategyActionNodeFactory()
|
||||
{
|
||||
creators["charge"] = &charge;
|
||||
creators["sunder armor"] = &sunder_armor;
|
||||
creators["commanding shout"] = &commanding_shout;
|
||||
creators["devastate"] = &devastate;
|
||||
creators["last stand"] = &last_stand;
|
||||
creators["heroic throw on snare target"] = &heroic_throw_on_snare_target;
|
||||
creators["heroic throw taunt"] = &heroic_throw_taunt;
|
||||
creators["taunt"] = &taunt;
|
||||
creators["taunt spell"] = &taunt;
|
||||
creators["vigilance"] = &vigilance;
|
||||
creators["enraged regeneration"] = &enraged_regeneration;
|
||||
}
|
||||
|
||||
private:
|
||||
static ActionNode* heroic_throw_taunt(PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"heroic throw",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("shield slam") },
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* heroic_throw_on_snare_target(PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"heroic throw on snare target",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("taunt on snare target") },
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* last_stand(PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"last stand",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("intimidating shout") },
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* devastate(PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"devastate",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("sunder armor") },
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* commanding_shout(PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"commanding shout",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("battle shout") },
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* sunder_armor(PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"sunder armor",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("melee") },
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* charge(PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"charge",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("reach melee") },
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* taunt(PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"taunt",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("heroic throw taunt") },
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* vigilance(PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"vigilance",
|
||||
/*P*/ {},
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* enraged_regeneration(PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"enraged regeneration",
|
||||
/*P*/ {},
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
TankWarriorStrategy::TankWarriorStrategy(PlayerbotAI* botAI) : GenericWarriorStrategy(botAI)
|
||||
{
|
||||
actionNodeFactories.Add(new TankWarriorStrategyActionNodeFactory());
|
||||
}
|
||||
|
||||
std::vector<NextAction> TankWarriorStrategy::getDefaultActions()
|
||||
{
|
||||
return {
|
||||
NextAction("devastate", ACTION_DEFAULT + 0.3f),
|
||||
NextAction("revenge", ACTION_DEFAULT + 0.2f),
|
||||
NextAction("demoralizing shout", ACTION_DEFAULT + 0.1f),
|
||||
NextAction("melee", ACTION_DEFAULT)
|
||||
};
|
||||
}
|
||||
|
||||
void TankWarriorStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
GenericWarriorStrategy::InitTriggers(triggers);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"vigilance",
|
||||
{
|
||||
NextAction("vigilance", ACTION_HIGH + 7)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"enemy out of melee",
|
||||
{
|
||||
NextAction("heroic throw", ACTION_MOVE + 11),
|
||||
NextAction("charge", ACTION_MOVE + 10)
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"thunder clap and rage",
|
||||
{
|
||||
NextAction("thunder clap", ACTION_MOVE + 11)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"defensive stance",
|
||||
{
|
||||
NextAction("defensive stance", ACTION_HIGH + 9)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"commanding shout",
|
||||
{
|
||||
NextAction("commanding shout", ACTION_HIGH + 8)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"bloodrage",
|
||||
{
|
||||
NextAction("bloodrage", ACTION_HIGH + 2)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"sunder armor",
|
||||
{
|
||||
NextAction("devastate", ACTION_HIGH + 2)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"medium rage available",
|
||||
{
|
||||
NextAction("shield slam", ACTION_HIGH + 2),
|
||||
NextAction("devastate", ACTION_HIGH + 1)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"shield block",
|
||||
{
|
||||
NextAction("shield block", ACTION_INTERRUPT + 1)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"revenge",
|
||||
{
|
||||
NextAction("revenge", ACTION_HIGH + 2)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"disarm",
|
||||
{
|
||||
NextAction("disarm", ACTION_HIGH + 1)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"lose aggro",
|
||||
{
|
||||
NextAction("taunt", ACTION_INTERRUPT + 1)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"taunt on snare target",
|
||||
{
|
||||
NextAction("heroic throw on snare target", ACTION_INTERRUPT)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"low health",
|
||||
{
|
||||
NextAction("shield wall", ACTION_MEDIUM_HEAL)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"critical health",
|
||||
{
|
||||
NextAction("last stand", ACTION_EMERGENCY + 3),
|
||||
NextAction("enraged regeneration", ACTION_EMERGENCY + 2)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"high aoe",
|
||||
{
|
||||
NextAction("challenging shout", ACTION_HIGH + 3)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"concussion blow",
|
||||
{
|
||||
NextAction("concussion blow", ACTION_INTERRUPT)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"shield bash",
|
||||
{
|
||||
NextAction("shield bash", ACTION_INTERRUPT)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"shield bash on enemy healer",
|
||||
{
|
||||
NextAction("shield bash on enemy healer", ACTION_INTERRUPT)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"spell reflection",
|
||||
{
|
||||
NextAction("spell reflection", ACTION_INTERRUPT + 1)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"victory rush",
|
||||
{
|
||||
NextAction("victory rush", ACTION_INTERRUPT)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"sword and board",
|
||||
{
|
||||
NextAction("shield slam", ACTION_INTERRUPT)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"rend",
|
||||
{
|
||||
NextAction("rend", ACTION_NORMAL + 1)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"rend on attacker",
|
||||
{
|
||||
NextAction("rend on attacker", ACTION_NORMAL + 1)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"protect party member",
|
||||
{
|
||||
NextAction("intervene", ACTION_EMERGENCY)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"high rage available",
|
||||
{
|
||||
NextAction("heroic strike", ACTION_HIGH)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"medium rage available",
|
||||
{
|
||||
NextAction("thunder clap", ACTION_HIGH + 1)
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
#ifndef _PLAYERBOT_WOTLKDUNGEONACTIONCONTEXT_H
|
||||
#define _PLAYERBOT_WOTLKDUNGEONACTIONCONTEXT_H
|
||||
|
||||
#include "UtgardeKeep/UtgardeKeepActionContext.h"
|
||||
#include "Nexus/NexusActionContext.h"
|
||||
#include "AzjolNerub/AzjolNerubActionContext.h"
|
||||
#include "OldKingdom/OldKingdomActionContext.h"
|
||||
#include "DraktharonKeep/DrakTharonKeepActionContext.h"
|
||||
#include "VioletHold/VioletHoldActionContext.h"
|
||||
#include "Gundrak/GundrakActionContext.h"
|
||||
#include "HallsOfStone/HallsOfStoneActionContext.h"
|
||||
#include "HallsOfLightning/HallsOfLightningActionContext.h"
|
||||
#include "Oculus/OculusActionContext.h"
|
||||
#include "UtgardePinnacle/UtgardePinnacleActionContext.h"
|
||||
#include "CullingOfStratholme/CullingOfStratholmeActionContext.h"
|
||||
#include "ForgeOfSouls/ForgeOfSoulsActionContext.h"
|
||||
#include "PitOfSaron/PitOfSaronActionContext.h"
|
||||
#include "TrialOfTheChampion/TrialOfTheChampionActionContext.h"
|
||||
// #include "HallsOfReflection/HallsOfReflectionActionContext.h"
|
||||
|
||||
#endif
|
||||
@@ -1,21 +0,0 @@
|
||||
#ifndef _PLAYERBOT_WOTLKDUNGEONTRIGGERCONTEXT_H
|
||||
#define _PLAYERBOT_WOTLKDUNGEONTRIGGERCONTEXT_H
|
||||
|
||||
#include "UtgardeKeep/UtgardeKeepTriggerContext.h"
|
||||
#include "Nexus/NexusTriggerContext.h"
|
||||
#include "AzjolNerub/AzjolNerubTriggerContext.h"
|
||||
#include "OldKingdom/OldKingdomTriggerContext.h"
|
||||
#include "DraktharonKeep/DrakTharonKeepTriggerContext.h"
|
||||
#include "VioletHold/VioletHoldTriggerContext.h"
|
||||
#include "Gundrak/GundrakTriggerContext.h"
|
||||
#include "HallsOfStone/HallsOfStoneTriggerContext.h"
|
||||
#include "HallsOfLightning/HallsOfLightningTriggerContext.h"
|
||||
#include "Oculus/OculusTriggerContext.h"
|
||||
#include "UtgardePinnacle/UtgardePinnacleTriggerContext.h"
|
||||
#include "CullingOfStratholme/CullingOfStratholmeTriggerContext.h"
|
||||
#include "ForgeOfSouls/ForgeOfSoulsTriggerContext.h"
|
||||
#include "PitOfSaron/PitOfSaronTriggerContext.h"
|
||||
#include "TrialOfTheChampion/TrialOfTheChampionTriggerContext.h"
|
||||
// #include "HallsOfReflection/HallsOfReflectionTriggerContext.h"
|
||||
|
||||
#endif
|
||||
@@ -1,15 +0,0 @@
|
||||
#include "RaidBwlStrategy.h"
|
||||
|
||||
#include "Strategy.h"
|
||||
|
||||
void RaidBwlStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(new TriggerNode("often",
|
||||
{ NextAction("bwl check onyxia scale cloak", ACTION_RAID) }));
|
||||
|
||||
triggers.push_back(new TriggerNode("bwl suppression device",
|
||||
{ NextAction("bwl turn off suppression device", ACTION_RAID) }));
|
||||
|
||||
triggers.push_back(new TriggerNode("bwl affliction bronze",
|
||||
{ NextAction("bwl use hourglass sand", ACTION_RAID) }));
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
#include "RaidEoEStrategy.h"
|
||||
#include "RaidEoEMultipliers.h"
|
||||
#include "Strategy.h"
|
||||
|
||||
void RaidEoEStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(new TriggerNode("malygos",
|
||||
{ NextAction("malygos position", ACTION_MOVE) }));
|
||||
triggers.push_back(new TriggerNode("malygos",
|
||||
{ NextAction("malygos target", ACTION_RAID + 1) }));
|
||||
|
||||
triggers.push_back(new TriggerNode("group flying",
|
||||
{ NextAction("eoe fly drake", ACTION_NORMAL + 1) }));
|
||||
triggers.push_back(new TriggerNode("drake combat",
|
||||
{ NextAction("eoe drake attack", ACTION_NORMAL + 5) }));
|
||||
}
|
||||
|
||||
void RaidEoEStrategy::InitMultipliers(std::vector<Multiplier*> &multipliers)
|
||||
{
|
||||
multipliers.push_back(new MalygosMultiplier(botAI));
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
#include "RaidGruulsLairStrategy.h"
|
||||
#include "RaidGruulsLairMultipliers.h"
|
||||
|
||||
void RaidGruulsLairStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
// High King Maulgar
|
||||
triggers.push_back(new TriggerNode("high king maulgar is main tank", {
|
||||
NextAction("high king maulgar main tank attack maulgar", ACTION_RAID + 1) }));
|
||||
|
||||
triggers.push_back(new TriggerNode("high king maulgar is first assist tank", {
|
||||
NextAction("high king maulgar first assist tank attack olm", ACTION_RAID + 1) }));
|
||||
|
||||
triggers.push_back(new TriggerNode("high king maulgar is second assist tank", {
|
||||
NextAction("high king maulgar second assist tank attack blindeye", ACTION_RAID + 1) }));
|
||||
|
||||
triggers.push_back(new TriggerNode("high king maulgar is mage tank", {
|
||||
NextAction("high king maulgar mage tank attack krosh", ACTION_RAID + 1) }));
|
||||
|
||||
triggers.push_back(new TriggerNode("high king maulgar is moonkin tank", {
|
||||
NextAction("high king maulgar moonkin tank attack kiggler", ACTION_RAID + 1) }));
|
||||
|
||||
triggers.push_back(new TriggerNode("high king maulgar determining kill order", {
|
||||
NextAction("high king maulgar assign dps priority", ACTION_RAID + 1) }));
|
||||
|
||||
triggers.push_back(new TriggerNode("high king maulgar healer in danger", {
|
||||
NextAction("high king maulgar healer find safe position", ACTION_RAID + 1) }));
|
||||
|
||||
triggers.push_back(new TriggerNode("high king maulgar boss channeling whirlwind", {
|
||||
NextAction("high king maulgar run away from whirlwind", ACTION_EMERGENCY + 6) }));
|
||||
|
||||
triggers.push_back(new TriggerNode("high king maulgar wild felstalker spawned", {
|
||||
NextAction("high king maulgar banish felstalker", ACTION_RAID + 2) }));
|
||||
|
||||
triggers.push_back(new TriggerNode("high king maulgar pulling olm and blindeye", {
|
||||
NextAction("high king maulgar misdirect olm and blindeye", ACTION_RAID + 2) }));
|
||||
|
||||
// Gruul the Dragonkiller
|
||||
triggers.push_back(new TriggerNode("gruul the dragonkiller boss engaged by main tank", {
|
||||
NextAction("gruul the dragonkiller main tank position boss", ACTION_RAID + 1) }));
|
||||
|
||||
triggers.push_back(new TriggerNode("gruul the dragonkiller boss engaged by range", {
|
||||
NextAction("gruul the dragonkiller spread ranged", ACTION_RAID + 1) }));
|
||||
|
||||
triggers.push_back(new TriggerNode("gruul the dragonkiller incoming shatter", {
|
||||
NextAction("gruul the dragonkiller shatter spread", ACTION_EMERGENCY + 6) }));
|
||||
}
|
||||
|
||||
void RaidGruulsLairStrategy::InitMultipliers(std::vector<Multiplier*>& multipliers)
|
||||
{
|
||||
multipliers.push_back(new HighKingMaulgarDisableTankAssistMultiplier(botAI));
|
||||
multipliers.push_back(new HighKingMaulgarAvoidWhirlwindMultiplier(botAI));
|
||||
multipliers.push_back(new HighKingMaulgarDisableArcaneShotOnKroshMultiplier(botAI));
|
||||
multipliers.push_back(new HighKingMaulgarDisableMageTankAOEMultiplier(botAI));
|
||||
multipliers.push_back(new GruulTheDragonkillerMainTankMovementMultiplier(botAI));
|
||||
multipliers.push_back(new GruulTheDragonkillerGroundSlamMultiplier(botAI));
|
||||
}
|
||||
@@ -1,186 +0,0 @@
|
||||
#include "RaidIccStrategy.h"
|
||||
|
||||
#include "RaidIccMultipliers.h"
|
||||
|
||||
void RaidIccStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
//Lord Marrogwar
|
||||
triggers.push_back(new TriggerNode("icc lm",
|
||||
{ NextAction("icc lm tank position", ACTION_RAID + 5),
|
||||
NextAction("icc spike", ACTION_RAID + 3) }));
|
||||
|
||||
//Lady Deathwhisper
|
||||
triggers.push_back(new TriggerNode("icc dark reckoning",
|
||||
{ NextAction("icc dark reckoning", ACTION_MOVE + 5) }));
|
||||
|
||||
triggers.push_back(new TriggerNode("icc lady deathwhisper",
|
||||
{ NextAction("icc ranged position lady deathwhisper", ACTION_MOVE + 2),
|
||||
NextAction("icc adds lady deathwhisper", ACTION_RAID + 3),
|
||||
NextAction("icc shade lady deathwhisper", ACTION_RAID + 4) }));
|
||||
|
||||
//Gunship Battle
|
||||
triggers.push_back(new TriggerNode("icc rotting frost giant tank position",
|
||||
{ NextAction("icc rotting frost giant tank position", ACTION_RAID + 5) }));
|
||||
|
||||
triggers.push_back(new TriggerNode("icc gunship cannon near",
|
||||
{ NextAction("icc gunship enter cannon", ACTION_RAID + 6) }));
|
||||
|
||||
triggers.push_back( new TriggerNode("icc in cannon",
|
||||
{ NextAction("icc cannon fire", ACTION_RAID+5) }));
|
||||
|
||||
triggers.push_back(new TriggerNode("icc gunship teleport ally",
|
||||
{ NextAction("icc gunship teleport ally", ACTION_RAID + 4) }));
|
||||
|
||||
triggers.push_back(new TriggerNode("icc gunship teleport horde",
|
||||
{ NextAction("icc gunship teleport horde", ACTION_RAID + 4) }));
|
||||
|
||||
//DBS
|
||||
triggers.push_back(new TriggerNode("icc dbs",
|
||||
{ NextAction("icc dbs tank position", ACTION_RAID + 3),
|
||||
NextAction("icc adds dbs", ACTION_RAID + 5) }));
|
||||
|
||||
triggers.push_back(new TriggerNode("icc dbs main tank rune of blood",
|
||||
{ NextAction("taunt spell", ACTION_EMERGENCY + 4) }));
|
||||
|
||||
//DOGS
|
||||
triggers.push_back(new TriggerNode("icc stinky precious main tank mortal wound",
|
||||
{ NextAction("taunt spell", ACTION_EMERGENCY + 4) }));
|
||||
|
||||
//FESTERGUT
|
||||
triggers.push_back(new TriggerNode("icc festergut group position",
|
||||
{ NextAction("icc festergut group position", ACTION_MOVE + 4) }));
|
||||
|
||||
triggers.push_back(new TriggerNode("icc festergut main tank gastric bloat",
|
||||
{ NextAction("taunt spell", ACTION_EMERGENCY + 6) }));
|
||||
|
||||
triggers.push_back(new TriggerNode("icc festergut spore",
|
||||
{ NextAction("icc festergut spore", ACTION_MOVE + 5) }));
|
||||
|
||||
//ROTFACE
|
||||
triggers.push_back(new TriggerNode("icc rotface tank position",
|
||||
{ NextAction("icc rotface tank position", ACTION_RAID + 5) }));
|
||||
|
||||
triggers.push_back(new TriggerNode("icc rotface group position",
|
||||
{ NextAction("icc rotface group position", ACTION_RAID + 6) }));
|
||||
|
||||
triggers.push_back(new TriggerNode("icc rotface move away from explosion",
|
||||
{ NextAction("icc rotface move away from explosion", ACTION_RAID +7) }));
|
||||
|
||||
//PP
|
||||
triggers.push_back(new TriggerNode("icc putricide volatile ooze",
|
||||
{ NextAction("icc putricide volatile ooze", ACTION_RAID + 4) }));
|
||||
|
||||
triggers.push_back(new TriggerNode("icc putricide gas cloud",
|
||||
{ NextAction("icc putricide gas cloud", ACTION_RAID + 5) }));
|
||||
|
||||
triggers.push_back(new TriggerNode("icc putricide growing ooze puddle",
|
||||
{ NextAction("icc putricide growing ooze puddle", ACTION_RAID + 3) }));
|
||||
|
||||
triggers.push_back(new TriggerNode("icc putricide main tank mutated plague",
|
||||
{ NextAction("taunt spell", ACTION_RAID + 10) }));
|
||||
|
||||
triggers.push_back(new TriggerNode("icc putricide malleable goo",
|
||||
{ NextAction("icc putricide avoid malleable goo", ACTION_RAID + 2) }));
|
||||
|
||||
//BPC
|
||||
triggers.push_back(new TriggerNode("icc bpc keleseth tank",
|
||||
{ NextAction("icc bpc keleseth tank", ACTION_RAID + 1) }));
|
||||
|
||||
triggers.push_back(new TriggerNode("icc bpc main tank",
|
||||
{ NextAction("icc bpc main tank", ACTION_RAID + 3) }));
|
||||
|
||||
triggers.push_back(new TriggerNode("icc bpc empowered vortex",
|
||||
{ NextAction("icc bpc empowered vortex", ACTION_RAID + 4) }));
|
||||
|
||||
triggers.push_back(new TriggerNode("icc bpc kinetic bomb",
|
||||
{ NextAction("icc bpc kinetic bomb", ACTION_RAID + 6) }));
|
||||
|
||||
triggers.push_back(new TriggerNode("icc bpc ball of flame",
|
||||
{ NextAction("icc bpc ball of flame", ACTION_RAID + 7) }));
|
||||
|
||||
//BQL
|
||||
triggers.push_back(new TriggerNode("icc bql group position",
|
||||
{ NextAction("icc bql group position", ACTION_RAID) }));
|
||||
|
||||
triggers.push_back(new TriggerNode("icc bql pact of darkfallen",
|
||||
{ NextAction("icc bql pact of darkfallen", ACTION_RAID +1) }));
|
||||
|
||||
triggers.push_back(new TriggerNode("icc bql vampiric bite",
|
||||
{ NextAction("icc bql vampiric bite", ACTION_EMERGENCY + 5) }));
|
||||
|
||||
//Sister Svalna
|
||||
triggers.push_back(new TriggerNode("icc valkyre spear",
|
||||
{ NextAction("icc valkyre spear", ACTION_EMERGENCY + 5) }));
|
||||
|
||||
triggers.push_back(new TriggerNode("icc sister svalna",
|
||||
{ NextAction("icc sister svalna", ACTION_RAID + 5) }));
|
||||
|
||||
//VDW
|
||||
triggers.push_back(new TriggerNode("icc valithria group",
|
||||
{ NextAction("icc valithria group", ACTION_RAID + 1) }));
|
||||
|
||||
triggers.push_back(new TriggerNode("icc valithria portal",
|
||||
{ NextAction("icc valithria portal", ACTION_RAID + 5) }));
|
||||
|
||||
triggers.push_back(new TriggerNode("icc valithria heal",
|
||||
{ NextAction("icc valithria heal", ACTION_RAID+2) }));
|
||||
|
||||
triggers.push_back(new TriggerNode("icc valithria dream cloud",
|
||||
{ NextAction("icc valithria dream cloud", ACTION_RAID + 4) }));
|
||||
|
||||
//SINDRAGOSA
|
||||
triggers.push_back(new TriggerNode("icc sindragosa group position",
|
||||
{ NextAction("icc sindragosa group position", ACTION_RAID + 1) }));
|
||||
|
||||
triggers.push_back(new TriggerNode("icc sindragosa frost beacon",
|
||||
{ NextAction("icc sindragosa frost beacon", ACTION_RAID + 5) }));
|
||||
|
||||
triggers.push_back(new TriggerNode("icc sindragosa blistering cold",
|
||||
{ NextAction("icc sindragosa blistering cold", ACTION_EMERGENCY + 4) }));
|
||||
|
||||
triggers.push_back(new TriggerNode("icc sindragosa unchained magic",
|
||||
{ NextAction("icc sindragosa unchained magic", ACTION_RAID + 2) }));
|
||||
|
||||
triggers.push_back(new TriggerNode("icc sindragosa chilled to the bone",
|
||||
{ NextAction("icc sindragosa chilled to the bone", ACTION_RAID + 2) }));
|
||||
|
||||
triggers.push_back(new TriggerNode("icc sindragosa mystic buffet",
|
||||
{ NextAction("icc sindragosa mystic buffet", ACTION_RAID + 3) }));
|
||||
|
||||
triggers.push_back(new TriggerNode("icc sindragosa main tank mystic buffet",
|
||||
{ NextAction("taunt spell", ACTION_EMERGENCY + 3) }));
|
||||
|
||||
triggers.push_back(new TriggerNode("icc sindragosa frost bomb",
|
||||
{ NextAction("icc sindragosa frost bomb", ACTION_RAID + 7) }));
|
||||
|
||||
triggers.push_back(new TriggerNode("icc sindragosa tank swap position",
|
||||
{ NextAction("icc sindragosa tank swap position", ACTION_EMERGENCY + 2) }));
|
||||
|
||||
//LICH KING
|
||||
triggers.push_back(new TriggerNode("icc lich king shadow trap",
|
||||
{ NextAction("icc lich king shadow trap", ACTION_RAID + 6) }));
|
||||
|
||||
triggers.push_back(new TriggerNode("icc lich king necrotic plague",
|
||||
{ NextAction("icc lich king necrotic plague", ACTION_RAID + 3) }));
|
||||
|
||||
triggers.push_back(new TriggerNode("icc lich king winter",
|
||||
{ NextAction("icc lich king winter", ACTION_RAID +5) }));
|
||||
|
||||
triggers.push_back(new TriggerNode("icc lich king adds",
|
||||
{ NextAction("icc lich king adds", ACTION_RAID +2) }));
|
||||
}
|
||||
|
||||
void RaidIccStrategy::InitMultipliers(std::vector<Multiplier*>& multipliers)
|
||||
{
|
||||
multipliers.push_back(new IccLadyDeathwhisperMultiplier(botAI));
|
||||
multipliers.push_back(new IccAddsDbsMultiplier(botAI));
|
||||
multipliers.push_back(new IccDogsMultiplier(botAI));
|
||||
multipliers.push_back(new IccFestergutMultiplier(botAI));
|
||||
multipliers.push_back(new IccRotfaceMultiplier(botAI));
|
||||
multipliers.push_back(new IccAddsPutricideMultiplier(botAI));
|
||||
multipliers.push_back(new IccBpcAssistMultiplier(botAI));
|
||||
multipliers.push_back(new IccBqlMultiplier(botAI));
|
||||
multipliers.push_back(new IccValithriaDreamCloudMultiplier(botAI));
|
||||
multipliers.push_back(new IccSindragosaMultiplier(botAI));
|
||||
multipliers.push_back(new IccLichKingAddsMultiplier(botAI));
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
#include "RaidMagtheridonStrategy.h"
|
||||
#include "RaidMagtheridonMultipliers.h"
|
||||
|
||||
void RaidMagtheridonStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(new TriggerNode("magtheridon incoming blast nova", {
|
||||
NextAction("magtheridon use manticron cube", ACTION_EMERGENCY + 10) }));
|
||||
|
||||
triggers.push_back(new TriggerNode("magtheridon need to manage timers and assignments", {
|
||||
NextAction("magtheridon manage timers and assignments", ACTION_EMERGENCY + 1) }));
|
||||
|
||||
triggers.push_back(new TriggerNode("magtheridon burning abyssal spawned", {
|
||||
NextAction("magtheridon warlock cc burning abyssal", ACTION_RAID + 3) }));
|
||||
|
||||
triggers.push_back(new TriggerNode("magtheridon boss engaged by ranged", {
|
||||
NextAction("magtheridon spread ranged", ACTION_RAID + 2) }));
|
||||
|
||||
triggers.push_back(new TriggerNode("magtheridon pulling west and east channelers", {
|
||||
NextAction("magtheridon misdirect hellfire channelers", ACTION_RAID + 2) }));
|
||||
|
||||
triggers.push_back(new TriggerNode("magtheridon boss engaged by main tank", {
|
||||
NextAction("magtheridon main tank position boss", ACTION_RAID + 2) }));
|
||||
|
||||
triggers.push_back(new TriggerNode("magtheridon first three channelers engaged by main tank", {
|
||||
NextAction("magtheridon main tank attack first three channelers", ACTION_RAID + 1) }));
|
||||
|
||||
triggers.push_back(new TriggerNode("magtheridon nw channeler engaged by first assist tank", {
|
||||
NextAction("magtheridon first assist tank attack nw channeler", ACTION_RAID + 1) }));
|
||||
|
||||
triggers.push_back(new TriggerNode("magtheridon ne channeler engaged by second assist tank", {
|
||||
NextAction("magtheridon second assist tank attack ne channeler", ACTION_RAID + 1) }));
|
||||
|
||||
triggers.push_back(new TriggerNode("magtheridon determining kill order", {
|
||||
NextAction("magtheridon assign dps priority", ACTION_RAID + 1) }));
|
||||
}
|
||||
|
||||
void RaidMagtheridonStrategy::InitMultipliers(std::vector<Multiplier*>& multipliers)
|
||||
{
|
||||
multipliers.push_back(new MagtheridonUseManticronCubeMultiplier(botAI));
|
||||
multipliers.push_back(new MagtheridonWaitToAttackMultiplier(botAI));
|
||||
multipliers.push_back(new MagtheridonDisableOffTankAssistMultiplier(botAI));
|
||||
}
|
||||
@@ -1,323 +0,0 @@
|
||||
#include "RaidUlduarStrategy.h"
|
||||
|
||||
#include "RaidUlduarMultipliers.h"
|
||||
|
||||
void RaidUlduarStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
//
|
||||
// Flame Leviathan
|
||||
//
|
||||
triggers.push_back(new TriggerNode(
|
||||
"flame leviathan vehicle near",
|
||||
{ NextAction("flame leviathan enter vehicle", ACTION_RAID + 2) }));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"flame leviathan on vehicle",
|
||||
{ NextAction("flame leviathan vehicle", ACTION_RAID + 1) }));
|
||||
|
||||
//
|
||||
// Razorscale
|
||||
//
|
||||
triggers.push_back(new TriggerNode(
|
||||
"razorscale avoid devouring flames",
|
||||
{ NextAction("razorscale avoid devouring flames", ACTION_RAID + 1) }));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"razorscale avoid sentinel",
|
||||
{ NextAction("razorscale avoid sentinel", ACTION_RAID + 2) }));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"razorscale flying alone",
|
||||
{ NextAction("razorscale ignore flying alone", ACTION_MOVE + 5) }));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"razorscale avoid whirlwind",
|
||||
{ NextAction("razorscale avoid whirlwind", ACTION_RAID + 3) }));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"razorscale grounded",
|
||||
{ NextAction("razorscale grounded", ACTION_RAID) }));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"razorscale harpoon trigger",
|
||||
{ NextAction("razorscale harpoon action", ACTION_MOVE) }));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"razorscale fuse armor trigger",
|
||||
{ NextAction("razorscale fuse armor action", ACTION_RAID + 2) }));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"razorscale fire resistance trigger",
|
||||
{ NextAction("razorscale fire resistance action", ACTION_RAID) }));
|
||||
|
||||
//
|
||||
// Ignis
|
||||
//
|
||||
triggers.push_back(new TriggerNode(
|
||||
"ignis fire resistance trigger",
|
||||
{ NextAction("ignis fire resistance action", ACTION_RAID) }));
|
||||
|
||||
//
|
||||
// Iron Assembly
|
||||
//
|
||||
triggers.push_back(new TriggerNode(
|
||||
"iron assembly lightning tendrils trigger",
|
||||
{ NextAction("iron assembly lightning tendrils action", ACTION_RAID) }));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"iron assembly overload trigger",
|
||||
{ NextAction("iron assembly overload action", ACTION_RAID) }));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"iron assembly rune of power trigger",
|
||||
{ NextAction("iron assembly rune of power action", ACTION_RAID) }));
|
||||
|
||||
//
|
||||
// Kologarn
|
||||
//
|
||||
triggers.push_back(new TriggerNode(
|
||||
"kologarn fall from floor trigger",
|
||||
{ NextAction("kologarn fall from floor action", ACTION_RAID + 1) }));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"kologarn rti target trigger",
|
||||
{ NextAction("kologarn rti target action", ACTION_RAID + 1) }));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"kologarn eyebeam trigger",
|
||||
{ NextAction("kologarn eyebeam action", ACTION_RAID + 1) }));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"kologarn attack dps target trigger",
|
||||
{ NextAction("attack rti target", ACTION_RAID) }));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"kologarn mark dps target trigger",
|
||||
{ NextAction("kologarn mark dps target action", ACTION_RAID) }));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"kologarn nature resistance trigger",
|
||||
{ NextAction("kologarn nature resistance action", ACTION_RAID) }));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"kologarn rubble slowdown trigger",
|
||||
{ NextAction("kologarn rubble slowdown action", ACTION_RAID) }));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"kologarn crunch armor trigger",
|
||||
{ NextAction("kologarn crunch armor action", ACTION_RAID) }));
|
||||
|
||||
//
|
||||
// Auriaya
|
||||
//
|
||||
triggers.push_back(new TriggerNode(
|
||||
"auriaya fall from floor trigger",
|
||||
{ NextAction("auriaya fall from floor action", ACTION_RAID) }));
|
||||
|
||||
//
|
||||
// Hodir
|
||||
//
|
||||
triggers.push_back(new TriggerNode(
|
||||
"hodir near snowpacked icicle",
|
||||
{ NextAction("hodir move snowpacked icicle", ACTION_RAID + 1) }));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"hodir biting cold",
|
||||
{ NextAction("hodir biting cold jump", ACTION_RAID) }));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"hodir frost resistance trigger",
|
||||
{ NextAction("hodir frost resistance action", ACTION_RAID) }));
|
||||
|
||||
//
|
||||
// Freya
|
||||
//
|
||||
triggers.push_back(new TriggerNode(
|
||||
"freya near nature bomb",
|
||||
{ NextAction("freya move away nature bomb", ACTION_RAID) }));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"freya nature resistance trigger",
|
||||
{ NextAction("freya nature resistance action", ACTION_RAID) }));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"freya fire resistance trigger",
|
||||
{ NextAction("freya fire resistance action", ACTION_RAID) }));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"freya mark dps target trigger",
|
||||
{ NextAction("freya mark dps target action", ACTION_RAID) }));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"freya move to healing spore trigger",
|
||||
{ NextAction("freya move to healing spore action", ACTION_RAID) }));
|
||||
|
||||
//
|
||||
// Thorim
|
||||
//
|
||||
triggers.push_back(new TriggerNode(
|
||||
"thorim nature resistance trigger",
|
||||
{ NextAction("thorim nature resistance action", ACTION_RAID) }));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"thorim frost resistance trigger",
|
||||
{ NextAction("thorim frost resistance action", ACTION_RAID) }));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"thorim unbalancing strike trigger",
|
||||
{ NextAction("thorim unbalancing strike action", ACTION_RAID) }));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"thorim mark dps target trigger",
|
||||
{ NextAction("thorim mark dps target action", ACTION_RAID) }));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"thorim gauntlet positioning trigger",
|
||||
{ NextAction("thorim gauntlet positioning action", ACTION_RAID) }));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"thorim arena positioning trigger",
|
||||
{ NextAction("thorim arena positioning action", ACTION_RAID) }));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"thorim fall from floor trigger",
|
||||
{ NextAction("thorim fall from floor action", ACTION_RAID + 1) }));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"thorim phase 2 positioning trigger",
|
||||
{ NextAction("thorim phase 2 positioning action", ACTION_RAID) }));
|
||||
|
||||
//
|
||||
// Mimiron
|
||||
//
|
||||
triggers.push_back(new TriggerNode(
|
||||
"mimiron p3wx2 laser barrage trigger",
|
||||
{ NextAction("mimiron p3wx2 laser barrage action", ACTION_RAID + 2) }));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"mimiron shock blast trigger",
|
||||
{ NextAction("mimiron shock blast action", ACTION_RAID + 1) }));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"mimiron fire resistance trigger",
|
||||
{ NextAction("mimiron fire resistance action", ACTION_RAID) }));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"mimiron phase 1 positioning trigger",
|
||||
{ NextAction("mimiron phase 1 positioning action", ACTION_RAID) }));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"mimiron rapid burst trigger",
|
||||
{ NextAction("mimiron rapid burst action", ACTION_RAID) }));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"mimiron aerial command unit trigger",
|
||||
{ NextAction("mimiron aerial command unit action", ACTION_RAID) }));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"mimiron rocket strike trigger",
|
||||
{ NextAction("mimiron rocket strike action", ACTION_RAID) }));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"mimiron phase 4 mark dps trigger",
|
||||
{ NextAction("mimiron phase 4 mark dps action", ACTION_RAID) }));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"mimiron cheat trigger",
|
||||
{ NextAction("mimiron cheat action", ACTION_RAID) }));
|
||||
|
||||
//
|
||||
// General Vezax
|
||||
//
|
||||
triggers.push_back(new TriggerNode(
|
||||
"vezax cheat trigger",
|
||||
{ NextAction("vezax cheat action", ACTION_RAID) }));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"vezax shadow crash trigger",
|
||||
{ NextAction("vezax shadow crash action", ACTION_RAID) }));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"vezax mark of the faceless trigger",
|
||||
{ NextAction("vezax mark of the faceless action", ACTION_RAID) }));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"vezax shadow resistance trigger",
|
||||
{ NextAction("vezax shadow resistance action", ACTION_RAID) }));
|
||||
|
||||
//
|
||||
// Yogg-Saron
|
||||
//
|
||||
triggers.push_back(new TriggerNode(
|
||||
"sara shadow resistance trigger",
|
||||
{ NextAction("sara shadow resistance action", ACTION_RAID) }));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"yogg-saron shadow resistance trigger",
|
||||
{ NextAction("yogg-saron shadow resistance action", ACTION_RAID) }));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"yogg-saron ominous cloud cheat trigger",
|
||||
{ NextAction("yogg-saron ominous cloud cheat action", ACTION_RAID) }));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"yogg-saron guardian positioning trigger",
|
||||
{ NextAction("yogg-saron guardian positioning action", ACTION_RAID) }));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"yogg-saron sanity trigger",
|
||||
{ NextAction("yogg-saron sanity action", ACTION_RAID + 1) }));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"yogg-saron death orb trigger",
|
||||
{ NextAction("yogg-saron death orb action", ACTION_RAID) }));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"yogg-saron malady of the mind trigger",
|
||||
{ NextAction("yogg-saron malady of the mind action", ACTION_RAID) }));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"yogg-saron mark target trigger",
|
||||
{ NextAction("yogg-saron mark target action", ACTION_RAID) }));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"yogg-saron brain link trigger",
|
||||
{ NextAction("yogg-saron brain link action", ACTION_RAID) }));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"yogg-saron move to enter portal trigger",
|
||||
{ NextAction("yogg-saron move to enter portal action", ACTION_RAID) }));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"yogg-saron use portal trigger",
|
||||
{ NextAction("yogg-saron use portal action", ACTION_RAID) }));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"yogg-saron fall from floor trigger",
|
||||
{ NextAction("yogg-saron fall from floor action", ACTION_RAID) }));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"yogg-saron boss room movement cheat trigger",
|
||||
{ NextAction("yogg-saron boss room movement cheat action", ACTION_RAID) }));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"yogg-saron illusion room trigger",
|
||||
{ NextAction("yogg-saron illusion room action", ACTION_RAID) }));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"yogg-saron move to exit portal trigger",
|
||||
{ NextAction("yogg-saron move to exit portal action", ACTION_RAID) }));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"yogg-saron lunatic gaze trigger",
|
||||
{ NextAction("yogg-saron lunatic gaze action", ACTION_EMERGENCY) }));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"yogg-saron phase 3 positioning trigger",
|
||||
{ NextAction("yogg-saron phase 3 positioning action", ACTION_RAID) }));
|
||||
}
|
||||
|
||||
void RaidUlduarStrategy::InitMultipliers(std::vector<Multiplier*>& multipliers)
|
||||
{
|
||||
multipliers.push_back(new FlameLeviathanMultiplier(botAI));
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "NewRpgStrategy.h"
|
||||
|
||||
#include "Playerbots.h"
|
||||
|
||||
NewRpgStrategy::NewRpgStrategy(PlayerbotAI* botAI) : Strategy(botAI) {}
|
||||
|
||||
std::vector<NextAction> NewRpgStrategy::getDefaultActions()
|
||||
{
|
||||
// the releavance should be greater than grind
|
||||
return {
|
||||
NextAction("new rpg status update", 11.0f)
|
||||
};
|
||||
}
|
||||
|
||||
void NewRpgStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"go grind status",
|
||||
{
|
||||
NextAction("new rpg go grind", 3.0f)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"go camp status",
|
||||
{
|
||||
NextAction("new rpg go camp", 3.0f)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"wander random status",
|
||||
{
|
||||
NextAction("new rpg wander random", 3.0f)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"wander npc status",
|
||||
{
|
||||
NextAction("new rpg wander npc", 3.0f)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"do quest status",
|
||||
{
|
||||
NextAction("new rpg do quest", 3.0f)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"travel flight status",
|
||||
{
|
||||
NextAction("new rpg travel flight", 3.0f)
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
void NewRpgStrategy::InitMultipliers(std::vector<Multiplier*>& multipliers)
|
||||
{
|
||||
|
||||
}
|
||||
@@ -140,37 +140,37 @@ BotRoles AiFactory::GetPlayerRoles(Player* player)
|
||||
switch (player->getClass())
|
||||
{
|
||||
case CLASS_PRIEST:
|
||||
if (tab == PRIEST_TAB_SHADOW)
|
||||
if (tab == 2)
|
||||
role = BOT_ROLE_DPS;
|
||||
else
|
||||
role = BOT_ROLE_HEALER;
|
||||
break;
|
||||
case CLASS_SHAMAN:
|
||||
if (tab == SHAMAN_TAB_RESTORATION)
|
||||
if (tab == 2)
|
||||
role = BOT_ROLE_HEALER;
|
||||
else
|
||||
role = BOT_ROLE_DPS;
|
||||
break;
|
||||
case CLASS_WARRIOR:
|
||||
if (tab == WARRIOR_TAB_PROTECTION)
|
||||
if (tab == 2)
|
||||
role = BOT_ROLE_TANK;
|
||||
else
|
||||
role = BOT_ROLE_DPS;
|
||||
break;
|
||||
case CLASS_PALADIN:
|
||||
if (tab == PALADIN_TAB_HOLY)
|
||||
if (tab == 0)
|
||||
role = BOT_ROLE_HEALER;
|
||||
else if (tab == PALADIN_TAB_PROTECTION)
|
||||
else if (tab == 1)
|
||||
role = BOT_ROLE_TANK;
|
||||
else if (tab == PALADIN_TAB_RETRIBUTION)
|
||||
else if (tab == 2)
|
||||
role = BOT_ROLE_DPS;
|
||||
break;
|
||||
case CLASS_DRUID:
|
||||
if (tab == DRUID_TAB_BALANCE)
|
||||
if (tab == 0)
|
||||
role = BOT_ROLE_DPS;
|
||||
else if (tab == DRUID_TAB_FERAL)
|
||||
else if (tab == 1)
|
||||
role = (BotRoles)(BOT_ROLE_TANK | BOT_ROLE_DPS);
|
||||
else if (tab == DRUID_TAB_RESTORATION)
|
||||
else if (tab == 2)
|
||||
role = BOT_ROLE_HEALER;
|
||||
break;
|
||||
default:
|
||||
@@ -188,83 +188,84 @@ std::string AiFactory::GetPlayerSpecName(Player* player)
|
||||
switch (player->getClass())
|
||||
{
|
||||
case CLASS_PRIEST:
|
||||
if (tab == PRIEST_TAB_SHADOW)
|
||||
if (tab == 2)
|
||||
specName = "shadow";
|
||||
else if (tab == PRIEST_TAB_HOLY)
|
||||
else if (tab == 1)
|
||||
specName = "holy";
|
||||
else
|
||||
specName = "disc";
|
||||
;
|
||||
break;
|
||||
case CLASS_SHAMAN:
|
||||
if (tab == SHAMAN_TAB_RESTORATION)
|
||||
if (tab == 2)
|
||||
specName = "resto";
|
||||
else if (tab == SHAMAN_TAB_ENHANCEMENT)
|
||||
else if (tab == 1)
|
||||
specName = "enhance";
|
||||
else
|
||||
specName = "elem";
|
||||
break;
|
||||
case CLASS_WARRIOR:
|
||||
if (tab == WARRIOR_TAB_PROTECTION)
|
||||
if (tab == 2)
|
||||
specName = "prot";
|
||||
else if (tab == WARRIOR_TAB_FURY)
|
||||
else if (tab == 1)
|
||||
specName = "fury";
|
||||
else
|
||||
specName = "arms";
|
||||
break;
|
||||
case CLASS_PALADIN:
|
||||
if (tab == PALADIN_TAB_HOLY)
|
||||
if (tab == 0)
|
||||
specName = "holy";
|
||||
else if (tab == PALADIN_TAB_PROTECTION)
|
||||
else if (tab == 1)
|
||||
specName = "prot";
|
||||
else if (tab == PALADIN_TAB_RETRIBUTION)
|
||||
else if (tab == 2)
|
||||
specName = "retrib";
|
||||
break;
|
||||
case CLASS_DRUID:
|
||||
if (tab == DRUID_TAB_BALANCE)
|
||||
if (tab == 0)
|
||||
specName = "balance";
|
||||
else if (tab == DRUID_TAB_FERAL)
|
||||
else if (tab == 1)
|
||||
specName = "feraldps";
|
||||
else if (tab == DRUID_TAB_RESTORATION)
|
||||
else if (tab == 2)
|
||||
specName = "resto";
|
||||
break;
|
||||
case CLASS_ROGUE:
|
||||
if (tab == ROGUE_TAB_ASSASSINATION)
|
||||
if (tab == 0)
|
||||
specName = "assas";
|
||||
else if (tab == ROGUE_TAB_COMBAT)
|
||||
else if (tab == 1)
|
||||
specName = "combat";
|
||||
else if (tab == ROGUE_TAB_SUBTLETY)
|
||||
else if (tab == 2)
|
||||
specName = "subtle";
|
||||
break;
|
||||
case CLASS_HUNTER:
|
||||
if (tab == HUNTER_TAB_BEAST_MASTERY)
|
||||
if (tab == 0)
|
||||
specName = "beast";
|
||||
else if (tab == HUNTER_TAB_MARKSMANSHIP)
|
||||
else if (tab == 1)
|
||||
specName = "marks";
|
||||
else if (tab == HUNTER_TAB_SURVIVAL)
|
||||
else if (tab == 2)
|
||||
specName = "surv";
|
||||
break;
|
||||
case CLASS_DEATH_KNIGHT:
|
||||
if (tab == DEATH_KNIGHT_TAB_BLOOD)
|
||||
if (tab == 0)
|
||||
specName = "blooddps";
|
||||
else if (tab == DEATH_KNIGHT_TAB_FROST)
|
||||
else if (tab == 1)
|
||||
specName = "frostdps";
|
||||
else if (tab == DEATH_KNIGHT_TAB_UNHOLY)
|
||||
else if (tab == 2)
|
||||
specName = "unholydps";
|
||||
break;
|
||||
case CLASS_MAGE:
|
||||
if (tab == MAGE_TAB_ARCANE)
|
||||
if (tab == 0)
|
||||
specName = "arcane";
|
||||
else if (tab == MAGE_TAB_FIRE)
|
||||
else if (tab == 1)
|
||||
specName = "fire";
|
||||
else if (tab == MAGE_TAB_FROST)
|
||||
else if (tab == 2)
|
||||
specName = "frost";
|
||||
break;
|
||||
case CLASS_WARLOCK:
|
||||
if (tab == WARLOCK_TAB_AFFLICTION)
|
||||
if (tab == 0)
|
||||
specName = "afflic";
|
||||
else if (tab == WARLOCK_TAB_DEMONOLOGY)
|
||||
else if (tab == 1)
|
||||
specName = "demo";
|
||||
else if (tab == WARLOCK_TAB_DESTRUCTION)
|
||||
else if (tab == 2)
|
||||
specName = "destro";
|
||||
break;
|
||||
default:
|
||||
@@ -279,124 +280,147 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa
|
||||
uint8 tab = GetPlayerSpecTab(player);
|
||||
|
||||
if (!player->InBattleground())
|
||||
{
|
||||
engine->addStrategiesNoInit("racials", "chat", "default", "cast time", "potions", "duel", "boost", nullptr);
|
||||
|
||||
}
|
||||
if (sPlayerbotAIConfig->autoAvoidAoe && facade->HasRealPlayerMaster())
|
||||
{
|
||||
engine->addStrategy("avoid aoe", false);
|
||||
|
||||
}
|
||||
engine->addStrategy("formation", false);
|
||||
|
||||
switch (player->getClass())
|
||||
{
|
||||
case CLASS_PRIEST:
|
||||
if (tab == PRIEST_TAB_SHADOW)
|
||||
if (tab == 2)
|
||||
{
|
||||
engine->addStrategiesNoInit("dps", "shadow debuff", "shadow aoe", nullptr);
|
||||
}
|
||||
else if (tab == PRIEST_TAB_DISCIPLINE)
|
||||
{
|
||||
engine->addStrategiesNoInit("heal", nullptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
engine->addStrategiesNoInit("holy heal", nullptr);
|
||||
}
|
||||
|
||||
engine->addStrategiesNoInit("dps assist", "cure", nullptr);
|
||||
break;
|
||||
case CLASS_MAGE:
|
||||
if (tab == MAGE_TAB_ARCANE)
|
||||
if (tab == 0) // Arcane
|
||||
engine->addStrategiesNoInit("arcane", nullptr);
|
||||
else if (tab == MAGE_TAB_FIRE)
|
||||
else if (tab == 1) // Fire
|
||||
{
|
||||
if (player->HasSpell(44614) /*Frostfire Bolt*/ && player->HasAura(15047) /*Ice Shards*/)
|
||||
{
|
||||
engine->addStrategiesNoInit("frostfire", nullptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
engine->addStrategiesNoInit("fire", nullptr);
|
||||
}
|
||||
}
|
||||
else
|
||||
else // Frost
|
||||
engine->addStrategiesNoInit("frost", nullptr);
|
||||
|
||||
engine->addStrategiesNoInit("dps", "dps assist", "cure", "aoe", nullptr);
|
||||
break;
|
||||
case CLASS_WARRIOR:
|
||||
if (tab == WARRIOR_TAB_PROTECTION)
|
||||
if (tab == 2)
|
||||
engine->addStrategiesNoInit("tank", "tank assist", "aoe", nullptr);
|
||||
else if (tab == WARRIOR_TAB_ARMS || !player->HasSpell(1680)) // Whirlwind
|
||||
engine->addStrategiesNoInit("arms", "aoe", "dps assist", nullptr);
|
||||
else if (tab == 0 || !player->HasSpell(1680)) // Whirlwind
|
||||
engine->addStrategiesNoInit("arms", "aoe", "dps assist", /*"behind",*/ nullptr);
|
||||
else
|
||||
engine->addStrategiesNoInit("fury", "aoe", "dps assist", nullptr);
|
||||
engine->addStrategiesNoInit("fury", "aoe", "dps assist", /*"behind",*/ nullptr);
|
||||
break;
|
||||
case CLASS_SHAMAN:
|
||||
if (tab == SHAMAN_TAB_ELEMENTAL)
|
||||
if (tab == 0) // Elemental
|
||||
engine->addStrategiesNoInit("ele", "stoneskin", "wrath", "mana spring", "wrath of air", nullptr);
|
||||
else if (tab == SHAMAN_TAB_RESTORATION)
|
||||
else if (tab == 2) // Restoration
|
||||
engine->addStrategiesNoInit("resto", "stoneskin", "flametongue", "mana spring", "wrath of air", nullptr);
|
||||
else
|
||||
else // Enhancement
|
||||
engine->addStrategiesNoInit("enh", "strength of earth", "magma", "healing stream", "windfury", nullptr);
|
||||
|
||||
engine->addStrategiesNoInit("dps assist", "cure", "aoe", nullptr);
|
||||
break;
|
||||
case CLASS_PALADIN:
|
||||
if (tab == PALADIN_TAB_PROTECTION)
|
||||
if (tab == 1)
|
||||
engine->addStrategiesNoInit("tank", "tank assist", "bthreat", "barmor", "cure", nullptr);
|
||||
else if (tab == PALADIN_TAB_HOLY)
|
||||
else if (tab == 0)
|
||||
engine->addStrategiesNoInit("heal", "dps assist", "cure", "bcast", nullptr);
|
||||
else
|
||||
engine->addStrategiesNoInit("dps", "dps assist", "cure", "baoe", nullptr);
|
||||
|
||||
break;
|
||||
case CLASS_DRUID:
|
||||
if (tab == DRUID_TAB_BALANCE)
|
||||
if (tab == 0)
|
||||
{
|
||||
engine->addStrategiesNoInit("caster", "cure", "caster aoe", "dps assist", nullptr);
|
||||
engine->addStrategy("caster debuff", false);
|
||||
}
|
||||
else if (tab == DRUID_TAB_RESTORATION)
|
||||
else if (tab == 2)
|
||||
engine->addStrategiesNoInit("heal", "cure", "dps assist", nullptr);
|
||||
else
|
||||
{
|
||||
if (player->HasSpell(768) /*cat form*/ && !player->HasAura(16931) /*thick hide*/)
|
||||
if (player->HasSpell(768) /*cat form*/&& !player->HasAura(16931) /*thick hide*/)
|
||||
{
|
||||
engine->addStrategiesNoInit("cat", "dps assist", nullptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
engine->addStrategiesNoInit("bear", "tank assist", nullptr);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CLASS_HUNTER:
|
||||
if (tab == HUNTER_TAB_BEAST_MASTERY)
|
||||
if (tab == 0) // Beast Mastery
|
||||
engine->addStrategiesNoInit("bm", nullptr);
|
||||
else if (tab == HUNTER_TAB_MARKSMANSHIP)
|
||||
else if (tab == 1) // Marksmanship
|
||||
engine->addStrategiesNoInit("mm", nullptr);
|
||||
else
|
||||
else if (tab == 2) // Survival
|
||||
engine->addStrategiesNoInit("surv", nullptr);
|
||||
|
||||
engine->addStrategiesNoInit("cc", "dps assist", "aoe", nullptr);
|
||||
break;
|
||||
case CLASS_ROGUE:
|
||||
if (tab == ROGUE_TAB_ASSASSINATION || tab == ROGUE_TAB_SUBTLETY)
|
||||
{
|
||||
engine->addStrategiesNoInit("melee", "dps assist", "aoe", nullptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
engine->addStrategiesNoInit("dps", "dps assist", "aoe", nullptr);
|
||||
}
|
||||
break;
|
||||
case CLASS_WARLOCK:
|
||||
if (tab == WARLOCK_TAB_AFFLICTION)
|
||||
if (tab == 0) // Affliction
|
||||
engine->addStrategiesNoInit("affli", "curse of agony", nullptr);
|
||||
else if (tab == WARLOCK_TAB_DEMONOLOGY)
|
||||
else if (tab == 1) // Demonology
|
||||
engine->addStrategiesNoInit("demo", "curse of agony", "meta melee", nullptr);
|
||||
else
|
||||
else if (tab == 2) // Destruction
|
||||
engine->addStrategiesNoInit("destro", "curse of elements", nullptr);
|
||||
|
||||
engine->addStrategiesNoInit("cc", "dps assist", "aoe", nullptr);
|
||||
break;
|
||||
|
||||
case CLASS_DEATH_KNIGHT:
|
||||
if (tab == DEATH_KNIGHT_TAB_BLOOD)
|
||||
if (tab == 0)
|
||||
engine->addStrategiesNoInit("blood", "tank assist", nullptr);
|
||||
else if (tab == DEATH_KNIGHT_TAB_FROST)
|
||||
else if (tab == 1)
|
||||
engine->addStrategiesNoInit("frost", "frost aoe", "dps assist", nullptr);
|
||||
else
|
||||
engine->addStrategiesNoInit("unholy", "unholy aoe", "dps assist", nullptr);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (PlayerbotAI::IsTank(player, true))
|
||||
{
|
||||
engine->addStrategy("tank face", false);
|
||||
|
||||
}
|
||||
if (PlayerbotAI::IsMelee(player, true) && PlayerbotAI::IsDps(player, true))
|
||||
{
|
||||
engine->addStrategy("behind", false);
|
||||
|
||||
}
|
||||
if (PlayerbotAI::IsHeal(player, true))
|
||||
{
|
||||
if (sPlayerbotAIConfig->autoSaveMana)
|
||||
@@ -404,7 +428,6 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa
|
||||
if (!sPlayerbotAIConfig->IsRestrictedHealerDPSMap(player->GetMapId()))
|
||||
engine->addStrategy("healer dps", false);
|
||||
}
|
||||
|
||||
if (facade->IsRealPlayer() || sRandomPlayerbotMgr->IsRandomBot(player))
|
||||
{
|
||||
if (!player->GetGroup())
|
||||
@@ -413,13 +436,15 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa
|
||||
engine->addStrategy("boost", false);
|
||||
engine->addStrategy("dps assist", false);
|
||||
engine->removeStrategy("threat", false);
|
||||
|
||||
// engine-
|
||||
switch (player->getClass())
|
||||
{
|
||||
case CLASS_PRIEST:
|
||||
{
|
||||
if (tab != PRIEST_TAB_SHADOW)
|
||||
{
|
||||
engine->addStrategiesNoInit("holy dps", "shadow debuff", "shadow aoe", nullptr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CLASS_DRUID:
|
||||
@@ -434,13 +459,17 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa
|
||||
case CLASS_SHAMAN:
|
||||
{
|
||||
if (tab == SHAMAN_TAB_RESTORATION)
|
||||
{
|
||||
engine->addStrategiesNoInit("caster", "caster aoe", "bmana", nullptr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CLASS_PALADIN:
|
||||
{
|
||||
if (tab == PALADIN_TAB_HOLY)
|
||||
{
|
||||
engine->addStrategiesNoInit("dps", "dps assist", "baoe", nullptr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@@ -449,9 +478,13 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa
|
||||
}
|
||||
}
|
||||
if (sRandomPlayerbotMgr->IsRandomBot(player))
|
||||
{
|
||||
engine->ChangeStrategy(sPlayerbotAIConfig->randomBotCombatStrategies);
|
||||
}
|
||||
else
|
||||
{
|
||||
engine->ChangeStrategy(sPlayerbotAIConfig->combatStrategies);
|
||||
}
|
||||
|
||||
// Battleground switch
|
||||
if (player->InBattleground() && player->GetBattleground())
|
||||
@@ -478,15 +511,23 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa
|
||||
if (player->InArena())
|
||||
{
|
||||
engine->addStrategy("arena", false);
|
||||
engine->addStrategiesNoInit("boost", "racials", "chat", "default", "aoe", "cast time", "dps assist", nullptr);
|
||||
}
|
||||
else
|
||||
engine->addStrategiesNoInit("boost", "racials", "chat", "default", "aoe", "potions", "cast time", "dps assist", nullptr);
|
||||
|
||||
engine->addStrategiesNoInit("boost", "racials", "chat", "default", "aoe", "potions", "cast time", "dps assist",
|
||||
nullptr);
|
||||
engine->removeStrategy("custom::say", false);
|
||||
engine->removeStrategy("flee", false);
|
||||
engine->removeStrategy("threat", false);
|
||||
engine->addStrategy("boost", false);
|
||||
|
||||
// if ((player->getClass() == CLASS_DRUID && tab == 2) || (player->getClass() == CLASS_SHAMAN && tab == 2))
|
||||
// engine->addStrategiesNoInit("caster", "caster aoe", nullptr);
|
||||
|
||||
// if (player->getClass() == CLASS_DRUID && tab == 1)
|
||||
// engine->addStrategiesNoInit(/*"behind",*/ "dps", nullptr);
|
||||
|
||||
// if (player->getClass() == CLASS_ROGUE)
|
||||
// engine->addStrategiesNoInit(/*"behind",*/ "stealth", nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -508,15 +549,19 @@ void AiFactory::AddDefaultNonCombatStrategies(Player* player, PlayerbotAI* const
|
||||
nonCombatEngine->addStrategiesNoInit("dps assist", "cure", nullptr);
|
||||
break;
|
||||
case CLASS_PALADIN:
|
||||
if (tab == PALADIN_TAB_PROTECTION)
|
||||
if (tab == 1)
|
||||
{
|
||||
nonCombatEngine->addStrategiesNoInit("bthreat", "tank assist", "barmor", nullptr);
|
||||
if (player->GetLevel() >= 20)
|
||||
{
|
||||
nonCombatEngine->addStrategy("bhealth", false);
|
||||
}
|
||||
else
|
||||
{
|
||||
nonCombatEngine->addStrategy("bdps", false);
|
||||
}
|
||||
}
|
||||
else if (tab == PALADIN_TAB_HOLY)
|
||||
else if (tab == 0)
|
||||
nonCombatEngine->addStrategiesNoInit("dps assist", "bmana", "bcast", nullptr);
|
||||
else
|
||||
nonCombatEngine->addStrategiesNoInit("dps assist", "bdps", "baoe", nullptr);
|
||||
@@ -527,7 +572,7 @@ void AiFactory::AddDefaultNonCombatStrategies(Player* player, PlayerbotAI* const
|
||||
nonCombatEngine->addStrategiesNoInit("bdps", "dps assist", "pet", nullptr);
|
||||
break;
|
||||
case CLASS_SHAMAN:
|
||||
if (tab == SHAMAN_TAB_ELEMENTAL || tab == SHAMAN_TAB_RESTORATION)
|
||||
if (tab == 0 || tab == 2)
|
||||
nonCombatEngine->addStrategy("bmana", false);
|
||||
else
|
||||
nonCombatEngine->addStrategy("bdps", false);
|
||||
@@ -543,34 +588,43 @@ void AiFactory::AddDefaultNonCombatStrategies(Player* player, PlayerbotAI* const
|
||||
nonCombatEngine->addStrategiesNoInit("dps assist", "cure", nullptr);
|
||||
break;
|
||||
case CLASS_DRUID:
|
||||
if (tab == DRUID_TAB_FERAL)
|
||||
if (tab == 1)
|
||||
{
|
||||
if (player->GetLevel() >= 20 && !player->HasAura(16931) /*thick hide*/)
|
||||
{
|
||||
nonCombatEngine->addStrategy("dps assist", false);
|
||||
}
|
||||
else
|
||||
{
|
||||
nonCombatEngine->addStrategy("tank assist", false);
|
||||
}
|
||||
}
|
||||
else
|
||||
nonCombatEngine->addStrategiesNoInit("dps assist", "cure", nullptr);
|
||||
break;
|
||||
case CLASS_WARRIOR:
|
||||
if (tab == WARRIOR_TAB_PROTECTION)
|
||||
if (tab == 2)
|
||||
nonCombatEngine->addStrategy("tank assist", false);
|
||||
else
|
||||
nonCombatEngine->addStrategy("dps assist", false);
|
||||
break;
|
||||
case CLASS_WARLOCK:
|
||||
if (tab == WARLOCK_TAB_AFFLICTION)
|
||||
{
|
||||
nonCombatEngine->addStrategiesNoInit("felhunter", "spellstone", nullptr);
|
||||
}
|
||||
else if (tab == WARLOCK_TAB_DEMONOLOGY)
|
||||
{
|
||||
nonCombatEngine->addStrategiesNoInit("felguard", "spellstone", nullptr);
|
||||
}
|
||||
else if (tab == WARLOCK_TAB_DESTRUCTION)
|
||||
{
|
||||
nonCombatEngine->addStrategiesNoInit("imp", "firestone", nullptr);
|
||||
|
||||
}
|
||||
nonCombatEngine->addStrategiesNoInit("dps assist", "ss self", nullptr);
|
||||
break;
|
||||
case CLASS_DEATH_KNIGHT:
|
||||
if (tab == DEATH_KNIGHT_TAB_BLOOD)
|
||||
if (tab == 0)
|
||||
nonCombatEngine->addStrategy("tank assist", false);
|
||||
else
|
||||
nonCombatEngine->addStrategy("dps assist", false);
|
||||
@@ -587,7 +641,9 @@ void AiFactory::AddDefaultNonCombatStrategies(Player* player, PlayerbotAI* const
|
||||
}
|
||||
|
||||
if (sPlayerbotAIConfig->autoSaveMana && PlayerbotAI::IsHeal(player, true))
|
||||
{
|
||||
nonCombatEngine->addStrategy("save mana", false);
|
||||
}
|
||||
|
||||
if ((sRandomPlayerbotMgr->IsRandomBot(player)) && !player->InBattleground())
|
||||
{
|
||||
@@ -613,14 +669,18 @@ void AiFactory::AddDefaultNonCombatStrategies(Player* player, PlayerbotAI* const
|
||||
nonCombatEngine->addStrategy("grind", false);
|
||||
|
||||
if (sPlayerbotAIConfig->enableNewRpgStrategy)
|
||||
{
|
||||
nonCombatEngine->addStrategy("new rpg", false);
|
||||
}
|
||||
else if (sPlayerbotAIConfig->autoDoQuests)
|
||||
{
|
||||
// nonCombatEngine->addStrategy("travel");
|
||||
nonCombatEngine->addStrategy("rpg", false);
|
||||
}
|
||||
else
|
||||
{
|
||||
nonCombatEngine->addStrategy("move random", false);
|
||||
}
|
||||
|
||||
if (sPlayerbotAIConfig->randomBotJoinBG)
|
||||
nonCombatEngine->addStrategy("bg", false);
|
||||
@@ -669,8 +729,11 @@ void AiFactory::AddDefaultNonCombatStrategies(Player* player, PlayerbotAI* const
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
nonCombatEngine->ChangeStrategy(sPlayerbotAIConfig->nonCombatStrategies);
|
||||
|
||||
}
|
||||
// nonCombatEngine->addStrategy("battleground");
|
||||
// nonCombatEngine->addStrategy("warsong");
|
||||
// Battleground switch
|
||||
if (player->InBattleground() && player->GetBattleground())
|
||||
{
|
||||
@@ -727,7 +790,9 @@ void AiFactory::AddDefaultDeadStrategies(Player* player, PlayerbotAI* const faca
|
||||
deadEngine->addStrategiesNoInit("dead", "stay", "chat", "default", "follow", nullptr);
|
||||
|
||||
if (sRandomPlayerbotMgr->IsRandomBot(player) && !player->GetGroup())
|
||||
{
|
||||
deadEngine->removeStrategy("follow", false);
|
||||
}
|
||||
}
|
||||
|
||||
Engine* AiFactory::createDeadEngine(Player* player, PlayerbotAI* const facade, AiObjectContext* AiObjectContext)
|
||||
@@ -1,20 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "Action.h"
|
||||
|
||||
#include "Playerbots.h"
|
||||
#include "Timer.h"
|
||||
|
||||
Value<Unit*>* Action::GetTargetValue() { return context->GetValue<Unit*>(GetTargetName()); }
|
||||
|
||||
Unit* Action::GetTarget() { return GetTargetValue()->Get(); }
|
||||
|
||||
ActionBasket::ActionBasket(ActionNode* action, float relevance, bool skipPrerequisites, Event event)
|
||||
: action(action), relevance(relevance), skipPrerequisites(skipPrerequisites), event(event), created(getMSTime())
|
||||
{
|
||||
}
|
||||
|
||||
bool ActionBasket::isExpired(uint32_t msecs) { return getMSTime() - created >= msecs; }
|
||||
@@ -1,145 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "Strategy.h"
|
||||
|
||||
#include "Playerbots.h"
|
||||
|
||||
class ActionNodeFactoryInternal : public NamedObjectFactory<ActionNode>
|
||||
{
|
||||
public:
|
||||
ActionNodeFactoryInternal()
|
||||
{
|
||||
creators["melee"] = &melee;
|
||||
creators["healthstone"] = &healthstone;
|
||||
creators["be near"] = &follow_master_random;
|
||||
creators["attack anything"] = &attack_anything;
|
||||
creators["move random"] = &move_random;
|
||||
creators["move to loot"] = &move_to_loot;
|
||||
creators["food"] = &food;
|
||||
creators["drink"] = &drink;
|
||||
creators["mana potion"] = &mana_potion;
|
||||
creators["healing potion"] = &healing_potion;
|
||||
creators["flee"] = &flee;
|
||||
}
|
||||
|
||||
private:
|
||||
static ActionNode* melee([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"melee",
|
||||
/*P*/ {},
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* healthstone([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"healthstone",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("healing potion") },
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* follow_master_random([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"be near",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("follow") },
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* attack_anything([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"attack anything",
|
||||
/*P*/ {},
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* move_random([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"move random",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("stay line") },
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* move_to_loot([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"move to loot",
|
||||
/*P*/ {},
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* food([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"food",
|
||||
/*P*/ {},
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* drink([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"drink",
|
||||
/*P*/ {},
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* mana_potion([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"mana potion",
|
||||
/*P*/ {},
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* healing_potion([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"healing potion",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("food") },
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* flee([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"flee",
|
||||
/*P*/ {},
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
Strategy::Strategy(PlayerbotAI* botAI) : PlayerbotAIAware(botAI)
|
||||
{
|
||||
actionNodeFactories.Add(new ActionNodeFactoryInternal());
|
||||
}
|
||||
|
||||
ActionNode* Strategy::GetAction(std::string const name) { return actionNodeFactories.GetContextObject(name, botAI); }
|
||||
@@ -1,39 +0,0 @@
|
||||
#include "FlightMasterCache.h"
|
||||
|
||||
void FlightMasterCache::AddHordeFlightMaster(uint32 entry, WorldPosition pos)
|
||||
{
|
||||
hordeFlightMasterCache[entry] = pos;
|
||||
}
|
||||
|
||||
void FlightMasterCache::AddAllianceFlightMaster(uint32 entry, WorldPosition pos)
|
||||
{
|
||||
allianceFlightMasterCache[entry] = pos;
|
||||
}
|
||||
|
||||
Creature* FlightMasterCache::GetNearestFlightMaster(Player* bot)
|
||||
{
|
||||
std::map<uint32, WorldPosition>& flightMasterCache =
|
||||
(bot->GetTeamId() == ALLIANCE) ? allianceFlightMasterCache : hordeFlightMasterCache;
|
||||
|
||||
Creature* nearestFlightMaster = nullptr;
|
||||
float nearestDistance = std::numeric_limits<float>::max();
|
||||
|
||||
for (auto const& [entry, pos] : flightMasterCache)
|
||||
{
|
||||
if (pos.GetMapId() == bot->GetMapId())
|
||||
{
|
||||
float distance = bot->GetExactDist2dSq(pos);
|
||||
if (distance < nearestDistance)
|
||||
{
|
||||
Creature* flightMaster = ObjectAccessor::GetSpawnedCreatureByDBGUID(bot->GetMapId(), entry);
|
||||
if (flightMaster)
|
||||
{
|
||||
nearestDistance = distance;
|
||||
nearestFlightMaster = flightMaster;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nearestFlightMaster;
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
#ifndef _PLAYERBOT_FLIGHTMASTER_H
|
||||
#define _PLAYERBOT_FLIGHTMASTER_H
|
||||
|
||||
#include "Creature.h"
|
||||
#include "Player.h"
|
||||
#include "TravelMgr.h"
|
||||
|
||||
class FlightMasterCache
|
||||
{
|
||||
public:
|
||||
static FlightMasterCache* Instance()
|
||||
{
|
||||
static FlightMasterCache instance;
|
||||
return &instance;
|
||||
}
|
||||
|
||||
Creature* GetNearestFlightMaster(Player* bot);
|
||||
void AddHordeFlightMaster(uint32 entry, WorldPosition pos);
|
||||
void AddAllianceFlightMaster(uint32 entry, WorldPosition pos);
|
||||
|
||||
private:
|
||||
std::map<uint32, WorldPosition> allianceFlightMasterCache;
|
||||
std::map<uint32, WorldPosition> hordeFlightMasterCache;
|
||||
};
|
||||
|
||||
#define sFlightMasterCache FlightMasterCache::Instance()
|
||||
#endif
|
||||
50
src/Helpers.cpp
Normal file
50
src/Helpers.cpp
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "Helpers.h"
|
||||
|
||||
char* strstri(char const* haystack, char const* needle)
|
||||
{
|
||||
if (!*needle)
|
||||
{
|
||||
return (char*)haystack;
|
||||
}
|
||||
|
||||
for (; *haystack; ++haystack)
|
||||
{
|
||||
if (tolower(*haystack) == tolower(*needle))
|
||||
{
|
||||
char const *h = haystack, *n = needle;
|
||||
for (; *h && *n; ++h, ++n)
|
||||
{
|
||||
if (tolower(*h) != tolower(*n))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!*n)
|
||||
{
|
||||
return (char*)haystack;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string& ltrim(std::string& s)
|
||||
{
|
||||
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](int c) { return !std::isspace(c); }));
|
||||
return s;
|
||||
}
|
||||
|
||||
std::string& rtrim(std::string& s)
|
||||
{
|
||||
s.erase(std::find_if(s.rbegin(), s.rend(), [](int c) { return !std::isspace(c); }).base(), s.end());
|
||||
return s;
|
||||
}
|
||||
|
||||
std::string& trim(std::string& s) { return ltrim(rtrim(s)); }
|
||||
55
src/Helpers.h
Normal file
55
src/Helpers.h
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#ifndef _PLAYERBOT_HELPERS_H
|
||||
#define _PLAYERBOT_HELPERS_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <functional>
|
||||
#include <locale>
|
||||
#include <map>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
void split(std::vector<std::string>& dest, std::string const str, char const* delim)
|
||||
{
|
||||
char* pTempStr = strdup(str.c_str());
|
||||
char* pWord = strtok(pTempStr, delim);
|
||||
|
||||
while (pWord != nullptr)
|
||||
{
|
||||
dest.push_back(pWord);
|
||||
pWord = strtok(nullptr, delim);
|
||||
}
|
||||
|
||||
free(pTempStr);
|
||||
}
|
||||
|
||||
std::vector<std::string>& split(std::string const s, char delim, std::vector<std::string>& elems)
|
||||
{
|
||||
std::stringstream ss(s);
|
||||
std::string item;
|
||||
|
||||
while (getline(ss, item, delim))
|
||||
{
|
||||
elems.push_back(item);
|
||||
}
|
||||
|
||||
return elems;
|
||||
}
|
||||
|
||||
std::vector<std::string> split(std::string const s, char delim)
|
||||
{
|
||||
std::vector<std::string> elems;
|
||||
return split(s, delim, elems);
|
||||
}
|
||||
|
||||
#endif
|
||||
39
src/LazyCalculatedValue.h
Normal file
39
src/LazyCalculatedValue.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#ifndef _PLAYERBOT_LAZYCALCULATEDVALUE_H
|
||||
#define _PLAYERBOT_LAZYCALCULATEDVALUE_H
|
||||
|
||||
template <class TValue, class TOwner>
|
||||
class LazyCalculatedValue
|
||||
{
|
||||
public:
|
||||
typedef TValue (TOwner::*Calculator)();
|
||||
|
||||
public:
|
||||
LazyCalculatedValue(TOwner* owner, Calculator calculator) : calculator(calculator), owner(owner) { Reset(); }
|
||||
|
||||
public:
|
||||
TValue GetValue()
|
||||
{
|
||||
if (!calculated)
|
||||
{
|
||||
value = (owner->*calculator)();
|
||||
calculated = true;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
void Reset() { calculated = false; }
|
||||
|
||||
protected:
|
||||
Calculator calculator;
|
||||
TOwner* owner;
|
||||
bool calculated;
|
||||
TValue value;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,322 +0,0 @@
|
||||
#include "PlayerbotGuildMgr.h"
|
||||
#include "Player.h"
|
||||
#include "PlayerbotAIConfig.h"
|
||||
#include "DatabaseEnv.h"
|
||||
#include "Guild.h"
|
||||
#include "GuildMgr.h"
|
||||
#include "RandomPlayerbotMgr.h"
|
||||
#include "ScriptMgr.h"
|
||||
|
||||
PlayerbotGuildMgr::PlayerbotGuildMgr(){}
|
||||
|
||||
void PlayerbotGuildMgr::Init()
|
||||
{
|
||||
_guildCache.clear();
|
||||
if (sPlayerbotAIConfig->deleteRandomBotGuilds)
|
||||
DeleteBotGuilds();
|
||||
|
||||
LoadGuildNames();
|
||||
ValidateGuildCache();
|
||||
}
|
||||
|
||||
bool PlayerbotGuildMgr::CreateGuild(Player* player, std::string guildName)
|
||||
{
|
||||
Guild* guild = new Guild();
|
||||
if (!guild->Create(player, guildName))
|
||||
{
|
||||
LOG_ERROR("playerbots", "Error creating guild [ {} ] with leader [ {} ]", guildName,
|
||||
player->GetName());
|
||||
delete guild;
|
||||
return false;
|
||||
}
|
||||
sGuildMgr->AddGuild(guild);
|
||||
|
||||
LOG_DEBUG("playerbots", "Guild created: id={} name='{}'", guild->GetId(), guildName);
|
||||
SetGuildEmblem(guild->GetId());
|
||||
|
||||
GuildCache entry;
|
||||
entry.name = guildName;
|
||||
entry.memberCount = 1;
|
||||
entry.status = 1;
|
||||
entry.maxMembers = sPlayerbotAIConfig->randomBotGuildSizeMax;
|
||||
entry.faction = player->GetTeamId();
|
||||
|
||||
_guildCache[guild->GetId()] = entry;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PlayerbotGuildMgr::SetGuildEmblem(uint32 guildId)
|
||||
{
|
||||
Guild* guild = sGuildMgr->GetGuildById(guildId);
|
||||
if (!guild)
|
||||
return false;
|
||||
|
||||
// create random emblem
|
||||
uint32 st, cl, br, bc, bg;
|
||||
bg = urand(0, 51);
|
||||
bc = urand(0, 17);
|
||||
cl = urand(0, 17);
|
||||
br = urand(0, 7);
|
||||
st = urand(0, 180);
|
||||
|
||||
LOG_DEBUG("playerbots",
|
||||
"[TABARD] new guild id={} random -> style={}, color={}, borderStyle={}, borderColor={}, bgColor={}",
|
||||
guild->GetId(), st, cl, br, bc, bg);
|
||||
|
||||
// populate guild table with a random tabard design
|
||||
CharacterDatabase.Execute(
|
||||
"UPDATE guild SET EmblemStyle={}, EmblemColor={}, BorderStyle={}, BorderColor={}, BackgroundColor={} "
|
||||
"WHERE guildid={}",
|
||||
st, cl, br, bc, bg, guild->GetId());
|
||||
LOG_DEBUG("playerbots", "[TABARD] UPDATE done for guild id={}", guild->GetId());
|
||||
|
||||
// Immediate reading for log
|
||||
if (QueryResult qr = CharacterDatabase.Query(
|
||||
"SELECT EmblemStyle,EmblemColor,BorderStyle,BorderColor,BackgroundColor FROM guild WHERE guildid={}",
|
||||
guild->GetId()))
|
||||
{
|
||||
Field* f = qr->Fetch();
|
||||
LOG_DEBUG("playerbots",
|
||||
"[TABARD] DB check guild id={} => style={}, color={}, borderStyle={}, borderColor={}, bgColor={}",
|
||||
guild->GetId(), f[0].Get<uint8>(), f[1].Get<uint8>(), f[2].Get<uint8>(), f[3].Get<uint8>(), f[4].Get<uint8>());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string PlayerbotGuildMgr::AssignToGuild(Player* player)
|
||||
{
|
||||
if (!player)
|
||||
return "";
|
||||
|
||||
uint8_t playerFaction = player->GetTeamId();
|
||||
std::vector<GuildCache*> partiallyfilledguilds;
|
||||
partiallyfilledguilds.reserve(_guildCache.size());
|
||||
|
||||
for (auto& keyValue : _guildCache)
|
||||
{
|
||||
GuildCache& cached = keyValue.second;
|
||||
if (!cached.hasRealPlayer && cached.status == 1 && cached.faction == playerFaction)
|
||||
partiallyfilledguilds.push_back(&cached);
|
||||
}
|
||||
|
||||
if (!partiallyfilledguilds.empty())
|
||||
{
|
||||
size_t idx = static_cast<size_t>(urand(0, static_cast<int>(partiallyfilledguilds.size()) - 1));
|
||||
return (partiallyfilledguilds[idx]->name);
|
||||
}
|
||||
|
||||
size_t count = std::count_if(
|
||||
_guildCache.begin(), _guildCache.end(),
|
||||
[](const std::pair<const uint32, GuildCache>& pair)
|
||||
{
|
||||
return !pair.second.hasRealPlayer;
|
||||
}
|
||||
);
|
||||
|
||||
if (count < sPlayerbotAIConfig->randomBotGuildCount)
|
||||
{
|
||||
for (auto& key : _shuffled_guild_keys)
|
||||
{
|
||||
if (_guildNames[key])
|
||||
{
|
||||
LOG_INFO("playerbots","Assigning player [{}] to guild [{}]", player->GetName(), key);
|
||||
return key;
|
||||
}
|
||||
}
|
||||
LOG_ERROR("playerbots","No available guild names left.");
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
void PlayerbotGuildMgr::OnGuildUpdate(Guild* guild)
|
||||
{
|
||||
auto it = _guildCache.find(guild->GetId());
|
||||
if (it == _guildCache.end())
|
||||
return;
|
||||
|
||||
GuildCache& entry = it->second;
|
||||
entry.memberCount = guild->GetMemberCount();
|
||||
if (entry.memberCount < entry.maxMembers)
|
||||
entry.status = 1;
|
||||
else if (entry.memberCount >= entry.maxMembers)
|
||||
entry.status = 2; // Full
|
||||
std::string guildName = guild->GetName();
|
||||
for (auto& it : _guildNames)
|
||||
{
|
||||
if (it.first == guildName)
|
||||
{
|
||||
it.second = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerbotGuildMgr::ResetGuildCache()
|
||||
{
|
||||
for (auto it = _guildCache.begin(); it != _guildCache.end();)
|
||||
{
|
||||
GuildCache& cached = it->second;
|
||||
cached.memberCount = 0;
|
||||
cached.faction = 2;
|
||||
cached.status = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerbotGuildMgr::LoadGuildNames()
|
||||
{
|
||||
LOG_INFO("playerbots", "Loading guild names from playerbots_guild_names...");
|
||||
|
||||
QueryResult result = CharacterDatabase.Query("SELECT name_id, name FROM playerbots_guild_names");
|
||||
|
||||
if (!result)
|
||||
{
|
||||
LOG_ERROR("playerbots", "No entries found in playerbots_guild_names. List is empty.");
|
||||
return;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
_guildNames[fields[1].Get<std::string>()] = true;
|
||||
} while (result->NextRow());
|
||||
|
||||
for (auto& pair : _guildNames)
|
||||
_shuffled_guild_keys.push_back(pair.first);
|
||||
|
||||
std::random_device rd;
|
||||
std::mt19937 g(rd());
|
||||
|
||||
std::shuffle(_shuffled_guild_keys.begin(), _shuffled_guild_keys.end(), g);
|
||||
LOG_INFO("playerbots", "Loaded {} guild entries from playerbots_guild_names table.", _guildNames.size());
|
||||
}
|
||||
|
||||
void PlayerbotGuildMgr::ValidateGuildCache()
|
||||
{
|
||||
QueryResult result = CharacterDatabase.Query("SELECT guildid, name FROM guild");
|
||||
if (!result)
|
||||
{
|
||||
LOG_ERROR("playerbots", "No guilds found in database, resetting guild cache");
|
||||
ResetGuildCache();
|
||||
return;
|
||||
}
|
||||
|
||||
std::unordered_map<uint32, std::string> dbGuilds;
|
||||
do
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
uint32 guildId = fields[0].Get<uint32>();
|
||||
std::string guildName = fields[1].Get<std::string>();
|
||||
dbGuilds[guildId] = guildName;
|
||||
} while (result->NextRow());
|
||||
|
||||
for (auto it = dbGuilds.begin(); it != dbGuilds.end(); it++)
|
||||
{
|
||||
uint32 guildId = it->first;
|
||||
GuildCache cache;
|
||||
cache.name = it->second;
|
||||
cache.maxMembers = sPlayerbotAIConfig->randomBotGuildSizeMax;
|
||||
|
||||
Guild* guild = sGuildMgr ->GetGuildById(guildId);
|
||||
if (!guild)
|
||||
continue;
|
||||
|
||||
cache.memberCount = guild->GetMemberCount();
|
||||
ObjectGuid leaderGuid = guild->GetLeaderGUID();
|
||||
CharacterCacheEntry const* leaderEntry = sCharacterCache->GetCharacterCacheByGuid(leaderGuid);
|
||||
uint32 leaderAccount = leaderEntry->AccountId;
|
||||
cache.hasRealPlayer = !(sPlayerbotAIConfig->IsInRandomAccountList(leaderAccount));
|
||||
cache.faction = Player::TeamIdForRace(leaderEntry->Race);
|
||||
if (cache.memberCount == 0)
|
||||
cache.status = 0; // empty
|
||||
else if (cache.memberCount < cache.maxMembers)
|
||||
cache.status = 1; // partially filled
|
||||
else
|
||||
cache.status = 2; // full
|
||||
|
||||
_guildCache.insert_or_assign(guildId, cache);
|
||||
for (auto& it : _guildNames)
|
||||
{
|
||||
if (it.first == cache.name)
|
||||
{
|
||||
it.second = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerbotGuildMgr::DeleteBotGuilds()
|
||||
{
|
||||
LOG_INFO("playerbots", "Deleting random bot guilds...");
|
||||
std::vector<uint32> randomBots;
|
||||
|
||||
PlayerbotsDatabasePreparedStatement* stmt = PlayerbotsDatabase.GetPreparedStatement(PLAYERBOTS_SEL_RANDOM_BOTS_BOT);
|
||||
stmt->SetData(0, "add");
|
||||
if (PreparedQueryResult result = PlayerbotsDatabase.Query(stmt))
|
||||
{
|
||||
do
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
uint32 bot = fields[0].Get<uint32>();
|
||||
randomBots.push_back(bot);
|
||||
} while (result->NextRow());
|
||||
}
|
||||
|
||||
for (std::vector<uint32>::iterator i = randomBots.begin(); i != randomBots.end(); ++i)
|
||||
{
|
||||
if (Guild* guild = sGuildMgr->GetGuildByLeader(ObjectGuid::Create<HighGuid::Player>(*i)))
|
||||
guild->Disband();
|
||||
}
|
||||
LOG_INFO("playerbots", "Random bot guilds deleted");
|
||||
}
|
||||
|
||||
bool PlayerbotGuildMgr::IsRealGuild(Player* bot)
|
||||
{
|
||||
if (!bot)
|
||||
return false;
|
||||
uint32 guildId = bot->GetGuildId();
|
||||
if (!guildId)
|
||||
return false;
|
||||
|
||||
return IsRealGuild(guildId);
|
||||
}
|
||||
|
||||
bool PlayerbotGuildMgr::IsRealGuild(uint32 guildId)
|
||||
{
|
||||
if (!guildId)
|
||||
return false;
|
||||
|
||||
auto it = _guildCache.find(guildId);
|
||||
if (it == _guildCache.end())
|
||||
return false;
|
||||
|
||||
return it->second.hasRealPlayer;
|
||||
}
|
||||
|
||||
class BotGuildCacheWorldScript : public WorldScript
|
||||
{
|
||||
public:
|
||||
|
||||
BotGuildCacheWorldScript() : WorldScript("BotGuildCacheWorldScript"), _validateTimer(0){}
|
||||
|
||||
void OnUpdate(uint32 diff) override
|
||||
{
|
||||
_validateTimer += diff;
|
||||
|
||||
if (_validateTimer >= _validateInterval) // Validate every hour
|
||||
{
|
||||
_validateTimer = 0;
|
||||
sPlayerbotGuildMgr->ValidateGuildCache();
|
||||
LOG_INFO("playerbots", "Scheduled guild cache validation");
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
uint32 _validateInterval = HOUR*IN_MILLISECONDS;
|
||||
uint32 _validateTimer;
|
||||
};
|
||||
|
||||
void PlayerBotsGuildValidationScript()
|
||||
{
|
||||
new BotGuildCacheWorldScript();
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
#ifndef _PLAYERBOT_PLAYERBOTGUILDMGR_H
|
||||
#define _PLAYERBOT_PLAYERBOTGUILDMGR_H
|
||||
|
||||
#include "Guild.h"
|
||||
#include "Player.h"
|
||||
#include "PlayerbotAI.h"
|
||||
|
||||
class PlayerbotAI;
|
||||
|
||||
class PlayerbotGuildMgr
|
||||
{
|
||||
public:
|
||||
static PlayerbotGuildMgr* instance()
|
||||
{
|
||||
static PlayerbotGuildMgr instance;
|
||||
return &instance;
|
||||
}
|
||||
|
||||
void Init();
|
||||
std::string AssignToGuild(Player* player);
|
||||
void LoadGuildNames();
|
||||
void ValidateGuildCache();
|
||||
void ResetGuildCache();
|
||||
bool CreateGuild(Player* player, std::string guildName);
|
||||
void OnGuildUpdate (Guild* guild);
|
||||
bool SetGuildEmblem(uint32 guildId);
|
||||
void DeleteBotGuilds();
|
||||
bool IsRealGuild(uint32 guildId);
|
||||
bool IsRealGuild(Player* bot);
|
||||
|
||||
private:
|
||||
PlayerbotGuildMgr();
|
||||
std::unordered_map<std::string, bool> _guildNames;
|
||||
|
||||
struct GuildCache
|
||||
{
|
||||
std::string name;
|
||||
uint8 status;
|
||||
uint32 maxMembers = 0;
|
||||
uint32 memberCount = 0;
|
||||
uint8 faction = 0;
|
||||
bool hasRealPlayer = false;
|
||||
};
|
||||
std::unordered_map<uint32 , GuildCache> _guildCache;
|
||||
std::vector<std::string> _shuffled_guild_keys;
|
||||
};
|
||||
|
||||
void PlayerBotsGuildValidationScript();
|
||||
|
||||
#define sPlayerbotGuildMgr PlayerbotGuildMgr::instance()
|
||||
|
||||
#endif
|
||||
@@ -3,11 +3,11 @@
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "PerfMonitor.h"
|
||||
#include "PerformanceMonitor.h"
|
||||
|
||||
#include "Playerbots.h"
|
||||
|
||||
PerfMonitorOperation* PerfMonitor::start(PerformanceMetric metric, std::string const name,
|
||||
PerformanceMonitorOperation* PerformanceMonitor::start(PerformanceMetric metric, std::string const name,
|
||||
PerformanceStack* stack)
|
||||
{
|
||||
if (!sPlayerbotAIConfig->perfMonEnabled)
|
||||
@@ -45,10 +45,10 @@ PerfMonitorOperation* PerfMonitor::start(PerformanceMetric metric, std::string c
|
||||
data[metric][stackName] = pd;
|
||||
}
|
||||
|
||||
return new PerfMonitorOperation(pd, name, stack);
|
||||
return new PerformanceMonitorOperation(pd, name, stack);
|
||||
}
|
||||
|
||||
void PerfMonitor::PrintStats(bool perTick, bool fullStack)
|
||||
void PerformanceMonitor::PrintStats(bool perTick, bool fullStack)
|
||||
{
|
||||
if (data.empty())
|
||||
return;
|
||||
@@ -247,7 +247,7 @@ void PerfMonitor::PrintStats(bool perTick, bool fullStack)
|
||||
}
|
||||
}
|
||||
|
||||
void PerfMonitor::Reset()
|
||||
void PerformanceMonitor::Reset()
|
||||
{
|
||||
for (std::map<PerformanceMetric, std::map<std::string, PerformanceData*>>::iterator i = data.begin();
|
||||
i != data.end(); ++i)
|
||||
@@ -265,7 +265,7 @@ void PerfMonitor::Reset()
|
||||
}
|
||||
}
|
||||
|
||||
PerfMonitorOperation::PerfMonitorOperation(PerformanceData* data, std::string const name,
|
||||
PerformanceMonitorOperation::PerformanceMonitorOperation(PerformanceData* data, std::string const name,
|
||||
PerformanceStack* stack)
|
||||
: data(data), name(name), stack(stack)
|
||||
{
|
||||
@@ -273,7 +273,7 @@ PerfMonitorOperation::PerfMonitorOperation(PerformanceData* data, std::string co
|
||||
.time_since_epoch();
|
||||
}
|
||||
|
||||
void PerfMonitorOperation::finish()
|
||||
void PerformanceMonitorOperation::finish()
|
||||
{
|
||||
std::chrono::microseconds finished =
|
||||
(std::chrono::time_point_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now()))
|
||||
@@ -34,10 +34,10 @@ enum PerformanceMetric
|
||||
PERF_MON_TOTAL
|
||||
};
|
||||
|
||||
class PerfMonitorOperation
|
||||
class PerformanceMonitorOperation
|
||||
{
|
||||
public:
|
||||
PerfMonitorOperation(PerformanceData* data, std::string const name, PerformanceStack* stack);
|
||||
PerformanceMonitorOperation(PerformanceData* data, std::string const name, PerformanceStack* stack);
|
||||
void finish();
|
||||
|
||||
private:
|
||||
@@ -47,19 +47,19 @@ private:
|
||||
std::chrono::microseconds started;
|
||||
};
|
||||
|
||||
class PerfMonitor
|
||||
class PerformanceMonitor
|
||||
{
|
||||
public:
|
||||
PerfMonitor(){};
|
||||
virtual ~PerfMonitor(){};
|
||||
static PerfMonitor* instance()
|
||||
PerformanceMonitor(){};
|
||||
virtual ~PerformanceMonitor(){};
|
||||
static PerformanceMonitor* instance()
|
||||
{
|
||||
static PerfMonitor instance;
|
||||
static PerformanceMonitor instance;
|
||||
return &instance;
|
||||
}
|
||||
|
||||
public:
|
||||
PerfMonitorOperation* start(PerformanceMetric metric, std::string const name,
|
||||
PerformanceMonitorOperation* start(PerformanceMetric metric, std::string const name,
|
||||
PerformanceStack* stack = nullptr);
|
||||
void PrintStats(bool perTick = false, bool fullStack = false);
|
||||
void Reset();
|
||||
@@ -69,6 +69,6 @@ private:
|
||||
std::mutex lock;
|
||||
};
|
||||
|
||||
#define sPerfMonitor PerfMonitor::instance()
|
||||
#define sPerformanceMonitor PerformanceMonitor::instance()
|
||||
|
||||
#endif
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
#include "Common.h"
|
||||
#include "Player.h"
|
||||
#include "PlayerbotDungeonRepository.h"
|
||||
#include "PlayerbotDungeonSuggestionMgr.h"
|
||||
|
||||
typedef std::map<std::string, std::string> PlaceholderMap;
|
||||
|
||||
@@ -38,12 +38,11 @@
|
||||
#include "NewRpgStrategy.h"
|
||||
#include "ObjectGuid.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "PerfMonitor.h"
|
||||
#include "PerformanceMonitor.h"
|
||||
#include "Player.h"
|
||||
#include "PlayerbotAIConfig.h"
|
||||
#include "PlayerbotRepository.h"
|
||||
#include "PlayerbotDbStore.h"
|
||||
#include "PlayerbotMgr.h"
|
||||
#include "PlayerbotGuildMgr.h"
|
||||
#include "Playerbots.h"
|
||||
#include "PointMovementGenerator.h"
|
||||
#include "PositionValue.h"
|
||||
@@ -89,10 +88,8 @@ void PacketHandlingHelper::Handle(ExternalEventHelper& helper)
|
||||
{
|
||||
while (!queue.empty())
|
||||
{
|
||||
WorldPacket packet = queue.top();
|
||||
queue.pop(); // remove first so handling can't modify the queue while we're using it
|
||||
|
||||
helper.HandlePacket(handlers, packet);
|
||||
helper.HandlePacket(handlers, queue.top());
|
||||
queue.pop();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -439,19 +436,12 @@ void PlayerbotAI::UpdateAIGroupMaster()
|
||||
|
||||
void PlayerbotAI::UpdateAIInternal([[maybe_unused]] uint32 elapsed, bool minimal)
|
||||
{
|
||||
|
||||
if (!bot || !bot->GetSession())
|
||||
if (bot->IsBeingTeleported() || !bot->IsInWorld())
|
||||
return;
|
||||
|
||||
if (!bot->IsInWorld() || bot->IsBeingTeleported() || bot->IsDuringRemoveFromWorld())
|
||||
return;
|
||||
|
||||
if (!bot->GetMap())
|
||||
return; // instances are created and destroyed on demand
|
||||
|
||||
std::string const mapString = WorldPosition(bot).isOverworld() ? std::to_string(bot->GetMapId()) : "I";
|
||||
PerfMonitorOperation* pmo =
|
||||
sPerfMonitor->start(PERF_MON_TOTAL, "PlayerbotAI::UpdateAIInternal " + mapString);
|
||||
PerformanceMonitorOperation* pmo =
|
||||
sPerformanceMonitor->start(PERF_MON_TOTAL, "PlayerbotAI::UpdateAIInternal " + mapString);
|
||||
ExternalEventHelper helper(aiObjectContext);
|
||||
|
||||
// chat replies
|
||||
@@ -525,37 +515,23 @@ void PlayerbotAI::UpdateAIInternal([[maybe_unused]] uint32 elapsed, bool minimal
|
||||
void PlayerbotAI::HandleCommands()
|
||||
{
|
||||
ExternalEventHelper helper(aiObjectContext);
|
||||
|
||||
for (auto it = chatCommands.begin(); it != chatCommands.end();)
|
||||
{
|
||||
time_t& checkTime = it->GetTime();
|
||||
if (checkTime && time(nullptr) < checkTime)
|
||||
if (checkTime && time(0) < checkTime)
|
||||
{
|
||||
++it;
|
||||
continue;
|
||||
}
|
||||
|
||||
Player* owner = it->GetOwner();
|
||||
if (!owner)
|
||||
{
|
||||
it = chatCommands.erase(it);
|
||||
continue;
|
||||
}
|
||||
|
||||
const std::string& command = it->GetCommand();
|
||||
if (command.empty())
|
||||
{
|
||||
it = chatCommands.erase(it);
|
||||
continue;
|
||||
}
|
||||
|
||||
Player* owner = it->GetOwner();
|
||||
if (!helper.ParseChatCommand(command, owner) && it->GetType() == CHAT_MSG_WHISPER)
|
||||
{
|
||||
// ostringstream out; out << "Unknown command " << command;
|
||||
// TellPlayer(out);
|
||||
// helper.ParseChatCommand("help");
|
||||
}
|
||||
|
||||
it = chatCommands.erase(it);
|
||||
}
|
||||
}
|
||||
@@ -563,9 +539,6 @@ void PlayerbotAI::HandleCommands()
|
||||
std::map<std::string, ChatMsg> chatMap;
|
||||
void PlayerbotAI::HandleCommand(uint32 type, const std::string& text, Player& fromPlayer, const uint32 lang)
|
||||
{
|
||||
if (!bot)
|
||||
return;
|
||||
|
||||
std::string filtered = text;
|
||||
|
||||
if (!IsAllowedCommand(filtered) && !GetSecurity()->CheckLevelFor(PlayerbotSecurityLevel::PLAYERBOT_SECURITY_INVITE,
|
||||
@@ -737,82 +710,65 @@ void PlayerbotAI::HandleCommand(uint32 type, const std::string& text, Player& fr
|
||||
|
||||
void PlayerbotAI::HandleTeleportAck()
|
||||
{
|
||||
if (!bot || !bot->GetSession())
|
||||
return;
|
||||
|
||||
// only for bots
|
||||
if (IsRealPlayer())
|
||||
return;
|
||||
|
||||
/*
|
||||
* FAR TELEPORT (worldport / map change)
|
||||
* Player may NOT be in world or grid here.
|
||||
* Handle this FIRST.
|
||||
*/
|
||||
if (bot->IsBeingTeleportedFar())
|
||||
{
|
||||
bot->GetSession()->HandleMoveWorldportAck();
|
||||
// Clearing motion generators and stopping movement which prevents
|
||||
// conflicts between teleport and any active motion (walk, run, swim, flight, etc.)
|
||||
bot->GetMotionMaster()->Clear(true);
|
||||
bot->StopMoving();
|
||||
|
||||
// after worldport ACK the player should be in a valid map
|
||||
if (!bot->GetMap())
|
||||
{
|
||||
LOG_ERROR("playerbot", "Bot {} has no map after worldport ACK", bot->GetGUID().ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
// apply instance-related strategies after map attach
|
||||
if (sPlayerbotAIConfig->applyInstanceStrategies)
|
||||
ApplyInstanceStrategies(bot->GetMapId(), true);
|
||||
|
||||
if (sPlayerbotAIConfig->restrictHealerDPS)
|
||||
EvaluateHealerDpsStrategy();
|
||||
|
||||
// reset AI state after teleport
|
||||
Reset(true);
|
||||
|
||||
// clear movement only AFTER teleport is finalized and bot is in world
|
||||
if (bot->IsInWorld() && bot->GetMotionMaster())
|
||||
{
|
||||
bot->GetMotionMaster()->Clear(true);
|
||||
bot->StopMoving();
|
||||
}
|
||||
|
||||
// simulate far teleport latency (cmangos-style)
|
||||
SetNextCheckDelay(urand(2000, 5000));
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* NEAR TELEPORT (same map / instance)
|
||||
* Player MUST be in world (and in grid).
|
||||
*/
|
||||
// Near teleport (within map/instance)
|
||||
if (bot->IsBeingTeleportedNear())
|
||||
{
|
||||
if (!bot->IsInWorld())
|
||||
return;
|
||||
// Previous versions manually added the bot to the map if it was not in the world.
|
||||
// not needed: HandleMoveTeleportAckOpcode() safely attaches the player to the map
|
||||
// and clears IsBeingTeleportedNear().
|
||||
|
||||
Player* plMover = bot->m_mover ? bot->m_mover->ToPlayer() : nullptr;
|
||||
Player* plMover = bot->m_mover->ToPlayer();
|
||||
if (!plMover)
|
||||
return;
|
||||
|
||||
// Send the near teleport ACK packet
|
||||
WorldPacket p(MSG_MOVE_TELEPORT_ACK, 20);
|
||||
p << plMover->GetPackGUID();
|
||||
p << uint32(0); // flags
|
||||
p << uint32(0); // time
|
||||
|
||||
p << uint32(0);
|
||||
p << uint32(0);
|
||||
bot->GetSession()->HandleMoveTeleportAck(p);
|
||||
|
||||
// clear movement after successful relocation
|
||||
if (bot->GetMotionMaster())
|
||||
// Simulate teleport latency and prevent AI from running too early (used cmangos delays)
|
||||
SetNextCheckDelay(urand(1000, 2000));
|
||||
}
|
||||
|
||||
// Far teleport (worldport / different map)
|
||||
if (bot->IsBeingTeleportedFar())
|
||||
{
|
||||
// Handle far teleport ACK:
|
||||
// Moves the bot to the new map, clears IsBeingTeleportedFar(), updates session/map references
|
||||
bot->GetSession()->HandleMoveWorldportAck();
|
||||
|
||||
// Ensure bot now has a valid map. If this fails, there is a core/session bug?
|
||||
if (!bot->GetMap())
|
||||
{
|
||||
bot->GetMotionMaster()->Clear(true);
|
||||
bot->StopMoving();
|
||||
LOG_ERROR("playerbot", "Bot {} has no map after worldport ACK", bot->GetGUID().ToString());
|
||||
}
|
||||
|
||||
// simulate near teleport latency
|
||||
SetNextCheckDelay(urand(1000, 2000));
|
||||
return;
|
||||
// Instance strategies after teleport
|
||||
if (sPlayerbotAIConfig->applyInstanceStrategies)
|
||||
ApplyInstanceStrategies(bot->GetMapId(), true);
|
||||
|
||||
// healer DPS strategies if restrictions are enabled
|
||||
if (sPlayerbotAIConfig->restrictHealerDPS)
|
||||
EvaluateHealerDpsStrategy();
|
||||
|
||||
// Reset AI state to to before teleport conditions
|
||||
Reset(true);
|
||||
|
||||
// Slightly longer delay to simulate far teleport latency (used cmangos delays)
|
||||
SetNextCheckDelay(urand(2000, 5000));
|
||||
}
|
||||
|
||||
SetNextCheckDelay(sPlayerbotAIConfig->globalCoolDown);
|
||||
}
|
||||
|
||||
void PlayerbotAI::Reset(bool full)
|
||||
@@ -974,6 +930,7 @@ void PlayerbotAI::HandleCommand(uint32 type, std::string const text, Player* fro
|
||||
fromPlayer->SendDirectMessage(&data);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!IsAllowedCommand(filtered) &&
|
||||
(!GetSecurity()->CheckLevelFor(PLAYERBOT_SECURITY_ALLOW_ALL, type != CHAT_MSG_WHISPER, fromPlayer)))
|
||||
return;
|
||||
@@ -1329,12 +1286,7 @@ void PlayerbotAI::SpellInterrupted(uint32 spellid)
|
||||
Spell* spell = bot->GetCurrentSpell((CurrentSpellTypes)type);
|
||||
if (!spell)
|
||||
continue;
|
||||
|
||||
SpellInfo const* spellInfo = spell->GetSpellInfo();
|
||||
if (!spellInfo)
|
||||
continue;
|
||||
|
||||
if (spellInfo->Id == spellid)
|
||||
if (spell->GetSpellInfo()->Id == spellid)
|
||||
bot->InterruptSpell((CurrentSpellTypes)type);
|
||||
}
|
||||
// LastSpellCast& lastSpell = aiObjectContext->GetValue<LastSpellCast&>("last spell cast")->Get();
|
||||
@@ -1435,8 +1387,8 @@ void PlayerbotAI::DoNextAction(bool min)
|
||||
return;
|
||||
}
|
||||
|
||||
// Change engine if just ressed (no movement update when rooted)
|
||||
if (currentEngine == engines[BOT_STATE_DEAD] && isBotAlive && !bot->IsRooted())
|
||||
// Change engine if just ressed
|
||||
if (currentEngine == engines[BOT_STATE_DEAD] && isBotAlive)
|
||||
{
|
||||
bot->SendMovementFlagUpdate();
|
||||
|
||||
@@ -1552,6 +1504,9 @@ void PlayerbotAI::ApplyInstanceStrategies(uint32 mapId, bool tellMaster)
|
||||
case 532:
|
||||
strategyName = "karazhan"; // Karazhan
|
||||
break;
|
||||
case 533:
|
||||
strategyName = "naxx"; // Naxxramas
|
||||
break;
|
||||
case 544:
|
||||
strategyName = "magtheridon"; // Magtheridon's Lair
|
||||
break;
|
||||
@@ -1740,7 +1695,7 @@ void PlayerbotAI::ResetStrategies(bool load)
|
||||
engines[i]->Init();
|
||||
|
||||
// if (load)
|
||||
// sPlayerbotRepository->Load(this);
|
||||
// sPlayerbotDbStore->Load(this);
|
||||
}
|
||||
|
||||
bool PlayerbotAI::IsRanged(Player* player, bool bySpec)
|
||||
@@ -1776,7 +1731,6 @@ bool PlayerbotAI::IsRanged(Player* player, bool bySpec)
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1796,46 +1750,35 @@ bool PlayerbotAI::IsCombo(Player* player)
|
||||
|
||||
bool PlayerbotAI::IsRangedDps(Player* player, bool bySpec) { return IsRanged(player, bySpec) && IsDps(player, bySpec); }
|
||||
|
||||
bool PlayerbotAI::IsAssistHealOfIndex(Player* player, int index, bool ignoreDeadPlayers)
|
||||
bool PlayerbotAI::IsHealAssistantOfIndex(Player* player, int index)
|
||||
{
|
||||
Group* group = player->GetGroup();
|
||||
if (!group)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int counter = 0;
|
||||
|
||||
// First, assistants
|
||||
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
||||
{
|
||||
Player* member = ref->GetSource();
|
||||
|
||||
if (!member)
|
||||
continue;
|
||||
|
||||
if (ignoreDeadPlayers && !member->IsAlive())
|
||||
continue;
|
||||
|
||||
if (group->IsAssistant(member->GetGUID()) && IsHeal(member))
|
||||
{
|
||||
if (index == counter)
|
||||
return player == member;
|
||||
counter++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// If not enough assistants, get non-assistants
|
||||
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
||||
{
|
||||
Player* member = ref->GetSource();
|
||||
if (!member)
|
||||
continue;
|
||||
|
||||
if (ignoreDeadPlayers && !member->IsAlive())
|
||||
continue;
|
||||
|
||||
if (!group->IsAssistant(member->GetGUID()) && IsHeal(member))
|
||||
if (IsHeal(member)) // Check if the member is a healer
|
||||
{
|
||||
if (index == counter)
|
||||
bool isAssistant = group->IsAssistant(member->GetGUID());
|
||||
|
||||
// Check if the index matches for both assistant and non-assistant healers
|
||||
if ((isAssistant && index == counter) || (!isAssistant && index == counter))
|
||||
{
|
||||
return player == member;
|
||||
}
|
||||
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
@@ -1843,46 +1786,35 @@ bool PlayerbotAI::IsAssistHealOfIndex(Player* player, int index, bool ignoreDead
|
||||
return false;
|
||||
}
|
||||
|
||||
bool PlayerbotAI::IsAssistRangedDpsOfIndex(Player* player, int index, bool ignoreDeadPlayers)
|
||||
bool PlayerbotAI::IsRangedDpsAssistantOfIndex(Player* player, int index)
|
||||
{
|
||||
Group* group = player->GetGroup();
|
||||
if (!group)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int counter = 0;
|
||||
|
||||
// First, assistants
|
||||
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
||||
{
|
||||
Player* member = ref->GetSource();
|
||||
|
||||
if (!member)
|
||||
continue;
|
||||
|
||||
if (ignoreDeadPlayers && !member->IsAlive())
|
||||
continue;
|
||||
|
||||
if (group->IsAssistant(member->GetGUID()) && IsRangedDps(member))
|
||||
{
|
||||
if (index == counter)
|
||||
return player == member;
|
||||
counter++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// If not enough assistants, get non-assistants
|
||||
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
||||
{
|
||||
Player* member = ref->GetSource();
|
||||
if (!member)
|
||||
continue;
|
||||
|
||||
if (ignoreDeadPlayers && !member->IsAlive())
|
||||
continue;
|
||||
|
||||
if (!group->IsAssistant(member->GetGUID()) && IsRangedDps(member))
|
||||
if (IsRangedDps(member)) // Check if the member is a ranged DPS
|
||||
{
|
||||
if (index == counter)
|
||||
bool isAssistant = group->IsAssistant(member->GetGUID());
|
||||
|
||||
// Check the index for both assistant and non-assistant ranges
|
||||
if ((isAssistant && index == counter) || (!isAssistant && index == counter))
|
||||
{
|
||||
return player == member;
|
||||
}
|
||||
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
@@ -1892,9 +1824,10 @@ bool PlayerbotAI::IsAssistRangedDpsOfIndex(Player* player, int index, bool ignor
|
||||
|
||||
bool PlayerbotAI::HasAggro(Unit* unit)
|
||||
{
|
||||
if (!IsValidUnit(unit))
|
||||
if (!unit)
|
||||
{
|
||||
return false;
|
||||
|
||||
}
|
||||
bool isMT = IsMainTank(bot);
|
||||
Unit* victim = unit->GetVictim();
|
||||
if (victim && (victim->GetGUID() == bot->GetGUID() || (!isMT && victim->ToPlayer() && IsTank(victim->ToPlayer()))))
|
||||
@@ -2102,7 +2035,7 @@ bool PlayerbotAI::IsTank(Player* player, bool bySpec)
|
||||
switch (player->getClass())
|
||||
{
|
||||
case CLASS_DEATH_KNIGHT:
|
||||
if (tab == DEATH_KNIGHT_TAB_BLOOD)
|
||||
if (tab == DEATHKNIGHT_TAB_BLOOD)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -2210,7 +2143,7 @@ bool PlayerbotAI::IsDps(Player* player, bool bySpec)
|
||||
}
|
||||
break;
|
||||
case CLASS_DEATH_KNIGHT:
|
||||
if (tab != DEATH_KNIGHT_TAB_BLOOD)
|
||||
if (tab != DEATHKNIGHT_TAB_BLOOD)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -2269,15 +2202,10 @@ bool PlayerbotAI::IsMainTank(Player* player)
|
||||
|
||||
bool PlayerbotAI::IsBotMainTank(Player* player)
|
||||
{
|
||||
if (!player || !player->IsInWorld() || player->IsDuringRemoveFromWorld())
|
||||
return false;
|
||||
|
||||
WorldSession* session = player->GetSession();
|
||||
if (!session || !session->IsBot())
|
||||
return false;
|
||||
|
||||
if (!IsTank(player))
|
||||
if (!player->GetSession()->IsBot() || !IsTank(player))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (IsMainTank(player))
|
||||
{
|
||||
@@ -2357,16 +2285,18 @@ bool PlayerbotAI::IsAssistTankOfIndex(Player* player, int index, bool ignoreDead
|
||||
{
|
||||
Group* group = player->GetGroup();
|
||||
if (!group)
|
||||
{
|
||||
return false;
|
||||
|
||||
}
|
||||
int counter = 0;
|
||||
|
||||
// First, assistants
|
||||
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
||||
{
|
||||
Player* member = ref->GetSource();
|
||||
|
||||
if (!member)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ignoreDeadPlayers && !member->IsAlive())
|
||||
continue;
|
||||
@@ -2374,17 +2304,21 @@ bool PlayerbotAI::IsAssistTankOfIndex(Player* player, int index, bool ignoreDead
|
||||
if (group->IsAssistant(member->GetGUID()) && IsAssistTank(member))
|
||||
{
|
||||
if (index == counter)
|
||||
{
|
||||
return player == member;
|
||||
}
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
|
||||
// If not enough assistants, get non-assistants
|
||||
// not enough
|
||||
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
||||
{
|
||||
Player* member = ref->GetSource();
|
||||
|
||||
if (!member)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ignoreDeadPlayers && !member->IsAlive())
|
||||
continue;
|
||||
@@ -2392,7 +2326,9 @@ bool PlayerbotAI::IsAssistTankOfIndex(Player* player, int index, bool ignoreDead
|
||||
if (!group->IsAssistant(member->GetGUID()) && IsAssistTank(member))
|
||||
{
|
||||
if (index == counter)
|
||||
{
|
||||
return player == member;
|
||||
}
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
@@ -2867,12 +2803,7 @@ bool PlayerbotAI::TellMaster(std::ostringstream& stream, PlayerbotSecurityLevel
|
||||
|
||||
bool PlayerbotAI::TellMaster(std::string const text, PlayerbotSecurityLevel securityLevel)
|
||||
{
|
||||
if (!master)
|
||||
{
|
||||
if (sPlayerbotAIConfig->randomBotSayWithoutMaster)
|
||||
return TellMasterNoFacing(text, securityLevel);
|
||||
}
|
||||
if (!TellMasterNoFacing(text, securityLevel))
|
||||
if (!master || !TellMasterNoFacing(text, securityLevel))
|
||||
return false;
|
||||
|
||||
if (!bot->isMoving() && !bot->IsInCombat() && bot->GetMapId() == master->GetMapId() &&
|
||||
@@ -2889,9 +2820,6 @@ bool PlayerbotAI::TellMaster(std::string const text, PlayerbotSecurityLevel secu
|
||||
|
||||
bool IsRealAura(Player* bot, AuraEffect const* aurEff, Unit const* unit)
|
||||
{
|
||||
if (!unit || !unit->IsInWorld() || unit->IsDuringRemoveFromWorld())
|
||||
return false;
|
||||
|
||||
if (!aurEff)
|
||||
return false;
|
||||
|
||||
@@ -2899,8 +2827,6 @@ bool IsRealAura(Player* bot, AuraEffect const* aurEff, Unit const* unit)
|
||||
return true;
|
||||
|
||||
SpellInfo const* spellInfo = aurEff->GetSpellInfo();
|
||||
if (!spellInfo)
|
||||
return false;
|
||||
|
||||
uint32 stacks = aurEff->GetBase()->GetStackAmount();
|
||||
if (stacks >= spellInfo->StackAmount)
|
||||
@@ -2916,7 +2842,7 @@ bool IsRealAura(Player* bot, AuraEffect const* aurEff, Unit const* unit)
|
||||
bool PlayerbotAI::HasAura(std::string const name, Unit* unit, bool maxStack, bool checkIsOwner, int maxAuraAmount,
|
||||
bool checkDuration)
|
||||
{
|
||||
if (!IsValidUnit(unit))
|
||||
if (!unit)
|
||||
return false;
|
||||
|
||||
std::wstring wnamepart;
|
||||
@@ -3012,7 +2938,7 @@ bool PlayerbotAI::HasAura(uint32 spellId, Unit const* unit)
|
||||
|
||||
Aura* PlayerbotAI::GetAura(std::string const name, Unit* unit, bool checkIsOwner, bool checkDuration, int checkStack)
|
||||
{
|
||||
if (!IsValidUnit(unit))
|
||||
if (!unit)
|
||||
return nullptr;
|
||||
|
||||
std::wstring wnamepart;
|
||||
@@ -3030,9 +2956,6 @@ Aura* PlayerbotAI::GetAura(std::string const name, Unit* unit, bool checkIsOwner
|
||||
for (AuraEffect const* aurEff : auras)
|
||||
{
|
||||
SpellInfo const* spellInfo = aurEff->GetSpellInfo();
|
||||
if (!spellInfo)
|
||||
continue;
|
||||
|
||||
std::string const& auraName = spellInfo->SpellName[0];
|
||||
|
||||
// Directly skip if name mismatch (both length and content)
|
||||
@@ -3113,9 +3036,6 @@ bool PlayerbotAI::CanCastSpell(uint32 spellid, Unit* target, bool checkHasSpell,
|
||||
if (!target)
|
||||
target = bot;
|
||||
|
||||
if (!IsValidUnit(target))
|
||||
return false;
|
||||
|
||||
if (Pet* pet = bot->GetPet())
|
||||
if (pet->HasSpell(spellid))
|
||||
return true;
|
||||
@@ -3377,9 +3297,6 @@ bool PlayerbotAI::CanCastSpell(uint32 spellid, float x, float y, float z, bool c
|
||||
|
||||
bool PlayerbotAI::CastSpell(std::string const name, Unit* target, Item* itemTarget)
|
||||
{
|
||||
if (!IsValidUnit(target))
|
||||
return false;
|
||||
|
||||
bool result = CastSpell(aiObjectContext->GetValue<uint32>("spell id", name)->Get(), target, itemTarget);
|
||||
if (result)
|
||||
{
|
||||
@@ -3392,19 +3309,15 @@ bool PlayerbotAI::CastSpell(std::string const name, Unit* target, Item* itemTarg
|
||||
bool PlayerbotAI::CastSpell(uint32 spellId, Unit* target, Item* itemTarget)
|
||||
{
|
||||
if (!spellId)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!target)
|
||||
target = bot;
|
||||
|
||||
if (!IsValidUnit(target))
|
||||
return false;
|
||||
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
|
||||
if (!spellInfo)
|
||||
return false;
|
||||
|
||||
Pet* pet = bot->GetPet();
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
|
||||
if (pet && pet->HasSpell(spellId))
|
||||
{
|
||||
// List of spell IDs for which we do NOT want to toggle auto-cast or send message
|
||||
@@ -3807,9 +3720,6 @@ bool PlayerbotAI::CanCastVehicleSpell(uint32 spellId, Unit* target)
|
||||
if (!spellId)
|
||||
return false;
|
||||
|
||||
if (!IsValidUnit(target))
|
||||
return false;
|
||||
|
||||
Vehicle* vehicle = bot->GetVehicle();
|
||||
if (!vehicle)
|
||||
return false;
|
||||
@@ -3820,12 +3730,12 @@ bool PlayerbotAI::CanCastVehicleSpell(uint32 spellId, Unit* target)
|
||||
return false;
|
||||
|
||||
Unit* vehicleBase = vehicle->GetBase();
|
||||
Unit* spellTarget = target;
|
||||
|
||||
Unit* spellTarget = target;
|
||||
if (!spellTarget)
|
||||
spellTarget = vehicleBase;
|
||||
|
||||
if (!IsValidUnit(spellTarget))
|
||||
if (!spellTarget)
|
||||
return false;
|
||||
|
||||
if (vehicleBase->HasSpellCooldown(spellId))
|
||||
@@ -3892,9 +3802,6 @@ bool PlayerbotAI::CastVehicleSpell(uint32 spellId, Unit* target)
|
||||
if (!spellId)
|
||||
return false;
|
||||
|
||||
if (!IsValidUnit(target))
|
||||
return false;
|
||||
|
||||
Vehicle* vehicle = bot->GetVehicle();
|
||||
if (!vehicle)
|
||||
return false;
|
||||
@@ -3905,12 +3812,12 @@ bool PlayerbotAI::CastVehicleSpell(uint32 spellId, Unit* target)
|
||||
return false;
|
||||
|
||||
Unit* vehicleBase = vehicle->GetBase();
|
||||
Unit* spellTarget = target;
|
||||
|
||||
Unit* spellTarget = target;
|
||||
if (!spellTarget)
|
||||
spellTarget = vehicleBase;
|
||||
|
||||
if (!IsValidUnit(spellTarget))
|
||||
if (!spellTarget)
|
||||
return false;
|
||||
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
|
||||
@@ -4063,13 +3970,9 @@ bool PlayerbotAI::IsInVehicle(bool canControl, bool canCast, bool canAttack, boo
|
||||
|
||||
void PlayerbotAI::WaitForSpellCast(Spell* spell)
|
||||
{
|
||||
if (!spell)
|
||||
return;
|
||||
|
||||
SpellInfo const* spellInfo = spell->GetSpellInfo();
|
||||
uint32 castTime = spell->GetCastTime();
|
||||
|
||||
if (spellInfo && spellInfo->IsChanneled())
|
||||
if (spellInfo->IsChanneled())
|
||||
{
|
||||
int32 duration = spellInfo->GetDuration();
|
||||
bot->ApplySpellMod(spellInfo->Id, SPELLMOD_DURATION, duration);
|
||||
@@ -4117,9 +4020,6 @@ void PlayerbotAI::RemoveAura(std::string const name)
|
||||
|
||||
bool PlayerbotAI::IsInterruptableSpellCasting(Unit* target, std::string const spell)
|
||||
{
|
||||
if (!IsValidUnit(target))
|
||||
return false;
|
||||
|
||||
uint32 spellid = aiObjectContext->GetValue<uint32>("spell id", spell)->Get();
|
||||
if (!spellid || !target->IsNonMeleeSpellCast(true))
|
||||
return false;
|
||||
@@ -4148,25 +4048,17 @@ bool PlayerbotAI::IsInterruptableSpellCasting(Unit* target, std::string const sp
|
||||
|
||||
bool PlayerbotAI::HasAuraToDispel(Unit* target, uint32 dispelType)
|
||||
{
|
||||
if (!IsValidUnit(target) || !target->IsAlive())
|
||||
if (!target->IsInWorld())
|
||||
{
|
||||
return false;
|
||||
|
||||
if (!IsValidPlayer(bot))
|
||||
return false;
|
||||
|
||||
}
|
||||
bool isFriend = bot->IsFriendlyTo(target);
|
||||
|
||||
Unit::VisibleAuraMap const* visibleAuras = target->GetVisibleAuras();
|
||||
if (!visibleAuras)
|
||||
return false;
|
||||
|
||||
for (Unit::VisibleAuraMap::const_iterator itr = visibleAuras->begin(); itr != visibleAuras->end(); ++itr)
|
||||
{
|
||||
if (!itr->second)
|
||||
continue;
|
||||
|
||||
Aura* aura = itr->second->GetBase();
|
||||
if (!aura || aura->IsPassive() || aura->IsRemoved())
|
||||
|
||||
if (aura->IsPassive())
|
||||
continue;
|
||||
|
||||
if (sPlayerbotAIConfig->dispelAuraDuration && aura->GetDuration() &&
|
||||
@@ -4174,8 +4066,6 @@ bool PlayerbotAI::HasAuraToDispel(Unit* target, uint32 dispelType)
|
||||
continue;
|
||||
|
||||
SpellInfo const* spellInfo = aura->GetSpellInfo();
|
||||
if (!spellInfo)
|
||||
continue;
|
||||
|
||||
bool isPositiveSpell = spellInfo->IsPositive();
|
||||
if (isPositiveSpell && isFriend)
|
||||
@@ -4187,7 +4077,6 @@ bool PlayerbotAI::HasAuraToDispel(Unit* target, uint32 dispelType)
|
||||
if (canDispel(spellInfo, dispelType))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -5818,7 +5707,7 @@ void PlayerbotAI::ImbueItem(Item* item) { ImbueItem(item, TARGET_FLAG_NONE, Obje
|
||||
// item on unit
|
||||
void PlayerbotAI::ImbueItem(Item* item, Unit* target)
|
||||
{
|
||||
if (!IsValidUnit(target))
|
||||
if (!target)
|
||||
return;
|
||||
|
||||
ImbueItem(item, TARGET_FLAG_UNIT, target->GetGUID());
|
||||
@@ -5960,38 +5849,30 @@ int32 PlayerbotAI::GetNearGroupMemberCount(float dis)
|
||||
|
||||
bool PlayerbotAI::CanMove()
|
||||
{
|
||||
// Most common checks: confused, stunned, fleeing, jumping, charging. All these
|
||||
// states are set when handling certain aura effects. We don't check against
|
||||
// UNIT_STATE_ROOT here, because this state is used by vehicles.
|
||||
if (bot->HasUnitState(UNIT_STATE_LOST_CONTROL))
|
||||
// do not allow if not vehicle driver
|
||||
if (IsInVehicle() && !IsInVehicle(true))
|
||||
return false;
|
||||
|
||||
// Death state (w/o spirit release) and Spirit of Redemption aura (priest)
|
||||
if ((bot->isDead() && !bot->HasPlayerFlag(PLAYER_FLAGS_GHOST)) || bot->HasSpiritOfRedemptionAura())
|
||||
if (bot->isFrozen() || bot->IsPolymorphed() || (bot->isDead() && !bot->HasPlayerFlag(PLAYER_FLAGS_GHOST)) ||
|
||||
bot->IsBeingTeleported() || bot->HasRootAura() || bot->HasSpiritOfRedemptionAura() || bot->HasConfuseAura() ||
|
||||
bot->IsCharmed() || bot->HasStunAura() || bot->IsInFlight() || bot->HasUnitState(UNIT_STATE_LOST_CONTROL))
|
||||
return false;
|
||||
|
||||
// Common CC effects, ordered by frequency: rooted > charmed > frozen > polymorphed.
|
||||
// NOTE: Can't find proper way to check if bot is rooted or charmed w/o additional
|
||||
// vehicle check -- when a passenger is added, they become rooted and charmed.
|
||||
if (!bot->GetVehicle() && (bot->IsRooted() || bot->IsCharmed()))
|
||||
return bot->GetMotionMaster()->GetCurrentMovementGeneratorType() != FLIGHT_MOTION_TYPE;
|
||||
}
|
||||
|
||||
bool PlayerbotAI::IsRealGuild(uint32 guildId)
|
||||
{
|
||||
Guild* guild = sGuildMgr->GetGuildById(guildId);
|
||||
if (!guild)
|
||||
{
|
||||
return false;
|
||||
if (bot->isFrozen() || bot->IsPolymorphed())
|
||||
}
|
||||
uint32 leaderAccount = sCharacterCache->GetCharacterAccountIdByGuid(guild->GetLeaderGUID());
|
||||
if (!leaderAccount)
|
||||
return false;
|
||||
|
||||
// Check for the MM controlled slot types: feared, confused, fleeing, etc.
|
||||
if (bot->GetMotionMaster()->GetMotionSlotType(MOTION_SLOT_CONTROLLED) != NULL_MOTION_TYPE)
|
||||
return false;
|
||||
|
||||
// Traveling state: taxi flight and being teleported (relatively rare)
|
||||
if (bot->IsInFlight() || bot->GetMotionMaster()->GetCurrentMovementGeneratorType() == FLIGHT_MOTION_TYPE ||
|
||||
bot->IsBeingTeleported())
|
||||
return false;
|
||||
|
||||
// Vehicle state: is in the vehicle and can control it (rare, content-specific)
|
||||
if ((bot->GetVehicle() && !IsInVehicle(true)))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
return !(sPlayerbotAIConfig->IsInRandomAccountList(leaderAccount));
|
||||
}
|
||||
|
||||
bool PlayerbotAI::IsInRealGuild()
|
||||
@@ -5999,7 +5880,7 @@ bool PlayerbotAI::IsInRealGuild()
|
||||
if (!bot->GetGuildId())
|
||||
return false;
|
||||
|
||||
return sPlayerbotGuildMgr->IsRealGuild(bot->GetGuildId());
|
||||
return IsRealGuild(bot->GetGuildId());
|
||||
}
|
||||
|
||||
void PlayerbotAI::QueueChatResponse(const ChatQueuedReply chatReply) { chatReplies.push_back(std::move(chatReply)); }
|
||||
@@ -276,7 +276,7 @@ enum BotRoles : uint8
|
||||
|
||||
enum HUNTER_TABS
|
||||
{
|
||||
HUNTER_TAB_BEAST_MASTERY,
|
||||
HUNTER_TAB_BEASTMASTERY,
|
||||
HUNTER_TAB_MARKSMANSHIP,
|
||||
HUNTER_TAB_SURVIVAL,
|
||||
};
|
||||
@@ -295,11 +295,11 @@ enum PRIEST_TABS
|
||||
PRIEST_TAB_SHADOW,
|
||||
};
|
||||
|
||||
enum DEATH_KNIGHT_TABS
|
||||
enum DEATHKNIGHT_TABS
|
||||
{
|
||||
DEATH_KNIGHT_TAB_BLOOD,
|
||||
DEATH_KNIGHT_TAB_FROST,
|
||||
DEATH_KNIGHT_TAB_UNHOLY,
|
||||
DEATHKNIGHT_TAB_BLOOD,
|
||||
DEATHKNIGHT_TAB_FROST,
|
||||
DEATHKNIGHT_TAB_UNHOLY,
|
||||
};
|
||||
|
||||
enum DRUID_TABS
|
||||
@@ -429,8 +429,8 @@ public:
|
||||
static uint32 GetGroupTankNum(Player* player);
|
||||
static bool IsAssistTank(Player* player);
|
||||
static bool IsAssistTankOfIndex(Player* player, int index, bool ignoreDeadPlayers = false);
|
||||
static bool IsAssistHealOfIndex(Player* player, int index, bool ignoreDeadPlayers = false);
|
||||
static bool IsAssistRangedDpsOfIndex(Player* player, int index, bool ignoreDeadPlayers = false);
|
||||
static bool IsHealAssistantOfIndex(Player* player, int index);
|
||||
static bool IsRangedDpsAssistantOfIndex(Player* player, int index);
|
||||
bool HasAggro(Unit* unit);
|
||||
static int32 GetAssistTankIndex(Player* player);
|
||||
int32 GetGroupSlotIndex(Player* player);
|
||||
@@ -579,6 +579,7 @@ public:
|
||||
void ResetJumpDestination() { jumpDestination = Position(); }
|
||||
|
||||
bool CanMove();
|
||||
static bool IsRealGuild(uint32 guildId);
|
||||
bool IsInRealGuild();
|
||||
static std::vector<std::string> dispel_whitelist;
|
||||
bool EqualLowercaseName(std::string s1, std::string s2);
|
||||
@@ -616,15 +617,7 @@ private:
|
||||
void HandleCommands();
|
||||
void HandleCommand(uint32 type, const std::string& text, Player& fromPlayer, const uint32 lang = LANG_UNIVERSAL);
|
||||
bool _isBotInitializing = false;
|
||||
inline bool IsValidUnit(const Unit* unit) const
|
||||
{
|
||||
return unit && unit->IsInWorld() && !unit->IsDuringRemoveFromWorld();
|
||||
}
|
||||
inline bool IsValidPlayer(const Player* player) const
|
||||
{
|
||||
return player && player->GetSession() && player->IsInWorld() && !player->IsDuringRemoveFromWorld() &&
|
||||
!player->IsBeingTeleported();
|
||||
}
|
||||
|
||||
protected:
|
||||
Player* bot;
|
||||
Player* master;
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user