Compare commits

..

2 Commits

Author SHA1 Message Date
bash
6620def962 auto-format 2025-11-24 11:59:06 +01:00
bash
cddd406b1c removed movementAction changed made due core movement changes 2025-11-24 11:55:03 +01:00
1262 changed files with 15900 additions and 19974 deletions

View File

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

View File

@@ -1,127 +0,0 @@
# Pull Request
## Summary
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.

View File

@@ -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 #
@@ -665,12 +630,12 @@ AiPlayerbot.RandomBotHordeRatio = 50
AiPlayerbot.DisableDeathKnightLogin = 0
# Enable simulated expansion limitation for talents and glyphs
# If enabled, limits talent trees to 5 rows plus the middle talent of the 6th row for bots until level 61
# If enabled, limits talent trees to 5 rows plus the middle talent of the 6th row for bots until level 61
# and 7 rows plus the middle talent of the 8th row for bots from level 61 until level 71
# 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 = ""
@@ -1223,7 +1185,7 @@ AiPlayerbot.DeleteRandomBotArenaTeams = 0
AiPlayerbot.PvpProhibitedZoneIds = "2255,656,2361,2362,2363,976,35,2268,3425,392,541,1446,3828,3712,3738,3565,3539,3623,4152,3988,4658,4284,4418,4436,4275,4323,4395,3703,4298,3951"
# PvP Restricted Areas (bots don't pvp)
AiPlayerbot.PvpProhibitedAreaIds = "976,35,392,2268,4161,4010,4317,4312,3649,3887,3958,3724,4080,3938,3754,3786,3973"
AiPlayerbot.PvpProhibitedAreaIds = "976,35,392,2268,4161,4010,4317,4312,3649,3887,3958,3724,4080,3938,3754"
# Improve reaction speeds in battlegrounds and arenas (may cause lag)
AiPlayerbot.FastReactInBG = 1
@@ -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
#
#

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,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)}));
}

View File

@@ -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");
}

View File

@@ -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)
};
}

View File

@@ -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) {}

View File

@@ -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) }));
}

View File

@@ -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) }));
}

View File

@@ -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) }));
}

View File

@@ -1,37 +0,0 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
* and/or modify it under version 3 of the License, or (at your option), any later version.
*/
#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) }));
}

View File

@@ -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)
}
)
);
}

View File

@@ -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)
}
)
);
}

View File

@@ -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));
}

View File

@@ -1,20 +0,0 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
* and/or modify it under version 3 of the License, or (at your option), any later version.
*/
#include "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) }));
}

View File

@@ -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)
}
)
);
}

View File

@@ -1,37 +0,0 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
* and/or modify it under version 3 of the License, or (at your option), any later version.
*/
#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)
}
)
);
}

View File

@@ -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) }));
}

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,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)
}
)
);
}

View File

@@ -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)
}
)
);
}

View File

@@ -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)
}
)
);
}

View File

@@ -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)
}
)
);
}

View File

@@ -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)
}
)
);
}

View File

@@ -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) {}

View File

@@ -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"] = &thorns;
creators["thorns on party"] = &thorns_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"] = &regrowth_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),
}));
}

View File

@@ -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),
}));
}

View File

@@ -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) }));
}

View File

@@ -1,307 +0,0 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
* and/or modify it under version 3 of the License, or (at your option), any later version.
*/
#include "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"] = &regrowth_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)
}
)
);
}

View File

@@ -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)}));
}

View File

@@ -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) }));
}

View File

@@ -1,159 +0,0 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
* and/or modify it under version 3 of the License, or (at your option), any later version.
*/
#include "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)
}
)
);
}

View File

@@ -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)
}
)
);
}

View File

@@ -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) }));
}
}

View File

@@ -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)
}
)
);
}

View File

@@ -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),
}));
}

View File

@@ -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)
}
)
);
}

View File

@@ -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)
}
)
);
}

View File

@@ -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)
}
)
);
}

View File

@@ -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) }));
}

View File

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

View File

@@ -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)
}
)
);
}

View File

@@ -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)
}
)
);
}

View File

@@ -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) }));
}

View File

@@ -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)
}
)
);
}

View File

@@ -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),
}
)
);
}

View File

@@ -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)
}
)
);
}

View File

@@ -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)
}
)
);
}

View File

@@ -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);
}

View File

@@ -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)
}
)
);
}

View File

@@ -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)
}
)
);
}

View File

@@ -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)
}
)
);
}

View File

@@ -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) }));
}

View File

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

View File

@@ -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)
}
)
);
}

View File

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

View File

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

View File

@@ -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) }));
}

View File

@@ -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));
}

View File

@@ -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));
}

View File

@@ -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));
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,322 +0,0 @@
#ifndef _PLAYERBOT_RAIDKARAZHANACTIONS_H
#define _PLAYERBOT_RAIDKARAZHANACTIONS_H
#include "Action.h"
#include "AttackAction.h"
#include "MovementActions.h"
class ManaWarpStunCreatureBeforeWarpBreachAction : public AttackAction
{
public:
ManaWarpStunCreatureBeforeWarpBreachAction(
PlayerbotAI* botAI, std::string const name = "mana warp stun creature before warp breach") : AttackAction(botAI, name) {}
bool Execute(Event event) override;
};
class AttumenTheHuntsmanMarkTargetAction : public AttackAction
{
public:
AttumenTheHuntsmanMarkTargetAction(
PlayerbotAI* botAI, std::string const name = "attumen the huntsman mark target") : AttackAction(botAI, name) {}
bool Execute(Event event) override;
};
class AttumenTheHuntsmanSplitBossesAction : public AttackAction
{
public:
AttumenTheHuntsmanSplitBossesAction(
PlayerbotAI* botAI, std::string const name = "attumen the huntsman split bosses") : AttackAction(botAI, name) {}
bool Execute(Event event) override;
};
class AttumenTheHuntsmanStackBehindAction : public MovementAction
{
public:
AttumenTheHuntsmanStackBehindAction(
PlayerbotAI* botAI, std::string const name = "attumen the huntsman stack behind") : MovementAction(botAI, name) {}
bool Execute(Event event) override;
};
class AttumenTheHuntsmanManageDpsTimerAction : public Action
{
public:
AttumenTheHuntsmanManageDpsTimerAction(
PlayerbotAI* botAI, std::string const name = "attumen the huntsman manage dps timer") : Action(botAI, name) {}
bool Execute(Event event) override;
};
class MoroesMainTankAttackBossAction : public AttackAction
{
public:
MoroesMainTankAttackBossAction(
PlayerbotAI* botAI, std::string const name = "moroes main tank attack boss") : AttackAction(botAI, name) {}
bool Execute(Event event) override;
};
class MoroesMarkTargetAction : public Action
{
public:
MoroesMarkTargetAction(
PlayerbotAI* botAI, std::string const name = "moroes mark target") : Action(botAI, name) {}
bool Execute(Event event) override;
};
class MaidenOfVirtueMoveBossToHealerAction : public AttackAction
{
public:
MaidenOfVirtueMoveBossToHealerAction(
PlayerbotAI* botAI, std::string const name = "maiden of virtue move boss to healer") : AttackAction(botAI, name) {}
bool Execute(Event event) override;
};
class MaidenOfVirtuePositionRangedAction : public MovementAction
{
public:
MaidenOfVirtuePositionRangedAction(
PlayerbotAI* botAI, std::string const name = "maiden of virtue position ranged") : MovementAction(botAI, name) {}
bool Execute(Event event) override;
};
class BigBadWolfPositionBossAction : public AttackAction
{
public:
BigBadWolfPositionBossAction(
PlayerbotAI* botAI, std::string const name = "big bad wolf position boss") : AttackAction(botAI, name) {}
bool Execute(Event event) override;
};
class BigBadWolfRunAwayFromBossAction : public MovementAction
{
public:
BigBadWolfRunAwayFromBossAction(
PlayerbotAI* botAI, std::string const name = "big bad wolf run away from boss") : MovementAction(botAI, name) {}
bool Execute(Event event) override;
};
class RomuloAndJulianneMarkTargetAction : public Action
{
public:
RomuloAndJulianneMarkTargetAction(
PlayerbotAI* botAI, std::string const name = "romulo and julianne mark target") : Action(botAI, name) {}
bool Execute(Event event) override;
};
class WizardOfOzMarkTargetAction : public Action
{
public:
WizardOfOzMarkTargetAction(
PlayerbotAI* botAI, std::string const name = "wizard of oz mark target") : Action(botAI, name) {}
bool Execute(Event event) override;
};
class WizardOfOzScorchStrawmanAction : public Action
{
public:
WizardOfOzScorchStrawmanAction(
PlayerbotAI* botAI, std::string const name = "wizard of oz scorch strawman") : Action(botAI, name) {}
bool Execute(Event event) override;
};
class TheCuratorMarkAstralFlareAction : public Action
{
public:
TheCuratorMarkAstralFlareAction(
PlayerbotAI* botAI, std::string const name = "the curator mark astral flare") : Action(botAI, name) {}
bool Execute(Event event) override;
};
class TheCuratorPositionBossAction : public AttackAction
{
public:
TheCuratorPositionBossAction(
PlayerbotAI* botAI, std::string const name = "the curator position boss") : AttackAction(botAI, name) {}
bool Execute(Event event) override;
};
class TheCuratorSpreadRangedAction : public MovementAction
{
public:
TheCuratorSpreadRangedAction(
PlayerbotAI* botAI, std::string const name = "the curator spread ranged") : MovementAction(botAI, name) {}
bool Execute(Event event) override;
};
class TerestianIllhoofMarkTargetAction : public Action
{
public:
TerestianIllhoofMarkTargetAction(
PlayerbotAI* botAI, std::string const name = "terestian illhoof mark target") : Action(botAI, name) {}
bool Execute(Event event) override;
};
class ShadeOfAranRunAwayFromArcaneExplosionAction : public MovementAction
{
public:
ShadeOfAranRunAwayFromArcaneExplosionAction(
PlayerbotAI* botAI, std::string const name = "shade of aran run away from arcane explosion") : MovementAction(botAI, name) {}
bool Execute(Event event) override;
};
class ShadeOfAranStopMovingDuringFlameWreathAction : public MovementAction
{
public:
ShadeOfAranStopMovingDuringFlameWreathAction(
PlayerbotAI* botAI, std::string const name = "shade of aran stop moving during flame wreath") : MovementAction(botAI, name) {}
bool Execute(Event event) override;
};
class ShadeOfAranMarkConjuredElementalAction : public Action
{
public:
ShadeOfAranMarkConjuredElementalAction(
PlayerbotAI* botAI, std::string const name = "shade of aran mark conjured elemental") : Action(botAI, name) {}
bool Execute(Event event) override;
};
class ShadeOfAranRangedMaintainDistanceAction : public MovementAction
{
public:
ShadeOfAranRangedMaintainDistanceAction(
PlayerbotAI* botAI, std::string const name = "shade of aran ranged maintain distance") : MovementAction(botAI, name) {}
bool Execute(Event event) override;
};
class NetherspiteBlockRedBeamAction : public MovementAction
{
public:
NetherspiteBlockRedBeamAction(
PlayerbotAI* botAI, std::string const name = "netherspite block red beam") : MovementAction(botAI, name) {}
bool Execute(Event event) override;
private:
Position GetPositionOnBeam(Unit* netherspite, Unit* portal, float distanceFromBoss);
std::unordered_map<ObjectGuid, bool> _wasBlockingRedBeam;
};
class NetherspiteBlockBlueBeamAction : public MovementAction
{
public:
NetherspiteBlockBlueBeamAction(
PlayerbotAI* botAI, std::string const name = "netherspite block blue beam") : MovementAction(botAI, name) {}
bool Execute(Event event) override;
private:
std::unordered_map<ObjectGuid, bool> _wasBlockingBlueBeam;
};
class NetherspiteBlockGreenBeamAction : public MovementAction
{
public:
NetherspiteBlockGreenBeamAction(
PlayerbotAI* botAI, std::string const name = "netherspite block green beam") : MovementAction(botAI, name) {}
bool Execute(Event event) override;
private:
std::unordered_map<ObjectGuid, bool> _wasBlockingGreenBeam;
};
class NetherspiteAvoidBeamAndVoidZoneAction : public MovementAction
{
public:
NetherspiteAvoidBeamAndVoidZoneAction(
PlayerbotAI* botAI, std::string const name = "netherspite avoid beam and void zone") : MovementAction(botAI, name) {}
bool Execute(Event event) override;
private:
struct BeamAvoid
{
Unit* portal;
float minDist, maxDist;
};
bool IsAwayFromBeams(float x, float y, const std::vector<BeamAvoid>& beams, Unit* netherspite);
};
class NetherspiteBanishPhaseAvoidVoidZoneAction : public MovementAction
{
public:
NetherspiteBanishPhaseAvoidVoidZoneAction(
PlayerbotAI* botAI, std::string const name = "netherspite banish phase avoid void zone") : MovementAction(botAI, name) {}
bool Execute(Event event) override;
};
class NetherspiteManageTimersAndTrackersAction : public Action
{
public:
NetherspiteManageTimersAndTrackersAction(
PlayerbotAI* botAI, std::string const name = "netherspite manage timers and trackers") : Action(botAI, name) {}
bool Execute(Event event) override;
};
class PrinceMalchezaarEnfeebledAvoidHazardAction : public MovementAction
{
public:
PrinceMalchezaarEnfeebledAvoidHazardAction(
PlayerbotAI* botAI, std::string const name = "prince malchezaar enfeebled avoid hazard") : MovementAction(botAI, name) {}
bool Execute(Event event) override;
};
class PrinceMalchezaarNonTankAvoidInfernalAction : public MovementAction
{
public:
PrinceMalchezaarNonTankAvoidInfernalAction(
PlayerbotAI* botAI, std::string const name = "prince malchezaar non tank avoid infernal") : MovementAction(botAI, name) {}
bool Execute(Event event) override;
};
class PrinceMalchezaarMainTankMovementAction : public AttackAction
{
public:
PrinceMalchezaarMainTankMovementAction(
PlayerbotAI* botAI, std::string const name = "prince malchezaar main tank movement") : AttackAction(botAI, name) {}
bool Execute(Event event) override;
};
class NightbaneGroundPhasePositionBossAction : public AttackAction
{
public:
NightbaneGroundPhasePositionBossAction(
PlayerbotAI* botAI, std::string const name = "nightbane ground phase position boss") : AttackAction(botAI, name) {}
bool Execute(Event event) override;
};
class NightbaneGroundPhaseRotateRangedPositionsAction : public MovementAction
{
public:
NightbaneGroundPhaseRotateRangedPositionsAction(
PlayerbotAI* botAI, std::string const name = "nightbane ground phase rotate ranged positions") : MovementAction(botAI, name) {}
bool Execute(Event event) override;
};
class NightbaneCastFearWardOnMainTankAction : public Action
{
public:
NightbaneCastFearWardOnMainTankAction(
PlayerbotAI* botAI, std::string const name = "nightbane cast fear ward on main tank") : Action(botAI, name) {}
bool Execute(Event event) override;
};
class NightbaneControlPetAggressionAction : public Action
{
public:
NightbaneControlPetAggressionAction(
PlayerbotAI* botAI, std::string const name = "nightbane control pet aggression") : Action(botAI, name) {}
bool Execute(Event event) override;
};
class NightbaneFlightPhaseMovementAction : public MovementAction
{
public:
NightbaneFlightPhaseMovementAction(
PlayerbotAI* botAI, std::string const name = "nightbane flight phase movement") : MovementAction(botAI, name) {}
bool Execute(Event event) override;
};
class NightbaneManageTimersAndTrackersAction : public Action
{
public:
NightbaneManageTimersAndTrackersAction(
PlayerbotAI* botAI, std::string const name = "nightbane manage timers and trackers") : Action(botAI, name) {}
bool Execute(Event event) override;
};
#endif

View File

@@ -1,363 +0,0 @@
#include "RaidKarazhanMultipliers.h"
#include "RaidKarazhanActions.h"
#include "RaidKarazhanHelpers.h"
#include "AttackAction.h"
#include "ChooseTargetActions.h"
#include "DruidActions.h"
#include "FollowActions.h"
#include "GenericActions.h"
#include "HunterActions.h"
#include "MageActions.h"
#include "Playerbots.h"
#include "PriestActions.h"
#include "ReachTargetActions.h"
#include "RogueActions.h"
#include "ShamanActions.h"
using namespace KarazhanHelpers;
// Keep tanks from jumping back and forth between Attumen and Midnight
float AttumenTheHuntsmanDisableTankAssistMultiplier::GetValue(Action* action)
{
Unit* midnight = AI_VALUE2(Unit*, "find target", "midnight");
if (!midnight)
return 1.0f;
Unit* attumen = AI_VALUE2(Unit*, "find target", "attumen the huntsman");
if (!attumen)
return 1.0f;
if (bot->GetVictim() != nullptr && dynamic_cast<TankAssistAction*>(action))
return 0.0f;
return 1.0f;
}
// Try to get rid of jittering when bots are stacked behind Attumen
float AttumenTheHuntsmanStayStackedMultiplier::GetValue(Action* action)
{
Unit* attumenMounted = GetFirstAliveUnitByEntry(botAI, NPC_ATTUMEN_THE_HUNTSMAN_MOUNTED);
if (!attumenMounted)
return 1.0f;
if (!botAI->IsMainTank(bot) && attumenMounted->GetVictim() != bot)
{
if (dynamic_cast<CombatFormationMoveAction*>(action) ||
dynamic_cast<FleeAction*>(action) ||
dynamic_cast<CastBlinkBackAction*>(action) ||
dynamic_cast<CastDisengageAction*>(action) ||
dynamic_cast<CastReachTargetSpellAction*>(action))
return 0.0f;
}
return 1.0f;
}
// Give the main tank 8 seconds to grab aggro when Attumen mounts Midnight
// In reality it's shorter because it takes Attumen a few seconds to aggro after mounting
float AttumenTheHuntsmanWaitForDpsMultiplier::GetValue(Action* action)
{
Unit* attumenMounted = GetFirstAliveUnitByEntry(botAI, NPC_ATTUMEN_THE_HUNTSMAN_MOUNTED);
if (!attumenMounted)
return 1.0f;
const uint32 instanceId = attumenMounted->GetMap()->GetInstanceId();
const time_t now = std::time(nullptr);
const uint8 dpsWaitSeconds = 8;
auto it = attumenDpsWaitTimer.find(instanceId);
if (it == attumenDpsWaitTimer.end() || (now - it->second) < dpsWaitSeconds)
{
if (!botAI->IsMainTank(bot))
{
if (dynamic_cast<AttackAction*>(action) || (dynamic_cast<CastSpellAction*>(action) &&
!dynamic_cast<CastHealingSpellAction*>(action)))
return 0.0f;
}
}
return 1.0f;
}
// The assist tank should stay on the boss to be 2nd on aggro and tank Hateful Bolts
float TheCuratorDisableTankAssistMultiplier::GetValue(Action* action)
{
Unit* curator = AI_VALUE2(Unit*, "find target", "the curator");
if (!curator)
return 1.0f;
if (bot->GetVictim() != nullptr && dynamic_cast<TankAssistAction*>(action))
return 0.0f;
return 1.0f;
}
// Save Bloodlust/Heroism for Evocation (100% increased damage)
float TheCuratorDelayBloodlustAndHeroismMultiplier::GetValue(Action* action)
{
Unit* curator = AI_VALUE2(Unit*, "find target", "the curator");
if (!curator)
return 1.0f;
if (!curator->HasAura(SPELL_CURATOR_EVOCATION))
{
if (dynamic_cast<CastBloodlustAction*>(action) ||
dynamic_cast<CastHeroismAction*>(action))
return 0.0f;
}
return 1.0f;
}
// Don't charge back in when running from Arcane Explosion
float ShadeOfAranArcaneExplosionDisableChargeMultiplier::GetValue(Action* action)
{
Unit* aran = AI_VALUE2(Unit*, "find target", "shade of aran");
if (!aran)
return 1.0f;
if (aran->HasUnitState(UNIT_STATE_CASTING) &&
aran->FindCurrentSpellBySpellId(SPELL_ARCANE_EXPLOSION))
{
if (dynamic_cast<CastReachTargetSpellAction*>(action))
return 0.0f;
if (bot->GetDistance2d(aran) >= 20.0f)
{
if (dynamic_cast<CombatFormationMoveAction*>(action) ||
dynamic_cast<FleeAction*>(action) ||
dynamic_cast<FollowAction*>(action) ||
dynamic_cast<ReachTargetAction*>(action) ||
dynamic_cast<AvoidAoeAction*>(action))
return 0.0f;
}
}
return 1.0f;
}
// I will not move when Flame Wreath is cast or the raid blows up
float ShadeOfAranFlameWreathDisableMovementMultiplier::GetValue(Action* action)
{
Unit* aran = AI_VALUE2(Unit*, "find target", "shade of aran");
if (!aran)
return 1.0f;
if (IsFlameWreathActive(botAI, bot))
{
if (dynamic_cast<CombatFormationMoveAction*>(action) ||
dynamic_cast<FleeAction*>(action) ||
dynamic_cast<FollowAction*>(action) ||
dynamic_cast<ReachTargetAction*>(action) ||
dynamic_cast<AvoidAoeAction*>(action) ||
dynamic_cast<CastKillingSpreeAction*>(action) ||
dynamic_cast<CastBlinkBackAction*>(action) ||
dynamic_cast<CastDisengageAction*>(action) ||
dynamic_cast<CastReachTargetSpellAction*>(action))
return 0.0f;
}
return 1.0f;
}
// Try to rid of the jittering when blocking beams
float NetherspiteKeepBlockingBeamMultiplier::GetValue(Action* action)
{
Unit* netherspite = AI_VALUE2(Unit*, "find target", "netherspite");
if (!netherspite || netherspite->HasAura(SPELL_NETHERSPITE_BANISHED))
return 1.0f;
auto [redBlocker, greenBlocker, blueBlocker] = GetCurrentBeamBlockers(botAI, bot);
if (bot == redBlocker)
{
if (dynamic_cast<CombatFormationMoveAction*>(action))
return 0.0f;
}
if (bot == blueBlocker)
{
if (dynamic_cast<CombatFormationMoveAction*>(action) ||
dynamic_cast<ReachTargetAction*>(action))
return 0.0f;
}
if (bot == greenBlocker)
{
if (dynamic_cast<CombatFormationMoveAction*>(action) ||
dynamic_cast<ReachTargetAction*>(action) ||
dynamic_cast<FleeAction*>(action) ||
dynamic_cast<CastKillingSpreeAction*>(action) ||
dynamic_cast<CastReachTargetSpellAction*>(action))
return 0.0f;
}
return 1.0f;
}
// Give tanks 5 seconds to get aggro during phase transitions
float NetherspiteWaitForDpsMultiplier::GetValue(Action* action)
{
Unit* netherspite = AI_VALUE2(Unit*, "find target", "netherspite");
if (!netherspite || netherspite->HasAura(SPELL_NETHERSPITE_BANISHED))
return 1.0f;
const uint32 instanceId = netherspite->GetMap()->GetInstanceId();
const time_t now = std::time(nullptr);
const uint8 dpsWaitSeconds = 5;
auto it = netherspiteDpsWaitTimer.find(instanceId);
if (it == netherspiteDpsWaitTimer.end() || (now - it->second) < dpsWaitSeconds)
{
if (!botAI->IsTank(bot))
{
if (dynamic_cast<AttackAction*>(action) || (dynamic_cast<CastSpellAction*>(action) &&
!dynamic_cast<CastHealingSpellAction*>(action)))
return 0.0f;
}
}
return 1.0f;
}
// Disable standard "avoid aoe" strategy, which may interfere with scripted avoidance
float PrinceMalchezaarDisableAvoidAoeMultiplier::GetValue(Action* action)
{
Unit* malchezaar = AI_VALUE2(Unit*, "find target", "prince malchezaar");
if (!malchezaar)
return 1.0f;
if (dynamic_cast<AvoidAoeAction*>(action))
return 0.0f;
return 1.0f;
}
// Don't run back into Shadow Nova when Enfeebled
float PrinceMalchezaarEnfeebleKeepDistanceMultiplier::GetValue(Action* action)
{
Unit* malchezaar = AI_VALUE2(Unit*, "find target", "prince malchezaar");
if (!malchezaar)
return 1.0f;
if (bot->HasAura(SPELL_ENFEEBLE))
{
if (dynamic_cast<MovementAction*>(action) &&
!dynamic_cast<PrinceMalchezaarEnfeebledAvoidHazardAction*>(action))
return 0.0f;
}
return 1.0f;
}
// Wait until Phase 3 to use Bloodlust/Heroism
float PrinceMalchezaarDelayBloodlustAndHeroismMultiplier::GetValue(Action* action)
{
Unit* malchezaar = AI_VALUE2(Unit*, "find target", "prince malchezaar");
if (!malchezaar)
return 1.0f;
if (malchezaar->GetHealthPct() > 30.0f)
{
if (dynamic_cast<CastBloodlustAction*>(action) ||
dynamic_cast<CastHeroismAction*>(action))
return 0.0f;
}
return 1.0f;
}
// Pets tend to run out of bounds and cause skeletons to spawn off the map
// Pets also tend to pull adds from inside of the tower through the floor
// This multiplier DOES NOT impact Hunter and Warlock pets
// Hunter and Warlock pets are addressed in ControlPetAggressionAction
float NightbaneDisablePetsMultiplier::GetValue(Action* action)
{
Unit* nightbane = AI_VALUE2(Unit*, "find target", "nightbane");
if (!nightbane)
return 1.0f;
if (dynamic_cast<CastForceOfNatureAction*>(action) ||
dynamic_cast<CastFeralSpiritAction*>(action) ||
dynamic_cast<CastFireElementalTotemAction*>(action) ||
dynamic_cast<CastFireElementalTotemMeleeAction*>(action) ||
dynamic_cast<CastSummonWaterElementalAction*>(action) ||
dynamic_cast<CastShadowfiendAction*>(action))
return 0.0f;
if (nightbane->GetPositionZ() > NIGHTBANE_FLIGHT_Z)
{
if (dynamic_cast<PetAttackAction*>(action))
return 0.0f;
}
return 1.0f;
}
// Give the main tank 8 seconds to get aggro during phase transitions
float NightbaneWaitForDpsMultiplier::GetValue(Action* action)
{
Unit* nightbane = AI_VALUE2(Unit*, "find target", "nightbane");
if (!nightbane || nightbane->GetPositionZ() > NIGHTBANE_FLIGHT_Z)
return 1.0f;
const uint32 instanceId = nightbane->GetMap()->GetInstanceId();
const time_t now = std::time(nullptr);
const uint8 dpsWaitSeconds = 8;
auto it = nightbaneDpsWaitTimer.find(instanceId);
if (it == nightbaneDpsWaitTimer.end() || (now - it->second) < dpsWaitSeconds)
{
if (!botAI->IsMainTank(bot))
{
if (dynamic_cast<AttackAction*>(action) || (dynamic_cast<CastSpellAction*>(action) &&
!dynamic_cast<CastHealingSpellAction*>(action)))
return 0.0f;
}
}
return 1.0f;
}
// The "avoid aoe" strategy must be disabled for the main tank
// Otherwise, the main tank will spin Nightbane to avoid Charred Earth and wipe the raid
// It is also disabled for all bots during the flight phase
float NightbaneDisableAvoidAoeMultiplier::GetValue(Action* action)
{
Unit* nightbane = AI_VALUE2(Unit*, "find target", "nightbane");
if (!nightbane)
return 1.0f;
if (nightbane->GetPositionZ() > NIGHTBANE_FLIGHT_Z || botAI->IsMainTank(bot))
{
if (dynamic_cast<AvoidAoeAction*>(action))
return 0.0f;
}
return 1.0f;
}
// Disable some movement actions that conflict with the strategies
float NightbaneDisableMovementMultiplier::GetValue(Action* action)
{
Unit* nightbane = AI_VALUE2(Unit*, "find target", "nightbane");
if (!nightbane)
return 1.0f;
if (dynamic_cast<CastBlinkBackAction*>(action) ||
dynamic_cast<CastDisengageAction*>(action) ||
dynamic_cast<FleeAction*>(action))
return 0.0f;
// Disable CombatFormationMoveAction for all bots except:
// (1) main tank and (2) only during the ground phase, other melee
if (botAI->IsRanged(bot) ||
(botAI->IsMelee(bot) && !botAI->IsMainTank(bot) &&
nightbane->GetPositionZ() > NIGHTBANE_FLIGHT_Z))
{
if (dynamic_cast<CombatFormationMoveAction*>(action))
return 0.0f;
}
return 1.0f;
}

View File

@@ -1,134 +0,0 @@
#ifndef _PLAYERBOT_RAIDKARAZHANMULTIPLIERS_H
#define _PLAYERBOT_RAIDKARAZHANMULTIPLIERS_H
#include "Multiplier.h"
class AttumenTheHuntsmanDisableTankAssistMultiplier : public Multiplier
{
public:
AttumenTheHuntsmanDisableTankAssistMultiplier(
PlayerbotAI* botAI) : Multiplier(botAI, "attumen the huntsman disable tank assist multiplier") {}
virtual float GetValue(Action* action);
};
class AttumenTheHuntsmanStayStackedMultiplier : public Multiplier
{
public:
AttumenTheHuntsmanStayStackedMultiplier(
PlayerbotAI* botAI) : Multiplier(botAI, "attumen the huntsman stay stacked multiplier") {}
virtual float GetValue(Action* action);
};
class AttumenTheHuntsmanWaitForDpsMultiplier : public Multiplier
{
public:
AttumenTheHuntsmanWaitForDpsMultiplier(
PlayerbotAI* botAI) : Multiplier(botAI, "attumen the huntsman wait for dps multiplier") {}
virtual float GetValue(Action* action);
};
class TheCuratorDisableTankAssistMultiplier : public Multiplier
{
public:
TheCuratorDisableTankAssistMultiplier(
PlayerbotAI* botAI) : Multiplier(botAI, "the curator disable tank assist multiplier") {}
virtual float GetValue(Action* action);
};
class TheCuratorDelayBloodlustAndHeroismMultiplier : public Multiplier
{
public:
TheCuratorDelayBloodlustAndHeroismMultiplier(
PlayerbotAI* botAI) : Multiplier(botAI, "the curator delay bloodlust and heroism multiplier") {}
virtual float GetValue(Action* action);
};
class ShadeOfAranArcaneExplosionDisableChargeMultiplier : public Multiplier
{
public:
ShadeOfAranArcaneExplosionDisableChargeMultiplier(
PlayerbotAI* botAI) : Multiplier(botAI, "shade of aran arcane explosion disable charge multiplier") {}
virtual float GetValue(Action* action);
};
class ShadeOfAranFlameWreathDisableMovementMultiplier : public Multiplier
{
public:
ShadeOfAranFlameWreathDisableMovementMultiplier(
PlayerbotAI* botAI) : Multiplier(botAI, "shade of aran flame wreath disable movement multiplier") {}
virtual float GetValue(Action* action);
};
class NetherspiteKeepBlockingBeamMultiplier : public Multiplier
{
public:
NetherspiteKeepBlockingBeamMultiplier(
PlayerbotAI* botAI) : Multiplier(botAI, "netherspite keep blocking beam multiplier") {}
virtual float GetValue(Action* action);
};
class NetherspiteWaitForDpsMultiplier : public Multiplier
{
public:
NetherspiteWaitForDpsMultiplier(
PlayerbotAI* botAI) : Multiplier(botAI, "netherspite wait for dps multiplier") {}
virtual float GetValue(Action* action);
};
class PrinceMalchezaarDisableAvoidAoeMultiplier : public Multiplier
{
public:
PrinceMalchezaarDisableAvoidAoeMultiplier(
PlayerbotAI* botAI) : Multiplier(botAI, "prince malchezaar disable avoid aoe multiplier") {}
virtual float GetValue(Action* action);
};
class PrinceMalchezaarEnfeebleKeepDistanceMultiplier : public Multiplier
{
public:
PrinceMalchezaarEnfeebleKeepDistanceMultiplier(
PlayerbotAI* botAI) : Multiplier(botAI, "prince malchezaar enfeeble keep distance multiplier") {}
virtual float GetValue(Action* action);
};
class PrinceMalchezaarDelayBloodlustAndHeroismMultiplier : public Multiplier
{
public:
PrinceMalchezaarDelayBloodlustAndHeroismMultiplier(
PlayerbotAI* botAI) : Multiplier(botAI, "prince malchezaar delay bloodlust and heroism multiplier") {}
virtual float GetValue(Action* action);
};
class NightbaneDisablePetsMultiplier : public Multiplier
{
public:
NightbaneDisablePetsMultiplier(
PlayerbotAI* botAI) : Multiplier(botAI, "nightbane disable pets multiplier") {}
virtual float GetValue(Action* action);
};
class NightbaneWaitForDpsMultiplier : public Multiplier
{
public:
NightbaneWaitForDpsMultiplier(
PlayerbotAI* botAI) : Multiplier(botAI, "nightbane wait for dps multiplier") {}
virtual float GetValue(Action* action);
};
class NightbaneDisableAvoidAoeMultiplier : public Multiplier
{
public:
NightbaneDisableAvoidAoeMultiplier(
PlayerbotAI* botAI) : Multiplier(botAI, "nightbane disable avoid aoe multiplier") {}
virtual float GetValue(Action* action);
};
class NightbaneDisableMovementMultiplier : public Multiplier
{
public:
NightbaneDisableMovementMultiplier(
PlayerbotAI* botAI) : Multiplier(botAI, "nightbane disable movement multiplier") {}
virtual float GetValue(Action* action);
};
#endif

View File

@@ -1,263 +0,0 @@
#ifndef _PLAYERBOT_RAIDKARAZHANACTIONCONTEXT_H
#define _PLAYERBOT_RAIDKARAZHANACTIONCONTEXT_H
#include "RaidKarazhanActions.h"
#include "NamedObjectContext.h"
class RaidKarazhanActionContext : public NamedObjectContext<Action>
{
public:
RaidKarazhanActionContext()
{
// Trash
creators["mana warp stun creature before warp breach"] =
&RaidKarazhanActionContext::mana_warp_stun_creature_before_warp_breach;
// Attumen the Huntsman
creators["attumen the huntsman mark target"] =
&RaidKarazhanActionContext::attumen_the_huntsman_mark_target;
creators["attumen the huntsman split bosses"] =
&RaidKarazhanActionContext::attumen_the_huntsman_split_bosses;
creators["attumen the huntsman stack behind"] =
&RaidKarazhanActionContext::attumen_the_huntsman_stack_behind;
creators["attumen the huntsman manage dps timer"] =
&RaidKarazhanActionContext::attumen_the_huntsman_manage_dps_timer;
// Moroes
creators["moroes main tank attack boss"] =
&RaidKarazhanActionContext::moroes_main_tank_attack_boss;
creators["moroes mark target"] =
&RaidKarazhanActionContext::moroes_mark_target;
// Maiden of Virtue
creators["maiden of virtue move boss to healer"] =
&RaidKarazhanActionContext::maiden_of_virtue_move_boss_to_healer;
creators["maiden of virtue position ranged"] =
&RaidKarazhanActionContext::maiden_of_virtue_position_ranged;
// The Big Bad Wolf
creators["big bad wolf position boss"] =
&RaidKarazhanActionContext::big_bad_wolf_position_boss;
creators["big bad wolf run away from boss"] =
&RaidKarazhanActionContext::big_bad_wolf_run_away_from_boss;
// Romulo and Julianne
creators["romulo and julianne mark target"] =
&RaidKarazhanActionContext::romulo_and_julianne_mark_target;
// The Wizard of Oz
creators["wizard of oz mark target"] =
&RaidKarazhanActionContext::wizard_of_oz_mark_target;
creators["wizard of oz scorch strawman"] =
&RaidKarazhanActionContext::wizard_of_oz_scorch_strawman;
// The Curator
creators["the curator mark astral flare"] =
&RaidKarazhanActionContext::the_curator_mark_astral_flare;
creators["the curator position boss"] =
&RaidKarazhanActionContext::the_curator_position_boss;
creators["the curator spread ranged"] =
&RaidKarazhanActionContext::the_curator_spread_ranged;
// Terestian Illhoof
creators["terestian illhoof mark target"] =
&RaidKarazhanActionContext::terestian_illhoof_mark_target;
// Shade of Aran
creators["shade of aran run away from arcane explosion"] =
&RaidKarazhanActionContext::shade_of_aran_run_away_from_arcane_explosion;
creators["shade of aran stop moving during flame wreath"] =
&RaidKarazhanActionContext::shade_of_aran_stop_moving_during_flame_wreath;
creators["shade of aran mark conjured elemental"] =
&RaidKarazhanActionContext::shade_of_aran_mark_conjured_elemental;
creators["shade of aran ranged maintain distance"] =
&RaidKarazhanActionContext::shade_of_aran_ranged_maintain_distance;
// Netherspite
creators["netherspite block red beam"] =
&RaidKarazhanActionContext::netherspite_block_red_beam;
creators["netherspite block blue beam"] =
&RaidKarazhanActionContext::netherspite_block_blue_beam;
creators["netherspite block green beam"] =
&RaidKarazhanActionContext::netherspite_block_green_beam;
creators["netherspite avoid beam and void zone"] =
&RaidKarazhanActionContext::netherspite_avoid_beam_and_void_zone;
creators["netherspite banish phase avoid void zone"] =
&RaidKarazhanActionContext::netherspite_banish_phase_avoid_void_zone;
creators["netherspite manage timers and trackers"] =
&RaidKarazhanActionContext::netherspite_manage_timers_and_trackers;
// Prince Malchezaar
creators["prince malchezaar enfeebled avoid hazard"] =
&RaidKarazhanActionContext::prince_malchezaar_enfeebled_avoid_hazard;
creators["prince malchezaar non tank avoid infernal"] =
&RaidKarazhanActionContext::prince_malchezaar_non_tank_avoid_infernal;
creators["prince malchezaar main tank movement"] =
&RaidKarazhanActionContext::prince_malchezaar_main_tank_movement;
// Nightbane
creators["nightbane ground phase position boss"] =
&RaidKarazhanActionContext::nightbane_ground_phase_position_boss;
creators["nightbane ground phase rotate ranged positions"] =
&RaidKarazhanActionContext::nightbane_ground_phase_rotate_ranged_positions;
creators["nightbane cast fear ward on main tank"] =
&RaidKarazhanActionContext::nightbane_cast_fear_ward_on_main_tank;
creators["nightbane control pet aggression"] =
&RaidKarazhanActionContext::nightbane_control_pet_aggression;
creators["nightbane flight phase movement"] =
&RaidKarazhanActionContext::nightbane_flight_phase_movement;
creators["nightbane manage timers and trackers"] =
&RaidKarazhanActionContext::nightbane_manage_timers_and_trackers;
}
private:
// Trash
static Action* mana_warp_stun_creature_before_warp_breach(
PlayerbotAI* botAI) { return new ManaWarpStunCreatureBeforeWarpBreachAction(botAI); }
// Attumen the Huntsman
static Action* attumen_the_huntsman_mark_target(
PlayerbotAI* botAI) { return new AttumenTheHuntsmanMarkTargetAction(botAI); }
static Action* attumen_the_huntsman_split_bosses(
PlayerbotAI* botAI) { return new AttumenTheHuntsmanSplitBossesAction(botAI); }
static Action* attumen_the_huntsman_stack_behind(
PlayerbotAI* botAI) { return new AttumenTheHuntsmanStackBehindAction(botAI); }
static Action* attumen_the_huntsman_manage_dps_timer(
PlayerbotAI* botAI) { return new AttumenTheHuntsmanManageDpsTimerAction(botAI); }
// Moroes
static Action* moroes_main_tank_attack_boss(
PlayerbotAI* botAI) { return new MoroesMainTankAttackBossAction(botAI); }
static Action* moroes_mark_target(
PlayerbotAI* botAI) { return new MoroesMarkTargetAction(botAI); }
// Maiden of Virtue
static Action* maiden_of_virtue_move_boss_to_healer(
PlayerbotAI* botAI) { return new MaidenOfVirtueMoveBossToHealerAction(botAI); }
static Action* maiden_of_virtue_position_ranged(
PlayerbotAI* botAI) { return new MaidenOfVirtuePositionRangedAction(botAI); }
// The Big Bad Wolf
static Action* big_bad_wolf_position_boss(
PlayerbotAI* botAI) { return new BigBadWolfPositionBossAction(botAI); }
static Action* big_bad_wolf_run_away_from_boss(
PlayerbotAI* botAI) { return new BigBadWolfRunAwayFromBossAction(botAI); }
// Romulo and Julianne
static Action* romulo_and_julianne_mark_target(
PlayerbotAI* botAI) { return new RomuloAndJulianneMarkTargetAction(botAI); }
// The Wizard of Oz
static Action* wizard_of_oz_mark_target(
PlayerbotAI* botAI) { return new WizardOfOzMarkTargetAction(botAI); }
static Action* wizard_of_oz_scorch_strawman(
PlayerbotAI* botAI) { return new WizardOfOzScorchStrawmanAction(botAI); }
// The Curator
static Action* the_curator_mark_astral_flare(
PlayerbotAI* botAI) { return new TheCuratorMarkAstralFlareAction(botAI); }
static Action* the_curator_position_boss(
PlayerbotAI* botAI) { return new TheCuratorPositionBossAction(botAI); }
static Action* the_curator_spread_ranged(
PlayerbotAI* botAI) { return new TheCuratorSpreadRangedAction(botAI); }
// Terestian Illhoof
static Action* terestian_illhoof_mark_target(
PlayerbotAI* botAI) { return new TerestianIllhoofMarkTargetAction(botAI); }
// Shade of Aran
static Action* shade_of_aran_run_away_from_arcane_explosion(
PlayerbotAI* botAI) { return new ShadeOfAranRunAwayFromArcaneExplosionAction(botAI); }
static Action* shade_of_aran_stop_moving_during_flame_wreath(
PlayerbotAI* botAI) { return new ShadeOfAranStopMovingDuringFlameWreathAction(botAI); }
static Action* shade_of_aran_mark_conjured_elemental(
PlayerbotAI* botAI) { return new ShadeOfAranMarkConjuredElementalAction(botAI); }
static Action* shade_of_aran_ranged_maintain_distance(
PlayerbotAI* botAI) { return new ShadeOfAranRangedMaintainDistanceAction(botAI); }
// Netherspite
static Action* netherspite_block_red_beam(
PlayerbotAI* botAI) { return new NetherspiteBlockRedBeamAction(botAI); }
static Action* netherspite_block_blue_beam(
PlayerbotAI* botAI) { return new NetherspiteBlockBlueBeamAction(botAI); }
static Action* netherspite_block_green_beam(
PlayerbotAI* botAI) { return new NetherspiteBlockGreenBeamAction(botAI); }
static Action* netherspite_avoid_beam_and_void_zone(
PlayerbotAI* botAI) { return new NetherspiteAvoidBeamAndVoidZoneAction(botAI); }
static Action* netherspite_banish_phase_avoid_void_zone(
PlayerbotAI* botAI) { return new NetherspiteBanishPhaseAvoidVoidZoneAction(botAI); }
static Action* netherspite_manage_timers_and_trackers(
PlayerbotAI* botAI) { return new NetherspiteManageTimersAndTrackersAction(botAI); }
// Prince Malchezaar
static Action* prince_malchezaar_enfeebled_avoid_hazard(
PlayerbotAI* botAI) { return new PrinceMalchezaarEnfeebledAvoidHazardAction(botAI); }
static Action* prince_malchezaar_non_tank_avoid_infernal(
PlayerbotAI* botAI) { return new PrinceMalchezaarNonTankAvoidInfernalAction(botAI); }
static Action* prince_malchezaar_main_tank_movement(
PlayerbotAI* botAI) { return new PrinceMalchezaarMainTankMovementAction(botAI); }
// Nightbane
static Action* nightbane_ground_phase_position_boss(
PlayerbotAI* botAI) { return new NightbaneGroundPhasePositionBossAction(botAI); }
static Action* nightbane_ground_phase_rotate_ranged_positions(
PlayerbotAI* botAI) { return new NightbaneGroundPhaseRotateRangedPositionsAction(botAI); }
static Action* nightbane_cast_fear_ward_on_main_tank(
PlayerbotAI* botAI) { return new NightbaneCastFearWardOnMainTankAction(botAI); }
static Action* nightbane_control_pet_aggression(
PlayerbotAI* botAI) { return new NightbaneControlPetAggressionAction(botAI); }
static Action* nightbane_flight_phase_movement(
PlayerbotAI* botAI) { return new NightbaneFlightPhaseMovementAction(botAI); }
static Action* nightbane_manage_timers_and_trackers(
PlayerbotAI* botAI) { return new NightbaneManageTimersAndTrackersAction(botAI); }
};
#endif

View File

@@ -1,263 +0,0 @@
#ifndef _PLAYERBOT_RAIDKARAZHANTRIGGERCONTEXT_H
#define _PLAYERBOT_RAIDKARAZHANTRIGGERCONTEXT_H
#include "RaidKarazhanTriggers.h"
#include "AiObjectContext.h"
class RaidKarazhanTriggerContext : public NamedObjectContext<Trigger>
{
public:
RaidKarazhanTriggerContext()
{
// Trash
creators["mana warp is about to explode"] =
&RaidKarazhanTriggerContext::mana_warp_is_about_to_explode;
// Attumen the Huntsman
creators["attumen the huntsman need target priority"] =
&RaidKarazhanTriggerContext::attumen_the_huntsman_need_target_priority;
creators["attumen the huntsman attumen spawned"] =
&RaidKarazhanTriggerContext::attumen_the_huntsman_attumen_spawned;
creators["attumen the huntsman attumen is mounted"] =
&RaidKarazhanTriggerContext::attumen_the_huntsman_attumen_is_mounted;
creators["attumen the huntsman boss wipes aggro when mounting"] =
&RaidKarazhanTriggerContext::attumen_the_huntsman_boss_wipes_aggro_when_mounting;
// Moroes
creators["moroes boss engaged by main tank"] =
&RaidKarazhanTriggerContext::moroes_boss_engaged_by_main_tank;
creators["moroes need target priority"] =
&RaidKarazhanTriggerContext::moroes_need_target_priority;
// Maiden of Virtue
creators["maiden of virtue healers are stunned by repentance"] =
&RaidKarazhanTriggerContext::maiden_of_virtue_healers_are_stunned_by_repentance;
creators["maiden of virtue holy wrath deals chain damage"] =
&RaidKarazhanTriggerContext::maiden_of_virtue_holy_wrath_deals_chain_damage;
// The Big Bad Wolf
creators["big bad wolf boss engaged by tank"] =
&RaidKarazhanTriggerContext::big_bad_wolf_boss_engaged_by_tank;
creators["big bad wolf boss is chasing little red riding hood"] =
&RaidKarazhanTriggerContext::big_bad_wolf_boss_is_chasing_little_red_riding_hood;
// Romulo and Julianne
creators["romulo and julianne both bosses revived"] =
&RaidKarazhanTriggerContext::romulo_and_julianne_both_bosses_revived;
// The Wizard of Oz
creators["wizard of oz need target priority"] =
&RaidKarazhanTriggerContext::wizard_of_oz_need_target_priority;
creators["wizard of oz strawman is vulnerable to fire"] =
&RaidKarazhanTriggerContext::wizard_of_oz_strawman_is_vulnerable_to_fire;
// The Curator
creators["the curator astral flare spawned"] =
&RaidKarazhanTriggerContext::the_curator_astral_flare_spawned;
creators["the curator boss engaged by tanks"] =
&RaidKarazhanTriggerContext::the_curator_boss_engaged_by_tanks;
creators["the curator astral flares cast arcing sear"] =
&RaidKarazhanTriggerContext::the_curator_astral_flares_cast_arcing_sear;
// Terestian Illhoof
creators["terestian illhoof need target priority"] =
&RaidKarazhanTriggerContext::terestian_illhoof_need_target_priority;
// Shade of Aran
creators["shade of aran arcane explosion is casting"] =
&RaidKarazhanTriggerContext::shade_of_aran_arcane_explosion_is_casting;
creators["shade of aran flame wreath is active"] =
&RaidKarazhanTriggerContext::shade_of_aran_flame_wreath_is_active;
creators["shade of aran conjured elementals summoned"] =
&RaidKarazhanTriggerContext::shade_of_aran_conjured_elementals_summoned;
creators["shade of aran boss uses counterspell and blizzard"] =
&RaidKarazhanTriggerContext::shade_of_aran_boss_uses_counterspell_and_blizzard;
// Netherspite
creators["netherspite red beam is active"] =
&RaidKarazhanTriggerContext::netherspite_red_beam_is_active;
creators["netherspite blue beam is active"] =
&RaidKarazhanTriggerContext::netherspite_blue_beam_is_active;
creators["netherspite green beam is active"] =
&RaidKarazhanTriggerContext::netherspite_green_beam_is_active;
creators["netherspite bot is not beam blocker"] =
&RaidKarazhanTriggerContext::netherspite_bot_is_not_beam_blocker;
creators["netherspite boss is banished"] =
&RaidKarazhanTriggerContext::netherspite_boss_is_banished;
creators["netherspite need to manage timers and trackers"] =
&RaidKarazhanTriggerContext::netherspite_need_to_manage_timers_and_trackers;
// Prince Malchezaar
creators["prince malchezaar bot is enfeebled"] =
&RaidKarazhanTriggerContext::prince_malchezaar_bot_is_enfeebled;
creators["prince malchezaar infernals are spawned"] =
&RaidKarazhanTriggerContext::prince_malchezaar_infernals_are_spawned;
creators["prince malchezaar boss engaged by main tank"] =
&RaidKarazhanTriggerContext::prince_malchezaar_boss_engaged_by_main_tank;
// Nightbane
creators["nightbane boss engaged by main tank"] =
&RaidKarazhanTriggerContext::nightbane_boss_engaged_by_main_tank;
creators["nightbane ranged bots are in charred earth"] =
&RaidKarazhanTriggerContext::nightbane_ranged_bots_are_in_charred_earth;
creators["nightbane main tank is susceptible to fear"] =
&RaidKarazhanTriggerContext::nightbane_main_tank_is_susceptible_to_fear;
creators["nightbane pets ignore collision to chase flying boss"] =
&RaidKarazhanTriggerContext::nightbane_pets_ignore_collision_to_chase_flying_boss;
creators["nightbane boss is flying"] =
&RaidKarazhanTriggerContext::nightbane_boss_is_flying;
creators["nightbane need to manage timers and trackers"] =
&RaidKarazhanTriggerContext::nightbane_need_to_manage_timers_and_trackers;
}
private:
// Trash
static Trigger* mana_warp_is_about_to_explode(
PlayerbotAI* botAI) { return new ManaWarpIsAboutToExplodeTrigger(botAI); }
// Attumen the Huntsman
static Trigger* attumen_the_huntsman_need_target_priority(
PlayerbotAI* botAI) { return new AttumenTheHuntsmanNeedTargetPriorityTrigger(botAI); }
static Trigger* attumen_the_huntsman_attumen_spawned(
PlayerbotAI* botAI) { return new AttumenTheHuntsmanAttumenSpawnedTrigger(botAI); }
static Trigger* attumen_the_huntsman_attumen_is_mounted(
PlayerbotAI* botAI) { return new AttumenTheHuntsmanAttumenIsMountedTrigger(botAI); }
static Trigger* attumen_the_huntsman_boss_wipes_aggro_when_mounting(
PlayerbotAI* botAI) { return new AttumenTheHuntsmanBossWipesAggroWhenMountingTrigger(botAI); }
// Moroes
static Trigger* moroes_boss_engaged_by_main_tank(
PlayerbotAI* botAI) { return new MoroesBossEngagedByMainTankTrigger(botAI); }
static Trigger* moroes_need_target_priority(
PlayerbotAI* botAI) { return new MoroesNeedTargetPriorityTrigger(botAI); }
// Maiden of Virtue
static Trigger* maiden_of_virtue_healers_are_stunned_by_repentance(
PlayerbotAI* botAI) { return new MaidenOfVirtueHealersAreStunnedByRepentanceTrigger(botAI); }
static Trigger* maiden_of_virtue_holy_wrath_deals_chain_damage(
PlayerbotAI* botAI) { return new MaidenOfVirtueHolyWrathDealsChainDamageTrigger(botAI); }
// The Big Bad Wolf
static Trigger* big_bad_wolf_boss_engaged_by_tank(
PlayerbotAI* botAI) { return new BigBadWolfBossEngagedByTankTrigger(botAI); }
static Trigger* big_bad_wolf_boss_is_chasing_little_red_riding_hood(
PlayerbotAI* botAI) { return new BigBadWolfBossIsChasingLittleRedRidingHoodTrigger(botAI); }
// Romulo and Julianne
static Trigger* romulo_and_julianne_both_bosses_revived(
PlayerbotAI* botAI) { return new RomuloAndJulianneBothBossesRevivedTrigger(botAI); }
// The Wizard of Oz
static Trigger* wizard_of_oz_need_target_priority(
PlayerbotAI* botAI) { return new WizardOfOzNeedTargetPriorityTrigger(botAI); }
static Trigger* wizard_of_oz_strawman_is_vulnerable_to_fire(
PlayerbotAI* botAI) { return new WizardOfOzStrawmanIsVulnerableToFireTrigger(botAI); }
// The Curator
static Trigger* the_curator_astral_flare_spawned(
PlayerbotAI* botAI) { return new TheCuratorAstralFlareSpawnedTrigger(botAI); }
static Trigger* the_curator_boss_engaged_by_tanks(
PlayerbotAI* botAI) { return new TheCuratorBossEngagedByTanksTrigger(botAI); }
static Trigger* the_curator_astral_flares_cast_arcing_sear(
PlayerbotAI* botAI) { return new TheCuratorBossAstralFlaresCastArcingSearTrigger(botAI); }
// Terestian Illhoof
static Trigger* terestian_illhoof_need_target_priority(
PlayerbotAI* botAI) { return new TerestianIllhoofNeedTargetPriorityTrigger(botAI); }
// Shade of Aran
static Trigger* shade_of_aran_arcane_explosion_is_casting(
PlayerbotAI* botAI) { return new ShadeOfAranArcaneExplosionIsCastingTrigger(botAI); }
static Trigger* shade_of_aran_flame_wreath_is_active(
PlayerbotAI* botAI) { return new ShadeOfAranFlameWreathIsActiveTrigger(botAI); }
static Trigger* shade_of_aran_conjured_elementals_summoned(
PlayerbotAI* botAI) { return new ShadeOfAranConjuredElementalsSummonedTrigger(botAI); }
static Trigger* shade_of_aran_boss_uses_counterspell_and_blizzard(
PlayerbotAI* botAI) { return new ShadeOfAranBossUsesCounterspellAndBlizzardTrigger(botAI); }
// Netherspite
static Trigger* netherspite_red_beam_is_active(
PlayerbotAI* botAI) { return new NetherspiteRedBeamIsActiveTrigger(botAI); }
static Trigger* netherspite_blue_beam_is_active(
PlayerbotAI* botAI) { return new NetherspiteBlueBeamIsActiveTrigger(botAI); }
static Trigger* netherspite_green_beam_is_active(
PlayerbotAI* botAI) { return new NetherspiteGreenBeamIsActiveTrigger(botAI); }
static Trigger* netherspite_bot_is_not_beam_blocker(
PlayerbotAI* botAI) { return new NetherspiteBotIsNotBeamBlockerTrigger(botAI); }
static Trigger* netherspite_boss_is_banished(
PlayerbotAI* botAI) { return new NetherspiteBossIsBanishedTrigger(botAI); }
static Trigger* netherspite_need_to_manage_timers_and_trackers(
PlayerbotAI* botAI) { return new NetherspiteNeedToManageTimersAndTrackersTrigger(botAI); }
// Prince Malchezaar
static Trigger* prince_malchezaar_bot_is_enfeebled(
PlayerbotAI* botAI) { return new PrinceMalchezaarBotIsEnfeebledTrigger(botAI); }
static Trigger* prince_malchezaar_infernals_are_spawned(
PlayerbotAI* botAI) { return new PrinceMalchezaarInfernalsAreSpawnedTrigger(botAI); }
static Trigger* prince_malchezaar_boss_engaged_by_main_tank(
PlayerbotAI* botAI) { return new PrinceMalchezaarBossEngagedByMainTankTrigger(botAI); }
// Nightbane
static Trigger* nightbane_boss_engaged_by_main_tank(
PlayerbotAI* botAI) { return new NightbaneBossEngagedByMainTankTrigger(botAI); }
static Trigger* nightbane_ranged_bots_are_in_charred_earth(
PlayerbotAI* botAI) { return new NightbaneRangedBotsAreInCharredEarthTrigger(botAI); }
static Trigger* nightbane_main_tank_is_susceptible_to_fear(
PlayerbotAI* botAI) { return new NightbaneMainTankIsSusceptibleToFearTrigger(botAI); }
static Trigger* nightbane_pets_ignore_collision_to_chase_flying_boss(
PlayerbotAI* botAI) { return new NightbanePetsIgnoreCollisionToChaseFlyingBossTrigger(botAI); }
static Trigger* nightbane_boss_is_flying(
PlayerbotAI* botAI) { return new NightbaneBossIsFlyingTrigger(botAI); }
static Trigger* nightbane_need_to_manage_timers_and_trackers(
PlayerbotAI* botAI) { return new NightbaneNeedToManageTimersAndTrackersTrigger(botAI); }
};
#endif

View File

@@ -1,162 +0,0 @@
#include "RaidKarazhanStrategy.h"
#include "RaidKarazhanMultipliers.h"
void RaidKarazhanStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
// Trash
triggers.push_back(new TriggerNode("mana warp is about to explode",
{ NextAction("mana warp stun creature before warp breach", ACTION_EMERGENCY + 6) }
));
// Attumen the Huntsman
triggers.push_back(new TriggerNode("attumen the huntsman need target priority",
{ NextAction("attumen the huntsman mark target", ACTION_RAID + 1) }
));
triggers.push_back(new TriggerNode("attumen the huntsman attumen spawned",
{ NextAction("attumen the huntsman split bosses", ACTION_RAID + 2) }
));
triggers.push_back(new TriggerNode("attumen the huntsman attumen is mounted",
{ NextAction("attumen the huntsman stack behind", ACTION_RAID + 1) }
));
triggers.push_back(new TriggerNode("attumen the huntsman boss wipes aggro when mounting",
{ NextAction("attumen the huntsman manage dps timer", ACTION_RAID + 2) }
));
// Moroes
triggers.push_back(new TriggerNode("moroes boss engaged by main tank",
{ NextAction("moroes main tank attack boss", ACTION_RAID + 1) }
));
triggers.push_back(new TriggerNode("moroes need target priority",
{ NextAction("moroes mark target", ACTION_RAID + 1) }
));
// Maiden of Virtue
triggers.push_back(new TriggerNode("maiden of virtue healers are stunned by repentance",
{ NextAction("maiden of virtue move boss to healer", ACTION_RAID + 1) }
));
triggers.push_back(new TriggerNode("maiden of virtue holy wrath deals chain damage",
{ NextAction("maiden of virtue position ranged", ACTION_RAID + 1) }
));
// The Big Bad Wolf
triggers.push_back(new TriggerNode("big bad wolf boss is chasing little red riding hood",
{ NextAction("big bad wolf run away from boss", ACTION_EMERGENCY + 6) }
));
triggers.push_back(new TriggerNode("big bad wolf boss engaged by tank",
{ NextAction("big bad wolf position boss", ACTION_RAID + 1) }
));
// Romulo and Julianne
triggers.push_back(new TriggerNode("romulo and julianne both bosses revived",
{ NextAction("romulo and julianne mark target", ACTION_RAID + 1) }
));
// The Wizard of Oz
triggers.push_back(new TriggerNode("wizard of oz need target priority",
{ NextAction("wizard of oz mark target", ACTION_RAID + 1) }
));
triggers.push_back(new TriggerNode("wizard of oz strawman is vulnerable to fire",
{ NextAction("wizard of oz scorch strawman", ACTION_RAID + 2) }
));
// The Curator
triggers.push_back(new TriggerNode("the curator astral flare spawned",
{ NextAction("the curator mark astral flare", ACTION_RAID + 1) }
));
triggers.push_back(new TriggerNode("the curator boss engaged by tanks",
{ NextAction("the curator position boss", ACTION_RAID + 2) }
));
triggers.push_back(new TriggerNode("the curator astral flares cast arcing sear",
{ NextAction("the curator spread ranged", ACTION_RAID + 2) }
));
// Terestian Illhoof
triggers.push_back(new TriggerNode("terestian illhoof need target priority",
{ NextAction("terestian illhoof mark target", ACTION_RAID + 1) }
));
// Shade of Aran
triggers.push_back(new TriggerNode("shade of aran arcane explosion is casting",
{ NextAction("shade of aran run away from arcane explosion", ACTION_EMERGENCY + 6) }
));
triggers.push_back(new TriggerNode("shade of aran flame wreath is active",
{ NextAction("shade of aran stop moving during flame wreath", ACTION_EMERGENCY + 7) }
));
triggers.push_back(new TriggerNode("shade of aran conjured elementals summoned",
{ NextAction("shade of aran mark conjured elemental", ACTION_RAID + 1) }
));
triggers.push_back(new TriggerNode("shade of aran boss uses counterspell and blizzard",
{ NextAction("shade of aran ranged maintain distance", ACTION_RAID + 2) }
));
// Netherspite
triggers.push_back(new TriggerNode("netherspite red beam is active",
{ NextAction("netherspite block red beam", ACTION_EMERGENCY + 8) }
));
triggers.push_back(new TriggerNode("netherspite blue beam is active",
{ NextAction("netherspite block blue beam", ACTION_EMERGENCY + 8) }
));
triggers.push_back(new TriggerNode("netherspite green beam is active",
{ NextAction("netherspite block green beam", ACTION_EMERGENCY + 8) }
));
triggers.push_back(new TriggerNode("netherspite bot is not beam blocker",
{ NextAction("netherspite avoid beam and void zone", ACTION_EMERGENCY + 7) }
));
triggers.push_back(new TriggerNode("netherspite boss is banished",
{ NextAction("netherspite banish phase avoid void zone", ACTION_RAID + 1) }
));
triggers.push_back(new TriggerNode("netherspite need to manage timers and trackers",
{ NextAction("netherspite manage timers and trackers", ACTION_EMERGENCY + 10) }
));
// Prince Malchezaar
triggers.push_back(new TriggerNode("prince malchezaar bot is enfeebled",
{ NextAction("prince malchezaar enfeebled avoid hazard", ACTION_EMERGENCY + 6) }
));
triggers.push_back(new TriggerNode("prince malchezaar infernals are spawned",
{ NextAction("prince malchezaar non tank avoid infernal", ACTION_EMERGENCY + 1) }
));
triggers.push_back(new TriggerNode("prince malchezaar boss engaged by main tank",
{ NextAction("prince malchezaar main tank movement", ACTION_EMERGENCY + 6) }
));
// Nightbane
triggers.push_back(new TriggerNode("nightbane boss engaged by main tank",
{ NextAction("nightbane ground phase position boss", ACTION_RAID + 1) }
));
triggers.push_back(new TriggerNode("nightbane ranged bots are in charred earth",
{ NextAction("nightbane ground phase rotate ranged positions", ACTION_EMERGENCY + 1) }
));
triggers.push_back(new TriggerNode("nightbane main tank is susceptible to fear",
{ NextAction("nightbane cast fear ward on main tank", ACTION_RAID + 2) }
));
triggers.push_back(new TriggerNode("nightbane pets ignore collision to chase flying boss",
{ NextAction("nightbane control pet aggression", ACTION_RAID + 2) }
));
triggers.push_back(new TriggerNode("nightbane boss is flying",
{ NextAction("nightbane flight phase movement", ACTION_RAID + 1) }
));
triggers.push_back(new TriggerNode("nightbane need to manage timers and trackers",
{ NextAction("nightbane manage timers and trackers", ACTION_EMERGENCY + 10) }
));
}
void RaidKarazhanStrategy::InitMultipliers(std::vector<Multiplier*>& multipliers)
{
multipliers.push_back(new AttumenTheHuntsmanDisableTankAssistMultiplier(botAI));
multipliers.push_back(new AttumenTheHuntsmanStayStackedMultiplier(botAI));
multipliers.push_back(new AttumenTheHuntsmanWaitForDpsMultiplier(botAI));
multipliers.push_back(new TheCuratorDisableTankAssistMultiplier(botAI));
multipliers.push_back(new TheCuratorDelayBloodlustAndHeroismMultiplier(botAI));
multipliers.push_back(new ShadeOfAranArcaneExplosionDisableChargeMultiplier(botAI));
multipliers.push_back(new ShadeOfAranFlameWreathDisableMovementMultiplier(botAI));
multipliers.push_back(new NetherspiteKeepBlockingBeamMultiplier(botAI));
multipliers.push_back(new NetherspiteWaitForDpsMultiplier(botAI));
multipliers.push_back(new PrinceMalchezaarDisableAvoidAoeMultiplier(botAI));
multipliers.push_back(new PrinceMalchezaarEnfeebleKeepDistanceMultiplier(botAI));
multipliers.push_back(new PrinceMalchezaarDelayBloodlustAndHeroismMultiplier(botAI));
multipliers.push_back(new NightbaneDisablePetsMultiplier(botAI));
multipliers.push_back(new NightbaneWaitForDpsMultiplier(botAI));
multipliers.push_back(new NightbaneDisableAvoidAoeMultiplier(botAI));
multipliers.push_back(new NightbaneDisableMovementMultiplier(botAI));
}

View File

@@ -1,385 +0,0 @@
#include "RaidKarazhanTriggers.h"
#include "RaidKarazhanHelpers.h"
#include "RaidKarazhanActions.h"
#include "Playerbots.h"
using namespace KarazhanHelpers;
bool ManaWarpIsAboutToExplodeTrigger::IsActive()
{
Unit* manaWarp = AI_VALUE2(Unit*, "find target", "mana warp");
return manaWarp && manaWarp->GetHealthPct() < 15;
}
bool AttumenTheHuntsmanNeedTargetPriorityTrigger::IsActive()
{
if (botAI->IsHeal(bot))
return false;
Unit* midnight = AI_VALUE2(Unit*, "find target", "midnight");
return midnight != nullptr;
}
bool AttumenTheHuntsmanAttumenSpawnedTrigger::IsActive()
{
if (!botAI->IsAssistTankOfIndex(bot, 0))
return false;
Unit* attumen = GetFirstAliveUnitByEntry(botAI, NPC_ATTUMEN_THE_HUNTSMAN);
return attumen != nullptr;
}
bool AttumenTheHuntsmanAttumenIsMountedTrigger::IsActive()
{
if (botAI->IsMainTank(bot))
return false;
Unit* attumenMounted = GetFirstAliveUnitByEntry(botAI, NPC_ATTUMEN_THE_HUNTSMAN_MOUNTED);
return attumenMounted && attumenMounted->GetVictim() != bot;
}
bool AttumenTheHuntsmanBossWipesAggroWhenMountingTrigger::IsActive()
{
if (!IsInstanceTimerManager(botAI, bot))
return false;
Unit* midnight = AI_VALUE2(Unit*, "find target", "midnight");
return midnight != nullptr;
}
bool MoroesBossEngagedByMainTankTrigger::IsActive()
{
if (!botAI->IsMainTank(bot))
return false;
Unit* moroes = AI_VALUE2(Unit*, "find target", "moroes");
return moroes != nullptr;
}
bool MoroesNeedTargetPriorityTrigger::IsActive()
{
if (!botAI->IsDps(bot))
return false;
Unit* dorothea = AI_VALUE2(Unit*, "find target", "baroness dorothea millstipe");
Unit* catriona = AI_VALUE2(Unit*, "find target", "lady catriona von'indi");
Unit* keira = AI_VALUE2(Unit*, "find target", "lady keira berrybuck");
Unit* rafe = AI_VALUE2(Unit*, "find target", "baron rafe dreuger");
Unit* robin = AI_VALUE2(Unit*, "find target", "lord robin daris");
Unit* crispin = AI_VALUE2(Unit*, "find target", "lord crispin ference");
Unit* target = GetFirstAliveUnit({ dorothea, catriona, keira, rafe, robin, crispin });
return target != nullptr;
}
bool MaidenOfVirtueHealersAreStunnedByRepentanceTrigger::IsActive()
{
if (!botAI->IsTank(bot))
return false;
Unit* maiden = AI_VALUE2(Unit*, "find target", "maiden of virtue");
return maiden && maiden->GetVictim() == bot;
}
bool MaidenOfVirtueHolyWrathDealsChainDamageTrigger::IsActive()
{
if (!botAI->IsRanged(bot))
return false;
Unit* maiden = AI_VALUE2(Unit*, "find target", "maiden of virtue");
return maiden != nullptr;
}
bool BigBadWolfBossEngagedByTankTrigger::IsActive()
{
if (!botAI->IsTank(bot) || bot->HasAura(SPELL_LITTLE_RED_RIDING_HOOD))
return false;
Unit* wolf = AI_VALUE2(Unit*, "find target", "the big bad wolf");
return wolf != nullptr;
}
bool BigBadWolfBossIsChasingLittleRedRidingHoodTrigger::IsActive()
{
if (!bot->HasAura(SPELL_LITTLE_RED_RIDING_HOOD))
return false;
Unit* wolf = AI_VALUE2(Unit*, "find target", "the big bad wolf");
return wolf != nullptr;
}
bool RomuloAndJulianneBothBossesRevivedTrigger::IsActive()
{
if (!IsInstanceTimerManager(botAI, bot))
return false;
Unit* romulo = AI_VALUE2(Unit*, "find target", "romulo");
if (!romulo)
return false;
Unit* julianne = AI_VALUE2(Unit*, "find target", "julianne");
if (!julianne)
return false;
return true;
}
bool WizardOfOzNeedTargetPriorityTrigger::IsActive()
{
if (!IsInstanceTimerManager(botAI, bot))
return false;
Unit* dorothee = AI_VALUE2(Unit*, "find target", "dorothee");
Unit* tito = AI_VALUE2(Unit*, "find target", "tito");
Unit* roar = AI_VALUE2(Unit*, "find target", "roar");
Unit* strawman = AI_VALUE2(Unit*, "find target", "strawman");
Unit* tinhead = AI_VALUE2(Unit*, "find target", "tinhead");
Unit* crone = AI_VALUE2(Unit*, "find target", "the crone");
Unit* target = GetFirstAliveUnit({ dorothee, tito, roar, strawman, tinhead, crone });
return target != nullptr;
}
bool WizardOfOzStrawmanIsVulnerableToFireTrigger::IsActive()
{
if (bot->getClass() != CLASS_MAGE)
return false;
Unit* strawman = AI_VALUE2(Unit*, "find target", "strawman");
return strawman && strawman->IsAlive();
}
bool TheCuratorAstralFlareSpawnedTrigger::IsActive()
{
if (!botAI->IsDps(bot))
return false;
Unit* flare = AI_VALUE2(Unit*, "find target", "astral flare");
return flare != nullptr;
}
bool TheCuratorBossEngagedByTanksTrigger::IsActive()
{
if (!botAI->IsMainTank(bot) && !botAI->IsAssistTankOfIndex(bot, 0))
return false;
Unit* curator = AI_VALUE2(Unit*, "find target", "the curator");
return curator != nullptr;
}
bool TheCuratorBossAstralFlaresCastArcingSearTrigger::IsActive()
{
if (!botAI->IsRanged(bot))
return false;
Unit* curator = AI_VALUE2(Unit*, "find target", "the curator");
return curator != nullptr;
}
bool TerestianIllhoofNeedTargetPriorityTrigger::IsActive()
{
if (!IsInstanceTimerManager(botAI, bot))
return false;
Unit* illhoof = AI_VALUE2(Unit*, "find target", "terestian illhoof");
return illhoof != nullptr;
}
bool ShadeOfAranArcaneExplosionIsCastingTrigger::IsActive()
{
Unit* aran = AI_VALUE2(Unit*, "find target", "shade of aran");
return aran && aran->HasUnitState(UNIT_STATE_CASTING) &&
aran->FindCurrentSpellBySpellId(SPELL_ARCANE_EXPLOSION) &&
!IsFlameWreathActive(botAI, bot);
}
bool ShadeOfAranFlameWreathIsActiveTrigger::IsActive()
{
Unit* aran = AI_VALUE2(Unit*, "find target", "shade of aran");
return aran && IsFlameWreathActive(botAI, bot);
}
// Exclusion of Banish is so the player may Banish elementals if they wish
bool ShadeOfAranConjuredElementalsSummonedTrigger::IsActive()
{
if (!IsInstanceTimerManager(botAI, bot))
return false;
Unit* elemental = AI_VALUE2(Unit*, "find target", "conjured elemental");
return elemental && elemental->IsAlive() &&
!elemental->HasAura(SPELL_WARLOCK_BANISH);
}
bool ShadeOfAranBossUsesCounterspellAndBlizzardTrigger::IsActive()
{
if (!botAI->IsRanged(bot))
return false;
Unit* aran = AI_VALUE2(Unit*, "find target", "shade of aran");
return aran && !(aran->HasUnitState(UNIT_STATE_CASTING) &&
aran->FindCurrentSpellBySpellId(SPELL_ARCANE_EXPLOSION)) &&
!IsFlameWreathActive(botAI, bot);
}
bool NetherspiteRedBeamIsActiveTrigger::IsActive()
{
Unit* netherspite = AI_VALUE2(Unit*, "find target", "netherspite");
if (!netherspite || netherspite->HasAura(SPELL_NETHERSPITE_BANISHED))
return false;
Unit* redPortal = bot->FindNearestCreature(NPC_RED_PORTAL, 150.0f);
return redPortal != nullptr;
}
bool NetherspiteBlueBeamIsActiveTrigger::IsActive()
{
Unit* netherspite = AI_VALUE2(Unit*, "find target", "netherspite");
if (!netherspite || netherspite->HasAura(SPELL_NETHERSPITE_BANISHED))
return false;
Unit* bluePortal = bot->FindNearestCreature(NPC_BLUE_PORTAL, 150.0f);
return bluePortal != nullptr;
}
bool NetherspiteGreenBeamIsActiveTrigger::IsActive()
{
Unit* netherspite = AI_VALUE2(Unit*, "find target", "netherspite");
if (!netherspite || netherspite->HasAura(SPELL_NETHERSPITE_BANISHED))
return false;
Unit* greenPortal = bot->FindNearestCreature(NPC_GREEN_PORTAL, 150.0f);
return greenPortal != nullptr;
}
bool NetherspiteBotIsNotBeamBlockerTrigger::IsActive()
{
Unit* netherspite = AI_VALUE2(Unit*, "find target", "netherspite");
if (!netherspite || netherspite->HasAura(SPELL_NETHERSPITE_BANISHED))
return false;
auto [redBlocker, greenBlocker, blueBlocker] = GetCurrentBeamBlockers(botAI, bot);
return bot != redBlocker && bot != blueBlocker && bot != greenBlocker;
}
bool NetherspiteBossIsBanishedTrigger::IsActive()
{
Unit* netherspite = AI_VALUE2(Unit*, "find target", "netherspite");
if (!netherspite || !netherspite->HasAura(SPELL_NETHERSPITE_BANISHED))
return false;
std::vector<Unit*> voidZones = GetAllVoidZones(botAI, bot);
for (Unit* vz : voidZones)
{
if (bot->GetExactDist2d(vz) < 4.0f)
return true;
}
return false;
}
bool NetherspiteNeedToManageTimersAndTrackersTrigger::IsActive()
{
if (!botAI->IsTank(bot) && !IsInstanceTimerManager(botAI, bot))
return false;
Unit* netherspite = AI_VALUE2(Unit*, "find target", "netherspite");
return netherspite != nullptr;
}
bool PrinceMalchezaarBotIsEnfeebledTrigger::IsActive()
{
return bot->HasAura(SPELL_ENFEEBLE);
}
bool PrinceMalchezaarInfernalsAreSpawnedTrigger::IsActive()
{
if (botAI->IsMainTank(bot) || bot->HasAura(SPELL_ENFEEBLE))
return false;
Unit* malchezaar = AI_VALUE2(Unit*, "find target", "prince malchezaar");
return malchezaar != nullptr;
}
bool PrinceMalchezaarBossEngagedByMainTankTrigger::IsActive()
{
if (!botAI->IsMainTank(bot))
return false;
Unit* malchezaar = AI_VALUE2(Unit*, "find target", "prince malchezaar");
return malchezaar != nullptr;
}
bool NightbaneBossEngagedByMainTankTrigger::IsActive()
{
if (!botAI->IsMainTank(bot))
return false;
Unit* nightbane = AI_VALUE2(Unit*, "find target", "nightbane");
return nightbane && nightbane->GetPositionZ() <= NIGHTBANE_FLIGHT_Z;
}
bool NightbaneRangedBotsAreInCharredEarthTrigger::IsActive()
{
if (!botAI->IsRanged(bot))
return false;
Unit* nightbane = AI_VALUE2(Unit*, "find target", "nightbane");
return nightbane && nightbane->GetPositionZ() <= NIGHTBANE_FLIGHT_Z;
}
bool NightbaneMainTankIsSusceptibleToFearTrigger::IsActive()
{
if (bot->getClass() != CLASS_PRIEST)
return false;
Unit* nightbane = AI_VALUE2(Unit*, "find target", "nightbane");
if (!nightbane)
return false;
Player* mainTank = nullptr;
if (Group* group = bot->GetGroup())
{
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
{
Player* member = ref->GetSource();
if (member && botAI->IsMainTank(member))
{
mainTank = member;
break;
}
}
}
return mainTank && !mainTank->HasAura(SPELL_FEAR_WARD) &&
botAI->CanCastSpell("fear ward", mainTank);
}
bool NightbanePetsIgnoreCollisionToChaseFlyingBossTrigger::IsActive()
{
Unit* nightbane = AI_VALUE2(Unit*, "find target", "nightbane");
if (!nightbane)
return false;
Pet* pet = bot->GetPet();
return pet && pet->IsAlive();
}
bool NightbaneBossIsFlyingTrigger::IsActive()
{
Unit* nightbane = AI_VALUE2(Unit*, "find target", "nightbane");
if (!nightbane || nightbane->GetPositionZ() <= NIGHTBANE_FLIGHT_Z)
return false;
const uint32 instanceId = nightbane->GetMap()->GetInstanceId();
const time_t now = std::time(nullptr);
const uint8 flightPhaseDurationSeconds = 35;
return nightbaneFlightPhaseStartTimer.find(instanceId) != nightbaneFlightPhaseStartTimer.end() &&
(now - nightbaneFlightPhaseStartTimer[instanceId] < flightPhaseDurationSeconds);
}
bool NightbaneNeedToManageTimersAndTrackersTrigger::IsActive()
{
Unit* nightbane = AI_VALUE2(Unit*, "find target", "nightbane");
return nightbane != nullptr;
}

View File

@@ -1,301 +0,0 @@
#ifndef _PLAYERBOT_RAIDKARAZHANTRIGGERS_H
#define _PLAYERBOT_RAIDKARAZHANTRIGGERS_H
#include "Trigger.h"
class ManaWarpIsAboutToExplodeTrigger : public Trigger
{
public:
ManaWarpIsAboutToExplodeTrigger(
PlayerbotAI* botAI) : Trigger(botAI, "mana warp is about to explode") {}
bool IsActive() override;
};
class AttumenTheHuntsmanNeedTargetPriorityTrigger : public Trigger
{
public:
AttumenTheHuntsmanNeedTargetPriorityTrigger(
PlayerbotAI* botAI) : Trigger(botAI, "attumen the huntsman need target priority") {}
bool IsActive() override;
};
class AttumenTheHuntsmanAttumenSpawnedTrigger : public Trigger
{
public:
AttumenTheHuntsmanAttumenSpawnedTrigger(
PlayerbotAI* botAI) : Trigger(botAI, "attumen the huntsman attumen spawned") {}
bool IsActive() override;
};
class AttumenTheHuntsmanAttumenIsMountedTrigger : public Trigger
{
public:
AttumenTheHuntsmanAttumenIsMountedTrigger(
PlayerbotAI* botAI) : Trigger(botAI, "attumen the huntsman attumen is mounted") {}
bool IsActive() override;
};
class AttumenTheHuntsmanBossWipesAggroWhenMountingTrigger : public Trigger
{
public:
AttumenTheHuntsmanBossWipesAggroWhenMountingTrigger(
PlayerbotAI* botAI) : Trigger(botAI, "attumen the huntsman boss wipes aggro when mounting") {}
bool IsActive() override;
};
class MoroesBossEngagedByMainTankTrigger : public Trigger
{
public:
MoroesBossEngagedByMainTankTrigger(
PlayerbotAI* botAI) : Trigger(botAI, "moroes boss engaged by main tank") {}
bool IsActive() override;
};
class MoroesNeedTargetPriorityTrigger : public Trigger
{
public:
MoroesNeedTargetPriorityTrigger(
PlayerbotAI* botAI) : Trigger(botAI, "moroes need target priority") {}
bool IsActive() override;
};
class MaidenOfVirtueHealersAreStunnedByRepentanceTrigger : public Trigger
{
public:
MaidenOfVirtueHealersAreStunnedByRepentanceTrigger(
PlayerbotAI* botAI) : Trigger(botAI, "maiden of virtue healers are stunned by repentance") {}
bool IsActive() override;
};
class MaidenOfVirtueHolyWrathDealsChainDamageTrigger : public Trigger
{
public:
MaidenOfVirtueHolyWrathDealsChainDamageTrigger(
PlayerbotAI* botAI) : Trigger(botAI, "maiden of virtue holy wrath deals chain damage") {}
bool IsActive() override;
};
class BigBadWolfBossEngagedByTankTrigger : public Trigger
{
public:
BigBadWolfBossEngagedByTankTrigger(
PlayerbotAI* botAI) : Trigger(botAI, "big bad wolf boss engaged by tank") {}
bool IsActive() override;
};
class BigBadWolfBossIsChasingLittleRedRidingHoodTrigger : public Trigger
{
public:
BigBadWolfBossIsChasingLittleRedRidingHoodTrigger(
PlayerbotAI* botAI) : Trigger(botAI, "big bad wolf boss is chasing little red riding hood") {}
bool IsActive() override;
};
class RomuloAndJulianneBothBossesRevivedTrigger : public Trigger
{
public:
RomuloAndJulianneBothBossesRevivedTrigger(
PlayerbotAI* botAI) : Trigger(botAI, "romulo and julianne both bosses revived") {}
bool IsActive() override;
};
class WizardOfOzNeedTargetPriorityTrigger : public Trigger
{
public:
WizardOfOzNeedTargetPriorityTrigger(
PlayerbotAI* botAI) : Trigger(botAI, "wizard of oz need target priority") {}
bool IsActive() override;
};
class WizardOfOzStrawmanIsVulnerableToFireTrigger : public Trigger
{
public:
WizardOfOzStrawmanIsVulnerableToFireTrigger(
PlayerbotAI* botAI) : Trigger(botAI, "wizard of oz strawman is vulnerable to fire") {}
bool IsActive() override;
};
class TheCuratorAstralFlareSpawnedTrigger : public Trigger
{
public:
TheCuratorAstralFlareSpawnedTrigger(
PlayerbotAI* botAI) : Trigger(botAI, "the curator astral flare spawned") {}
bool IsActive() override;
};
class TheCuratorBossEngagedByTanksTrigger : public Trigger
{
public:
TheCuratorBossEngagedByTanksTrigger(
PlayerbotAI* botAI) : Trigger(botAI, "the curator boss engaged by tanks") {}
bool IsActive() override;
};
class TheCuratorBossAstralFlaresCastArcingSearTrigger : public Trigger
{
public:
TheCuratorBossAstralFlaresCastArcingSearTrigger(
PlayerbotAI* botAI) : Trigger(botAI, "the curator astral flares cast arcing sear") {}
bool IsActive() override;
};
class TerestianIllhoofNeedTargetPriorityTrigger : public Trigger
{
public:
TerestianIllhoofNeedTargetPriorityTrigger(
PlayerbotAI* botAI) : Trigger(botAI, "terestian illhoof need target priority") {}
bool IsActive() override;
};
class ShadeOfAranArcaneExplosionIsCastingTrigger : public Trigger
{
public:
ShadeOfAranArcaneExplosionIsCastingTrigger(
PlayerbotAI* botAI) : Trigger(botAI, "shade of aran arcane explosion is casting") {}
bool IsActive() override;
};
class ShadeOfAranFlameWreathIsActiveTrigger : public Trigger
{
public:
ShadeOfAranFlameWreathIsActiveTrigger(
PlayerbotAI* botAI) : Trigger(botAI, "shade of aran flame wreath is active") {}
bool IsActive() override;
};
class ShadeOfAranConjuredElementalsSummonedTrigger : public Trigger
{
public:
ShadeOfAranConjuredElementalsSummonedTrigger(
PlayerbotAI* botAI) : Trigger(botAI, "shade of aran conjured elementals summoned") {}
bool IsActive() override;
};
class ShadeOfAranBossUsesCounterspellAndBlizzardTrigger : public Trigger
{
public:
ShadeOfAranBossUsesCounterspellAndBlizzardTrigger(
PlayerbotAI* botAI) : Trigger(botAI, "shade of aran boss uses counterspell and blizzard") {}
bool IsActive() override;
};
class NetherspiteRedBeamIsActiveTrigger : public Trigger
{
public:
NetherspiteRedBeamIsActiveTrigger(
PlayerbotAI* botAI) : Trigger(botAI, "netherspite red beam is active") {}
bool IsActive() override;
};
class NetherspiteBlueBeamIsActiveTrigger : public Trigger
{
public:
NetherspiteBlueBeamIsActiveTrigger(
PlayerbotAI* botAI) : Trigger(botAI, "netherspite blue beam is active") {}
bool IsActive() override;
};
class NetherspiteGreenBeamIsActiveTrigger : public Trigger
{
public:
NetherspiteGreenBeamIsActiveTrigger(
PlayerbotAI* botAI) : Trigger(botAI, "netherspite green beam is active") {}
bool IsActive() override;
};
class NetherspiteBotIsNotBeamBlockerTrigger : public Trigger
{
public:
NetherspiteBotIsNotBeamBlockerTrigger(
PlayerbotAI* botAI) : Trigger(botAI, "netherspite bot is not beam blocker") {}
bool IsActive() override;
};
class NetherspiteBossIsBanishedTrigger : public Trigger
{
public:
NetherspiteBossIsBanishedTrigger(
PlayerbotAI* botAI) : Trigger(botAI, "netherspite boss is banished") {}
bool IsActive() override;
};
class NetherspiteNeedToManageTimersAndTrackersTrigger : public Trigger
{
public:
NetherspiteNeedToManageTimersAndTrackersTrigger(
PlayerbotAI* botAI) : Trigger(botAI, "netherspite need to manage timers and trackers") {}
bool IsActive() override;
};
class PrinceMalchezaarBotIsEnfeebledTrigger : public Trigger
{
public:
PrinceMalchezaarBotIsEnfeebledTrigger(
PlayerbotAI* botAI) : Trigger(botAI, "prince malchezaar bot is enfeebled") {}
bool IsActive() override;
};
class PrinceMalchezaarInfernalsAreSpawnedTrigger : public Trigger
{
public:
PrinceMalchezaarInfernalsAreSpawnedTrigger(
PlayerbotAI* botAI) : Trigger(botAI, "prince malchezaar infernals are spawned") {}
bool IsActive() override;
};
class PrinceMalchezaarBossEngagedByMainTankTrigger : public Trigger
{
public:
PrinceMalchezaarBossEngagedByMainTankTrigger(
PlayerbotAI* botAI) : Trigger(botAI, "prince malchezaar boss engaged by main tank") {}
bool IsActive() override;
};
class NightbaneBossEngagedByMainTankTrigger : public Trigger
{
public:
NightbaneBossEngagedByMainTankTrigger(
PlayerbotAI* botAI) : Trigger(botAI, "nightbane boss engaged by main tank") {}
bool IsActive() override;
};
class NightbaneRangedBotsAreInCharredEarthTrigger : public Trigger
{
public:
NightbaneRangedBotsAreInCharredEarthTrigger(
PlayerbotAI* botAI) : Trigger(botAI, "nightbane ranged bots are in charred earth") {}
bool IsActive() override;
};
class NightbaneMainTankIsSusceptibleToFearTrigger : public Trigger
{
public:
NightbaneMainTankIsSusceptibleToFearTrigger(
PlayerbotAI* botAI) : Trigger(botAI, "nightbane main tank is susceptible to fear") {}
bool IsActive() override;
};
class NightbanePetsIgnoreCollisionToChaseFlyingBossTrigger : public Trigger
{
public:
NightbanePetsIgnoreCollisionToChaseFlyingBossTrigger(
PlayerbotAI* botAI) : Trigger(botAI, "nightbane pets ignore collision to chase flying boss") {}
bool IsActive() override;
};
class NightbaneBossIsFlyingTrigger : public Trigger
{
public:
NightbaneBossIsFlyingTrigger(
PlayerbotAI* botAI) : Trigger(botAI, "nightbane boss is flying") {}
bool IsActive() override;
};
class NightbaneNeedToManageTimersAndTrackersTrigger : public Trigger
{
public:
NightbaneNeedToManageTimersAndTrackersTrigger(
PlayerbotAI* botAI) : Trigger(botAI, "nightbane need to manage timers and trackers") {}
bool IsActive() override;
};
#endif

View File

@@ -1,490 +0,0 @@
#include "RaidKarazhanHelpers.h"
#include "RaidKarazhanActions.h"
#include "Playerbots.h"
#include "RtiTargetValue.h"
namespace KarazhanHelpers
{
// Attumen the Huntsman
std::unordered_map<uint32, time_t> attumenDpsWaitTimer;
// Big Bad Wolf
std::unordered_map<ObjectGuid, uint8> bigBadWolfRunIndex;
// Netherspite
std::unordered_map<uint32, time_t> netherspiteDpsWaitTimer;
std::unordered_map<ObjectGuid, time_t> redBeamMoveTimer;
std::unordered_map<ObjectGuid, bool> lastBeamMoveSideways;
// Nightbane
std::unordered_map<uint32, time_t> nightbaneDpsWaitTimer;
std::unordered_map<ObjectGuid, uint8> nightbaneTankStep;
std::unordered_map<ObjectGuid, uint8> nightbaneRangedStep;
std::unordered_map<uint32, time_t> nightbaneFlightPhaseStartTimer;
std::unordered_map<ObjectGuid, bool> nightbaneRainOfBonesHit;
const Position MAIDEN_OF_VIRTUE_BOSS_POSITION = { -10945.881f, -2103.782f, 92.712f };
const Position MAIDEN_OF_VIRTUE_RANGED_POSITION[8] =
{
{ -10931.178f, -2116.580f, 92.179f },
{ -10925.828f, -2102.425f, 92.180f },
{ -10933.089f, -2088.502f, 92.180f },
{ -10947.590f, -2082.815f, 92.180f },
{ -10960.912f, -2090.437f, 92.179f },
{ -10966.017f, -2105.288f, 92.175f },
{ -10959.242f, -2119.617f, 92.180f },
{ -10944.495f, -2123.857f, 92.180f },
};
const Position BIG_BAD_WOLF_BOSS_POSITION = { -10913.391f, -1773.508f, 90.477f };
const Position BIG_BAD_WOLF_RUN_POSITION[4] =
{
{ -10875.456f, -1779.036f, 90.477f },
{ -10872.281f, -1751.638f, 90.477f },
{ -10910.492f, -1747.401f, 90.477f },
{ -10913.391f, -1773.508f, 90.477f },
};
const Position THE_CURATOR_BOSS_POSITION = { -11139.463f, -1884.645f, 165.765f };
const Position NIGHTBANE_TRANSITION_BOSS_POSITION = { -11160.646f, -1932.773f, 91.473f }; // near some ribs
const Position NIGHTBANE_FINAL_BOSS_POSITION = { -11173.530f, -1940.707f, 91.473f };
const Position NIGHTBANE_RANGED_POSITION1 = { -11145.949f, -1970.927f, 91.473f };
const Position NIGHTBANE_RANGED_POSITION2 = { -11143.594f, -1954.981f, 91.473f };
const Position NIGHTBANE_RANGED_POSITION3 = { -11159.778f, -1961.031f, 91.473f };
const Position NIGHTBANE_FLIGHT_STACK_POSITION = { -11159.555f, -1893.526f, 91.473f }; // Broken Barrel
const Position NIGHTBANE_RAIN_OF_BONES_POSITION = { -11165.233f, -1911.123f, 91.473f };
void MarkTargetWithIcon(Player* bot, Unit* target, uint8 iconId)
{
if (!target)
return;
if (Group* group = bot->GetGroup())
{
ObjectGuid currentGuid = group->GetTargetIcon(iconId);
if (currentGuid != target->GetGUID())
group->SetTargetIcon(iconId, bot->GetGUID(), target->GetGUID());
}
}
void MarkTargetWithSkull(Player* bot, Unit* target)
{
MarkTargetWithIcon(bot, target, RtiTargetValue::skullIndex);
}
void MarkTargetWithSquare(Player* bot, Unit* target)
{
MarkTargetWithIcon(bot, target, RtiTargetValue::squareIndex);
}
void MarkTargetWithStar(Player* bot, Unit* target)
{
MarkTargetWithIcon(bot, target, RtiTargetValue::starIndex);
}
void MarkTargetWithCircle(Player* bot, Unit* target)
{
MarkTargetWithIcon(bot, target, RtiTargetValue::circleIndex);
}
void MarkTargetWithMoon(Player* bot, Unit* target)
{
MarkTargetWithIcon(bot, target, RtiTargetValue::moonIndex);
}
void SetRtiTarget(PlayerbotAI* botAI, const std::string& rtiName, Unit* target)
{
if (!target)
return;
std::string currentRti = botAI->GetAiObjectContext()->GetValue<std::string>("rti")->Get();
Unit* currentTarget = botAI->GetAiObjectContext()->GetValue<Unit*>("rti target")->Get();
if (currentRti != rtiName || currentTarget != target)
{
botAI->GetAiObjectContext()->GetValue<std::string>("rti")->Set(rtiName);
botAI->GetAiObjectContext()->GetValue<Unit*>("rti target")->Set(target);
}
}
// Only one bot is needed to set/reset instance-wide timers
bool IsInstanceTimerManager(PlayerbotAI* botAI, Player* bot)
{
if (Group* group = bot->GetGroup())
{
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
{
Player* member = ref->GetSource();
if (member && member->IsAlive() && botAI->IsDps(member) && GET_PLAYERBOT_AI(member))
return member == bot;
}
}
return false;
}
Unit* GetFirstAliveUnit(const std::vector<Unit*>& units)
{
for (Unit* unit : units)
{
if (unit && unit->IsAlive())
return unit;
}
return nullptr;
}
Unit* GetFirstAliveUnitByEntry(PlayerbotAI* botAI, uint32 entry)
{
const GuidVector npcs = botAI->GetAiObjectContext()->GetValue<GuidVector>("nearest hostile npcs")->Get();
for (auto const& npcGuid : npcs)
{
Unit* unit = botAI->GetUnit(npcGuid);
if (unit && unit->IsAlive() && unit->GetEntry() == entry)
return unit;
}
return nullptr;
}
Unit* GetNearestPlayerInRadius(Player* bot, float radius)
{
Unit* nearestPlayer = nullptr;
float nearestDistance = radius;
if (Group* group = bot->GetGroup())
{
for (GroupReference* ref = group->GetFirstMember(); ref != nullptr; ref = ref->next())
{
Player* member = ref->GetSource();
if (!member || !member->IsAlive() || member == bot)
continue;
float distance = bot->GetExactDist2d(member);
if (distance < nearestDistance)
{
nearestDistance = distance;
nearestPlayer = member;
}
}
}
return nearestPlayer;
}
bool IsFlameWreathActive(PlayerbotAI* botAI, Player* bot)
{
Unit* aran = botAI->GetAiObjectContext()->GetValue<Unit*>("find target", "shade of aran")->Get();
Spell* currentSpell = aran ? aran->GetCurrentSpell(CURRENT_GENERIC_SPELL) : nullptr;
if (currentSpell && currentSpell->m_spellInfo &&
currentSpell->m_spellInfo->Id == SPELL_FLAME_WREATH_CAST)
return true;
if (Group* group = bot->GetGroup())
{
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
{
Player* member = ref->GetSource();
if (!member || !member->IsAlive())
continue;
if (member->HasAura(SPELL_FLAME_WREATH_AURA))
return true;
}
}
return false;
}
// Red beam blockers: tank bots, no Nether Exhaustion Red
std::vector<Player*> GetRedBlockers(PlayerbotAI* botAI, Player* bot)
{
std::vector<Player*> redBlockers;
if (Group* group = bot->GetGroup())
{
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
{
Player* member = ref->GetSource();
if (!member || !member->IsAlive() || !botAI->IsTank(member) || !GET_PLAYERBOT_AI(member) ||
member->HasAura(SPELL_NETHER_EXHAUSTION_RED))
continue;
redBlockers.push_back(member);
}
}
return redBlockers;
}
// Blue beam blockers: non-Rogue/Warrior DPS bots, no Nether Exhaustion Blue and <24 stacks of Blue Beam debuff
std::vector<Player*> GetBlueBlockers(PlayerbotAI* botAI, Player* bot)
{
std::vector<Player*> blueBlockers;
if (Group* group = bot->GetGroup())
{
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
{
Player* member = ref->GetSource();
if (!member || !member->IsAlive() || !GET_PLAYERBOT_AI(member))
continue;
bool hasExhaustion = member->HasAura(SPELL_NETHER_EXHAUSTION_BLUE);
Aura* blueBuff = member->GetAura(SPELL_BLUE_BEAM_DEBUFF);
bool overStack = blueBuff && blueBuff->GetStackAmount() >= 24;
bool isDps = botAI->IsDps(member);
bool isWarrior = member->getClass() == CLASS_WARRIOR;
bool isRogue = member->getClass() == CLASS_ROGUE;
if (isDps && !isWarrior && !isRogue && !hasExhaustion && !overStack)
blueBlockers.push_back(member);
}
}
return blueBlockers;
}
// Green beam blockers:
// (1) Prioritize Rogues and non-tank Warrior bots, no Nether Exhaustion Green
// (2) Then assign Healer bots, no Nether Exhaustion Green and <24 stacks of Green Beam debuff
std::vector<Player*> GetGreenBlockers(PlayerbotAI* botAI, Player* bot)
{
std::vector<Player*> greenBlockers;
if (Group* group = bot->GetGroup())
{
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
{
Player* member = ref->GetSource();
if (!member || !member->IsAlive() || !GET_PLAYERBOT_AI(member))
continue;
bool hasExhaustion = member->HasAura(SPELL_NETHER_EXHAUSTION_GREEN);
bool isRogue = member->getClass() == CLASS_ROGUE;
bool isDpsWarrior = member->getClass() == CLASS_WARRIOR && botAI->IsDps(member);
bool eligibleRogueWarrior = (isRogue || isDpsWarrior) && !hasExhaustion;
if (eligibleRogueWarrior)
greenBlockers.push_back(member);
}
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
{
Player* member = ref->GetSource();
if (!member || !member->IsAlive() || !GET_PLAYERBOT_AI(member))
continue;
bool hasExhaustion = member->HasAura(SPELL_NETHER_EXHAUSTION_GREEN);
Aura* greenBuff = member->GetAura(SPELL_GREEN_BEAM_DEBUFF);
bool overStack = greenBuff && greenBuff->GetStackAmount() >= 24;
bool isHealer = botAI->IsHeal(member);
bool eligibleHealer = isHealer && !hasExhaustion && !overStack;
if (eligibleHealer)
greenBlockers.push_back(member);
}
}
return greenBlockers;
}
std::tuple<Player*, Player*, Player*> GetCurrentBeamBlockers(PlayerbotAI* botAI, Player* bot)
{
static ObjectGuid currentRedBlocker;
static ObjectGuid currentGreenBlocker;
static ObjectGuid currentBlueBlocker;
Player* redBlocker = nullptr;
Player* greenBlocker = nullptr;
Player* blueBlocker = nullptr;
std::vector<Player*> redBlockers = GetRedBlockers(botAI, bot);
if (!redBlockers.empty())
{
auto it = std::find_if(redBlockers.begin(), redBlockers.end(), [](Player* player)
{
return player && player->GetGUID() == currentRedBlocker;
});
if (it != redBlockers.end())
redBlocker = *it;
else
redBlocker = redBlockers.front();
currentRedBlocker = redBlocker ? redBlocker->GetGUID() : ObjectGuid::Empty;
}
else
{
currentRedBlocker = ObjectGuid::Empty;
redBlocker = nullptr;
}
std::vector<Player*> greenBlockers = GetGreenBlockers(botAI, bot);
if (!greenBlockers.empty())
{
auto it = std::find_if(greenBlockers.begin(), greenBlockers.end(), [](Player* player)
{
return player && player->GetGUID() == currentGreenBlocker;
});
if (it != greenBlockers.end())
greenBlocker = *it;
else
greenBlocker = greenBlockers.front();
currentGreenBlocker = greenBlocker ? greenBlocker->GetGUID() : ObjectGuid::Empty;
}
else
{
currentGreenBlocker = ObjectGuid::Empty;
greenBlocker = nullptr;
}
std::vector<Player*> blueBlockers = GetBlueBlockers(botAI, bot);
if (!blueBlockers.empty())
{
auto it = std::find_if(blueBlockers.begin(), blueBlockers.end(), [](Player* player)
{
return player && player->GetGUID() == currentBlueBlocker;
});
if (it != blueBlockers.end())
blueBlocker = *it;
else
blueBlocker = blueBlockers.front();
currentBlueBlocker = blueBlocker ? blueBlocker->GetGUID() : ObjectGuid::Empty;
}
else
{
currentBlueBlocker = ObjectGuid::Empty;
blueBlocker = nullptr;
}
return std::make_tuple(redBlocker, greenBlocker, blueBlocker);
}
std::vector<Unit*> GetAllVoidZones(PlayerbotAI* botAI, Player* bot)
{
std::vector<Unit*> voidZones;
const float radius = 30.0f;
const GuidVector npcs = botAI->GetAiObjectContext()->GetValue<GuidVector>("nearest npcs")->Get();
for (auto const& npcGuid : npcs)
{
Unit* unit = botAI->GetUnit(npcGuid);
if (!unit || unit->GetEntry() != NPC_VOID_ZONE)
continue;
float dist = bot->GetExactDist2d(unit);
if (dist < radius)
voidZones.push_back(unit);
}
return voidZones;
}
bool IsSafePosition(float x, float y, float z, const std::vector<Unit*>& hazards, float hazardRadius)
{
for (Unit* hazard : hazards)
{
float dist = hazard->GetExactDist2d(x, y);
if (dist < hazardRadius)
return false;
}
return true;
}
std::vector<Unit*> GetSpawnedInfernals(PlayerbotAI* botAI)
{
std::vector<Unit*> infernals;
const GuidVector npcs = botAI->GetAiObjectContext()->GetValue<GuidVector>("nearest npcs")->Get();
for (auto const& npcGuid : npcs)
{
Unit* unit = botAI->GetUnit(npcGuid);
if (unit && unit->GetEntry() == NPC_NETHERSPITE_INFERNAL)
infernals.push_back(unit);
}
return infernals;
}
bool IsStraightPathSafe(const Position& start, const Position& target, const std::vector<Unit*>& hazards,
float hazardRadius, float stepSize)
{
float sx = start.GetPositionX();
float sy = start.GetPositionY();
float sz = start.GetPositionZ();
float tx = target.GetPositionX();
float ty = target.GetPositionY();
float tz = target.GetPositionZ();
const float totalDist = start.GetExactDist2d(target.GetPositionX(), target.GetPositionY());
if (totalDist == 0.0f)
return true;
for (float checkDist = 0.0f; checkDist <= totalDist; checkDist += stepSize)
{
float t = checkDist / totalDist;
float checkX = sx + (tx - sx) * t;
float checkY = sy + (ty - sy) * t;
float checkZ = sz + (tz - sz) * t;
for (Unit* hazard : hazards)
{
const float hx = checkX - hazard->GetPositionX();
const float hy = checkY - hazard->GetPositionY();
if ((hx*hx + hy*hy) < hazardRadius * hazardRadius)
return false;
}
}
return true;
}
bool TryFindSafePositionWithSafePath(
Player* bot, float originX, float originY, float originZ, float centerX, float centerY, float centerZ,
const std::vector<Unit*>& hazards, float safeDistance, float stepSize, uint8 numAngles,
float maxSampleDist, bool requireSafePath, float& bestDestX, float& bestDestY, float& bestDestZ)
{
float bestMoveDist = std::numeric_limits<float>::max();
bool found = false;
for (int i = 0; i < numAngles; ++i)
{
float angle = (2.0f * M_PI * i) / numAngles;
float dx = cos(angle);
float dy = sin(angle);
for (float dist = stepSize; dist <= maxSampleDist; dist += stepSize)
{
float x = centerX + dx * dist;
float y = centerY + dy * dist;
float z = centerZ;
float destX = x, destY = y, destZ = z;
if (!bot->GetMap()->CheckCollisionAndGetValidCoords(bot, centerX, centerY, centerZ,
destX, destY, destZ, true))
continue;
if (!IsSafePosition(destX, destY, destZ, hazards, safeDistance))
continue;
if (requireSafePath)
{
if (!IsStraightPathSafe(Position(originX, originY, originZ), Position(destX, destY, destZ),
hazards, safeDistance, stepSize))
continue;
}
const float moveDist = Position(originX, originY, originZ).GetExactDist2d(destX, destY);
if (moveDist < bestMoveDist)
{
bestMoveDist = moveDist;
bestDestX = destX;
bestDestY = destY;
bestDestZ = destZ;
found = true;
}
}
}
return found;
}
}

View File

@@ -1,136 +0,0 @@
#ifndef _PLAYERBOT_RAIDKARAZHANHELPERS_H_
#define _PLAYERBOT_RAIDKARAZHANHELPERS_H_
#include <ctime>
#include <unordered_map>
#include "AiObject.h"
#include "Position.h"
#include "Unit.h"
namespace KarazhanHelpers
{
enum KarazhanSpells
{
// Maiden of Virtue
SPELL_REPENTANCE = 29511,
// Opera Event
SPELL_LITTLE_RED_RIDING_HOOD = 30756,
// The Curator
SPELL_CURATOR_EVOCATION = 30254,
// Shade of Aran
SPELL_FLAME_WREATH_CAST = 30004,
SPELL_FLAME_WREATH_AURA = 29946,
SPELL_ARCANE_EXPLOSION = 29973,
// Netherspite
SPELL_RED_BEAM_DEBUFF = 30421, // "Nether Portal - Perseverance" (player aura)
SPELL_GREEN_BEAM_DEBUFF = 30422, // "Nether Portal - Serenity" (player aura)
SPELL_BLUE_BEAM_DEBUFF = 30423, // "Nether Portal - Dominance" (player aura)
SPELL_GREEN_BEAM_HEAL = 30467, // "Nether Portal - Serenity" (Netherspite aura)
SPELL_NETHER_EXHAUSTION_RED = 38637,
SPELL_NETHER_EXHAUSTION_GREEN = 38638,
SPELL_NETHER_EXHAUSTION_BLUE = 38639,
SPELL_NETHERSPITE_BANISHED = 39833, // "Vortex Shade Black"
// Prince Malchezaar
SPELL_ENFEEBLE = 30843,
// Nightbane
SPELL_CHARRED_EARTH = 30129,
SPELL_BELLOWING_ROAR = 36922,
SPELL_RAIN_OF_BONES = 37091,
// Warlock
SPELL_WARLOCK_BANISH = 18647,
// Priest
SPELL_FEAR_WARD = 6346,
};
enum KarazhanNPCs
{
// Trash
NPC_SPECTRAL_RETAINER = 16410,
NPC_MANA_WARP = 16530,
// Attumen the Huntsman
NPC_ATTUMEN_THE_HUNTSMAN = 15550,
NPC_ATTUMEN_THE_HUNTSMAN_MOUNTED = 16152,
// Shade of Aran
NPC_CONJURED_ELEMENTAL = 17167,
// Netherspite
NPC_VOID_ZONE = 16697,
NPC_GREEN_PORTAL = 17367, // "Nether Portal - Serenity <Healing Portal>"
NPC_BLUE_PORTAL = 17368, // "Nether Portal - Dominance <Damage Portal>"
NPC_RED_PORTAL = 17369, // "Nether Portal - Perseverance <Tanking Portal>"
// Prince Malchezaar
NPC_NETHERSPITE_INFERNAL = 17646,
};
const uint32 KARAZHAN_MAP_ID = 532;
const float NIGHTBANE_FLIGHT_Z = 95.0f;
// Attumen the Huntsman
extern std::unordered_map<uint32, time_t> attumenDpsWaitTimer;
// Big Bad Wolf
extern std::unordered_map<ObjectGuid, uint8> bigBadWolfRunIndex;
// Netherspite
extern std::unordered_map<uint32, time_t> netherspiteDpsWaitTimer;
extern std::unordered_map<ObjectGuid, time_t> redBeamMoveTimer;
extern std::unordered_map<ObjectGuid, bool> lastBeamMoveSideways;
// Nightbane
extern std::unordered_map<uint32, time_t> nightbaneDpsWaitTimer;
extern std::unordered_map<ObjectGuid, uint8> nightbaneTankStep;
extern std::unordered_map<ObjectGuid, uint8> nightbaneRangedStep;
extern std::unordered_map<uint32, time_t> nightbaneFlightPhaseStartTimer;
extern std::unordered_map<ObjectGuid, bool> nightbaneRainOfBonesHit;
extern const Position MAIDEN_OF_VIRTUE_BOSS_POSITION;
extern const Position MAIDEN_OF_VIRTUE_RANGED_POSITION[8];
extern const Position BIG_BAD_WOLF_BOSS_POSITION;
extern const Position BIG_BAD_WOLF_RUN_POSITION[4];
extern const Position THE_CURATOR_BOSS_POSITION;
extern const Position NIGHTBANE_TRANSITION_BOSS_POSITION;
extern const Position NIGHTBANE_FINAL_BOSS_POSITION;
extern const Position NIGHTBANE_RANGED_POSITION1;
extern const Position NIGHTBANE_RANGED_POSITION2;
extern const Position NIGHTBANE_RANGED_POSITION3;
extern const Position NIGHTBANE_FLIGHT_STACK_POSITION;
extern const Position NIGHTBANE_RAIN_OF_BONES_POSITION;
void MarkTargetWithIcon(Player* bot, Unit* target, uint8 iconId);
void MarkTargetWithSkull(Player* bot, Unit* target);
void MarkTargetWithSquare(Player* bot, Unit* target);
void MarkTargetWithStar(Player* bot, Unit* target);
void MarkTargetWithCircle(Player* bot, Unit* target);
void MarkTargetWithMoon(Player* bot, Unit* target);
void SetRtiTarget(PlayerbotAI* botAI, const std::string& rtiName, Unit* target);
bool IsInstanceTimerManager(PlayerbotAI* botAI, Player* bot);
Unit* GetFirstAliveUnit(const std::vector<Unit*>& units);
Unit* GetFirstAliveUnitByEntry(PlayerbotAI* botAI, uint32 entry);
Unit* GetNearestPlayerInRadius(Player* bot, float radius);
bool IsFlameWreathActive(PlayerbotAI* botAI, Player* bot);
std::vector<Player*> GetRedBlockers(PlayerbotAI* botAI, Player* bot);
std::vector<Player*> GetBlueBlockers(PlayerbotAI* botAI, Player* bot);
std::vector<Player*> GetGreenBlockers(PlayerbotAI* botAI, Player* bot);
std::tuple<Player*, Player*, Player*> GetCurrentBeamBlockers(PlayerbotAI* botAI, Player* bot);
std::vector<Unit*> GetAllVoidZones(PlayerbotAI *botAI, Player* bot);
bool IsSafePosition (float x, float y, float z, const std::vector<Unit*>& hazards, float hazardRadius);
std::vector<Unit*> GetSpawnedInfernals(PlayerbotAI* botAI);
bool IsStraightPathSafe(
const Position& start, const Position& target,
const std::vector<Unit*>& hazards, float hazardRadius, float stepSize);
bool TryFindSafePositionWithSafePath(
Player* bot, float originX, float originY, float originZ, float centerX, float centerY, float centerZ,
const std::vector<Unit*>& hazards, float safeDistance, float stepSize, uint8 numAngles,
float maxSampleDist, bool requireSafePath, float& bestDestX, float& bestDestY, float& bestDestZ);
}
#endif

View File

@@ -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));
}

View File

@@ -1,215 +0,0 @@
#include "RaidMcActions.h"
#include "Playerbots.h"
#include "RtiTargetValue.h"
#include "RaidMcTriggers.h"
#include "RaidMcHelpers.h"
static constexpr float LIVING_BOMB_DISTANCE = 20.0f;
static constexpr float INFERNO_DISTANCE = 20.0f;
// don't get hit by Arcane Explosion but still be in casting range
static constexpr float ARCANE_EXPLOSION_DISTANCE = 26.0f;
// dedicated tank positions; prevents assist tanks from positioning Core Ragers on steep walls on pull
static const Position GOLEMAGG_TANK_POSITION{795.7308, -994.8848, -207.18661};
static const Position CORE_RAGER_TANK_POSITION{846.6453, -1019.0639, -198.9819};
static constexpr float GOLEMAGGS_TRUST_DISTANCE = 30.0f;
static constexpr float CORE_RAGER_STEP_DISTANCE = 5.0f;
using namespace MoltenCoreHelpers;
bool McMoveFromGroupAction::Execute(Event event)
{
return MoveFromGroup(LIVING_BOMB_DISTANCE);
}
bool McMoveFromBaronGeddonAction::Execute(Event event)
{
if (Unit* boss = AI_VALUE2(Unit*, "find target", "baron geddon"))
{
float distToTravel = INFERNO_DISTANCE - bot->GetDistance2d(boss);
if (distToTravel > 0)
{
// Stop current spell first
bot->AttackStop();
bot->InterruptNonMeleeSpells(false);
return MoveAway(boss, distToTravel);
}
}
return false;
}
bool McShazzrahMoveAwayAction::Execute(Event event)
{
if (Unit* boss = AI_VALUE2(Unit*, "find target", "shazzrah"))
{
float distToTravel = ARCANE_EXPLOSION_DISTANCE - bot->GetDistance2d(boss);
if (distToTravel > 0)
return MoveAway(boss, distToTravel);
}
return false;
}
bool McGolemaggMarkBossAction::Execute(Event event)
{
if (Unit* boss = AI_VALUE2(Unit*, "find target", "golemagg the incinerator"))
{
if (Group* group = bot->GetGroup())
{
ObjectGuid currentSkullGuid = group->GetTargetIcon(RtiTargetValue::skullIndex);
if (currentSkullGuid.IsEmpty() || currentSkullGuid != boss->GetGUID())
{
group->SetTargetIcon(RtiTargetValue::skullIndex, bot->GetGUID(), boss->GetGUID());
return true;
}
}
}
return false;
}
bool McGolemaggTankAction::MoveUnitToPosition(Unit* target, const Position& tankPosition, float maxDistance,
float stepDistance)
{
if (bot->GetVictim() != target)
return Attack(target);
if (target->GetVictim() == bot)
{
float distanceToTankPosition = bot->GetExactDist2d(tankPosition.GetPositionX(), tankPosition.GetPositionY());
if (distanceToTankPosition > maxDistance)
{
float dX = tankPosition.GetPositionX() - bot->GetPositionX();
float dY = tankPosition.GetPositionY() - bot->GetPositionY();
float dist = sqrt(dX * dX + dY * dY);
float moveX = bot->GetPositionX() + (dX / dist) * stepDistance;
float moveY = bot->GetPositionY() + (dY / dist) * stepDistance;
return MoveTo(bot->GetMapId(), moveX, moveY, bot->GetPositionZ(), false, false,
false, false, MovementPriority::MOVEMENT_COMBAT, true,
true);
}
}
else if (botAI->DoSpecificAction("taunt spell", Event(), true))
return true;
return false;
}
bool McGolemaggTankAction::FindCoreRagers(Unit*& coreRager1, Unit*& coreRager2) const
{
coreRager1 = coreRager2 = nullptr;
for (auto const& target : AI_VALUE(GuidVector, "possible targets no los"))
{
Unit* unit = botAI->GetUnit(target);
if (unit && unit->IsAlive() && unit->GetEntry() == NPC_CORE_RAGER)
{
if (coreRager1 == nullptr)
coreRager1 = unit;
else if (coreRager2 == nullptr)
{
coreRager2 = unit;
break; // There should be no third Core Rager.
}
}
}
return coreRager1 != nullptr && coreRager2 != nullptr;
}
bool McGolemaggMainTankAttackGolemaggAction::Execute(Event event)
{
// At this point, we know we are not the last living tank in the group.
if (Unit* boss = AI_VALUE2(Unit*, "find target", "golemagg the incinerator"))
{
Unit* coreRager1;
Unit* coreRager2;
if (!FindCoreRagers(coreRager1, coreRager2))
return false; // safety check
// We only need to move if the Core Ragers still have Golemagg's Trust
if (coreRager1->HasAura(SPELL_GOLEMAGGS_TRUST) || coreRager2->HasAura(SPELL_GOLEMAGGS_TRUST))
return MoveUnitToPosition(boss, GOLEMAGG_TANK_POSITION, boss->GetCombatReach());
}
return false;
}
bool McGolemaggAssistTankAttackCoreRagerAction::Execute(Event event)
{
Unit* boss = AI_VALUE2(Unit*, "find target", "golemagg the incinerator");
if (!boss)
return false;
// Step 0: Filter additional assist tanks. We only need 2.
bool isFirstAssistTank = PlayerbotAI::IsAssistTankOfIndex(bot, 0, true);
bool isSecondAssistTank = PlayerbotAI::IsAssistTankOfIndex(bot, 1, true);
if (!isFirstAssistTank && !isSecondAssistTank)
return Attack(boss);
// Step 1: Find both Core Ragers
Unit* coreRager1;
Unit* coreRager2;
if (!FindCoreRagers(coreRager1, coreRager2))
return false; // safety check
// Step 2: Assign Core Rager to bot
Unit* myCoreRager = nullptr;
Unit* otherCoreRager = nullptr;
if (isFirstAssistTank)
{
myCoreRager = coreRager1;
otherCoreRager = coreRager2;
}
else // isSecondAssistTank is always true here
{
myCoreRager = coreRager2;
otherCoreRager = coreRager1;
}
// Step 3: Select the right target
if (myCoreRager->GetVictim() != bot)
{
// Step 3.1: My Core Rager isn't attacking me. Attack until it does.
if (bot->GetVictim() != myCoreRager)
return Attack(myCoreRager);
return botAI->DoSpecificAction("taunt spell", event, true);
}
Unit* otherCoreRagerVictim = otherCoreRager->GetVictim();
if (otherCoreRagerVictim) // Core Rager victim can be NULL
{
// Step 3.2: Check if the other Core Rager isn't attacking its assist tank.
Player* otherCoreRagerPlayerVictim = otherCoreRagerVictim->ToPlayer();
if (otherCoreRagerPlayerVictim &&
!PlayerbotAI::IsAssistTankOfIndex(otherCoreRagerPlayerVictim, 0, true) &&
!PlayerbotAI::IsAssistTankOfIndex(otherCoreRagerPlayerVictim, 1, true))
{
// Assume we are the only assist tank or the other assist tank is dead => pick up other Core Rager!
if (bot->GetVictim() != otherCoreRager)
return Attack(otherCoreRager);
return botAI->DoSpecificAction("taunt spell", event, true);
}
}
if (bot->GetVictim() != myCoreRager)
return Attack(myCoreRager); // Step 3.3: Attack our Core Rager in case we previously switched in 3.2.
// Step 4: Prevent Golemagg's Trust on Core Ragers
if (myCoreRager->HasAura(SPELL_GOLEMAGGS_TRUST) ||
(otherCoreRagerVictim == bot && otherCoreRager->HasAura(SPELL_GOLEMAGGS_TRUST)))
{
// Step 4.1: Move Core Ragers to dedicated tank position (only if Golemagg is far enough away from said position)
float bossDistanceToCoreRagerTankPosition = boss->GetExactDist2d(
CORE_RAGER_TANK_POSITION.GetPositionX(), CORE_RAGER_TANK_POSITION.GetPositionY());
if (bossDistanceToCoreRagerTankPosition > GOLEMAGGS_TRUST_DISTANCE)
{
float distanceToTankPosition = bot->GetExactDist2d(CORE_RAGER_TANK_POSITION.GetPositionX(),
CORE_RAGER_TANK_POSITION.GetPositionY());
if (distanceToTankPosition > CORE_RAGER_STEP_DISTANCE)
return MoveUnitToPosition(myCoreRager, CORE_RAGER_TANK_POSITION, CORE_RAGER_STEP_DISTANCE);
}
// Step 4.2: if boss is too close to tank position, or we are already there, move away from Golemagg to try to out-range Golemagg's Trust
return MoveAway(boss, CORE_RAGER_STEP_DISTANCE, true);
}
return false;
}

View File

@@ -1,67 +0,0 @@
#ifndef _PLAYERBOT_RAIDMCACTIONS_H
#define _PLAYERBOT_RAIDMCACTIONS_H
#include "AttackAction.h"
#include "MovementActions.h"
#include "PlayerbotAI.h"
#include "Playerbots.h"
class McMoveFromGroupAction : public MovementAction
{
public:
McMoveFromGroupAction(PlayerbotAI* botAI, std::string const name = "mc move from group")
: MovementAction(botAI, name) {}
bool Execute(Event event) override;
};
class McMoveFromBaronGeddonAction : public MovementAction
{
public:
McMoveFromBaronGeddonAction(PlayerbotAI* botAI, std::string const name = "mc move from baron geddon")
: MovementAction(botAI, name) {}
bool Execute(Event event) override;
};
class McShazzrahMoveAwayAction : public MovementAction
{
public:
McShazzrahMoveAwayAction(PlayerbotAI* botAI, std::string const name = "mc shazzrah move away")
: MovementAction(botAI, name) {}
bool Execute(Event event) override;
};
class McGolemaggMarkBossAction : public Action
{
public:
McGolemaggMarkBossAction(PlayerbotAI* botAI, std::string const name = "mc golemagg mark boss")
: Action(botAI, name) {};
bool Execute(Event event) override;
};
class McGolemaggTankAction : public AttackAction
{
public:
McGolemaggTankAction(PlayerbotAI* botAI, std::string const name)
: AttackAction(botAI, name) {}
protected:
bool MoveUnitToPosition(Unit* target, const Position& tankPosition, float maxDistance, float stepDistance = 3.0f);
bool FindCoreRagers(Unit*& coreRager1, Unit*& coreRager2) const;
};
class McGolemaggMainTankAttackGolemaggAction : public McGolemaggTankAction
{
public:
McGolemaggMainTankAttackGolemaggAction(PlayerbotAI* botAI, std::string const name = "mc golemagg main tank attack golemagg")
: McGolemaggTankAction(botAI, name) {};
bool Execute(Event event) override;
};
class McGolemaggAssistTankAttackCoreRagerAction : public McGolemaggTankAction
{
public:
McGolemaggAssistTankAttackCoreRagerAction(PlayerbotAI* botAI, std::string const name = "mc golemagg assist tank attack core rager")
: McGolemaggTankAction(botAI, name) {};
bool Execute(Event event) override;
};
#endif

View File

@@ -1,117 +0,0 @@
#include "RaidMcMultipliers.h"
#include "Playerbots.h"
#include "ChooseTargetActions.h"
#include "GenericSpellActions.h"
#include "DruidActions.h"
#include "HunterActions.h"
#include "PaladinActions.h"
#include "ShamanActions.h"
#include "WarriorActions.h"
#include "DKActions.h"
#include "RaidMcActions.h"
#include "RaidMcHelpers.h"
using namespace MoltenCoreHelpers;
static bool IsDpsBotWithAoeAction(Player* bot, Action* action)
{
if (PlayerbotAI::IsDps(bot))
{
if (dynamic_cast<DpsAoeAction*>(action) || dynamic_cast<CastConsecrationAction*>(action) ||
dynamic_cast<CastStarfallAction*>(action) || dynamic_cast<CastWhirlwindAction*>(action) ||
dynamic_cast<CastMagmaTotemAction*>(action) || dynamic_cast<CastExplosiveTrapAction*>(action) ||
dynamic_cast<CastDeathAndDecayAction*>(action))
return true;
if (auto castSpellAction = dynamic_cast<CastSpellAction*>(action))
{
if (castSpellAction->getThreatType() == Action::ActionThreatType::Aoe)
return true;
}
}
return false;
}
float GarrDisableDpsAoeMultiplier::GetValue(Action* action)
{
if (AI_VALUE2(Unit*, "find target", "garr"))
{
if (IsDpsBotWithAoeAction(bot, action))
return 0.0f;
}
return 1.0f;
}
static bool IsAllowedGeddonMovementAction(Action* action)
{
if (dynamic_cast<MovementAction*>(action) &&
!dynamic_cast<McMoveFromGroupAction*>(action) &&
!dynamic_cast<McMoveFromBaronGeddonAction*>(action))
return false;
if (dynamic_cast<CastReachTargetSpellAction*>(action))
return false;
return true;
}
float BaronGeddonAbilityMultiplier::GetValue(Action* action)
{
if (Unit* boss = AI_VALUE2(Unit*, "find target", "baron geddon"))
{
if (boss->HasAura(SPELL_INFERNO))
{
if (!IsAllowedGeddonMovementAction(action))
return 0.0f;
}
}
// No check for Baron Geddon, because bots may have the bomb even after Geddon died.
if (bot->HasAura(SPELL_LIVING_BOMB))
{
if (!IsAllowedGeddonMovementAction(action))
return 0.0f;
}
return 1.0f;
}
static bool IsSingleLivingTankInGroup(Player* bot)
{
if (Group* group = bot->GetGroup())
{
for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next())
{
Player* member = itr->GetSource();
if (!member || !member->IsAlive() || member == bot)
continue;
if (PlayerbotAI::IsTank(member))
return false;
}
}
return true;
}
float GolemaggMultiplier::GetValue(Action* action)
{
if (AI_VALUE2(Unit*, "find target", "golemagg the incinerator"))
{
if (PlayerbotAI::IsTank(bot) && IsSingleLivingTankInGroup(bot))
{
// Only one tank => Pick up Golemagg and the two Core Ragers
if (dynamic_cast<McGolemaggMainTankAttackGolemaggAction*>(action) ||
dynamic_cast<McGolemaggAssistTankAttackCoreRagerAction*>(action))
return 0.0f;
}
if (PlayerbotAI::IsAssistTank(bot))
{
// The first two assist tanks manage the Core Ragers. The remaining assist tanks attack the boss.
if (dynamic_cast<TankAssistAction*>(action))
return 0.0f;
}
if (IsDpsBotWithAoeAction(bot, action))
return 0.0f;
}
return 1.0f;
}

View File

@@ -1,27 +0,0 @@
#ifndef _PLAYERBOT_RAIDMCMULTIPLIERS_H
#define _PLAYERBOT_RAIDMCMULTIPLIERS_H
#include "Multiplier.h"
class GarrDisableDpsAoeMultiplier : public Multiplier
{
public:
GarrDisableDpsAoeMultiplier(PlayerbotAI* botAI) : Multiplier(botAI, "garr disable dps aoe multiplier") {}
float GetValue(Action* action) override;
};
class BaronGeddonAbilityMultiplier : public Multiplier
{
public:
BaronGeddonAbilityMultiplier(PlayerbotAI* botAI) : Multiplier(botAI, "baron geddon ability multiplier") {}
float GetValue(Action* action) override;
};
class GolemaggMultiplier : public Multiplier
{
public:
GolemaggMultiplier(PlayerbotAI* botAI) : Multiplier(botAI, "golemagg multiplier") {}
float GetValue(Action* action) override;
};
#endif

View File

@@ -1,48 +0,0 @@
#ifndef _PLAYERBOT_RAIDMCACTIONCONTEXT_H
#define _PLAYERBOT_RAIDMCACTIONCONTEXT_H
#include "Action.h"
#include "NamedObjectContext.h"
#include "RaidMcActions.h"
class RaidMcActionContext : public NamedObjectContext<Action>
{
public:
RaidMcActionContext()
{
creators["mc lucifron shadow resistance"] = &RaidMcActionContext::lucifron_shadow_resistance;
creators["mc magmadar fire resistance"] = &RaidMcActionContext::magmadar_fire_resistance;
creators["mc gehennas shadow resistance"] = &RaidMcActionContext::gehennas_shadow_resistance;
creators["mc garr fire resistance"] = &RaidMcActionContext::garr_fire_resistance;
creators["mc baron geddon fire resistance"] = &RaidMcActionContext::baron_geddon_fire_resistance;
creators["mc move from group"] = &RaidMcActionContext::check_should_move_from_group;
creators["mc move from baron geddon"] = &RaidMcActionContext::move_from_baron_geddon;
creators["mc shazzrah move away"] = &RaidMcActionContext::shazzrah_move_away;
creators["mc sulfuron harbinger fire resistance"] = &RaidMcActionContext::sulfuron_harbinger_fire_resistance;
creators["mc golemagg fire resistance"] = &RaidMcActionContext::golemagg_fire_resistance;
creators["mc golemagg mark boss"] = &RaidMcActionContext::golemagg_mark_boss;
creators["mc golemagg main tank attack golemagg"] = &RaidMcActionContext::golemagg_main_tank_attack_golemagg;
creators["mc golemagg assist tank attack core rager"] = &RaidMcActionContext::golemagg_assist_tank_attack_core_rager;
creators["mc majordomo shadow resistance"] = &RaidMcActionContext::majordomo_shadow_resistance;
creators["mc ragnaros fire resistance"] = &RaidMcActionContext::ragnaros_fire_resistance;
}
private:
static Action* lucifron_shadow_resistance(PlayerbotAI* botAI) { return new BossShadowResistanceAction(botAI, "lucifron"); }
static Action* magmadar_fire_resistance(PlayerbotAI* botAI) { return new BossFireResistanceAction(botAI, "magmadar"); }
static Action* gehennas_shadow_resistance(PlayerbotAI* botAI) { return new BossShadowResistanceAction(botAI, "gehennas"); }
static Action* garr_fire_resistance(PlayerbotAI* botAI) { return new BossFireResistanceAction(botAI, "garr"); }
static Action* baron_geddon_fire_resistance(PlayerbotAI* botAI) { return new BossFireResistanceAction(botAI, "baron geddon"); }
static Action* check_should_move_from_group(PlayerbotAI* botAI) { return new McMoveFromGroupAction(botAI); }
static Action* move_from_baron_geddon(PlayerbotAI* botAI) { return new McMoveFromBaronGeddonAction(botAI); }
static Action* shazzrah_move_away(PlayerbotAI* botAI) { return new McShazzrahMoveAwayAction(botAI); }
static Action* sulfuron_harbinger_fire_resistance(PlayerbotAI* botAI) { return new BossFireResistanceAction(botAI, "sulfuron harbinger"); }
static Action* golemagg_fire_resistance(PlayerbotAI* botAI) { return new BossFireResistanceAction(botAI, "golemagg the incinerator"); }
static Action* golemagg_mark_boss(PlayerbotAI* botAI) { return new McGolemaggMarkBossAction(botAI); }
static Action* golemagg_main_tank_attack_golemagg(PlayerbotAI* botAI) { return new McGolemaggMainTankAttackGolemaggAction(botAI); }
static Action* golemagg_assist_tank_attack_core_rager(PlayerbotAI* botAI) { return new McGolemaggAssistTankAttackCoreRagerAction(botAI); }
static Action* majordomo_shadow_resistance(PlayerbotAI* botAI) { return new BossShadowResistanceAction(botAI, "majordomo executus"); }
static Action* ragnaros_fire_resistance(PlayerbotAI* botAI) { return new BossFireResistanceAction(botAI, "ragnaros"); }
};
#endif

View File

@@ -1,22 +0,0 @@
#ifndef _PLAYERBOT_RAIDMCHELPERS_H
#define _PLAYERBOT_RAIDMCHELPERS_H
namespace MoltenCoreHelpers
{
enum MoltenCoreNPCs
{
// Golemagg
NPC_CORE_RAGER = 11672,
};
enum MoltenCoreSpells
{
// Baron Geddon
SPELL_INFERNO = 19695,
SPELL_LIVING_BOMB = 20475,
// Golemagg
SPELL_GOLEMAGGS_TRUST = 20553,
};
}
#endif

View File

@@ -1,48 +0,0 @@
#ifndef _PLAYERBOT_RAIDMCTRIGGERCONTEXT_H
#define _PLAYERBOT_RAIDMCTRIGGERCONTEXT_H
#include "AiObjectContext.h"
#include "NamedObjectContext.h"
#include "RaidMcTriggers.h"
class RaidMcTriggerContext : public NamedObjectContext<Trigger>
{
public:
RaidMcTriggerContext()
{
creators["mc lucifron shadow resistance"] = &RaidMcTriggerContext::lucifron_shadow_resistance;
creators["mc magmadar fire resistance"] = &RaidMcTriggerContext::magmadar_fire_resistance;
creators["mc gehennas shadow resistance"] = &RaidMcTriggerContext::gehennas_shadow_resistance;
creators["mc garr fire resistance"] = &RaidMcTriggerContext::garr_fire_resistance;
creators["mc baron geddon fire resistance"] = &RaidMcTriggerContext::baron_geddon_fire_resistance;
creators["mc living bomb debuff"] = &RaidMcTriggerContext::living_bomb_debuff;
creators["mc baron geddon inferno"] = &RaidMcTriggerContext::baron_geddon_inferno;
creators["mc shazzrah ranged"] = &RaidMcTriggerContext::shazzrah_ranged;
creators["mc sulfuron harbinger fire resistance"] = &RaidMcTriggerContext::sulfuron_harbinger_fire_resistance;
creators["mc golemagg fire resistance"] = &RaidMcTriggerContext::golemagg_fire_resistance;
creators["mc golemagg mark boss"] = &RaidMcTriggerContext::golemagg_mark_boss;
creators["mc golemagg is main tank"] = &RaidMcTriggerContext::golemagg_is_main_tank;
creators["mc golemagg is assist tank"] = &RaidMcTriggerContext::golemagg_is_assist_tank;
creators["mc majordomo shadow resistance"] = &RaidMcTriggerContext::majordomo_shadow_resistance;
creators["mc ragnaros fire resistance"] = &RaidMcTriggerContext::ragnaros_fire_resistance;
}
private:
static Trigger* lucifron_shadow_resistance(PlayerbotAI* botAI) { return new BossShadowResistanceTrigger(botAI, "lucifron"); }
static Trigger* magmadar_fire_resistance(PlayerbotAI* botAI) { return new BossFireResistanceTrigger(botAI, "magmadar"); }
static Trigger* gehennas_shadow_resistance(PlayerbotAI* botAI) { return new BossShadowResistanceTrigger(botAI, "gehennas"); }
static Trigger* garr_fire_resistance(PlayerbotAI* botAI) { return new BossFireResistanceTrigger(botAI, "garr"); }
static Trigger* baron_geddon_fire_resistance(PlayerbotAI* botAI) { return new BossFireResistanceTrigger(botAI, "baron geddon"); }
static Trigger* living_bomb_debuff(PlayerbotAI* botAI) { return new McLivingBombDebuffTrigger(botAI); }
static Trigger* baron_geddon_inferno(PlayerbotAI* botAI) { return new McBaronGeddonInfernoTrigger(botAI); }
static Trigger* shazzrah_ranged(PlayerbotAI* botAI) { return new McShazzrahRangedTrigger(botAI); }
static Trigger* sulfuron_harbinger_fire_resistance(PlayerbotAI* botAI) { return new BossFireResistanceTrigger(botAI, "sulfuron harbinger"); }
static Trigger* golemagg_fire_resistance(PlayerbotAI* botAI) { return new BossFireResistanceTrigger(botAI, "golemagg the incinerator"); }
static Trigger* golemagg_mark_boss(PlayerbotAI* botAI) { return new McGolemaggMarkBossTrigger(botAI); }
static Trigger* golemagg_is_main_tank(PlayerbotAI* botAI) { return new McGolemaggIsMainTankTrigger(botAI); }
static Trigger* golemagg_is_assist_tank(PlayerbotAI* botAI) { return new McGolemaggIsAssistTankTrigger(botAI); }
static Trigger* majordomo_shadow_resistance(PlayerbotAI* botAI) { return new BossShadowResistanceTrigger(botAI, "majordomo executus"); }
static Trigger* ragnaros_fire_resistance(PlayerbotAI* botAI) { return new BossFireResistanceTrigger(botAI, "ragnaros"); }
};
#endif

View File

@@ -1,81 +0,0 @@
#include "RaidMcStrategy.h"
#include "RaidMcMultipliers.h"
#include "Strategy.h"
void RaidMcStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
// Lucifron
triggers.push_back(
new TriggerNode("mc lucifron shadow resistance",
{ NextAction("mc lucifron shadow resistance", ACTION_RAID) }));
// Magmadar
// TODO: Fear ward / tremor totem, or general anti-fear strat development. Same as King Dred (Drak'Tharon) and faction commander (Nexus).
triggers.push_back(
new TriggerNode("mc magmadar fire resistance",
{ NextAction("mc magmadar fire resistance", ACTION_RAID) }));
// Gehennas
triggers.push_back(
new TriggerNode("mc gehennas shadow resistance",
{ NextAction("mc gehennas shadow resistance", ACTION_RAID) }));
// Garr
triggers.push_back(
new TriggerNode("mc garr fire resistance",
{ NextAction("mc garr fire resistance", ACTION_RAID) }));
// Baron Geddon
triggers.push_back(
new TriggerNode("mc baron geddon fire resistance",
{ NextAction("mc baron geddon fire resistance", ACTION_RAID) }));
triggers.push_back(
new TriggerNode("mc living bomb debuff",
{ NextAction("mc move from group", ACTION_RAID) }));
triggers.push_back(
new TriggerNode("mc baron geddon inferno",
{ NextAction("mc move from baron geddon", ACTION_RAID) }));
// Shazzrah
triggers.push_back(
new TriggerNode("mc shazzrah ranged",
{ NextAction("mc shazzrah move away", ACTION_RAID) }));
// Sulfuron Harbinger
// Alternatively, shadow resistance is also possible.
triggers.push_back(
new TriggerNode("mc sulfuron harbinger fire resistance",
{ NextAction("mc sulfuron harbinger fire resistance", ACTION_RAID) }));
// Golemagg the Incinerator
triggers.push_back(
new TriggerNode("mc golemagg fire resistance",
{ NextAction("mc golemagg fire resistance", ACTION_RAID) }));
triggers.push_back(
new TriggerNode("mc golemagg mark boss",
{ NextAction("mc golemagg mark boss", ACTION_RAID) }));
triggers.push_back(
new TriggerNode("mc golemagg is main tank",
{ NextAction("mc golemagg main tank attack golemagg", ACTION_RAID) }));
triggers.push_back(
new TriggerNode("mc golemagg is assist tank",
{ NextAction("mc golemagg assist tank attack core rager", ACTION_RAID) }));
// Majordomo Executus
triggers.push_back(
new TriggerNode("mc majordomo shadow resistance",
{ NextAction("mc majordomo shadow resistance", ACTION_RAID) }));
// Ragnaros
triggers.push_back(
new TriggerNode("mc ragnaros fire resistance",
{ NextAction("mc ragnaros fire resistance", ACTION_RAID) }));
}
void RaidMcStrategy::InitMultipliers(std::vector<Multiplier*>& multipliers)
{
multipliers.push_back(new GarrDisableDpsAoeMultiplier(botAI));
multipliers.push_back(new BaronGeddonAbilityMultiplier(botAI));
multipliers.push_back(new GolemaggMultiplier(botAI));
}

View File

@@ -1,17 +0,0 @@
#ifndef _PLAYERBOT_RAIDMCSTRATEGY_H
#define _PLAYERBOT_RAIDMCSTRATEGY_H
#include "AiObjectContext.h"
#include "Multiplier.h"
#include "Strategy.h"
class RaidMcStrategy : public Strategy
{
public:
RaidMcStrategy(PlayerbotAI* botAI) : Strategy(botAI) {}
std::string const getName() override { return "moltencore"; }
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
void InitMultipliers(std::vector<Multiplier*> &multipliers) override;
};
#endif

View File

@@ -1,40 +0,0 @@
#include "RaidMcTriggers.h"
#include "SharedDefines.h"
#include "RaidMcHelpers.h"
using namespace MoltenCoreHelpers;
bool McLivingBombDebuffTrigger::IsActive()
{
// No check for Baron Geddon, because bots may have the bomb even after Geddon died.
return bot->HasAura(SPELL_LIVING_BOMB);
}
bool McBaronGeddonInfernoTrigger::IsActive()
{
if (Unit* boss = AI_VALUE2(Unit*, "find target", "baron geddon"))
return boss->HasAura(SPELL_INFERNO);
return false;
}
bool McShazzrahRangedTrigger::IsActive()
{
return AI_VALUE2(Unit*, "find target", "shazzrah") && PlayerbotAI::IsRanged(bot);
}
bool McGolemaggMarkBossTrigger::IsActive()
{
// any tank may mark the boss
return AI_VALUE2(Unit*, "find target", "golemagg the incinerator") && PlayerbotAI::IsTank(bot);
}
bool McGolemaggIsMainTankTrigger::IsActive()
{
return AI_VALUE2(Unit*, "find target", "golemagg the incinerator") && PlayerbotAI::IsMainTank(bot);
}
bool McGolemaggIsAssistTankTrigger::IsActive()
{
return AI_VALUE2(Unit*, "find target", "golemagg the incinerator") && PlayerbotAI::IsAssistTank(bot);
}

View File

@@ -1,50 +0,0 @@
#ifndef _PLAYERBOT_RAIDMCTRIGGERS_H
#define _PLAYERBOT_RAIDMCTRIGGERS_H
#include "PlayerbotAI.h"
#include "Playerbots.h"
#include "Trigger.h"
class McLivingBombDebuffTrigger : public Trigger
{
public:
McLivingBombDebuffTrigger(PlayerbotAI* botAI) : Trigger(botAI, "mc living bomb debuff") {}
bool IsActive() override;
};
class McBaronGeddonInfernoTrigger : public Trigger
{
public:
McBaronGeddonInfernoTrigger(PlayerbotAI* botAI) : Trigger(botAI, "mc baron geddon inferno") {}
bool IsActive() override;
};
class McShazzrahRangedTrigger : public Trigger
{
public:
McShazzrahRangedTrigger(PlayerbotAI* botAI) : Trigger(botAI, "mc shazzrah ranged") {}
bool IsActive() override;
};
class McGolemaggMarkBossTrigger : public Trigger
{
public:
McGolemaggMarkBossTrigger(PlayerbotAI* botAI) : Trigger(botAI, "mc golemagg mark boss") {}
bool IsActive() override;
};
class McGolemaggIsMainTankTrigger : public Trigger
{
public:
McGolemaggIsMainTankTrigger(PlayerbotAI* botAI) : Trigger(botAI, "mc golemagg is main tank") {}
bool IsActive() override;
};
class McGolemaggIsAssistTankTrigger : public Trigger
{
public:
McGolemaggIsAssistTankTrigger(PlayerbotAI* botAI) : Trigger(botAI, "mc golemagg is assist tank") {}
bool IsActive() override;
};
#endif

View File

@@ -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));
}

View File

@@ -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)
{
}

View File

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

View File

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

View File

@@ -1,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); }

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