Merge remote-tracking branch 'origin/test-staging' into TravelSystem-pr

This commit is contained in:
Keleborn 2026-04-27 20:31:17 -07:00
commit bd14756b20
149 changed files with 3206 additions and 521 deletions

View File

@ -651,9 +651,14 @@ 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
@ -801,6 +806,27 @@ 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
@ -1325,7 +1351,7 @@ AiPlayerbot.DeleteRandomBotArenaTeams = 0
AiPlayerbot.PvpProhibitedZoneIds = "2255,656,2361,2362,2363,976,35,2268,3425,392,541,1446,3828,3712,3738,3565,3539,3623,4152,3988,4658,4284,4418,4436,4275,4323,4395,3703,4298,3951"
# PvP Restricted Areas (bots don't pvp)
AiPlayerbot.PvpProhibitedAreaIds = "976,35,392,2268,4161,4010,4317,4312,3649,3887,3958,3724,4080,3938,3754,3786,3973"
AiPlayerbot.PvpProhibitedAreaIds = "976,35,392,2268,4161,4010,4317,4312,3649,3887,3958,3724,4080,3938,3754,3786,3973,4085,4086,4087,4088"
# Improve reaction speeds in battlegrounds and arenas (may cause lag)
AiPlayerbot.FastReactInBG = 1
@ -1803,10 +1829,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 list of level 80 buffs for each implemented pve spec from the "Premade Specs" section
# 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 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
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
#
#
@ -1837,12 +1863,24 @@ 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
#
#
@ -1854,12 +1892,24 @@ AiPlayerbot.RandomClassSpecIndex.1.2 = 2
#
#
# 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
#
#
@ -1871,12 +1921,24 @@ AiPlayerbot.RandomClassSpecIndex.2.2 = 2
#
#
# 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
#
#
@ -1888,12 +1950,24 @@ AiPlayerbot.RandomClassSpecIndex.3.2 = 2
#
#
# 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
#
#
@ -1905,12 +1979,24 @@ AiPlayerbot.RandomClassSpecIndex.4.2 = 2
#
#
# 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
#
#
@ -1922,12 +2008,27 @@ AiPlayerbot.RandomClassSpecIndex.5.2 = 2
#
#
# 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
#
#
@ -1939,12 +2040,24 @@ AiPlayerbot.RandomClassSpecIndex.6.2 = 2
#
#
# 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
#
#
@ -1956,12 +2069,27 @@ AiPlayerbot.RandomClassSpecIndex.7.2 = 2
#
#
# 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
#
#
@ -1973,12 +2101,24 @@ AiPlayerbot.RandomClassSpecIndex.8.2 = 2
#
#
# 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
#
#
@ -1990,14 +2130,27 @@ AiPlayerbot.RandomClassSpecIndex.9.2 = 2
#
#
# 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
#
#

View File

@ -0,0 +1,102 @@
-- #########################################################
-- 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);

View File

@ -45,6 +45,7 @@
#include "NonCombatActions.h"
#include "OutfitAction.h"
#include "PositionAction.h"
#include "PullActions.h"
#include "DropQuestAction.h"
#include "RandomBotUpdateAction.h"
#include "ReachTargetActions.h"
@ -105,6 +106,13 @@ 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;
@ -313,6 +321,13 @@ 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); }

View File

@ -53,22 +53,6 @@ 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)
@ -85,6 +69,15 @@ 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) &&
@ -121,6 +114,18 @@ 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)
@ -147,7 +152,6 @@ bool AttackAction::Attack(Unit* target, bool /*with_pet*/ /*true*/)
bot->SetSelection(target->GetGUID());
context->GetValue<Unit*>("old target")->Set(oldTarget);
context->GetValue<Unit*>("current target")->Set(target);
context->GetValue<LootObjectStack*>("available loot")->Get()->Add(guid);

View File

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

View File

@ -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 == "?")
{

View File

@ -534,21 +534,18 @@ bool BGJoinAction::JoinQueue(uint32 type)
botAI->GetAiObjectContext()->GetValue<uint32>("bg type")->Set(0);
WorldPacket* packet = nullptr;
if (!isArena)
{
WorldPacket* packet = new WorldPacket(CMSG_BATTLEMASTER_JOIN, 20);
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
{
WorldPacket arena_packet(CMSG_BATTLEMASTER_JOIN_ARENA, 20);
arena_packet << unit->GetGUID() << arenaslot << asGroup << uint8(isRated);
bot->GetSession()->HandleBattlemasterJoinArena(arena_packet);
packet = new WorldPacket(CMSG_BATTLEMASTER_JOIN_ARENA, 20);
*packet << unit->GetGUID() << arenaslot << asGroup << uint8(isRated);
}
bot->GetSession()->QueuePacket(packet);
return true;
}

View File

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

View File

@ -80,7 +80,7 @@ bool FollowChatShortcutAction::Execute(Event /*event*/)
true, priority);
}
if (Pet* pet = bot->GetPet())
if (bot->GetPet())
botAI->PetFollow();
if (moved)

View File

@ -116,6 +116,7 @@ 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.
}

View File

@ -62,31 +62,16 @@ 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)
{
@ -101,34 +86,24 @@ 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++;
@ -137,8 +112,6 @@ 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);
@ -147,19 +120,15 @@ 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.");
}
}
}
return true;
}
@ -174,7 +143,6 @@ void CleanQuestLogAction::DropQuestType(uint8& numQuest, uint8 wantNum, bool isG
{
std::random_device rd;
std::mt19937 g(rd());
std::shuffle(slots.begin(), slots.end(), g);
}
@ -200,9 +168,11 @@ 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
{
if (isGreen)

View File

@ -93,8 +93,8 @@ bool FollowAction::Execute(Event /*event*/)
? MovementPriority::MOVEMENT_COMBAT
: MovementPriority::MOVEMENT_NORMAL;
bool const movingAllowed = IsMovingAllowed(mapId, destX, destY, destZ);
bool const dupMove = IsDuplicateMove(mapId, destX, destY, destZ);
bool const movingAllowed = IsMovingAllowed();
bool const dupMove = IsDuplicateMove(destX, destY, destZ);
bool const waiting = IsWaitingForLastMove(priority);
if (movingAllowed && !dupMove && !waiting)

View File

@ -273,7 +273,7 @@ bool BuffOnPartyAction::Execute(Event /*event*/)
}
// End greater buff fix
CastShootAction::CastShootAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "shoot")
CastShootAction::CastShootAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "shoot"), shootSpellId(0)
{
if (Item* const pItem = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_RANGED))
{
@ -283,17 +283,40 @@ 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);

View File

@ -253,7 +253,12 @@ 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

View File

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

View File

@ -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 (ItemTemplate const* proto = sObjectMgr->GetItemTemplate(i->item_template))
if (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;

View File

@ -67,10 +67,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(mapId, x, y, z))
if (!IsMovingAllowed())
return false;
if (IsDuplicateMove(mapId, x, y, z))
if (IsDuplicateMove(x, y, z))
return false;
if (IsWaitingForLastMove(priority))
@ -173,11 +173,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(mapId, x, y, z))
if (!IsMovingAllowed())
{
return false;
}
if (IsDuplicateMove(mapId, x, y, z))
if (IsDuplicateMove(x, y, z))
{
return false;
}
@ -899,20 +899,7 @@ bool MovementAction::IsMovingAllowed(WorldObject* target)
return IsMovingAllowed();
}
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)
bool MovementAction::IsDuplicateMove(float x, float y, float z)
{
LastMovement& lastMove = *context->GetValue<LastMovement&>("last movement");
@ -1288,7 +1275,7 @@ bool MovementAction::Follow(Unit* target, float distance, float angle)
return true;
}
bool MovementAction::ChaseTo(WorldObject* obj, float distance, float angle)
bool MovementAction::ChaseTo(WorldObject* obj, float distance)
{
if (!IsMovingAllowed())
{
@ -1874,7 +1861,7 @@ bool FleeAction::isUseful()
bool FleeWithPetAction::Execute(Event /*event*/)
{
if (Pet* pet = bot->GetPet())
if (bot->GetPet())
botAI->PetFollow();
return Flee(AI_VALUE(Unit*, "current target"));

View File

@ -57,14 +57,13 @@ 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, float angle = 0.0f);
bool ChaseTo(WorldObject* obj, float distance = 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 IsMovingAllowed(uint32 mapId, float x, float y, float z);
bool IsDuplicateMove(uint32 mapId, float x, float y, float z);
bool IsDuplicateMove(float x, float y, float z);
bool IsWaitingForLastMove(MovementPriority priority);
bool IsMovingAllowed();
bool Flee(Unit* target);

View File

@ -0,0 +1,321 @@
/*
* 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();
}

View File

@ -0,0 +1,90 @@
/*
* 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

View File

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

View File

@ -65,7 +65,7 @@ void ReleaseSpiritAction::IncrementDeathCount() const
}
}
void ReleaseSpiritAction::LogRelease(const std::string& releaseMsg, bool isAutoRelease) const
void ReleaseSpiritAction::LogRelease(const std::string& releaseMsg) 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", true);
LogRelease("auto released");
WorldPacket packet(CMSG_REPOP_REQUEST);
packet << uint8(0);
bot->GetSession()->HandleRepopRequestOpcode(packet);
LogRelease("releases spirit", true);
LogRelease("releases spirit");
if (bot->InBattleground())
{

View File

@ -18,7 +18,7 @@ public:
: Action(botAI, name) {}
bool Execute(Event event) override;
void LogRelease(const std::string& releaseType, bool isAutoRelease = false) const;
void LogRelease(const std::string& releaseType) const;
protected:
void IncrementDeathCount() const;

View File

@ -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};
races = {RACE_HUMAN, RACE_DWARF, RACE_GNOME, RACE_NIGHTELF, RACE_DRAENEI};
else
races = {RACE_ORC, RACE_TROLL, RACE_TAUREN, RACE_UNDEAD_PLAYER};
races = {RACE_ORC, RACE_TROLL, RACE_TAUREN, RACE_UNDEAD_PLAYER, RACE_BLOODELF};
float graveDistance = -1;

View File

@ -154,7 +154,7 @@ bool SayAction::isUseful()
return (time(nullptr) - lastSaid) > 30;
}
void ChatReplyAction::ChatReplyDo(Player* bot, uint32& type, uint32& guid1, uint32& guid2, std::string& msg, std::string& chanName, std::string& name)
void ChatReplyAction::ChatReplyDo(Player* bot, uint32& type, uint32& guid1, 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, uint
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, msg, name);
HandleToxicLinksReply(bot, chatChannelSource);
return;
}
//thunderfury
if (GET_PLAYERBOT_AI(bot)->GetChatHelper()->ExtractAllItemIds(msg).count(19019))
{
HandleThunderfuryReply(bot, chatChannelSource, msg, name);
HandleThunderfuryReply(bot, chatChannelSource);
return;
}
@ -220,7 +220,7 @@ void ChatReplyAction::ChatReplyDo(Player* bot, uint32& type, uint32& guid1, uint
SendGeneralResponse(bot, chatChannelSource, messageRepy, name);
}
bool ChatReplyAction::HandleThunderfuryReply(Player* bot, ChatChannelSource chatChannelSource, std::string& msg, std::string& name)
bool ChatReplyAction::HandleThunderfuryReply(Player* bot, ChatChannelSource chatChannelSource)
{
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, std::string& msg, std::string& name)
bool ChatReplyAction::HandleToxicLinksReply(Player* bot, ChatChannelSource chatChannelSource)
{
//quests
std::vector<uint32> incompleteQuests;

View File

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

View File

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

View File

@ -61,7 +61,7 @@ bool SummonAction::Execute(Event /*event*/)
if (!master)
return false;
if (Pet* pet = bot->GetPet())
if (bot->GetPet())
botAI->PetFollow();
if (master->GetSession()->GetSecurity() >= SEC_PLAYER)

View File

@ -43,6 +43,7 @@
#include "NewRpgAction.h"
#include "PassLeadershipToMasterAction.h"
#include "PositionAction.h"
#include "PullActions.h"
#include "QueryItemUsageAction.h"
#include "QueryQuestAction.h"
#include "RangeAction.h"
@ -138,6 +139,8 @@ 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;
@ -250,6 +253,8 @@ 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); }

View File

@ -66,6 +66,9 @@ 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;
@ -209,6 +212,9 @@ 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"); }

View File

@ -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,6 +81,12 @@ 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(

View File

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

View File

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

View File

@ -12,6 +12,6 @@ std::vector<NextAction> FollowMasterStrategy::getDefaultActions()
};
}
void FollowMasterStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
void FollowMasterStrategy::InitTriggers(std::vector<TriggerNode*>& /*triggers*/)
{
}

View File

@ -12,4 +12,4 @@ std::vector<NextAction> GuardStrategy::getDefaultActions()
};
}
void GuardStrategy::InitTriggers(std::vector<TriggerNode*>& triggers) {}
void GuardStrategy::InitTriggers(std::vector<TriggerNode*>& /*triggers*/) {}

View File

@ -13,7 +13,7 @@ void MaintenanceStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
triggers.push_back(
new TriggerNode(
"random",
"seldom",
{
NextAction("clean quest log", 6.0f)
}

View File

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

View File

@ -5,8 +5,188 @@
#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
{
@ -24,8 +204,16 @@ 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 == "reach spell" || name == "change strategy")
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")
return 1.0f;
return PassiveMultiplier::GetValue(action);
@ -34,18 +222,32 @@ float MagePullMultiplier::GetValue(Action* action)
std::vector<NextAction> PullStrategy::getDefaultActions()
{
return {
NextAction(action, 105.0f),
NextAction("follow", 104.0f),
NextAction("end pull", 103.0f),
NextAction("pull action", 105.0f),
};
}
void PullStrategy::InitTriggers(std::vector<TriggerNode*>& triggers) { CombatStrategy::InitTriggers(triggers); }
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::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)
@ -61,3 +263,15 @@ 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)
}
));
}

View File

@ -6,22 +6,65 @@
#ifndef _PLAYERBOT_PULLSTRATEGY_H
#define _PLAYERBOT_PULLSTRATEGY_H
#include "CombatStrategy.h"
#include "Strategy.h"
class Action;
class Multiplier;
class Unit;
class PlayerbotAI;
class PullStrategy : public CombatStrategy
class PullStrategy : public Strategy
{
public:
PullStrategy(PlayerbotAI* botAI, std::string const action) : CombatStrategy(botAI), action(action) {}
PullStrategy(PlayerbotAI* botAI, std::string const action, std::string const preAction = "");
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
@ -33,4 +76,13 @@ 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

View File

@ -7,4 +7,4 @@
RTSCStrategy::RTSCStrategy(PlayerbotAI* botAI) : Strategy(botAI) {}
void RTSCStrategy::InitTriggers(std::vector<TriggerNode*>& triggers) {}
void RTSCStrategy::InitTriggers(std::vector<TriggerNode*>& /*triggers*/) {}

View File

@ -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*/ {},

View File

@ -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*/ {},

View File

@ -82,6 +82,7 @@ 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")

View File

@ -95,6 +95,7 @@ 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;
@ -171,6 +172,7 @@ 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); }

View File

@ -0,0 +1,62 @@
/*
* 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;
}

View File

@ -0,0 +1,35 @@
/*
* 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

View File

@ -16,6 +16,7 @@
#include "NewRpgStrategy.h"
#include "NewRpgTriggers.h"
#include "PvpTriggers.h"
#include "PullTriggers.h"
#include "RpgTriggers.h"
#include "RtiTriggers.h"
#include "StuckTriggers.h"
@ -129,6 +130,9 @@ 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;
@ -280,6 +284,9 @@ 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); }

View File

@ -19,6 +19,7 @@ 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;
@ -147,7 +148,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);

View File

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

View File

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

View File

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

View File

@ -11,8 +11,6 @@ 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);

View File

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

View File

@ -48,23 +48,6 @@ 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;

View File

@ -234,6 +234,11 @@ ItemUsage ItemUsageValue::QueryItemUsageForEquip(ItemTemplate const* itemProto,
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)
@ -864,8 +869,6 @@ 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)

View File

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

View File

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

View File

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

View File

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

View File

@ -40,12 +40,12 @@ bool SpellCastUsefulValue::Calculate()
return false;
}
// TODO: workaround
if (qualifier == "windfury weapon" || qualifier == "flametongue weapon" || qualifier == "frostbrand weapon" ||
qualifier == "rockbiter weapon" || qualifier == "earthliving weapon" || qualifier == "spellstone")
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))
if (item->IsInWorld() && item->GetEnchantmentId(TEMP_ENCHANTMENT_SLOT))
if (Item* item = AI_VALUE2(Item*, "item for spell", spellid);
item && item->IsInWorld() && item->GetEnchantmentId(TEMP_ENCHANTMENT_SLOT))
return false;
}

View File

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

View File

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

View File

@ -116,6 +116,15 @@ 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:

View File

@ -241,6 +241,7 @@ 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;
@ -498,6 +499,7 @@ 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); }

View File

@ -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 PullStrategy(botAI, "icy touch"); }
static Strategy* pull(PlayerbotAI* botAI) { return new DeathKnightPullStrategy(botAI); }
static Strategy* frost_aoe(PlayerbotAI* botAI) { return new FrostDKAoeStrategy(botAI); }
static Strategy* unholy_aoe(PlayerbotAI* botAI) { return new UnholyDKAoeStrategy(botAI); }
};

View File

@ -0,0 +1,43 @@
/*
* 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();
}

View File

@ -0,0 +1,19 @@
/*
* 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

View File

@ -47,7 +47,7 @@ void GenericDKNonCombatStrategy::InitTriggers(std::vector<TriggerNode*>& trigger
new TriggerNode("bone shield", { NextAction("bone shield", 21.0f) }));
}
void DKBuffDpsStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
void DKBuffDpsStrategy::InitTriggers(std::vector<TriggerNode*>& /*triggers*/)
{
}

View File

@ -19,6 +19,7 @@
#include "MeleeDruidStrategy.h"
#include "OffhealDruidCatStrategy.h"
#include "Playerbots.h"
#include "DruidPullStrategy.h"
class DruidStrategyFactoryInternal : public NamedObjectContext<Strategy>
{
@ -26,6 +27,7 @@ public:
DruidStrategyFactoryInternal()
{
creators["nc"] = &DruidStrategyFactoryInternal::nc;
creators["pull"] = &DruidStrategyFactoryInternal::pull;
creators["cat aoe"] = &DruidStrategyFactoryInternal::cat_aoe;
creators["caster aoe"] = &DruidStrategyFactoryInternal::caster_aoe;
creators["caster debuff"] = &DruidStrategyFactoryInternal::caster_debuff;
@ -40,6 +42,7 @@ public:
private:
static Strategy* nc(PlayerbotAI* botAI) { return new GenericDruidNonCombatStrategy(botAI); }
static Strategy* pull(PlayerbotAI* botAI) { return new DruidPullStrategy(botAI); }
static Strategy* cat_aoe(PlayerbotAI* botAI) { return new CatAoeDruidStrategy(botAI); }
static Strategy* caster_aoe(PlayerbotAI* botAI) { return new CasterDruidAoeStrategy(botAI); }
static Strategy* caster_debuff(PlayerbotAI* botAI) { return new CasterDruidDebuffStrategy(botAI); }

View File

@ -311,4 +311,4 @@ void CatDpsDruidStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
);
}
void CatAoeDruidStrategy::InitTriggers(std::vector<TriggerNode*>& triggers) {}
void CatAoeDruidStrategy::InitTriggers(std::vector<TriggerNode*>& /*triggers*/) {}

View File

@ -0,0 +1,46 @@
/*
* 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 "DruidPullStrategy.h"
#include "AiObjectContext.h"
#include "Player.h"
#include "PlayerbotAI.h"
#include "Playerbots.h"
std::string DruidPullStrategy::GetPullActionName() const
{
Player* bot = botAI->GetBot();
std::string actionName = PullStrategy::GetPullActionName();
if (!bot)
return actionName;
uint32 const faerieFireFeralId = botAI->GetAiObjectContext()->GetValue<uint32>("spell id", "faerie fire (feral)")->Get();
if (faerieFireFeralId && bot->HasSpell(faerieFireFeralId) &&
(botAI->HasStrategy("bear", BOT_STATE_COMBAT) || botAI->HasStrategy("cat", BOT_STATE_COMBAT)))
{
actionName = "faerie fire (feral)";
}
Unit* target = GetTarget();
uint32 const faerieFireSpellId = botAI->GetAiObjectContext()->GetValue<uint32>("spell id", actionName)->Get();
if (target && (!faerieFireSpellId || !bot->HasSpell(faerieFireSpellId) ||
!botAI->CanCastSpell(faerieFireSpellId, target)))
{
uint32 const growlSpellId = botAI->GetAiObjectContext()->GetValue<uint32>("spell id", "growl")->Get();
if (growlSpellId && bot->HasSpell(growlSpellId) && botAI->CanCastSpell(growlSpellId, target))
return "growl";
}
return actionName;
}
std::string DruidPullStrategy::GetPreActionName() const
{
if (GetPullActionName() == "faerie fire")
return "";
return PullStrategy::GetPreActionName();
}

View File

@ -0,0 +1,20 @@
/*
* 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_DRUID_PULL_STRATEGY_H
#define _PLAYERBOT_DRUID_PULL_STRATEGY_H
#include "PullStrategy.h"
class DruidPullStrategy : public PullStrategy
{
public:
DruidPullStrategy(PlayerbotAI* botAI) : PullStrategy(botAI, "faerie fire", "dire bear form") {}
std::string GetPullActionName() const override;
std::string GetPreActionName() const override;
};
#endif

View File

@ -392,7 +392,7 @@ class CastExplosiveShotRank4Action : public CastExplosiveShotBaseAction
public:
CastExplosiveShotRank4Action(PlayerbotAI* botAI) :
CastExplosiveShotBaseAction(botAI) {}
bool Execute(Event event) override
bool Execute(Event /*event*/) override
{
return botAI->CastSpell(60053, GetTarget());
}
@ -412,7 +412,7 @@ class CastExplosiveShotRank3Action : public CastExplosiveShotBaseAction
public:
CastExplosiveShotRank3Action(PlayerbotAI* botAI) :
CastExplosiveShotBaseAction(botAI) {}
bool Execute(Event event) override
bool Execute(Event /*event*/) override
{
return botAI->CastSpell(60052, GetTarget());
}
@ -432,7 +432,7 @@ class CastExplosiveShotRank2Action : public CastExplosiveShotBaseAction
public:
CastExplosiveShotRank2Action(PlayerbotAI* botAI) :
CastExplosiveShotBaseAction(botAI) {}
bool Execute(Event event) override
bool Execute(Event /*event*/) override
{
return botAI->CastSpell(60051, GetTarget());
}
@ -452,7 +452,7 @@ class CastExplosiveShotRank1Action : public CastExplosiveShotBaseAction
public:
CastExplosiveShotRank1Action(PlayerbotAI* botAI) :
CastExplosiveShotBaseAction(botAI) {}
bool Execute(Event event) override
bool Execute(Event /*event*/) override
{
return botAI->CastSpell(53301, GetTarget());
}

View File

@ -12,6 +12,7 @@
#include "OffhealRetPaladinStrategy.h"
#include "PaladinActions.h"
#include "PaladinBuffStrategies.h"
#include "PaladinPullStrategy.h"
#include "PaladinTriggers.h"
#include "Playerbots.h"
#include "TankPaladinStrategy.h"
@ -22,6 +23,7 @@ public:
PaladinStrategyFactoryInternal()
{
creators["nc"] = &PaladinStrategyFactoryInternal::nc;
creators["pull"] = &PaladinStrategyFactoryInternal::pull;
creators["cure"] = &PaladinStrategyFactoryInternal::cure;
creators["boost"] = &PaladinStrategyFactoryInternal::boost;
creators["cc"] = &PaladinStrategyFactoryInternal::cc;
@ -31,6 +33,7 @@ public:
private:
static Strategy* nc(PlayerbotAI* botAI) { return new GenericPaladinNonCombatStrategy(botAI); }
static Strategy* pull(PlayerbotAI* botAI) { return new PaladinPullStrategy(botAI); }
static Strategy* cure(PlayerbotAI* botAI) { return new PaladinCureStrategy(botAI); }
static Strategy* boost(PlayerbotAI* botAI) { return new PaladinBoostStrategy(botAI); }
static Strategy* cc(PlayerbotAI* botAI) { return new PaladinCcStrategy(botAI); }

View File

@ -54,7 +54,7 @@ void PaladinCureStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{ NextAction("cleanse magic on party", ACTION_DISPEL + 1) }));
}
void PaladinBoostStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
void PaladinBoostStrategy::InitTriggers(std::vector<TriggerNode*>& /*triggers*/)
{
// triggers.push_back(new TriggerNode("divine favor", { NextAction("divine favor",

View File

@ -0,0 +1,46 @@
/*
* 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 "PaladinPullStrategy.h"
#include "AiObjectContext.h"
#include "Player.h"
#include "PlayerbotAI.h"
#include "Playerbots.h"
std::string PaladinPullStrategy::GetPullActionName() const
{
Player* bot = botAI->GetBot();
Unit* target = GetTarget();
if (!bot || !target ||
(!botAI->HasStrategy("tank", BOT_STATE_COMBAT) && !botAI->HasStrategy("tank", BOT_STATE_NON_COMBAT)))
{
return PullStrategy::GetPullActionName();
}
uint32 const avengersShieldSpellId = botAI->GetAiObjectContext()->GetValue<uint32>("spell id", "avenger's shield")->Get();
if (avengersShieldSpellId && bot->HasSpell(avengersShieldSpellId) &&
botAI->CanCastSpell(avengersShieldSpellId, target))
{
return "avenger's shield";
}
uint32 const handOfReckoningSpellId = botAI->GetAiObjectContext()->GetValue<uint32>("spell id", "hand of reckoning")->Get();
if (handOfReckoningSpellId && bot->HasSpell(handOfReckoningSpellId) &&
botAI->CanCastSpell(handOfReckoningSpellId, target))
{
return "hand of reckoning";
}
return PullStrategy::GetPullActionName();
}
std::string PaladinPullStrategy::GetPreActionName() const
{
if (botAI->HasStrategy("tank", BOT_STATE_COMBAT) || botAI->HasStrategy("tank", BOT_STATE_NON_COMBAT))
return "";
return PullStrategy::GetPreActionName();
}

View File

@ -0,0 +1,20 @@
/*
* 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_PALADIN_PULL_STRATEGY_H
#define _PLAYERBOT_PALADIN_PULL_STRATEGY_H
#include "PullStrategy.h"
class PaladinPullStrategy : public PullStrategy
{
public:
PaladinPullStrategy(PlayerbotAI* botAI) : PullStrategy(botAI, "judgement", "seal of righteousness") {}
std::string GetPullActionName() const override;
std::string GetPreActionName() const override;
};
#endif

View File

@ -124,12 +124,12 @@ void AoEWarlockStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
);
}
void WarlockBoostStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
void WarlockBoostStrategy::InitTriggers(std::vector<TriggerNode*>& /*triggers*/)
{
// Placeholder for future boost triggers
}
void WarlockPetStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
void WarlockPetStrategy::InitTriggers(std::vector<TriggerNode*>& /*triggers*/)
{
// Placeholder for future pet triggers
}

View File

@ -41,6 +41,6 @@ std::vector<NextAction> TankWarlockStrategy::getDefaultActions()
};
}
void TankWarlockStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
void TankWarlockStrategy::InitTriggers(std::vector<TriggerNode*>& /*triggers*/)
{
}

View File

@ -21,7 +21,7 @@ public:
}
private:
static ActionNode* charge(PlayerbotAI* botAI)
static ActionNode* charge(PlayerbotAI* /*botAI*/)
{
return new ActionNode(
"charge",
@ -31,7 +31,7 @@ private:
);
}
static ActionNode* death_wish(PlayerbotAI* botAI)
static ActionNode* death_wish(PlayerbotAI* /*botAI*/)
{
return new ActionNode(
"death wish",
@ -41,7 +41,7 @@ private:
);
}
static ActionNode* piercing_howl(PlayerbotAI* botAI)
static ActionNode* piercing_howl(PlayerbotAI* /*botAI*/)
{
return new ActionNode(
"piercing howl",
@ -51,7 +51,7 @@ private:
);
}
static ActionNode* mocking_blow(PlayerbotAI* botAI)
static ActionNode* mocking_blow(PlayerbotAI* /*botAI*/)
{
return new ActionNode(
"mocking blow",
@ -61,7 +61,7 @@ private:
);
}
static ActionNode* heroic_strike(PlayerbotAI* botAI)
static ActionNode* heroic_strike(PlayerbotAI* /*botAI*/)
{
return new ActionNode(
"heroic strike",
@ -71,7 +71,7 @@ private:
);
}
static ActionNode* enraged_regeneration(PlayerbotAI* botAI)
static ActionNode* enraged_regeneration(PlayerbotAI* /*botAI*/)
{
return new ActionNode(
"enraged regeneration",
@ -81,7 +81,7 @@ private:
);
}
static ActionNode* retaliation(PlayerbotAI* botAI)
static ActionNode* retaliation(PlayerbotAI* /*botAI*/)
{
return new ActionNode(
"retaliation",
@ -91,7 +91,7 @@ private:
);
}
static ActionNode* shattering_throw(PlayerbotAI* botAI)
static ActionNode* shattering_throw(PlayerbotAI* /*botAI*/)
{
return new ActionNode(
"shattering throw",

View File

@ -18,7 +18,7 @@ public:
}
private:
static ActionNode* charge(PlayerbotAI* botAI)
static ActionNode* charge(PlayerbotAI* /*botAI*/)
{
return new ActionNode(
"charge",
@ -28,7 +28,7 @@ private:
);
}
static ActionNode* intercept(PlayerbotAI* botAI)
static ActionNode* intercept(PlayerbotAI* /*botAI*/)
{
return new ActionNode(
"intercept",
@ -38,7 +38,7 @@ private:
);
}
static ActionNode* piercing_howl(PlayerbotAI* botAI)
static ActionNode* piercing_howl(PlayerbotAI* /*botAI*/)
{
return new ActionNode(
"piercing howl",
@ -48,7 +48,7 @@ private:
);
}
static ActionNode* pummel(PlayerbotAI* botAI)
static ActionNode* pummel(PlayerbotAI* /*botAI*/)
{
return new ActionNode(
"pummel",
@ -58,7 +58,7 @@ private:
);
}
static ActionNode* enraged_regeneration(PlayerbotAI* botAI)
static ActionNode* enraged_regeneration(PlayerbotAI* /*botAI*/)
{
return new ActionNode(
"enraged regeneration",

View File

@ -24,7 +24,7 @@ public:
}
private:
static ActionNode* heroic_throw_taunt(PlayerbotAI* botAI)
static ActionNode* heroic_throw_taunt(PlayerbotAI* /*botAI*/)
{
return new ActionNode(
"heroic throw",
@ -34,7 +34,7 @@ private:
);
}
static ActionNode* heroic_throw_on_snare_target(PlayerbotAI* botAI)
static ActionNode* heroic_throw_on_snare_target(PlayerbotAI* /*botAI*/)
{
return new ActionNode(
"heroic throw on snare target",
@ -44,7 +44,7 @@ private:
);
}
static ActionNode* last_stand(PlayerbotAI* botAI)
static ActionNode* last_stand(PlayerbotAI* /*botAI*/)
{
return new ActionNode(
"last stand",
@ -54,7 +54,7 @@ private:
);
}
static ActionNode* devastate(PlayerbotAI* botAI)
static ActionNode* devastate(PlayerbotAI* /*botAI*/)
{
return new ActionNode(
"devastate",
@ -64,7 +64,7 @@ private:
);
}
static ActionNode* commanding_shout(PlayerbotAI* botAI)
static ActionNode* commanding_shout(PlayerbotAI* /*botAI*/)
{
return new ActionNode(
"commanding shout",
@ -74,7 +74,7 @@ private:
);
}
static ActionNode* sunder_armor(PlayerbotAI* botAI)
static ActionNode* sunder_armor(PlayerbotAI* /*botAI*/)
{
return new ActionNode(
"sunder armor",
@ -84,7 +84,7 @@ private:
);
}
static ActionNode* charge(PlayerbotAI* botAI)
static ActionNode* charge(PlayerbotAI* /*botAI*/)
{
return new ActionNode(
"charge",
@ -94,7 +94,7 @@ private:
);
}
static ActionNode* taunt(PlayerbotAI* botAI)
static ActionNode* taunt(PlayerbotAI* /*botAI*/)
{
return new ActionNode(
"taunt",
@ -104,7 +104,7 @@ private:
);
}
static ActionNode* vigilance(PlayerbotAI* botAI)
static ActionNode* vigilance(PlayerbotAI* /*botAI*/)
{
return new ActionNode(
"vigilance",
@ -114,7 +114,7 @@ private:
);
}
static ActionNode* enraged_regeneration(PlayerbotAI* botAI)
static ActionNode* enraged_regeneration(PlayerbotAI* /*botAI*/)
{
return new ActionNode(
"enraged regeneration",

View File

@ -0,0 +1,27 @@
/*
* 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 "WarriorPullStrategy.h"
#include "AiObjectContext.h"
#include "Player.h"
#include "PlayerbotAI.h"
std::string WarriorPullStrategy::GetPullActionName() const
{
Player* bot = botAI->GetBot();
Unit* target = GetTarget();
if (!bot || !target)
return PullStrategy::GetPullActionName();
uint32 const heroicThrowSpellId = botAI->GetAiObjectContext()->GetValue<uint32>("spell id", "heroic throw")->Get();
if (heroicThrowSpellId && bot->HasSpell(heroicThrowSpellId) &&
botAI->CanCastSpell(heroicThrowSpellId, target))
{
return "heroic throw";
}
return PullStrategy::GetPullActionName();
}

View File

@ -0,0 +1,19 @@
/*
* 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_WARRIOR_PULL_STRATEGY_H
#define _PLAYERBOT_WARRIOR_PULL_STRATEGY_H
#include "PullStrategy.h"
class WarriorPullStrategy : public PullStrategy
{
public:
WarriorPullStrategy(PlayerbotAI* botAI) : PullStrategy(botAI, "shoot") {}
std::string GetPullActionName() const override;
};
#endif

View File

@ -10,8 +10,8 @@
#include "GenericWarriorNonCombatStrategy.h"
#include "NamedObjectContext.h"
#include "Playerbots.h"
#include "PullStrategy.h"
#include "TankWarriorStrategy.h"
#include "WarriorPullStrategy.h"
#include "WarriorActions.h"
#include "WarriorTriggers.h"
@ -28,7 +28,7 @@ public:
private:
static Strategy* nc(PlayerbotAI* botAI) { return new GenericWarriorNonCombatStrategy(botAI); }
static Strategy* warrior_aoe(PlayerbotAI* botAI) { return new WarrirorAoeStrategy(botAI); }
static Strategy* pull(PlayerbotAI* botAI) { return new PullStrategy(botAI, "shoot"); }
static Strategy* pull(PlayerbotAI* botAI) { return new WarriorPullStrategy(botAI); }
};
class WarriorCombatStrategyFactoryInternal : public NamedObjectContext<Strategy>

View File

@ -0,0 +1,117 @@
#include "Playerbots.h"
#include "AiFactory.h"
#include "AuchenaiCryptsTriggers.h"
#include "AuchenaiCryptsActions.h"
// Shirrak the Dead Watcher
static const Position SHIRRAK_RANGED_POSITION = { -21.777f, -162.700f, 26.062f };
static const Position SHIRRAK_TANK_POSITION = { -65.171f, -162.920f, 26.504f };
// Tank will position Shirrak at the specified coordinates, further down the corridor past the stairs
bool ShirrakTankPositionBossAction::Execute(Event /*event*/)
{
Unit* shirrak = AI_VALUE2(Unit*, "find target", "shirrak the dead watcher");
if (!shirrak)
return false;
if (bot->GetVictim() != shirrak)
return Attack(shirrak);
if (shirrak->GetVictim() == bot && bot->IsWithinMeleeRange(shirrak) &&
bot->GetHealthPct()>30.0f)
{
const Position& position = SHIRRAK_TANK_POSITION;
float distToPosition = bot->GetExactDist2d(position.GetPositionX(),
position.GetPositionY());
if (distToPosition > 6.0f)
{
float dX = position.GetPositionX() - bot->GetPositionX();
float dY = position.GetPositionY() - bot->GetPositionY();
float moveDist = std::min(2.0f, distToPosition);
float moveX = bot->GetPositionX() + (dX / distToPosition) * moveDist;
float moveY = bot->GetPositionY() + (dY / distToPosition) * moveDist;
return MoveTo(bot->GetMapId(), moveX, moveY, bot->GetPositionZ(), false, false,
false, false, MovementPriority::MOVEMENT_COMBAT, true, true);
}
}
return false;
}
// Flee from Shirrak's Focus Fire
bool ShirrakFleeFocusFireAction::Execute(Event /*event*/)
{
std::list<Creature*> creatureList;
bot->GetCreatureListWithEntryInGrid(creatureList, static_cast<uint32>(AuchenaiCryptsIDs::NPC_FOCUS_FIRE), 20.0f);
for (Creature* flare : creatureList)
{
if (flare && flare->IsAlive())
{
float currentDistance = bot->GetDistance2d(flare);
constexpr float safeDistance = 12.0f;
constexpr float buffer = 5.0f;
if (currentDistance < safeDistance)
{
bot->AttackStop();
float distanceToMove = safeDistance - currentDistance + buffer;
return MoveAway(flare, distanceToMove);
}
}
}
return false;
}
// Ranged should keep distance from Shirrak, staying at the edge of the stairs
bool ShirrakRangedKeepDistanceAction::Execute(Event /*event*/)
{
std::vector<Player*> rangedBots;
if (Group* group = bot->GetGroup())
{
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
{
Player* member = ref->GetSource();
if (member && botAI->IsRanged(member))
rangedBots.push_back(member);
}
}
auto findIt = std::find(rangedBots.begin(), rangedBots.end(), bot);
size_t botIndex = (findIt != rangedBots.end()) ? std::distance(rangedBots.begin(), findIt) : 0;
size_t count = rangedBots.size();
constexpr float arcSpan = M_PI / 2.0f;
float arcCenter = M_PI;
float arcStart = arcCenter - (arcSpan / 2.0f);
float angle = (count <= 1) ? arcCenter : (arcStart + (arcSpan * (float)botIndex / (float)(count - 1)));
constexpr float spreadRadius = 3.0f;
float targetX = SHIRRAK_RANGED_POSITION.GetPositionX() + cos(angle) * spreadRadius;
float targetY = SHIRRAK_RANGED_POSITION.GetPositionY() + sin(angle) * spreadRadius;
float distToSpot = bot->GetExactDist2d(targetX, targetY);
if (distToSpot > 4.0f)
{
float dX = targetX - bot->GetPositionX();
float dY = targetY - bot->GetPositionY();
float moveDist = std::min(2.0f, distToSpot);
float moveX = bot->GetPositionX() + (dX / distToSpot) * moveDist;
float moveY = bot->GetPositionY() + (dY / distToSpot) * moveDist;
return MoveTo(bot->GetMapId(), moveX, moveY, bot->GetPositionZ(), false, false,
false, false, MovementPriority::MOVEMENT_COMBAT, true, false);
}
return false;
}

View File

@ -0,0 +1,31 @@
#ifndef _PLAYERBOT_TBCDUNGEONAUCHENAICRYPTSACTIONS_H
#define _PLAYERBOT_TBCDUNGEONAUCHENAICRYPTSACTIONS_H
#include "AttackAction.h"
#include "MovementActions.h"
#include "AuchenaiCryptsTriggers.h"
// Shirrak the Dead Watcher
class ShirrakTankPositionBossAction : public AttackAction
{
public:
ShirrakTankPositionBossAction(PlayerbotAI* botAI) : AttackAction(botAI, "shirrak tank position boss") {}
bool Execute(Event event) override;
};
class ShirrakFleeFocusFireAction : public MovementAction
{
public:
ShirrakFleeFocusFireAction(PlayerbotAI* botAI) : MovementAction(botAI, "shirrak flee focus fire") {}
bool Execute(Event event) override;
};
class ShirrakRangedKeepDistanceAction : public MovementAction
{
public:
ShirrakRangedKeepDistanceAction(PlayerbotAI* botAI) : MovementAction(botAI, "shirrak ranged keep distance") {}
bool Execute(Event event) override;
};
#endif

View File

@ -0,0 +1,34 @@
#ifndef _PLAYERBOT_TBCDUNGEONAUCHENAICRYPTSACTIONCONTEXT_H
#define _PLAYERBOT_TBCDUNGEONAUCHENAICRYPTSACTIONCONTEXT_H
#include "AiObjectContext.h"
#include "Action.h"
#include "AuchenaiCryptsActions.h"
class TbcDungeonAuchenaiCryptsActionContext : public NamedObjectContext<Action>
{
public:
TbcDungeonAuchenaiCryptsActionContext() : NamedObjectContext<Action>(false, true)
{
creators["shirrak tank position boss"] =
&TbcDungeonAuchenaiCryptsActionContext::shirrak_tank_position_boss;
creators["shirrak flee focus fire"] =
&TbcDungeonAuchenaiCryptsActionContext::shirrak_flee_focus_fire;
creators["shirrak ranged keep distance"] =
&TbcDungeonAuchenaiCryptsActionContext::shirrak_ranged_keep_distance;
}
private:
static Action* shirrak_tank_position_boss(
PlayerbotAI* botAI) { return new ShirrakTankPositionBossAction(botAI); }
static Action* shirrak_flee_focus_fire(
PlayerbotAI* botAI) { return new ShirrakFleeFocusFireAction(botAI); }
static Action* shirrak_ranged_keep_distance(
PlayerbotAI* botAI) { return new ShirrakRangedKeepDistanceAction(botAI); }
};
#endif

View File

@ -0,0 +1,35 @@
#ifndef _PLAYERBOT_TBCDUNGEONAUCHENAICRYPTSTRIGGERCONTEXT_H
#define _PLAYERBOT_TBCDUNGEONAUCHENAICRYPTSTRIGGERCONTEXT_H
#include "AiObjectContext.h"
#include "TriggerContext.h"
#include "AuchenaiCryptsTriggers.h"
class TbcDungeonAuchenaiCryptsTriggerContext : public NamedObjectContext<Trigger>
{
public:
// Shirrak the Dead Watcher
TbcDungeonAuchenaiCryptsTriggerContext()
{
creators["shirrak tank position boss"] =
&TbcDungeonAuchenaiCryptsTriggerContext::shirrak_tank_position_boss;
creators["shirrak flee focus fire"] =
&TbcDungeonAuchenaiCryptsTriggerContext::shirrak_flee_focus_fire;
creators["shirrak ranged keep distance"] =
&TbcDungeonAuchenaiCryptsTriggerContext::shirrak_ranged_keep_distance;
}
private:
// Shirrak the Dead Watcher
static Trigger* shirrak_tank_position_boss(
PlayerbotAI* botAI) { return new ShirrakTankPositionBossTrigger(botAI); }
static Trigger* shirrak_flee_focus_fire(
PlayerbotAI* botAI) { return new ShirrakFleeFocusFireTrigger(botAI); }
static Trigger* shirrak_ranged_keep_distance(
PlayerbotAI* botAI) { return new ShirrakRangedKeepDistanceTrigger(botAI); }
};
#endif

View File

@ -0,0 +1,45 @@
#include "AuchenaiCryptsMultipliers.h"
#include "AuchenaiCryptsActions.h"
#include "AuchenaiCryptsTriggers.h"
#include "MovementActions.h"
#include "ReachTargetActions.h"
#include "FollowActions.h"
#include "AiObjectContext.h"
#include "Playerbots.h"
// Shirrak the Dead Watcher
// Flee from Focus Fire and dont run back in
float ShirrakFleeFocusFireMultiplier::GetValue(Action* action)
{
if (!AI_VALUE2(Unit*, "find target", "shirrak the dead watcher"))
return 1.0f;
std::list<Creature*> creatureList;
bot->GetCreatureListWithEntryInGrid(creatureList, static_cast<uint32>(AuchenaiCryptsIDs::NPC_FOCUS_FIRE), 20.0f);
for (Creature* flare : creatureList)
{
if (flare && flare->IsAlive())
{
if (dynamic_cast<CastReachTargetSpellAction*>(action))
return 0.0f;
float currentDistance = bot->GetDistance2d(flare);
constexpr float safeDistance = 12.0f;
constexpr float buffer = 5.0f;
if (currentDistance < safeDistance + buffer && (
dynamic_cast<CombatFormationMoveAction*>(action) ||
dynamic_cast<ShirrakRangedKeepDistanceAction*>(action) ||
dynamic_cast<FleeAction*>(action) ||
dynamic_cast<FollowAction*>(action) ||
dynamic_cast<ReachTargetAction*>(action) ||
dynamic_cast<AvoidAoeAction*>(action)))
{
return 0.0f;
}
}
}
return 1.0f;
}

View File

@ -0,0 +1,13 @@
#ifndef _PLAYERBOT_TBCDUNGEONAUCHENAICRYPTSMULTIPLIERS_H
#define _PLAYERBOT_TBCDUNGEONAUCHENAICRYPTSMULTIPLIERS_H
#include "Multiplier.h"
class ShirrakFleeFocusFireMultiplier : public Multiplier
{
public:
ShirrakFleeFocusFireMultiplier(PlayerbotAI* botAI) : Multiplier(botAI, "shirrak flee focus fire") {}
float GetValue(Action* action) override;
};
#endif

View File

@ -0,0 +1,21 @@
#include "AuchenaiCryptsTriggers.h"
#include "AuchenaiCryptsStrategy.h"
#include "AuchenaiCryptsMultipliers.h"
void TbcDungeonAuchenaiCryptsStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
// Shirrak The Dead Watcher
triggers.push_back(new TriggerNode("shirrak tank position boss", {
NextAction("shirrak tank position boss", ACTION_RAID + 1) }));
triggers.push_back(new TriggerNode("shirrak flee focus fire", {
NextAction("shirrak flee focus fire", ACTION_EMERGENCY + 10) }));
triggers.push_back(new TriggerNode("shirrak ranged keep distance", {
NextAction("shirrak ranged keep distance", ACTION_RAID + 1) }));
}
void TbcDungeonAuchenaiCryptsStrategy::InitMultipliers(std::vector<Multiplier*>& multipliers)
{
multipliers.push_back(new ShirrakFleeFocusFireMultiplier(botAI));
}

View File

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

View File

@ -0,0 +1,34 @@
#include "Playerbots.h"
#include "AuchenaiCryptsTriggers.h"
#include "AiObject.h"
#include "AiObjectContext.h"
// Shirrak the Dead Watcher
bool ShirrakTankPositionBossTrigger::IsActive()
{
return botAI->IsTank(bot) &&
AI_VALUE2(Unit*, "find target", "shirrak the dead watcher");
}
bool ShirrakFleeFocusFireTrigger::IsActive()
{
if (!AI_VALUE2(Unit*, "find target", "shirrak the dead watcher"))
return false;
std::list<Creature*> creatureList;
bot->GetCreatureListWithEntryInGrid(creatureList, static_cast<uint32>(AuchenaiCryptsIDs::NPC_FOCUS_FIRE), 20.0f);
for (Creature* flare : creatureList)
{
if (flare && flare->IsAlive())
return true;
}
return false;
}
bool ShirrakRangedKeepDistanceTrigger::IsActive()
{
return botAI->IsRanged(bot) &&
AI_VALUE2(Unit*, "find target", "shirrak the dead watcher");
}

View File

@ -0,0 +1,38 @@
#ifndef _PLAYERBOT_TBCDUNGEONAUCHENAICRYPTSTRIGGERS_H
#define _PLAYERBOT_TBCDUNGEONAUCHENAICRYPTSTRIGGERS_H
#include "Trigger.h"
#include "GenericTriggers.h"
#include "DungeonStrategyUtils.h"
enum class AuchenaiCryptsIDs : uint32
{
// Shirrak The Dead Watcher
NPC_FOCUS_FIRE = 18374,
};
class ShirrakTankPositionBossTrigger : public Trigger
{
public:
ShirrakTankPositionBossTrigger(PlayerbotAI* botAI) : Trigger(botAI, "shirrak tank position boss") {}
bool IsActive() override;
};
class ShirrakFleeFocusFireTrigger : public Trigger
{
public:
ShirrakFleeFocusFireTrigger(PlayerbotAI* botAI) : Trigger(botAI, "shirrak flee focus fire") {}
bool IsActive() override;
};
class ShirrakRangedKeepDistanceTrigger : public Trigger
{
public:
ShirrakRangedKeepDistanceTrigger(PlayerbotAI* botAI) : Trigger(botAI, "shirrak ranged keep distance") {}
bool IsActive() override;
};
#endif

View File

@ -2,6 +2,7 @@
#define _PLAYERBOT_DUNGEONSTRATEGYCONTEXT_H
#include "Strategy.h"
#include "AuchenaiCrypts/Strategy/AuchenaiCryptsStrategy.h"
#include "UtgardeKeep/Strategy/UtgardeKeepStrategy.h"
#include "Nexus/Strategy/NexusStrategy.h"
#include "AzjolNerub/Strategy/AzjolNerubStrategy.h"
@ -44,7 +45,7 @@ class DungeonStrategyContext : public NamedObjectContext<Strategy>
// ...
// Burning Crusade
// ...
creators["tbc-ac"] = &DungeonStrategyContext::tbc_ac; // Auchindoun: Auchenai Crypts
// Wrath of the Lich King
creators["wotlk-uk"] = &DungeonStrategyContext::wotlk_uk; // Utgarde Keep
@ -65,6 +66,7 @@ class DungeonStrategyContext : public NamedObjectContext<Strategy>
creators["wotlk-fos"] = &DungeonStrategyContext::wotlk_fos; // The Forge of Souls
}
private:
static Strategy* tbc_ac(PlayerbotAI* botAI) { return new TbcDungeonAuchenaiCryptsStrategy(botAI); }
static Strategy* wotlk_uk(PlayerbotAI* botAI) { return new WotlkDungeonUKStrategy(botAI); }
static Strategy* wotlk_nex(PlayerbotAI* botAI) { return new WotlkDungeonNexStrategy(botAI); }
static Strategy* wotlk_an(PlayerbotAI* botAI) { return new WotlkDungeonANStrategy(botAI); }

View File

@ -134,7 +134,7 @@ bool IckAndKrickAction::PoisonNova(bool poisonNova, Unit* boss)
return false;
}
bool IckAndKrickAction::ExplosiveBarrage(bool explosiveBarrage, Unit* boss)
bool IckAndKrickAction::ExplosiveBarrage(bool /*explosiveBarrage*/, Unit* boss)
{
std::vector<Unit*> orbs;
Unit* closestOrb = nullptr;

View File

@ -27,7 +27,7 @@ float IckAndKrickMultiplier::GetValue(Action* action)
return 1.0f;
}
float GarfrostMultiplier::GetValue(Action* action)
float GarfrostMultiplier::GetValue(Action* /*action*/)
{
Unit* boss = AI_VALUE2(Unit*, "find target", "garfrost");
if (!boss)

View File

@ -0,0 +1,6 @@
#ifndef _PLAYERBOT_TBCDUNGEONACTIONCONTEXT_H
#define _PLAYERBOT_TBCDUNGEONACTIONCONTEXT_H
#include "AuchenaiCrypts/AuchenaiCryptsActionContext.h"
#endif

View File

@ -0,0 +1,6 @@
#ifndef _PLAYERBOT_TBCDUNGEONTRIGGERCONTEXT_H
#define _PLAYERBOT_TBCDUNGEONTRIGGERCONTEXT_H
#include "AuchenaiCrypts/AuchenaiCryptsTriggerContext.h"
#endif

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