mirror of
https://github.com/liyunfan1223/mod-playerbots.git
synced 2026-06-20 15:39:25 +02:00
Compare commits
No commits in common. "38caa1daa7399f272267cd6ffc9d2d4f154b7f3e" and "e1f5064c9df720d33bbe7a52525b44ee895e283b" have entirely different histories.
38caa1daa7
...
e1f5064c9d
2
.github/workflows/core_build.yml
vendored
2
.github/workflows/core_build.yml
vendored
@ -39,7 +39,7 @@ jobs:
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
repository: 'mod-playerbots/azerothcore-wotlk'
|
||||
ref: ${{ (github.base_ref || github.ref_name) == 'test-staging' && 'test-staging' || 'Playerbot' }}
|
||||
ref: 'Playerbot'
|
||||
|
||||
- name: Set reusable strings
|
||||
id: strings
|
||||
|
||||
39
.github/workflows/label_translation-pr.yml
vendored
39
.github/workflows/label_translation-pr.yml
vendored
@ -1,39 +0,0 @@
|
||||
name: Label translation PRs
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [opened, synchronize, reopened]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
label-translation:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Fetch PR diff
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
gh api \
|
||||
repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }} \
|
||||
--header "Accept: application/vnd.github.v3.diff" > pr.diff
|
||||
|
||||
- name: Detect ai_playerbot_texts inserts
|
||||
id: detect
|
||||
run: |
|
||||
if grep -E '^\+.*INSERT[[:space:]]+INTO[[:space:]]+`?ai_playerbot_texts`?' pr.diff; then
|
||||
echo "has_translation=true" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "has_translation=false" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
- name: Add label
|
||||
if: steps.detect.outputs.has_translation == 'true'
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
gh pr edit ${{ github.event.pull_request.number }} \
|
||||
--repo ${{ github.repository }} \
|
||||
--add-label "Added translation"
|
||||
2
.github/workflows/macos_build.yml
vendored
2
.github/workflows/macos_build.yml
vendored
@ -23,7 +23,7 @@ jobs:
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: 'mod-playerbots/azerothcore-wotlk'
|
||||
ref: ${{ (github.base_ref || github.ref_name) == 'test-staging' && 'test-staging' || 'Playerbot' }}
|
||||
ref: 'Playerbot'
|
||||
- name: Checkout Playerbot Module
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
|
||||
2
.github/workflows/windows_build.yml
vendored
2
.github/workflows/windows_build.yml
vendored
@ -24,7 +24,7 @@ jobs:
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
repository: 'mod-playerbots/azerothcore-wotlk'
|
||||
ref: ${{ (github.base_ref || github.ref_name) == 'test-staging' && 'test-staging' || 'Playerbot' }}
|
||||
ref: 'Playerbot'
|
||||
path: 'ac'
|
||||
- name: Checkout Playerbot Module
|
||||
uses: actions/checkout@v3
|
||||
|
||||
@ -32,7 +32,7 @@
|
||||
# LEVELS
|
||||
# GEAR
|
||||
# QUESTS
|
||||
# ACTIVITY
|
||||
# ACTIVITIES
|
||||
# SPELLS
|
||||
# STRATEGIES
|
||||
# RPG STRATEGY
|
||||
@ -581,10 +581,10 @@ AiPlayerbot.AutoGearScoreLimit = 0
|
||||
# Default: food, taxi, and raid are enabled
|
||||
AiPlayerbot.BotCheats = "food,taxi,raid"
|
||||
|
||||
# List of attunement quests (comma-separated list of quest IDs) that are automatically completed for all bots.
|
||||
# While mod-playerbots does not restore removed attunement requirements, other mods, such as mod-individual-progression, may do so.
|
||||
# List of attunement quests (comma-separated list of quest IDs) that are automatically completed for all bots.
|
||||
# While mod-playerbots does not restore removed attunement requirements, although other mods, such as mod-individual-progression, may do so.
|
||||
# This is meant to exclude bots from such requirements.
|
||||
#
|
||||
#
|
||||
# Default:
|
||||
# Caverns of Time - Part 1
|
||||
# - 10279, To The Master's Lair
|
||||
@ -651,14 +651,9 @@ AiPlayerbot.BotTaxiGapJitterMs = 100
|
||||
|
||||
####################################################################################################
|
||||
# PROFESSIONS
|
||||
# Note: Random bots currently do not get professions
|
||||
#
|
||||
|
||||
# Percentage of randombots in each class bucket that receive a class-matching
|
||||
# weighted profession combination. The remaining randombots use the weighted
|
||||
# random sane-pair profession pool.
|
||||
# Default: 30
|
||||
AiPlayerbot.ClassMatchingProfessionChance = 30
|
||||
|
||||
# Automatically adds the 'master fishing' strategy to bots that have the fishing skill when the bots master fishes.
|
||||
# Default: 1 (Enabled)
|
||||
AiPlayerbot.EnableFishingWithMaster = 1
|
||||
@ -806,27 +801,6 @@ AiPlayerbot.RandomGearQualityLimit = 3
|
||||
# Default: 0 (no limit)
|
||||
AiPlayerbot.RandomGearScoreLimit = 0
|
||||
|
||||
# Prefer armor of the class's ideal type: apply 3x score multiplier to class-appropriate armor.
|
||||
# When enabled, Warriors strongly prefer plate, Shamans prefer mail, etc.
|
||||
# A truly superior item can still win (no hard filtering), but same-quality
|
||||
# armor of the preferred type will score 3x higher and be equipped instead.
|
||||
#
|
||||
# ARMOR TYPE PREFERENCES:
|
||||
# Plate: Warriors, Paladins, Death Knights
|
||||
# Mail: Hunters, Shamans
|
||||
# Leather: Rogues, Druids
|
||||
# Cloth: Priests, Mages, Warlocks
|
||||
#
|
||||
# Default: 0 (disabled)
|
||||
AiPlayerbot.PreferClassArmorType = 0
|
||||
|
||||
|
||||
# When enabled, bots prefer spec-appropriate weapons based on speed and weapon type during autogear.
|
||||
# Examples: Arms Warriors favor slow 2H axes/polearms (Axe Specialization), Combat Rogues
|
||||
# favor a slow MH with a fast OH, and Enhancement Shamans favor synchronized slow 1H weapons.
|
||||
# Default: 0 (disabled)
|
||||
AiPlayerbot.PreferredSpecWeapons = 0
|
||||
|
||||
# If disabled, random bots can only upgrade equipment through looting and quests
|
||||
# Default: 1 (enabled)
|
||||
AiPlayerbot.IncrementalGearInit = 1
|
||||
@ -891,65 +865,34 @@ AiPlayerbot.ExcludedHunterPetFamilies = ""
|
||||
#
|
||||
#
|
||||
####################################################################################################
|
||||
####################################################################################################
|
||||
# ACTIVITY
|
||||
#
|
||||
# BotActiveAlone
|
||||
# - Controls how many bots are active when no real players are nearby.
|
||||
# - Think of it as a rough percentage: 10 means approximately 10% of bots will be active.
|
||||
# Not exact — the actual number may vary slightly per rotation cycle.
|
||||
# - The active bots rotate: every <DurationSeconds> a different set of bots takes a turn.
|
||||
# - The real number of active bots will always be higher than this value, because bots in
|
||||
# combat, dungeons, battlegrounds, LFG queue, groups with real players, etc. are always
|
||||
# forced active on top of this (see force rules below).
|
||||
# - Set to 100 (with SmartScale off) = all bots always active. Maximum server load.
|
||||
# - Set to 0 = only bots that match a force rule below will be active.
|
||||
#
|
||||
# BotActiveAloneDurationSeconds
|
||||
# - How often the active roster rotates (in seconds). A different group of bots wakes up
|
||||
# and the previous group may go idle.
|
||||
# - This is a minimum, not exact. If a bot is in combat or meets any force rule when the
|
||||
# rotation happens, it stays active until those conditions end — it won't be cut off
|
||||
# mid-fight just because its turn expired.
|
||||
#
|
||||
AiPlayerbot.BotActiveAlone = 10
|
||||
AiPlayerbot.BotActiveAloneDurationSeconds = 30
|
||||
|
||||
|
||||
####################################################################################################
|
||||
# ACTIVITIES
|
||||
#
|
||||
# Force-active rules (1 = on, 0 = off)
|
||||
# These override the percentage above. If any of these conditions is true, the bot stays active.
|
||||
#
|
||||
# InRadius - A real player is within this many yards (set to 0 to disable).
|
||||
# InZone - A real player is in the same zone (e.g. Elwynn Forest).
|
||||
# InMap - A real player is on the same continent (e.g. Eastern Kingdoms).
|
||||
# IsFriend - A real player has this bot on their friends list.
|
||||
# InGuild - This bot is in a guild that has a real player in it.
|
||||
#
|
||||
# Bots are also always forced active (not configurable) when:
|
||||
# in combat, inside a dungeon/raid/BG, in a BG or LFG queue,
|
||||
# grouped with a real player, or controlled by a real player.
|
||||
#
|
||||
# Specify percent of active bots
|
||||
# The default is 100% but will be automatically adjusted if botActiveAloneSmartScale
|
||||
# is enabled. Regardless, this value is only applied to inactive areas where no real players
|
||||
# are detected. When real players are nearby, the value is always enforced to 100%
|
||||
AiPlayerbot.BotActiveAlone = 100
|
||||
|
||||
# Force botActiveAlone when bot is within the specified distance of a real player
|
||||
AiPlayerbot.BotActiveAloneForceWhenInRadius = 150
|
||||
AiPlayerbot.BotActiveAloneForceWhenInZone = 1
|
||||
AiPlayerbot.BotActiveAloneForceWhenInMap = 0
|
||||
AiPlayerbot.BotActiveAloneForceWhenIsFriend = 0
|
||||
AiPlayerbot.BotActiveAloneForceWhenIsFriend = 1
|
||||
AiPlayerbot.BotActiveAloneForceWhenInGuild = 1
|
||||
|
||||
# SmartScale — automatically reduces active bots when the server is struggling.
|
||||
# Monitors the server's update time (how long each server tick takes in milliseconds).
|
||||
# When the server slows down, fewer bots are kept active to reduce load.
|
||||
# SmartScale (automatic scaling of percentage of active bots based on latency)
|
||||
# The default is 1. When enabled (smart) scales the 'BotActiveAlone' value.
|
||||
# (The scaling will be overruled by the BotActiveAloneForceWhen...rules)
|
||||
#
|
||||
# Floor (default 50ms) - Below this, no reduction. Server is running fine.
|
||||
# Ceiling (default 200ms) - At or above this, all non-forced bots are paused.
|
||||
# Between floor and ceiling, activity scales down gradually.
|
||||
# Example: BotActiveAlone=10, floor=50, ceiling=200
|
||||
# Server at 50ms → ~10% active (no reduction)
|
||||
# Server at 125ms → ~5% active (half reduction)
|
||||
# Server at 200ms → 0% active (only forced bots remain)
|
||||
# Limitfloor - when DIFF (latency) is above floor, activity scaling begins
|
||||
# LimitCeiling - when DIFF (latency) is above ceiling, activity is 0%
|
||||
#
|
||||
# MinLevel/MaxLevel — only bots within this level range are affected by SmartScale.
|
||||
# Bots outside the range always use the full BotActiveAlone value.
|
||||
# Force rules always win over SmartScale.
|
||||
# MinLevel - only apply scaling when level is above or equal to min(bot)Level
|
||||
# MaxLevel - only apply scaling when level is lower or equal of max(bot)Level
|
||||
#
|
||||
AiPlayerbot.botActiveAloneSmartScale = 1
|
||||
AiPlayerbot.botActiveAloneSmartScaleDiffLimitfloor = 50
|
||||
@ -1064,7 +1007,6 @@ AiPlayerbot.EnableNewRpgStrategy = 1
|
||||
# DoQuest (Default: 60 Select quest from the quest log and head to the location to attempt completion)
|
||||
# TravelFlight (Default: 15 Go to the nearest flightmaster and fly to a level-appropriate area)
|
||||
# Rest (Default: 5 Take a break for a while and do nothing)
|
||||
# OutdoorPvp (Default: 10 Participate in outdoor PvP capture points if already in an outdoor PvP zone)
|
||||
AiPlayerbot.RpgStatusProbWeight.WanderRandom = 15
|
||||
AiPlayerbot.RpgStatusProbWeight.WanderNpc = 20
|
||||
AiPlayerbot.RpgStatusProbWeight.GoGrind = 15
|
||||
@ -1072,7 +1014,6 @@ AiPlayerbot.RpgStatusProbWeight.GoCamp = 10
|
||||
AiPlayerbot.RpgStatusProbWeight.DoQuest = 60
|
||||
AiPlayerbot.RpgStatusProbWeight.TravelFlight = 15
|
||||
AiPlayerbot.RpgStatusProbWeight.Rest = 5
|
||||
AiPlayerbot.RpgStatusProbWeight.OutdoorPvp = 10
|
||||
|
||||
# Bots' minimum and maximum level when teleporting in and out of a zone, according to the new RPG strategy
|
||||
# Format: AiPlayerbot.ZoneBracket.zoneID = minLevel,maxLevel
|
||||
@ -1345,7 +1286,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,4085,4086,4087,4088"
|
||||
AiPlayerbot.PvpProhibitedAreaIds = "976,35,392,2268,4161,4010,4317,4312,3649,3887,3958,3724,4080,3938,3754,3786,3973"
|
||||
|
||||
# Improve reaction speeds in battlegrounds and arenas (may cause lag)
|
||||
AiPlayerbot.FastReactInBG = 1
|
||||
@ -1746,7 +1687,7 @@ AiPlayerbot.PremadeSpecLink.9.1.60 = -003203301135112530135201051
|
||||
AiPlayerbot.PremadeSpecLink.9.1.70 = -003203301135112530135201051-55
|
||||
AiPlayerbot.PremadeSpecLink.9.1.80 = -003203301135112530135221351-55000005
|
||||
AiPlayerbot.PremadeSpecName.9.2 = destro pve
|
||||
AiPlayerbot.PremadeSpecGlyph.9.2 = 45785,43390,42454,43394,43393,42453
|
||||
AiPlayerbot.PremadeSpecGlyph.9.2 = 45785,43390,42454,43394,43393,45785
|
||||
AiPlayerbot.PremadeSpecLink.9.2.60 = --05203215200231051305031151
|
||||
AiPlayerbot.PremadeSpecLink.9.2.80 = 23-0302-05203215220331051335231351
|
||||
AiPlayerbot.PremadeSpecName.9.3 = affli pvp
|
||||
@ -1823,10 +1764,10 @@ AiPlayerbot.PremadeSpecLink.11.6.80 = 05320021--230033312031500531353013251
|
||||
# Requires sending the command "nc +worldbuff" in chat to a bot (or a group of bots) to enable
|
||||
# Each entry in the matrix should be formatted as follows: Entry:FactionID,ClassID,SpecID,MinimumLevel,MaximumLevel:SpellID1,SpellID2,etc.;
|
||||
# FactionID may be set to 0 for the entry to apply buffs to bots of either faction
|
||||
# The default entries create a cross-faction level 60-69 Vanilla buffs, level 70-79 TBC buffs, and level 80 buffs for each implemented pve spec from the "Premade Specs" section
|
||||
# The default entries create a cross-faction list of level 80 buffs for each implemented pve spec from the "Premade Specs" section
|
||||
# The default entries may be deleted or modified, and new custom entries may be added
|
||||
|
||||
AiPlayerbot.WorldBuffMatrix = # WARRIOR ARMS 1:0,1,0,80,80:53760,57358; # WARRIOR FURY 2:0,1,1,80,80:53760,57358; # WARRIOR PROTECTION 3:0,1,2,80,80:53758,57356; # PALADIN HOLY 4:0,2,0,80,80:53749,57332,60347; # PALADIN PROTECTION 5:0,2,1,80,80:53758,57356; # PALADIN RETRIBUTION 6:0,2,2,80,80:53760,57371; # HUNTER BEAST 7:0,3,0,80,80:53760,57325; # HUNTER MARKSMANSHIP 8:0,3,1,80,80:53760,57358; # HUNTER SURVIVAL 9:0,3,2,80,80:53760,57367; # ROGUE ASSASSINATION 10:0,4,0,80,80:53760,57325; # ROGUE COMBAT 11:0,4,1,80,80:53760,57358; # ROGUE SUBTLETY 12:0,4,2,80,80:53760,57367; # PRIEST DISCIPLINE 13:0,5,0,80,80:53755,57327; # PRIEST HOLY 14:0,5,1,80,80:53755,57327; # PRIEST SHADOW 15:0,5,2,80,80:53755,57327; # DEATH KNIGHT BLOOD 16:0,6,0,80,80:53758,57356; # DEATH KNIGHT FROST 17:0,6,1,80,80:53760,57358; # DEATH KNIGHT UNHOLY 18:0,6,2,80,80:53760,57358; # DEATH KNIGHT BLOOD DPS 19:0,6,3,80,80:53760,57371; # SHAMAN ELEMENTAL 20:0,7,0,80,80:53755,57327; # SHAMAN ENHANCEMENT 21:0,7,1,80,80:53760,57325; # SHAMAN RESTORATION 22:0,7,2,80,80:53755,57327; # MAGE ARCANE 23:0,8,0,80,80:53755,57327; # MAGE FIRE 24:0,8,1,80,80:53755,57327; # MAGE FROST 25:0,8,2,80,80:53755,57327; # WARLOCK AFFLICTION 26:0,9,0,80,80:53755,57327; # WARLOCK DEMONOLOGY 27:0,9,1,80,80:53755,57327; # WARLOCK DESTRUCTION 28:0,9,2,80,80:53755,57327; # DRUID BALANCE 29:0,11,0,80,80:53755,57327; # DRUID FERAL BEAR 30:0,11,1,80,80:53749,53763,57367; # DRUID RESTORATION 31:0,11,2,80,80:54212,57334; # DRUID FERAL CAT 32:0,11,3,80,80:53760,57358; # WARRIOR ARMS TBC 33:0,1,0,70,79:28520,33256; # WARRIOR FURY TBC 34:0,1,1,70,79:28520,33256; # WARRIOR PROTECTION TBC 35:0,1,2,70,79:28518,33257; # PALADIN HOLY TBC 36:0,2,0,70,79:28491,39627,33263; # PALADIN PROTECTION TBC 37:0,2,1,70,79:28518,33257; # PALADIN RETRIBUTION TBC 38:0,2,2,70,79:28520,33256; # HUNTER BEAST TBC 39:0,3,0,70,79:28520,33261; # HUNTER MARKSMANSHIP TBC 40:0,3,1,70,79:28520,33261; # HUNTER SURVIVAL TBC 41:0,3,2,70,79:28520,33261; # ROGUE ASSASSINATION TBC 42:0,4,0,70,79:28520,33261; # ROGUE COMBAT TBC 43:0,4,1,70,79:28520,33261; # ROGUE SUBTLETY TBC 44:0,4,2,70,79:28520,33261; # PRIEST DISCIPLINE TBC 45:0,5,0,70,79:28491,39627,33263; # PRIEST HOLY TBC 46:0,5,1,70,79:28491,39627,33263; # PRIEST SHADOW TBC 47:0,5,2,70,79:28540,33263; # SHAMAN ELEMENTAL TBC 48:0,7,0,70,79:28521,33263; # SHAMAN ENHANCEMENT TBC 49:0,7,1,70,79:28520,33261; # SHAMAN RESTORATION TBC 50:0,7,2,70,79:28491,39627,33263; # MAGE ARCANE TBC 51:0,8,0,70,79:28521,33263; # MAGE FIRE TBC 52:0,8,1,70,79:28540,33263; # MAGE FROST TBC 53:0,8,2,70,79:28540,33263; # WARLOCK AFFLICTION TBC 54:0,9,0,70,79:28540,33263; # WARLOCK DEMONOLOGY TBC 55:0,9,1,70,79:28540,33263; # WARLOCK DESTRUCTION TBC 56:0,9,2,70,79:28540,33263; # DRUID BALANCE TBC 57:0,11,0,70,79:28521,33263; # DRUID FERAL BEAR TBC 58:0,11,1,70,79:28518,33257; # DRUID RESTORATION TBC 59:0,11,2,70,79:28491,39627,33263; # DRUID FERAL CAT TBC 60:0,11,3,70,79:28520,33261; # WARRIOR ARMS VANILLA 61:0,1,0,60,69:17538,24799; # WARRIOR FURY VANILLA 62:0,1,1,60,69:17538,24799; # WARRIOR PROTECTION VANILLA 63:0,1,2,60,69:17626,25661; # PALADIN HOLY VANILLA 64:0,2,0,60,69:17627,18194; # PALADIN PROTECTION VANILLA 65:0,2,1,60,69:17626,25661; # PALADIN RETRIBUTION VANILLA 66:0,2,2,60,69:17628,24799; # HUNTER BEAST VANILLA 67:0,3,0,60,69:17538,18192; # HUNTER MARKSMANSHIP VANILLA 68:0,3,1,60,69:17538,18192; # HUNTER SURVIVAL VANILLA 69:0,3,2,60,69:17538,18192; # ROGUE ASSASSINATION VANILLA 70:0,4,0,60,69:17538,18192; # ROGUE COMBAT VANILLA 71:0,4,1,60,69:17538,18192; # ROGUE SUBTLETY VANILLA 72:0,4,2,60,69:17538,18192; # PRIEST DISCIPLINE VANILLA 73:0,5,0,60,69:17628,18194; # PRIEST HOLY VANILLA 74:0,5,1,60,69:17627,18194; # PRIEST SHADOW VANILLA 75:0,5,2,60,69:17628,18194; # SHAMAN ELEMENTAL VANILLA 76:0,7,0,60,69:17628,18194; # SHAMAN ENHANCEMENT VANILLA 77:0,7,1,60,69:17538,24799; # SHAMAN RESTORATION VANILLA 78:0,7,2,60,69:17627,18194; # MAGE ARCANE VANILLA 79:0,8,0,60,69:17628,18194; # MAGE FIRE VANILLA 80:0,8,1,60,69:17628,18194; # MAGE FROST VANILLA 81:0,8,2,60,69:17628,18194; # WARLOCK AFFLICTION VANILLA 82:0,9,0,60,69:17628,25661; # WARLOCK DEMONOLOGY VANILLA 83:0,9,1,60,69:17628,25661; # WARLOCK DESTRUCTION VANILLA 84:0,9,2,60,69:17628,25661; # DRUID BALANCE VANILLA 85:0,11,0,60,69:17628,18194; # DRUID FERAL BEAR VANILLA 86:0,11,1,60,69:17626,25661; # DRUID RESTORATION VANILLA 87:0,11,2,60,69:17627,18194; # DRUID FERAL CAT VANILLA 88:0,11,3,60,69:17538,24799
|
||||
AiPlayerbot.WorldBuffMatrix = # WARRIOR ARMS 1:0,1,0,80,80:53760,57358; # WARRIOR FURY 2:0,1,1,80,80:53760,57358; # WARRIOR PROTECTION 3:0,1,2,80,80:53758,57356; # PALADIN HOLY 4:0,2,0,80,80:53749,57332,60347; # PALADIN PROTECTION 5:0,2,1,80,80:53758,57356; # PALADIN RETRIBUTION 6:0,2,2,80,80:53760,57371; # HUNTER BEAST 7:0,3,0,80,80:53760,57325; # HUNTER MARKSMANSHIP 8:0,3,1,80,80:53760,57358; # HUNTER SURVIVAL 9:0,3,2,80,80:53760,57367; # ROGUE ASSASSINATION 10:0,4,0,80,80:53760,57325; # ROGUE COMBAT 11:0,4,1,80,80:53760,57358; # ROGUE SUBTLETY 12:0,4,2,80,80:53760,57367; # PRIEST DISCIPLINE 13:0,5,0,80,80:53755,57327; # PRIEST HOLY 14:0,5,1,80,80:53755,57327; # PRIEST SHADOW 15:0,5,2,80,80:53755,57327; # DEATH KNIGHT BLOOD 16:0,6,0,80,80:53758,57356; # DEATH KNIGHT FROST 17:0,6,1,80,80:53760,57358; # DEATH KNIGHT UNHOLY 18:0,6,2,80,80:53760,57358; # DEATH KNIGHT BLOOD DPS 19:0,6,3,80,80:53760,57371; # SHAMAN ELEMENTAL 20:0,7,0,80,80:53755,57327; # SHAMAN ENHANCEMENT 21:0,7,1,80,80:53760,57325; # SHAMAN RESTORATION 22:0,7,2,80,80:53755,57327; # MAGE ARCANE 23:0,8,0,80,80:53755,57327; # MAGE FIRE 24:0,8,1,80,80:53755,57327; # MAGE FROST 25:0,8,2,80,80:53755,57327; # WARLOCK AFFLICTION 26:0,9,0,80,80:53755,57327; # WARLOCK DEMONOLOGY 27:0,9,1,80,80:53755,57327; # WARLOCK DESTRUCTION 28:0,9,2,80,80:53755,57327; # DRUID BALANCE 29:0,11,0,80,80:53755,57327; # DRUID FERAL BEAR 30:0,11,1,80,80:53749,53763,57367; # DRUID RESTORATION 31:0,11,2,80,80:54212,57334; # DRUID FERAL CAT 32:0,11,3,80,80:53760,57358
|
||||
|
||||
#
|
||||
#
|
||||
@ -1857,24 +1798,12 @@ AiPlayerbot.WorldBuffMatrix = # WARRIOR ARMS 1:0,1,0,80,80:53760,57358; # WARRIO
|
||||
#
|
||||
#
|
||||
|
||||
# arms pve
|
||||
AiPlayerbot.RandomClassSpecProb.1.0 = 20
|
||||
AiPlayerbot.RandomClassSpecIndex.1.0 = 0
|
||||
# fury pve
|
||||
AiPlayerbot.RandomClassSpecProb.1.1 = 40
|
||||
AiPlayerbot.RandomClassSpecIndex.1.1 = 1
|
||||
# prot pve
|
||||
AiPlayerbot.RandomClassSpecProb.1.2 = 40
|
||||
AiPlayerbot.RandomClassSpecIndex.1.2 = 2
|
||||
# arms pvp
|
||||
AiPlayerbot.RandomClassSpecProb.1.3 = 0
|
||||
AiPlayerbot.RandomClassSpecIndex.1.3 = 3
|
||||
# fury pvp
|
||||
AiPlayerbot.RandomClassSpecProb.1.4 = 0
|
||||
AiPlayerbot.RandomClassSpecIndex.1.4 = 4
|
||||
# prot pvp
|
||||
AiPlayerbot.RandomClassSpecProb.1.5 = 0
|
||||
AiPlayerbot.RandomClassSpecIndex.1.5 = 5
|
||||
|
||||
#
|
||||
#
|
||||
@ -1886,24 +1815,12 @@ AiPlayerbot.RandomClassSpecIndex.1.5 = 5
|
||||
#
|
||||
#
|
||||
|
||||
# holy pve
|
||||
AiPlayerbot.RandomClassSpecProb.2.0 = 30
|
||||
AiPlayerbot.RandomClassSpecIndex.2.0 = 0
|
||||
# prot pve
|
||||
AiPlayerbot.RandomClassSpecProb.2.1 = 40
|
||||
AiPlayerbot.RandomClassSpecIndex.2.1 = 1
|
||||
# ret pve
|
||||
AiPlayerbot.RandomClassSpecProb.2.2 = 30
|
||||
AiPlayerbot.RandomClassSpecIndex.2.2 = 2
|
||||
# holy pvp
|
||||
AiPlayerbot.RandomClassSpecProb.2.3 = 0
|
||||
AiPlayerbot.RandomClassSpecIndex.2.3 = 3
|
||||
# prot pvp
|
||||
AiPlayerbot.RandomClassSpecProb.2.4 = 0
|
||||
AiPlayerbot.RandomClassSpecIndex.2.4 = 4
|
||||
# ret pvp
|
||||
AiPlayerbot.RandomClassSpecProb.2.5 = 0
|
||||
AiPlayerbot.RandomClassSpecIndex.2.5 = 5
|
||||
|
||||
#
|
||||
#
|
||||
@ -1915,24 +1832,12 @@ AiPlayerbot.RandomClassSpecIndex.2.5 = 5
|
||||
#
|
||||
#
|
||||
|
||||
# bm pve
|
||||
AiPlayerbot.RandomClassSpecProb.3.0 = 33
|
||||
AiPlayerbot.RandomClassSpecIndex.3.0 = 0
|
||||
# mm pve
|
||||
AiPlayerbot.RandomClassSpecProb.3.1 = 33
|
||||
AiPlayerbot.RandomClassSpecIndex.3.1 = 1
|
||||
# surv pve
|
||||
AiPlayerbot.RandomClassSpecProb.3.2 = 33
|
||||
AiPlayerbot.RandomClassSpecIndex.3.2 = 2
|
||||
# bm pvp
|
||||
AiPlayerbot.RandomClassSpecProb.3.3 = 0
|
||||
AiPlayerbot.RandomClassSpecIndex.3.3 = 3
|
||||
# mm pvp
|
||||
AiPlayerbot.RandomClassSpecProb.3.4 = 0
|
||||
AiPlayerbot.RandomClassSpecIndex.3.4 = 4
|
||||
# surv pvp
|
||||
AiPlayerbot.RandomClassSpecProb.3.5 = 0
|
||||
AiPlayerbot.RandomClassSpecIndex.3.5 = 5
|
||||
|
||||
#
|
||||
#
|
||||
@ -1944,24 +1849,12 @@ AiPlayerbot.RandomClassSpecIndex.3.5 = 5
|
||||
#
|
||||
#
|
||||
|
||||
# as pve
|
||||
AiPlayerbot.RandomClassSpecProb.4.0 = 45
|
||||
AiPlayerbot.RandomClassSpecIndex.4.0 = 0
|
||||
# combat pve
|
||||
AiPlayerbot.RandomClassSpecProb.4.1 = 45
|
||||
AiPlayerbot.RandomClassSpecIndex.4.1 = 1
|
||||
# subtlety pve
|
||||
AiPlayerbot.RandomClassSpecProb.4.2 = 10
|
||||
AiPlayerbot.RandomClassSpecIndex.4.2 = 2
|
||||
# as pvp
|
||||
AiPlayerbot.RandomClassSpecProb.4.3 = 0
|
||||
AiPlayerbot.RandomClassSpecIndex.4.3 = 3
|
||||
# combat pvp
|
||||
AiPlayerbot.RandomClassSpecProb.4.4 = 0
|
||||
AiPlayerbot.RandomClassSpecIndex.4.4 = 4
|
||||
# subtlety pvp
|
||||
AiPlayerbot.RandomClassSpecProb.4.5 = 0
|
||||
AiPlayerbot.RandomClassSpecIndex.4.5 = 5
|
||||
|
||||
#
|
||||
#
|
||||
@ -1973,24 +1866,12 @@ AiPlayerbot.RandomClassSpecIndex.4.5 = 5
|
||||
#
|
||||
#
|
||||
|
||||
# disc pve
|
||||
AiPlayerbot.RandomClassSpecProb.5.0 = 40
|
||||
AiPlayerbot.RandomClassSpecIndex.5.0 = 0
|
||||
# holy pve
|
||||
AiPlayerbot.RandomClassSpecProb.5.1 = 35
|
||||
AiPlayerbot.RandomClassSpecIndex.5.1 = 1
|
||||
# shadow pve
|
||||
AiPlayerbot.RandomClassSpecProb.5.2 = 25
|
||||
AiPlayerbot.RandomClassSpecIndex.5.2 = 2
|
||||
# disc pvp
|
||||
AiPlayerbot.RandomClassSpecProb.5.3 = 0
|
||||
AiPlayerbot.RandomClassSpecIndex.5.3 = 3
|
||||
# holy pvp
|
||||
AiPlayerbot.RandomClassSpecProb.5.4 = 0
|
||||
AiPlayerbot.RandomClassSpecIndex.5.4 = 4
|
||||
# shadow pvp
|
||||
AiPlayerbot.RandomClassSpecProb.5.5 = 0
|
||||
AiPlayerbot.RandomClassSpecIndex.5.5 = 5
|
||||
|
||||
#
|
||||
#
|
||||
@ -2002,27 +1883,12 @@ AiPlayerbot.RandomClassSpecIndex.5.5 = 5
|
||||
#
|
||||
#
|
||||
|
||||
# blood pve
|
||||
AiPlayerbot.RandomClassSpecProb.6.0 = 30
|
||||
AiPlayerbot.RandomClassSpecIndex.6.0 = 0
|
||||
# frost pve
|
||||
AiPlayerbot.RandomClassSpecProb.6.1 = 40
|
||||
AiPlayerbot.RandomClassSpecIndex.6.1 = 1
|
||||
# unholy pve
|
||||
AiPlayerbot.RandomClassSpecProb.6.2 = 30
|
||||
AiPlayerbot.RandomClassSpecIndex.6.2 = 2
|
||||
# double aura blood pve
|
||||
AiPlayerbot.RandomClassSpecProb.6.3 = 0
|
||||
AiPlayerbot.RandomClassSpecIndex.6.3 = 3
|
||||
# blood pvp
|
||||
AiPlayerbot.RandomClassSpecProb.6.4 = 0
|
||||
AiPlayerbot.RandomClassSpecIndex.6.4 = 4
|
||||
# frost pvp
|
||||
AiPlayerbot.RandomClassSpecProb.6.5 = 0
|
||||
AiPlayerbot.RandomClassSpecIndex.6.5 = 5
|
||||
# unholy pvp
|
||||
AiPlayerbot.RandomClassSpecProb.6.6 = 0
|
||||
AiPlayerbot.RandomClassSpecIndex.6.6 = 6
|
||||
|
||||
#
|
||||
#
|
||||
@ -2034,24 +1900,12 @@ AiPlayerbot.RandomClassSpecIndex.6.6 = 6
|
||||
#
|
||||
#
|
||||
|
||||
# ele pve
|
||||
AiPlayerbot.RandomClassSpecProb.7.0 = 33
|
||||
AiPlayerbot.RandomClassSpecIndex.7.0 = 0
|
||||
# enh pve
|
||||
AiPlayerbot.RandomClassSpecProb.7.1 = 33
|
||||
AiPlayerbot.RandomClassSpecIndex.7.1 = 1
|
||||
# resto pve
|
||||
AiPlayerbot.RandomClassSpecProb.7.2 = 33
|
||||
AiPlayerbot.RandomClassSpecIndex.7.2 = 2
|
||||
# ele pvp
|
||||
AiPlayerbot.RandomClassSpecProb.7.3 = 0
|
||||
AiPlayerbot.RandomClassSpecIndex.7.3 = 3
|
||||
# enh pvp
|
||||
AiPlayerbot.RandomClassSpecProb.7.4 = 0
|
||||
AiPlayerbot.RandomClassSpecIndex.7.4 = 4
|
||||
# resto pvp
|
||||
AiPlayerbot.RandomClassSpecProb.7.5 = 0
|
||||
AiPlayerbot.RandomClassSpecIndex.7.5 = 5
|
||||
|
||||
#
|
||||
#
|
||||
@ -2063,27 +1917,12 @@ AiPlayerbot.RandomClassSpecIndex.7.5 = 5
|
||||
#
|
||||
#
|
||||
|
||||
# arcane pve
|
||||
AiPlayerbot.RandomClassSpecProb.8.0 = 30
|
||||
AiPlayerbot.RandomClassSpecIndex.8.0 = 0
|
||||
# fire pve
|
||||
AiPlayerbot.RandomClassSpecProb.8.1 = 30
|
||||
AiPlayerbot.RandomClassSpecIndex.8.1 = 1
|
||||
# frost pve
|
||||
AiPlayerbot.RandomClassSpecProb.8.2 = 40
|
||||
AiPlayerbot.RandomClassSpecIndex.8.2 = 2
|
||||
# frostfire pve
|
||||
AiPlayerbot.RandomClassSpecProb.8.3 = 0
|
||||
AiPlayerbot.RandomClassSpecIndex.8.3 = 3
|
||||
# arcane pvp
|
||||
AiPlayerbot.RandomClassSpecProb.8.4 = 0
|
||||
AiPlayerbot.RandomClassSpecIndex.8.4 = 4
|
||||
# fire pvp
|
||||
AiPlayerbot.RandomClassSpecProb.8.5 = 0
|
||||
AiPlayerbot.RandomClassSpecIndex.8.5 = 5
|
||||
# frost pvp
|
||||
AiPlayerbot.RandomClassSpecProb.8.6 = 0
|
||||
AiPlayerbot.RandomClassSpecIndex.8.6 = 6
|
||||
|
||||
#
|
||||
#
|
||||
@ -2095,24 +1934,12 @@ AiPlayerbot.RandomClassSpecIndex.8.6 = 6
|
||||
#
|
||||
#
|
||||
|
||||
# affli pve
|
||||
AiPlayerbot.RandomClassSpecProb.9.0 = 33
|
||||
AiPlayerbot.RandomClassSpecIndex.9.0 = 0
|
||||
# demo pve
|
||||
AiPlayerbot.RandomClassSpecProb.9.1 = 34
|
||||
AiPlayerbot.RandomClassSpecIndex.9.1 = 1
|
||||
# destro pve
|
||||
AiPlayerbot.RandomClassSpecProb.9.2 = 33
|
||||
AiPlayerbot.RandomClassSpecIndex.9.2 = 2
|
||||
# affli pvp
|
||||
AiPlayerbot.RandomClassSpecProb.9.3 = 0
|
||||
AiPlayerbot.RandomClassSpecIndex.9.3 = 3
|
||||
# demo pvp
|
||||
AiPlayerbot.RandomClassSpecProb.9.4 = 0
|
||||
AiPlayerbot.RandomClassSpecIndex.9.4 = 4
|
||||
# destro pvp
|
||||
AiPlayerbot.RandomClassSpecProb.9.5 = 0
|
||||
AiPlayerbot.RandomClassSpecIndex.9.5 = 5
|
||||
|
||||
#
|
||||
#
|
||||
@ -2124,27 +1951,14 @@ AiPlayerbot.RandomClassSpecIndex.9.5 = 5
|
||||
#
|
||||
#
|
||||
|
||||
# balance pve
|
||||
AiPlayerbot.RandomClassSpecProb.11.0 = 20
|
||||
AiPlayerbot.RandomClassSpecIndex.11.0 = 0
|
||||
# bear pve
|
||||
AiPlayerbot.RandomClassSpecProb.11.1 = 25
|
||||
AiPlayerbot.RandomClassSpecIndex.11.1 = 1
|
||||
# resto pve
|
||||
AiPlayerbot.RandomClassSpecProb.11.2 = 35
|
||||
AiPlayerbot.RandomClassSpecIndex.11.2 = 2
|
||||
# cat pve
|
||||
AiPlayerbot.RandomClassSpecProb.11.3 = 20
|
||||
AiPlayerbot.RandomClassSpecIndex.11.3 = 3
|
||||
# balance pvp
|
||||
AiPlayerbot.RandomClassSpecProb.11.4 = 0
|
||||
AiPlayerbot.RandomClassSpecIndex.11.4 = 4
|
||||
# cat pvp
|
||||
AiPlayerbot.RandomClassSpecProb.11.5 = 0
|
||||
AiPlayerbot.RandomClassSpecIndex.11.5 = 5
|
||||
# resto pvp
|
||||
AiPlayerbot.RandomClassSpecProb.11.6 = 0
|
||||
AiPlayerbot.RandomClassSpecIndex.11.6 = 6
|
||||
|
||||
#
|
||||
#
|
||||
|
||||
@ -1,240 +0,0 @@
|
||||
-- #########################################################
|
||||
-- Playerbots - Add focus heal command texts
|
||||
-- Localized for all WotLK locales (koKR, frFR, deDE, zhCN,
|
||||
-- zhTW, esES, esMX, ruRU)
|
||||
-- #########################################################
|
||||
|
||||
DELETE FROM ai_playerbot_texts WHERE name IN (
|
||||
'focus_heal_not_healer',
|
||||
'focus_heal_provide_names',
|
||||
'focus_heal_no_targets',
|
||||
'focus_heal_current_targets',
|
||||
'focus_heal_cleared',
|
||||
'focus_heal_add_remove_syntax',
|
||||
'focus_heal_not_in_group',
|
||||
'focus_heal_not_in_group_with',
|
||||
'focus_heal_added',
|
||||
'focus_heal_removed'
|
||||
);
|
||||
DELETE FROM ai_playerbot_texts_chance WHERE name IN (
|
||||
'focus_heal_not_healer',
|
||||
'focus_heal_provide_names',
|
||||
'focus_heal_no_targets',
|
||||
'focus_heal_current_targets',
|
||||
'focus_heal_cleared',
|
||||
'focus_heal_add_remove_syntax',
|
||||
'focus_heal_not_in_group',
|
||||
'focus_heal_not_in_group_with',
|
||||
'focus_heal_added',
|
||||
'focus_heal_removed'
|
||||
);
|
||||
|
||||
-- focus_heal_not_healer
|
||||
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 (
|
||||
1745,
|
||||
'focus_heal_not_healer',
|
||||
'I''m not a healer or offhealer (please change my strats to heal or offheal)',
|
||||
0, 0,
|
||||
'저는 힐러나 오프힐러가 아닙니다 (전략을 heal 또는 offheal로 변경해주세요)',
|
||||
'Je ne suis pas un soigneur ou un soigneur secondaire (veuillez changer mes strats en heal ou offheal)',
|
||||
'Ich bin kein Heiler oder Nebenheiler (bitte ändere meine Strategien auf heal oder offheal)',
|
||||
'我不是治疗者或副治疗者(请将我的策略更改为 heal 或 offheal)',
|
||||
'我不是治療者或副治療者(請將我的策略更改為 heal 或 offheal)',
|
||||
'No soy un sanador ni un sanador secundario (por favor cambia mis estrategias a heal o offheal)',
|
||||
'No soy un sanador ni un sanador secundario (por favor cambia mis estrategias a heal o offheal)',
|
||||
'Я не лекарь и не побочный лекарь (пожалуйста, измените мои стратегии на heal или offheal)');
|
||||
|
||||
INSERT INTO ai_playerbot_texts_chance (name, probability) VALUES ('focus_heal_not_healer', 100);
|
||||
|
||||
-- focus_heal_provide_names
|
||||
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 (
|
||||
1746,
|
||||
'focus_heal_provide_names',
|
||||
'Please provide one or more player names',
|
||||
0, 0,
|
||||
'하나 이상의 플레이어 이름을 제공해주세요',
|
||||
'Veuillez fournir un ou plusieurs noms de joueurs',
|
||||
'Bitte geben Sie einen oder mehrere Spielernamen an',
|
||||
'请提供一个或多个玩家名称',
|
||||
'請提供一個或多個玩家名稱',
|
||||
'Por favor proporciona uno o más nombres de jugadores',
|
||||
'Por favor proporciona uno o más nombres de jugadores',
|
||||
'Пожалуйста, укажите одно или несколько имён игроков');
|
||||
|
||||
INSERT INTO ai_playerbot_texts_chance (name, probability) VALUES ('focus_heal_provide_names', 100);
|
||||
|
||||
-- focus_heal_no_targets
|
||||
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 (
|
||||
1747,
|
||||
'focus_heal_no_targets',
|
||||
'I don''t have any focus heal targets',
|
||||
0, 0,
|
||||
'지정된 집중 치유 대상이 없습니다',
|
||||
'Je n''ai aucune cible de soin prioritaire',
|
||||
'Ich habe keine fokussierten Heilziele',
|
||||
'我没有任何集中治疗目标',
|
||||
'我沒有任何集中治療目標',
|
||||
'No tengo ningún objetivo de sanación prioritario',
|
||||
'No tengo ningún objetivo de sanación prioritario',
|
||||
'У меня нет целей приоритетного лечения');
|
||||
|
||||
INSERT INTO ai_playerbot_texts_chance (name, probability) VALUES ('focus_heal_no_targets', 100);
|
||||
|
||||
-- focus_heal_current_targets: %targets is replaced with comma-separated player names
|
||||
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 (
|
||||
1748,
|
||||
'focus_heal_current_targets',
|
||||
'My focus heal targets are %targets',
|
||||
0, 0,
|
||||
'나의 집중 치유 대상: %targets',
|
||||
'Mes cibles de soin prioritaire sont %targets',
|
||||
'Meine fokussierten Heilziele sind %targets',
|
||||
'我的集中治疗目标是 %targets',
|
||||
'我的集中治療目標是 %targets',
|
||||
'Mis objetivos de sanación prioritarios son %targets',
|
||||
'Mis objetivos de sanación prioritarios son %targets',
|
||||
'Мои цели приоритетного лечения: %targets');
|
||||
|
||||
INSERT INTO ai_playerbot_texts_chance (name, probability) VALUES ('focus_heal_current_targets', 100);
|
||||
|
||||
-- focus_heal_cleared
|
||||
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 (
|
||||
1749,
|
||||
'focus_heal_cleared',
|
||||
'Removed focus heal targets',
|
||||
0, 0,
|
||||
'집중 치유 대상을 제거했습니다',
|
||||
'Cibles de soin prioritaire supprimées',
|
||||
'Fokussierte Heilziele entfernt',
|
||||
'已移除集中治疗目标',
|
||||
'已移除集中治療目標',
|
||||
'Objetivos de sanación prioritarios eliminados',
|
||||
'Objetivos de sanación prioritarios eliminados',
|
||||
'Цели приоритетного лечения удалены');
|
||||
|
||||
INSERT INTO ai_playerbot_texts_chance (name, probability) VALUES ('focus_heal_cleared', 100);
|
||||
|
||||
-- focus_heal_add_remove_syntax
|
||||
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 (
|
||||
1750,
|
||||
'focus_heal_add_remove_syntax',
|
||||
'Please specify a + for add or - to remove a target',
|
||||
0, 0,
|
||||
'대상을 추가하려면 +, 제거하려면 -를 지정해주세요',
|
||||
'Veuillez spécifier + pour ajouter ou - pour retirer une cible',
|
||||
'Bitte geben Sie + zum Hinzufügen oder - zum Entfernen eines Ziels an',
|
||||
'请指定 + 添加或 - 移除目标',
|
||||
'請指定 + 添加或 - 移除目標',
|
||||
'Por favor especifica + para agregar o - para eliminar un objetivo',
|
||||
'Por favor especifica + para agregar o - para eliminar un objetivo',
|
||||
'Пожалуйста, укажите + для добавления или - для удаления цели');
|
||||
|
||||
INSERT INTO ai_playerbot_texts_chance (name, probability) VALUES ('focus_heal_add_remove_syntax', 100);
|
||||
|
||||
-- focus_heal_not_in_group
|
||||
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 (
|
||||
1751,
|
||||
'focus_heal_not_in_group',
|
||||
'I''m not in a group',
|
||||
0, 0,
|
||||
'저는 파티에 속해있지 않습니다',
|
||||
'Je ne suis pas dans un groupe',
|
||||
'Ich bin in keiner Gruppe',
|
||||
'我不在队伍中',
|
||||
'我不在隊伍中',
|
||||
'No estoy en un grupo',
|
||||
'No estoy en un grupo',
|
||||
'Я не в группе');
|
||||
|
||||
INSERT INTO ai_playerbot_texts_chance (name, probability) VALUES ('focus_heal_not_in_group', 100);
|
||||
|
||||
-- focus_heal_not_in_group_with: %player_name is replaced with the target player's name
|
||||
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 (
|
||||
1752,
|
||||
'focus_heal_not_in_group_with',
|
||||
'I''m not in a group with %player_name',
|
||||
0, 0,
|
||||
'%player_name 와(과) 같은 파티에 없습니다',
|
||||
'Je ne suis pas dans un groupe avec %player_name',
|
||||
'Ich bin nicht in einer Gruppe mit %player_name',
|
||||
'我与 %player_name 不在同一队伍中',
|
||||
'我與 %player_name 不在同一隊伍中',
|
||||
'No estoy en un grupo con %player_name',
|
||||
'No estoy en un grupo con %player_name',
|
||||
'Я не в группе с %player_name');
|
||||
|
||||
INSERT INTO ai_playerbot_texts_chance (name, probability) VALUES ('focus_heal_not_in_group_with', 100);
|
||||
|
||||
-- focus_heal_added: %player_name is replaced with the added player's name
|
||||
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 (
|
||||
1753,
|
||||
'focus_heal_added',
|
||||
'Added %player_name to focus heal targets',
|
||||
0, 0,
|
||||
'%player_name 을(를) 집중 치유 대상에 추가했습니다',
|
||||
'%player_name ajouté aux cibles de soin prioritaire',
|
||||
'%player_name zu den fokussierten Heilzielen hinzugefügt',
|
||||
'已将 %player_name 添加到集中治疗目标',
|
||||
'已將 %player_name 添加到集中治療目標',
|
||||
'%player_name agregado a los objetivos de sanación prioritarios',
|
||||
'%player_name agregado a los objetivos de sanación prioritarios',
|
||||
'%player_name добавлен в цели приоритетного лечения');
|
||||
|
||||
INSERT INTO ai_playerbot_texts_chance (name, probability) VALUES ('focus_heal_added', 100);
|
||||
|
||||
-- focus_heal_removed: %player_name is replaced with the removed player's name
|
||||
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 (
|
||||
1754,
|
||||
'focus_heal_removed',
|
||||
'Removed %player_name from focus heal targets',
|
||||
0, 0,
|
||||
'%player_name 을(를) 집중 치유 대상에서 제거했습니다',
|
||||
'%player_name retiré des cibles de soin prioritaire',
|
||||
'%player_name aus den fokussierten Heilzielen entfernt',
|
||||
'已将 %player_name 从集中治疗目标中移除',
|
||||
'已將 %player_name 從集中治療目標中移除',
|
||||
'%player_name eliminado de los objetivos de sanación prioritarios',
|
||||
'%player_name eliminado de los objetivos de sanación prioritarios',
|
||||
'%player_name удалён из целей приоритетного лечения');
|
||||
|
||||
INSERT INTO ai_playerbot_texts_chance (name, probability) VALUES ('focus_heal_removed', 100);
|
||||
@ -1,102 +0,0 @@
|
||||
-- #########################################################
|
||||
-- Playerbots - Add pull command texts
|
||||
-- Localized for all WotLK locales (koKR, frFR, deDE, zhCN,
|
||||
-- zhTW, esES, esMX, ruRU)
|
||||
-- #########################################################
|
||||
|
||||
DELETE FROM ai_playerbot_texts WHERE name IN (
|
||||
'pull_no_target_error',
|
||||
'pull_target_too_far_error',
|
||||
'pull_invalid_target_error',
|
||||
'pull_action_unavailable_error'
|
||||
);
|
||||
DELETE FROM ai_playerbot_texts_chance WHERE name IN (
|
||||
'pull_no_target_error',
|
||||
'pull_target_too_far_error',
|
||||
'pull_invalid_target_error',
|
||||
'pull_action_unavailable_error'
|
||||
);
|
||||
|
||||
-- pull_no_target_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 (
|
||||
1755,
|
||||
'pull_no_target_error',
|
||||
'You have no target',
|
||||
0, 0,
|
||||
'대상이 없습니다',
|
||||
'Vous n''avez pas de cible',
|
||||
'Du hast kein Ziel',
|
||||
'你没有目标',
|
||||
'你沒有目標',
|
||||
'No tienes objetivo',
|
||||
'No tienes objetivo',
|
||||
'У вас нет цели');
|
||||
|
||||
INSERT INTO ai_playerbot_texts_chance (name, probability) VALUES ('pull_no_target_error', 100);
|
||||
|
||||
-- pull_target_too_far_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 (
|
||||
1756,
|
||||
'pull_target_too_far_error',
|
||||
'The target is too far away',
|
||||
0, 0,
|
||||
'대상이 너무 멀리 있습니다',
|
||||
'La cible est trop loin',
|
||||
'Das Ziel ist zu weit entfernt',
|
||||
'目标太远了',
|
||||
'目標太遠了',
|
||||
'El objetivo está demasiado lejos',
|
||||
'El objetivo está demasiado lejos',
|
||||
'Цель слишком далеко');
|
||||
|
||||
INSERT INTO ai_playerbot_texts_chance (name, probability) VALUES ('pull_target_too_far_error', 100);
|
||||
|
||||
-- pull_invalid_target_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 (
|
||||
1757,
|
||||
'pull_invalid_target_error',
|
||||
'The target can''t be pulled',
|
||||
0, 0,
|
||||
'해당 대상은 풀링할 수 없습니다',
|
||||
'La cible ne peut pas être attirée',
|
||||
'Das Ziel kann nicht gepullt werden',
|
||||
'该目标无法被拉怪',
|
||||
'該目標無法被拉怪',
|
||||
'No se puede hacer pull al objetivo',
|
||||
'No se puede hacer pull al objetivo',
|
||||
'Эту цель нельзя пуллить');
|
||||
|
||||
INSERT INTO ai_playerbot_texts_chance (name, probability) VALUES ('pull_invalid_target_error', 100);
|
||||
|
||||
-- pull_action_unavailable_error: %action_name is replaced with the configured pull action
|
||||
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 (
|
||||
1758,
|
||||
'pull_action_unavailable_error',
|
||||
'Can''t perform pull action ''%action_name''',
|
||||
0, 0,
|
||||
'''%action_name'' 풀 액션을 수행할 수 없습니다',
|
||||
'Impossible d''effectuer l''action d''engagement ''%action_name''',
|
||||
'Die Pull-Aktion ''%action_name'' kann nicht ausgeführt werden',
|
||||
'无法执行拉怪动作“%action_name”',
|
||||
'無法執行拉怪動作「%action_name」',
|
||||
'No se puede realizar la acción de pull ''%action_name''',
|
||||
'No se puede realizar la acción de pull ''%action_name''',
|
||||
'Невозможно выполнить действие пула ''%action_name''');
|
||||
|
||||
INSERT INTO ai_playerbot_texts_chance (name, probability) VALUES ('pull_action_unavailable_error', 100);
|
||||
@ -45,7 +45,6 @@
|
||||
#include "NonCombatActions.h"
|
||||
#include "OutfitAction.h"
|
||||
#include "PositionAction.h"
|
||||
#include "PullActions.h"
|
||||
#include "DropQuestAction.h"
|
||||
#include "RandomBotUpdateAction.h"
|
||||
#include "ReachTargetActions.h"
|
||||
@ -64,7 +63,6 @@
|
||||
#include "WorldBuffAction.h"
|
||||
#include "XpGainAction.h"
|
||||
#include "NewRpgAction.h"
|
||||
#include "NewRpgOutdoorPvP.h"
|
||||
#include "FishingAction.h"
|
||||
#include "CancelChannelAction.h"
|
||||
#include "WaitForAttackAction.h"
|
||||
@ -106,13 +104,6 @@ public:
|
||||
creators["shoot"] = &ActionContext::shoot;
|
||||
creators["lifeblood"] = &ActionContext::lifeblood;
|
||||
creators["arcane torrent"] = &ActionContext::arcane_torrent;
|
||||
creators["pull my target"] = &ActionContext::pull_my_target;
|
||||
creators["pull rti target"] = &ActionContext::pull_rti_target;
|
||||
creators["pull start"] = &ActionContext::pull_start;
|
||||
creators["pull action"] = &ActionContext::pull_action;
|
||||
creators["pull end"] = &ActionContext::pull_end;
|
||||
creators["return to pull position"] = &ActionContext::return_to_pull_position;
|
||||
creators["reach pull"] = &ActionContext::reach_pull;
|
||||
creators["end pull"] = &ActionContext::end_pull;
|
||||
creators["healthstone"] = &ActionContext::healthstone;
|
||||
creators["healing potion"] = &ActionContext::healing_potion;
|
||||
@ -274,7 +265,6 @@ public:
|
||||
creators["new rpg wander npc"] = &ActionContext::new_rpg_wander_npc;
|
||||
creators["new rpg do quest"] = &ActionContext::new_rpg_do_quest;
|
||||
creators["new rpg travel flight"] = &ActionContext::new_rpg_travel_flight;
|
||||
creators["new rpg outdoor pvp"] = &ActionContext::new_rpg_outdoor_pvp;
|
||||
creators["wait for attack keep safe distance"] = &ActionContext::wait_for_attack_keep_safe_distance;
|
||||
}
|
||||
|
||||
@ -321,13 +311,6 @@ private:
|
||||
static Action* gift_of_the_naaru(PlayerbotAI* botAI) { return new CastGiftOfTheNaaruAction(botAI); }
|
||||
static Action* lifeblood(PlayerbotAI* botAI) { return new CastLifeBloodAction(botAI); }
|
||||
static Action* arcane_torrent(PlayerbotAI* botAI) { return new CastArcaneTorrentAction(botAI); }
|
||||
static Action* pull_my_target(PlayerbotAI* botAI) { return new PullMyTargetAction(botAI); }
|
||||
static Action* pull_rti_target(PlayerbotAI* botAI) { return new PullRtiTargetAction(botAI); }
|
||||
static Action* pull_start(PlayerbotAI* botAI) { return new PullStartAction(botAI); }
|
||||
static Action* pull_action(PlayerbotAI* botAI) { return new PullAction(botAI); }
|
||||
static Action* pull_end(PlayerbotAI* botAI) { return new PullEndAction(botAI); }
|
||||
static Action* return_to_pull_position(PlayerbotAI* botAI) { return new ReturnToPullPositionAction(botAI); }
|
||||
static Action* reach_pull(PlayerbotAI* botAI) { return new ReachPullAction(botAI); }
|
||||
static Action* mana_tap(PlayerbotAI* botAI) { return new CastManaTapAction(botAI); }
|
||||
static Action* end_pull(PlayerbotAI* botAI) { return new ChangeCombatStrategyAction(botAI, "-pull"); }
|
||||
static Action* cancel_channel(PlayerbotAI* botAI) { return new CancelChannelAction(botAI); }
|
||||
@ -479,7 +462,6 @@ private:
|
||||
static Action* new_rpg_wander_npc(PlayerbotAI* ai) { return new NewRpgWanderNpcAction(ai); }
|
||||
static Action* new_rpg_do_quest(PlayerbotAI* ai) { return new NewRpgDoQuestAction(ai); }
|
||||
static Action* new_rpg_travel_flight(PlayerbotAI* ai) { return new NewRpgTravelFlightAction(ai); }
|
||||
static Action* new_rpg_outdoor_pvp(PlayerbotAI* ai) { return new NewRpgOutdoorPvpAction(ai); }
|
||||
static Action* wait_for_attack_keep_safe_distance(PlayerbotAI* ai) { return new WaitForAttackKeepSafeDistanceAction(ai); }
|
||||
};
|
||||
|
||||
|
||||
@ -53,6 +53,22 @@ bool AttackMyTargetAction::Execute(Event /*event*/)
|
||||
|
||||
bool AttackAction::Attack(Unit* target, bool /*with_pet*/ /*true*/)
|
||||
{
|
||||
Unit* oldTarget = context->GetValue<Unit*>("current target")->Get();
|
||||
bool shouldMelee = bot->IsWithinMeleeRange(target) || botAI->IsMelee(bot);
|
||||
|
||||
bool sameTarget = oldTarget == target && bot->GetVictim() == target;
|
||||
bool inCombat = botAI->GetState() == BOT_STATE_COMBAT;
|
||||
bool sameAttackMode = bot->HasUnitState(UNIT_STATE_MELEE_ATTACKING) == shouldMelee;
|
||||
|
||||
if (bot->GetMotionMaster()->GetCurrentMovementGeneratorType() == FLIGHT_MOTION_TYPE ||
|
||||
bot->HasUnitState(UNIT_STATE_IN_FLIGHT))
|
||||
{
|
||||
if (verbose)
|
||||
botAI->TellError("I cannot attack in flight");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!target)
|
||||
{
|
||||
if (verbose)
|
||||
@ -69,15 +85,6 @@ bool AttackAction::Attack(Unit* target, bool /*with_pet*/ /*true*/)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (bot->GetMotionMaster()->GetCurrentMovementGeneratorType() == FLIGHT_MOTION_TYPE ||
|
||||
bot->HasUnitState(UNIT_STATE_IN_FLIGHT))
|
||||
{
|
||||
if (verbose)
|
||||
botAI->TellError("I cannot attack in flight");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if bot OR target is in prohibited zone/area (skip for duels)
|
||||
if ((target->IsPlayer() || target->IsPet()) &&
|
||||
(!bot->duel || bot->duel->Opponent != target) &&
|
||||
@ -114,18 +121,6 @@ bool AttackAction::Attack(Unit* target, bool /*with_pet*/ /*true*/)
|
||||
return false;
|
||||
}
|
||||
|
||||
// Infantry attacks are not allowed from vehicles drivers.
|
||||
// Check is needed to stop some auto-attack situations.
|
||||
if (botAI->IsInVehicle() && !botAI->IsInVehicle(false, false, true))
|
||||
return false;
|
||||
|
||||
Unit* oldTarget = context->GetValue<Unit*>("current target")->Get();
|
||||
bool shouldMelee = bot->IsWithinMeleeRange(target) || botAI->IsMelee(bot);
|
||||
|
||||
bool sameTarget = oldTarget == target && bot->GetVictim() == target;
|
||||
bool inCombat = botAI->GetState() == BOT_STATE_COMBAT;
|
||||
bool sameAttackMode = bot->HasUnitState(UNIT_STATE_MELEE_ATTACKING) == shouldMelee;
|
||||
|
||||
if (sameTarget && inCombat && sameAttackMode)
|
||||
{
|
||||
if (verbose)
|
||||
@ -151,7 +146,8 @@ bool AttackAction::Attack(Unit* target, bool /*with_pet*/ /*true*/)
|
||||
ObjectGuid guid = target->GetGUID();
|
||||
bot->SetSelection(target->GetGUID());
|
||||
|
||||
context->GetValue<Unit*>("old target")->Set(oldTarget);
|
||||
context->GetValue<Unit*>("old target")->Set(oldTarget);
|
||||
|
||||
context->GetValue<Unit*>("current target")->Set(target);
|
||||
context->GetValue<LootObjectStack*>("available loot")->Get()->Add(guid);
|
||||
|
||||
|
||||
@ -73,7 +73,7 @@ void AutoMaintenanceOnLevelupAction::LearnSpells(std::ostringstream* out)
|
||||
LearnQuestSpells(out);
|
||||
}
|
||||
|
||||
void AutoMaintenanceOnLevelupAction::LearnTrainerSpells(std::ostringstream* /*out*/)
|
||||
void AutoMaintenanceOnLevelupAction::LearnTrainerSpells(std::ostringstream* out)
|
||||
{
|
||||
PlayerbotFactory factory(bot, bot->GetLevel());
|
||||
factory.InitSkills();
|
||||
|
||||
@ -27,7 +27,7 @@ bool BankAction::Execute(Event event)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool BankAction::ExecuteBank(std::string const text, Unit* /*bank*/)
|
||||
bool BankAction::ExecuteBank(std::string const text, Unit* bank)
|
||||
{
|
||||
if (text.empty() || text == "?")
|
||||
{
|
||||
|
||||
@ -343,7 +343,7 @@ bool BGJoinAction::isUseful()
|
||||
return false;
|
||||
|
||||
// check Deserter debuff
|
||||
if (bot->IsDeserter())
|
||||
if (!bot->CanJoinToBattleground())
|
||||
return false;
|
||||
|
||||
// check if has free queue slots (pointless as already making sure not in queue)
|
||||
@ -534,18 +534,21 @@ bool BGJoinAction::JoinQueue(uint32 type)
|
||||
|
||||
botAI->GetAiObjectContext()->GetValue<uint32>("bg type")->Set(0);
|
||||
|
||||
WorldPacket* packet = nullptr;
|
||||
if (!isArena)
|
||||
{
|
||||
packet = new WorldPacket(CMSG_BATTLEMASTER_JOIN, 20);
|
||||
WorldPacket* packet = new WorldPacket(CMSG_BATTLEMASTER_JOIN, 20);
|
||||
*packet << bot->GetGUID() << bgTypeId_ << instanceId << joinAsGroup;
|
||||
/// FIX race condition
|
||||
// bot->GetSession()->HandleBattlemasterJoinOpcode(packet);
|
||||
bot->GetSession()->QueuePacket(packet);
|
||||
}
|
||||
else
|
||||
{
|
||||
packet = new WorldPacket(CMSG_BATTLEMASTER_JOIN_ARENA, 20);
|
||||
*packet << unit->GetGUID() << arenaslot << asGroup << uint8(isRated);
|
||||
WorldPacket arena_packet(CMSG_BATTLEMASTER_JOIN_ARENA, 20);
|
||||
arena_packet << unit->GetGUID() << arenaslot << asGroup << uint8(isRated);
|
||||
bot->GetSession()->HandleBattlemasterJoinArena(arena_packet);
|
||||
}
|
||||
bot->GetSession()->QueuePacket(packet);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@ -213,7 +213,13 @@ bool BuyAction::Execute(Event event)
|
||||
}
|
||||
}
|
||||
|
||||
return vendored;
|
||||
if (!vendored)
|
||||
{
|
||||
botAI->TellError("There are no vendors nearby");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BuyAction::BuyItem(VendorItemData const* tItems, ObjectGuid vendorguid, ItemTemplate const* proto)
|
||||
|
||||
@ -21,7 +21,7 @@ public:
|
||||
}
|
||||
|
||||
bool Execute(Event event) override;
|
||||
virtual std::string const castString(WorldObject* /*target*/) { return "cast"; }
|
||||
virtual std::string const castString(WorldObject* target) { return "cast"; }
|
||||
|
||||
protected:
|
||||
bool ncCast = false;
|
||||
@ -49,7 +49,7 @@ public:
|
||||
|
||||
bool isUseful() override { return false; }
|
||||
virtual bool AcceptSpell(SpellInfo const* spellInfo);
|
||||
virtual uint32 GetSpellPriority(SpellInfo const* /*spellInfo*/) { return 1; }
|
||||
virtual uint32 GetSpellPriority(SpellInfo const* spellInfo) { return 1; }
|
||||
virtual bool castSpell(uint32 spellId, WorldObject* wo);
|
||||
bool Execute(Event event) override;
|
||||
|
||||
|
||||
@ -80,7 +80,7 @@ bool FollowChatShortcutAction::Execute(Event /*event*/)
|
||||
true, priority);
|
||||
}
|
||||
|
||||
if (bot->GetPet())
|
||||
if (Pet* pet = bot->GetPet())
|
||||
botAI->PetFollow();
|
||||
|
||||
if (moved)
|
||||
|
||||
@ -116,7 +116,6 @@ bool ChooseRpgTargetAction::Execute(Event /*event*/)
|
||||
GuidPosition masterRpgTarget;
|
||||
if (master && master != bot && GET_PLAYERBOT_AI(master) && master->GetMapId() == bot->GetMapId() && !master->IsBeingTeleported())
|
||||
{
|
||||
//TODO Implement
|
||||
Player* player = botAI->GetMaster();
|
||||
//GuidPosition masterRpgTarget = PAI_VALUE(GuidPosition, "rpg target"); //not used, line marked for removal.
|
||||
}
|
||||
|
||||
@ -62,16 +62,31 @@ bool CleanQuestLogAction::Execute(Event event)
|
||||
{
|
||||
Player* requester = event.getOwner() ? event.getOwner() : GetMaster();
|
||||
if (!requester)
|
||||
{
|
||||
botAI->TellMaster("No event owner detected");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!sPlayerbotAIConfig.dropObsoleteQuests)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only output this message if "debug rpg" strategy is enabled
|
||||
if (botAI->HasStrategy("debug rpg", BotState::BOT_STATE_COMBAT))
|
||||
{
|
||||
botAI->TellMaster("Clean Quest Log command received, removing grey/trivial quests...");
|
||||
}
|
||||
|
||||
uint8 botLevel = bot->GetLevel(); // Get bot's level
|
||||
uint8 numQuest = 0;
|
||||
for (uint8 slot = 0; slot < MAX_QUEST_LOG_SIZE; ++slot)
|
||||
{
|
||||
if (bot->GetQuestSlotQuestId(slot))
|
||||
{
|
||||
numQuest++;
|
||||
}
|
||||
}
|
||||
|
||||
for (uint8 slot = 0; slot < MAX_QUEST_LOG_SIZE; ++slot)
|
||||
{
|
||||
@ -86,24 +101,34 @@ bool CleanQuestLogAction::Execute(Event event)
|
||||
// Determine if quest is trivial by comparing levels
|
||||
int32 questLevel = quest->GetQuestLevel();
|
||||
if (questLevel == -1) // For scaling quests, default to bot level
|
||||
{
|
||||
questLevel = botLevel;
|
||||
}
|
||||
|
||||
// Set the level difference for when a quest becomes trivial
|
||||
// This was determined by using the Lua code the client uses
|
||||
int32 trivialLevel = 5;
|
||||
if (botLevel >= 40)
|
||||
{
|
||||
trivialLevel = 8;
|
||||
}
|
||||
else if (botLevel >= 30)
|
||||
{
|
||||
trivialLevel = 7;
|
||||
}
|
||||
else if (botLevel >= 20)
|
||||
{
|
||||
trivialLevel = 6;
|
||||
}
|
||||
|
||||
// Check if the quest is trivial (grey) for the bot
|
||||
if ((botLevel - questLevel) > trivialLevel)
|
||||
{
|
||||
// Output only if "debug rpg" strategy is enabled
|
||||
if (botAI->HasStrategy("debug rpg", BotState::BOT_STATE_COMBAT))
|
||||
{
|
||||
botAI->TellMaster("Quest [ " + quest->GetTitle() + " ] will be removed because it is trivial (grey).");
|
||||
}
|
||||
|
||||
// Remove quest
|
||||
botAI->rpgStatistic.questDropped++;
|
||||
@ -112,6 +137,8 @@ bool CleanQuestLogAction::Execute(Event event)
|
||||
bot->SetQuestStatus(questId, QUEST_STATUS_NONE);
|
||||
bot->RemoveRewardedQuest(questId);
|
||||
|
||||
numQuest--;
|
||||
|
||||
if (botAI->HasStrategy("debug rpg", BotState::BOT_STATE_COMBAT))
|
||||
{
|
||||
const std::string text_quest = ChatHelper::FormatQuest(quest);
|
||||
@ -120,13 +147,17 @@ bool CleanQuestLogAction::Execute(Event event)
|
||||
}
|
||||
|
||||
if (botAI->HasStrategy("debug rpg", BotState::BOT_STATE_COMBAT))
|
||||
{
|
||||
botAI->TellMaster("Quest [ " + quest->GetTitle() + " ] has been removed.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Only output if "debug rpg" strategy is enabled
|
||||
if (botAI->HasStrategy("debug rpg", BotState::BOT_STATE_COMBAT))
|
||||
{
|
||||
botAI->TellMaster("Quest [ " + quest->GetTitle() + " ] is not trivial and will be kept.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -143,6 +174,7 @@ void CleanQuestLogAction::DropQuestType(uint8& numQuest, uint8 wantNum, bool isG
|
||||
{
|
||||
std::random_device rd;
|
||||
std::mt19937 g(rd());
|
||||
|
||||
std::shuffle(slots.begin(), slots.end(), g);
|
||||
}
|
||||
|
||||
@ -168,10 +200,8 @@ void CleanQuestLogAction::DropQuestType(uint8& numQuest, uint8 wantNum, bool isG
|
||||
bot->GetLevel() <= bot->GetQuestLevel(quest) + uint32(lowLevelDiff)) // Quest is not gray
|
||||
{
|
||||
if (bot->GetLevel() + 5 > bot->GetQuestLevel(quest)) // Quest is not red
|
||||
{
|
||||
if (!isGreen)
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else // Quest is gray
|
||||
{
|
||||
|
||||
@ -168,8 +168,8 @@ bool FollowAction::Execute(Event /*event*/)
|
||||
? MovementPriority::MOVEMENT_COMBAT
|
||||
: MovementPriority::MOVEMENT_NORMAL;
|
||||
|
||||
bool const movingAllowed = IsMovingAllowed();
|
||||
bool const dupMove = IsDuplicateMove(destX, destY, destZ);
|
||||
bool const movingAllowed = IsMovingAllowed(mapId, destX, destY, destZ);
|
||||
bool const dupMove = IsDuplicateMove(mapId, destX, destY, destZ);
|
||||
bool const waiting = IsWaitingForLastMove(priority);
|
||||
|
||||
if (movingAllowed && !dupMove && !waiting)
|
||||
|
||||
@ -151,9 +151,7 @@ bool CastMeleeSpellAction::isUseful()
|
||||
return CastSpellAction::isUseful();
|
||||
}
|
||||
|
||||
CastMeleeDebuffSpellAction::CastMeleeDebuffSpellAction(
|
||||
PlayerbotAI* botAI, std::string const spell, bool isOwner, float needLifeTime) :
|
||||
CastDebuffSpellAction(botAI, spell, isOwner, needLifeTime)
|
||||
CastMeleeDebuffSpellAction::CastMeleeDebuffSpellAction(PlayerbotAI* botAI, std::string const spell, bool isOwner, float needLifeTime) : CastDebuffSpellAction(botAI, spell, isOwner, needLifeTime)
|
||||
{
|
||||
range = ATTACK_DISTANCE;
|
||||
}
|
||||
@ -205,35 +203,6 @@ bool CastEnchantItemAction::isPossible()
|
||||
return spellId && AI_VALUE2(Item*, "item for spell", spellId);
|
||||
}
|
||||
|
||||
CastEnchantItemMainHandAction::CastEnchantItemMainHandAction(PlayerbotAI* botAI, std::string const spell)
|
||||
: CastEnchantItemAction(botAI, spell) {}
|
||||
|
||||
bool CastEnchantItemMainHandAction::isPossible()
|
||||
{
|
||||
if (!CastEnchantItemAction::isPossible())
|
||||
return false;
|
||||
|
||||
Item* item = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND);
|
||||
return item && !item->GetEnchantmentId(TEMP_ENCHANTMENT_SLOT) &&
|
||||
item->GetTemplate()->Class == ITEM_CLASS_WEAPON;
|
||||
}
|
||||
|
||||
CastEnchantItemOffHandAction::CastEnchantItemOffHandAction(PlayerbotAI* botAI, std::string const spell)
|
||||
: CastEnchantItemAction(botAI, spell) {}
|
||||
|
||||
bool CastEnchantItemOffHandAction::isPossible()
|
||||
{
|
||||
if (!CastEnchantItemAction::isPossible())
|
||||
return false;
|
||||
|
||||
Item* item = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
|
||||
if (!item || item->GetEnchantmentId(TEMP_ENCHANTMENT_SLOT))
|
||||
return false;
|
||||
|
||||
uint32 invType = item->GetTemplate()->InventoryType;
|
||||
return invType == INVTYPE_WEAPON || invType == INVTYPE_WEAPONOFFHAND;
|
||||
}
|
||||
|
||||
CastHealingSpellAction::CastHealingSpellAction(PlayerbotAI* botAI, std::string const spell, uint8 estAmount,
|
||||
HealingManaEfficiency manaEfficiency, bool isOwner)
|
||||
: CastAuraSpellAction(botAI, spell, isOwner), estAmount(estAmount), manaEfficiency(manaEfficiency)
|
||||
@ -273,7 +242,7 @@ bool BuffOnPartyAction::Execute(Event /*event*/)
|
||||
}
|
||||
// End greater buff fix
|
||||
|
||||
CastShootAction::CastShootAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "shoot"), shootSpellId(0)
|
||||
CastShootAction::CastShootAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "shoot")
|
||||
{
|
||||
if (Item* const pItem = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_RANGED))
|
||||
{
|
||||
@ -283,40 +252,17 @@ CastShootAction::CastShootAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "s
|
||||
{
|
||||
case ITEM_SUBCLASS_WEAPON_GUN:
|
||||
spell += " gun";
|
||||
shootSpellId = 3018;
|
||||
break;
|
||||
case ITEM_SUBCLASS_WEAPON_BOW:
|
||||
spell += " bow";
|
||||
shootSpellId = 3018;
|
||||
break;
|
||||
case ITEM_SUBCLASS_WEAPON_CROSSBOW:
|
||||
spell += " crossbow";
|
||||
shootSpellId = 3018;
|
||||
break;
|
||||
case ITEM_SUBCLASS_WEAPON_THROWN:
|
||||
spell = "throw";
|
||||
shootSpellId = 2764;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CastShootAction::isPossible()
|
||||
{
|
||||
if (shootSpellId)
|
||||
return botAI->CanCastSpell(shootSpellId, GetTarget(), false);
|
||||
|
||||
return CastSpellAction::isPossible();
|
||||
}
|
||||
|
||||
bool CastShootAction::Execute(Event /*event*/)
|
||||
{
|
||||
if (shootSpellId)
|
||||
return botAI->CastSpell(shootSpellId, GetTarget());
|
||||
|
||||
return botAI->CastSpell(spell, GetTarget());
|
||||
}
|
||||
|
||||
Value<Unit*>* CastDebuffSpellOnAttackerAction::GetTargetValue()
|
||||
{
|
||||
return context->GetValue<Unit*>("attacker without aura", spell);
|
||||
|
||||
@ -130,20 +130,6 @@ public:
|
||||
std::string const GetTargetName() override { return "self target"; }
|
||||
};
|
||||
|
||||
class CastEnchantItemMainHandAction : public CastEnchantItemAction
|
||||
{
|
||||
public:
|
||||
CastEnchantItemMainHandAction(PlayerbotAI* botAI, std::string const spell);
|
||||
bool isPossible() override;
|
||||
};
|
||||
|
||||
class CastEnchantItemOffHandAction : public CastEnchantItemAction
|
||||
{
|
||||
public:
|
||||
CastEnchantItemOffHandAction(PlayerbotAI* botAI, std::string const spell);
|
||||
bool isPossible() override;
|
||||
};
|
||||
|
||||
class CastHealingSpellAction : public CastAuraSpellAction
|
||||
{
|
||||
public:
|
||||
@ -253,12 +239,7 @@ class CastShootAction : public CastSpellAction
|
||||
public:
|
||||
CastShootAction(PlayerbotAI* botAI);
|
||||
|
||||
bool isPossible() override;
|
||||
bool Execute(Event event) override;
|
||||
ActionThreatType getThreatType() override { return ActionThreatType::None; }
|
||||
|
||||
private:
|
||||
uint32 shootSpellId;
|
||||
};
|
||||
|
||||
class CastLifeBloodAction : public CastHealingSpellAction
|
||||
|
||||
@ -53,7 +53,7 @@ bool GuildBankAction::Execute(std::string const text, GameObject* bank)
|
||||
return result;
|
||||
}
|
||||
|
||||
bool GuildBankAction::MoveFromCharToBank(Item* item, GameObject* /*bank*/)
|
||||
bool GuildBankAction::MoveFromCharToBank(Item* item, GameObject* bank)
|
||||
{
|
||||
uint32 playerSlot = item->GetSlot();
|
||||
uint32 playerBag = item->GetBagSlot();
|
||||
|
||||
@ -296,7 +296,7 @@ bool PetitionTurnInAction::isUseful()
|
||||
|
||||
bool BuyTabardAction::Execute(Event /*event*/)
|
||||
{
|
||||
bool canBuy = botAI->DoSpecificAction("buy", Event("buy tabard", "Hitem:5976:"), true);
|
||||
bool canBuy = botAI->DoSpecificAction("buy", Event("buy tabard", "Hitem:5976:"));
|
||||
if (canBuy && AI_VALUE2(uint32, "item count", chat->FormatQItem(5976)))
|
||||
return true;
|
||||
|
||||
|
||||
@ -78,7 +78,7 @@ private:
|
||||
class TakeMailProcessor : public MailProcessor
|
||||
{
|
||||
public:
|
||||
bool Process(uint32 /*index*/, Mail* mail, PlayerbotAI* botAI) override
|
||||
bool Process(uint32 index, Mail* mail, PlayerbotAI* botAI) override
|
||||
{
|
||||
Player* bot = botAI->GetBot();
|
||||
if (!CheckBagSpace(bot))
|
||||
@ -104,7 +104,7 @@ public:
|
||||
{
|
||||
std::vector<uint32> guids;
|
||||
for (MailItemInfoVec::iterator i = mail->items.begin(); i != mail->items.end(); ++i)
|
||||
if (sObjectMgr->GetItemTemplate(i->item_template))
|
||||
if (ItemTemplate const* proto = sObjectMgr->GetItemTemplate(i->item_template))
|
||||
guids.push_back(i->item_guid);
|
||||
|
||||
for (std::vector<uint32>::iterator i = guids.begin(); i != guids.end(); ++i)
|
||||
@ -157,7 +157,7 @@ private:
|
||||
class DeleteMailProcessor : public MailProcessor
|
||||
{
|
||||
public:
|
||||
bool Process(uint32 /*index*/, Mail* mail, PlayerbotAI* botAI) override
|
||||
bool Process(uint32 index, Mail* mail, PlayerbotAI* botAI) override
|
||||
{
|
||||
std::ostringstream out;
|
||||
out << "|cffffffff" << mail->subject << "|cffff0000 deleted";
|
||||
@ -172,7 +172,7 @@ public:
|
||||
class ReadMailProcessor : public MailProcessor
|
||||
{
|
||||
public:
|
||||
bool Process(uint32 /*index*/, Mail* mail, PlayerbotAI* botAI) override
|
||||
bool Process(uint32 index, Mail* mail, PlayerbotAI* botAI) override
|
||||
{
|
||||
std::ostringstream out, body;
|
||||
out << "|cffffffff" << mail->subject;
|
||||
|
||||
@ -74,18 +74,8 @@ bool MoveToTravelTargetAction::Execute(Event /*event*/)
|
||||
|
||||
float maxDistance = target->getDestination()->getRadiusMin();
|
||||
|
||||
// Spread bots around the target but keep the offset stable per
|
||||
// (bot, destination) pair. Previously the angle and radius were
|
||||
// re-rolled every time the action re-entered (i.e. every tick the
|
||||
// bot wasn't already moving), which made bots oscillate between
|
||||
// two random points around the same quest POI instead of
|
||||
// committing to one approach.
|
||||
uint32 botLow = bot->GetGUID().GetCounter();
|
||||
int32 destSeed = static_cast<int32>(location.GetPositionX()) * 73856093 ^
|
||||
static_cast<int32>(location.GetPositionY()) * 19349663;
|
||||
uint32 seed = botLow ^ static_cast<uint32>(destSeed);
|
||||
float angle = 2.0f * static_cast<float>(M_PI) * static_cast<float>(seed % 1000) / 1000.0f;
|
||||
float mod = 0.5f + static_cast<float>((seed / 1000) % 1000) / 2000.0f; // [0.5, 1.0]
|
||||
// Evenly distribute around the target.
|
||||
float angle = 2 * M_PI * urand(0, 100) / 100.0;
|
||||
|
||||
if (target->getMaxTravelTime() > target->getTimeLeft()) // The bot is late. Speed it up.
|
||||
{
|
||||
@ -99,6 +89,9 @@ bool MoveToTravelTargetAction::Execute(Event /*event*/)
|
||||
float z = location.GetPositionZ();
|
||||
float mapId = location.GetMapId();
|
||||
|
||||
// Move between 0.5 and 1.0 times the maxDistance.
|
||||
float mod = frand(50.f, 100.f) / 100.0f;
|
||||
|
||||
x += cos(angle) * maxDistance * mod;
|
||||
y += sin(angle) * maxDistance * mod;
|
||||
|
||||
|
||||
@ -63,10 +63,10 @@ void MovementAction::CreateWp(Player* wpOwner, float x, float y, float z, float
|
||||
bool MovementAction::JumpTo(uint32 mapId, float x, float y, float z, MovementPriority priority)
|
||||
{
|
||||
UpdateMovementState();
|
||||
if (!IsMovingAllowed())
|
||||
if (!IsMovingAllowed(mapId, x, y, z))
|
||||
return false;
|
||||
|
||||
if (IsDuplicateMove(x, y, z))
|
||||
if (IsDuplicateMove(mapId, x, y, z))
|
||||
return false;
|
||||
|
||||
if (IsWaitingForLastMove(priority))
|
||||
@ -101,11 +101,6 @@ bool MovementAction::MoveNear(WorldObject* target, float distance, MovementPrior
|
||||
float x = target->GetPositionX() + cos(angle) * distance;
|
||||
float y = target->GetPositionY() + sin(angle) * distance;
|
||||
float z = target->GetPositionZ();
|
||||
// Clamp Z to the terrain under the offset point so we don't
|
||||
// hand PointMovementGenerator a Z that matches the target's
|
||||
// floor but not the sampled (x,y) — avoids straight-line
|
||||
// fallbacks through geometry.
|
||||
bot->UpdateAllowedPositionZ(x, y, z);
|
||||
|
||||
if (!bot->IsWithinLOS(x, y, z))
|
||||
continue;
|
||||
@ -171,11 +166,11 @@ bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle,
|
||||
bool exact_waypoint, MovementPriority priority, bool lessDelay, bool backwards)
|
||||
{
|
||||
UpdateMovementState();
|
||||
if (!IsMovingAllowed())
|
||||
if (!IsMovingAllowed(mapId, x, y, z))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (IsDuplicateMove(x, y, z))
|
||||
if (IsDuplicateMove(mapId, x, y, z))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@ -255,7 +250,7 @@ bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle,
|
||||
// bot->CastStop();
|
||||
// botAI->InterruptSpell();
|
||||
// }
|
||||
DoMovePoint(bot, x, y, modifiedZ, generatePath, backwards);
|
||||
DoMovePoint(bot, x, y, z, generatePath, backwards);
|
||||
float delay = 1000.0f * MoveDelay(distance, backwards);
|
||||
if (lessDelay)
|
||||
{
|
||||
@ -263,8 +258,7 @@ bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle,
|
||||
}
|
||||
delay = std::max(.0f, delay);
|
||||
delay = std::min((float)sPlayerbotAIConfig.maxWaitForMove, delay);
|
||||
AI_VALUE(LastMovement&, "last movement")
|
||||
.Set(mapId, x, y, modifiedZ, bot->GetOrientation(), delay, priority);
|
||||
AI_VALUE(LastMovement&, "last movement").Set(mapId, x, y, z, bot->GetOrientation(), delay, priority);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -784,17 +778,15 @@ bool MovementAction::MoveTo(WorldObject* target, float distance, MovementPriorit
|
||||
|
||||
float dx = cos(angle) * needToGo + bx;
|
||||
float dy = sin(angle) * needToGo + by;
|
||||
// Start from a seed Z between bot and target, then clamp to the
|
||||
// terrain under (dx,dy). Linear interpolation alone ignores hills
|
||||
// between the two units and fed PointMovementGenerator a Z that
|
||||
// could be well above/below ground, triggering straight-line
|
||||
// fallbacks through walls.
|
||||
float dz;
|
||||
float dz; // = std::max(bz, tz); // calc accurate z position to avoid stuck
|
||||
if (distanceToTarget > CONTACT_DISTANCE)
|
||||
{
|
||||
dz = bz + (tz - bz) * (needToGo / distanceToTarget);
|
||||
}
|
||||
else
|
||||
{
|
||||
dz = tz;
|
||||
bot->UpdateAllowedPositionZ(dx, dy, dz);
|
||||
}
|
||||
return MoveTo(target->GetMapId(), dx, dy, dz, false, false, false, false, priority);
|
||||
}
|
||||
|
||||
@ -897,7 +889,20 @@ bool MovementAction::IsMovingAllowed(WorldObject* target)
|
||||
return IsMovingAllowed();
|
||||
}
|
||||
|
||||
bool MovementAction::IsDuplicateMove(float x, float y, float z)
|
||||
bool MovementAction::IsMovingAllowed(uint32 mapId, float x, float y, float z)
|
||||
{
|
||||
// removed sqrt as means distance limit was effectively 22500 (ReactDistance<63>)
|
||||
// leaving it commented incase we find ReactDistance limit causes problems
|
||||
// float distance = sqrt(bot->GetDistance(x, y, z));
|
||||
|
||||
// Remove react distance limit
|
||||
// if (!bot->InBattleground())
|
||||
// return false;
|
||||
|
||||
return IsMovingAllowed();
|
||||
}
|
||||
|
||||
bool MovementAction::IsDuplicateMove(uint32 mapId, float x, float y, float z)
|
||||
{
|
||||
LastMovement& lastMove = *context->GetValue<LastMovement&>("last movement");
|
||||
|
||||
@ -1273,7 +1278,7 @@ bool MovementAction::Follow(Unit* target, float distance, float angle)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MovementAction::ChaseTo(WorldObject* obj, float distance)
|
||||
bool MovementAction::ChaseTo(WorldObject* obj, float distance, float angle)
|
||||
{
|
||||
if (!IsMovingAllowed())
|
||||
{
|
||||
@ -1846,7 +1851,7 @@ bool FleeAction::isUseful()
|
||||
|
||||
bool FleeWithPetAction::Execute(Event /*event*/)
|
||||
{
|
||||
if (bot->GetPet())
|
||||
if (Pet* pet = bot->GetPet())
|
||||
botAI->PetFollow();
|
||||
|
||||
return Flee(AI_VALUE(Unit*, "current target"));
|
||||
|
||||
@ -43,13 +43,14 @@ protected:
|
||||
float GetFollowAngle();
|
||||
bool Follow(Unit* target, float distance = sPlayerbotAIConfig.followDistance);
|
||||
bool Follow(Unit* target, float distance, float angle);
|
||||
bool ChaseTo(WorldObject* obj, float distance = 0.0f);
|
||||
bool ChaseTo(WorldObject* obj, float distance = 0.0f, float angle = 0.0f);
|
||||
bool ReachCombatTo(Unit* target, float distance = 0.0f);
|
||||
float MoveDelay(float distance, bool backwards = false);
|
||||
void WaitForReach(float distance);
|
||||
void SetNextMovementDelay(float delayMillis);
|
||||
bool IsMovingAllowed(WorldObject* target);
|
||||
bool IsDuplicateMove(float x, float y, float z);
|
||||
bool IsMovingAllowed(uint32 mapId, float x, float y, float z);
|
||||
bool IsDuplicateMove(uint32 mapId, float x, float y, float z);
|
||||
bool IsWaitingForLastMove(MovementPriority priority);
|
||||
bool IsMovingAllowed();
|
||||
bool Flee(Unit* target);
|
||||
|
||||
@ -1,321 +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 "AttackersValue.h"
|
||||
#include "CreatureAI.h"
|
||||
#include "Playerbots.h"
|
||||
#include "PlayerbotTextMgr.h"
|
||||
#include "PositionValue.h"
|
||||
#include "PullActions.h"
|
||||
#include "PullStrategy.h"
|
||||
#include "RtiTargetValue.h"
|
||||
#include <algorithm>
|
||||
|
||||
namespace
|
||||
{
|
||||
float GetPullReachDistance(Player* bot, Unit* target, PullStrategy const* strategy)
|
||||
{
|
||||
if (!bot || !target || !strategy)
|
||||
return 0.0f;
|
||||
|
||||
float const combatDistance = bot->GetCombatReach() + target->GetCombatReach();
|
||||
return std::max(0.0f, strategy->GetRange() - combatDistance);
|
||||
}
|
||||
|
||||
bool IsWithinPullRange(Player* bot, Unit* target, PullStrategy const* strategy)
|
||||
{
|
||||
return bot && target && strategy && bot->GetExactDist(target) <= strategy->GetRange();
|
||||
}
|
||||
}
|
||||
|
||||
bool PullRequestAction::Execute(Event event)
|
||||
{
|
||||
PullStrategy* strategy = PullStrategy::Get(botAI);
|
||||
if (!strategy)
|
||||
return false;
|
||||
|
||||
if (!botAI->IsTank(bot))
|
||||
return false;
|
||||
|
||||
Unit* target = GetPullTarget(event);
|
||||
if (!target || !target->IsInWorld())
|
||||
{
|
||||
std::string const text = PlayerbotTextMgr::instance().GetBotTextOrDefault(
|
||||
"pull_no_target_error", "You have no target", {});
|
||||
botAI->TellError(text);
|
||||
return false;
|
||||
}
|
||||
|
||||
float const maxPullDistance = sPlayerbotAIConfig.reactDistance * 3.0f;
|
||||
if (target->GetMapId() != bot->GetMapId() || bot->GetDistance(target) > maxPullDistance)
|
||||
{
|
||||
std::string const text = PlayerbotTextMgr::instance().GetBotTextOrDefault(
|
||||
"pull_target_too_far_error", "The target is too far away", {});
|
||||
botAI->TellError(text);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!AttackersValue::IsPossibleTarget(target, bot))
|
||||
{
|
||||
std::string const text = PlayerbotTextMgr::instance().GetBotTextOrDefault(
|
||||
"pull_invalid_target_error", "The target can't be pulled", {});
|
||||
botAI->TellError(text);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!strategy->CanDoPullAction(target))
|
||||
{
|
||||
std::string const actionName = strategy->GetPullActionName();
|
||||
std::string const text = PlayerbotTextMgr::instance().GetBotTextOrDefault(
|
||||
"pull_action_unavailable_error",
|
||||
"Can't perform pull action '%action_name'",
|
||||
{{"%action_name", actionName}});
|
||||
botAI->TellError(text);
|
||||
return false;
|
||||
}
|
||||
|
||||
PositionMap& posMap = AI_VALUE(PositionMap&, "position");
|
||||
PositionInfo pullPosition = posMap["pull"];
|
||||
pullPosition.Set(bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ(), bot->GetMapId());
|
||||
posMap["pull"] = pullPosition;
|
||||
|
||||
strategy->RequestPull(target);
|
||||
context->GetValue<Unit*>("current target")->Set(target);
|
||||
botAI->ChangeEngine(BOT_STATE_COMBAT);
|
||||
botAI->SetNextCheckDelay(sPlayerbotAIConfig.reactDelay);
|
||||
return true;
|
||||
}
|
||||
|
||||
Unit* PullMyTargetAction::GetPullTarget(Event event)
|
||||
{
|
||||
Player* requester = event.getOwner() ? event.getOwner() : GetMaster();
|
||||
if (event.GetSource() == "attack anything")
|
||||
return botAI->GetCreature(event.getObject());
|
||||
|
||||
return requester ? requester->GetSelectedUnit() : nullptr;
|
||||
}
|
||||
|
||||
Unit* PullRtiTargetAction::GetPullTarget(Event /*event*/)
|
||||
{
|
||||
Unit* rtiTarget = AI_VALUE(Unit*, "rti target");
|
||||
if (rtiTarget)
|
||||
return rtiTarget;
|
||||
|
||||
Group* group = bot->GetGroup();
|
||||
if (!group)
|
||||
return nullptr;
|
||||
|
||||
std::string const rti = AI_VALUE(std::string, "rti");
|
||||
int32 const index = RtiTargetValue::GetRtiIndex(rti);
|
||||
if (index < 0)
|
||||
return nullptr;
|
||||
|
||||
ObjectGuid const guid = group->GetTargetIcon(index);
|
||||
return guid.IsEmpty() ? nullptr : botAI->GetUnit(guid);
|
||||
}
|
||||
|
||||
bool PullStartAction::Execute(Event event)
|
||||
{
|
||||
PullStrategy* strategy = PullStrategy::Get(botAI);
|
||||
if (!strategy)
|
||||
return false;
|
||||
|
||||
Unit* target = strategy->GetTarget();
|
||||
if (!target)
|
||||
return false;
|
||||
|
||||
std::string const preActionName = strategy->GetPreActionName();
|
||||
if (!preActionName.empty() && !botAI->DoSpecificAction(preActionName, event, true))
|
||||
return false;
|
||||
|
||||
if (Pet* pet = bot->GetPet())
|
||||
{
|
||||
Creature* creature = pet->ToCreature();
|
||||
if (creature)
|
||||
{
|
||||
strategy->SetPetReactState(creature->GetReactState());
|
||||
creature->SetReactState(REACT_PASSIVE);
|
||||
}
|
||||
}
|
||||
|
||||
strategy->OnPullStarted();
|
||||
return true;
|
||||
}
|
||||
|
||||
PullAction::PullAction(PlayerbotAI* botAI, std::string const name) : CastSpellAction(botAI, name) { InitPullAction(); }
|
||||
|
||||
Unit* PullAction::GetTarget()
|
||||
{
|
||||
PullStrategy* strategy = PullStrategy::Get(botAI);
|
||||
if (!strategy)
|
||||
return nullptr;
|
||||
|
||||
return strategy->GetTarget();
|
||||
}
|
||||
|
||||
std::vector<NextAction> PullAction::getPrerequisites()
|
||||
{
|
||||
PullStrategy* strategy = PullStrategy::Get(botAI);
|
||||
Unit* target = strategy ? strategy->GetTarget() : nullptr;
|
||||
if (!strategy || !target)
|
||||
return {};
|
||||
|
||||
return IsWithinPullRange(bot, target, strategy) ? std::vector<NextAction>{}
|
||||
: std::vector<NextAction>{ NextAction("reach pull", ACTION_MOVE) };
|
||||
}
|
||||
|
||||
bool PullAction::Execute(Event event)
|
||||
{
|
||||
InitPullAction();
|
||||
|
||||
PullStrategy* strategy = PullStrategy::Get(botAI);
|
||||
if (!strategy)
|
||||
return false;
|
||||
|
||||
Unit* target = strategy->GetTarget();
|
||||
if (!target || !target->IsInWorld())
|
||||
return false;
|
||||
|
||||
if (target->IsInCombat())
|
||||
return false;
|
||||
|
||||
if (!IsWithinPullRange(bot, target, strategy))
|
||||
{
|
||||
strategy->RequestPull(target, false);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (bot->isMoving())
|
||||
{
|
||||
bot->StopMoving();
|
||||
strategy->RequestPull(target, false);
|
||||
return false;
|
||||
}
|
||||
|
||||
context->GetValue<Unit*>("current target")->Set(target);
|
||||
if (!botAI->DoSpecificAction(strategy->GetPullActionName(), event, true))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PullAction::isPossible()
|
||||
{
|
||||
InitPullAction();
|
||||
|
||||
PullStrategy* strategy = PullStrategy::Get(botAI);
|
||||
if (!strategy)
|
||||
return false;
|
||||
|
||||
Unit* target = strategy->GetTarget();
|
||||
std::string const spellName = strategy->GetSpellName();
|
||||
if (!target || !target->IsInWorld() || target->GetMapId() != bot->GetMapId() || spellName.empty())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void PullAction::InitPullAction()
|
||||
{
|
||||
PullStrategy* strategy = PullStrategy::Get(botAI);
|
||||
if (!strategy)
|
||||
return;
|
||||
|
||||
std::string const spellName = strategy->GetSpellName();
|
||||
if (spellName.empty())
|
||||
return;
|
||||
|
||||
spell = spellName;
|
||||
|
||||
bool isShoot = (spellName == "shoot" || spellName == "shoot bow" ||
|
||||
spellName == "shoot gun" || spellName == "shoot crossbow" ||
|
||||
spellName == "throw");
|
||||
range = botAI->GetRange(isShoot ? "shoot" : "spell");
|
||||
}
|
||||
|
||||
bool PullEndAction::Execute(Event /*event*/)
|
||||
{
|
||||
PullStrategy* strategy = PullStrategy::Get(botAI);
|
||||
if (!strategy)
|
||||
return false;
|
||||
|
||||
Unit* pullTarget = strategy->GetTarget();
|
||||
|
||||
if (!strategy->HasPullStarted() && !strategy->IsPullPendingToStart() && !strategy->HasTarget())
|
||||
return false;
|
||||
|
||||
if (Pet* pet = bot->GetPet())
|
||||
{
|
||||
Creature* creature = pet->ToCreature();
|
||||
if (creature)
|
||||
creature->SetReactState(strategy->GetPetReactState());
|
||||
}
|
||||
|
||||
PositionMap& posMap = AI_VALUE(PositionMap&, "position");
|
||||
PositionInfo pullPosition = posMap["pull"];
|
||||
if (pullPosition.isSet())
|
||||
posMap.erase("pull");
|
||||
|
||||
if (pullTarget && context->GetValue<Unit*>("current target")->Get() == pullTarget)
|
||||
context->GetValue<Unit*>("current target")->Set(nullptr);
|
||||
|
||||
strategy->OnPullEnded();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ReturnToPullPositionAction::Execute(Event /*event*/)
|
||||
{
|
||||
PositionInfo pullPosition = AI_VALUE(PositionMap&, "position")["pull"];
|
||||
if (!pullPosition.isSet() || pullPosition.mapId != bot->GetMapId())
|
||||
return false;
|
||||
|
||||
return MoveTo(pullPosition.mapId, pullPosition.x, pullPosition.y, pullPosition.z,
|
||||
false, false, false, false, MovementPriority::MOVEMENT_COMBAT, true);
|
||||
}
|
||||
|
||||
bool ReturnToPullPositionAction::isUseful()
|
||||
{
|
||||
PullStrategy* strategy = PullStrategy::Get(botAI);
|
||||
Unit* target = strategy ? strategy->GetTarget() : nullptr;
|
||||
if (!strategy || !target || !target->IsInCombat())
|
||||
return false;
|
||||
|
||||
PositionInfo pullPosition = AI_VALUE(PositionMap&, "position")["pull"];
|
||||
return pullPosition.isSet() && pullPosition.mapId == bot->GetMapId() &&
|
||||
bot->GetDistance(pullPosition.x, pullPosition.y, pullPosition.z) > sPlayerbotAIConfig.followDistance;
|
||||
}
|
||||
|
||||
bool ReachPullAction::Execute(Event /*event*/)
|
||||
{
|
||||
Unit* target = GetTarget();
|
||||
PullStrategy* strategy = PullStrategy::Get(botAI);
|
||||
if (!target || !strategy)
|
||||
return false;
|
||||
|
||||
float const reachDistance = GetPullReachDistance(bot, target, strategy);
|
||||
return ReachCombatTo(target, reachDistance);
|
||||
}
|
||||
|
||||
bool ReachPullAction::isUseful()
|
||||
{
|
||||
if (botAI->HasStrategy("stay", botAI->GetState()))
|
||||
return false;
|
||||
|
||||
if (bot->GetCurrentSpell(CURRENT_CHANNELED_SPELL) != nullptr)
|
||||
return false;
|
||||
|
||||
PullStrategy* strategy = PullStrategy::Get(botAI);
|
||||
Unit* target = strategy ? strategy->GetTarget() : nullptr;
|
||||
return target && !IsWithinPullRange(bot, target, strategy);
|
||||
}
|
||||
|
||||
Unit* ReachPullAction::GetTarget()
|
||||
{
|
||||
PullStrategy* strategy = PullStrategy::Get(botAI);
|
||||
if (!strategy)
|
||||
return nullptr;
|
||||
|
||||
return strategy->GetTarget();
|
||||
}
|
||||
@ -1,90 +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_PULLACTIONS_H
|
||||
#define _PLAYERBOT_PULLACTIONS_H
|
||||
|
||||
#include "GenericSpellActions.h"
|
||||
#include "ReachTargetActions.h"
|
||||
|
||||
class PullRequestAction : public Action
|
||||
{
|
||||
public:
|
||||
PullRequestAction(PlayerbotAI* botAI, std::string const name) : Action(botAI, name) {}
|
||||
|
||||
bool Execute(Event event) override;
|
||||
|
||||
protected:
|
||||
virtual Unit* GetPullTarget(Event event) = 0;
|
||||
};
|
||||
|
||||
class PullMyTargetAction : public PullRequestAction
|
||||
{
|
||||
public:
|
||||
PullMyTargetAction(PlayerbotAI* botAI) : PullRequestAction(botAI, "pull my target") {}
|
||||
|
||||
private:
|
||||
Unit* GetPullTarget(Event event) override;
|
||||
};
|
||||
|
||||
class PullRtiTargetAction : public PullRequestAction
|
||||
{
|
||||
public:
|
||||
PullRtiTargetAction(PlayerbotAI* botAI) : PullRequestAction(botAI, "pull rti target") {}
|
||||
|
||||
private:
|
||||
Unit* GetPullTarget(Event event) override;
|
||||
};
|
||||
|
||||
class PullStartAction : public Action
|
||||
{
|
||||
public:
|
||||
PullStartAction(PlayerbotAI* botAI, std::string const name = "pull start") : Action(botAI, name) {}
|
||||
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class PullAction : public CastSpellAction
|
||||
{
|
||||
public:
|
||||
PullAction(PlayerbotAI* botAI, std::string const name = "pull action");
|
||||
|
||||
bool Execute(Event event) override;
|
||||
bool isPossible() override;
|
||||
std::vector<NextAction> getPrerequisites() override;
|
||||
Unit* GetTarget() override;
|
||||
|
||||
private:
|
||||
void InitPullAction();
|
||||
};
|
||||
|
||||
class PullEndAction : public Action
|
||||
{
|
||||
public:
|
||||
PullEndAction(PlayerbotAI* botAI, std::string const name = "pull end") : Action(botAI, name) {}
|
||||
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class ReachPullAction : public ReachTargetAction
|
||||
{
|
||||
public:
|
||||
ReachPullAction(PlayerbotAI* botAI) : ReachTargetAction(botAI, "reach pull", botAI->GetRange("spell")) {}
|
||||
|
||||
bool Execute(Event event) override;
|
||||
bool isUseful() override;
|
||||
Unit* GetTarget() override;
|
||||
};
|
||||
|
||||
class ReturnToPullPositionAction : public MovementAction
|
||||
{
|
||||
public:
|
||||
ReturnToPullPositionAction(PlayerbotAI* botAI) : MovementAction(botAI, "return to pull position") {}
|
||||
|
||||
bool Execute(Event event) override;
|
||||
bool isUseful() override;
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -45,7 +45,7 @@ std::once_flag ReadyChecker::initFlag;
|
||||
class HealthChecker : public ReadyChecker
|
||||
{
|
||||
public:
|
||||
bool Check(PlayerbotAI* /*botAI*/, AiObjectContext* context) override
|
||||
bool Check(PlayerbotAI* botAI, AiObjectContext* context) override
|
||||
{
|
||||
return AI_VALUE2(uint8, "health", "self target") > sPlayerbotAIConfig.almostFullHealth;
|
||||
}
|
||||
@ -56,7 +56,7 @@ public:
|
||||
class ManaChecker : public ReadyChecker
|
||||
{
|
||||
public:
|
||||
bool Check(PlayerbotAI* /*botAI*/, AiObjectContext* context) override
|
||||
bool Check(PlayerbotAI* botAI, AiObjectContext* context) override
|
||||
{
|
||||
return !AI_VALUE2(bool, "has mana", "self target") ||
|
||||
AI_VALUE2(uint8, "mana", "self target") > sPlayerbotAIConfig.mediumHealth;
|
||||
@ -68,7 +68,7 @@ public:
|
||||
class DistanceChecker : public ReadyChecker
|
||||
{
|
||||
public:
|
||||
bool Check(PlayerbotAI* botAI, AiObjectContext* /*context*/) override
|
||||
bool Check(PlayerbotAI* botAI, AiObjectContext* context) override
|
||||
{
|
||||
Player* bot = botAI->GetBot();
|
||||
if (Player* master = botAI->GetMaster())
|
||||
@ -90,7 +90,7 @@ public:
|
||||
class HunterChecker : public ReadyChecker
|
||||
{
|
||||
public:
|
||||
bool Check(PlayerbotAI* botAI, AiObjectContext* /*context*/) override
|
||||
bool Check(PlayerbotAI* botAI, AiObjectContext* context) override
|
||||
{
|
||||
Player* bot = botAI->GetBot();
|
||||
if (bot->getClass() == CLASS_HUNTER)
|
||||
@ -126,7 +126,7 @@ class ItemCountChecker : public ReadyChecker
|
||||
public:
|
||||
ItemCountChecker(std::string const item, std::string const name) : item(item), name(name) {}
|
||||
|
||||
bool Check(PlayerbotAI* /*botAI*/, AiObjectContext* context) override
|
||||
bool Check(PlayerbotAI* botAI, AiObjectContext* context) override
|
||||
{
|
||||
return AI_VALUE2(uint32, "item count", item) > 0;
|
||||
}
|
||||
@ -225,4 +225,4 @@ bool ReadyCheckAction::ReadyCheck()
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FinishReadyCheckAction::Execute(Event /*event*/) { return ReadyCheck(); }
|
||||
bool FinishReadyCheckAction::Execute(Event event) { return ReadyCheck(); }
|
||||
|
||||
@ -65,7 +65,7 @@ void ReleaseSpiritAction::IncrementDeathCount() const
|
||||
}
|
||||
}
|
||||
|
||||
void ReleaseSpiritAction::LogRelease(const std::string& releaseMsg) const
|
||||
void ReleaseSpiritAction::LogRelease(const std::string& releaseMsg, bool isAutoRelease) const
|
||||
{
|
||||
const std::string teamPrefix = bot->GetTeamId() == TEAM_ALLIANCE ? "A" : "H";
|
||||
|
||||
@ -82,13 +82,13 @@ bool AutoReleaseSpiritAction::Execute(Event /*event*/)
|
||||
{
|
||||
IncrementDeathCount();
|
||||
bot->DurabilityRepairAll(false, 1.0f, false);
|
||||
LogRelease("auto released");
|
||||
LogRelease("auto released", true);
|
||||
|
||||
WorldPacket packet(CMSG_REPOP_REQUEST);
|
||||
packet << uint8(0);
|
||||
bot->GetSession()->HandleRepopRequestOpcode(packet);
|
||||
|
||||
LogRelease("releases spirit");
|
||||
LogRelease("releases spirit", true);
|
||||
|
||||
if (bot->InBattleground())
|
||||
{
|
||||
|
||||
@ -18,7 +18,7 @@ public:
|
||||
: Action(botAI, name) {}
|
||||
|
||||
bool Execute(Event event) override;
|
||||
void LogRelease(const std::string& releaseType) const;
|
||||
void LogRelease(const std::string& releaseType, bool isAutoRelease = false) const;
|
||||
|
||||
protected:
|
||||
void IncrementDeathCount() const;
|
||||
|
||||
@ -251,9 +251,9 @@ GraveyardStruct const* SpiritHealerAction::GetGrave(bool startZone)
|
||||
std::vector<uint32> races;
|
||||
|
||||
if (bot->GetTeamId() == TEAM_ALLIANCE)
|
||||
races = {RACE_HUMAN, RACE_DWARF, RACE_GNOME, RACE_NIGHTELF, RACE_DRAENEI};
|
||||
races = {RACE_HUMAN, RACE_DWARF, RACE_GNOME, RACE_NIGHTELF};
|
||||
else
|
||||
races = {RACE_ORC, RACE_TROLL, RACE_TAUREN, RACE_UNDEAD_PLAYER, RACE_BLOODELF};
|
||||
races = {RACE_ORC, RACE_TROLL, RACE_TAUREN, RACE_UNDEAD_PLAYER};
|
||||
|
||||
float graveDistance = -1;
|
||||
|
||||
|
||||
@ -154,7 +154,7 @@ bool SayAction::isUseful()
|
||||
return (time(nullptr) - lastSaid) > 30;
|
||||
}
|
||||
|
||||
void ChatReplyAction::ChatReplyDo(Player* bot, uint32& type, uint32& guid1, std::string& msg, std::string& chanName, std::string& name)
|
||||
void ChatReplyAction::ChatReplyDo(Player* bot, uint32& type, uint32& guid1, uint32& guid2, std::string& msg, std::string& chanName, std::string& name)
|
||||
{
|
||||
std::string respondsText = "";
|
||||
|
||||
@ -205,14 +205,14 @@ void ChatReplyAction::ChatReplyDo(Player* bot, uint32& type, uint32& guid1, std:
|
||||
if (msg.starts_with(sPlayerbotAIConfig.toxicLinksPrefix)
|
||||
&& (GET_PLAYERBOT_AI(bot)->GetChatHelper()->ExtractAllItemIds(msg).size() > 0 || GET_PLAYERBOT_AI(bot)->GetChatHelper()->ExtractAllQuestIds(msg).size() > 0))
|
||||
{
|
||||
HandleToxicLinksReply(bot, chatChannelSource);
|
||||
HandleToxicLinksReply(bot, chatChannelSource, msg, name);
|
||||
return;
|
||||
}
|
||||
|
||||
//thunderfury
|
||||
if (GET_PLAYERBOT_AI(bot)->GetChatHelper()->ExtractAllItemIds(msg).count(19019))
|
||||
{
|
||||
HandleThunderfuryReply(bot, chatChannelSource);
|
||||
HandleThunderfuryReply(bot, chatChannelSource, msg, name);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -220,7 +220,7 @@ void ChatReplyAction::ChatReplyDo(Player* bot, uint32& type, uint32& guid1, std:
|
||||
SendGeneralResponse(bot, chatChannelSource, messageRepy, name);
|
||||
}
|
||||
|
||||
bool ChatReplyAction::HandleThunderfuryReply(Player* bot, ChatChannelSource chatChannelSource)
|
||||
bool ChatReplyAction::HandleThunderfuryReply(Player* bot, ChatChannelSource chatChannelSource, std::string& msg, std::string& name)
|
||||
{
|
||||
std::map<std::string, std::string> placeholders;
|
||||
const auto thunderfury = sObjectMgr->GetItemTemplate(19019);
|
||||
@ -248,7 +248,7 @@ bool ChatReplyAction::HandleThunderfuryReply(Player* bot, ChatChannelSource chat
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ChatReplyAction::HandleToxicLinksReply(Player* bot, ChatChannelSource chatChannelSource)
|
||||
bool ChatReplyAction::HandleToxicLinksReply(Player* bot, ChatChannelSource chatChannelSource, std::string& msg, std::string& name)
|
||||
{
|
||||
//quests
|
||||
std::vector<uint32> incompleteQuests;
|
||||
|
||||
@ -29,12 +29,12 @@ class ChatReplyAction : public Action
|
||||
{
|
||||
public:
|
||||
ChatReplyAction(PlayerbotAI* ai) : Action(ai, "chat message") {}
|
||||
virtual bool Execute(Event /*event*/) { return true; }
|
||||
virtual bool Execute(Event event) { return true; }
|
||||
bool isUseful() { return true; }
|
||||
|
||||
static void ChatReplyDo(Player* bot, uint32& type, uint32& guid1, std::string& msg, std::string& chanName, std::string& name);
|
||||
static bool HandleThunderfuryReply(Player* bot, ChatChannelSource chatChannelSource);
|
||||
static bool HandleToxicLinksReply(Player* bot, ChatChannelSource chatChannelSource);
|
||||
static void ChatReplyDo(Player* bot, uint32& type, uint32& guid1, uint32& guid2, std::string& msg, std::string& chanName, std::string& name);
|
||||
static bool HandleThunderfuryReply(Player* bot, ChatChannelSource chatChannelSource, std::string& msg, std::string& name);
|
||||
static bool HandleToxicLinksReply(Player* bot, ChatChannelSource chatChannelSource, std::string& msg, std::string& name);
|
||||
static bool HandleWTBItemsReply(Player* bot, ChatChannelSource chatChannelSource, std::string& msg, std::string& name);
|
||||
static bool HandleLFGQuestsReply(Player* bot, ChatChannelSource chatChannelSource, std::string& msg, std::string& name);
|
||||
static bool SendGeneralResponse(Player* bot, ChatChannelSource chatChannelSource, std::string& responseMessage, std::string& name);
|
||||
|
||||
@ -15,7 +15,7 @@
|
||||
|
||||
std::set<uint32> const FISHING_SPELLS = {7620, 7731, 7732, 18248, 33095, 51294};
|
||||
|
||||
Creature* SeeSpellAction::CreateWps(Player* wpOwner, float x, float y, float z, float o, uint32 entry, Creature* /*lastWp*/,
|
||||
Creature* SeeSpellAction::CreateWps(Player* wpOwner, float x, float y, float z, float o, uint32 entry, Creature* lastWp,
|
||||
bool important)
|
||||
{
|
||||
float dist = wpOwner->GetDistance(x, y, z);
|
||||
|
||||
@ -1,219 +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 "SetFocusHealTargetsAction.h"
|
||||
|
||||
#include "ObjectAccessor.h"
|
||||
#include "Playerbots.h"
|
||||
#include "PlayerbotTextMgr.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
|
||||
static std::string LowercaseString(std::string const& str)
|
||||
{
|
||||
std::string result = str;
|
||||
std::transform(result.begin(), result.end(), result.begin(),
|
||||
[](unsigned char c) { return std::tolower(c); });
|
||||
return result;
|
||||
}
|
||||
|
||||
static Player* FindGroupPlayerByName(Player* player, std::string const& playerName)
|
||||
{
|
||||
if (!player)
|
||||
return nullptr;
|
||||
|
||||
Group* group = player->GetGroup();
|
||||
if (!group)
|
||||
return nullptr;
|
||||
|
||||
for (GroupReference* gref = group->GetFirstMember(); gref; gref = gref->next())
|
||||
{
|
||||
Player* member = gref->GetSource();
|
||||
if (member)
|
||||
{
|
||||
std::string memberName = member->GetName();
|
||||
if (LowercaseString(memberName) == playerName)
|
||||
return member;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool SetFocusHealTargetsAction::Execute(Event event)
|
||||
{
|
||||
if (!botAI->IsHeal(bot) && !botAI->HasStrategy("offheal", BOT_STATE_COMBAT))
|
||||
{
|
||||
std::string text = PlayerbotTextMgr::instance().GetBotTextOrDefault(
|
||||
"focus_heal_not_healer",
|
||||
"I'm not a healer or offhealer (please change my strats to heal or offheal)",
|
||||
{});
|
||||
botAI->TellMasterNoFacing(text);
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string const param = LowercaseString(event.getParam());
|
||||
if (param.empty())
|
||||
{
|
||||
std::string text = PlayerbotTextMgr::instance().GetBotTextOrDefault(
|
||||
"focus_heal_provide_names",
|
||||
"Please provide one or more player names",
|
||||
{});
|
||||
botAI->TellMasterNoFacing(text);
|
||||
return false;
|
||||
}
|
||||
|
||||
std::list<ObjectGuid> focusHealTargets =
|
||||
AI_VALUE(std::list<ObjectGuid>, "focus heal targets");
|
||||
|
||||
// Query current focus targets
|
||||
if (param.find('?') != std::string::npos)
|
||||
{
|
||||
if (focusHealTargets.empty())
|
||||
{
|
||||
std::string text = PlayerbotTextMgr::instance().GetBotTextOrDefault(
|
||||
"focus_heal_no_targets",
|
||||
"I don't have any focus heal targets",
|
||||
{});
|
||||
botAI->TellMasterNoFacing(text);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::stringstream targetNames;
|
||||
for (auto it = focusHealTargets.begin(); it != focusHealTargets.end(); ++it)
|
||||
{
|
||||
Unit* target = botAI->GetUnit(*it);
|
||||
if (target)
|
||||
{
|
||||
if (it != focusHealTargets.begin())
|
||||
targetNames << ", ";
|
||||
targetNames << target->GetName();
|
||||
}
|
||||
}
|
||||
|
||||
std::map<std::string, std::string> placeholders;
|
||||
placeholders["%targets"] = targetNames.str();
|
||||
std::string text = PlayerbotTextMgr::instance().GetBotTextOrDefault(
|
||||
"focus_heal_current_targets",
|
||||
"My focus heal targets are %targets",
|
||||
placeholders);
|
||||
botAI->TellMasterNoFacing(text);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Clear all targets
|
||||
if (param == "none" || param == "unset" || param == "clear")
|
||||
{
|
||||
focusHealTargets.clear();
|
||||
SET_AI_VALUE(std::list<ObjectGuid>, "focus heal targets", focusHealTargets);
|
||||
botAI->ChangeStrategy("-focus heal targets", BOT_STATE_COMBAT);
|
||||
std::string text = PlayerbotTextMgr::instance().GetBotTextOrDefault(
|
||||
"focus_heal_cleared",
|
||||
"Removed focus heal targets",
|
||||
{});
|
||||
botAI->TellMasterNoFacing(text);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Parse multiple targets separated by commas
|
||||
std::vector<std::string> targetNames;
|
||||
if (param.find(',') != std::string::npos)
|
||||
{
|
||||
std::string targetName;
|
||||
std::stringstream ss(param);
|
||||
while (std::getline(ss, targetName, ','))
|
||||
targetNames.push_back(targetName);
|
||||
}
|
||||
else
|
||||
targetNames.push_back(param);
|
||||
|
||||
if (targetNames.empty())
|
||||
{
|
||||
std::string text = PlayerbotTextMgr::instance().GetBotTextOrDefault(
|
||||
"focus_heal_provide_names",
|
||||
"Please provide one or more player names",
|
||||
{});
|
||||
botAI->TellMasterNoFacing(text);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!bot->GetGroup())
|
||||
{
|
||||
std::string text = PlayerbotTextMgr::instance().GetBotTextOrDefault(
|
||||
"focus_heal_not_in_group",
|
||||
"I'm not in a group",
|
||||
{});
|
||||
botAI->TellMasterNoFacing(text);
|
||||
return false;
|
||||
}
|
||||
|
||||
for (std::string const& targetName : targetNames)
|
||||
{
|
||||
bool const add = targetName.find("+") != std::string::npos;
|
||||
bool const remove = targetName.find("-") != std::string::npos;
|
||||
if (!add && !remove)
|
||||
{
|
||||
std::string text = PlayerbotTextMgr::instance().GetBotTextOrDefault(
|
||||
"focus_heal_add_remove_syntax",
|
||||
"Please specify a + for add or - to remove a target",
|
||||
{});
|
||||
botAI->TellMasterNoFacing(text);
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string const playerName = targetName.substr(1);
|
||||
Player* target = FindGroupPlayerByName(bot, playerName);
|
||||
if (!target)
|
||||
{
|
||||
std::map<std::string, std::string> placeholders;
|
||||
placeholders["%player_name"] = playerName;
|
||||
std::string text = PlayerbotTextMgr::instance().GetBotTextOrDefault(
|
||||
"focus_heal_not_in_group_with",
|
||||
"I'm not in a group with %player_name",
|
||||
placeholders);
|
||||
botAI->TellMasterNoFacing(text);
|
||||
continue;
|
||||
}
|
||||
|
||||
ObjectGuid const& targetGuid = target->GetGUID();
|
||||
if (add)
|
||||
{
|
||||
if (std::find(focusHealTargets.begin(), focusHealTargets.end(), targetGuid) ==
|
||||
focusHealTargets.end())
|
||||
focusHealTargets.push_back(targetGuid);
|
||||
|
||||
std::map<std::string, std::string> placeholders;
|
||||
placeholders["%player_name"] = playerName;
|
||||
std::string text = PlayerbotTextMgr::instance().GetBotTextOrDefault(
|
||||
"focus_heal_added",
|
||||
"Added %player_name to focus heal targets",
|
||||
placeholders);
|
||||
botAI->TellMasterNoFacing(text);
|
||||
}
|
||||
else
|
||||
{
|
||||
focusHealTargets.remove(targetGuid);
|
||||
std::map<std::string, std::string> placeholders;
|
||||
placeholders["%player_name"] = playerName;
|
||||
std::string text = PlayerbotTextMgr::instance().GetBotTextOrDefault(
|
||||
"focus_heal_removed",
|
||||
"Removed %player_name from focus heal targets",
|
||||
placeholders);
|
||||
botAI->TellMasterNoFacing(text);
|
||||
}
|
||||
}
|
||||
|
||||
SET_AI_VALUE(std::list<ObjectGuid>, "focus heal targets", focusHealTargets);
|
||||
|
||||
if (focusHealTargets.empty())
|
||||
botAI->ChangeStrategy("-focus heal targets", BOT_STATE_COMBAT);
|
||||
else
|
||||
botAI->ChangeStrategy("+focus heal targets", BOT_STATE_COMBAT);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -1,21 +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_SETFOCUSHEALTARGETSACTION_H
|
||||
#define _PLAYERBOT_SETFOCUSHEALTARGETSACTION_H
|
||||
|
||||
#include "Action.h"
|
||||
|
||||
class PlayerbotAI;
|
||||
|
||||
class SetFocusHealTargetsAction : public Action
|
||||
{
|
||||
public:
|
||||
SetFocusHealTargetsAction(PlayerbotAI* botAI) : Action(botAI, "focus heal targets") {}
|
||||
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -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 "TellEmblemsAction.h"
|
||||
|
||||
#include <array>
|
||||
|
||||
#include "Event.h"
|
||||
#include "Playerbots.h"
|
||||
|
||||
bool TellEmblemsAction::Execute(Event /*event*/)
|
||||
{
|
||||
static std::array<uint32, 6> const emblemIds = {
|
||||
29434, // Badge of Justice
|
||||
40752, // Emblem of Heroism
|
||||
40753, // Emblem of Valor
|
||||
45624, // Emblem of Conquest
|
||||
47241, // Emblem of Triumph
|
||||
49426 // Emblem of Frost
|
||||
};
|
||||
|
||||
botAI->TellMaster("=== Emblems ===");
|
||||
|
||||
for (uint32 itemId : emblemIds)
|
||||
{
|
||||
ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemId);
|
||||
if (!proto)
|
||||
continue;
|
||||
|
||||
uint32 count = bot->GetItemCount(itemId, false);
|
||||
std::ostringstream out;
|
||||
out << chat->FormatItem(proto, count);
|
||||
botAI->TellMaster(out);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -1,21 +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_TELLEMBLEMSACTION_H
|
||||
#define _PLAYERBOT_TELLEMBLEMSACTION_H
|
||||
|
||||
#include "InventoryAction.h"
|
||||
|
||||
class PlayerbotAI;
|
||||
|
||||
class TellEmblemsAction : public InventoryAction
|
||||
{
|
||||
public:
|
||||
TellEmblemsAction(PlayerbotAI* botAI) : InventoryAction(botAI, "emblems") {}
|
||||
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -5,23 +5,34 @@
|
||||
|
||||
#include "TellReputationAction.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "Event.h"
|
||||
#include "PlayerbotAI.h"
|
||||
#include "ReputationMgr.h"
|
||||
|
||||
#include "SharedDefines.h"
|
||||
|
||||
std::string TellReputationAction::BuildReputationLine(FactionEntry const* entry)
|
||||
bool TellReputationAction::Execute(Event /*event*/)
|
||||
{
|
||||
ReputationMgr& repMgr = bot->GetReputationMgr();
|
||||
ReputationRank rank = repMgr.GetRank(entry);
|
||||
int32 reputation = repMgr.GetReputation(entry->ID);
|
||||
Player* master = GetMaster();
|
||||
if (!master)
|
||||
return false;
|
||||
|
||||
ObjectGuid selection = master->GetTarget();
|
||||
if (selection.IsEmpty())
|
||||
return false;
|
||||
|
||||
Unit* unit = ObjectAccessor::GetUnit(*master, selection);
|
||||
if (!unit)
|
||||
return false;
|
||||
|
||||
FactionTemplateEntry const* factionTemplate = unit->GetFactionTemplateEntry();
|
||||
uint32 faction = factionTemplate->faction;
|
||||
FactionEntry const* entry = sFactionStore.LookupEntry(faction);
|
||||
int32 reputation = bot->GetReputationMgr().GetReputation(faction);
|
||||
|
||||
std::ostringstream out;
|
||||
out << entry->name[0] << ": |cff";
|
||||
out << entry->name[0] << ": ";
|
||||
out << "|cff";
|
||||
|
||||
ReputationRank rank = bot->GetReputationMgr().GetRank(entry);
|
||||
switch (rank)
|
||||
{
|
||||
case REP_HATED:
|
||||
@ -60,65 +71,7 @@ std::string TellReputationAction::BuildReputationLine(FactionEntry const* entry)
|
||||
base -= ReputationMgr::PointsInRank[i];
|
||||
|
||||
out << " (" << (reputation - base) << "/" << ReputationMgr::PointsInRank[rank] << ")";
|
||||
return out.str();
|
||||
}
|
||||
|
||||
bool TellReputationAction::Execute(Event event)
|
||||
{
|
||||
std::string const param = event.getParam();
|
||||
if (param == "all")
|
||||
{
|
||||
ReputationMgr& repMgr = bot->GetReputationMgr();
|
||||
std::vector<std::string> lines;
|
||||
|
||||
FactionStateList const& stateList = repMgr.GetStateList();
|
||||
lines.reserve(stateList.size());
|
||||
|
||||
for (auto const& itr : stateList)
|
||||
{
|
||||
FactionState const& faction = itr.second;
|
||||
if (!(faction.Flags & FACTION_FLAG_VISIBLE))
|
||||
continue;
|
||||
|
||||
if (faction.Flags & (FACTION_FLAG_HIDDEN | FACTION_FLAG_INVISIBLE_FORCED) &&
|
||||
!(faction.Flags & FACTION_FLAG_SPECIAL))
|
||||
continue;
|
||||
|
||||
FactionEntry const* entry = sFactionStore.LookupEntry(faction.ID);
|
||||
if (!entry)
|
||||
continue;
|
||||
|
||||
lines.push_back(BuildReputationLine(entry));
|
||||
}
|
||||
|
||||
std::sort(lines.begin(), lines.end());
|
||||
|
||||
botAI->TellMaster("=== Reputations ===");
|
||||
for (auto const& line : lines)
|
||||
botAI->TellMaster(line);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Player* master = GetMaster();
|
||||
if (!master)
|
||||
return false;
|
||||
|
||||
ObjectGuid selection = master->GetTarget();
|
||||
if (selection.IsEmpty())
|
||||
return false;
|
||||
|
||||
Unit* unit = ObjectAccessor::GetUnit(*master, selection);
|
||||
if (!unit)
|
||||
return false;
|
||||
|
||||
FactionTemplateEntry const* factionTemplate = unit->GetFactionTemplateEntry();
|
||||
|
||||
FactionEntry const* entry = sFactionStore.LookupEntry(factionTemplate->faction);
|
||||
if (!entry)
|
||||
return false;
|
||||
|
||||
botAI->TellMaster(BuildReputationLine(entry));
|
||||
botAI->TellMaster(out);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -6,11 +6,8 @@
|
||||
#ifndef _PLAYERBOT_TELLREPUTATIONACTION_H
|
||||
#define _PLAYERBOT_TELLREPUTATIONACTION_H
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "Action.h"
|
||||
|
||||
struct FactionEntry;
|
||||
class PlayerbotAI;
|
||||
|
||||
class TellReputationAction : public Action
|
||||
@ -19,9 +16,6 @@ public:
|
||||
TellReputationAction(PlayerbotAI* botAI) : Action(botAI, "reputation") {}
|
||||
|
||||
bool Execute(Event event) override;
|
||||
|
||||
private:
|
||||
std::string BuildReputationLine(FactionEntry const* entry);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@ -61,7 +61,7 @@ bool SummonAction::Execute(Event /*event*/)
|
||||
if (!master)
|
||||
return false;
|
||||
|
||||
if (bot->GetPet())
|
||||
if (Pet* pet = bot->GetPet())
|
||||
botAI->PetFollow();
|
||||
|
||||
if (master->GetSession()->GetSecurity() >= SEC_PLAYER)
|
||||
|
||||
@ -44,12 +44,7 @@ WorldPosition GetBestPoint(AiObjectContext* context, Player* bot, Unit* target,
|
||||
float z = targetPosition.GetPositionZ() + 1.0f;
|
||||
|
||||
WorldPosition point(targetPosition.GetMapId(), x, y, z);
|
||||
|
||||
float groundZ = bot->GetMapHeight(x, y, z);
|
||||
if (groundZ == INVALID_HEIGHT || groundZ == VMAP_INVALID_HEIGHT_VALUE)
|
||||
continue;
|
||||
|
||||
point.setZ(groundZ);
|
||||
point.setZ(point.getHeight());
|
||||
|
||||
// Check line of sight to target
|
||||
if (!target->IsWithinLOS(point.GetPositionX(), point.GetPositionY(),
|
||||
@ -93,11 +88,8 @@ bool WaitForAttackKeepSafeDistanceAction::Execute(Event /*event*/)
|
||||
{
|
||||
Unit* target = AI_VALUE(Unit*, "current target");
|
||||
|
||||
if (!target)
|
||||
return false;
|
||||
|
||||
// If our target is moving towards a stationary unit, use that unit as anchor
|
||||
if (!target->IsStopped())
|
||||
if (target && !target->IsStopped())
|
||||
{
|
||||
ObjectGuid targetGuid = target->GetTarget();
|
||||
if (targetGuid)
|
||||
@ -108,7 +100,7 @@ bool WaitForAttackKeepSafeDistanceAction::Execute(Event /*event*/)
|
||||
}
|
||||
}
|
||||
|
||||
if (target->IsAlive())
|
||||
if (target && target->IsAlive())
|
||||
{
|
||||
float safeDistance = std::max(
|
||||
target->GetCombatReach() + ATTACK_DISTANCE,
|
||||
|
||||
@ -37,13 +37,11 @@
|
||||
#include "LogLevelAction.h"
|
||||
#include "LootStrategyAction.h"
|
||||
#include "LootRollAction.h"
|
||||
#include "SetFocusHealTargetsAction.h"
|
||||
#include "MailAction.h"
|
||||
#include "NamedObjectContext.h"
|
||||
#include "NewRpgAction.h"
|
||||
#include "PassLeadershipToMasterAction.h"
|
||||
#include "PositionAction.h"
|
||||
#include "PullActions.h"
|
||||
#include "QueryItemUsageAction.h"
|
||||
#include "QueryQuestAction.h"
|
||||
#include "RangeAction.h"
|
||||
@ -66,7 +64,6 @@
|
||||
#include "TaxiAction.h"
|
||||
#include "TeleportAction.h"
|
||||
#include "TellCastFailedAction.h"
|
||||
#include "TellEmblemsAction.h"
|
||||
#include "TellItemCountAction.h"
|
||||
#include "TellLosAction.h"
|
||||
#include "TellReputationAction.h"
|
||||
@ -121,7 +118,6 @@ public:
|
||||
creators["teleport"] = &ChatActionContext::teleport;
|
||||
creators["taxi"] = &ChatActionContext::taxi;
|
||||
creators["repair"] = &ChatActionContext::repair;
|
||||
creators["emblems"] = &ChatActionContext::emblems;
|
||||
creators["use"] = &ChatActionContext::use;
|
||||
creators["item count"] = &ChatActionContext::item_count;
|
||||
creators["equip"] = &ChatActionContext::equip;
|
||||
@ -141,8 +137,6 @@ public:
|
||||
creators["autogear"] = &ChatActionContext::autogear;
|
||||
creators["equip upgrade"] = &ChatActionContext::equip_upgrade;
|
||||
creators["attack my target"] = &ChatActionContext::attack_my_target;
|
||||
creators["pull my target"] = &ChatActionContext::pull_my_target;
|
||||
creators["pull rti target"] = &ChatActionContext::pull_rti_target;
|
||||
creators["chat"] = &ChatActionContext::chat;
|
||||
creators["home"] = &ChatActionContext::home;
|
||||
creators["destroy"] = &ChatActionContext::destroy;
|
||||
@ -207,7 +201,6 @@ public:
|
||||
creators["pet attack"] = &ChatActionContext::pet_attack;
|
||||
creators["roll"] = &ChatActionContext::roll_action;
|
||||
creators["wait for attack time"] = &ChatActionContext::wait_for_attack_time;
|
||||
creators["focus heal targets"] = &ChatActionContext::focus_heal_targets;
|
||||
}
|
||||
|
||||
private:
|
||||
@ -255,8 +248,6 @@ private:
|
||||
static Action* home(PlayerbotAI* botAI) { return new SetHomeAction(botAI); }
|
||||
static Action* chat(PlayerbotAI* botAI) { return new ChangeChatAction(botAI); }
|
||||
static Action* attack_my_target(PlayerbotAI* botAI) { return new AttackMyTargetAction(botAI); }
|
||||
static Action* pull_my_target(PlayerbotAI* botAI) { return new PullMyTargetAction(botAI); }
|
||||
static Action* pull_rti_target(PlayerbotAI* botAI) { return new PullRtiTargetAction(botAI); }
|
||||
static Action* trainer(PlayerbotAI* botAI) { return new TrainerAction(botAI); }
|
||||
static Action* maintenance(PlayerbotAI* botAI) { return new MaintenanceAction(botAI); }
|
||||
static Action* remove_glyph(PlayerbotAI* botAI) { return new RemoveGlyphAction(botAI); }
|
||||
@ -278,7 +269,6 @@ private:
|
||||
static Action* item_count(PlayerbotAI* botAI) { return new TellItemCountAction(botAI); }
|
||||
static Action* use(PlayerbotAI* botAI) { return new UseItemAction(botAI); }
|
||||
static Action* repair(PlayerbotAI* botAI) { return new RepairAllAction(botAI); }
|
||||
static Action* emblems(PlayerbotAI* botAI) { return new TellEmblemsAction(botAI); }
|
||||
static Action* taxi(PlayerbotAI* botAI) { return new TaxiAction(botAI); }
|
||||
static Action* teleport(PlayerbotAI* botAI) { return new TeleportAction(botAI); }
|
||||
static Action* release(PlayerbotAI* botAI) { return new ReleaseSpiritAction(botAI); }
|
||||
@ -324,7 +314,6 @@ private:
|
||||
static Action* pet_attack(PlayerbotAI* botAI) { return new PetsAction(botAI, "attack"); }
|
||||
static Action* roll_action(PlayerbotAI* botAI) { return new RollAction(botAI); }
|
||||
static Action* wait_for_attack_time(PlayerbotAI* botAI) { return new SetWaitForAttackTimeAction(botAI); }
|
||||
static Action* focus_heal_targets(PlayerbotAI* botAI) { return new SetFocusHealTargetsAction(botAI); }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@ -41,7 +41,6 @@ public:
|
||||
creators["teleport"] = &ChatTriggerContext::teleport;
|
||||
creators["taxi"] = &ChatTriggerContext::taxi;
|
||||
creators["repair"] = &ChatTriggerContext::repair;
|
||||
creators["emblems"] = &ChatTriggerContext::emblems;
|
||||
creators["u"] = &ChatTriggerContext::use;
|
||||
creators["use"] = &ChatTriggerContext::use;
|
||||
creators["c"] = &ChatTriggerContext::item_count;
|
||||
@ -67,9 +66,6 @@ public:
|
||||
creators["autogear"] = &ChatTriggerContext::autogear;
|
||||
creators["equip upgrade"] = &ChatTriggerContext::equip_upgrade;
|
||||
creators["attack"] = &ChatTriggerContext::attack;
|
||||
creators["pull"] = &ChatTriggerContext::pull;
|
||||
creators["pull back"] = &ChatTriggerContext::pull_back;
|
||||
creators["pull rti"] = &ChatTriggerContext::pull_rti;
|
||||
creators["chat"] = &ChatTriggerContext::chat;
|
||||
creators["accept"] = &ChatTriggerContext::accept;
|
||||
creators["home"] = &ChatTriggerContext::home;
|
||||
@ -150,7 +146,6 @@ public:
|
||||
creators["pet attack"] = &ChatTriggerContext::pet_attack;
|
||||
creators["roll"] = &ChatTriggerContext::roll_action;
|
||||
creators["wait for attack time"] = &ChatTriggerContext::wait_for_attack_time;
|
||||
creators["focus heal"] = &ChatTriggerContext::focus_heal;
|
||||
}
|
||||
|
||||
private:
|
||||
@ -213,9 +208,6 @@ private:
|
||||
static Trigger* accept(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "accept"); }
|
||||
static Trigger* chat(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "chat"); }
|
||||
static Trigger* attack(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "attack"); }
|
||||
static Trigger* pull(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "pull"); }
|
||||
static Trigger* pull_back(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "pull back"); }
|
||||
static Trigger* pull_rti(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "pull rti"); }
|
||||
static Trigger* trainer(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "trainer"); }
|
||||
static Trigger* maintenance(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "maintenance"); }
|
||||
static Trigger* remove_glyph(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "remove glyph"); }
|
||||
@ -236,7 +228,6 @@ private:
|
||||
static Trigger* item_count(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "c"); }
|
||||
static Trigger* use(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "use"); }
|
||||
static Trigger* repair(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "repair"); }
|
||||
static Trigger* emblems(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "emblems"); }
|
||||
static Trigger* taxi(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "taxi"); }
|
||||
static Trigger* teleport(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "teleport"); }
|
||||
static Trigger* q(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "q"); }
|
||||
@ -280,7 +271,6 @@ private:
|
||||
static Trigger* pet_attack(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "pet attack"); }
|
||||
static Trigger* roll_action(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "roll"); }
|
||||
static Trigger* wait_for_attack_time(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "wait for attack time"); }
|
||||
static Trigger* focus_heal(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "focus heal"); }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@ -11,7 +11,7 @@ public:
|
||||
ChatCommandActionNodeFactoryInternal() { creators["tank attack chat shortcut"] = &tank_attack_chat_shortcut; }
|
||||
|
||||
private:
|
||||
static ActionNode* tank_attack_chat_shortcut(PlayerbotAI* /*botAI*/)
|
||||
static ActionNode* tank_attack_chat_shortcut(PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode("tank attack chat shortcut",
|
||||
/*P*/ {},
|
||||
@ -81,12 +81,6 @@ void ChatCommandHandlerStrategy::InitTriggers(std::vector<TriggerNode*>& trigger
|
||||
new TriggerNode("attackers", { NextAction("tell attackers", relevance) }));
|
||||
triggers.push_back(
|
||||
new TriggerNode("target", { NextAction("tell target", relevance) }));
|
||||
triggers.push_back(
|
||||
new TriggerNode("pull", { NextAction("pull my target", relevance) }));
|
||||
triggers.push_back(
|
||||
new TriggerNode("pull back", { NextAction("pull my target", relevance) }));
|
||||
triggers.push_back(
|
||||
new TriggerNode("pull rti", { NextAction("pull rti target", relevance) }));
|
||||
triggers.push_back(
|
||||
new TriggerNode("ready", { NextAction("ready check", relevance) }));
|
||||
triggers.push_back(
|
||||
@ -113,8 +107,6 @@ void ChatCommandHandlerStrategy::InitTriggers(std::vector<TriggerNode*>& trigger
|
||||
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) }));
|
||||
triggers.push_back(new TriggerNode("focus heal", { NextAction("focus heal targets", relevance) }));
|
||||
triggers.push_back(new TriggerNode("emblems", { NextAction("emblems", relevance) }));
|
||||
}
|
||||
|
||||
ChatCommandHandlerStrategy::ChatCommandHandlerStrategy(PlayerbotAI* botAI) : PassTroughStrategy(botAI)
|
||||
@ -139,7 +131,6 @@ ChatCommandHandlerStrategy::ChatCommandHandlerStrategy(PlayerbotAI* botAI) : Pas
|
||||
supported.push_back("teleport");
|
||||
supported.push_back("taxi");
|
||||
supported.push_back("repair");
|
||||
supported.push_back("emblems");
|
||||
supported.push_back("talents");
|
||||
supported.push_back("spells");
|
||||
supported.push_back("co");
|
||||
@ -204,10 +195,9 @@ ChatCommandHandlerStrategy::ChatCommandHandlerStrategy(PlayerbotAI* botAI) : Pas
|
||||
supported.push_back("unlock items");
|
||||
supported.push_back("unlock traded item");
|
||||
supported.push_back("tame");
|
||||
supported.push_back("glyphs");
|
||||
supported.push_back("glyph equip");
|
||||
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");
|
||||
supported.push_back("wait for attack time");
|
||||
supported.push_back("focus heal");
|
||||
}
|
||||
|
||||
@ -64,11 +64,11 @@ std::vector<NextAction> AvoidAoeStrategy::getDefaultActions()
|
||||
};
|
||||
}
|
||||
|
||||
void AvoidAoeStrategy::InitTriggers(std::vector<TriggerNode*>& /*triggers*/)
|
||||
void AvoidAoeStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
}
|
||||
|
||||
void AvoidAoeStrategy::InitMultipliers(std::vector<Multiplier*>& /*multipliers*/)
|
||||
void AvoidAoeStrategy::InitMultipliers(std::vector<Multiplier*>& multipliers)
|
||||
{
|
||||
}
|
||||
|
||||
@ -81,7 +81,7 @@ std::vector<NextAction> TankFaceStrategy::getDefaultActions()
|
||||
};
|
||||
}
|
||||
|
||||
void TankFaceStrategy::InitTriggers(std::vector<TriggerNode*>& /*triggers*/)
|
||||
void TankFaceStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@ -17,6 +17,6 @@ void DuelStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
|
||||
DuelStrategy::DuelStrategy(PlayerbotAI* botAI) : PassTroughStrategy(botAI) {}
|
||||
|
||||
void StartDuelStrategy::InitTriggers(std::vector<TriggerNode*>& /*triggers*/) {}
|
||||
void StartDuelStrategy::InitTriggers(std::vector<TriggerNode*>& triggers) {}
|
||||
|
||||
StartDuelStrategy::StartDuelStrategy(PlayerbotAI* botAI) : Strategy(botAI) {}
|
||||
|
||||
@ -1,20 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#ifndef _PLAYERBOT_FOCUSTARGETSTRATEGY_H
|
||||
#define _PLAYERBOT_FOCUSTARGETSTRATEGY_H
|
||||
|
||||
#include "Strategy.h"
|
||||
|
||||
class PlayerbotAI;
|
||||
|
||||
class FocusHealTargetsStrategy : public Strategy
|
||||
{
|
||||
public:
|
||||
FocusHealTargetsStrategy(PlayerbotAI* botAI) : Strategy(botAI) {}
|
||||
std::string const getName() override { return "focus heal targets"; }
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -12,6 +12,6 @@ std::vector<NextAction> FollowMasterStrategy::getDefaultActions()
|
||||
};
|
||||
}
|
||||
|
||||
void FollowMasterStrategy::InitTriggers(std::vector<TriggerNode*>& /*triggers*/)
|
||||
void FollowMasterStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
}
|
||||
|
||||
@ -12,4 +12,4 @@ std::vector<NextAction> GuardStrategy::getDefaultActions()
|
||||
};
|
||||
}
|
||||
|
||||
void GuardStrategy::InitTriggers(std::vector<TriggerNode*>& /*triggers*/) {}
|
||||
void GuardStrategy::InitTriggers(std::vector<TriggerNode*>& triggers) {}
|
||||
|
||||
@ -13,7 +13,7 @@ void MaintenanceStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"seldom",
|
||||
"random",
|
||||
{
|
||||
NextAction("clean quest log", 6.0f)
|
||||
}
|
||||
|
||||
@ -17,7 +17,7 @@ void CollisionStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
new TriggerNode("collision", { NextAction("move out of collision", 2.0f) }));
|
||||
}
|
||||
|
||||
void MountStrategy::InitTriggers(std::vector<TriggerNode*>& /*triggers*/)
|
||||
void MountStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@ -5,188 +5,8 @@
|
||||
|
||||
#include "PullStrategy.h"
|
||||
|
||||
#include "AiObjectContext.h"
|
||||
#include "PassiveMultiplier.h"
|
||||
#include "Player.h"
|
||||
#include "PlayerbotAI.h"
|
||||
#include "Playerbots.h"
|
||||
#include "SpellMgr.h"
|
||||
|
||||
class PullStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
|
||||
{
|
||||
public:
|
||||
PullStrategyActionNodeFactory()
|
||||
{
|
||||
creators["pull start"] = &pull_start;
|
||||
}
|
||||
|
||||
private:
|
||||
static ActionNode* pull_start(PlayerbotAI* /*botAI*/)
|
||||
{
|
||||
return new ActionNode("pull start", {}, {}, { NextAction("pull action", ACTION_NORMAL) });
|
||||
}
|
||||
};
|
||||
|
||||
PullStrategy::PullStrategy(PlayerbotAI* botAI, std::string const action, std::string const preAction)
|
||||
: Strategy(botAI), action(action), preAction(preAction)
|
||||
{
|
||||
actionNodeFactories.Add(new PullStrategyActionNodeFactory());
|
||||
}
|
||||
|
||||
PullStrategy* PullStrategy::Get(PlayerbotAI* botAI)
|
||||
{
|
||||
if (!botAI)
|
||||
return nullptr;
|
||||
|
||||
if (PullStrategy* strategy = dynamic_cast<PullStrategy*>(botAI->GetStrategy("pull", BOT_STATE_NON_COMBAT)))
|
||||
{
|
||||
if (strategy->IsPullPendingToStart() || strategy->HasPullStarted() || strategy->HasTarget())
|
||||
return strategy;
|
||||
}
|
||||
|
||||
return dynamic_cast<PullStrategy*>(botAI->GetStrategy("pull", BOT_STATE_COMBAT));
|
||||
}
|
||||
|
||||
Unit* PullStrategy::GetTarget() const
|
||||
{
|
||||
ObjectGuid const guid = botAI->GetAiObjectContext()->GetValue<ObjectGuid>("pull strategy target")->Get();
|
||||
if (guid.IsEmpty())
|
||||
return nullptr;
|
||||
|
||||
Unit* target = botAI->GetUnit(guid);
|
||||
Player* bot = botAI->GetBot();
|
||||
if (!bot || !target || !target->IsAlive() || !target->IsInWorld() ||
|
||||
target->GetMapId() != bot->GetMapId())
|
||||
return nullptr;
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
bool PullStrategy::HasTarget() const { return GetTarget() != nullptr; }
|
||||
|
||||
void PullStrategy::SetTarget(Unit* target)
|
||||
{
|
||||
botAI->GetAiObjectContext()->GetValue<ObjectGuid>("pull strategy target")->Set(target ? target->GetGUID() : ObjectGuid::Empty);
|
||||
}
|
||||
|
||||
std::string PullStrategy::GetPullActionName() const
|
||||
{
|
||||
return action;
|
||||
}
|
||||
|
||||
std::string PullStrategy::GetSpellName() const
|
||||
{
|
||||
Player* bot = botAI->GetBot();
|
||||
std::string spellName = GetPullActionName();
|
||||
if (!bot || spellName != "shoot")
|
||||
return spellName;
|
||||
|
||||
Item* equippedWeapon = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_RANGED);
|
||||
if (!equippedWeapon)
|
||||
return spellName;
|
||||
|
||||
ItemTemplate const* itemTemplate = equippedWeapon->GetTemplate();
|
||||
if (!itemTemplate)
|
||||
return spellName;
|
||||
|
||||
switch (itemTemplate->SubClass)
|
||||
{
|
||||
case ITEM_SUBCLASS_WEAPON_THROWN:
|
||||
return "throw";
|
||||
case ITEM_SUBCLASS_WEAPON_GUN:
|
||||
return "shoot gun";
|
||||
case ITEM_SUBCLASS_WEAPON_BOW:
|
||||
return "shoot bow";
|
||||
case ITEM_SUBCLASS_WEAPON_CROSSBOW:
|
||||
return "shoot crossbow";
|
||||
default:
|
||||
return spellName;
|
||||
}
|
||||
}
|
||||
|
||||
float PullStrategy::GetRange() const
|
||||
{
|
||||
Player* bot = botAI->GetBot();
|
||||
std::string const spellName = GetSpellName();
|
||||
if (bot && !spellName.empty())
|
||||
{
|
||||
uint32 const spellId = botAI->GetAiObjectContext()->GetValue<uint32>("spell id", spellName)->Get();
|
||||
if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId))
|
||||
return bot->GetSpellMaxRangeForTarget(GetTarget(), spellInfo) - CONTACT_DISTANCE;
|
||||
}
|
||||
|
||||
return (action == "shoot" ? botAI->GetRange("shoot") : botAI->GetRange("spell")) - CONTACT_DISTANCE;
|
||||
}
|
||||
|
||||
std::string PullStrategy::GetPreActionName() const
|
||||
{
|
||||
return preAction;
|
||||
}
|
||||
|
||||
bool PullStrategy::CanDoPullAction(Unit* target)
|
||||
{
|
||||
Player* bot = botAI->GetBot();
|
||||
if (!bot || !target)
|
||||
return false;
|
||||
|
||||
if (!target->IsInWorld() || target->GetMapId() != bot->GetMapId())
|
||||
return false;
|
||||
|
||||
if (bot->getClass() != CLASS_DRUID && bot->getClass() != CLASS_PALADIN &&
|
||||
GetPullActionName() == "shoot" && !bot->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_RANGED))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string const spellName = GetSpellName();
|
||||
if (spellName.empty())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void PullStrategy::RequestPull(Unit* target, bool resetTime)
|
||||
{
|
||||
SetTarget(target);
|
||||
pendingToStart = true;
|
||||
if (resetTime)
|
||||
pullStartTime = time(nullptr);
|
||||
}
|
||||
|
||||
void PullStrategy::OnPullStarted() { pendingToStart = false; }
|
||||
|
||||
void PullStrategy::OnPullEnded()
|
||||
{
|
||||
pullStartTime = 0;
|
||||
pendingToStart = false;
|
||||
SetTarget(nullptr);
|
||||
}
|
||||
|
||||
PullMultiplier::PullMultiplier(PlayerbotAI* botAI) : Multiplier(botAI, "pull") {}
|
||||
|
||||
float PullMultiplier::GetValue(Action* action)
|
||||
{
|
||||
PullStrategy const* strategy = PullStrategy::Get(botAI);
|
||||
if (!strategy || !strategy->HasTarget() || !action)
|
||||
return 1.0f;
|
||||
|
||||
if (!strategy->IsPullPendingToStart() && !strategy->HasPullStarted())
|
||||
return 1.0f;
|
||||
|
||||
std::string const actionName = action->getName();
|
||||
if (actionName == "pull my target" ||
|
||||
actionName == "pull rti target" ||
|
||||
actionName == "reach pull" ||
|
||||
actionName == "pull start" ||
|
||||
actionName == "pull action" ||
|
||||
actionName == "return to pull position" ||
|
||||
actionName == "pull end" ||
|
||||
actionName == "follow" ||
|
||||
actionName == "set facing")
|
||||
return 1.0f;
|
||||
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
class MagePullMultiplier : public PassiveMultiplier
|
||||
{
|
||||
@ -204,16 +24,8 @@ float MagePullMultiplier::GetValue(Action* action)
|
||||
if (!action)
|
||||
return 1.0f;
|
||||
|
||||
PullStrategy const* strategy = PullStrategy::Get(botAI);
|
||||
if (!strategy || !strategy->HasTarget())
|
||||
return 1.0f;
|
||||
|
||||
std::string const name = action->getName();
|
||||
if (actionName == name || name == "pull action" || name == "pull start" || name == "pull end" ||
|
||||
name == "pull my target" || name == "pull rti target" ||
|
||||
name == "reach spell" || name == "reach pull" ||
|
||||
name == "return to pull position" || name == "follow" ||
|
||||
name == "set facing" || name == "change strategy")
|
||||
if (actionName == name || name == "reach spell" || name == "change strategy")
|
||||
return 1.0f;
|
||||
|
||||
return PassiveMultiplier::GetValue(action);
|
||||
@ -222,32 +34,18 @@ float MagePullMultiplier::GetValue(Action* action)
|
||||
std::vector<NextAction> PullStrategy::getDefaultActions()
|
||||
{
|
||||
return {
|
||||
NextAction("pull action", 105.0f),
|
||||
NextAction(action, 105.0f),
|
||||
NextAction("follow", 104.0f),
|
||||
NextAction("end pull", 103.0f),
|
||||
};
|
||||
}
|
||||
|
||||
void PullStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(new TriggerNode(
|
||||
"pull start",
|
||||
{
|
||||
NextAction("pull start", 106.0f),
|
||||
NextAction("pull action", ACTION_MOVE)
|
||||
}
|
||||
));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"pull end",
|
||||
{
|
||||
NextAction("pull end", 107.0f)
|
||||
}
|
||||
));
|
||||
}
|
||||
void PullStrategy::InitTriggers(std::vector<TriggerNode*>& triggers) { CombatStrategy::InitTriggers(triggers); }
|
||||
|
||||
void PullStrategy::InitMultipliers(std::vector<Multiplier*>& multipliers)
|
||||
{
|
||||
multipliers.push_back(new PullMultiplier(botAI));
|
||||
multipliers.push_back(new MagePullMultiplier(botAI, action));
|
||||
CombatStrategy::InitMultipliers(multipliers);
|
||||
}
|
||||
|
||||
void PossibleAddsStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
@ -263,15 +61,3 @@ void PossibleAddsStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
void PullBackStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
Strategy::InitTriggers(triggers);
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"return to pull position",
|
||||
{
|
||||
NextAction("return to pull position", ACTION_MOVE + 5.0f)
|
||||
}
|
||||
));
|
||||
}
|
||||
|
||||
@ -6,65 +6,22 @@
|
||||
#ifndef _PLAYERBOT_PULLSTRATEGY_H
|
||||
#define _PLAYERBOT_PULLSTRATEGY_H
|
||||
|
||||
#include "Strategy.h"
|
||||
|
||||
class Action;
|
||||
class Multiplier;
|
||||
class Unit;
|
||||
#include "CombatStrategy.h"
|
||||
|
||||
class PlayerbotAI;
|
||||
|
||||
class PullStrategy : public Strategy
|
||||
class PullStrategy : public CombatStrategy
|
||||
{
|
||||
public:
|
||||
PullStrategy(PlayerbotAI* botAI, std::string const action, std::string const preAction = "");
|
||||
PullStrategy(PlayerbotAI* botAI, std::string const action) : CombatStrategy(botAI), action(action) {}
|
||||
|
||||
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
|
||||
void InitMultipliers(std::vector<Multiplier*>& multipliers) override;
|
||||
std::string const getName() override { return "pull"; }
|
||||
std::vector<NextAction> getDefaultActions() override;
|
||||
uint32 GetType() const override { return STRATEGY_TYPE_COMBAT | STRATEGY_TYPE_NONCOMBAT; }
|
||||
|
||||
static PullStrategy* Get(PlayerbotAI* botAI);
|
||||
static uint8 GetMaxPullTime() { return 15; }
|
||||
|
||||
time_t GetPullStartTime() const { return pullStartTime; }
|
||||
bool IsPullPendingToStart() const { return pendingToStart; }
|
||||
bool HasPullStarted() const { return pullStartTime > 0; }
|
||||
|
||||
bool CanDoPullAction(Unit* target);
|
||||
Unit* GetTarget() const;
|
||||
bool HasTarget() const;
|
||||
|
||||
virtual std::string GetPullActionName() const;
|
||||
std::string GetSpellName() const;
|
||||
float GetRange() const;
|
||||
virtual std::string GetPreActionName() const;
|
||||
|
||||
void RequestPull(Unit* target, bool resetTime = true);
|
||||
void OnPullStarted();
|
||||
void OnPullEnded();
|
||||
|
||||
ReactStates GetPetReactState() const { return petReactState; }
|
||||
void SetPetReactState(ReactStates reactState) { petReactState = reactState; }
|
||||
|
||||
private:
|
||||
void SetTarget(Unit* target);
|
||||
|
||||
private:
|
||||
std::string const action;
|
||||
std::string const preAction;
|
||||
bool pendingToStart = false;
|
||||
time_t pullStartTime = 0;
|
||||
ReactStates petReactState = REACT_DEFENSIVE;
|
||||
};
|
||||
|
||||
class PullMultiplier : public Multiplier
|
||||
{
|
||||
public:
|
||||
PullMultiplier(PlayerbotAI* botAI);
|
||||
|
||||
float GetValue(Action* action) override;
|
||||
};
|
||||
|
||||
class PossibleAddsStrategy : public Strategy
|
||||
@ -76,13 +33,4 @@ public:
|
||||
std::string const getName() override { return "adds"; }
|
||||
};
|
||||
|
||||
class PullBackStrategy : public Strategy
|
||||
{
|
||||
public:
|
||||
PullBackStrategy(PlayerbotAI* botAI) : Strategy(botAI) {}
|
||||
|
||||
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
|
||||
std::string const getName() override { return "pull back"; }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@ -7,4 +7,4 @@
|
||||
|
||||
RTSCStrategy::RTSCStrategy(PlayerbotAI* botAI) : Strategy(botAI) {}
|
||||
|
||||
void RTSCStrategy::InitTriggers(std::vector<TriggerNode*>& /*triggers*/) {}
|
||||
void RTSCStrategy::InitTriggers(std::vector<TriggerNode*>& triggers) {}
|
||||
|
||||
@ -11,7 +11,7 @@ public:
|
||||
RacialsStrategyActionNodeFactory() { creators["lifeblood"] = &lifeblood; }
|
||||
|
||||
private:
|
||||
static ActionNode* lifeblood(PlayerbotAI* /*botAI*/)
|
||||
static ActionNode* lifeblood(PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode("lifeblood",
|
||||
/*P*/ {},
|
||||
|
||||
@ -11,7 +11,7 @@ public:
|
||||
UsePotionsStrategyActionNodeFactory() { creators["healthstone"] = &healthstone; }
|
||||
|
||||
private:
|
||||
static ActionNode* healthstone(PlayerbotAI* /*botAI*/)
|
||||
static ActionNode* healthstone(PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode("healthstone",
|
||||
/*P*/ {},
|
||||
|
||||
@ -82,7 +82,6 @@ float WaitForAttackMultiplier::GetValue(Action* action)
|
||||
actionName != "set facing" &&
|
||||
actionName != "pull my target" &&
|
||||
actionName != "pull rti target" &&
|
||||
actionName != "reach pull" &&
|
||||
actionName != "pull start" &&
|
||||
actionName != "pull action" &&
|
||||
actionName != "pull end")
|
||||
|
||||
@ -19,7 +19,6 @@
|
||||
#include "DuelStrategy.h"
|
||||
#include "EmoteStrategy.h"
|
||||
#include "FleeStrategy.h"
|
||||
#include "FocusTargetStrategy.h"
|
||||
#include "FollowMasterStrategy.h"
|
||||
#include "GrindingStrategy.h"
|
||||
#include "GroupStrategy.h"
|
||||
@ -95,7 +94,6 @@ public:
|
||||
creators["sit"] = &StrategyContext::sit;
|
||||
creators["mark rti"] = &StrategyContext::mark_rti;
|
||||
creators["adds"] = &StrategyContext::possible_adds;
|
||||
creators["pull back"] = &StrategyContext::pull_back;
|
||||
creators["close"] = &StrategyContext::close;
|
||||
creators["ranged"] = &StrategyContext::ranged;
|
||||
creators["behind"] = &StrategyContext::behind;
|
||||
@ -128,7 +126,6 @@ public:
|
||||
creators["use bobber"] = &StrategyContext::bobber_strategy;
|
||||
creators["master fishing"] = &StrategyContext::master_fishing;
|
||||
creators["wait for attack"] = &StrategyContext::wait_for_attack;
|
||||
creators["focus heal targets"] = &StrategyContext::focus_heal_targets;
|
||||
}
|
||||
|
||||
private:
|
||||
@ -172,7 +169,6 @@ private:
|
||||
static Strategy* map_full(PlayerbotAI* botAI) { return new MapFullStrategy(botAI); }
|
||||
static Strategy* sit(PlayerbotAI* botAI) { return new SitStrategy(botAI); }
|
||||
static Strategy* possible_adds(PlayerbotAI* botAI) { return new PossibleAddsStrategy(botAI); }
|
||||
static Strategy* pull_back(PlayerbotAI* botAI) { return new PullBackStrategy(botAI); }
|
||||
static Strategy* mount(PlayerbotAI* botAI) { return new MountStrategy(botAI); }
|
||||
static Strategy* bg(PlayerbotAI* botAI) { return new BGStrategy(botAI); }
|
||||
static Strategy* battleground(PlayerbotAI* botAI) { return new BattlegroundStrategy(botAI); }
|
||||
@ -202,7 +198,6 @@ private:
|
||||
static Strategy* bobber_strategy(PlayerbotAI* botAI) { return new UseBobberStrategy(botAI); }
|
||||
static Strategy* master_fishing(PlayerbotAI* botAI) { return new MasterFishingStrategy(botAI); }
|
||||
static Strategy* wait_for_attack(PlayerbotAI* botAI) { return new WaitForAttackStrategy(botAI); }
|
||||
static Strategy* focus_heal_targets(PlayerbotAI* botAI) { return new FocusHealTargetsStrategy(botAI); }
|
||||
};
|
||||
|
||||
class MovementStrategyContext : public NamedObjectContext<Strategy>
|
||||
|
||||
@ -481,13 +481,6 @@ bool FearCharmSleepTrigger::IsActive()
|
||||
bot->HasAuraWithMechanic(1 << MECHANIC_SLEEP);
|
||||
}
|
||||
|
||||
bool FearSleepSapTrigger::IsActive()
|
||||
{
|
||||
return bot->HasAuraType(SPELL_AURA_MOD_FEAR) ||
|
||||
bot->HasAuraWithMechanic(1 << MECHANIC_SLEEP) ||
|
||||
bot->HasAuraWithMechanic(1 << MECHANIC_SAPPED);
|
||||
}
|
||||
|
||||
bool HasAuraStackTrigger::IsActive()
|
||||
{
|
||||
Aura* aura = botAI->GetAura(getName(), GetTarget(), false, true, stack);
|
||||
|
||||
@ -762,14 +762,6 @@ public:
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class FearSleepSapTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
FearSleepSapTrigger(PlayerbotAI* botAI) : Trigger(botAI, "fear sleep sap", 1) {}
|
||||
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class IsSwimmingTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
|
||||
@ -1,62 +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 "PullTriggers.h"
|
||||
|
||||
#include "PositionValue.h"
|
||||
#include "Player.h"
|
||||
#include "PlayerbotAI.h"
|
||||
#include "Playerbots.h"
|
||||
#include "PullStrategy.h"
|
||||
|
||||
bool PullStartTrigger::IsActive()
|
||||
{
|
||||
PullStrategy const* strategy = PullStrategy::Get(botAI);
|
||||
return strategy && strategy->IsPullPendingToStart();
|
||||
}
|
||||
|
||||
bool PullEndTrigger::IsActive()
|
||||
{
|
||||
PullStrategy const* strategy = PullStrategy::Get(botAI);
|
||||
|
||||
if (!strategy || !strategy->HasPullStarted())
|
||||
return false;
|
||||
|
||||
Unit* target = strategy->GetTarget();
|
||||
if (!target || !target->IsInWorld() || !target->IsAlive())
|
||||
return true;
|
||||
|
||||
time_t const secondsSincePullStarted = time(nullptr) - strategy->GetPullStartTime();
|
||||
if (secondsSincePullStarted >= PullStrategy::GetMaxPullTime())
|
||||
return true;
|
||||
|
||||
float distanceToPullTarget = bot->GetDistance(target);
|
||||
if (distanceToPullTarget > ATTACK_DISTANCE && !target->IsNonMeleeSpellCast(false, false, true) &&
|
||||
(!botAI->IsRanged(bot) || distanceToPullTarget > botAI->GetRange("spell")))
|
||||
return false;
|
||||
|
||||
if (!botAI->HasStrategy("pull back", BOT_STATE_COMBAT))
|
||||
return true;
|
||||
|
||||
PositionInfo pullPosition = AI_VALUE(PositionMap&, "position")["pull"];
|
||||
if (!pullPosition.isSet() || pullPosition.mapId != bot->GetMapId())
|
||||
return true;
|
||||
|
||||
return bot->GetDistance(pullPosition.x, pullPosition.y, pullPosition.z) <= botAI->GetRange("follow");
|
||||
}
|
||||
|
||||
bool ReturnToPullPositionTrigger::IsActive()
|
||||
{
|
||||
PullStrategy const* strategy = PullStrategy::Get(botAI);
|
||||
|
||||
Unit* target = strategy ? strategy->GetTarget() : nullptr;
|
||||
if (!strategy || !strategy->HasPullStarted() || !target || !target->IsInCombat() ||
|
||||
!botAI->HasStrategy("pull back", BOT_STATE_COMBAT))
|
||||
return false;
|
||||
|
||||
PositionInfo pullPosition = AI_VALUE(PositionMap&, "position")["pull"];
|
||||
return pullPosition.isSet() && pullPosition.mapId == bot->GetMapId() &&
|
||||
bot->GetDistance(pullPosition.x, pullPosition.y, pullPosition.z) > sPlayerbotAIConfig.followDistance;
|
||||
}
|
||||
@ -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.
|
||||
*/
|
||||
|
||||
#ifndef _PLAYERBOT_PULLTRIGGERS_H
|
||||
#define _PLAYERBOT_PULLTRIGGERS_H
|
||||
|
||||
#include "Trigger.h"
|
||||
|
||||
class PullStartTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
PullStartTrigger(PlayerbotAI* botAI, std::string const name = "pull start") : Trigger(botAI, name) {}
|
||||
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class PullEndTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
PullEndTrigger(PlayerbotAI* botAI, std::string const name = "pull end") : Trigger(botAI, name) {}
|
||||
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class ReturnToPullPositionTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
ReturnToPullPositionTrigger(PlayerbotAI* botAI) : Trigger(botAI, "return to pull position") {}
|
||||
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -297,7 +297,7 @@ bool PlayerWantsInBattlegroundTrigger::IsActive()
|
||||
if (bot->GetBattleground() && bot->GetBattleground()->GetStatus() == STATUS_IN_PROGRESS)
|
||||
return false;
|
||||
|
||||
if (bot->IsDeserter())
|
||||
if (!bot->CanJoinToBattleground())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
||||
@ -16,5 +16,5 @@ bool NoRtiTrigger::IsActive()
|
||||
return false;
|
||||
|
||||
Unit* target = AI_VALUE(Unit*, "rti target");
|
||||
return target == nullptr;
|
||||
return target != nullptr;
|
||||
}
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
#include "CellImpl.h"
|
||||
#include "PathGenerator.h"
|
||||
#include "Playerbots.h"
|
||||
#include "MapCollisionData.h"
|
||||
#include "MMapFactory.h"
|
||||
|
||||
bool MoveStuckTrigger::IsActive()
|
||||
{
|
||||
@ -89,7 +89,8 @@ bool MoveLongStuckTrigger::IsActive()
|
||||
return true;
|
||||
}
|
||||
|
||||
if (bot->GetMap()->IsGridCreated(GridCoord(cell.GridX(), cell.GridY())))
|
||||
if (cell.GridX() > 0 && cell.GridY() > 0 &&
|
||||
!MMAP::MMapFactory::createOrGetMMapMgr()->loadMap(botPos.GetMapId(), cell.GridX(), cell.GridY()))
|
||||
{
|
||||
// LOG_INFO("playerbots", "Bot {} {}:{} <{}> was in unloaded grid {},{} on map {}",
|
||||
// bot->GetGUID().ToString().c_str(), bot->GetTeamId() == TEAM_ALLIANCE ? "A" : "H", bot->GetLevel(),
|
||||
|
||||
@ -16,7 +16,6 @@
|
||||
#include "NewRpgStrategy.h"
|
||||
#include "NewRpgTriggers.h"
|
||||
#include "PvpTriggers.h"
|
||||
#include "PullTriggers.h"
|
||||
#include "RpgTriggers.h"
|
||||
#include "RtiTriggers.h"
|
||||
#include "StuckTriggers.h"
|
||||
@ -63,7 +62,6 @@ public:
|
||||
creators["generic boost"] = &TriggerContext::generic_boost;
|
||||
creators["loss of control"] = &TriggerContext::loss_of_control;
|
||||
creators["fear charm sleep"] = &TriggerContext::fear_charm_sleep;
|
||||
creators["fear sleep sap"] = &TriggerContext::fear_sleep_sap;
|
||||
|
||||
creators["protect party member"] = &TriggerContext::protect_party_member;
|
||||
|
||||
@ -130,9 +128,6 @@ public:
|
||||
creators["has attackers"] = &TriggerContext::has_attackers;
|
||||
creators["no possible targets"] = &TriggerContext::no_possible_targets;
|
||||
creators["possible adds"] = &TriggerContext::possible_adds;
|
||||
creators["pull start"] = &TriggerContext::pull_start;
|
||||
creators["pull end"] = &TriggerContext::pull_end;
|
||||
creators["return to pull position"] = &TriggerContext::return_to_pull_position;
|
||||
|
||||
creators["no drink"] = &TriggerContext::no_drink;
|
||||
creators["no food"] = &TriggerContext::no_food;
|
||||
@ -234,7 +229,6 @@ public:
|
||||
creators["wander npc status"] = &TriggerContext::wander_npc_status;
|
||||
creators["do quest status"] = &TriggerContext::do_quest_status;
|
||||
creators["travel flight status"] = &TriggerContext::travel_flight_status;
|
||||
creators["outdoor pvp status"] = &TriggerContext::outdoor_pvp_status;
|
||||
creators["can self resurrect"] = &TriggerContext::can_self_resurrect;
|
||||
creators["can fish"] = &TriggerContext::can_fish;
|
||||
creators["can use fishing bobber"] = &TriggerContext::can_use_fishing_bobber;
|
||||
@ -284,9 +278,6 @@ private:
|
||||
static Trigger* swimming(PlayerbotAI* botAI) { return new IsSwimmingTrigger(botAI); }
|
||||
static Trigger* no_possible_targets(PlayerbotAI* botAI) { return new NoPossibleTargetsTrigger(botAI); }
|
||||
static Trigger* possible_adds(PlayerbotAI* botAI) { return new PossibleAddsTrigger(botAI); }
|
||||
static Trigger* pull_start(PlayerbotAI* botAI) { return new PullStartTrigger(botAI); }
|
||||
static Trigger* pull_end(PlayerbotAI* botAI) { return new PullEndTrigger(botAI); }
|
||||
static Trigger* return_to_pull_position(PlayerbotAI* botAI) { return new ReturnToPullPositionTrigger(botAI); }
|
||||
static Trigger* can_loot(PlayerbotAI* botAI) { return new CanLootTrigger(botAI); }
|
||||
static Trigger* far_from_loot_target(PlayerbotAI* botAI) { return new FarFromCurrentLootTrigger(botAI); }
|
||||
static Trigger* far_from_master(PlayerbotAI* botAI) { return new FarFromMasterTrigger(botAI); }
|
||||
@ -378,7 +369,6 @@ private:
|
||||
static Trigger* generic_boost(PlayerbotAI* botAI) { return new GenericBoostTrigger(botAI); }
|
||||
static Trigger* loss_of_control(PlayerbotAI* botAI) { return new LossOfControlTrigger(botAI); }
|
||||
static Trigger* fear_charm_sleep(PlayerbotAI* botAI) { return new FearCharmSleepTrigger(botAI); }
|
||||
static Trigger* fear_sleep_sap(PlayerbotAI* botAI) { return new FearSleepSapTrigger(botAI); }
|
||||
static Trigger* PartyMemberCriticalHealth(PlayerbotAI* botAI)
|
||||
{
|
||||
return new PartyMemberCriticalHealthTrigger(botAI);
|
||||
@ -444,7 +434,6 @@ private:
|
||||
static Trigger* wander_npc_status(PlayerbotAI* botAI) { return new NewRpgStatusTrigger(botAI, RPG_WANDER_NPC); }
|
||||
static Trigger* do_quest_status(PlayerbotAI* botAI) { return new NewRpgStatusTrigger(botAI, RPG_DO_QUEST); }
|
||||
static Trigger* travel_flight_status(PlayerbotAI* botAI) { return new NewRpgStatusTrigger(botAI, RPG_TRAVEL_FLIGHT); }
|
||||
static Trigger* outdoor_pvp_status(PlayerbotAI* botAI) { return new NewRpgStatusTrigger(botAI, RPG_OUTDOOR_PVP); }
|
||||
static Trigger* can_self_resurrect(PlayerbotAI* ai) { return new SelfResurrectTrigger(ai); }
|
||||
static Trigger* can_fish(PlayerbotAI* ai) { return new CanFishTrigger(ai); }
|
||||
static Trigger* can_use_fishing_bobber(PlayerbotAI* ai) { return new CanUseFishingBobberTrigger(ai); }
|
||||
|
||||
@ -19,7 +19,6 @@ WorldLocation ArrowFormation::GetLocationInternal()
|
||||
uint32 tankLines = 1 + tanks.Size() / 6;
|
||||
uint32 meleeLines = 1 + melee.Size() / 6;
|
||||
uint32 rangedLines = 1 + ranged.Size() / 6;
|
||||
//TODO Implement Healer Lines
|
||||
uint32 healerLines = 1 + healers.Size() / 6;
|
||||
float offset = 0.f;
|
||||
|
||||
@ -148,7 +147,7 @@ UnitPosition MultiLineUnitPlacer::Place(FormationUnit* unit, uint32 index, uint3
|
||||
return placer.Place(unit, indexInLine, lineSize);
|
||||
}
|
||||
|
||||
UnitPosition SingleLineUnitPlacer::Place(FormationUnit* /*unit*/, uint32 index, uint32 count)
|
||||
UnitPosition SingleLineUnitPlacer::Place(FormationUnit* unit, uint32 index, uint32 count)
|
||||
{
|
||||
float angle = orientation - M_PI / 2.0f;
|
||||
float x = cos(angle) * sPlayerbotAIConfig.followDistance * ((float)index - (float)count / 2);
|
||||
|
||||
@ -20,7 +20,7 @@ public:
|
||||
}
|
||||
|
||||
public:
|
||||
void CheckAttacker(Unit* creature, ThreatManager* /*threatMgr*/) override
|
||||
void CheckAttacker(Unit* creature, ThreatManager* threatMgr) override
|
||||
{
|
||||
Player* bot = botAI->GetBot();
|
||||
if (!botAI->CanCastSpell(spell, creature))
|
||||
|
||||
@ -13,7 +13,7 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
void CheckAttacker(Unit* attacker, ThreatManager* /*threatMgr*/) override
|
||||
void CheckAttacker(Unit* attacker, ThreatManager* threatMgr) override
|
||||
{
|
||||
if (botAI->HasAura(spell, attacker))
|
||||
result = attacker;
|
||||
|
||||
@ -50,7 +50,7 @@ public:
|
||||
result = nullptr;
|
||||
}
|
||||
|
||||
void CheckAttacker(Unit* attacker, ThreatManager* /*threatMgr*/) override
|
||||
void CheckAttacker(Unit* attacker, ThreatManager* threatMgr) override
|
||||
{
|
||||
if (Group* group = botAI->GetBot()->GetGroup())
|
||||
{
|
||||
|
||||
@ -11,6 +11,8 @@ std::vector<Item*> InventoryItemValueBase::Find(std::string const qualifier)
|
||||
{
|
||||
std::vector<Item*> result;
|
||||
|
||||
Player* bot = InventoryAction::botAI->GetBot();
|
||||
|
||||
std::vector<Item*> items = InventoryAction::parseItems(qualifier);
|
||||
for (Item* item : items)
|
||||
result.push_back(item);
|
||||
|
||||
@ -17,7 +17,7 @@ class InventoryItemValueBase : public InventoryAction
|
||||
public:
|
||||
InventoryItemValueBase(PlayerbotAI* botAI) : InventoryAction(botAI, "empty") {}
|
||||
|
||||
bool Execute(Event /*event*/) override { return false; }
|
||||
bool Execute(Event event) override { return false; }
|
||||
|
||||
protected:
|
||||
std::vector<Item*> Find(std::string const qualifier);
|
||||
|
||||
@ -48,6 +48,23 @@ Item* ItemForSpellValue::Calculate()
|
||||
}
|
||||
}
|
||||
|
||||
// Workaround as some spells have no item mask (e.g. shaman weapon enhancements)
|
||||
if (!strcmpi(spellInfo->SpellName[0], "rockbiter weapon") ||
|
||||
!strcmpi(spellInfo->SpellName[0], "flametongue weapon") ||
|
||||
!strcmpi(spellInfo->SpellName[0], "earthliving weapon") ||
|
||||
!strcmpi(spellInfo->SpellName[0], "frostbrand weapon") || !strcmpi(spellInfo->SpellName[0], "windfury weapon"))
|
||||
{
|
||||
itemForSpell = GetItemFitsToSpellRequirements(EQUIPMENT_SLOT_MAINHAND, spellInfo);
|
||||
if (itemForSpell && itemForSpell->GetTemplate()->Class == ITEM_CLASS_WEAPON)
|
||||
return itemForSpell;
|
||||
|
||||
itemForSpell = GetItemFitsToSpellRequirements(EQUIPMENT_SLOT_OFFHAND, spellInfo);
|
||||
if (itemForSpell && itemForSpell->GetTemplate()->Class == ITEM_CLASS_WEAPON)
|
||||
return itemForSpell;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!(spellInfo->Targets & TARGET_FLAG_ITEM))
|
||||
return nullptr;
|
||||
|
||||
|
||||
@ -180,11 +180,19 @@ ItemUsage ItemUsageValue::QueryItemUsageForEquip(ItemTemplate const* itemProto,
|
||||
delete pItem;
|
||||
|
||||
if (result != EQUIP_ERR_OK && result != EQUIP_ERR_CANT_CARRY_MORE_OF_THIS)
|
||||
{
|
||||
return ITEM_USAGE_NONE;
|
||||
|
||||
// Check if unique items are equipped or not
|
||||
bool needToCheckUnique = result == EQUIP_ERR_CANT_CARRY_MORE_OF_THIS ||
|
||||
itemProto->HasFlag(ITEM_FLAG_UNIQUE_EQUIPPABLE);
|
||||
}
|
||||
// Check is unique items are equipped or not
|
||||
bool needToCheckUnique = false;
|
||||
if (result == EQUIP_ERR_CANT_CARRY_MORE_OF_THIS)
|
||||
{
|
||||
needToCheckUnique = true;
|
||||
}
|
||||
else if (itemProto->HasFlag(ITEM_FLAG_UNIQUE_EQUIPPABLE))
|
||||
{
|
||||
needToCheckUnique = true;
|
||||
}
|
||||
|
||||
if (needToCheckUnique)
|
||||
{
|
||||
@ -198,38 +206,34 @@ ItemUsage ItemUsageValue::QueryItemUsageForEquip(ItemTemplate const* itemProto,
|
||||
bool isEquipped = (totalItemCount > bagItemCount);
|
||||
|
||||
if (isEquipped)
|
||||
{
|
||||
return ITEM_USAGE_NONE; // Item is already equipped
|
||||
}
|
||||
// If not equipped, continue processing
|
||||
}
|
||||
|
||||
if (itemProto->Class == ITEM_CLASS_QUIVER && bot->getClass() != CLASS_HUNTER)
|
||||
return ITEM_USAGE_NONE;
|
||||
if (itemProto->Class == ITEM_CLASS_QUIVER)
|
||||
if (bot->getClass() != CLASS_HUNTER)
|
||||
return ITEM_USAGE_NONE;
|
||||
|
||||
if (itemProto->Class == ITEM_CLASS_CONTAINER)
|
||||
{
|
||||
if (itemProto->SubClass != ITEM_SUBCLASS_CONTAINER)
|
||||
return ITEM_USAGE_NONE; // Todo add logic for non-bag containers. We want to look at professions/class and
|
||||
// only replace if non-bag is larger than bag.
|
||||
|
||||
if (GetSmallestBagSize() >= itemProto->ContainerSlots)
|
||||
return ITEM_USAGE_NONE;
|
||||
|
||||
return ITEM_USAGE_EQUIP;
|
||||
}
|
||||
|
||||
if (itemProto->Class == ITEM_CLASS_WEAPON && itemProto->SubClass == ITEM_SUBCLASS_WEAPON_MISC)
|
||||
return ITEM_USAGE_NONE;
|
||||
|
||||
bool shouldEquip = false;
|
||||
// uint32 statWeight = sRandomItemMgr.GetLiveStatWeight(bot, itemProto->ItemId);
|
||||
StatsWeightCalculator calculator(bot);
|
||||
calculator.SetItemSetBonus(false);
|
||||
calculator.SetOverflowPenalty(false);
|
||||
|
||||
// Apply PvP weights if the bot is specced for PvP
|
||||
bool isPvp = sRandomPlayerbotMgr.IsSpecPvp(bot->GetGUID().GetCounter(), bot->getClass());
|
||||
if (isPvp)
|
||||
calculator.SetPvpSpec(true);
|
||||
|
||||
float itemScore = calculator.CalculateItem(itemProto->ItemId, randomPropertyId);
|
||||
|
||||
if (itemScore)
|
||||
@ -245,14 +249,19 @@ ItemUsage ItemUsageValue::QueryItemUsageForEquip(ItemTemplate const* itemProto,
|
||||
uint8 dstSlot = botAI->FindEquipSlot(itemProto, NULL_SLOT, true);
|
||||
// Check if dest wasn't set correctly by CanEquipItem and use FindEquipSlot instead
|
||||
// This occurs with unique items that are already in the bots bags when CanEquipItem is called
|
||||
if (dest == 0 && dstSlot != NULL_SLOT)
|
||||
if (dest == 0)
|
||||
{
|
||||
// Construct dest from dstSlot
|
||||
dest = (INVENTORY_SLOT_BAG_0 << 8) | dstSlot;
|
||||
if (dstSlot != NULL_SLOT)
|
||||
{
|
||||
// Construct dest from dstSlot
|
||||
dest = (INVENTORY_SLOT_BAG_0 << 8) | dstSlot;
|
||||
}
|
||||
}
|
||||
|
||||
if (dstSlot == EQUIPMENT_SLOT_FINGER1 || dstSlot == EQUIPMENT_SLOT_TRINKET1)
|
||||
{
|
||||
possibleSlots = 2;
|
||||
}
|
||||
|
||||
// Check weapon case separately to keep things a bit cleaner
|
||||
bool have2HWeapon = false;
|
||||
@ -269,9 +278,14 @@ ItemUsage ItemUsageValue::QueryItemUsageForEquip(ItemTemplate const* itemProto,
|
||||
itemProto->SubClass == ITEM_SUBCLASS_WEAPON_SWORD2);
|
||||
|
||||
// If the bot can Titan Grip, ignore any 2H weapon that isn't a 2H sword, mace, or axe.
|
||||
// If this weapon is 2H but not one of the valid TG weapon types, do not equip it at all.
|
||||
if (bot->CanTitanGrip() && itemProto->InventoryType == INVTYPE_2HWEAPON && !isValidTGWeapon)
|
||||
return ITEM_USAGE_NONE;
|
||||
if (bot->CanTitanGrip())
|
||||
{
|
||||
// If this weapon is 2H but not one of the valid TG weapon types, do not equip it at all.
|
||||
if (itemProto->InventoryType == INVTYPE_2HWEAPON && !isValidTGWeapon)
|
||||
{
|
||||
return ITEM_USAGE_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
// Now handle the logic for equipping and possible offhand slots
|
||||
// If the bot can Dual Wield and:
|
||||
@ -298,7 +312,9 @@ ItemUsage ItemUsageValue::QueryItemUsageForEquip(ItemTemplate const* itemProto,
|
||||
if (shouldEquipInSlot)
|
||||
return ITEM_USAGE_EQUIP;
|
||||
else
|
||||
{
|
||||
return ITEM_USAGE_BAD_EQUIP;
|
||||
}
|
||||
}
|
||||
|
||||
ItemTemplate const* oldItemProto = oldItem->GetTemplate();
|
||||
@ -307,16 +323,22 @@ ItemUsage ItemUsageValue::QueryItemUsageForEquip(ItemTemplate const* itemProto,
|
||||
{
|
||||
// uint32 oldStatWeight = sRandomItemMgr.GetLiveStatWeight(bot, oldItemProto->ItemId);
|
||||
if (itemScore || oldScore)
|
||||
{
|
||||
shouldEquipInSlot = itemScore > oldScore * sPlayerbotAIConfig.equipUpgradeThreshold;
|
||||
}
|
||||
}
|
||||
|
||||
// Bigger quiver
|
||||
if (itemProto->Class == ITEM_CLASS_QUIVER)
|
||||
{
|
||||
if (!oldItem || oldItemProto->ContainerSlots < itemProto->ContainerSlots)
|
||||
{
|
||||
return ITEM_USAGE_EQUIP;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ITEM_USAGE_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
bool existingShouldEquip = true;
|
||||
@ -842,6 +864,8 @@ bool ItemUsageValue::SpellGivesSkillUp(uint32 spellId, Player* bot)
|
||||
{
|
||||
uint32 SkillValue = bot->GetPureSkillValue(skill->SkillLine);
|
||||
|
||||
uint32 craft_skill_gain = sWorld->getIntConfig(CONFIG_SKILL_GAIN_CRAFTING);
|
||||
|
||||
if (SkillGainChance(SkillValue, skill->TrivialSkillLineRankHigh,
|
||||
(skill->TrivialSkillLineRankHigh + skill->TrivialSkillLineRankLow) / 2,
|
||||
skill->TrivialSkillLineRankLow) > 0)
|
||||
|
||||
@ -13,7 +13,7 @@ class FindLeastHpTargetStrategy : public FindNonCcTargetStrategy
|
||||
public:
|
||||
FindLeastHpTargetStrategy(PlayerbotAI* botAI) : FindNonCcTargetStrategy(botAI), minHealth(0) {}
|
||||
|
||||
void CheckAttacker(Unit* attacker, ThreatManager* /*threatMgr*/) override
|
||||
void CheckAttacker(Unit* attacker, ThreatManager* threatMgr) override
|
||||
{
|
||||
if (IsCcTarget(attacker))
|
||||
return;
|
||||
|
||||
@ -60,7 +60,7 @@ public:
|
||||
class AllLootStrategy : public LootStrategy
|
||||
{
|
||||
public:
|
||||
bool CanLoot(ItemTemplate const* /*proto*/, AiObjectContext* /*context*/) override { return true; }
|
||||
bool CanLoot(ItemTemplate const* proto, AiObjectContext* context) override { return true; }
|
||||
|
||||
std::string const GetName() override { return "all"; }
|
||||
};
|
||||
|
||||
@ -28,4 +28,4 @@ void NearestCorpsesValue::FindUnits(std::list<Unit*>& targets)
|
||||
Cell::VisitObjects(bot, searcher, range);
|
||||
}
|
||||
|
||||
bool NearestCorpsesValue::AcceptUnit(Unit* /*unit*/) { return true; }
|
||||
bool NearestCorpsesValue::AcceptUnit(Unit* unit) { return true; }
|
||||
|
||||
@ -1,64 +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 "PartyMemberSnaredTargetValue.h"
|
||||
|
||||
#include <limits>
|
||||
|
||||
#include "PlayerbotAIAware.h"
|
||||
#include "Playerbots.h"
|
||||
|
||||
class PartyMemberSnaredTargetPredicate : public FindPlayerPredicate, public PlayerbotAIAware
|
||||
{
|
||||
public:
|
||||
PartyMemberSnaredTargetPredicate(PlayerbotAI* botAI)
|
||||
: PlayerbotAIAware(botAI)
|
||||
{
|
||||
}
|
||||
|
||||
bool Check(Unit* unit) override
|
||||
{
|
||||
if (!unit || !unit->IsAlive() || !unit->IsInWorld() || unit == botAI->GetBot())
|
||||
return false;
|
||||
|
||||
if (unit->GetMapId() != botAI->GetBot()->GetMapId())
|
||||
return false;
|
||||
|
||||
if (!botAI->GetBot()->IsWithinLOSInMap(unit))
|
||||
return false;
|
||||
|
||||
return botAI->IsMovementImpaired(unit);
|
||||
}
|
||||
};
|
||||
|
||||
Unit* PartyMemberSnaredTargetValue::Calculate()
|
||||
{
|
||||
Group* group = bot->GetGroup();
|
||||
if (!group)
|
||||
return nullptr;
|
||||
|
||||
PartyMemberSnaredTargetPredicate predicate(botAI);
|
||||
Player* bestTarget = nullptr;
|
||||
float closestDistanceSq = std::numeric_limits<float>::max();
|
||||
|
||||
for (GroupReference* gref = group->GetFirstMember(); gref; gref = gref->next())
|
||||
{
|
||||
Player* member = gref->GetSource();
|
||||
if (!member)
|
||||
continue;
|
||||
|
||||
if (!predicate.Check(member))
|
||||
continue;
|
||||
|
||||
float const distanceSq = bot->GetExactDist2dSq(member->GetPositionX(), member->GetPositionY());
|
||||
if (distanceSq < closestDistanceSq)
|
||||
{
|
||||
closestDistanceSq = distanceSq;
|
||||
bestTarget = member;
|
||||
}
|
||||
}
|
||||
|
||||
return bestTarget;
|
||||
}
|
||||
@ -1,24 +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_PARTYMEMBERSNAREDTARGETVALUE_H
|
||||
#define _PLAYERBOT_PARTYMEMBERSNAREDTARGETVALUE_H
|
||||
|
||||
#include "NamedObjectContext.h"
|
||||
#include "PartyMemberValue.h"
|
||||
|
||||
class PartyMemberSnaredTargetValue : public PartyMemberValue
|
||||
{
|
||||
public:
|
||||
PartyMemberSnaredTargetValue(PlayerbotAI* botAI, std::string const name = "party member snared target")
|
||||
: PartyMemberValue(botAI, name)
|
||||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
Unit* Calculate() override;
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -38,36 +38,6 @@ Unit* PartyMemberToHeal::Calculate()
|
||||
bool isRaid = bot->GetGroup()->isRaidGroup();
|
||||
MinValueCalculator calc(100);
|
||||
|
||||
// If focus heal targets strategy is active, only heal those targets
|
||||
if (botAI->HasStrategy("focus heal targets", BOT_STATE_COMBAT))
|
||||
{
|
||||
std::list<ObjectGuid> const focusHealTargets =
|
||||
AI_VALUE(std::list<ObjectGuid>, "focus heal targets");
|
||||
|
||||
for (ObjectGuid const& focusHealTarget : focusHealTargets)
|
||||
{
|
||||
Player* player = ObjectAccessor::FindPlayer(focusHealTarget);
|
||||
if (!player || !player->IsInWorld() || !player->IsAlive() || !player->IsInSameGroupWith(bot))
|
||||
continue;
|
||||
|
||||
float health = player->GetHealthPct();
|
||||
if (isRaid || health < sPlayerbotAIConfig.mediumHealth ||
|
||||
!IsTargetOfSpellCast(player, predicate))
|
||||
{
|
||||
float probeValue = 100.0f;
|
||||
if (player->GetDistance2d(bot) > sPlayerbotAIConfig.healDistance)
|
||||
probeValue = health + 30.0f;
|
||||
else
|
||||
probeValue = health + player->GetDistance2d(bot) / 10.0f;
|
||||
|
||||
if (probeValue < calc.minValue && Check(player))
|
||||
calc.probe(probeValue, player);
|
||||
}
|
||||
}
|
||||
|
||||
return (Unit*)calc.param;
|
||||
}
|
||||
|
||||
for (GroupReference* gref = group->GetFirstMember(); gref; gref = gref->next())
|
||||
{
|
||||
Player* player = gref->GetSource();
|
||||
@ -75,17 +45,17 @@ Unit* PartyMemberToHeal::Calculate()
|
||||
continue;
|
||||
if (player && player->IsAlive())
|
||||
{
|
||||
float health = player->GetHealthPct();
|
||||
uint8 health = player->GetHealthPct();
|
||||
if (isRaid || health < sPlayerbotAIConfig.mediumHealth || !IsTargetOfSpellCast(player, predicate))
|
||||
{
|
||||
float probeValue = 100.0f;
|
||||
uint32 probeValue = 100;
|
||||
if (player->GetDistance2d(bot) > sPlayerbotAIConfig.healDistance)
|
||||
{
|
||||
probeValue = health + 30.0f;
|
||||
probeValue = health + 30;
|
||||
}
|
||||
else
|
||||
{
|
||||
probeValue = health + player->GetDistance2d(bot) / 10.0f;
|
||||
probeValue = health + player->GetDistance2d(bot) / 10;
|
||||
}
|
||||
// delay Check player to here for better performance
|
||||
if (probeValue < calc.minValue && Check(player))
|
||||
@ -98,10 +68,10 @@ Unit* PartyMemberToHeal::Calculate()
|
||||
Pet* pet = player->GetPet();
|
||||
if (pet && pet->IsAlive())
|
||||
{
|
||||
float health = ((Unit*)pet)->GetHealthPct();
|
||||
float probeValue = 100.0f;
|
||||
uint8 health = ((Unit*)pet)->GetHealthPct();
|
||||
uint32 probeValue = 100;
|
||||
if (isRaid || health < sPlayerbotAIConfig.mediumHealth)
|
||||
probeValue = health + 30.0f;
|
||||
probeValue = health + 30;
|
||||
// delay Check pet to here for better performance
|
||||
if (probeValue < calc.minValue && Check(pet))
|
||||
{
|
||||
@ -112,10 +82,10 @@ Unit* PartyMemberToHeal::Calculate()
|
||||
Unit* charm = player->GetCharm();
|
||||
if (charm && charm->IsAlive())
|
||||
{
|
||||
float health = charm->GetHealthPct();
|
||||
float probeValue = 100.0f;
|
||||
uint8 health = charm->GetHealthPct();
|
||||
uint32 probeValue = 100;
|
||||
if (isRaid || health < sPlayerbotAIConfig.mediumHealth)
|
||||
probeValue = health + 30.0f;
|
||||
probeValue = health + 30;
|
||||
// delay Check charm to here for better performance
|
||||
if (probeValue < calc.minValue && Check(charm))
|
||||
{
|
||||
|
||||
@ -27,7 +27,7 @@ Unit* PartyMemberValue::FindPartyMember(std::vector<Player*>* party, FindPlayerP
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Unit* PartyMemberValue::FindPartyMember(FindPlayerPredicate& predicate, bool /*ignoreOutOfGroup*/)
|
||||
Unit* PartyMemberValue::FindPartyMember(FindPlayerPredicate& predicate, bool ignoreOutOfGroup)
|
||||
{
|
||||
Player* master = GetMaster();
|
||||
// GuidVector nearestPlayers;
|
||||
|
||||
@ -13,7 +13,6 @@
|
||||
#include "ServerFacade.h"
|
||||
#include "SharedDefines.h"
|
||||
#include "NearestGameObjects.h"
|
||||
#include <unordered_set>
|
||||
|
||||
std::vector<uint32> PossibleRpgTargetsValue::allowedNpcFlags;
|
||||
|
||||
@ -89,11 +88,8 @@ bool PossibleRpgTargetsValue::AcceptUnit(Unit* unit)
|
||||
|
||||
std::vector<uint32> PossibleNewRpgTargetsValue::allowedNpcFlags;
|
||||
|
||||
// Sparse starting zones where the default scan range is insufficient for WANDER_NPC (requires >= 3 NPCs)
|
||||
static const std::unordered_set<uint32> rpgRangeOverrideAreaIds = { 3526 /* Ammen Vale */, 2117 /* Deathknell */ };
|
||||
|
||||
PossibleNewRpgTargetsValue::PossibleNewRpgTargetsValue(PlayerbotAI* botAI, float range)
|
||||
: NearestUnitsValue(botAI, "possible new rpg targets", range, true), defaultRange(range)
|
||||
: NearestUnitsValue(botAI, "possible new rpg targets", range, true)
|
||||
{
|
||||
if (allowedNpcFlags.empty())
|
||||
{
|
||||
@ -123,11 +119,6 @@ PossibleNewRpgTargetsValue::PossibleNewRpgTargetsValue(PlayerbotAI* botAI, float
|
||||
|
||||
GuidVector PossibleNewRpgTargetsValue::Calculate()
|
||||
{
|
||||
if (rpgRangeOverrideAreaIds.count(bot->GetAreaId()) && defaultRange < 200.0f)
|
||||
range = 200.0f;
|
||||
else
|
||||
range = defaultRange;
|
||||
|
||||
std::list<Unit*> targets;
|
||||
FindUnits(targets);
|
||||
|
||||
|
||||
@ -35,8 +35,6 @@ public:
|
||||
protected:
|
||||
void FindUnits(std::list<Unit*>& targets) override;
|
||||
bool AcceptUnit(Unit* unit) override;
|
||||
private:
|
||||
float defaultRange;
|
||||
};
|
||||
|
||||
class PossibleNewRpgGameObjectsValue : public ObjectGuidListCalculatedValue
|
||||
|
||||
@ -40,13 +40,13 @@ bool SpellCastUsefulValue::Calculate()
|
||||
return false;
|
||||
}
|
||||
|
||||
if (qualifier == "windfury weapon" || qualifier == "flametongue weapon" ||
|
||||
qualifier == "frostbrand weapon" || qualifier == "rockbiter weapon" ||
|
||||
qualifier == "earthliving weapon" || qualifier == "spellstone")
|
||||
// TODO: workaround
|
||||
if (qualifier == "windfury weapon" || qualifier == "flametongue weapon" || qualifier == "frostbrand weapon" ||
|
||||
qualifier == "rockbiter weapon" || qualifier == "earthliving weapon" || qualifier == "spellstone")
|
||||
{
|
||||
if (Item* item = AI_VALUE2(Item*, "item for spell", spellid);
|
||||
item && item->IsInWorld() && item->GetEnchantmentId(TEMP_ENCHANTMENT_SLOT))
|
||||
return false;
|
||||
if (Item* item = AI_VALUE2(Item*, "item for spell", spellid))
|
||||
if (item->IsInWorld() && item->GetEnchantmentId(TEMP_ENCHANTMENT_SLOT))
|
||||
return false;
|
||||
}
|
||||
|
||||
std::set<uint32>& skipSpells = AI_VALUE(std::set<uint32>&, "skip spells list");
|
||||
|
||||
@ -49,7 +49,7 @@ class FindTankTargetSmartStrategy : public FindTargetStrategy
|
||||
public:
|
||||
FindTankTargetSmartStrategy(PlayerbotAI* botAI) : FindTargetStrategy(botAI) {}
|
||||
|
||||
void CheckAttacker(Unit* attacker, ThreatManager* /*threatMgr*/) override
|
||||
void CheckAttacker(Unit* attacker, ThreatManager* threatMgr) override
|
||||
{
|
||||
if (Group* group = botAI->GetBot()->GetGroup())
|
||||
{
|
||||
|
||||
@ -161,7 +161,7 @@ Unit* FindTargetValue::Calculate()
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void FindBossTargetStrategy::CheckAttacker(Unit* attacker, ThreatManager* /*threatManager*/)
|
||||
void FindBossTargetStrategy::CheckAttacker(Unit* attacker, ThreatManager* threatManager)
|
||||
{
|
||||
UnitAI* unitAI = attacker->GetAI();
|
||||
BossAI* bossAI = dynamic_cast<BossAI*>(unitAI);
|
||||
|
||||
@ -116,15 +116,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class PullStrategyTargetValue : public ManualSetValue<ObjectGuid>
|
||||
{
|
||||
public:
|
||||
PullStrategyTargetValue(PlayerbotAI* botAI, std::string const name = "pull strategy target")
|
||||
: ManualSetValue<ObjectGuid>(botAI, ObjectGuid::Empty, name)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class FindTargetValue : public UnitCalculatedValue, public Qualified
|
||||
{
|
||||
public:
|
||||
@ -149,11 +140,4 @@ public:
|
||||
public:
|
||||
Unit* Calculate();
|
||||
};
|
||||
|
||||
class FocusHealTargetValue : public ManualSetValue<std::list<ObjectGuid>>
|
||||
{
|
||||
public:
|
||||
FocusHealTargetValue(PlayerbotAI* botAI) : ManualSetValue<std::list<ObjectGuid>>(botAI, {}, "focus heal targets") {}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@ -66,7 +66,6 @@
|
||||
#include "PartyMemberToDispel.h"
|
||||
#include "PartyMemberToHeal.h"
|
||||
#include "PartyMemberToResurrect.h"
|
||||
#include "PartyMemberSnaredTargetValue.h"
|
||||
#include "PartyMemberWithoutAuraValue.h"
|
||||
#include "PartyMemberWithoutItemValue.h"
|
||||
#include "PetTargetValue.h"
|
||||
@ -153,7 +152,6 @@ public:
|
||||
creators["duel target"] = &ValueContext::duel_target;
|
||||
creators["party member to dispel"] = &ValueContext::party_member_to_dispel;
|
||||
creators["party member to protect"] = &ValueContext::party_member_to_protect;
|
||||
creators["party member snared target"] = &ValueContext::party_member_snared_target;
|
||||
creators["health"] = &ValueContext::health;
|
||||
creators["rage"] = &ValueContext::rage;
|
||||
creators["energy"] = &ValueContext::energy;
|
||||
@ -241,8 +239,6 @@ public:
|
||||
creators["travel target"] = &ValueContext::travel_target;
|
||||
creators["talk target"] = &ValueContext::talk_target;
|
||||
creators["pull target"] = &ValueContext::pull_target;
|
||||
creators["pull strategy target"] = &ValueContext::pull_strategy_target;
|
||||
creators["focus heal targets"] = &ValueContext::focus_heal_targets;
|
||||
creators["group"] = &ValueContext::group;
|
||||
creators["range"] = &ValueContext::range;
|
||||
creators["inside target"] = &ValueContext::inside_target;
|
||||
@ -454,7 +450,6 @@ private:
|
||||
static UntypedValue* party_member_to_resurrect(PlayerbotAI* botAI) { return new PartyMemberToResurrect(botAI); }
|
||||
static UntypedValue* party_member_to_dispel(PlayerbotAI* botAI) { return new PartyMemberToDispel(botAI); }
|
||||
static UntypedValue* party_member_to_protect(PlayerbotAI* botAI) { return new PartyMemberToProtect(botAI); }
|
||||
static UntypedValue* party_member_snared_target(PlayerbotAI* botAI) { return new PartyMemberSnaredTargetValue(botAI); }
|
||||
static UntypedValue* current_target(PlayerbotAI* botAI) { return new CurrentTargetValue(botAI); }
|
||||
static UntypedValue* old_target(PlayerbotAI* botAI) { return new CurrentTargetValue(botAI); }
|
||||
static UntypedValue* self_target(PlayerbotAI* botAI) { return new SelfTargetValue(botAI); }
|
||||
@ -499,8 +494,6 @@ private:
|
||||
static UntypedValue* next_rpg_action(PlayerbotAI* botAI) { return new NextRpgActionValue(botAI); }
|
||||
static UntypedValue* travel_target(PlayerbotAI* botAI) { return new TravelTargetValue(botAI); }
|
||||
static UntypedValue* pull_target(PlayerbotAI* botAI) { return new PullTargetValue(botAI); }
|
||||
static UntypedValue* pull_strategy_target(PlayerbotAI* botAI) { return new PullStrategyTargetValue(botAI); }
|
||||
static UntypedValue* focus_heal_targets(PlayerbotAI* botAI) { return new FocusHealTargetValue(botAI); }
|
||||
|
||||
static UntypedValue* bg_master(PlayerbotAI* botAI) { return new BgMasterValue(botAI); }
|
||||
static UntypedValue* bg_role(PlayerbotAI* botAI) { return new BgRoleValue(botAI); }
|
||||
|
||||
@ -48,55 +48,3 @@ bool CastRaiseDeadAction::Execute(Event event)
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Unit* CastHysteriaAction::GetTarget()
|
||||
{
|
||||
Group* group = bot->GetGroup();
|
||||
if (!group)
|
||||
{
|
||||
if (!bot->HasAura(49016))
|
||||
return bot;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Unit* rangedDps = nullptr;
|
||||
Unit* tank = nullptr;
|
||||
|
||||
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
||||
{
|
||||
Player* member = ref->GetSource();
|
||||
if (!member || !member->IsAlive())
|
||||
continue;
|
||||
|
||||
if (member->GetMap() != bot->GetMap() || bot->GetDistance(member) > sPlayerbotAIConfig.spellDistance)
|
||||
continue;
|
||||
|
||||
// Skip if already has hysteria
|
||||
if (member->HasAura(49016))
|
||||
continue;
|
||||
|
||||
// Priority 1: Melee DPS
|
||||
if (botAI->IsMelee(member) && botAI->IsDps(member))
|
||||
return member;
|
||||
|
||||
// Priority 2: Ranged DPS (physical, not casters)
|
||||
if (!rangedDps && botAI->IsRanged(member) && botAI->IsDps(member) && !botAI->IsCaster(member))
|
||||
rangedDps = member;
|
||||
|
||||
// Priority 3: Tank
|
||||
if (!tank && botAI->IsTank(member))
|
||||
tank = member;
|
||||
}
|
||||
|
||||
if (rangedDps)
|
||||
return rangedDps;
|
||||
|
||||
if (tank)
|
||||
return tank;
|
||||
|
||||
// Fallback to self if no hysteria
|
||||
if (!bot->HasAura(49016))
|
||||
return bot;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -340,11 +340,4 @@ public:
|
||||
CastBloodTapAction(PlayerbotAI* botAI) : CastMeleeSpellAction(botAI, "blood tap") {}
|
||||
};
|
||||
|
||||
class CastHysteriaAction : public CastSpellAction
|
||||
{
|
||||
public:
|
||||
CastHysteriaAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "hysteria") {}
|
||||
Unit* GetTarget() override;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@ -8,11 +8,11 @@
|
||||
#include "BloodDKStrategy.h"
|
||||
#include "DKActions.h"
|
||||
#include "DKTriggers.h"
|
||||
#include "DeathKnightPullStrategy.h"
|
||||
#include "FrostDKStrategy.h"
|
||||
#include "GenericDKNonCombatStrategy.h"
|
||||
#include "GenericTriggers.h"
|
||||
#include "Playerbots.h"
|
||||
#include "PullStrategy.h"
|
||||
#include "UnholyDKStrategy.h"
|
||||
|
||||
class DeathKnightStrategyFactoryInternal : public NamedObjectContext<Strategy>
|
||||
@ -28,7 +28,7 @@ public:
|
||||
|
||||
private:
|
||||
static Strategy* nc(PlayerbotAI* botAI) { return new GenericDKNonCombatStrategy(botAI); }
|
||||
static Strategy* pull(PlayerbotAI* botAI) { return new DeathKnightPullStrategy(botAI); }
|
||||
static Strategy* pull(PlayerbotAI* botAI) { return new PullStrategy(botAI, "icy touch"); }
|
||||
static Strategy* frost_aoe(PlayerbotAI* botAI) { return new FrostDKAoeStrategy(botAI); }
|
||||
static Strategy* unholy_aoe(PlayerbotAI* botAI) { return new UnholyDKAoeStrategy(botAI); }
|
||||
};
|
||||
@ -100,7 +100,6 @@ public:
|
||||
creators["dd cd and no desolation"] = &DeathKnightTriggerFactoryInternal::dd_cd_and_no_desolation;
|
||||
creators["death and decay cooldown"] = &DeathKnightTriggerFactoryInternal::death_and_decay_cooldown;
|
||||
creators["army of the dead"] = &DeathKnightTriggerFactoryInternal::army_of_the_dead;
|
||||
creators["hysteria no cd"] = &DeathKnightTriggerFactoryInternal::hysteria_no_cd;
|
||||
}
|
||||
|
||||
private:
|
||||
@ -153,7 +152,6 @@ private:
|
||||
}
|
||||
static Trigger* death_and_decay_cooldown(PlayerbotAI* botAI) { return new DeathAndDecayCooldownTrigger(botAI); }
|
||||
static Trigger* army_of_the_dead(PlayerbotAI* botAI) { return new ArmyOfTheDeadTrigger(botAI); }
|
||||
static Trigger* hysteria_no_cd(PlayerbotAI* botAI) { return new HysteriaNoCooldownTrigger(botAI); }
|
||||
};
|
||||
|
||||
class DeathKnightAiObjectContextInternal : public NamedObjectContext<Action>
|
||||
@ -211,7 +209,7 @@ public:
|
||||
creators["vampiric blood"] = &DeathKnightAiObjectContextInternal::vampiric_blood;
|
||||
creators["death pact"] = &DeathKnightAiObjectContextInternal::death_pact;
|
||||
creators["death rune_mastery"] = &DeathKnightAiObjectContextInternal::death_rune_mastery;
|
||||
creators["hysteria"] = &DeathKnightAiObjectContextInternal::hysteria;
|
||||
// creators["hysteria"] = &DeathKnightAiObjectContextInternal::hysteria;
|
||||
creators["dancing rune weapon"] = &DeathKnightAiObjectContextInternal::dancing_rune_weapon;
|
||||
creators["dark command"] = &DeathKnightAiObjectContextInternal::dark_command;
|
||||
}
|
||||
@ -267,7 +265,7 @@ private:
|
||||
static Action* vampiric_blood(PlayerbotAI* botAI) { return new CastVampiricBloodAction(botAI); }
|
||||
static Action* death_pact(PlayerbotAI* botAI) { return new CastDeathPactAction(botAI); }
|
||||
static Action* death_rune_mastery(PlayerbotAI* botAI) { return new CastDeathRuneMasteryAction(botAI); }
|
||||
static Action* hysteria(PlayerbotAI* botAI) { return new CastHysteriaAction(botAI); }
|
||||
// static Action* hysteria(PlayerbotAI* botAI) { return new CastHysteriaAction(botAI); }
|
||||
static Action* dancing_rune_weapon(PlayerbotAI* botAI) { return new CastDancingRuneWeaponAction(botAI); }
|
||||
static Action* dark_command(PlayerbotAI* botAI) { return new CastDarkCommandAction(botAI); }
|
||||
static Action* mind_freeze_on_enemy_healer(PlayerbotAI* botAI)
|
||||
|
||||
@ -50,9 +50,7 @@ private:
|
||||
{
|
||||
NextAction("frost presence")
|
||||
},
|
||||
/*A*/ {
|
||||
NextAction("blood strike")
|
||||
},
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
@ -91,11 +89,13 @@ BloodDKStrategy::BloodDKStrategy(PlayerbotAI* botAI) : GenericDKStrategy(botAI)
|
||||
std::vector<NextAction> BloodDKStrategy::getDefaultActions()
|
||||
{
|
||||
return {
|
||||
NextAction("rune strike", ACTION_DEFAULT + 0.6f),
|
||||
NextAction("icy touch", ACTION_DEFAULT + 0.5f),
|
||||
NextAction("heart strike", ACTION_DEFAULT + 0.4f),
|
||||
NextAction("dancing rune weapon", ACTION_DEFAULT + 0.3f),
|
||||
NextAction("death coil", ACTION_DEFAULT + 0.2f),
|
||||
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)
|
||||
};
|
||||
@ -105,14 +105,6 @@ void BloodDKStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
GenericDKStrategy::InitTriggers(triggers);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"hysteria no cd",
|
||||
{
|
||||
NextAction("hysteria", ACTION_NORMAL + 4)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"rune strike",
|
||||
@ -170,12 +162,4 @@ void BloodDKStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"high unholy rune",
|
||||
{
|
||||
NextAction("death strike", ACTION_HIGH + 1)
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@ -1,43 +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 "DeathKnightPullStrategy.h"
|
||||
|
||||
#include "AiObjectContext.h"
|
||||
#include "Player.h"
|
||||
#include "PlayerbotAI.h"
|
||||
#include "Playerbots.h"
|
||||
|
||||
std::string DeathKnightPullStrategy::GetPullActionName() const
|
||||
{
|
||||
Player* bot = botAI->GetBot();
|
||||
Unit* target = GetTarget();
|
||||
if (!bot || !target ||
|
||||
(!botAI->HasStrategy("blood", BOT_STATE_COMBAT) && !botAI->HasStrategy("blood", BOT_STATE_NON_COMBAT)))
|
||||
{
|
||||
return PullStrategy::GetPullActionName();
|
||||
}
|
||||
|
||||
uint32 const deathGripSpellId = botAI->GetAiObjectContext()->GetValue<uint32>("spell id", "death grip")->Get();
|
||||
if (deathGripSpellId && bot->HasSpell(deathGripSpellId) &&
|
||||
botAI->CanCastSpell(deathGripSpellId, target))
|
||||
{
|
||||
return "death grip";
|
||||
}
|
||||
|
||||
uint32 const icyTouchSpellId = botAI->GetAiObjectContext()->GetValue<uint32>("spell id", "icy touch")->Get();
|
||||
if (!icyTouchSpellId || !bot->HasSpell(icyTouchSpellId) ||
|
||||
!botAI->CanCastSpell(icyTouchSpellId, target))
|
||||
{
|
||||
uint32 const darkCommandSpellId = botAI->GetAiObjectContext()->GetValue<uint32>("spell id", "dark command")->Get();
|
||||
if (darkCommandSpellId && bot->HasSpell(darkCommandSpellId) &&
|
||||
botAI->CanCastSpell(darkCommandSpellId, target))
|
||||
{
|
||||
return "dark command";
|
||||
}
|
||||
}
|
||||
|
||||
return PullStrategy::GetPullActionName();
|
||||
}
|
||||
@ -1,19 +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_DEATH_KNIGHT_PULL_STRATEGY_H
|
||||
#define _PLAYERBOT_DEATH_KNIGHT_PULL_STRATEGY_H
|
||||
|
||||
#include "PullStrategy.h"
|
||||
|
||||
class DeathKnightPullStrategy : public PullStrategy
|
||||
{
|
||||
public:
|
||||
DeathKnightPullStrategy(PlayerbotAI* botAI) : PullStrategy(botAI, "icy touch") {}
|
||||
|
||||
std::string GetPullActionName() const override;
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -91,6 +91,7 @@ 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)
|
||||
};
|
||||
|
||||
@ -41,13 +41,19 @@ void GenericDKNonCombatStrategy::InitTriggers(std::vector<TriggerNode*>& trigger
|
||||
{
|
||||
NonCombatStrategy::InitTriggers(triggers);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode("no pet", { NextAction("raise dead", ACTION_NORMAL + 1) }));
|
||||
triggers.push_back(
|
||||
new TriggerNode("horn of winter", { NextAction("horn of winter", 21.0f) }));
|
||||
triggers.push_back(
|
||||
new TriggerNode("bone shield", { NextAction("bone shield", 21.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) }));
|
||||
}
|
||||
|
||||
void DKBuffDpsStrategy::InitTriggers(std::vector<TriggerNode*>& /*triggers*/)
|
||||
void DKBuffDpsStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@ -165,6 +165,12 @@ void GenericDKStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
MeleeCombatStrategy::InitTriggers(triggers);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode("no pet", { NextAction("raise dead", ACTION_NORMAL + 5) }));
|
||||
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("mind freeze", { NextAction("mind freeze", ACTION_HIGH + 1) }));
|
||||
triggers.push_back(
|
||||
@ -173,8 +179,7 @@ void GenericDKStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
triggers.push_back(new TriggerNode(
|
||||
"horn of winter", { NextAction("horn of winter", ACTION_NORMAL + 1) }));
|
||||
triggers.push_back(new TriggerNode("critical health",
|
||||
{ NextAction("raise dead", ACTION_HIGH + 6),
|
||||
NextAction("death pact", ACTION_HIGH + 5) }));
|
||||
{ NextAction("death pact", ACTION_HIGH + 5) }));
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode("low health", { NextAction("icebound fortitude", ACTION_HIGH + 5),
|
||||
@ -185,11 +190,4 @@ void GenericDKStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
NextAction("blood boil", ACTION_NORMAL + 3) }));
|
||||
triggers.push_back(
|
||||
new TriggerNode("pestilence glyph", { NextAction("pestilence", ACTION_HIGH + 9) }));
|
||||
triggers.push_back(
|
||||
new TriggerNode("no rune",
|
||||
{
|
||||
NextAction("empower rune weapon", ACTION_HIGH + 1)
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@ -87,13 +87,6 @@ void UnholyDKStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
GenericDKStrategy::InitTriggers(triggers);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode("no pet", { NextAction("raise dead", ACTION_NORMAL + 5) }));
|
||||
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(
|
||||
"death and decay cooldown",
|
||||
@ -153,6 +146,13 @@ void UnholyDKStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode("no rune",
|
||||
{
|
||||
NextAction("empower rune weapon", ACTION_HIGH + 1)
|
||||
}
|
||||
)
|
||||
);
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"army of the dead",
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user