Big update.

This commit is contained in:
UltraNix 2022-03-12 22:27:09 +01:00
parent b3d00ccb26
commit b952636f0d
843 changed files with 1534330 additions and 99 deletions

View File

@ -22,7 +22,7 @@ jobs:
- uses: actions/checkout@v2
with:
submodules: 'recursive'
path: 'modules/skeleton-module'
path: 'modules/mod_playerbots'
- name: Cache
uses: actions/cache@v2
with:

View File

@ -6,27 +6,27 @@
## BASE SQL
DB_AUTH_CUSTOM_PATHS+=(
"$MOD_SKELETON_ROOT/sql/auth/base/"
$MOD_PLAYERBOTS_ROOT"/sql/auth/base/"
)
DB_CHARACTERS_CUSTOM_PATHS+=(
"$MOD_SKELETON_ROOT/sql/characters/base/"
$MOD_PLAYERBOTS_ROOT"/sql/characters/base/"
)
DB_WORLD_CUSTOM_PATHS+=(
"$MOD_SKELETON_ROOT/sql/world/base/"
$MOD_PLAYERBOTS_ROOT"/sql/world/base/"
)
## UPDATES
DB_AUTH_UPDATES_PATHS+=(
"$MOD_SKELETON_ROOT/sql/auth/updates/"
DB_AUTH_UPDATE_PATHS+=(
$MOD_PLAYERBOTS_ROOT"/sql/auth/updates/"
)
DB_CHARACTERS_UPDATES_PATHS+=(
"$MOD_SKELETON_ROOT/sql/characters/updates/"
DB_CHARACTERS_UPDATE_PATHS+=(
$MOD_PLAYERBOTS_ROOT"/sql/characters/updates/"
)
DB_WORLD_UPDATES_PATHS+=(
"$MOD_SKELETON_ROOT/sql/world/updates/"
DB_WORLD_UPDATE_PATHS+=(
$MOD_PLAYERBOTS_ROOT"/sql/world/updates/"
)

View File

@ -1,17 +0,0 @@
#
# Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
#
[worldserver]
########################################
# My module configuration
########################################
#
# MyModule.Enable
# Description: Enable my module and print "Hello World" message at server start
# Default: 0 - Disabled
# 1 - Enabled
#
MyModule.Enable = 0

644
conf/playerbots.conf.dist Normal file
View File

@ -0,0 +1,644 @@
##########################################
# Playerbot Configuration file #
##########################################
# Enable or disable AI Playerbot
AiPlayerbot.Enabled = 1
# Enable random bot system
AiPlayerbot.RandomBotAutologin = 1
# Log on all random bots on start
AiPlayerbot.RandomBotLoginAtStartup = 1
# Delete all random bot accounts (reset randombots)
AiPlayerbot.DeleteRandomBotAccounts = 0
# auto-login all player alts as bots on player login
AiPlayerbot.BotAutologin = 0
# Guild Task system
AiPlayerbot.EnableGuildTasks = 1
# Enable LFG for random bots
AiPlayerbot.RandomBotJoinLfg = 1
# Enable BG/Arena for random Bots
AiPlayerbot.RandomBotJoinBG = 1
# Mark many quests <= Bot level as complete (slows down bot creation)
AiPlayerbot.PreQuests = 1
# Random bot count
AiPlayerbot.MinRandomBots = 50
AiPlayerbot.MaxRandomBots = 200
AiPlayerbot.RandomBotMinLevel = 1
AiPlayerbot.RandomBotMaxLevel = 80
# Accounts to create for random bots
AiPlayerbot.RandomBotAccountPrefix = "rndbot"
AiPlayerbot.RandomBotAccountCount = 200
# Random bot guild count
AiPlayerbot.RandomBotGuildCount = 20
# Delete all random bot guilds
AiPlayerbot.DeleteRandomBotGuilds = 0
# Random bot arena team count
AiPlayerbot.RandomBotArenaTeamCount = 20
# Delete all random bot arena teams
AiPlayerbot.DeleteRandomBotArenaTeams = 0
# Change random bot has lower gear
AiPlayerbot.RandomGearLoweringChance = 0.15
# Chance random bot has max level on first randomize (default 0.15)
AiPlayerbot.RandomBotMaxLevelChance = 0.15
# Chance bot chooses RPG (Teleport to random camp for their level) instead of grinding
AiPlayerbot.RandomBotRpgChance = 0.20
# Set randombots movement speed to walking anywhere
AiPlayerbot.RandombotsWalkingRPG = 0
# Set randombots movement speed to walking only inside buildings
AiPlayerbot.RandombotsWalkingRPG.InDoors = 0
# Bots greet to the players
AiPlayerbot.EnableGreet = 1
# Show helmet and cloak on randombots (reset required)
AiPlayerbot.RandomBotShowHelmet = 1
AiPlayerbot.RandomBotShowCloak = 1
# Disable random levels for randombots
# Every bots started on the specified level and level up by killing mobs.
AiPlayerbot.DisableRandomLevels = 0
# Set randombots starting level here if "AiPlayerbot.DisableRandomLevels" enabled
# Recommended: 5+
AiPlayerbot.RandombotStartingLevel = 5
# Set kill XP rate for bots (default: 1)
# Server XP Rate * AiPlayerbot.KillXPRate
AiPlayerbot.KillXPRate = 1
# Specify percent of active bots
# The default is 10. With 10% of all bots going active or inactive each minute.
AiPlayerbot.BotActiveAlone = 10
# Set minimum level of randombots where gets enchants on items (Maxlevel + 1 to disable)
# Default: 60
AiPlayerbot.MinEnchantingBotLevel = 60
# Randombots checking players gear score level and deny the group invite if it's too low
# Default: 1 (enabled)
AiPlayerbot.GearScoreCheck = 0
# Quest that will be completed and rewarded to all random bots
AiPlayerbot.RandomBotQuestIds = "7848,3802,5505,6502,7761"
# Randombots will group with nearby bots to do shared quests
AiPlayerbot.RandomBotGroupNearby = 1
# Bots without a master will say their lines
AiPlayerbot.RandomBotSayWithoutMaster = 0
# Automation
# Bots pick their quest reward (yes = picks first useful item, no = list all rewards, ask = pick useful item and lists if multiple)
AiPlayerbot.AutoPickReward = yes
# Bots equip upgrades (Bots will equip any item obtained from looting or a quest if they are upgrades)
# Default: 0 (disabled)
AiPlayerbot.AutoEquipUpgradeLoot = 1
# Sync quests with player (Bots will complete quests the moment you hand them in. Bots will ignore looting quest items.)
# Default: 0 (disabled)
AiPlayerbot.SyncQuestWithPlayer = 0
# Bots will auto-complete quests for the player when handing in
# Default: 0 (disabled)
AiPlayerbot.SyncQuestForPlayer = 0
# Sync max random bot level with max level of online players
# Default: 0 (disabled)
AiPlayerbot.SyncLevelWithPlayers = 0
# Bot automatically trains spells when talking to trainer (yes = train all available spells as long as the bot has the money, free = auto trains with no money cost, no = only list spells)
AiPlayerbot.AutoTrainSpells = yes
# Bot automatically picks talent points based on current spec (full = pick spec based on probability if multiple are like current spec, semi = only apply points if 1 spec looks like current spec, no = no auto talent points)
AiPlayerbot.AutoPickTalents = full
# Bots automatically learn trainable spells on levelup
# Default: 0 (disabled)
AiPlayerbot.AutoLearnTrainerSpells = 0
# Bots automatically learn classquest reward spells on levelup
# Default: 0 (disabled)
AiPlayerbot.AutoLearnQuestSpells = 0
# Random Bots will pick quests on their own and try to complete
# Default: 0 (disabled)
AiPlayerbot.AutoDoQuests = 0
##################################################################################
# #
# All other parameters are optional but can be changed by uncommenting them here #
# #
##################################################################################
##################################################################################
# #
# Premade builds #
# #
##################################################################################
#
# AiPlayerbot.PremadeSpecName.<class>.<specno> = <name> #Name of the talent specialisation
# AiPlayerbot.PremadeSpecProb.<class>.<specno> = <number> #Probability Randombots will pick this spec. (default 100)
# AiPlayerbot.PremadeSpecLink.<class>.<specno>.<level> = <link> #Wowhead style link the bot should work towards at given level.
# Preset talents supplied by Lidocain. Do you have more/improved specs? Let us know!
# Warrior
AiPlayerbot.PremadeSpecName.1.0 = pve arms
AiPlayerbot.PremadeSpecLink.1.0.80 = 3022032123335100202012013031251-32505010002
AiPlayerbot.PremadeSpecName.1.1 = pve fury
AiPlayerbot.PremadeSpecLink.1.1.80 = 30202300233-305053000500310153120511351
AiPlayerbot.PremadeSpecName.1.2 = pve prot
AiPlayerbot.PremadeSpecLink.1.2.80 = 05-3025-053351225000210521030113321
AiPlayerbot.PremadeSpecName.1.3 = pvp arms
AiPlayerbot.PremadeSpecLink.1.3.80 = 3020232023335100222212013221251-32500013
AiPlayerbot.PremadeSpecName.1.4 = pvp fury
AiPlayerbot.PremadeSpecLink.1.4.80 = 32003200233-325000131504012050122511351
AiPlayerbot.PremadeSpecName.1.5 = pvp prot
AiPlayerbot.PremadeSpecLink.1.5.80 = 32003200233-325000131504012050122511351
# Paladin
AiPlayerbot.PremadeSpecName.2.1 = Ret Pvp
AiPlayerbot.PremadeSpecProb.2.1 = 100
AiPlayerbot.PremadeSpecLink.2.1.80 = 05002-053201-05222150203331322133201331
AiPlayerbot.PremadeSpecName.2.2 = Prot Pvp
AiPlayerbot.PremadeSpecProb.2.2 = 100
AiPlayerbot.PremadeSpecLink.2.2.80 = -15320130223122321333312321052300500002
AiPlayerbot.PremadeSpecName.2.3 = Holy Pvp
AiPlayerbot.PremadeSpecProb.2.3 = 100
AiPlayerbot.PremadeSpecLink.2.3.80 = 503521503000131501034142215032013122
AiPlayerbot.PremadeSpecName.2.4 = Ret Pve
AiPlayerbot.PremadeSpecProb.2.4 = 100
AiPlayerbot.PremadeSpecLink.2.4.80 = 050501-05-05232051203331302133231331
AiPlayerbot.PremadeSpecName.2.5 = Prot Pve
AiPlayerbot.PremadeSpecProb.2.5 = 100
AiPlayerbot.PremadeSpecLink.2.5.80 = -050051352031323113333123215023005
AiPlayerbot.PremadeSpecName.2.6 = Holy Pve
AiPlayerbot.PremadeSpecProb.2.6 = 100
AiPlayerbot.PremadeSpecLink.2.6.80 = 503501510200130531005152215-503205
# Hunter
AiPlayerbot.PremadeSpecName.3.1 = BM Pvp
AiPlayerbot.PremadeSpecProb.3.1 = 100
AiPlayerbot.PremadeSpecLink.3.1.80 = 05203001505212233100531351005305131
AiPlayerbot.PremadeSpecName.3.2 = MM Pvp
AiPlayerbot.PremadeSpecProb.3.2 = 100
AiPlayerbot.PremadeSpecLink.3.2.80 = 052-025305101030213233115031051530020201
AiPlayerbot.PremadeSpecName.3.3 = Surv Pvp
AiPlayerbot.PremadeSpecProb.3.3 = 100
AiPlayerbot.PremadeSpecLink.3.3.80 = -005305101-3300132510233330532135001031
AiPlayerbot.PremadeSpecName.3.4 = BM Pve
AiPlayerbot.PremadeSpecProb.3.4 = 100
AiPlayerbot.PremadeSpecLink.3.4.80 = 51200201505112253100531351015305021
AiPlayerbot.PremadeSpecName.3.5 = MM Pve
AiPlayerbot.PremadeSpecProb.3.5 = 100
AiPlayerbot.PremadeSpecLink.3.5.80 = 502-0353051012300132331350313515000002
AiPlayerbot.PremadeSpecName.3.6 = Surv Pve
AiPlayerbot.PremadeSpecProb.3.6 = 100
AiPlayerbot.PremadeSpecLink.3.6.80 = -0053041-5000032500033330523134321331
# Rogue
AiPlayerbot.PremadeSpecName.4.1 = Assassination Pvp
AiPlayerbot.PremadeSpecProb.4.1 = 100
AiPlayerbot.PremadeSpecLink.4.1.80 = 005303103342102522103031000004-532023203000012
AiPlayerbot.PremadeSpecName.4.2 = Combat Pvp
AiPlayerbot.PremadeSpecProb.4.2 = 100
AiPlayerbot.PremadeSpecLink.4.2.80 = 005-3250302102205015023122021251230023013
AiPlayerbot.PremadeSpecName.4.3 = Subtlety Pvp
AiPlayerbot.PremadeSpecProb.4.3 = 100
AiPlayerbot.PremadeSpecLink.4.3.80 = 0053031-1-5020232033322121350105131251
AiPlayerbot.PremadeSpecName.4.4 = Assassination Pve
AiPlayerbot.PremadeSpecProb.4.4 = 100
AiPlayerbot.PremadeSpecLink.4.4.80 = 005323005350100520103331051005005003-502
AiPlayerbot.PremadeSpecName.4.5 = Combat Pve
AiPlayerbot.PremadeSpecProb.4.5 = 100
AiPlayerbot.PremadeSpecLink.4.5.80 = 30530000522-0252051000035015223100501251
AiPlayerbot.PremadeSpecName.4.6 = Subtlety Pve
AiPlayerbot.PremadeSpecProb.4.6 = 100
AiPlayerbot.PremadeSpecLink.4.6.80 = 0053231-2-5120222030321121050135231251
# Priest
AiPlayerbot.PremadeSpecName.5.1 = Shadow PvE
AiPlayerbot.PremadeSpecProb.5.1 = 100
AiPlayerbot.PremadeSpecLink.5.1.80 = 0503203--325023051223010323152301351
AiPlayerbot.PremadeSpecName.5.2 = Shadow PvP
AiPlayerbot.PremadeSpecProb.5.2 = 100
AiPlayerbot.PremadeSpecLink.5.2.80 = 502320013--005023251023112123152311351
AiPlayerbot.PremadeSpecName.5.3 = Disc PvE
AiPlayerbot.PremadeSpecProb.5.3 = 100
AiPlayerbot.PremadeSpecLink.5.3.80 = 050320313030051233132323125100550103
AiPlayerbot.PremadeSpecName.5.4 = Disc PvE renew build
AiPlayerbot.PremadeSpecProb.5.4 = 100
AiPlayerbot.PremadeSpecLink.5.4.80 = 050320313030051233132323125103530003
AiPlayerbot.PremadeSpecName.5.5 = Holy PvE
AiPlayerbot.PremadeSpecProb.5.5 = 100
AiPlayerbot.PremadeSpecLink.5.5.80 = 05032031-235050032302152530000331351
AiPlayerbot.PremadeSpecName.5.6 = Holy PvP
AiPlayerbot.PremadeSpecProb.5.6 = 100
AiPlayerbot.PremadeSpecLink.5.6.80 = 500320313030251233102323115120350123
# Death Knight
AiPlayerbot.PremadeSpecName.6.1 = Blood Pvp
AiPlayerbot.PremadeSpecProb.6.1 = 100
AiPlayerbot.PremadeSpecLink.6.1.80 = 20450215333033132002231313513232
AiPlayerbot.PremadeSpecName.6.2 = Unholy Pvp
AiPlayerbot.PremadeSpecProb.6.2 = 100
AiPlayerbot.PremadeSpecLink.6.2.80 = -320050410002-2301323301002152233101203103151
AiPlayerbot.PremadeSpecName.6.3 = Frost Pvp
AiPlayerbot.PremadeSpecProb.6.3 = 100
AiPlayerbot.PremadeSpecLink.6.3.80 = 0325101303-32025351052203012001033101341
AiPlayerbot.PremadeSpecName.6.4 = Blood Pve
AiPlayerbot.PremadeSpecProb.6.4 = 100
AiPlayerbot.PremadeSpecLink.6.4.80 = 0355220530003313221020131351305-0052
AiPlayerbot.PremadeSpecName.6.5 = Unholy Pve
AiPlayerbot.PremadeSpecProb.6.5 = 100
AiPlayerbot.PremadeSpecLink.6.5.80 = 23050202--2302003350032152003150003133151
AiPlayerbot.PremadeSpecName.6.6 = Frost Pve
AiPlayerbot.PremadeSpecProb.6.6 = 100
AiPlayerbot.PremadeSpecLink.6.6.80 = 03-32002350352203012300033101351230200305
# Shaman
AiPlayerbot.PremadeSpecName.7.1 = Enh Pvp
AiPlayerbot.PremadeSpecProb.7.1 = 100
AiPlayerbot.PremadeSpecLink.7.1.80 = 05032005-02305233105001333201131231251
AiPlayerbot.PremadeSpecName.7.2 = Ele Pvp
AiPlayerbot.PremadeSpecProb.7.2 = 100
AiPlayerbot.PremadeSpecLink.7.2.80 = 0533001503213051322331351-024252001
AiPlayerbot.PremadeSpecName.7.3 = Resto Pvp
AiPlayerbot.PremadeSpecProb.7.3 = 100
AiPlayerbot.PremadeSpecLink.7.3.80 = -023202301-50032331330313551120321251
AiPlayerbot.PremadeSpecName.7.4 = Enh Pve
AiPlayerbot.PremadeSpecProb.7.4 = 100
AiPlayerbot.PremadeSpecLink.7.4.80 = 053030052-30205033005021333031131131051
AiPlayerbot.PremadeSpecName.7.5 = Ele Pve
AiPlayerbot.PremadeSpecProb.7.5 = 100
AiPlayerbot.PremadeSpecLink.7.5.80 = 3530001523213351322301351005050031
AiPlayerbot.PremadeSpecName.7.6 = Resto Pve
AiPlayerbot.PremadeSpecProb.7.6 = 100
AiPlayerbot.PremadeSpecLink.7.6.80 = -00505031-50005331335310501022331251
# Mage
AiPlayerbot.PremadeSpecName.8.1 = Arcane Pvp
AiPlayerbot.PremadeSpecProb.8.1 = 100
AiPlayerbot.PremadeSpecLink.8.1.80 = 205025220122032103323102515321--203023001
AiPlayerbot.PremadeSpecName.8.2 = Fire Pvp
AiPlayerbot.PremadeSpecProb.8.2 = 100
AiPlayerbot.PremadeSpecLink.8.2.80 = 230320220122-2305022310220031243122201351
AiPlayerbot.PremadeSpecName.8.3 = Frost Pvp
AiPlayerbot.PremadeSpecProb.8.3 = 100
AiPlayerbot.PremadeSpecLink.8.3.80 = 23002322010203--3533103310203100232102231151
AiPlayerbot.PremadeSpecName.8.4 = Arcane Pve
AiPlayerbot.PremadeSpecProb.8.4 = 100
AiPlayerbot.PremadeSpecLink.8.4.80 = 23500503010023015032310250532103-203023001
AiPlayerbot.PremadeSpecName.8.5 = Fire Pve
AiPlayerbot.PremadeSpecProb.8.5 = 100
AiPlayerbot.PremadeSpecLink.8.5.80 = 23000503310003-0055030012303330053120300351
AiPlayerbot.PremadeSpecName.8.6 = Frost Arcane Pve
AiPlayerbot.PremadeSpecProb.8.6 = 100
AiPlayerbot.PremadeSpecLink.8.6.80 = 23500503110023015032310250532003-203023001
# Warlock
AiPlayerbot.PremadeSpecName.9.1 = Affli CoE Pvp
AiPlayerbot.PremadeSpecProb.9.1 = 100
AiPlayerbot.PremadeSpecLink.9.1.80 = 03500022312233110535023011510032203011302
AiPlayerbot.PremadeSpecName.9.2 = Affli CoA Pvp
AiPlayerbot.PremadeSpecProb.9.2 = 100
AiPlayerbot.PremadeSpecLink.9.2.80 = 23500022312231110535023011510032203011302
AiPlayerbot.PremadeSpecName.9.3 = Destro Pvp
AiPlayerbot.PremadeSpecProb.9.3 = 100
AiPlayerbot.PremadeSpecLink.9.3.80 = 03-0032203011302-05230015220331351005031051
AiPlayerbot.PremadeSpecName.9.4 = Demo Pve
AiPlayerbot.PremadeSpecProb.9.4 = 100
AiPlayerbot.PremadeSpecLink.9.4.80 = -00320330113520253013523134155000005
AiPlayerbot.PremadeSpecName.9.5 = Affli Pve
AiPlayerbot.PremadeSpecProb.9.5 = 100
AiPlayerbot.PremadeSpecLink.9.5.80 = 2350002030023510253500331151--550000051
AiPlayerbot.PremadeSpecName.9.6 = Destro Pve
AiPlayerbot.PremadeSpecProb.9.6 = 100
AiPlayerbot.PremadeSpecLink.9.6.80 = -03310030003-05203205210331051335230351
AiPlayerbot.PremadeSpecName.9.7 = Demo Pve
AiPlayerbot.PremadeSpecProb.9.7 = 100
AiPlayerbot.PremadeSpecLink.9.7.80 = -00320330113520253013523134155-5
# Druid
AiPlayerbot.PremadeSpecName.11.1 = Feral shred Pvp
AiPlayerbot.PremadeSpecProb.11.1 = 100
AiPlayerbot.PremadeSpecLink.11.1.80 = -55020213232021205312301331051100550101
AiPlayerbot.PremadeSpecName.11.2 = Feral 1v1 Pvp
AiPlayerbot.PremadeSpecProb.11.2 = 100
AiPlayerbot.PremadeSpecLink.11.2.80 = -53020213032021205312303331351100550001
AiPlayerbot.PremadeSpecName.11.3 = Balance Pvp
AiPlayerbot.PremadeSpecProb.11.3 = 100
AiPlayerbot.PremadeSpecLink.11.3.80 = 5022203125331003213035311231--230033012
AiPlayerbot.PremadeSpecName.11.4 = Resto Pvp
AiPlayerbot.PremadeSpecProb.11.4 = 100
AiPlayerbot.PremadeSpecLink.11.4.80 = 5532000120321--230033312031502221350013200
AiPlayerbot.PremadeSpecName.11.5 = Feral dps Pve
AiPlayerbot.PremadeSpecProb.11.5 = 100
AiPlayerbot.PremadeSpecLink.11.5.80 = -550202132322010053120030312511005503012
AiPlayerbot.PremadeSpecName.11.6 = Feral Tank Pve
AiPlayerbot.PremadeSpecProb.11.6 = 100
AiPlayerbot.PremadeSpecLink.11.6.80 = -50123213032211035312030331351120350001
AiPlayerbot.PremadeSpecName.11.7 = Balance Pve
AiPlayerbot.PremadeSpecProb.11.7 = 100
AiPlayerbot.PremadeSpecLink.11.7.80 = 5012203125331103213305301231--205003212
AiPlayerbot.PremadeSpecName.11.8 = Restro Pve
AiPlayerbot.PremadeSpecProb.11.8 = 100
AiPlayerbot.PremadeSpecLink.11.8.80 = 05320001--230033312031512531153313051
# Prefix for bot chat commands (e.g. follow, stay)
AiPlayerbot.CommandPrefix = ""
# Separator for bot chat commands
AiPlayerbot.CommandSeparator = "\\\\"
# Max AI iterations per tick
AiPlayerbot.IterationsPerTick = 100
# Allow/deny bots from your guild
AiPlayerbot.AllowGuildBots = 1
# Delay between two short-time spells cast
AiPlayerbot.GlobalCooldown = 1500
# Max wait time when moving
AiPlayerbot.MaxWaitForMove = 5000
# Action expiration time
AiPlayerbot.ExpireActionTime = 5000
# Max dispel auras duration
AiPlayerbot.DispelAuraDuration = 7000
# Delay between two bot actions
AiPlayerbot.ReactDelay = 500
# Inactivity delay
AiPlayerbot.PassiveDelay = 10000
# Minimum delay between repeating actions (chat messages, emotes etc)
AiPlayerbot.RepeatDelay = 5000
# Delay timers
AiPlayerbot.ErrorDelay = 5000
AiPlayerbot.RpgDelay = 10000
AiPlayerbot.SitDelay = 30000
AiPlayerbot.ReturnDelay = 7000
AiPlayerbot.LootDelay = 1000
# Distances
AiPlayerbot.FarDistance = 20.0
AiPlayerbot.SightDistance = 75.0
AiPlayerbot.SpellDistance = 22.0
AiPlayerbot.ShootDistance = 25.0
AiPlayerbot.ReactDistance = 150.0
AiPlayerbot.GrindDistance = 75.0
AiPlayerbot.HealDistance = 20.0
AiPlayerbot.LootDistance = 15.0
AiPlayerbot.FleeDistance = 7.5
AiPlayerbot.TooCloseDistance = 5.0
AiPlayerbot.MeleeDistance = 1.5
AiPlayerbot.FollowDistance = 1.5
AiPlayerbot.WhisperDistance = 6000.0
AiPlayerbot.ContactDistance = 0.5
AiPlayerbot.AoeRadius = 5
AiPlayerbot.RpgDistance = 200
AiPlayerbot.AggroDistance = 22
# Bot can flee for enemy
AiPlayerbot.FleeingEnabled = 1
# Health/Mana levels
AiPlayerbot.CriticalHealth = 20
AiPlayerbot.LowHealth = 45
AiPlayerbot.MediumHealth = 65
AiPlayerbot.AlmostFullHealth = 85
AiPlayerbot.LowMana = 15
AiPlayerbot.MediumMana = 40
# Random bot default strategies (applied after defaults)
AiPlayerbot.RandomBotCombatStrategies = "-threat"
AiPlayerbot.RandomBotNonCombatStrategies = ""
AiPlayerbot.CombatStrategies = "+custom::say"
AiPlayerbot.NonCombatStrategies = "+custom::say,+return"
# How often tasks are changed
AiPlayerbot.MinGuildTaskChangeTime = 172800
AiPlayerbot.MaxGuildTaskChangeTime = 432000
# Mail spam interval
AiPlayerbot.MinGuildTaskAdvertisementTime = 300
AiPlayerbot.MaxGuildTaskAdvertisementTime = 43200
# Delay before reward is sent
AiPlayerbot.MinGuildTaskRewardTime = 300
AiPlayerbot.MaxGuildTaskRewardTime = 3600
# Cleanup of guild tasks interval
AiPlayerbot.GuildTaskAdvertCleanupTime = 300
# Specify max distance between victim and bot when creating guild kill task
AiPlayerbot.GuildTaskKillTaskDistance = 2000
# Distance margin for facade calculations
AiPlayerbot.TargetPosRecalcDistance = 0.1
# Maps where bots can be teleported to
AiPlayerbot.RandomBotMaps = 0,1,530,571
# Quest items to leave (do not destroy)
AiPlayerbot.RandomBotQuestItems = "6948,5175,5176,5177,5178,16309,12382,13704,11000""
# PvP Restricted Zones (bots don't pvp)
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""
# Spells every random bot will learn on randomize (54197 - cold weather flying)
AiPlayerbot.RandomBotSpellIds = "1""
# Level diff between random bots and nearby creatures for random teleports
AiPlayerbot.RandomBotTeleLevel = 5
# ID of spell to open lootable chests
AiPlayerbot.OpenGoSpell = 6477
# Intervals
AiPlayerbot.RandomBotUpdateInterval = 60
AiPlayerbot.RandomBotCountChangeMinInterval = 1800
AiPlayerbot.RandomBotCountChangeMaxInterval = 7200
AiPlayerbot.MinRandomBotInWorldTime = 7200
AiPlayerbot.MaxRandomBotInWorldTime = 43200
AiPlayerbot.MinRandomBotRandomizeTime = 7200
AiPlayerbot.MaxRandomRandomizeTime = 1209600
AiPlayerbot.RandomBotsPerInterval = 60
AiPlayerbot.MinRandomBotsPriceChangeInterval = 7200
AiPlayerbot.MaxRandomBotsPriceChangeInterval = 172800
AiPlayerbot.MinRandomBotChangeStrategyTime = 1800
AiPlayerbot.MaxRandomBotChangeStrategyTime = 7200
AiPlayerbot.MinRandomBotReviveTime = 60
AiPlayerbot.MaxRandomBotReviveTime = 300
# How far random bots are teleported after death
AiPlayerbot.RandomBotTeleportDistance = 100
# Debug switches
AiPlayerbot.SpellDump = 0
AiPlayerbot.LogInGroupOnly = 1
AiPlayerbot.LogValuesPerTick = 0
AiPlayerbot.RandomChangeMultiplier = 1
# Command server port, 0 - disabled
AiPlayerbot.CommandServerPort = 8888
# Enables/Disables performance monitor
AiPlayerbot.PerfMonEnabled = 0
# Allow bots to be summoned near innkeepers
AiPlayerbot.SummonAtInnkeepersEnabled = 1
# Custom config to allow logfiles to be created.
# Example: AiPlayerbot.AllowedLogFiles = travelNodes.csv,travelPaths.csv,TravelNodeStore.h,bot_movement.csv,bot_location.csv
AiPlayerbot.AllowedLogFiles = ""
# Applies a permanent buff to all bots.
# WorldBuff.Faction.Class.MinLevel.MaxLevel
# Added following config
# Selfbot permission level (0 = disabled, 1 = gm only (default), 2 = all players, 3 = activate on login) # AiPlayerbot.SelfBotLevel = 1
AiPlayerbot.SelfBotLevel = 1
# Enables/Disables bot cheating
AiPlayerbot.BotCheats = "taxi"
# Enables/Disables password to bot account
AiPlayerbot.RandomBotRandomPassword = 1
##################################################################################
# #
# Database Stuff #
# #
##################################################################################
#
# PlayerbotsDatabaseInfo
# Description: Database connection settings for the playerbots server.
# Example: "hostname;port;username;password;database"
# ".;somenumber;username;password;database" - (Use named pipes on Windows
# "enable-named-pipe" to [mysqld]
# section my.ini)
# ".;/path/to/unix_socket;username;password;database" - (use Unix sockets on
# Unix/Linux)
# Default: "127.0.0.1;3306;acore;acore;acore_playerbots" - (PlayerbotDatabaseInfo)
PlayerbotsDatabaseInfo = "127.0.0.1;3306;acore;acore;acore_playerbots"
#
# PlayerbotsDatabase.WorkerThreads
# Description: The amount of worker threads spawned to handle asynchronous (delayed) MySQL
# statements. Each worker thread is mirrored with its own connection to the
# MySQL server and their own thread on the MySQL server.
# Default: 1 - (PlayerbotsDatabase.WorkerThreads)
PlayerbotsDatabase.WorkerThreads = 1
#
# PlayerbotsDatabase.SynchThreads
# Description: The amount of MySQL connections spawned to handle.
# Default: 1 - (PlayerbotDatabase.WorkerThreads)
PlayerbotsDatabase.SynchThreads = 1
# Playerbot.Updates.EnableDatabases
# Description: Determined if updates system work with playerbot database.
#
# Default: 1 - (Enabled)
# 0 - (Disabled)
Playerbots.Updates.EnableDatabases = 1
#
##################################################################################
# #
# Logging Stuff #
# #
##################################################################################
Appender.Playerbots=2,5,0,Playerbots.log,w
Logger.playerbots=5,Playerbots

View File

@ -1,10 +1,10 @@
#!/usr/bin/env bash
## GETS THE CURRENT MODULE ROOT DIRECTORY
MOD_SKELETON_ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )/" && pwd )"
MOD_PLAYERBOTS_ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )/" && pwd )"
source $MOD_SKELETON_ROOT"/conf/conf.sh.dist"
source $MOD_PLAYERBOTS_ROOT"/conf/conf.sh.dist"
if [ -f $MOD_SKELETON_ROOT"/conf/conf.sh" ]; then
source $MOD_SKELETON_ROOT"/conf/conf.sh"
if [ -f $MOD_PLAYERBOTS_ROOT"/conf/conf.sh" ]; then
source $MOD_PLAYERBOTS_ROOT"/conf/conf.sh"
fi

View File

@ -1,3 +0,0 @@
-- Put only sql data in this file (insert, update, replace into, delete etc...).
-- If you don't use this database, then delete this file.
-- If no data, just delete this file.

View File

@ -1,3 +0,0 @@
-- Put only sql data in this file (insert, update, replace into, delete etc...).
-- If you don't use this database, then delete this file.
-- If no data, just delete this file.

View File

@ -1,2 +0,0 @@
-- Put only sql structure in this file (create table if exists, delete table, alter table etc...).
-- If you don't use this database, then delete this file.

View File

@ -1,3 +0,0 @@
-- Put only sql data in this file (insert, update, replace into, delete etc...).
-- If you don't use this database, then delete this file.
-- If no data, just delete this file.

View File

@ -1,3 +0,0 @@
-- Put only sql data in this file (insert, update, replace into, delete etc...).
-- If you don't use this database, then delete this file.
-- If no data, just delete this file.

View File

@ -1,2 +0,0 @@
-- Put only sql structure in this file (create table if exists, delete table, alter table etc...).
-- If you don't use this database, then delete this file.

View File

@ -0,0 +1,626 @@
DROP TABLE IF EXISTS `playerbot_arena_team_names`;
CREATE TABLE `playerbot_arena_team_names` (
`name_id` mediumint(8) NOT NULL AUTO_INCREMENT UNIQUE,
`name` varchar(24) NOT NULL UNIQUE,
`type` TINYINT(3) NOT NULL,
PRIMARY KEY (`name_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Playerbot arena team names';
DELETE FROM `playerbot_arena_team_names`;
INSERT INTO `playerbot_arena_team_names` (`name_id`,`name`, `type`) VALUES
(NULL, 'out of coverage',2),
(NULL, 'Dead or Alive',2),
(NULL, 'Noßrain',2),
(NULL, 'Истребление',2),
(NULL, 'Pieces',2),
(NULL, 'ßurst',2),
(NULL, 'hey im actually not mvp',2),
(NULL, 'Group Therapy',2),
(NULL, 'Outland Elite',2),
(NULL, 'Исчадье Тьмы',2),
(NULL, 'Dun Spetsnaz',2),
(NULL, 'ЧСВ РБГ',2),
(NULL, 'ShameReborn',2),
(NULL, 'TEAM VÉSUVE',2),
(NULL, 'Battle for Apes',2),
(NULL, 'Can You Feel It',2),
(NULL, 'Zero to Hero',2),
(NULL, 'Link Curve',2),
(NULL, 'Project',2),
(NULL, 'Security',2),
(NULL, 'Skill Loading',2),
(NULL, 'Cya Bro',2),
(NULL, 'out of rage',2),
(NULL, 'Improve',2),
(NULL, 'WORST GENERATION',2),
(NULL, 'KFC Fitness Club',2),
(NULL, 'unlucky',2),
(NULL, 'OldStyle',2),
(NULL, 'Walkthrough',2),
(NULL, 'Лё Резистанс',2),
(NULL, 'League of Gladiators',2),
(NULL, 'Practice',2),
(NULL, 'Rofl So Bad',2),
(NULL, 'Synergy',2),
(NULL, 'Que la famille',2),
(NULL, 'Древние баги',2),
(NULL, 'Echo',2),
(NULL, 'KARMA',2),
(NULL, 'Exodus',2),
(NULL, 'Felsenfest',2),
(NULL, 'LifeIsPain',2),
(NULL, 'The Eternal',2),
(NULL, 'Raid Trap',2),
(NULL, 'The Dambusters',2),
(NULL, 'Станция Токсичных',2),
(NULL, 'Cykla Blöt',2),
(NULL, 'Ethics',2),
(NULL, 'Human ZOO',2),
(NULL, 'Mausoleum',2),
(NULL, 'Nashwan GoDs',2),
(NULL, 'PASTIS PETANQUE ARENE',2),
(NULL, 'tweet holinka',2),
(NULL, 'Пять Бутылок Водки',2),
(NULL, 'РЕТРИК РУКИ ПОЛТОРАШКИ',2),
(NULL, 'У беляша',2),
(NULL, 'A M K',2),
(NULL, 'Against The WorId',2),
(NULL, 'Dilemma',2),
(NULL, 'Efficiency',2),
(NULL, 'Halcyon',2),
(NULL, 'I SoliD I',2),
(NULL, 'Impact',2),
(NULL, 'Melk Trupp',2),
(NULL, 'Tatortreiniger',2),
(NULL, 'TG Gaming',2),
(NULL, 'Without a Trace',2),
(NULL, 'Fysikbasserne',3),
(NULL, 'Helion',3),
(NULL, 'Twix',3),
(NULL, 'Unethical',3),
(NULL, 'Advance',3),
(NULL, 'Arctic Avengers',3),
(NULL, 'E V O L U T I O N',3),
(NULL, 'FOR THE ALLÎANCE',3),
(NULL, 'Insanity',3),
(NULL, 'Integrity',3),
(NULL, 'Oderant',3),
(NULL, 'P G',3),
(NULL, 'PMA',3),
(NULL, 'Revoke',3),
(NULL, 'stay hydrated',3),
(NULL, 'Sum optime',3),
(NULL, 'Team Sweden',3),
(NULL, 'Two Ghouls One Cup',3),
(NULL, 'Vous ne passerez pas',3),
(NULL, 'Øgma Tuatha',3),
(NULL, 'Адская Орда',3),
(NULL, 'Селфлесс',3),
(NULL, 'Чёрный Лотос',3),
(NULL, 'Crown',3),
(NULL, 'Distopia',3),
(NULL, 'FatSharkYes',3),
(NULL, 'Feed',3),
(NULL, 'Myst',3),
(NULL, 'Slack',3),
(NULL, 'Team Fight',3),
(NULL, 'The Haunted',3),
(NULL, 'Unicornz',3),
(NULL, 'В КОЛХОЗ ЗА ПЕТУХАМИ',3),
(NULL, 'THE MOVE',3),
(NULL, 'SSEN',3),
(NULL, 'Mørdor',3),
(NULL, 'one lesson per day',3),
(NULL, 'ddosed',3),
(NULL, 'hey im mvp',3),
(NULL, 'Still On Sargeras',3),
(NULL, 'ddosedx',3),
(NULL, 'Cyber Athletes',3),
(NULL, 'Gnomeland Security',3),
(NULL, 'ad hoc',3),
(NULL, 'slash spit',3),
(NULL, 'Suppy',3),
(NULL, 'Crimson Dragon',3),
(NULL, 'The Syndicate',3),
(NULL, 'Blur',3),
(NULL, 'tEh mOve',3),
(NULL, 'Cherry Pink',3),
(NULL, 'Honestly',3),
(NULL, 'Disney World',3),
(NULL, 'poptart corndoG',3),
(NULL, 'See Again Solitary',3),
(NULL, 'Infinity',3),
(NULL, 'BIG DAM',3),
(NULL, 'Ethical',3),
(NULL, 'BloodBoùnd',3),
(NULL, 'Show Me How',3),
(NULL, 'dog squad',3),
(NULL, 'Zandalari Bobsled Team',3),
(NULL, 'Goons Goonies',3),
(NULL, 'Legacy of the Alliance',3),
(NULL, 'Spiral Out',3),
(NULL, 'Melt',3),
(NULL, 'Last Attempt',3),
(NULL, 'Nolifer',3),
(NULL, 'RBG Hero',5),
(NULL, 'Medium',5),
(NULL, 'Nascent',5),
(NULL, 'M E R C I L E S S',5),
(NULL, 'Team Thougs',5),
(NULL, 'Verdict',5),
(NULL, 'CMG',5),
(NULL, 'Dishonorable Kill',5),
(NULL, 'Knights Who Say Yee',5),
(NULL, 'Restricted',5),
(NULL, 'Vile',5),
(NULL, 'Nemesis',5),
(NULL, 'Oasis',5),
(NULL, 'The Depraved',5),
(NULL, 'didnt ask',5),
(NULL, 'Epic Gamers',5),
(NULL, 'Essence',5),
(NULL, 'i love slicedbaka',5),
(NULL, 'Lights Oath',5),
(NULL, 'M Y T H I C C',5),
(NULL, 'Major Pain',5),
(NULL, 'Dads Against Vaping',5),
(NULL, 'No Skill',5),
(NULL, 'The Degenerates',5),
(NULL,'Boralus Yacht Club',5),
(NULL, 'Censored',5),
(NULL, 'Defenestrate',5),
(NULL, 'HATE DIVISION',5),
(NULL, 'hi',5),
(NULL, 'Ironsworn Regiment',5),
(NULL, 'is kinda like god',5),
(NULL, 'Temerity',5),
(NULL, 'The Pantheon NB',5),
(NULL, 'Vision',5),
(NULL, 'Baddies',5),
(NULL, 'Complexity Limit',5),
(NULL, 'Dark Clan of Fenris',5),
(NULL, 'Elite Horde',5),
(NULL, 'Makin a Bagel',5),
(NULL, 'Nimue',5),
(NULL, 'Ran Thru',5),
(NULL, 'Sin',5),
(NULL, 'VØDKA SØCIETY',5),
(NULL, 'Wizards and Monkeys',5),
(NULL, 'Is cute AF',5),
(NULL, 'Reckless Ambition',5),
(NULL, 'Solidarity Gaming',5),
(NULL, 'Spike Flail',5),
(NULL, 'Vexation',5),
(NULL, 'Hungry Wolves',5),
(NULL, 'Peel Team Six',5),
(NULL, 'Polaris',5),
(NULL, 'rest easy criter',5),
(NULL, 'Scripted',5),
(NULL, 'TAG',5),
(NULL, 'toXique',5),
(NULL, 'who are you talkin to',5),
(NULL, 'CRvillains',5),
(NULL, 'Decapodian',5),
(NULL, 'Fierce',5),
(NULL, 'Glad to see you',5),
(NULL, 'Impression',5),
(NULL, 'Nerd Rage',5),
(NULL, 'The Art of War',5),
(NULL, 'Wisdom',5),
(NULL, 'Against',2),
(NULL, 'Dot Run Profit',2),
(NULL, 'Fluffy Doods of Doom',2),
(NULL, 'Dot Pillar Profit',2),
(NULL, 'Team GG',2),
(NULL, 'Paizuri',2),
(NULL, 'Plz i need',2),
(NULL, 'shadow resist last week',2),
(NULL, 'shen diao xia lv',2),
(NULL, 'Speechless',2),
(NULL, 'Pandaninja Team',2),
(NULL, 'Kettes Ninja',2),
(NULL, 'PROXIMO',2),
(NULL, 'System Down',2),
(NULL, 'Hakuna matata',2),
(NULL, 'Freshly Baked',2),
(NULL, 'Abandon All Hope',2),
(NULL, 'GIEF UR POINTS PLX',2),
(NULL, 'Schobbejakken',2),
(NULL, 'Our team got deleted',2),
(NULL, 'Chocolate fingers',2),
(NULL, 'Wet Dreams',2),
(NULL, 'Vissnar er skit',2),
(NULL, 'Holla Fo Da Top Dolla',2),
(NULL, 'WTS Taran Icebreaker',2),
(NULL, 'Copenhagen eSports',2),
(NULL, 'SWE HORDE',2),
(NULL, 'I Touch Myself',2),
(NULL, 'Kines Jaegarna',2),
(NULL, 'Greek SOUVLAKI',2),
(NULL, 'Halinallet',2),
(NULL, 'TELLME WHEN THEY TRINKE',2),
(NULL, 'Team Obie',2),
(NULL, 'weh',2),
(NULL, 'Coconat Crew',2),
(NULL, 'DISPEL DUXE',2),
(NULL, 'Aftermath of GeekBoys',2),
(NULL, 'RockStarz',2),
(NULL, 'Triple Penetration',2),
(NULL, 'Abandoned hope',2),
(NULL, 'Againandagain',2),
(NULL, 'WTFGON',2),
(NULL, 'Chill',2),
(NULL, 'SUPERPVPPOWER',2),
(NULL, 'Funky ShEt',2),
(NULL, 'Cyclone it and Run',2),
(NULL, 'Mante and Alvi',2),
(NULL, 'Toku was off',2),
(NULL, 'BOOMHEADSHOT',2),
(NULL, 'Beer',2),
(NULL, 'Will you marry Me',2),
(NULL, 'Razer was a piece of St',2),
(NULL, 'More Dots',2),
(NULL, 'SuirotkiV',2),
(NULL, 'Celguar and Mostlikely',2),
(NULL, 'You got PWNed',2),
(NULL, 'Lido and Nonuse',2),
(NULL, 'I Am Your Father',2),
(NULL, 'TO XRYSO KOUFETO',2),
(NULL, 'FourKings',2),
(NULL, 'Dont hate the player',2),
(NULL, 'LF akashis replacement',2),
(NULL, 'Found Your Cookies',2),
(NULL, 'manglecritTIOtysen',2),
(NULL, 'For sale',2),
(NULL, 'Pirates',2),
(NULL, 'råttakuninkaat',2),
(NULL, 'DotaAPgogo',2),
(NULL, 'Has gone offline',2),
(NULL, 'Hide your Cookies',2),
(NULL, 'Player Hater Foundation',2),
(NULL, 'Something new',2),
(NULL, 'asdklfjkläasdhjkla',2),
(NULL, 'Ignorance is Bliss',2),
(NULL, 'Spellbook OPEN',2),
(NULL, 'BIG SMITING MACHINE',2),
(NULL, 'The Five Musketeers',2),
(NULL, 'Proximity',2),
(NULL, 'Artefakt',2),
(NULL, 'Devastation',2),
(NULL, 'Spawn more Overlords',2),
(NULL, 'We only log on for arena',2),
(NULL, 'Come Honour Face',2),
(NULL, 'High Caliberr',2),
(NULL, 'Wildhammer',2),
(NULL, 'We dont like Arena',2),
(NULL, 'No mercy for the noobs',2),
(NULL, 'we loose because of exor',2),
(NULL, 'Hit Me Hard',2),
(NULL, 'Variksen Orjat',2),
(NULL, 'Jumalauta',2),
(NULL, 'Baqa lack skills',2),
(NULL, 'The Crackheads',2),
(NULL, 'Me Smash You',2),
(NULL, 'Over the Top',2),
(NULL, 'We like cookies',2),
(NULL, 'Devil wears SRada',2),
(NULL, 'Healing Misery',2),
(NULL, 'Just gear',2),
(NULL, 'Mystical Is Fat Dorf IRL',2),
(NULL, 'DISPELL ME PLZ',2),
(NULL, 'Death Note',2),
(NULL, 'Wicked Grin',2),
(NULL, 'Analnie Oduvanchiki',2),
(NULL, 'eru bränd lr',2),
(NULL, 'we lose coz schade sux',2),
(NULL, 'forte gaming',2),
(NULL, 'Blitzkrieg Platoon',2),
(NULL, 'CC Inc',2),
(NULL, 'Razerium',2),
(NULL, 'Crusty Farmers',2),
(NULL, 'Unrated',2),
(NULL, 'jag grindar för guld',2),
(NULL, 'Razor',2),
(NULL, 'Sarahs Evil Minions',2),
(NULL, 'Brutal Team',2),
(NULL, 'apekatt',2),
(NULL, 'Diekmann',2),
(NULL, 'Balanced Combo',2),
(NULL, 'Team of Lolroots',2),
(NULL, 'Ajs is ubernoob',2),
(NULL, 'Snowy gryphon',2),
(NULL, 'steady hand',2),
(NULL, 'Imbanuke',2),
(NULL, 'Hello I like you',2),
(NULL, 'Pallokala',2),
(NULL, 'PuG And Pray',3),
(NULL, 'DoT BoTs',3),
(NULL, 'Italianstyle',3),
(NULL, 'Fear Inc',3),
(NULL, 'We survived Gnomeregan',3),
(NULL, 'Three Mighty Mice',3),
(NULL, 'Murlox',3),
(NULL, 'Poon',3),
(NULL, 'Manbearpig',3),
(NULL, 'Yea we lift',3),
(NULL, 'PuG KZ Fans',3),
(NULL, 'Abandoned',3),
(NULL, 'Rinse And Repeat',3),
(NULL, 'WHATS GOING ON',3),
(NULL, 'Chillside',3),
(NULL, 'SUPERPVEPOWER',3),
(NULL, 'Juicy Guys',3),
(NULL, 'Cyclone and Run',3),
(NULL, 'Check and Mate',3),
(NULL, 'CC to Death',3),
(NULL, 'two gimps and mighty pet',3),
(NULL, 'Boulderfist Geeks',3),
(NULL, 'Sap and Consecration',3),
(NULL, 'Rusty Robocop',3),
(NULL, 'More Dots Plx',3),
(NULL, 'kARVAKAMUT',3),
(NULL, 'Your face',3),
(NULL, 'You got Stoneformed',3),
(NULL, 'fluffy evil bunnies',3),
(NULL, 'watrox elemental iceblox',3),
(NULL, 'Serotonine',3),
(NULL, 'Imbalanced',3),
(NULL, 'inYaface',3),
(NULL, 'lol we liek pie',3),
(NULL, 'Pat Sharp Celebrity DJ',3),
(NULL, 'Eighty gold WTF',3),
(NULL, 'Righteous Rage',3),
(NULL, 'momma said knock you out',3),
(NULL, 'TeletabiTransformers',3),
(NULL, 'Team Murloc',3),
(NULL, 'GK',3),
(NULL, 'kayfour',3),
(NULL, 'we loose cos spraaty sux',3),
(NULL, 'Infected Infinity',3),
(NULL, 'Demogorgon sux',3),
(NULL, 'My mate sux',3),
(NULL, 'Set to Kill',3),
(NULL, 'Team China',3),
(NULL, 'schlag',3),
(NULL, 'klops',3),
(NULL, 'HAF A NAIS CUP O MANGEL',3),
(NULL, 'Mantrain of Love',3),
(NULL, 'The Light Embrace',3),
(NULL, 'Team Glasmastarn',3),
(NULL, 'Dwarf Wet Tshirt Team',3),
(NULL, 'Tur med Vädret INC',3),
(NULL, 'Dumb Dumber Dimtim',3),
(NULL, 'Büdösbunkók',3),
(NULL, 'ze germans are coming',3),
(NULL, 'XND',3),
(NULL, 'Hooked up by LFG chat',3),
(NULL, 'KaplA',3),
(NULL, 'The Perfect Storm',3),
(NULL, 'ashwjzrwtficantmove',3),
(NULL, 'Strawberry',3),
(NULL, 'Three Ladies',3),
(NULL, 'I Dont Know',3),
(NULL, 'Our warrior cant do dmg',3),
(NULL, 'Lockout',3),
(NULL, 'Scrubs',3),
(NULL, 'Tarmed',3),
(NULL, 'Knockout',3),
(NULL, 'Trollout',3),
(NULL, 'Midgets and Co',3),
(NULL, 'toy soldiers',3),
(NULL, 'Your Nightmare',3),
(NULL, 'lack of experience',3),
(NULL, 'socialbidrag',3),
(NULL, 'Sweep The Leg',3),
(NULL, 'YourMomIsAnEpicMount',3),
(NULL, 'Captain Birdseye',3),
(NULL, 'Wasted Talent',3),
(NULL, 'Hammer Time',3),
(NULL, 'Really Powerful PvP',3),
(NULL, 'TESTOVOIMAA',3),
(NULL, 'Reptile in my Pants',3),
(NULL, 'Insert Coin',3),
(NULL, 'Vixens',3),
(NULL, 'Keyboard Blackbelts',3),
(NULL, 'Giggity',3),
(NULL, 'Landoo',3),
(NULL, 'GG MAN',3),
(NULL, 'excrucio',3),
(NULL, 'Recklessness',3),
(NULL, 'envious',3),
(NULL, 'Mordbrenner',3),
(NULL, 'not my account',3),
(NULL, 'Wir ausm Märchenland',3),
(NULL, 'Erdbeerwochen',3),
(NULL, 'Vierundzwanzig sieben',3),
(NULL, 'PiDaBeLJueNDi',3),
(NULL, 'Target was friendly',3),
(NULL, 'Straight Outta Pjöngjang',3),
(NULL, 'Y not',3),
(NULL, 'Infamous',3),
(NULL, 'NullachtfünfzehneR',5),
(NULL, 'Dunkle Schar',5),
(NULL, 'Flex',5),
(NULL, 'Chîkara',5),
(NULL, 'because size does matter',5),
(NULL, 'wir ownen euch JETZT',5),
(NULL, 'three bathing beauties',5),
(NULL, 'Straight Outta Timbuktu',5),
(NULL, 'Keyboard Turnerrizor',5),
(NULL, 'dinosekz',5),
(NULL, '',5),
(NULL, 'Boondock Pandas',5),
(NULL, 'perfect',5),
(NULL, 'Dracorex',5),
(NULL, 'Annihilation',5),
(NULL, 'X files',5),
(NULL, 'Kuschlig weich',5),
(NULL, 'Arcanum',5),
(NULL, 'fatalis drei',5),
(NULL, 'Psyms Team',5),
(NULL, 'Push it to the Límit',5),
(NULL, 'MassacreGamingDotCom',5),
(NULL, 'need equip',5),
(NULL, 'First Kill',5),
(NULL, 'Sand in der Vaseline',5),
(NULL, 'Panda',5),
(NULL, 'Eradication Instincts',5),
(NULL, 'eMiNeNCe',5),
(NULL, 'O M F G ICH ZERHACK DICH',5),
(NULL, 'foresighted',5),
(NULL, 'heavy petting zoo',5),
(NULL, 'Pew Pew Laser',5),
(NULL, 'OMFG ICH ZERHACK DICH II',5),
(NULL, 'Maustilicious',5),
(NULL, 'FAQ',5),
(NULL, 'Dreist',5),
(NULL, 'Höllenflämmchen',5),
(NULL, 'five mins no rush',5),
(NULL, 'Sarang',5),
(NULL, 'Die Wiederkäuer',5),
(NULL, 'Schäfchen reloaded',5),
(NULL, 'excellent',5),
(NULL, 'Abyza',5),
(NULL, 'n to the p',5),
(NULL, 'haRdcorE baSh',5),
(NULL, 'TeaM LoTTo',5),
(NULL, 'Shattered Hand says hi',5),
(NULL, 'Troll Cat',5),
(NULL, 'Hilgrim INC',5),
(NULL, 'Panda Assault',5),
(NULL, 'Enter Victory',5),
(NULL, 'Hung like a Cow',5),
(NULL, 'Sangis Cobras',5),
(NULL, 'Team Failure',5),
(NULL, 'Viva Pinatas',5),
(NULL, 'Blood Brothers',5),
(NULL, 'Swomp Was Here',5),
(NULL, 'ÆNima',5),
(NULL, 'Team Poison',5),
(NULL, 'WTB Flying Pink Elephant',5),
(NULL, 'Thiz is a mans world',5),
(NULL, 'Ri',5),
(NULL, 'Poison',5),
(NULL, 'BARE AND PLATE',5),
(NULL, 'Skuggelaget',5),
(NULL, 'Le Pinatas',5),
(NULL, 'Finish Him',5),
(NULL, 'Gentle Seduction',5),
(NULL, 'Warrior Mage Paladin',5),
(NULL, 'Haha',5),
(NULL, 'NewtypE',5),
(NULL, 'Mazinger Z',5),
(NULL, 'Triple Impact',5),
(NULL, 'Me lieK',5),
(NULL, 'beep beep i am jeep',5),
(NULL, 'Imprudent',5),
(NULL, 'Galaxy Angel Team',5),
(NULL, 'IceCrown',5),
(NULL, 'Nba',5),
(NULL, 'We fight for pie',5),
(NULL, 'OK',5),
(NULL, 'Randoms',5),
(NULL, 'Wanna Be',5),
(NULL, 'WANNA GO UBRS NVM AB LOL',5),
(NULL, 'Deadly n Stuff',5),
(NULL, 'Shadow Vulnerability',5),
(NULL, 'Occult',5),
(NULL, 'Crab People',5),
(NULL, 'ena xeri kai ena podi',5),
(NULL, 'OutPlayed',5),
(NULL, 'No Life',5),
(NULL, 'Shadows Edge',5),
(NULL, 'Durotar Fight Club',5),
(NULL, 'Warriors are easy',5),
(NULL, 'Shatter',5),
(NULL, 'Powerhouse',5),
(NULL, 'Higitus Figitus',5),
(NULL, 'RIP',5),
(NULL, 'TSoG',5),
(NULL, 'JUSTINS ENTOURAGE',5),
(NULL, 'Guess Who',5),
(NULL, 'Feeders Club',5),
(NULL, 'Crab Pupils',5),
(NULL, 'lol its a bird',5),
(NULL, 'Deaf In Texas',5),
(NULL, 'Millenium',5),
(NULL, 'Les Pores',5),
(NULL, 'No need War',5),
(NULL, 'Overall',5),
(NULL, 'WeLoseCozLweySux',5),
(NULL, 'Epik Boyz de Lumière',5),
(NULL, 'Himalaya',5),
(NULL, 'Take it deep RETURNZ',5),
(NULL, 'Gangrenaab',5),
(NULL, 'Millenium Stylz',5),
(NULL, 'Where is my umbrella',5),
(NULL, 'Esport LOL',5),
(NULL, 'HARDCORE UNITED',5),
(NULL, 'Korean Wannabe',5),
(NULL, 'Nétalïon',5),
(NULL, 'Mega Jaunes volume Deux',5),
(NULL, 'Impending Doom',5),
(NULL, 'Les Poulets Fringuants',5),
(NULL, 'Kool and teh Gank',5),
(NULL, 'Mille Margoulins',5),
(NULL, 'Naabz',5),
(NULL, 'Need du stuff plz',5),
(NULL, 'Typhoon',5),
(NULL, 'A new Begining',5),
(NULL, 'Est',5),
(NULL, 'Les Rois Mages',5),
(NULL, 'WeLooseCuzImoSux',5),
(NULL, 'WeLozCozShamSuX',5),
(NULL, 'WeLoseCuzNetherSux',5),
(NULL, 'eXecut Him',5),
(NULL, 'Økra est unstuff',5),
(NULL, 'WeLoseCauzNetherSux',5),
(NULL, 'WeLoseCozVixcisSux',5),
(NULL, 'RAT',5),
(NULL, 'a A a Arena',5),
(NULL, 'OMG',5),
(NULL, 'NoraJ ThX',5),
(NULL, 'Tendresse et calin',5),
(NULL, 'Laming is not a crime',5),
(NULL, 'Over',5),
(NULL, 'You love it',5),
(NULL, 'Naturiste Dance',5),
(NULL, 'Dead Breed',5),
(NULL, 'To lazy',5),
(NULL, 'CN',5),
(NULL, 'Burn Mana',5),
(NULL, 'A vendre',5),
(NULL, 'We Lose Cuz Kisame Sux',5),
(NULL, 'Pestis Atra',5),
(NULL, 'Un vs deux',5),
(NULL, 'Pwee Pwee BOUM',5),
(NULL, 'Gnomette Team',5),
(NULL, 'Croque plz',5),
(NULL, 'Sux Compagny',5),
(NULL, 'JESUS SAVE ME',5),
(NULL, 'anatheme',5),
(NULL, 'heal mon pet ffs',5),
(NULL, 'Bip bip',5),
(NULL, 'MbT',5),
(NULL, 'CYCLONECOPTER',5),
(NULL, 'Sargeras',5),
(NULL, 'Dots n Hots or something',5),
(NULL, 'This bear can eat you',5),
(NULL, 'Combination of Male love',5),
(NULL, 'Right in Two',5),
(NULL, 'Rends Wrath',5),
(NULL, 'Vita Brevis',5),
(NULL, 'Tysken Justus',5),
(NULL, 'Iso Kikkeli',5),
(NULL, 'imbas',5),
(NULL, 'Me love You',5),
(NULL, 'We love pie',5),
(NULL, 'F U',5),
(NULL, 'CRITICAL ERROR',5),
(NULL, 'Epica',5),
(NULL, 'V i X',5),
(NULL, 'Derka Derka Derka',5),
(NULL, 'Killalot',5),
(NULL, 'Flagstång',5),
(NULL, 'The beauty and the beast',5);

View File

@ -0,0 +1,649 @@
DROP TABLE IF EXISTS `playerbot_guild_names`;
CREATE TABLE `playerbot_guild_names` (
`name_id` INT(11) NOT NULL AUTO_INCREMENT UNIQUE,
`name` varchar(24) NOT NULL UNIQUE,
PRIMARY KEY (`name_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Playerbot guild names';
INSERT INTO `playerbot_guild_names` VALUES
(NULL, 'Black Guard'),
(NULL, 'Abyssal Kingdoms'),
(NULL, 'Acid Evil'),
(NULL, 'Addicts Muskateers'),
(NULL, 'Adventurers War'),
(NULL, 'Age of Red Water Clan'),
(NULL, 'Alivso Reason'),
(NULL, 'All Knights'),
(NULL, 'Allegiance of the Vile'),
(NULL, 'Alliance Clan'),
(NULL, 'Alliance of Defectives'),
(NULL, 'Alti Legions'),
(NULL, 'Anarchie Shi'),
(NULL, 'Anchors of the Nominal'),
(NULL, 'Ancients of Part Times'),
(NULL, 'Angelus Gods'),
(NULL, 'Angry Party'),
(NULL, 'Apocalyptic Lamont'),
(NULL, 'Architects of Green'),
(NULL, 'Army of Black Widows'),
(NULL, 'Army of Orgrimmar Minds'),
(NULL, 'Army of Three Horses'),
(NULL, 'Arrows of Midlight'),
(NULL, 'Artisans of Best Guild'),
(NULL, 'Assasins of the Pyrewood'),
(NULL, 'Assassins Bane'),
(NULL, 'Avatars of Warsong Stuff'),
(NULL, 'Axis of the Funky Night'),
(NULL, 'Azeroth Souls'),
(NULL, 'Azeroths Rabbits'),
(NULL, 'Bad Sentinels'),
(NULL, 'Banana Song'),
(NULL, 'Band of Tarantula Attack'),
(NULL, 'Band of the Dark Reveren'),
(NULL, 'Barcode Praised'),
(NULL, 'Basher Goats'),
(NULL, 'Basic Order'),
(NULL, 'Batman of Banished'),
(NULL, 'Betrayers of Lucky Child'),
(NULL, 'Blackwater Committee'),
(NULL, 'Blades of Lich Kings'),
(NULL, 'Blades of the Hive'),
(NULL, 'Blades of the Total'),
(NULL, 'Bleeding War'),
(NULL, 'Blessed Lair'),
(NULL, 'Blizzards of the Iron'),
(NULL, 'Blood Chaos'),
(NULL, 'Blood Intrigue'),
(NULL, 'Blood Samurai'),
(NULL, 'Bloodlust Good'),
(NULL, 'Bonds of Reported Ignore'),
(NULL, 'Booty Cry'),
(NULL, 'Border Knights'),
(NULL, 'Bossmans Targaryen'),
(NULL, 'Braveheart Heaven'),
(NULL, 'Brotherhood of Twilight'),
(NULL, 'Bruised Pain'),
(NULL, 'Burning Control'),
(NULL, 'Burning Oblivion'),
(NULL, 'Cabal of Kalimdor'),
(NULL, 'Cake Crusade'),
(NULL, 'Call of the Ironforge'),
(NULL, 'Carebears Thunder'),
(NULL, 'Carpe Heaven'),
(NULL, 'Carpe Regiment'),
(NULL, 'Children of Order'),
(NULL, 'Children of the Gods'),
(NULL, 'Circle of Amor E Bobby'),
(NULL, 'Clan of the Elven Toys'),
(NULL, 'Clan of the Strike Light'),
(NULL, 'Coalition of Super Best'),
(NULL, 'Collective Pimps'),
(NULL, 'Companions of the Gnome'),
(NULL, 'Company of the Vibe'),
(NULL, 'Conclave of the Triad'),
(NULL, 'Council of Final Demise'),
(NULL, 'Council of Hard Core Ord'),
(NULL, 'Craaweh Thrall'),
(NULL, 'Cradle Scourge'),
(NULL, 'Crimson Angels'),
(NULL, 'Crimson Saints'),
(NULL, 'Crusade of Oh'),
(NULL, 'Crusaders of Undead'),
(NULL, 'Cryptic Serenity'),
(NULL, 'Csa Rigged'),
(NULL, 'Cult of the Raging Raid'),
(NULL, 'Dalaran Fair'),
(NULL, 'Damage Inc'),
(NULL, 'Dark Alliance'),
(NULL, 'Dark Azeroth'),
(NULL, 'Dark Damage'),
(NULL, 'Dark Resistus'),
(NULL, 'Dark Samurai'),
(NULL, 'Dark Turtles'),
(NULL, 'Darken Mercenaries'),
(NULL, 'Darkened Malevolence'),
(NULL, 'Darkness of Sword Coast'),
(NULL, 'Dawn of Knights Society'),
(NULL, 'Dawn of Mad Sentry'),
(NULL, 'Dead Zug'),
(NULL, 'Death Darkness'),
(NULL, 'Death Knights'),
(NULL, 'Deathlike Goods'),
(NULL, 'Deaths Venoms'),
(NULL, 'Decree of the Phumpers'),
(NULL, 'Defenders of Da Raised'),
(NULL, 'Defenders of Hyuuga Dark'),
(NULL, 'Defenders of Sacred Harm'),
(NULL, 'Deths Lords'),
(NULL, 'Devil Circl'),
(NULL, 'Devils Klng'),
(NULL, 'Dharma Hand'),
(NULL, 'Dharma Thorn'),
(NULL, 'Dies Ravager'),
(NULL, 'Disciples of Dead Panda'),
(NULL, 'Disciples of the Rot'),
(NULL, 'Doomsday Youth'),
(NULL, 'Dorcha Knights'),
(NULL, 'Dots of Dead Skull'),
(NULL, 'Dragon Arms'),
(NULL, 'Dragonhawk Revolution'),
(NULL, 'Dragons Erythnul'),
(NULL, 'Dragons of the Black'),
(NULL, 'Drunken Thunder'),
(NULL, 'Drunks of Matoskan'),
(NULL, 'Dwarven Rock'),
(NULL, 'Dynasty of the Emerald'),
(NULL, 'Eastern Asylum'),
(NULL, 'Echo Sanctus'),
(NULL, 'Echoes of the Muphin'),
(NULL, 'Effreno Death'),
(NULL, 'Elite Guild'),
(NULL, 'Elite Legion'),
(NULL, 'Elite Veritas'),
(NULL, 'Elunes Meat'),
(NULL, 'Emerald Men'),
(NULL, 'Emerald Mjolnir'),
(NULL, 'Endless Defense'),
(NULL, 'Enemies of Bleeding'),
(NULL, 'Enternal Saber'),
(NULL, 'Evictors of the Returned'),
(NULL, 'Evil Guard'),
(NULL, 'Exalted Effect'),
(NULL, 'Eyes of a Night Elf'),
(NULL, 'Eyes of the Elton Souls'),
(NULL, 'Fallen Clan'),
(NULL, 'Fallen Milk'),
(NULL, 'Fenrir Seeker'),
(NULL, 'Final Army'),
(NULL, 'Flames of Ale Drinkers'),
(NULL, 'Flames of Antarian Chaos'),
(NULL, 'Forestt''s Wrath'),
(NULL, 'Forgotten Within'),
(NULL, 'From Synergy'),
(NULL, 'Frozen Oblivion'),
(NULL, 'Gashlycrumb Rollers'),
(NULL, 'Giovannitwos Elune'),
(NULL, 'Glass Meridian'),
(NULL, 'Gnome Faction'),
(NULL, 'Gods Gold'),
(NULL, 'Gods of the Complete'),
(NULL, 'Gold Catchers'),
(NULL, 'Golden Legendz'),
(NULL, 'Golden Souls'),
(NULL, 'Goldshire Goats'),
(NULL, 'Good Azeroth'),
(NULL, 'Gotz Safety'),
(NULL, 'Grammaton Alliance'),
(NULL, 'Great Circle'),
(NULL, 'Guardians of Honor'),
(NULL, 'Guards of Frostmane'),
(NULL, 'Guild of La Mano Dragons'),
(NULL, 'Guild of the Puppet'),
(NULL, 'Haggles Brigade'),
(NULL, 'Hammer of the Moral'),
(NULL, 'Hand of the Iron'),
(NULL, 'Hands of Far Con Buddies'),
(NULL, 'Hearts Knights'),
(NULL, 'Hell Angels'),
(NULL, 'Hells Thorn'),
(NULL, 'Holy Darnassus'),
(NULL, 'Horde Abh'),
(NULL, 'Horde Dragons'),
(NULL, 'Horde Leaders'),
(NULL, 'Horde Squad'),
(NULL, 'Horde of Omnia'),
(NULL, 'Horde of Free Brigade'),
(NULL, 'Horde of Shadow Flush'),
(NULL, 'Hordes Buccaneers'),
(NULL, 'Hordes Marauders'),
(NULL, 'House Crusaders'),
(NULL, 'Immortality Honor'),
(NULL, 'Inside Poof'),
(NULL, 'Iron Boyz'),
(NULL, 'Iscariot Ginas'),
(NULL, 'Island Kimchi'),
(NULL, 'Jenovas Wild'),
(NULL, 'Kalimdor Darkness'),
(NULL, 'Keepers of Golden Misery'),
(NULL, 'Keggers of Alt Hand Aton'),
(NULL, 'Kill Mafia'),
(NULL, 'Killer Durotar'),
(NULL, 'Killer Force'),
(NULL, 'Kindred Yardies'),
(NULL, 'Kindred of King Assassin'),
(NULL, 'Kingdom of the Ordo Crew'),
(NULL, 'Kings Boys'),
(NULL, 'Kings Windstorm'),
(NULL, 'Kings of Blood Knuckle'),
(NULL, 'Kings of Dol Aegis'),
(NULL, 'Knight Combat'),
(NULL, 'Knight of Fuzzy Night'),
(NULL, 'Knights of Darkspear'),
(NULL, 'Knights of Heavens Grave'),
(NULL, 'Knights of Myrmidon Ivxx'),
(NULL, 'Knights of the Avenging'),
(NULL, 'Knights of the Ballpeen'),
(NULL, 'Knights of the Black'),
(NULL, 'Knights of the Bloodhoof'),
(NULL, 'Knights of the Sovereign'),
(NULL, 'Knights of the Storm'),
(NULL, 'Knights of the Zulian'),
(NULL, 'Last Ptesanwi'),
(NULL, 'League of Hate Crew Seek'),
(NULL, 'Legacy of Ninth Beard'),
(NULL, 'Legendary Sons'),
(NULL, 'Legion of Maple Syrup'),
(NULL, 'Legion of Public Works'),
(NULL, 'Legion of Three Course'),
(NULL, 'Legion of United Souls'),
(NULL, 'Legion of Westfall Gold'),
(NULL, 'Legion of the Dark'),
(NULL, 'Legionnaires of Skull'),
(NULL, 'Les Warriors'),
(NULL, 'Lifetakers Inc'),
(NULL, 'Light of Dark Spire'),
(NULL, 'Light of Jade Renegade'),
(NULL, 'Liquid Guild'),
(NULL, 'Lone Side'),
(NULL, 'Lords of Fallen Blood'),
(NULL, 'Los Frum'),
(NULL, 'Lost Boyz'),
(NULL, 'Lost Squad'),
(NULL, 'Mad Daggers'),
(NULL, 'Malice Fatale'),
(NULL, 'Mandate of Jade'),
(NULL, 'Marines of the Butt'),
(NULL, 'Mercenaries of the Death'),
(NULL, 'Midget Council'),
(NULL, 'Midgets of Dark Sexy'),
(NULL, 'Midnight Norrathians'),
(NULL, 'Midnight Slayer'),
(NULL, 'Midnight War'),
(NULL, 'Minions of the Shadow'),
(NULL, 'Ministry of the Allince'),
(NULL, 'Mithril Destiny'),
(NULL, 'Monarchs of Party Crew'),
(NULL, 'Money Call'),
(NULL, 'Moonwood Redeye'),
(NULL, 'Narrow Patrol'),
(NULL, 'New Clan'),
(NULL, 'Night Pack'),
(NULL, 'Nightmare Guild'),
(NULL, 'Ninja Pledge'),
(NULL, 'Nocturne of Totally Dead'),
(NULL, 'Obsidian Fish'),
(NULL, 'Old Cosa'),
(NULL, 'One Valor'),
(NULL, 'Opus Faithful'),
(NULL, 'Order of Alts oF Fate'),
(NULL, 'Order of Nagas Bike Hunt'),
(NULL, 'Order of Omega Wards'),
(NULL, 'Order of Pink'),
(NULL, 'Order of Shield Bed'),
(NULL, 'Order of the Alt Sheep'),
(NULL, 'Order of the Honor'),
(NULL, 'Order of the Divine Lord'),
(NULL, 'Ordo Force'),
(NULL, 'Orgrimmar Ones'),
(NULL, 'Out of Lw Downed Wrynn'),
(NULL, 'Out of Mithril Avengers'),
(NULL, 'Oxbloods Medivh'),
(NULL, 'Pally Guard'),
(NULL, 'Path of the Brain'),
(NULL, 'Peddlers of the Hidden'),
(NULL, 'Phantoms of Wicked'),
(NULL, 'Phoenix Keepers'),
(NULL, 'Pillowcase Azeroth'),
(NULL, 'Pillowcase Cats'),
(NULL, 'Pius Tribe'),
(NULL, 'Plague of Human Slayer'),
(NULL, 'Plan Hand'),
(NULL, 'Power of Tuatha De Blood'),
(NULL, 'Priest Guild'),
(NULL, 'Prophets of Fatima War'),
(NULL, 'Prophets of Outlaw'),
(NULL, 'Prophets of the Red Mean'),
(NULL, 'Protectors of Black Hand'),
(NULL, 'Pure Aequitas'),
(NULL, 'Question Thrall'),
(NULL, 'Quintessential Sister'),
(NULL, 'Rage of Prairie Black'),
(NULL, 'Rage of the Flame'),
(NULL, 'Raiders of Candy Heart'),
(NULL, 'Raiders of the Purple'),
(NULL, 'Raiders of the Sil'),
(NULL, 'Ram Runners'),
(NULL, 'Rangers Vengeance'),
(NULL, 'Rangers of Interitus'),
(NULL, 'Raven Clan'),
(NULL, 'Razzle Guardian'),
(NULL, 'Reapers of the Shadow'),
(NULL, 'Reckless Knights'),
(NULL, 'Red Byam'),
(NULL, 'Red Death'),
(NULL, 'Reign of Alliance Task'),
(NULL, 'Reign of Blazing Frell'),
(NULL, 'Reign of Pure Conway'),
(NULL, 'Restoration of Illegal'),
(NULL, 'Resurrection of Tenui'),
(NULL, 'Ronin Kalimdor'),
(NULL, 'Rotting Tears'),
(NULL, 'Ruins of Dark Azeroth'),
(NULL, 'Rulers of Devils'),
(NULL, 'Sacred Parts'),
(NULL, 'Sacred Society'),
(NULL, 'Sacrificial Brotherhood'),
(NULL, 'Sanguine Council'),
(NULL, 'Sapphic Exiles'),
(NULL, 'Savage Kalimdor'),
(NULL, 'Scourge of Eight Inches'),
(NULL, 'Scourge of Wow Knights'),
(NULL, 'Scythe Sauce'),
(NULL, 'Secret Clan'),
(NULL, 'Seki Council'),
(NULL, 'Seraph Legends'),
(NULL, 'Shaded Judgement'),
(NULL, 'Shadow America'),
(NULL, 'Shadow Boys'),
(NULL, 'Shadow Knights'),
(NULL, 'Shadowed Ghosts'),
(NULL, 'Shadowed Goat'),
(NULL, 'Shadows of Cole Trainz'),
(NULL, 'Shadows of Los Banditos'),
(NULL, 'Shattered Stormrage'),
(NULL, 'Silent Night'),
(NULL, 'Silver Fools'),
(NULL, 'Silversky Sun'),
(NULL, 'Sisters of Kalimdor'),
(NULL, 'Skulled Ironforge'),
(NULL, 'Slayers of the Primals'),
(NULL, 'Sleepy Steel'),
(NULL, 'Soldiers of Azeroth'),
(NULL, 'Soldiers of Stalker'),
(NULL, 'Sons of Lambent Virtue'),
(NULL, 'Sons of the Top Truth'),
(NULL, 'Soul Wish'),
(NULL, 'Souls of Elite Gnome'),
(NULL, 'Spanaway Metalheadz'),
(NULL, 'Spoony Demise'),
(NULL, 'Squires of Sacred Tribe'),
(NULL, 'Stagnant Jesters'),
(NULL, 'Stars of Gear Farming'),
(NULL, 'Stupid Crusaders'),
(NULL, 'Stop Guides'),
(NULL, 'Storm of the Mope''s'),
(NULL, 'Stormrage Ferguson'),
(NULL, 'Stormtroopers of Fatima '),
(NULL, 'Stormwind Crew'),
(NULL, 'Straight Caedes'),
(NULL, 'Stronghold Angels'),
(NULL, 'Sturgeon Empire'),
(NULL, 'Survivors of Devil Club'),
(NULL, 'Sweet Bear'),
(NULL, 'Sword of Lost Evil'),
(NULL, 'Tainted Bunnies'),
(NULL, 'Talon of the Eclectic'),
(NULL, 'Team Kingdom'),
(NULL, 'Team United'),
(NULL, 'Tears of Eternal Kitties'),
(NULL, 'Tears of Phantom Druids'),
(NULL, 'Templar of Raid Dodgers'),
(NULL, 'Templars of Plagueware'),
(NULL, 'Terra Totem'),
(NULL, 'Terra War'),
(NULL, 'The Abiem'),
(NULL, 'The Aceofchaos'),
(NULL, 'The Afterlife'),
(NULL, 'The Aggression'),
(NULL, 'The Alliance of Dark'),
(NULL, 'The Altimate'),
(NULL, 'The Ancona Fire'),
(NULL, 'The Apocalypse'),
(NULL, 'The Arcane Monkey'),
(NULL, 'The Army of Spartans'),
(NULL, 'The Avalon'),
(NULL, 'The Avengers of Shining'),
(NULL, 'The Azure Gangstaz'),
(NULL, 'The Battlegnome'),
(NULL, 'The Black Hand Haven'),
(NULL, 'The Blackdraygon'),
(NULL, 'The Blackout'),
(NULL, 'The Blade'),
(NULL, 'The Blades of Caer Eel'),
(NULL, 'The Blades of Onyxia'),
(NULL, 'The Blood Red Violence'),
(NULL, 'The Blood of Red Powers'),
(NULL, 'The Bloodycrusaders'),
(NULL, 'The Blues Azeroth'),
(NULL, 'The Blues Grimfang'),
(NULL, 'The Bluethunder'),
(NULL, 'The Bonds of Arcane'),
(NULL, 'The Brimstone'),
(NULL, 'The Broken Chaos'),
(NULL, 'The Brood of Unknown'),
(NULL, 'The Burning Dog Firewall'),
(NULL, 'The Cabal'),
(NULL, 'The Cake Gankers'),
(NULL, 'The Cannabuddies'),
(NULL, 'The Circle of Shadow'),
(NULL, 'The Clan Blackwatch Few'),
(NULL, 'The Clan Cats'),
(NULL, 'The Clan Knights'),
(NULL, 'The Clean Combinations'),
(NULL, 'The Clean Up Guard'),
(NULL, 'The Council of Dark'),
(NULL, 'The Covenant'),
(NULL, 'The Crimson Guild'),
(NULL, 'The Crimson Marbock'),
(NULL, 'The Crusaders of Horde'),
(NULL, 'The Crusaders of Seksoni'),
(NULL, 'The Cult of Clan Brigade'),
(NULL, 'The Cult of the Pink'),
(NULL, 'The Daggers of the Vile'),
(NULL, 'The Dark'),
(NULL, 'The Dark Dogs'),
(NULL, 'The Dark Pain'),
(NULL, 'The Darkfall'),
(NULL, 'The Darkside Vanguard'),
(NULL, 'The Darkside of Initium'),
(NULL, 'The Daughters of the Elite'),
(NULL, 'The Daytripper'),
(NULL, 'The Deadfriends'),
(NULL, 'The Defiant'),
(NULL, 'The Dont Overwhelming'),
(NULL, 'The Doom Pasta'),
(NULL, 'The Dragon Redeye'),
(NULL, 'The Dragons Flame'),
(NULL, 'The Dreadlords'),
(NULL, 'The Dublainn Crown'),
(NULL, 'The Durban Protecters'),
(NULL, 'The Echoes of Goldshire'),
(NULL, 'The Elit of Dark Elune'),
(NULL, 'The Emissaries of Furiou'),
(NULL, 'The Eternal Chaos'),
(NULL, 'The Eternus'),
(NULL, 'The Exiie'),
(NULL, 'The Expendable Shadow'),
(NULL, 'The Faith of Desert'),
(NULL, 'The Family Misfits'),
(NULL, 'The Fere Darkness'),
(NULL, 'The Final Tears'),
(NULL, 'The Forsaken Boochies'),
(NULL, 'The Gates of the Bloody'),
(NULL, 'The Gnomes Lordaero'),
(NULL, 'The Gods of Blackscar'),
(NULL, 'The Gods of Twilight'),
(NULL, 'The Gold Fighters'),
(NULL, 'The Guardian Thieves'),
(NULL, 'The Guardians of Gnome'),
(NULL, 'The Hands of Redridge'),
(NULL, 'The Hawk'),
(NULL, 'The Hearts Images'),
(NULL, 'The Hellborn Die'),
(NULL, 'The Heroes Plague'),
(NULL, 'The Horde Farmer'),
(NULL, 'The Horde Honor'),
(NULL, 'The Hotpocket'),
(NULL, 'The Ignis Prophecy'),
(NULL, 'The Illuminatie'),
(NULL, 'The Immortal League'),
(NULL, 'The Independant'),
(NULL, 'The Infragilis Legion'),
(NULL, 'The Jag'),
(NULL, 'The Jookmaster'),
(NULL, 'The Kataclysm'),
(NULL, 'The Knight'),
(NULL, 'The Knightelf'),
(NULL, 'The Knights Thorn'),
(NULL, 'The Knights of Gods Fury'),
(NULL, 'The Knights of Lost Peon'),
(NULL, 'The Knights of Mortal'),
(NULL, 'The Knights of Samurai'),
(NULL, 'The Kobra'),
(NULL, 'The Leaders of Evil'),
(NULL, 'The Leaders of Life'),
(NULL, 'The League of Red Knight'),
(NULL, 'The Legacy Meathooks'),
(NULL, 'The Legion of the Blue'),
(NULL, 'The Legion of Death'),
(NULL, 'The Lemmings of Flaming'),
(NULL, 'The Let Blood Gamer'),
(NULL, 'The Light'),
(NULL, 'The Little Hunters'),
(NULL, 'The Lords of Vae Knight'),
(NULL, 'The Mercenaries'),
(NULL, 'The Midieval Vanguard'),
(NULL, 'The Might of Dark Tong'),
(NULL, 'The Mithril Justice'),
(NULL, 'The Mithril Pepsi'),
(NULL, 'The Mjollnir'),
(NULL, 'The Moo Licht'),
(NULL, 'The Morgantis'),
(NULL, 'The Mulletmen'),
(NULL, 'The Necrontyr of Eternal'),
(NULL, 'The Nedrage Kills'),
(NULL, 'The Night'),
(NULL, 'The Nightfall'),
(NULL, 'The Ninja Heroes'),
(NULL, 'The Order of Gold'),
(NULL, 'The Order of Warcraft'),
(NULL, 'The Order of Warsong'),
(NULL, 'The Over Louder'),
(NULL, 'The Overlord'),
(NULL, 'The Pants'),
(NULL, 'The Pie'),
(NULL, 'The Pretectors'),
(NULL, 'The Project Disease'),
(NULL, 'The Psychotics'),
(NULL, 'The Puggers'),
(NULL, 'The Pyreborne'),
(NULL, 'The Queen of Meow'),
(NULL, 'The Red Hood Thunder'),
(NULL, 'The Reign of Uber Enigma'),
(NULL, 'The Resurrection'),
(NULL, 'The Ring of Honor'),
(NULL, 'The Ropetown'),
(NULL, 'The Royal Militia Blanco'),
(NULL, 'The Samurai Banda'),
(NULL, 'The Sanity'),
(NULL, 'The Sauce'),
(NULL, 'The Schoolyard Reapers'),
(NULL, 'The Secrets of Hehog'),
(NULL, 'The Seers'),
(NULL, 'The Servants of Cyclone'),
(NULL, 'The Seven'),
(NULL, 'The Shadow Gate'),
(NULL, 'The Shadow Misfits'),
(NULL, 'The Shadow of Ninja Pain'),
(NULL, 'The Shadowborn'),
(NULL, 'The Shizam'),
(NULL, 'The Shockers'),
(NULL, 'The Shriek of Nightmare'),
(NULL, 'The Silent Grunts'),
(NULL, 'The Silent Legion'),
(NULL, 'The Skunkdesigns'),
(NULL, 'The Sorrow'),
(NULL, 'The Souls of Azeroth Old'),
(NULL, 'The Spazler'),
(NULL, 'The Squirrels'),
(NULL, 'The Stringville'),
(NULL, 'The Stronghold of Reds'),
(NULL, 'The Tha Handlers'),
(NULL, 'The Thieves of Moral'),
(NULL, 'The Thorium Claw'),
(NULL, 'The Thread'),
(NULL, 'The Thule'),
(NULL, 'The Thunderslayers'),
(NULL, 'The True Wow'),
(NULL, 'The Trusted Minions'),
(NULL, 'The Twilight Rangers'),
(NULL, 'The Tyraels Aggression'),
(NULL, 'The Ultimates'),
(NULL, 'The Unforgiven Heresy'),
(NULL, 'The Unholy Bards'),
(NULL, 'The Unsung Efficiency'),
(NULL, 'The Valley of the Demon'),
(NULL, 'The Valor'),
(NULL, 'The Violent Chaos'),
(NULL, 'The Virus Eternal'),
(NULL, 'The War'),
(NULL, 'The Warsong Gnomeregan'),
(NULL, 'The Westcoast'),
(NULL, 'The Wicked'),
(NULL, 'The Will of Chronicles'),
(NULL, 'The Windsword Nightmare'),
(NULL, 'The Wings of Oxy Claw'),
(NULL, 'The Wrath of Elton'),
(NULL, 'The Wut'),
(NULL, 'The Yoricks Assassins'),
(NULL, 'The Zeksonic Thieves'),
(NULL, 'Theramore Azeroth'),
(NULL, 'Thirstquencher Chaos'),
(NULL, 'Thralls Caribous'),
(NULL, 'Three Alive'),
(NULL, 'Titans of Blood Sun'),
(NULL, 'Torvus Dragons'),
(NULL, 'Tower of the Little'),
(NULL, 'True Team'),
(NULL, 'Tul Inc'),
(NULL, 'Twinks of Cold Club'),
(NULL, 'Twinks of Hidden Venture'),
(NULL, 'Ultimate Rules'),
(NULL, 'Undead Kingdom'),
(NULL, 'Unforgiven Destiny'),
(NULL, 'Unguilded War'),
(NULL, 'Unholy Cats'),
(NULL, 'Unholy Teeth'),
(NULL, 'Union of Burning Prz'),
(NULL, 'Unusual Guard'),
(NULL, 'Valiant Riderz'),
(NULL, 'Vanguard Omen'),
(NULL, 'Vanguard Redeemers'),
(NULL, 'Vanguard of Teutonic'),
(NULL, 'Vengeful Mayhem'),
(NULL, 'Verata Blackflame'),
(NULL, 'Vicious Renegade'),
(NULL, 'Vile Dead'),
(NULL, 'Voodoo Hearth'),
(NULL, 'War Legion'),
(NULL, 'Warlockian Tree'),
(NULL, 'Warlords of Kungfu Army'),
(NULL, 'Warriors of Happy Death'),
(NULL, 'Warriors of the Tundra'),
(NULL, 'Warsong Insanity'),
(NULL, 'Waste of Grey Death'),
(NULL, 'Wayfarers of Maple Leaf'),
(NULL, 'Wayward Agenda'),
(NULL, 'Web of Forgoten Warfare'),
(NULL, 'Wet Guard'),
(NULL, 'Wild Fire'),
(NULL, 'Will of the Forgotten'),
(NULL, 'Winds of Steve Irwin'),
(NULL, 'Wings of Emerald Minions'),
(NULL, 'Wintermane Good'),
(NULL, 'Witchhunters of Chaos'),
(NULL, 'With Sea'),
(NULL, 'Wrath of the Horde Troop'),
(NULL, 'Wtf Losers'),
(NULL, 'Xcalibur of Shogunz Depo'),
(NULL, 'Xelium Determination');

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,20 @@
DROP TABLE IF EXISTS `playerbots_custom_strategy`;
CREATE TABLE `playerbots_custom_strategy` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`idx` int(11),
`owner` int(11),
`action_line` varchar(1024) NOT NULL,
PRIMARY KEY (`id`),
KEY `name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
DELETE FROM `playerbots_custom_strategy`;
INSERT INTO `playerbots_custom_strategy` VALUES
(NULL, 'say', 1, 0, 'critical health>emote::helpme!99,say::critical health!98'),
(NULL, 'say', 2, 0, 'low health>emote::healme!99,say::low health!98'),
(NULL, 'say', 3, 0, 'low mana>emote::oom!99,say::low mana!98'),
(NULL, 'say', 4, 0, 'tank aoe>charge!99,say::taunt!98'),
(NULL, 'say', 5, 0, 'medium aoe>say::aoe!99'),
(NULL, 'say', 6, 0, 'can loot>say::loot!99'),
(NULL, 'say', 7, 0, 'dps assist>say::taunt!97');

View File

@ -0,0 +1,9 @@
DROP TABLE IF EXISTS `playerbots_db_store`;
CREATE TABLE `playerbots_db_store` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`guid` int(11) NOT NULL,
`key` varchar(32) NOT NULL,
`value` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `guid` (`guid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

View File

@ -0,0 +1,252 @@
-- --------------------------------------------------------
-- Host: 127.0.0.1
-- Server version: 5.7.21 - MySQL Community Server (GPL)
-- Server OS: Win64
-- HeidiSQL Verzió: 9.5.0.5338
-- --------------------------------------------------------
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET NAMES utf8 */;
/*!50503 SET NAMES utf8mb4 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
-- Dumping data for table characters-tbc.ai_playerbot_enchants: ~220 rows (approximately)
DROP TABLE IF EXISTS `playerbots_enchants`;
CREATE TABLE `playerbots_enchants` (
`class` TINYINT(3) NOT NULL,
`spec` TINYINT(3) NOT NULL,
`spellid` INT(11) NOT NULL,
`slotid` TINYINT(3) DEFAULT 1,
`name` VARCHAR(255) NOT NULL COMMENT 'name of the enchant',
PRIMARY KEY (`class`,`spec`,`spellid`,`slotid`)
) ENGINE=INNODB DEFAULT CHARSET=latin1;
/*!40000 ALTER TABLE `playerbots_enchants` DISABLE KEYS */;
DELETE FROM `playerbots_enchants`;
INSERT INTO `playerbots_enchants` (`class`, `spec`, `spellid`, `slotid`, `name`) VALUES
(1, 10, 20034, 15, 'Crusader '),
(1, 10, 22779, 17, '30 Hit '),
(1, 10, 27927, 10, '4 All Stats '),
(1, 10, 27927, 11, '4 All Stats '),
(1, 10, 27960, 4, '6 All Stats '),
(1, 10, 27984, 16, 'Mongoose '),
(1, 10, 29483, 2, '26 Attackpower 14 Crit '),
(1, 10, 33996, 9, '26 Attackpower '),
(1, 10, 34002, 8, '24 Attackpower '),
(1, 10, 34004, 14, '12 Agility '),
(1, 10, 34007, 7, 'Minor Speed 6 Agility'),
(1, 10, 35452, 0, '34 Attackpower 16 Hit '),
(1, 10, 35490, 6, '50 Attackpower 12 Crit '),
(1, 11, 20034, 15, 'Crusader '),
(1, 11, 20034, 16, 'Crusader '),
(1, 11, 22779, 17, '30 Hit '),
(1, 11, 27927, 10, '4 All Stats '),
(1, 11, 27927, 11, '4 All Stats '),
(1, 11, 27960, 4, '6 All Stats '),
(1, 11, 29483, 2, '26 Attackpower 14 Crit '),
(1, 11, 33996, 9, '26 Attackpower '),
(1, 11, 34002, 8, '24 Attackpower '),
(1, 11, 34004, 14, '12 Agility '),
(1, 11, 34007, 7, 'Minor Speed 6 Agility'),
(1, 11, 35452, 0, '34 Attackpower 16 Hit '),
(1, 11, 35490, 6, '50 Attackpower 12 Crit '),
(1, 12, 22779, 17, '30 Hit '),
(1, 12, 25072, 9, '2% Threat '),
(1, 12, 27906, 8, '12 Defense '),
(1, 12, 27927, 10, '4 All Stats '),
(1, 12, 27927, 11, '4 All Stats '),
(1, 12, 27954, 7, '5% Root/Snare Resist 10 Hit'),
(1, 12, 27960, 4, '6 All Stats '),
(1, 12, 28004, 15, 'Battlemaster '),
(1, 12, 34009, 16, '18 Stamina '),
(1, 12, 35433, 2, '10 Dodge 15 Defense '),
(1, 12, 35443, 0, '16 Defense 17 Dodge '),
(1, 12, 35495, 6, '40 Stamina 12 Agility '),
(1, 12, 47051, 14, '12 Defense '),
(2, 20, 22779, 17, '30 Hit '),
(2, 20, 27926, 10, '20 Healing 7 Spelldamage '),
(2, 20, 27926, 11, '20 Healing 7 Spelldamage '),
(2, 20, 27945, 16, '12 Intellect '),
(2, 20, 27954, 7, '5% Root/Snare Resist 10 Hit'),
(2, 20, 27960, 4, '6 All Stats '),
(2, 20, 29475, 2, '31 Healing 11 Spelldamage 5 mp5 '),
(2, 20, 31370, 6, '66 Healing 22 Spelldamage 20 Stamina '),
(2, 20, 33999, 9, '35 Healing 12 Spelldamage '),
(2, 20, 34001, 8, '12 Intellect '),
(2, 20, 34003, 14, '20 Spell Penetration '),
(2, 20, 34010, 15, '81 Healing 27 Spelldamage '),
(2, 20, 35445, 0, '35 Healing 12 Spelldamage 7 mp5 '),
(2, 21, 22779, 17, '30 Hit '),
(2, 21, 25072, 9, '2% Threat '),
(2, 21, 27906, 8, '12 Defense '),
(2, 21, 27927, 10, '4 All Stats '),
(2, 21, 27927, 11, '4 All Stats '),
(2, 21, 27954, 7, '5% Root/Snare Resist 10 Hit'),
(2, 21, 27960, 4, '6 All Stats '),
(2, 21, 28004, 15, 'Battlemaster '),
(2, 21, 34009, 16, '18 Stamina '),
(2, 21, 35433, 2, '10 Dodge 15 Defense '),
(2, 21, 35443, 0, '16 Defense 17 Dodge '),
(2, 21, 35495, 6, '40 Stamina 12 Agility '),
(2, 21, 47051, 14, '12 Defense '),
(2, 22, 20034, 15, 'Crusader '),
(2, 22, 22779, 17, '30 Hit '),
(2, 22, 27899, 8, '12 Strength '),
(2, 22, 27927, 10, '4 All Stats '),
(2, 22, 27927, 11, '4 All Stats '),
(2, 22, 27960, 4, '6 All Stats '),
(2, 22, 29483, 2, '26 Attackpower 14 Crit '),
(2, 22, 33995, 6, '50 Attackpower 12 Crit '),
(2, 22, 33996, 9, '15 Strength '),
(2, 22, 34004, 14, '12 Agility '),
(2, 22, 34007, 7, 'Minor Speed 6 Agility'),
(2, 22, 37891, 0, '17 Strength16 Intellect '),
(3, 30, 22779, 17, '30 Hit '),
(3, 30, 25080, 9, '15 Agility '),
(3, 30, 27927, 10, '4 All Stats '),
(3, 30, 27927, 11, '4 All Stats '),
(3, 30, 27951, 7, '12 Agility'),
(3, 30, 27960, 4, '6 All Stats '),
(3, 30, 29483, 2, '26 Attackpower 14 Crit '),
(3, 30, 34002, 8, '24 Attackpower '),
(3, 30, 34004, 14, '12 Agility '),
(3, 30, 35452, 0, '34 Attackpower 16 Hit '),
(3, 30, 35495, 6, '40 Stamina 12 Agility '),
(3, 30, 42620, 15, 'Greater Agility '),
(3, 30, 42620, 16, 'Greater Agility '),
(4, 40, 22779, 17, '30 Hit '),
(4, 40, 25080, 9, '15 Agility '),
(4, 40, 27927, 10, '4 All Stats '),
(4, 40, 27927, 11, '4 All Stats '),
(4, 40, 27951, 7, '12 Agility'),
(4, 40, 27960, 4, '6 All Stats '),
(4, 40, 27984, 15, 'Mongoose '),
(4, 40, 27984, 16, 'Mongoose '),
(4, 40, 29483, 2, '26 Attackpower 14 Crit '),
(4, 40, 34002, 8, '24 Attackpower '),
(4, 40, 34004, 14, '12 Agility '),
(4, 40, 35452, 0, '34 Attackpower 16 Hit '),
(4, 40, 35495, 6, '40 Stamina 12 Agility '),
(5, 50, 22779, 17, '30 Hit '),
(5, 50, 27926, 10, '20 Healing 7 Spelldamage '),
(5, 50, 27926, 11, '20 Healing 7 Spelldamage '),
(5, 50, 27945, 16, '12 Intellect '),
(5, 50, 27954, 7, '5% Root/Snare Resist 10 Hit'),
(5, 50, 27960, 4, '6 All Stats '),
(5, 50, 29475, 2, '31 Healing 11 Spelldamage 5 mp5 '),
(5, 50, 31370, 6, '66 Healing 22 Spelldamage 20 Stamina '),
(5, 50, 33999, 9, '35 Healing 12 Spelldamage '),
(5, 50, 34001, 8, '12 Intellect '),
(5, 50, 34003, 14, '20 Spell Penetration '),
(5, 50, 34010, 15, '81 Healing 27 Spelldamage '),
(5, 50, 35445, 0, '35 Healing 12 Spelldamage 7 mp5 '),
(7, 70, 22779, 17, '30 Hit '),
(7, 70, 27926, 10, '20 Healing 7 Spelldamage '),
(7, 70, 27926, 11, '20 Healing 7 Spelldamage '),
(7, 70, 27945, 16, '12 Intellect '),
(7, 70, 27954, 7, '5% Root/Snare Resist 10 Hit'),
(7, 70, 27960, 4, '6 All Stats '),
(7, 70, 31370, 6, '66 Healing 22 Spelldamage 20 Stamina '),
(7, 70, 33994, 9, '15 Spell Hit '),
(7, 70, 34001, 8, '12 Intellect '),
(7, 70, 34003, 14, '20 Spell Penetration '),
(7, 70, 34010, 15, '81 Healing 27 Spelldamage '),
(7, 70, 35406, 2, '18 Spelldamage 10 Crit '),
(7, 70, 35447, 0, '22 Spelldamage 14 Hit '),
(7, 71, 22779, 17, '30 Hit '),
(7, 71, 25080, 9, '15 Agility '),
(7, 71, 27927, 10, '4 All Stats '),
(7, 71, 27927, 11, '4 All Stats '),
(7, 71, 27951, 7, '12 Agility'),
(7, 71, 27960, 4, '6 All Stats '),
(7, 71, 27977, 15, '35 Agility '),
(7, 71, 27984, 16, 'Mongoose '),
(7, 71, 29483, 2, '26 Attackpower 14 Crit '),
(7, 71, 34002, 8, '24 Attackpower '),
(7, 71, 34004, 14, '12 Agility '),
(7, 71, 35452, 0, '34 Attackpower 16 Hit '),
(7, 71, 35495, 6, '40 Stamina 12 Agility '),
(7, 72, 22779, 17, '30 Hit '),
(7, 72, 27926, 10, '20 Healing 7 Spelldamage '),
(7, 72, 27926, 11, '20 Healing 7 Spelldamage '),
(7, 72, 27945, 16, '12 Intellect '),
(7, 72, 27954, 7, '5% Root/Snare Resist 10 Hit'),
(7, 72, 27960, 4, '6 All Stats '),
(7, 72, 29475, 2, '31 Healing 11 Spelldamage 5 mp5 '),
(7, 72, 31370, 6, '66 Healing 22 Spelldamage 20 Stamina '),
(7, 72, 33999, 9, '35 Healing 12 Spelldamage '),
(7, 72, 34001, 8, '12 Intellect '),
(7, 72, 34003, 14, '20 Spell Penetration '),
(7, 72, 34010, 15, '81 Healing 27 Spelldamage '),
(7, 72, 35445, 0, '35 Healing 12 Spelldamage 7 mp5 '),
(8, 80, 22779, 17, '30 Hit '),
(8, 80, 27927, 10, '4 All Stats '),
(8, 80, 27927, 11, '4 All Stats '),
(8, 80, 27945, 16, '12 Intellect '),
(8, 80, 27954, 7, '5% Root/Snare Resist 10 Hit'),
(8, 80, 27960, 4, '6 All Stats '),
(8, 80, 27975, 15, '40 Spelldamage '),
(8, 80, 31372, 6, '35 Spelldamage 20 Stamina '),
(8, 80, 33994, 9, '15 Spell Hit '),
(8, 80, 34001, 8, '12 Intellect '),
(8, 80, 34003, 14, '20 Spell Penetration '),
(8, 80, 35406, 2, '18 Spelldamage 10 Crit '),
(8, 80, 35447, 0, '22 Spelldamage 14 Hit '),
(9, 90, 22779, 17, '30 Hit '),
(9, 90, 27924, 11, '12 Spelldamage '),
(9, 90, 27927, 10, '4 All Stats '),
(9, 90, 27945, 16, '12 Intellect '),
(9, 90, 27954, 7, '5% Root/Snare Resist 10 Hit'),
(9, 90, 27960, 4, '6 All Stats '),
(9, 90, 27975, 15, '40 Spelldamage '),
(9, 90, 31372, 6, '35 Spelldamage 20 Stamina '),
(9, 90, 33994, 9, '15 Spell Hit '),
(9, 90, 34001, 8, '12 Intellect '),
(9, 90, 34003, 14, '20 Spell Penetration '),
(9, 90, 35406, 2, '18 Spelldamage 10 Crit '),
(9, 90, 35447, 0, '22 Spelldamage 14 Hit '),
(11, 110, 22779, 17, '30 Hit '),
(11, 110, 27926, 10, '20 Healing 7 Spelldamage '),
(11, 110, 27926, 11, '20 Healing 7 Spelldamage '),
(11, 110, 27945, 16, '12 Intellect '),
(11, 110, 27954, 7, '5% Root/Snare Resist 10 Hit'),
(11, 110, 27960, 4, '6 All Stats '),
(11, 110, 31370, 6, '66 Healing 22 Spelldamage 20 Stamina '),
(11, 110, 33994, 9, '15 Spell Hit '),
(11, 110, 34001, 8, '12 Intellect '),
(11, 110, 34003, 14, '20 Spell Penetration '),
(11, 110, 34010, 15, '81 Healing 27 Spelldamage '),
(11, 110, 35406, 2, '18 Spelldamage 10 Crit '),
(11, 110, 35447, 0, '22 Spelldamage 14 Hit '),
(11, 111, 22779, 17, '30 Hit '),
(11, 111, 25080, 9, '15 Agility '),
(11, 111, 27927, 10, '4 All Stats '),
(11, 111, 27927, 11, '4 All Stats '),
(11, 111, 27951, 7, '12 Agility'),
(11, 111, 27960, 4, '6 All Stats '),
(11, 111, 29483, 2, '26 Attackpower 14 Crit '),
(11, 111, 34002, 8, '24 Attackpower '),
(11, 111, 34004, 14, '12 Agility '),
(11, 111, 35452, 0, '34 Attackpower 16 Hit '),
(11, 111, 35495, 6, '40 Stamina 12 Agility '),
(11, 111, 42620, 15, 'Greater Agility '),
(11, 111, 42620, 16, 'Greater Agility '),
(11, 112, 22779, 17, '30 Hit '),
(11, 112, 27926, 10, '20 Healing 7 Spelldamage '),
(11, 112, 27926, 11, '20 Healing 7 Spelldamage '),
(11, 112, 27945, 16, '12 Intellect '),
(11, 112, 27954, 7, '5% Root/Snare Resist 10 Hit'),
(11, 112, 27960, 4, '6 All Stats '),
(11, 112, 29475, 2, '31 Healing 11 Spelldamage 5 mp5 '),
(11, 112, 31370, 6, '66 Healing 22 Spelldamage 20 Stamina '),
(11, 112, 33999, 9, '35 Healing 12 Spelldamage '),
(11, 112, 34001, 8, '12 Intellect '),
(11, 112, 34003, 14, '20 Spell Penetration '),
(11, 112, 34010, 15, '81 Healing 27 Spelldamage '),
(11, 112, 35445, 0, '35 Healing 12 Spelldamage 7 mp5 ');
/*!40000 ALTER TABLE `playerbots_enchants` ENABLE KEYS */;
/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */;
/*!40014 SET FOREIGN_KEY_CHECKS=IF(@OLD_FOREIGN_KEY_CHECKS IS NULL, 1, @OLD_FOREIGN_KEY_CHECKS) */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;

View File

@ -0,0 +1,10 @@
DROP TABLE IF EXISTS `playerbots_equip_cache`;
CREATE TABLE `playerbots_equip_cache` (
`id` INT(11) auto_increment,
`clazz` TINYINT(3) NOT NULL,
`lvl` INT(11) NOT NULL,
`slot` TINYINT(8) NOT NULL,
`quality` INT(11) NOT NULL,
`item` INT(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Playerbots equip Cache';

View File

@ -0,0 +1,15 @@
DROP TABLE IF EXISTS `playerbots_guild_tasks`;
CREATE TABLE `playerbots_guild_tasks` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`owner` INT(11) NOT NULL,
`guildid` INT(11) NOT NULL,
`time` INT(11) NOT NULL,
`validIn` INT(11) DEFAULT NULL,
`type` varchar(45) DEFAULT NULL,
`value` INT(11) DEFAULT NULL,
`data` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `owner` (`owner`),
KEY `guildid` (`guildid`),
KEY `type` (`type`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

View File

@ -0,0 +1,45 @@
DROP TABLE IF EXISTS `playerbots_item_info_cache`;
CREATE TABLE IF NOT EXISTS `playerbots_item_info_cache` (
`id` int(11) NOT NULL,
`quality` int(11) DEFAULT NULL,
`slot` int(11) DEFAULT NULL,
`source` mediumint(8) DEFAULT NULL,
`sourceId` mediumint(8) DEFAULT NULL,
`team` mediumint(8) DEFAULT NULL,
`faction` mediumint(8) DEFAULT NULL,
`factionRepRank` mediumint(8) DEFAULT NULL,
`minLevel` mediumint(8) DEFAULT NULL,
`scale_1` mediumint(8) DEFAULT NULL,
`scale_2` mediumint(8) DEFAULT NULL,
`scale_3` mediumint(8) DEFAULT NULL,
`scale_4` mediumint(8) DEFAULT NULL,
`scale_5` mediumint(8) DEFAULT NULL,
`scale_6` mediumint(8) DEFAULT NULL,
`scale_7` mediumint(8) DEFAULT NULL,
`scale_8` mediumint(8) DEFAULT NULL,
`scale_9` mediumint(8) DEFAULT NULL,
`scale_10` mediumint(8) DEFAULT NULL,
`scale_11` mediumint(8) DEFAULT NULL,
`scale_12` mediumint(8) DEFAULT NULL,
`scale_13` mediumint(8) DEFAULT NULL,
`scale_14` mediumint(8) DEFAULT NULL,
`scale_15` mediumint(8) DEFAULT NULL,
`scale_16` mediumint(8) DEFAULT NULL,
`scale_17` mediumint(8) DEFAULT NULL,
`scale_18` mediumint(8) DEFAULT NULL,
`scale_19` mediumint(8) DEFAULT NULL,
`scale_20` mediumint(8) DEFAULT NULL,
`scale_21` mediumint(8) DEFAULT NULL,
`scale_22` mediumint(8) DEFAULT NULL,
`scale_23` mediumint(8) DEFAULT NULL,
`scale_24` mediumint(8) DEFAULT NULL,
`scale_25` mediumint(8) DEFAULT NULL,
`scale_26` mediumint(8) DEFAULT NULL,
`scale_27` mediumint(8) DEFAULT NULL,
`scale_28` mediumint(8) DEFAULT NULL,
`scale_29` mediumint(8) DEFAULT NULL,
`scale_30` mediumint(8) DEFAULT NULL,
`scale_31` mediumint(8) DEFAULT NULL,
`scale_32` mediumint(8) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='PlayerbotAI item info Cache';

View File

@ -0,0 +1,15 @@
DROP TABLE IF EXISTS `playerbots_random_bots`;
CREATE TABLE `playerbots_random_bots` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`owner` INT(11) NOT NULL,
`bot` INT(11) NOT NULL,
`time` INT(11) NOT NULL,
`validIn` INT(11) DEFAULT NULL,
`event` varchar(45) DEFAULT NULL,
`value` INT(11) DEFAULT NULL,
`data` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `owner` (`owner`),
KEY `bot` (`bot`),
KEY `event` (`event`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

View File

@ -0,0 +1,7 @@
DROP TABLE IF EXISTS `playerbots_rarity_cache`;
CREATE TABLE `playerbots_rarity_cache` (
`id` INT(11) auto_increment,
`item` INT(11) NOT NULL,
`rarity` float NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Playerbots Rarity Cache';

View File

@ -0,0 +1,8 @@
DROP TABLE IF EXISTS `playerbots_rnditem_cache`;
CREATE TABLE `playerbots_rnditem_cache` (
`id` INT(11) auto_increment,
`lvl` INT(11) NOT NULL,
`type` INT(11) NOT NULL,
`item` INT(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Playerbots Random Item Cache';

View File

@ -0,0 +1,236 @@
DROP TABLE IF EXISTS `playerbots_speech`;
CREATE TABLE `playerbots_speech` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`text` varchar(1024) NOT NULL,
`type` varchar(10) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `playerbots_speech` VALUES
(NULL, 'taunt', 'I have puppies under my armor!', 'say'),
(NULL, 'taunt', 'Bite me, <target>!', 'say'),
(NULL, 'taunt', 'Hey <target>! Guess what your mom said last night!', 'say'),
(NULL, 'taunt', '<target>, you''re so ugly you couldn''t score in a monkey whorehouse with a bag of bananas!', 'say'),
(NULL, 'taunt', 'Shut up <target>, you''ll never be the man your mother is!!', 'say'),
(NULL, 'taunt', 'Your mother was a hampster and your father smelt of elderberries!!!!', 'say'),
(NULL, 'taunt', 'I don''t want to talk to you no more, you empty headed animal food trough wiper!!!', 'say'),
(NULL, 'taunt', 'I fart in your general direction!!!', 'say'),
(NULL, 'taunt', 'Go and boil your bottom, you son of a silly person!!!', 'say'),
(NULL, 'taunt', 'What are you going to do <target>, bleed on me? HAVE AT YOU!', 'say'),
(NULL, 'taunt', 'M-O-O-N! That spells aggro!', 'say'),
(NULL, 'taunt', 'You''re about as useful as a one-legged man in an ass kicking contest.', 'say'),
(NULL, 'taunt', 'Hey <target>! Stop hitting on them, they''re not your type. They aren''t inflatable.', 'say'),
(NULL, 'taunt', '<target> you''re so far outta your league, you''re playing a different sport.', 'say'),
(NULL, 'taunt', 'You made a big mistake today <target>, you got out of bed.', 'say'),
(NULL, 'taunt', 'I wanna try turning into a horse, but I need help. I''ll be the front, you be yourself.', 'say'),
(NULL, 'taunt', 'Can I borrow your face for a few days? My ass is going on holiday....', 'say'),
(NULL, 'taunt', 'I''d like to give you a going away present... First you do your part.', 'say'),
(NULL, 'taunt', 'Before you came along we were hungry, Now we''re just fed up.', 'say'),
(NULL, 'taunt', 'I like you. People say I have no taste, but I like you.', 'say'),
(NULL, 'taunt', 'I think you have an inferiority complex, but that''s okay, it''s justified.', 'say'),
(NULL, 'taunt', 'Hence rotten thing! Or I shall shake thy bones out of thy garments.', 'say'),
(NULL, 'taunt', 'I can''t believe I''m wasting my time with you!', 'say'),
(NULL, 'taunt', 'I love it when someone insults me, it means I don''t have to be nice anymore.', 'say'),
(NULL, 'taunt', 'Thou leathern-jerkin, crystal-button, knot-pated, agatering, puke-stocking, caddis-garter, smooth-tongue, Spanish pouch!', 'say'),
(NULL, 'taunt', 'Thou qualling bat-fowling malt-worm!', 'say'),
(NULL, 'taunt', 'Thou art truely an idol of idiot-worshippers!', 'say'),
(NULL, 'taunt', 'Thou misbegotten knotty-pated wagtail!', 'say'),
(NULL, 'taunt', 'Thou whoreson mandrake, thou art fitter to be worn in my cap than to wait at my heels!', 'say'),
(NULL, 'taunt', 'You! You scullion! You rampallian! You fustilarian! I''ll tickle your catastrophe!', 'say'),
(NULL, 'taunt', 'Oh <target>! Thou infectious ill-nurtured flax-wench!', 'say'),
(NULL, 'taunt', 'We leak in your chimney, <target>!', 'say'),
(NULL, 'taunt', 'Oh thou bootless fen-sucked canker-blossom!', 'say'),
(NULL, 'taunt', 'Were I like thee I''d throw away myself!', 'say'),
(NULL, 'taunt', 'O teach me <target>, how I should forget to think!', 'say'),
(NULL, 'taunt', 'Truly thou art damned, like an ill-roasted egg, all on one side!', 'say'),
(NULL, 'taunt', 'You starvelling, you eel-skin, you dried neat''s-tongue, you bull''s-pizzle, you stock-fish- O for breath to utter what is like thee!! -you tailor''s-yard, you sheath, you bow-case, you vile standing tuck!', 'say'),
(NULL, 'taunt', 'Fie! Drop thee into the rotten mouth of Death!', 'say'),
(NULL, 'taunt', '<target>, you are a fishmonger!', 'say'),
(NULL, 'taunt', 'I shall live to knock thy brains out!', 'say'),
(NULL, 'taunt', 'Most shallow are you, <target>!! Thou art worms-meat in respect of a good piece of flesh, indeed!!', 'say'),
(NULL, 'taunt', 'Vile wretch! O <target>, thou odiferous hell-hated pignut!', 'say'),
(NULL, 'taunt', '<target>! Thy kiss is as comfortless as frozen water to a starved snake!', 'say'),
(NULL, 'taunt', 'I scorn you, scurvy companion. What, you poor, base, rascally, cheating, lack-linen mate! Away, you moldy rogue, away!', 'say'),
(NULL, 'taunt', 'Out of my sight! Thou dost infect my eyes <target>!', 'say'),
(NULL, 'taunt', 'PLAY TIME!!!!', 'say'),
(NULL, 'taunt', 'None shall pass!', 'say'),
(NULL, 'taunt', 'We''re under attack! A vast, ye swabs! Repel the invaders!', 'say'),
(NULL, 'taunt', 'None may challenge the Brotherhood!', 'say'),
(NULL, 'taunt', 'Foolsss...Kill the one in the dress!', 'say'),
(NULL, 'taunt', 'I''ll feed your soul to Hakkar himself! ', 'say'),
(NULL, 'taunt', 'Pride heralds the end of your world! Come, mortals! Face the wrath of the <randomfaction>!', 'say'),
(NULL, 'taunt', 'All my plans have led to this!', 'say'),
(NULL, 'taunt', 'Ahh! More lambs to the slaughter!', 'say'),
(NULL, 'taunt', 'Another day, another glorious battle!', 'say'),
(NULL, 'taunt', 'So, business... or pleasure?', 'say'),
(NULL, 'taunt', 'You are not prepared!', 'say'),
(NULL, 'taunt', 'The <randomfaction>''s final conquest has begun! Once again the subjugation of this world is within our grasp. Let none survive! ', 'say'),
(NULL, 'taunt', 'Your death will be a painful one. ', 'say'),
(NULL, 'taunt', 'Cry for mercy! Your meaningless lives will soon be forfeit. ', 'say'),
(NULL, 'taunt', 'Abandon all hope! The <randomfaction> has returned to finish what was begun so many years ago. This time there will be no escape! ', 'say'),
(NULL, 'taunt', 'Alert! You are marked for Extermination! ', 'say'),
(NULL, 'taunt', 'The <subzone> is for guests only...', 'say'),
(NULL, 'taunt', 'Ha ha ha! You are hopelessly outmatched!', 'say'),
(NULL, 'taunt', 'I will crush your delusions of grandeur! ', 'say'),
(NULL, 'taunt', 'Forgive me, for you are about to lose the game.', 'say'),
(NULL, 'taunt', 'Struggling only makes it worse.', 'say'),
(NULL, 'taunt', 'Vermin! Leeches! Take my blood and choke on it!', 'say'),
(NULL, 'taunt', 'Not again... NOT AGAIN!', 'say'),
(NULL, 'taunt', 'My blood will be the end of you!', 'say'),
(NULL, 'taunt', 'Good, now you fight me!', 'say'),
(NULL, 'taunt', 'Get da move on, guards! It be killin'' time!', 'say'),
(NULL, 'taunt', 'Don''t be delayin'' your fate. Come to me now. I make your sacrifice quick.', 'say'),
(NULL, 'taunt', 'You be dead soon enough!', 'say'),
(NULL, 'taunt', 'Mua-ha-ha!', 'say'),
(NULL, 'taunt', 'I be da predator! You da prey...', 'say'),
(NULL, 'taunt', 'You gonna leave in pieces!', 'say'),
(NULL, 'taunt', 'Death comes. Will your conscience be clear? ', 'say'),
(NULL, 'taunt', 'Your behavior will not be tolerated.', 'say'),
(NULL, 'taunt', 'The Menagerie is for guests only.', 'say'),
(NULL, 'taunt', 'Hmm, unannounced visitors, Preparations must be made... ', 'say'),
(NULL, 'taunt', 'Hostile entities detected. Threat assessment protocol active. Primary target engaged. Time minus thirty seconds to re-evaluation.', 'say'),
(NULL, 'taunt', 'New toys? For me? I promise I won''t break them this time!', 'say'),
(NULL, 'taunt', 'I''m ready to play!', 'say'),
(NULL, 'taunt', 'Shhh... it will all be over soon.', 'say'),
(NULL, 'taunt', 'Aaaaaughibbrgubugbugrguburgle!', 'say'),
(NULL, 'taunt', 'RwlRwlRwlRwl!', 'say'),
(NULL, 'taunt', 'You too, shall serve!', 'say'),
(NULL, 'taunt', 'Tell me... tell me everything! Naughty secrets! I''ll rip the secrets from your flesh!', 'say'),
(NULL, 'taunt', 'Prepare yourselves, the bells have tolled! Shelter your weak, your young and your old! Each of you shall pay the final sum! Cry for mercy; the reckoning has come!', 'say'),
(NULL, 'taunt', 'Where in Bonzo''s brass buttons am I?', 'say'),
(NULL, 'taunt', 'I can bear it no longer! Goblin King! Goblin King! Wherever you may be! Take this <target> far away from me!', 'say'),
(NULL, 'taunt', 'You have thirteen hours in which to solve the labyrinth, before your baby brother becomes one of us... forever.', 'say'),
(NULL, 'taunt', 'So, the <subzone> is a piece of cake, is it? Well, let''s see how you deal with this little slice... ', 'say'),
(NULL, 'taunt', 'Back off, I''ll take you on, headstrong to take on anyone, I know that you are wrong, and this is not where you belong', 'say'),
(NULL, 'taunt', 'Show me whatcha got!', 'say'),
(NULL, 'taunt', 'To the death!', 'say'),
(NULL, 'taunt', 'Twin blade action, for a clean close shave every time.', 'say'),
(NULL, 'taunt', 'Bring it on!', 'say'),
(NULL, 'taunt', 'You''re goin'' down!', 'say'),
(NULL, 'taunt', 'Stabby stab stab!', 'say'),
(NULL, 'taunt', 'Let''s get this over quick; time is mana.', 'say'),
(NULL, 'taunt', 'I do not think you realise the gravity of your situation.', 'say'),
(NULL, 'taunt', 'I will bring honor to my family and my kingdom!', 'say'),
(NULL, 'taunt', 'Light, give me strength!', 'say'),
(NULL, 'taunt', 'My church is the field of battle - time to worship...', 'say'),
(NULL, 'taunt', 'I hold you in contempt...', 'say'),
(NULL, 'taunt', 'Face the hammer of justice!', 'say'),
(NULL, 'taunt', 'Prove your worth in the test of arms under the Light!', 'say'),
(NULL, 'taunt', 'All must fall before the might and right of my cause, you shall be next!', 'say'),
(NULL, 'taunt', 'Prepare to die!', 'say'),
(NULL, 'taunt', 'The beast with me is nothing compared to the beast within...', 'say'),
(NULL, 'taunt', 'Witness the firepower of this fully armed huntsman!', 'say');
INSERT INTO `playerbots_speech` VALUES
(NULL, 'critical health', 'Heal me! Quick!', 'yell'),
(NULL, 'critical health', 'Almost dead! Heal me!', 'yell'),
(NULL, 'critical health', 'Help! Heal me!', 'yell'),
(NULL, 'critical health', 'Somebody! Heal me!', 'yell'),
(NULL, 'critical health', 'Heal! Heal! Heal!', 'yell'),
(NULL, 'critical health', 'I am dying! Heal! Aaaaarhg!', 'yell'),
(NULL, 'critical health', 'Heal me!', 'yell'),
(NULL, 'critical health', 'I will die. I will die. I will die. Heal!', 'yell'),
(NULL, 'critical health', 'Healers, where are you? I am dying!', 'yell'),
(NULL, 'critical health', 'Oh the pain. Heal me quick!', 'yell');
INSERT INTO `playerbots_speech` VALUES
(NULL, 'low health', 'Need heal', 'say'),
(NULL, 'low health', 'Low health', 'say'),
(NULL, 'low health', 'Drop a heal. Please.', 'say'),
(NULL, 'low health', 'Could somebody drop a heal on me?', 'say'),
(NULL, 'low health', 'Hey! Better heal me now than rez later', 'say'),
(NULL, 'low health', 'I am sorry. Need another heal', 'say'),
(NULL, 'low health', 'Damn mobs. Heal me please', 'say'),
(NULL, 'low health', 'One more hit and I am done for. Heal please', 'say'),
(NULL, 'low health', 'Are there any healers?', 'say'),
(NULL, 'low health', 'Why do they always punch me in the face? Need heal', 'say'),
(NULL, 'low health', 'Can anybody heal me a bit?', 'say');
INSERT INTO `playerbots_speech` VALUES
(NULL, 'low mana', 'OOM', 'say'),
(NULL, 'low mana', 'I am out of mana', 'say'),
(NULL, 'low mana', 'Damn I wasted all my mana on this', 'say'),
(NULL, 'low mana', 'You should wait until I drink or regenerate my mana', 'say'),
(NULL, 'low mana', 'Low mana', 'say'),
(NULL, 'low mana', 'No mana. Again?', 'say'),
(NULL, 'low mana', 'Low mana. Wanna drink', 'say'),
(NULL, 'low mana', 'Do we have a vending machine? Out of mana again', 'say'),
(NULL, 'low mana', 'My mana is history', 'say'),
(NULL, 'low mana', 'I''d get some drinks next time. Out of mana', 'say'),
(NULL, 'low mana', 'Where is my mana?', 'say');
INSERT INTO `playerbots_speech` VALUES
(NULL, 'aoe', 'Oh god!', 'say'),
(NULL, 'aoe', 'I am scared', 'say'),
(NULL, 'aoe', 'We are done for', 'say'),
(NULL, 'aoe', 'This is over', 'say'),
(NULL, 'aoe', 'This ends now', 'say'),
(NULL, 'aoe', 'Could somebody cast blizzard or something?', 'say'),
(NULL, 'aoe', 'Damn. The tank aggroed all the mobs around', 'say'),
(NULL, 'aoe', 'We gonna die. We gonna die. We gonna die.', 'say'),
(NULL, 'aoe', 'Whoa! So many toys to play with', 'say'),
(NULL, 'aoe', 'I gonna kill them all!', 'say'),
(NULL, 'aoe', 'If the tank dies we are history', 'say'),
(NULL, 'aoe', 'Aaaaaargh!', 'yell'),
(NULL, 'aoe', 'LEEEEERROOOYYYYYYYYYYYY JENNKINNNSSSSSS!!!!!!!', 'yell'),
(NULL, 'aoe', 'Right. What do we have in AOE?', 'say'),
(NULL, 'aoe', 'This gets interesting', 'say'),
(NULL, 'aoe', 'Cool. Get them in one place for a good flamestrike', 'say'),
(NULL, 'aoe', 'Kill! Kill! Kill!', 'say'),
(NULL, 'aoe', 'I think my pants are wet', 'say'),
(NULL, 'aoe', 'We are history', 'say'),
(NULL, 'aoe', 'I hope healers are ready. Leeeeroy!', 'say'),
(NULL, 'aoe', 'I hope they won''t come for me', 'say'),
(NULL, 'aoe', 'Oh no. I can''t see at this slaugther', 'say');
INSERT INTO `playerbots_speech` VALUES
(NULL, 'loot', 'I hope there will be some money', 'say'),
(NULL, 'loot', 'Loot! Loot!', 'say'),
(NULL, 'loot', 'My precious', 'say'),
(NULL, 'loot', 'I hope there is a shiny epic item waiting for me there', 'say'),
(NULL, 'loot', 'I have deep pockets and bags', 'say'),
(NULL, 'loot', 'All is mine!', 'say'),
(NULL, 'loot', 'Hope no gray shit today', 'say'),
(NULL, 'loot', 'This loot is MINE!', 'say'),
(NULL, 'loot', 'Looting is disgusting but I need money', 'say'),
(NULL, 'loot', 'Gold!', 'say'),
(NULL, 'loot', 'OK. Let''s see what they''ve got', 'say'),
(NULL, 'loot', 'Do not worry. I will loot eveything', 'say'),
(NULL, 'loot', 'I am loot ninja', 'say'),
(NULL, 'loot', 'Do I neeed to roll?', 'say'),
(NULL, 'loot', 'Somebody explain me, where they did put all this stuff?', 'say'),
(NULL, 'loot', 'No, I won''t loot gray shit', 'say'),
(NULL, 'loot', 'I''m first. I''m first. I''m first.', 'say'),
(NULL, 'loot', 'Give me your money!', 'say'),
(NULL, 'loot', 'My pockets are empty, I need to fill them', 'say'),
(NULL, 'loot', 'I''ve got a new bag for this', 'say'),
(NULL, 'loot', 'I hope I won''t aggro anybody while looting', 'say'),
(NULL, 'loot', 'Please don''t watch. I am looting', 'say'),
(NULL, 'loot', 'Ha! You won''t get any piece of it!', 'say'),
(NULL, 'loot', 'Looting is cool', 'say'),
(NULL, 'loot', 'I like new gear', 'say'),
(NULL, 'loot', 'I''l quit if there is nothing valuable again', 'say'),
(NULL, 'loot', 'I hope it is be a pretty ring', 'say'),
(NULL, 'loot', 'I''l rip the loot from you', 'say'),
(NULL, 'loot', 'Everybody stay off. I''m going to loot', 'say'),
(NULL, 'loot', 'Sweet loot', 'say'),
(NULL, 'loot', 'The Roll God! Give me an epic today', 'say'),
(NULL, 'loot', 'Please give me new toys', 'say'),
(NULL, 'loot', 'I hope they carry tasties', 'say'),
(NULL, 'loot', 'The gold is mine. I''l leave everyting, I promise', 'say'),
(NULL, 'loot', 'No, I can''t resist', 'say'),
(NULL, 'loot', 'I want more!', 'say');
INSERT INTO `playerbots_speech` VALUES
(NULL, 'low ammo', 'I have few <ammo> left!', 'say'),
(NULL, 'low ammo', 'I need more <ammo>!', 'say'),
(NULL, 'low ammo', '100 <ammo> left!', 'say'),
(NULL, 'no ammo', 'That\'s it! No <ammo>!', 'say'),
(NULL, 'no ammo', 'And you have my bow... Oops, no <ammo>!', 'say'),
(NULL, 'no ammo', 'Need ammo!', 'yell');

View File

@ -0,0 +1,12 @@
DROP TABLE IF EXISTS `playerbots_speech_probability`;
CREATE TABLE `playerbots_speech_probability` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`probability` INT(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `playerbots_speech_probability` VALUES
(NULL, 'taunt', 30),
(NULL, 'aoe', 75),
(NULL, 'loot', 20);

View File

@ -0,0 +1,10 @@
DROP TABLE IF EXISTS `playerbots_tele_cache`;
CREATE TABLE `playerbots_tele_cache` (
`id` INT(11) auto_increment,
`level` TINYINT(3) NOT NULL,
`map_id` mediumint(8) NOT NULL,
`x` float(8) NOT NULL,
`y` float(8) NOT NULL,
`z` float(8) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Playerbots Tele Cache';

View File

@ -0,0 +1,246 @@
DROP TABLE IF EXISTS `playerbots_text`;
CREATE TABLE `playerbots_text` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`key` varchar(255) NOT NULL,
`text` varchar(1024) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `playerbots_text` VALUES
-- %role - Healer, Tank, Frost Mage, Elemental Shaman etc
-- %instance - name of the dungeon by bot's level
(NULL, 'suggest_instance', 'Anyone wants %instance?'),
(NULL, 'suggest_instance', 'Any groups for %instance?'),
(NULL, 'suggest_instance', 'Need help for %instance?'),
(NULL, 'suggest_instance', 'LFD: %instance.'),
(NULL, 'suggest_instance', 'Anyone needs %role for %instance?'),
(NULL, 'suggest_instance', 'Missing %role for %instance?'),
(NULL, 'suggest_instance', 'Can be a %role for %instance.'),
(NULL, 'suggest_instance', 'Need help with %instance?'),
(NULL, 'suggest_instance', 'Need %role help with %instance?'),
(NULL, 'suggest_instance', 'Anyone needs gear from %instance?'),
(NULL, 'suggest_instance', 'A little grind in %instance?'),
(NULL, 'suggest_instance', 'WTR %instance'),
(NULL, 'suggest_instance', 'Need help for %instance.'),
(NULL, 'suggest_instance', 'Wanna run %instance.'),
(NULL, 'suggest_instance', '%role looks for %instance.'),
(NULL, 'suggest_instance', 'What about %instance?'),
(NULL, 'suggest_instance', 'Who wants to farm %instance?'),
(NULL, 'suggest_instance', 'Go in %instance?'),
(NULL, 'suggest_instance', 'Looking for %instance.'),
(NULL, 'suggest_instance', 'Need help with %instance quests?'),
(NULL, 'suggest_instance', 'Wanna quest in %instance.'),
(NULL, 'suggest_instance', 'Anyone with quests in %instance?'),
(NULL, 'suggest_instance', 'Could help with quests in %instance.'),
(NULL, 'suggest_instance', '%role: any place in group for %instance?'),
(NULL, 'suggest_instance', 'Does anybody still run %instance this days?'),
(NULL, 'suggest_instance', '%instance: anyone wants to take a %role?'),
(NULL, 'suggest_instance', 'Is there any point being %role in %instance?'),
(NULL, 'suggest_instance', 'It is really worth to go to %instance?'),
(NULL, 'suggest_instance', 'Anybody needs more people for %instance?'),
(NULL, 'suggest_instance', '%instance bosses drop good gear. Wanna run?'),
(NULL, 'suggest_instance', 'What about %instance?'),
(NULL, 'suggest_instance', 'Anybody needs %role?'),
(NULL, 'suggest_instance', 'Anyone needs %role?'),
(NULL, 'suggest_instance', 'Who wants %instance?'),
(NULL, 'suggest_instance', 'Can anybody summon me at %instance?'),
(NULL, 'suggest_instance', 'Meet me in %instance'),
(NULL, 'suggest_instance', 'Wanna quick %instance run'),
(NULL, 'suggest_instance', 'Wanna full %instance run'),
(NULL, 'suggest_instance', 'How many times were you in %instance?'),
(NULL, 'suggest_instance', 'Another %instance run?'),
(NULL, 'suggest_instance', 'Wiped in %instance? Take me instead!'),
(NULL, 'suggest_instance', 'Take me in %instance please.'),
(NULL, 'suggest_instance', 'Quick %instance run?'),
(NULL, 'suggest_instance', 'Full %instance run?'),
(NULL, 'suggest_instance', 'Who can take %role to %instance?'),
-- == Quest ==
-- %quest - random player's quest
(NULL, 'suggest_quest', 'Need help with %quest?'),
(NULL, 'suggest_quest', 'Anyone wants to share %quest?'),
(NULL, 'suggest_quest', 'Anyone doing %quest?'),
(NULL, 'suggest_quest', 'Wanna do %quest.'),
-- == Trade materials (AH) ==
-- %category - AH category to grind
(NULL, 'suggest_trade', 'Anyone to farm %category?'),
(NULL, 'suggest_trade', 'Looking for help farming %category.'),
(NULL, 'suggest_trade', 'Damn %category are so expensive!'),
(NULL, 'suggest_trade', 'Wanna %category.'),
(NULL, 'suggest_trade', 'Need help with %category.'),
(NULL, 'suggest_trade', 'WTB %category.'),
(NULL, 'suggest_trade', 'Anyone interested in %category?'),
(NULL, 'suggest_trade', 'WTS %category.'),
(NULL, 'suggest_trade', 'I am selling %category cheaper than AH.'),
(NULL, 'suggest_trade', 'Who wants to farm %category?'),
(NULL, 'suggest_trade', 'Wanna farm %category.'),
(NULL, 'suggest_trade', 'Looking for party after %category.'),
(NULL, 'suggest_trade', 'Any %category are appreciated.'),
(NULL, 'suggest_trade', 'Buying anything of %category.'),
(NULL, 'suggest_trade', 'Wow, anybody is farming %category!'),
(NULL, 'suggest_trade', '%category are selling mad in the AH.'),
(NULL, 'suggest_trade', 'AH is hot for %category.'),
(NULL, 'suggest_trade', '%category are on the market.'),
(NULL, 'suggest_trade', 'Wanna trade some %category.'),
(NULL, 'suggest_trade', 'Need more %category.'),
(NULL, 'suggest_trade', 'Anybody can spare some %category?'),
(NULL, 'suggest_trade', 'Who wants %category?'),
(NULL, 'suggest_trade', 'Some %category please?'),
(NULL, 'suggest_trade', 'I should have got skill for %category.'),
(NULL, 'suggest_trade', 'I am dying for %category.'),
(NULL, 'suggest_trade', 'People are killing for %category.'),
(NULL, 'suggest_trade', '%category is a great bargain!'),
(NULL, 'suggest_trade', 'Everybody is mad for %category!'),
(NULL, 'suggest_trade', 'Where is the best place to farm for %category?'),
(NULL, 'suggest_trade', 'I am all set for %category.'),
(NULL, 'suggest_trade', 'Is it good to sell %category?'),
(NULL, 'suggest_trade', 'I''d probably keep all my %category with me.'),
(NULL, 'suggest_trade', 'Need group? Maybe to farm some %category?'),
(NULL, 'suggest_trade', 'I am still thinking about %category.'),
(NULL, 'suggest_trade', 'I heard about %category already, but my pockets are empty.'),
(NULL, 'suggest_trade', 'LFG for %category'),
(NULL, 'suggest_trade', 'Would selling %category make me rich?'),
(NULL, 'suggest_trade', 'OK. I an farming %category tomorrow.'),
(NULL, 'suggest_trade', 'Everyone is talking about %category.'),
(NULL, 'suggest_trade', 'I saw at least ten people farming for %category.'),
(NULL, 'suggest_trade', 'I sold all my %category yesterday. I am completely broke!'),
(NULL, 'suggest_trade', 'Wanna join a guild farming for %category.'),
-- == Reputation ==
-- %faction - random faction name
-- %level - random level (honored, revered, exalted)
-- %rnd - urand(1,5)
(NULL, 'suggest_faction', 'Anyone farming %faction rep?'),
(NULL, 'suggest_faction', 'Anyone help with %faction?'),
(NULL, 'suggest_faction', 'Wanna quest for %faction.'),
(NULL, 'suggest_faction', '%faction is the best.'),
(NULL, 'suggest_faction', 'Need just a bit to be %level with %faction.'),
(NULL, 'suggest_faction', 'Anyone got %level with %faction?'),
(NULL, 'suggest_faction', 'Who wants to be %level with %faction?'),
(NULL, 'suggest_faction', 'I''ll never be %level with %faction.'),
(NULL, 'suggest_faction', 'Someone missing %faction rep?'),
(NULL, 'suggest_faction', 'Could help farming %faction rep.'),
(NULL, 'suggest_faction', 'The more rep the better. Especially with %faction.'),
(NULL, 'suggest_faction', '%faction: need %rndK for %level.'),
(NULL, 'suggest_faction', 'Who can share %faction quests?'),
(NULL, 'suggest_faction', 'Any dungeons for %faction?'),
(NULL, 'suggest_faction', 'Wanna do %faction rep grind.'),
(NULL, 'suggest_faction', 'Let''s farm %faction rep!'),
(NULL, 'suggest_faction', 'Farming for %faction rep.'),
(NULL, 'suggest_faction', 'Wanna farm for %faction.'),
(NULL, 'suggest_faction', 'Need help with %faction.'),
(NULL, 'suggest_faction', 'Is %faction sells something useful?'),
(NULL, 'suggest_faction', 'Are there %faction vendors?'),
(NULL, 'suggest_faction', 'Who farms %faction?'),
(NULL, 'suggest_faction', 'Which is the best way to farm %faction?'),
(NULL, 'suggest_faction', 'I hate %faction rep grind.'),
(NULL, 'suggest_faction', 'I am so tired of %faction.'),
(NULL, 'suggest_faction', 'Go for %faction?'),
(NULL, 'suggest_faction', 'Seems everyone is %level with %faction. Only me is late as usually.'),
(NULL, 'suggest_faction', 'LFG for %faction rep grind?'),
(NULL, 'suggest_faction', 'Can anobody suggest a good spot for %faction rep grind?'),
(NULL, 'suggest_faction', 'Would %faction rep benefit me?'),
(NULL, 'suggest_faction', 'Who would''ve thought that %faction rep will be useful after all...'),
(NULL, 'suggest_faction', 'I wanna be exalted with all factions, starting with %faction.'),
(NULL, 'suggest_faction', 'Is there any point to improve my rep with %faction?'),
(NULL, 'suggest_faction', 'What is better for %faction? Quests or mob grinding?'),
(NULL, 'suggest_faction', 'Will grind %faction rep for you. Just give me some gold.'),
(NULL, 'suggest_faction', 'I think grinding rep with %faction would take forever.'),
(NULL, 'suggest_faction', 'I am killing for %faction every day now but still far from %level.'),
(NULL, 'suggest_faction', 'At %level AH deposits will decrease, right?'),
(NULL, 'suggest_faction', 'How many exalted reps do you have?'),
(NULL, 'suggest_faction', 'Who wants to be %level with %faction?'),
(NULL, 'suggest_faction', 'Damn. My guild did a good %faction grind yesterday without me.'),
(NULL, 'suggest_faction', 'Nobody wants to help me because I am %level with %faction.'),
(NULL, 'suggest_faction', 'Please stay away from %faction.'),
-- == Anything ==
-- %role - Healer, Tank, Frost Mage, Elemental Shaman etc
-- %zone - Name of the bot zone
(NULL, 'suggest_something', 'Wanna party in %zone.'),
(NULL, 'suggest_something', 'Anyone is looking for %role?'),
(NULL, 'suggest_something', '%role is looking for quild.'),
(NULL, 'suggest_something', 'Looking for gold.'),
(NULL, 'suggest_something', '%role wants to join a good guild.'),
(NULL, 'suggest_something', 'Need a friend.'),
(NULL, 'suggest_something', 'Anyone feels alone?'),
(NULL, 'suggest_something', 'Boring...'),
(NULL, 'suggest_something', 'Who wants some?'),
(NULL, 'suggest_something', 'Go get me!'),
(NULL, 'suggest_something', 'Maybe a duel in %zone?'),
(NULL, 'suggest_something', 'Anybody doing something?'),
(NULL, 'suggest_something', '%zone: is anybody here?'),
(NULL, 'suggest_something', '%zone: where is everyone?'),
(NULL, 'suggest_something', 'Looks like I am alone in %zone.'),
(NULL, 'suggest_something', 'Meet me in %zone.'),
(NULL, 'suggest_something', 'Let''s quest in %zone!'),
(NULL, 'suggest_something', '%zone is the best place to be!'),
(NULL, 'suggest_something', 'Wanna go to %zone. Anybody with me?'),
(NULL, 'suggest_something', 'Who wants going to %zone?'),
(NULL, 'suggest_something', 'I don''t like %zone. Where to go?'),
(NULL, 'suggest_something', 'Are there a good quests in %zone?'),
(NULL, 'suggest_something', 'Where to go after %zone?'),
(NULL, 'suggest_something', 'Who is in %zone?'),
(NULL, 'suggest_something', 'LFG in %zone.'),
(NULL, 'suggest_something', '%zone is the worst place to be.'),
(NULL, 'suggest_something', 'Catch me in %zone!'),
(NULL, 'suggest_something', 'Go for %zone!'),
(NULL, 'suggest_something', 'Wanna quest in %zone'),
(NULL, 'suggest_something', 'Anyone has quests in %zone?'),
(NULL, 'suggest_something', 'Come here to %zone!'),
(NULL, 'suggest_something', 'Seems there is no Horde in %zone'),
(NULL, 'suggest_something', 'Seems there is no Alliance in %zone'),
(NULL, 'suggest_something', 'I am really tired of %zone. Maybe go somewhere else?'),
-- == Trade ==
-- %item - [item]xN
(NULL, 'suggest_sell', 'WTS %item for %gold.'),
(NULL, 'suggest_sell', 'Who wants %item for %gold?'),
(NULL, 'suggest_sell', 'Anyone wants %item? Only %gold.'),
(NULL, 'suggest_sell', 'Just %gold for %item!'),
(NULL, 'suggest_sell', 'Selling %item for %gold.'),
(NULL, 'suggest_sell', '%item is yours just for %gold!'),
(NULL, 'suggest_sell', 'Ridiculus price of %gold for %item!'),
(NULL, 'suggest_sell', 'Wanna sell %item for %gold.'),
(NULL, 'suggest_sell', 'Who needs %item? Only %gold.'),
(NULL, 'suggest_sell', 'Anyone needs %item for %gold?'),
(NULL, 'suggest_sell', '%gold for %item. Less than AH!'),
(NULL, 'suggest_sell', '%item is expensive, but I''d sell it for %gold.'),
(NULL, 'suggest_sell', 'You''ll never find %item cheaper than %gold!'),
(NULL, 'suggest_sell', 'Need more than %item!'),
(NULL, 'suggest_sell', 'I have %item and need more.'),
(NULL, 'suggest_sell', 'Have %item. Who wants to buy for %gold?'),
(NULL, 'suggest_sell', 'Anyone WTB %item for %gold?'),
(NULL, 'suggest_sell', 'What about %item? For %gold.'),
(NULL, 'suggest_sell', 'Who said I am a bastard? %item for %gold is a good price.'),
(NULL, 'suggest_sell', 'I am selling %item? Just %gold.'),
(NULL, 'suggest_sell', 'LFG for farming. You can still buy %item I have for %gold.'),
(NULL, 'suggest_sell', 'Sold almost everything today. Still have %item for %gold.'),
(NULL, 'suggest_sell', 'What use for trade chat? Of course to sell %item for %gold.'),
(NULL, 'suggest_sell', 'Can anyone beat the price of %gold for %item?'),
(NULL, 'suggest_sell', 'Wanna stop trade chat? Just buy %item? For %gold!'),
(NULL, 'suggest_sell', 'Everybody spams in trade chat. Me too - %gold for %item!'),
(NULL, 'suggest_sell', 'Is %item any use? Just selling it for %gold.'),
(NULL, 'suggest_sell', 'I have %item ready to sell you for %gold.'),
(NULL, 'suggest_sell', 'Did nothing yesterday but have got %item. Selling it for %gold.'),
(NULL, 'suggest_sell', 'Farmed yesterday and got %item. Anyone wtb for %gold?'),
(NULL, 'suggest_sell', 'Bought %item yesterday. Anyone needs it for %gold?'),
(NULL, 'suggest_sell', 'Who asked for %item? The price is the same - %gold.'),
(NULL, 'suggest_sell', 'I sill have %item. WTB for %gold?'),
(NULL, 'suggest_sell', 'I used to have more than %item. Now needs to sell it for %gold.'),
(NULL, 'suggest_sell', 'I wish I have more than %item. You could buy it for %gold anyways.'),
(NULL, 'suggest_sell', 'What use for your gold? To buy my %item for %gold.'),
(NULL, 'suggest_sell', 'Please spare some gold for me. You can buy %item for %gold.'),
(NULL, 'suggest_sell', 'Is %gold is a good price for %item?'),
(NULL, 'suggest_sell', 'Just bought yesterday %items, but do not need it anymore. Anyone wants for %gold?'),
(NULL, 'suggest_sell', 'I am going to post %item on the AH but you can buy it now cheaper just for %gold.'),
(NULL, 'suggest_sell', 'Why the #!@ have I bought %item? Anyone needs it for %gold?')
;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,284 @@
DROP TABLE IF EXISTS `playerbots_weightscale_data`;
CREATE TABLE IF NOT EXISTS `playerbots_weightscale_data` (
`id` int(32) NOT NULL,
`field` varchar(18) NOT NULL,
`val` smallint(6) unsigned NOT NULL,
KEY `id` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `playerbots_weightscale_data` (`id`, `field`, `val`) VALUES
(1, 'exprtng', 100),
(1, 'str', 82),
(1, 'critstrkrtng', 66),
(1, 'agi', 53),
(1, 'armorpenrtng', 52),
(1, 'hitrtng', 48),
(1, 'hastertng', 36),
(1, 'atkpwr', 31),
(1, 'armor', 5),
(2, 'exprtng', 100),
(2, 'str', 82),
(2, 'critstrkrtng', 66),
(2, 'agi', 53),
(2, 'armorpenrtng', 52),
(2, 'hitrtng', 48),
(2, 'hastertng', 36),
(2, 'atkpwr', 31),
(2, 'armor', 5),
(3, 'sta', 100),
(3, 'dodgertng', 90),
(3, 'defrtng', 86),
(3, 'block', 81),
(3, 'agi', 67),
(3, 'parryrtng', 67),
(3, 'blockrtng', 48),
(3, 'str', 48),
(3, 'exprtng', 19),
(3, 'hitrtng', 10),
(3, 'armorpenrtng', 10),
(3, 'critstrkrtng', 7),
(3, 'armor', 6),
(3, 'hastertng', 1),
(3, 'atkpwr', 1),
(4, 'int', 100),
(4, 'manargn', 88),
(4, 'splpwr', 58),
(4, 'critstrkrtng', 46),
(4, 'hastertng', 35),
(5, 'sta', 100),
(5, 'dodgertng', 94),
(5, 'block', 86),
(5, 'defrtng', 86),
(5, 'exprtng', 79),
(5, 'agi', 76),
(5, 'parryrtng', 76),
(5, 'hitrtng', 58),
(5, 'blockrtng', 52),
(5, 'str', 50),
(5, 'armor', 6),
(5, 'atkpwr', 6),
(5, 'splpwr', 4),
(5, 'critstrkrtng', 3),
(6, 'mledps', 470),
(6, 'hitrtng', 100),
(6, 'str', 80),
(6, 'exprtng', 66),
(6, 'critstrkrtng', 40),
(6, 'atkpwr', 34),
(6, 'agi', 32),
(6, 'hastertng', 30),
(6, 'armorpenrtng', 22),
(6, 'splpwr', 9),
(7, 'rgddps', 213),
(7, 'hitrtng', 100),
(7, 'agi', 58),
(7, 'critstrkrtng', 40),
(7, 'int', 37),
(7, 'atkpwr', 30),
(7, 'armorpenrtng', 28),
(7, 'hastertng', 21),
(8, 'rgddps', 379),
(8, 'hitrtng', 100),
(8, 'agi', 74),
(8, 'critstrkrtng', 57),
(8, 'armorpenrtng', 40),
(8, 'int', 39),
(8, 'atkpwr', 32),
(8, 'hastertng', 24),
(9, 'rgddps', 181),
(9, 'hitrtng', 100),
(9, 'agi', 76),
(9, 'critstrkrtng', 42),
(9, 'int', 35),
(9, 'hastertng', 31),
(9, 'atkpwr', 29),
(9, 'armorpenrtng', 26),
(10, 'mledps', 170),
(10, 'agi', 100),
(10, 'exprtng', 87),
(10, 'hitrtng', 83),
(10, 'critstrkrtng', 81),
(10, 'atkpwr', 65),
(10, 'armorpenrtng', 65),
(10, 'hastertng', 64),
(10, 'str', 55),
(11, 'mledps', 220),
(11, 'armorpenrtng', 100),
(11, 'agi', 100),
(11, 'exprtng', 82),
(11, 'hitrtng', 80),
(11, 'critstrkrtng', 75),
(11, 'hastertng', 73),
(11, 'str', 55),
(11, 'atkpwr', 50),
(12, 'mledps', 228),
(12, 'exprtng', 100),
(12, 'agi', 100),
(12, 'hitrtng', 80),
(12, 'armorpenrtng', 75),
(12, 'critstrkrtng', 75),
(12, 'hastertng', 75),
(12, 'str', 55),
(12, 'atkpwr', 50),
(13, 'splpwr', 100),
(13, 'manargn', 67),
(13, 'int', 65),
(13, 'hastertng', 59),
(13, 'critstrkrtng', 48),
(13, 'spi', 22),
(14, 'manargn', 100),
(14, 'int', 69),
(14, 'splpwr', 60),
(14, 'spi', 52),
(14, 'critstrkrtng', 38),
(14, 'hastertng', 31),
(15, 'hitrtng', 100),
(15, 'shasplpwr', 76),
(15, 'splpwr', 76),
(15, 'critstrkrtng', 54),
(15, 'hastertng', 50),
(15, 'spi', 16),
(15, 'int', 16),
(16, 'mledps', 360),
(16, 'armorpenrtng', 100),
(16, 'str', 99),
(16, 'hitrtng', 91),
(16, 'exprtng', 90),
(16, 'critstrkrtng', 57),
(16, 'hastertng', 55),
(16, 'atkpwr', 36),
(16, 'armor', 1),
(17, 'mledps', 337),
(17, 'hitrtng', 100),
(17, 'str', 97),
(17, 'exprtng', 81),
(17, 'armorpenrtng', 61),
(17, 'critstrkrtng', 45),
(17, 'atkpwr', 35),
(17, 'hastertng', 28),
(17, 'armor', 1),
(18, 'mledps', 419),
(18, 'parryrtng', 100),
(18, 'hitrtng', 97),
(18, 'str', 96),
(18, 'defrtng', 85),
(18, 'exprtng', 69),
(18, 'dodgertng', 61),
(18, 'agi', 61),
(18, 'sta', 61),
(18, 'critstrkrtng', 49),
(18, 'atkpwr', 41),
(18, 'armorpenrtng', 31),
(18, 'armor', 5),
(19, 'mledps', 209),
(19, 'str', 100),
(19, 'hitrtng', 66),
(19, 'exprtng', 51),
(19, 'hastertng', 48),
(19, 'critstrkrtng', 45),
(19, 'atkpwr', 34),
(19, 'armorpenrtng', 32),
(19, 'armor', 1),
(20, 'hitrtng', 100),
(20, 'splpwr', 60),
(20, 'hastertng', 56),
(20, 'critstrkrtng', 40),
(20, 'int', 11),
(21, 'mledps', 135),
(21, 'hitrtng', 100),
(21, 'exprtng', 84),
(21, 'agi', 55),
(21, 'int', 55),
(21, 'critstrkrtng', 55),
(21, 'hastertng', 42),
(21, 'str', 35),
(21, 'atkpwr', 32),
(21, 'splpwr', 29),
(21, 'armorpenrtng', 26),
(22, 'manargn', 100),
(22, 'int', 85),
(22, 'splpwr', 77),
(22, 'critstrkrtng', 62),
(22, 'hastertng', 35),
(23, 'hitrtng', 100),
(23, 'hastertng', 54),
(23, 'arcsplpwr', 49),
(23, 'splpwr', 49),
(23, 'critstrkrtng', 37),
(23, 'int', 34),
(23, 'frosplpwr', 24),
(23, 'firsplpwr', 24),
(23, 'spi', 14),
(24, 'hitrtng', 100),
(24, 'hastertng', 53),
(24, 'firsplpwr', 46),
(24, 'splpwr', 46),
(24, 'critstrkrtng', 43),
(24, 'frosplpwr', 23),
(24, 'arcsplpwr', 23),
(24, 'int', 13),
(25, 'hitrtng', 100),
(25, 'hastertng', 42),
(25, 'frosplpwr', 39),
(25, 'splpwr', 39),
(25, 'arcsplpwr', 19),
(25, 'firsplpwr', 19),
(25, 'critstrkrtng', 19),
(25, 'int', 6),
(26, 'hitrtng', 100),
(26, 'shasplpwr', 72),
(26, 'splpwr', 72),
(26, 'hastertng', 61),
(26, 'critstrkrtng', 38),
(26, 'firsplpwr', 36),
(26, 'spi', 34),
(26, 'int', 15),
(27, 'hitrtng', 100),
(27, 'hastertng', 50),
(27, 'firsplpwr', 45),
(27, 'shasplpwr', 45),
(27, 'splpwr', 45),
(27, 'critstrkrtng', 31),
(27, 'spi', 29),
(27, 'int', 13),
(28, 'hitrtng', 100),
(28, 'firsplpwr', 47),
(28, 'splpwr', 47),
(28, 'hastertng', 46),
(28, 'spi', 26),
(28, 'shasplpwr', 23),
(28, 'critstrkrtng', 16),
(28, 'int', 13),
(29, 'hitrtng', 100),
(29, 'splpwr', 66),
(29, 'hastertng', 54),
(29, 'critstrkrtng', 43),
(29, 'spi', 22),
(29, 'int', 22),
(30, 'agi', 100),
(30, 'sta', 75),
(30, 'dodgertng', 65),
(30, 'defrtng', 60),
(30, 'exprtng', 16),
(30, 'str', 10),
(30, 'armor', 10),
(30, 'hitrtng', 8),
(30, 'hastertng', 5),
(30, 'atkpwr', 4),
(30, 'feratkpwr', 4),
(30, 'critstrkrtng', 3),
(31, 'splpwr', 100),
(31, 'manargn', 73),
(31, 'hastertng', 57),
(31, 'int', 51),
(31, 'spi', 32),
(31, 'critstrkrtng', 11),
(32, 'agi', 100),
(32, 'armorpenrtng', 90),
(32, 'str', 80),
(32, 'critstrkrtng', 55),
(32, 'exprtng', 50),
(32, 'hitrtng', 50),
(32, 'feratkpwr', 40),
(32, 'atkpwr', 40),
(32, 'hastertng', 35);

View File

@ -0,0 +1,41 @@
DROP TABLE IF EXISTS `playerbots_weightscales`;
CREATE TABLE IF NOT EXISTS `playerbots_weightscales` (
`id` int(32) NOT NULL AUTO_INCREMENT,
`name` varchar(32) NOT NULL,
`class` tinyint(3) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=33 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT;
INSERT INTO `playerbots_weightscales` (`id`, `name`, `class`) VALUES
(1, 'arms', 1),
(2, 'fury', 1),
(3, 'prot', 1),
(4, 'holy', 2),
(5, 'prot', 2),
(6, 'retrib', 2),
(7, 'beast', 3),
(8, 'marks', 3),
(9, 'surv', 3),
(10, 'assas', 4),
(11, 'combat', 4),
(12, 'subtle', 4),
(13, 'disc', 5),
(14, 'holy', 5),
(15, 'shadow', 5),
(16, 'blooddps', 6),
(17, 'frostdps', 6),
(18, 'frosttank', 6),
(19, 'unholydps', 6),
(20, 'elem', 7),
(21, 'enhance', 7),
(22, 'resto', 7),
(23, 'arcane', 8),
(24, 'fire', 8),
(25, 'frost', 8),
(26, 'afflic', 9),
(27, 'demo', 9),
(28, 'destro', 9),
(29, 'balance', 11),
(30, 'feraltank', 11),
(31, 'resto', 11),
(32, 'feraldps', 11);

View File

@ -0,0 +1,31 @@
-- --------------------------------------------------------
-- Хост: 127.0.0.1
-- Версия сервера: 10.6.4-MariaDB - mariadb.org binary distribution
-- Операционная система: Win64
-- HeidiSQL Версия: 11.3.0.6295
-- --------------------------------------------------------
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET NAMES utf8 */;
/*!50503 SET NAMES utf8mb4 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
-- Дамп структуры для таблица _acore_playerbots.updates
DROP TABLE IF EXISTS `updates`;
CREATE TABLE IF NOT EXISTS `updates` (
`name` varchar(200) NOT NULL COMMENT 'filename with extension of the update.',
`hash` char(40) DEFAULT '' COMMENT 'sha1 hash of the sql file.',
`state` enum('RELEASED','ARCHIVED','CUSTOM') NOT NULL DEFAULT 'RELEASED' COMMENT 'defines if an update is released or archived.',
`timestamp` timestamp NOT NULL DEFAULT current_timestamp() COMMENT 'timestamp when the query was applied.',
`speed` INT unsigned NOT NULL DEFAULT 0 COMMENT 'time the query takes to apply in ms.',
PRIMARY KEY (`name`) USING BTREE
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC COMMENT='List of all applied updates in this database.';
/*!40000 ALTER TABLE `updates` ENABLE KEYS */;
/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */;
/*!40014 SET FOREIGN_KEY_CHECKS=IFNULL(@OLD_FOREIGN_KEY_CHECKS, 1) */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40111 SET SQL_NOTES=IFNULL(@OLD_SQL_NOTES, 1) */;

View File

@ -0,0 +1,35 @@
-- --------------------------------------------------------
-- Хост: 127.0.0.1
-- Версия сервера: 10.6.4-MariaDB - mariadb.org binary distribution
-- Операционная система: Win64
-- HeidiSQL Версия: 11.3.0.6295
-- --------------------------------------------------------
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET NAMES utf8 */;
/*!50503 SET NAMES utf8mb4 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
-- Дамп структуры для таблица _acore_playerbots.updates_include
DROP TABLE IF EXISTS `updates_include`;
CREATE TABLE IF NOT EXISTS `updates_include` (
`path` varchar(200) NOT NULL COMMENT 'directory to include. $ means relative to the source directory.',
`state` enum('RELEASED','ARCHIVED','CUSTOM') NOT NULL DEFAULT 'RELEASED' COMMENT 'defines if the directory contains released or archived updates.',
PRIMARY KEY (`path`) USING BTREE
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC COMMENT='List of directories where we want to include sql updates.';
-- Дамп данных таблицы _acore_playerbots.updates_include: 3 rows
DELETE FROM `updates_include`;
/*!40000 ALTER TABLE `updates_include` DISABLE KEYS */;
INSERT INTO `updates_include` (`path`, `state`) VALUES
('$/sql/playerbots/updates', 'RELEASED'),
('$/sql/playerbots/custom', 'CUSTOM'),
('$/sql/playerbots/archive', 'ARCHIVED');
/*!40000 ALTER TABLE `updates_include` ENABLE KEYS */;
/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */;
/*!40014 SET FOREIGN_KEY_CHECKS=IFNULL(@OLD_FOREIGN_KEY_CHECKS, 1) */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40111 SET SQL_NOTES=IFNULL(@OLD_SQL_NOTES, 1) */;

View File

@ -0,0 +1,31 @@
-- --------------------------------------------------------
-- Хост: 127.0.0.1
-- Версия сервера: 10.6.4-MariaDB - mariadb.org binary distribution
-- Операционная система: Win64
-- HeidiSQL Версия: 11.3.0.6295
-- --------------------------------------------------------
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET NAMES utf8 */;
/*!50503 SET NAMES utf8mb4 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
-- Дамп структуры для таблица _acore_playerbots.version_db_playerbots
DROP TABLE IF EXISTS `version_db_playerbots`;
CREATE TABLE IF NOT EXISTS `version_db_playerbots` (
`sql_rev` varchar(100) NOT NULL,
`required_rev` varchar(100) DEFAULT NULL,
`date` varchar(50) DEFAULT NULL,
PRIMARY KEY (`sql_rev`),
KEY `required` (`required_rev`),
CONSTRAINT `required` FOREIGN KEY (`required_rev`) REFERENCES `version_db_playerbots` (`sql_rev`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC COMMENT='Last applied sql update to DB';
/*!40000 ALTER TABLE `version_db_playerbots` ENABLE KEYS */;
/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */;
/*!40014 SET FOREIGN_KEY_CHECKS=IFNULL(@OLD_FOREIGN_KEY_CHECKS, 1) */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40111 SET SQL_NOTES=IFNULL(@OLD_SQL_NOTES, 1) */;

View File

@ -0,0 +1,5 @@
GRANT ALL PRIVILEGES ON * . * TO 'acore'@'localhost' WITH GRANT OPTION;
CREATE DATABASE `acore_playerbots` DEFAULT CHARACTER SET UTF8MB4 COLLATE utf8mb4_general_ci;
GRANT ALL PRIVILEGES ON `acore_playerbots` . * TO 'acore'@'localhost' WITH GRANT OPTION;

View File

@ -0,0 +1,9 @@
REVOKE ALL PRIVILEGES ON * . * FROM 'acore'@'localhost';
REVOKE ALL PRIVILEGES ON `acore_playerbots` . * FROM 'acore'@'localhost';
REVOKE GRANT OPTION ON `acore_playerbots` . * FROM 'acore'@'localhost';
DROP USER 'acore'@'localhost';
DROP DATABASE IF EXISTS `acore_playerbots`;

View File

@ -0,0 +1,5 @@
REVOKE ALL PRIVILEGES, GRANT OPTION FROM 'acore'@'localhost';
DROP USER 'acore'@'localhost';
DROP DATABASE IF EXISTS `acore_playerbots`;

View File

@ -0,0 +1,10 @@
This folder should contains only re-applicable sql
e.g:
- CREATE IF NOT EXISTS
- REPLACE INTO
- DELETE + INSERT
- UPDATES with fixed values
etc.

View File

@ -0,0 +1,2 @@
Please read [this](http://www.azerothcore.org/wiki/Dealing-with-SQL-files) before adding new SQL-update files.

View File

@ -1,3 +0,0 @@
-- Put only sql data in this file (insert, update, replace into, delete etc...).
-- If you don't use this database, then delete this file.
-- If no data, just delete this file.

View File

@ -1,3 +0,0 @@
-- Put only sql data in this file (insert, update, replace into, delete etc...).
-- If you don't use this database, then delete this file.
-- If no data, just delete this file.

View File

@ -1,2 +0,0 @@
-- Put only sql structure in this file (create table if exists, delete table, alter table etc...).
-- If you don't use this database, then delete this file.

View File

@ -0,0 +1,14 @@
DROP TABLE IF EXISTS `charsections_dbc`;
CREATE TABLE `charsections_dbc` (
`Id` INT NOT NULL DEFAULT '0',
`Race` INT NOT NULL DEFAULT '0',
`Gender` INT NOT NULL DEFAULT '0',
`GenType` INT NOT NULL DEFAULT '0',
`TexturePath1` VARCHAR(100) DEFAULT NULL,
`TexturePath2` VARCHAR(100) DEFAULT NULL,
`TexturePath3` VARCHAR(100) DEFAULT NULL,
`Flags` INT NOT NULL DEFAULT '0',
`Type` INT NOT NULL DEFAULT '0',
`Color` INT NOT NULL DEFAULT '0',
PRIMARY KEY (`ID`) USING BTREE
) ENGINE=MYISAM DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC;

View File

@ -0,0 +1,9 @@
DROP TABLE IF EXISTS `emotetextsound_dbc`;
CREATE TABLE `emotetextsound_dbc` (
`Id` INT NOT NULL DEFAULT '0',
`EmotesTextId` INT NOT NULL DEFAULT '0',
`RaceId` INT NOT NULL DEFAULT '0',
`SexId` INT NOT NULL DEFAULT '0',
`SoundId` INT NOT NULL DEFAULT '0',
PRIMARY KEY (`Id`) USING BTREE
) ENGINE=MYISAM DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC;

View File

@ -0,0 +1,782 @@
DROP TABLE IF EXISTS `playerbots_rpg_races`;
CREATE TABLE `playerbots_rpg_races`
(
`id` int(11) NOT NULL AUTO_INCREMENT,
`entry` int(11),
`race` int(11),
`minl` int(11),
`maxl` int(11),
PRIMARY KEY (`id`),
KEY `entry` (`entry`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
DELETE FROM `playerbots_rpg_races`;
-- say
INSERT INTO `playerbots_rpg_races` VALUES
--
-- DRAENEI
--
-- Draenei Azumeryst Isle
(NULL, 16553, 11, 1, 10),
-- Draenei Bloodmyst Isle
(NULL, 17553, 11, 10, 20),
--
-- HUMANS
--
-- Innkeeper Farley, Goldshire
(NULL, 295, 1, 1, 10),
-- Innkeeper Heather, Westfall
(NULL, 8931, 1, 10, 20),
--
-- DWARVES & GNOMES
--
-- Innkeeper Belm, Kharanos
(NULL, 1247, 3, 1, 10),
(NULL, 1247, 7, 1, 10),
-- Innkeeper Hearthstove, Loch Modan
(NULL, 6734, 3, 10, 20),
(NULL, 6734, 7, 10, 20),
--
-- NIGHT ELVES
--
-- Innkeeper Keldamyr, Dolanaar
(NULL, 6736, 4, 1, 10),
-- Innkeeper Shaussiy, Auberdine
(NULL, 6737, 4, 10, 20),
--
-- ALLIANCE CITIES
--
-- Innkeeper Saelienne, Darnassus
(NULL, 6735, 4, 10, 80), -- elves
--
-- Innkeeper Firebrew, Ironforge
(NULL, 5111, 3, 10, 80), -- dwarves
(NULL, 5111, 7, 10, 80), -- gnomes
(NULL, 5111, 4, 10, 80), -- elves
(NULL, 5111, 1, 10, 80), -- human
(NULL, 5111, 11, 20, 80), -- draenei
--
-- Innkeeper Allison, Stormwind
(NULL, 6740, 1, 10, 80), -- human
(NULL, 6740, 3, 10, 80), -- dwarves
(NULL, 6740, 4, 10, 80), -- elves
(NULL, 6740, 7, 10, 80), -- gnomes
(NULL, 6740, 11, 20, 80), -- draenei
--
-- Caregiver Breel Exodar
(NULL, 16739, 11, 10, 80), -- draenei
(NULL, 16739, 1, 60, 80), -- human
(NULL, 16739, 3, 60, 80), -- dwarves
(NULL, 16739, 4, 60, 80), -- elves
(NULL, 16739, 7, 60, 80), -- gnomes
--
-- ALLIANCE CONTESTED LOCATIONS
--
-- Innkeeper Kimlya, Astranaar
--
(NULL, 6738, 4, 15, 30), -- elves
(NULL, 6738, 11, 20, 30), -- draenei
--
-- Innkeeper Faralia, Stonetalon Peak
--
(NULL, 16458, 4, 15, 27), -- elves
--
-- Innkeeper Lyshaerya, Desolase
--
(NULL, 11103, 4, 30, 40), -- elves
--
-- Innkeeper Shyria, Feathermoon, Feralas
(NULL, 7736, 4, 40, 50), -- elves
--
-- Falfindel Waywarder, Feralas elf camp
(NULL, 4048, 4, 40, 50), -- elves
--
-- Innkeeper Helbrek, Wetlands
--
(NULL, 1464, 3, 20, 30), -- dwarves
(NULL, 1464, 7, 20, 30), -- gnomes
--
-- Innkeeper Trelayne, Duskwood
--
(NULL, 6790, 1, 18, 30), -- human
(NULL, 6790, 3, 18, 30), -- dwarves
(NULL, 6790, 7, 18, 30), -- gnomes
(NULL, 6790, 11, 20, 30), -- draenei
--
-- Innkeeper Brianna, Redridge Mountains
--
(NULL, 6727, 1, 15, 25), -- human
--
-- Innkeeper Anderson, Southshore, Hillsbrad
(NULL, 2352, 1, 20, 30), -- human
(NULL, 2352, 3, 20, 30), -- dwarves
(NULL, 2352, 7, 20, 30), -- gnomes
(NULL, 2352, 11, 20, 30), -- draenei
--
-- Captain Nials, Refuge Pointe, Arathi
(NULL, 2700, 1, 30, 40), -- human
(NULL, 2700, 3, 30, 40), -- dwarves
(NULL, 2700, 7, 30, 40), -- gnomes
(NULL, 2700, 4, 30, 40), -- elves
(NULL, 2700, 11, 30, 40), -- draenei
--
-- Lt. Doren, Stranglethorn Vale
(NULL, 469, 1, 30, 45), -- human
(NULL, 469, 3, 30, 45), -- dwarves
(NULL, 469, 4, 30, 45), -- elves
(NULL, 469, 7, 30, 45), -- gnomes
(NULL, 469, 11, 30, 45), -- draenei
--
-- Innkeeper Janene, Theramore
(NULL, 6272, 1, 35, 45), -- human
(NULL, 6272, 3, 35, 45), -- dwarves
(NULL, 6272, 7, 35, 45), -- gnomes
(NULL, 6272, 11, 35, 45), -- draenei
--
-- Innkeeper Prospector Ryedol, Badlands Q-giver
(NULL, 2910, 3, 35, 45), -- dwarves
(NULL, 2910, 7, 35, 45), -- gnomes
--
-- Innkeeper Thulfram, Hinterlands, Dwarven Outpost
(NULL, 7744, 3, 40, 50), -- dwarves
(NULL, 7744, 1, 40, 50), -- human
(NULL, 7744, 7, 40, 50), -- gnomes
--
-- Loh'atu, Azshara alliance camp Q-giver 11548
(NULL, 11548, 4, 45, 55), -- elves
(NULL, 11548, 1, 45, 55), -- human
(NULL, 11548, 11, 45, 55), -- draenei
--
-- Thadius Grimshade, Nethergarde Keep, Blasted Lands
(NULL, 8022, 1, 45, 55), -- human
(NULL, 8022, 3, 45, 55), -- dwarves
(NULL, 8022, 4, 45, 55), -- elves
(NULL, 8022, 7, 45, 55), -- gnomes
(NULL, 8022, 11, 45, 55), -- draenei
--
-- Gothine the Hooded, Felwood Alliance camp
(NULL, 9465, 4, 48, 55), -- elves
(NULL, 9465, 1, 48, 55), -- human
(NULL, 9465, 3, 48, 55), -- dwarves
(NULL, 9465, 7, 48, 55), -- gnomes
(NULL, 9465, 11, 48, 55), -- draenei
--
-- Muigin, Alliance Q-giver, Un'Goro
(NULL, 9119, 1, 48, 55), -- human
(NULL, 9119, 3, 48, 55), -- dwarves
(NULL, 9119, 4, 48, 55), -- elves
(NULL, 9119, 7, 48, 55), -- gnomes
(NULL, 9119, 11, 48, 55), -- draenei
--
-- Alchemist Arbington, West Plaguelands, Human
(NULL, 11056, 1, 51, 58), -- human
(NULL, 11056, 3, 51, 58), -- dwarves
(NULL, 11056, 4, 51, 58), -- elves
(NULL, 11056, 7, 51, 58), -- gnomes
(NULL, 11056, 11, 51, 58), -- draenei
--
-- Borgus Stourarm, Alliance Taxi, Burning Steppes
(NULL, 2299, 1, 50, 60), -- human
(NULL, 2299, 3, 50, 60), -- dwarves
(NULL, 2299, 4, 50, 60), -- elves
(NULL, 2299, 7, 50, 60), -- gnomes
(NULL, 2299, 11, 50, 60), -- draenei
--
-- Marshal Bluewall, Alliance camp, Silithus
(NULL, 17080, 1, 55, 60), -- human
(NULL, 17080, 3, 55, 60), -- dwarves
(NULL, 17080, 4, 55, 60), -- elves
(NULL, 17080, 7, 55, 60), -- gnomes
(NULL, 17080, 11, 55, 60), -- draenei
--
-- OUTLAND
--
-- Commander Duron, Dark Portal
(NULL, 19229, 1, 58, 59), -- human
(NULL, 19229, 3, 58, 59), -- dwarves
(NULL, 19229, 4, 58, 59), -- elves
(NULL, 19229, 7, 58, 59), -- gnomes
(NULL, 19229, 11, 58, 59), -- draenei
--
-- Sid Limbardi, Honor Hold, Hellfire
(NULL, 16826, 1, 58, 63), -- human
(NULL, 16826, 3, 58, 63), -- dwarves
(NULL, 16826, 4, 58, 63), -- elves
(NULL, 16826, 7, 58, 63), -- gnomes
(NULL, 16826, 11, 58, 63), -- draenei
--
-- Caregiver Ophera Windfury, Draenei, Hellfire
(NULL, 18906, 1, 60, 63), -- human
(NULL, 18906, 3, 60, 63), -- dwarves
(NULL, 18906, 4, 60, 63), -- elves
(NULL, 18906, 7, 60, 63), -- gnomes
(NULL, 18906, 11, 60, 63), -- draenei
--
-- Caregiver Abidaar, Telredor, Zangarmarsh
(NULL, 18251, 1, 60, 63), -- human
(NULL, 18251, 3, 60, 63), -- dwarves
(NULL, 18251, 4, 60, 63), -- elves
(NULL, 18251, 7, 60, 63), -- gnomes
(NULL, 18251, 11, 60, 63), -- draenei
--
-- Caregiver Kerp, Orebor, Zangarmarsh
(NULL, 18908, 1, 61, 64), -- human
(NULL, 18908, 3, 61, 64), -- dwarves
(NULL, 18908, 4, 61, 64), -- elves
(NULL, 18908, 7, 61, 64), -- gnomes
(NULL, 18908, 11, 61, 64), -- draenei
--
-- Innkeeper Biribi, Terrokar
(NULL, 19296, 1, 62, 65), -- human
(NULL, 19296, 3, 62, 65), -- dwarves
(NULL, 19296, 4, 62, 65), -- elves
(NULL, 19296, 7, 62, 65), -- gnomes
(NULL, 19296, 11, 62, 65), -- draenei
--
-- Caregiver Isel, Telaar, Nagrand
(NULL, 18914, 1, 64, 67), -- human
(NULL, 18914, 3, 64, 67), -- dwarves
(NULL, 18914, 4, 64, 67), -- elves
(NULL, 18914, 7, 64, 67), -- gnomes
(NULL, 18914, 11, 64, 67), -- draenei
--
-- Innkeeper Shaunessy, Sylvanaar, Blade's Edge
(NULL, 19495, 1, 65, 68), -- human
(NULL, 19495, 3, 65, 68), -- dwarves
(NULL, 19495, 4, 65, 68), -- elves
(NULL, 19495, 7, 65, 68), -- gnomes
(NULL, 19495, 11, 65, 68), -- draenei
--
-- Innkeeper Fizir Doc Clocktock, Blade's Edge
(NULL, 21110, 1, 65, 68), -- human
(NULL, 21110, 3, 65, 68), -- dwarves
(NULL, 21110, 4, 65, 68), -- elves
(NULL, 21110, 7, 65, 68), -- gnomes
(NULL, 21110, 11, 65, 68), -- draenei
--
-- Innkeeper Dreg Cloudsweeper, Shadowmoon
(NULL, 19352, 1, 67, 70), -- human
(NULL, 19352, 3, 67, 70), -- dwarves
(NULL, 19352, 4, 67, 70), -- elves
(NULL, 19352, 7, 67, 70), -- gnomes
(NULL, 19352, 11, 67, 70), -- draenei
--
-- NORTHREND
--
-- Isirami Fairwind, Dalaran
(NULL, 32413, 1, 72, 80), -- human
(NULL, 32413, 3, 72, 80), -- dwarves
(NULL, 32413, 4, 72, 80), -- elves
(NULL, 32413, 7, 72, 80), -- gnomes
(NULL, 32413, 11, 72, 80), -- draenei
--
-- James Deacon, Valiance Keep, Borean Tundra
(NULL, 25245, 1, 68, 72), -- human
(NULL, 25245, 3, 68, 72), -- dwarves
(NULL, 25245, 4, 68, 72), -- elves
(NULL, 25245, 7, 68, 72), -- gnomes
(NULL, 25245, 11, 68, 72), -- draenei
--
-- "Charlie" Northtop, Fizzcrank Airstrip, Borean Tundra
(NULL, 26596, 1, 69, 72), -- human
(NULL, 26596, 3, 69, 72), -- dwarves
(NULL, 26596, 4, 69, 72), -- elves
(NULL, 26596, 7, 69, 72), -- gnomes
(NULL, 26596, 11, 69, 72), -- draenei
--
-- Innkeeper Hazel Lagras, Valgarde, Howling Fjord
(NULL, 23731, 1, 68, 72), -- human
(NULL, 23731, 3, 68, 72), -- dwarves
(NULL, 23731, 4, 68, 72), -- elves
(NULL, 23731, 7, 68, 72), -- gnomes
(NULL, 23731, 11, 68, 72), -- draenei
--
-- Innkeeper Celeste Goodhutch, Westguard Keep, Howling Fjord
(NULL, 23937, 1, 69, 72), -- human
(NULL, 23937, 3, 69, 72), -- dwarves
(NULL, 23937, 4, 69, 72), -- elves
(NULL, 23937, 7, 69, 72), -- gnomes
(NULL, 23937, 11, 69, 72), -- draenei
--
-- Christina Daniels, Fort Wildervar, Howling Fjord
(NULL, 24057, 1, 70, 72), -- human
(NULL, 24057, 3, 70, 72), -- dwarves
(NULL, 24057, 4, 70, 72), -- elves
(NULL, 24057, 7, 70, 72), -- gnomes
(NULL, 24057, 11, 70, 72), -- draenei
--
-- Jennifer Bell, Amberpine Lodge, Grizzly Hills
(NULL, 27066, 1, 70, 74), -- human
(NULL, 27066, 3, 70, 74), -- dwarves
(NULL, 27066, 4, 70, 74), -- elves
(NULL, 27066, 7, 70, 74), -- gnomes
(NULL, 27066, 11, 70, 74), -- draenei
--
-- Quartermaster McCarty, Westfall Brigade Encampment, Grizzly Hills
(NULL, 26375, 1, 70, 74), -- human
(NULL, 26375, 3, 70, 74), -- dwarves
(NULL, 26375, 4, 70, 74), -- elves
(NULL, 26375, 7, 70, 74), -- gnomes
(NULL, 26375, 11, 70, 74), -- draenei
--
-- Illusia Lune, Wintergarde Keep, Dragonblight
(NULL, 27042, 1, 71, 75), -- human
(NULL, 27042, 3, 71, 75), -- dwarves
(NULL, 27042, 4, 71, 75), -- elves
(NULL, 27042, 7, 71, 75), -- gnomes
(NULL, 27042, 11, 71, 75), -- draenei
--
-- Naohain, Stars' Rest, Dragonblight
(NULL, 27052, 1, 71, 75), -- human
(NULL, 27052, 3, 71, 75), -- dwarves
(NULL, 27052, 4, 71, 75), -- elves
(NULL, 27052, 7, 71, 75), -- gnomes
(NULL, 27052, 11, 71, 75), -- draenei
--
-- Gunda Boldhammer, Frosthold, Storm Peaks
(NULL, 29926, 1, 77, 80), -- human
(NULL, 29926, 3, 77, 80), -- dwarves
(NULL, 29926, 4, 77, 80), -- elves
(NULL, 29926, 7, 77, 80), -- gnomes
(NULL, 29926, 11, 77, 80), -- draenei
--
-- Caris Sunlance, Argent Tournament, Icecrown
(NULL, 33970, 1, 80, 80), -- human
(NULL, 33970, 3, 80, 80), -- dwarves
(NULL, 33970, 4, 80, 80), -- elves
(NULL, 33970, 7, 80, 80), -- gnomes
(NULL, 33970, 11, 80, 80), -- draenei
--
-- ALLIANCE MOUNT VENDORS
--
-- Milli Featherwhistle, Gnome Mechanostrider merchant, Dun Morogh
-- (NULL, 7955, 3),
-- (NULL, 7955, 7),
--
-- Lelanai, Night Elf Night Saber vendor, Darnassus
-- (NULL, 4730, 4),
--
-- Katie Hunter, Human Horse vendor, Elwynn Forest
-- (NULL, 384, 1),
--
-- HORDE
--
-- ORCS & TROLLS
--
-- Innkeeper Grosk, Durotar
(NULL, 6928, 2, 1, 10),
(NULL, 6928, 8, 1, 10),
--
-- TAUREN
--
-- Innkeeper Pala, Mulgore
(NULL, 6746, 6, 1, 10),
--
-- UNDEAD
--
-- Innkeeper Renee, Brill, Tirisfal Glades
(NULL, 5688, 5, 1, 10),
-- Innkeeper Bates, The Sepulcher, Silverpine Forest
(NULL, 6739, 5, 10, 20),
--
-- BLOOD ELVES
--
-- Blood Elves Eversong Woods
(NULL, 15397, 10, 1, 10),
-- Blood Elves Ghostlands
(NULL, 16542, 10, 10, 20),
--
-- HORDE CITIES
--
-- Innkeeper Gryshka, Orgrimmar
(NULL, 6929, 2, 10, 80), -- orcs
(NULL, 6929, 8, 10, 80), -- trolls
(NULL, 6929, 6, 10, 80), -- tauren
(NULL, 6929, 5, 20, 80), -- undead
(NULL, 6929, 10, 20, 80), -- blood elves
--
-- Innkeeper Pala, Thunder Bluff, Mulgore
(NULL, 6746, 6, 10, 80), -- tauren
--
-- Innkeeper Norman, Undercity
(NULL, 6741, 5, 10, 80), -- undead
(NULL, 6741, 10, 20, 80), -- blood elves
--
-- Innkeeper Velandra Silvermoon
(NULL, 16618, 10, 10, 80), -- blood elves
-- Innkeeper Jovia Silvermoon
(NULL, 17630, 2, 60, 80), -- orcs
(NULL, 17630, 5, 60, 80), -- undead
(NULL, 17630, 6, 60, 80), -- tauren
(NULL, 17630, 8, 60, 80), -- trolls
-- Innkeeper Delaniel Silvermoon Entrance
(NULL, 15433, 10, 5, 7), -- blood elves
--
-- HORDE CONTESTED LOCATIONS
--
-- Innkeeper Boorand Plainswind, Crossroads, Barrens
(NULL, 3934, 2, 10, 25), -- orcs
(NULL, 3934, 6, 10, 25), -- tauren
(NULL, 3934, 8, 10, 25), -- trolls
(NULL, 3934, 10, 20, 25), -- blood elves
-- (NULL, 3934, 5, 15, 25), -- undead
--
-- Innkeeper Byula, Camp Taurajo, Barrens
(NULL, 7714, 2, 10, 25), -- orcs
(NULL, 7714, 6, 10, 25), -- tauren
(NULL, 7714, 8, 10, 25), -- trolls
--
-- Innkeeper Jayka, Stonetalon, Red Rock Retreat
(NULL, 7731, 2, 15, 27), -- orcs
(NULL, 7731, 6, 15, 27), -- tauren
(NULL, 7731, 8, 15, 27), -- trolls
(NULL, 7731, 10, 20, 27), -- blood elves
--
-- Innkeeper Abeqwa, Thousand Needles
(NULL, 11116, 2, 25, 35), -- orcs
(NULL, 11116, 6, 25, 35), -- tauren
(NULL, 11116, 8, 25, 35), -- trolls
(NULL, 11116, 10, 25, 35), -- blood elves
--
-- Innkeeper Shay, Tarren Mill, Hillsbrad
(NULL, 2388, 5, 20, 30), -- undead
(NULL, 2388, 10, 20, 30), -- blood elves
--
-- Innkeeper Greul, Feralas, Horde
(NULL, 7737, 6, 40, 50), -- tauren
--
-- Innkeeper Kaylisk, Splitertree, Ashenvale
(NULL, 12196, 2, 18, 30), -- orcs
(NULL, 12196, 8, 18, 30), -- trolls
(NULL, 12196, 10, 20, 30), -- blood elves
--
-- Marukai, Zoram'gar, Ashenvale
(NULL, 12719, 2, 18, 30), -- orcs
(NULL, 12719, 8, 18, 30), -- trolls
--
-- Innkeeper Sikewa, Desolace
(NULL, 11106, 2, 30, 40), -- orcs
(NULL, 11106, 6, 30, 40), -- tauren
(NULL, 11106, 8, 30, 40), -- trolls
--
-- Innkeeper Adegwa, Arathi, Hammerfall
(NULL, 9501, 2, 30, 40), -- orcs
(NULL, 9501, 5, 30, 40), -- undead
(NULL, 9501, 6, 30, 40), -- tauren
(NULL, 9501, 8, 30, 40), -- trolls
(NULL, 9501, 10, 30, 40), -- blood elves
--
-- Innkeeper Lard, Revantusk Village , Hinterlands
(NULL, 14731, 2, 40, 50), -- orcs
(NULL, 14731, 5, 40, 50), -- undead
(NULL, 14731, 6, 40, 50), -- tauren
(NULL, 14731, 8, 40, 50), -- trolls
(NULL, 14731, 10, 40, 50), -- blood elves
--
-- Innkeeper Shul'kar, Kargath Outpost, Badlands
(NULL, 9356, 2, 35, 45), -- orcs
(NULL, 9356, 5, 35, 45), -- undead
(NULL, 9356, 6, 35, 45), -- tauren
(NULL, 9356, 8, 35, 45), -- trolls
(NULL, 9356, 10, 35, 45), -- blood elves
--
-- Innkeeper Karakul, Swamp of Sorrows
(NULL, 6930, 2, 35, 45), -- orcs
(NULL, 6930, 5, 35, 45), -- undead
(NULL, 6930, 6, 35, 45), -- tauren
(NULL, 6930, 8, 35, 45), -- trolls
(NULL, 6930, 10, 35, 45), -- blood elves
--
-- Innkeeper Thulbek, Grom Gol, Stranglethorn Vale
(NULL, 5814, 2, 30, 45), -- orcs
(NULL, 5814, 5, 30, 45), -- undead
(NULL, 5814, 6, 30, 45), -- tauren
(NULL, 5814, 8, 30, 45), -- trolls
(NULL, 5814, 10, 30, 45), -- blood elves
--
-- Overlord Mok'Morokk, Dustwallow Marsh
(NULL, 4500, 2, 35, 45), -- orcs
(NULL, 4500, 6, 35, 45), -- tauren
(NULL, 4500, 8, 35, 45), -- trolls
--
-- Jediga, Azshara horde camp
(NULL, 8587, 2, 45, 55), -- orcs
(NULL, 8587, 8, 45, 55), -- trolls
(NULL, 8587, 6, 45, 55), -- tauren
(NULL, 8587, 10, 45, 55), -- blood elves
--
-- Winna Hazzard, Felwood horde camp
(NULL, 9996, 2, 48, 55), -- orcs
(NULL, 9996, 6, 48, 55), -- tauren
(NULL, 9996, 8, 48, 55), -- trolls
(NULL, 9996, 5, 48, 55), -- undead
(NULL, 9996, 10, 48, 55), -- blood elves
--
-- Larion, Horde Q-giver, Un'Goro
(NULL, 9118, 2, 48, 55), -- orcs
(NULL, 9118, 6, 48, 55), -- tauren
(NULL, 9118, 8, 48, 55), -- trolls
(NULL, 9118, 5, 48, 55), -- undead
(NULL, 9118, 10, 48, 55), -- blood elves
--
-- Vahgruk, Horde Taxi, Burning Steppes
(NULL, 13177, 2, 50, 60), -- orcs
(NULL, 13177, 5, 50, 60), -- undead
(NULL, 13177, 6, 50, 60), -- tauren
(NULL, 13177, 8, 50, 60), -- trolls
(NULL, 13177, 10, 50, 60), -- blood elves
--
-- General Kirika, Horde camp, Silithus
(NULL, 17079, 2, 55, 60), -- orcs
(NULL, 17079, 5, 55, 60), -- undead
(NULL, 17079, 6, 55, 60), -- tauren
(NULL, 17079, 8, 55, 60), -- trolls
(NULL, 17079, 10, 55, 60), -- blood elves
--
-- OUTLAND
--
-- Lieutenant General Orion, Dark Portal
(NULL, 19253, 2, 58, 59), -- orcs
(NULL, 19253, 5, 58, 59), -- undead
(NULL, 19253, 6, 58, 59), -- tauren
(NULL, 19253, 8, 58, 59), -- trolls
(NULL, 19253, 10, 58, 59), -- blood elves
--
-- Floyd Pinkus, Thrallmar, Hellfire
(NULL, 16602, 2, 58, 63), -- orcs
(NULL, 16602, 5, 58, 63), -- undead
(NULL, 16602, 6, 58, 63), -- tauren
(NULL, 16602, 8, 58, 63), -- trolls
(NULL, 16602, 10, 58, 63), -- blood elves
--
-- Innkeeper Bazil, Falcon Watch, Hellfire
(NULL, 18905, 2, 60, 63), -- orcs
(NULL, 18905, 5, 60, 63), -- undead
(NULL, 18905, 6, 60, 63), -- tauren
(NULL, 18905, 8, 60, 63), -- trolls
(NULL, 18905, 10, 60, 63), -- blood elves
--
-- Innkeeper Merajit, Zabra'jin, Zangarmarsh
(NULL, 18245, 2, 60, 64), -- orcs
(NULL, 18245, 5, 60, 64), -- undead
(NULL, 18245, 6, 60, 64), -- tauren
(NULL, 18245, 8, 60, 64), -- trolls
(NULL, 18245, 10, 60, 64), -- blood elves
--
-- Innkeeper Grilka, Terrokar
(NULL, 18957, 2, 62, 65), -- orcs
(NULL, 18957, 5, 62, 65), -- undead
(NULL, 18957, 6, 62, 65), -- tauren
(NULL, 18957, 8, 62, 65), -- trolls
(NULL, 18957, 10, 62, 65), -- blood elves
--
-- Matron Tikkit, Garadar, Nagrand
(NULL, 18913, 2, 62, 65), -- orcs
(NULL, 18913, 5, 62, 65), -- undead
(NULL, 18913, 6, 62, 65), -- tauren
(NULL, 18913, 8, 62, 65), -- trolls
(NULL, 18913, 10, 62, 65), -- blood elves
--
-- Innkeeper Matron Varah, Mok'Nathal, Blade's Edge
(NULL, 21088, 2, 65, 68), -- orcs
(NULL, 21088, 5, 65, 68), -- undead
(NULL, 21088, 6, 65, 68), -- tauren
(NULL, 21088, 8, 65, 68), -- trolls
(NULL, 21088, 10, 65, 68), -- blood elves
--
-- Innkeeper Gholah, Thunderlord, Blade's Edge
(NULL, 19470, 2, 65, 68), -- orcs
(NULL, 19470, 5, 65, 68), -- undead
(NULL, 19470, 6, 65, 68), -- tauren
(NULL, 19470, 8, 65, 68), -- trolls
(NULL, 19470, 10, 65, 68), -- blood elves
--
-- Innkeeper Darg Bloodclaw, Shadowmoon Village
(NULL, 19319, 2, 67, 70), -- orcs
(NULL, 19319, 5, 67, 70), -- undead
(NULL, 19319, 6, 67, 70), -- tauren
(NULL, 19319, 8, 67, 70), -- trolls
(NULL, 19319, 10, 67, 70), -- blood elves
--
-- NORTHREND
--
-- Uda the Beast, Dalaran
(NULL, 31557, 2, 72, 80), -- orcs
(NULL, 31557, 5, 72, 80), -- undead
(NULL, 31557, 6, 72, 80), -- tauren
(NULL, 31557, 8, 72, 80), -- trolls
(NULL, 31557, 10, 72, 80), -- blood elves
--
-- Williamson, Warsong Hold, Borean Tundra
(NULL, 25278, 2, 68, 72), -- orcs
(NULL, 25278, 5, 68, 72), -- undead
(NULL, 25278, 6, 68, 72), -- tauren
(NULL, 25278, 8, 68, 72), -- trolls
(NULL, 25278, 10, 68, 72), -- blood elves
--
-- Pahu Frosthoof, Taunka'le Village, Borean Tundra
(NULL, 26709, 2, 69, 72), -- orcs
(NULL, 26709, 5, 69, 72), -- undead
(NULL, 26709, 6, 69, 72), -- tauren
(NULL, 26709, 8, 69, 72), -- trolls
(NULL, 26709, 10, 69, 72), -- blood elves
--
-- Matron Magah, Bor'Gorok Outpost, Borean Tundra
(NULL, 26709, 2, 70, 72), -- orcs
(NULL, 26709, 5, 70, 72), -- undead
(NULL, 26709, 6, 70, 72), -- tauren
(NULL, 26709, 8, 70, 72), -- trolls
(NULL, 26709, 10, 70, 72), -- blood elves
--
-- Basil Osgood, New Agamand, Howling Fjord
(NULL, 24149, 2, 68, 72), -- orcs
(NULL, 24149, 5, 68, 72), -- undead
(NULL, 24149, 6, 68, 72), -- tauren
(NULL, 24149, 8, 68, 72), -- trolls
(NULL, 24149, 10, 68, 72), -- blood elves
--
-- Timothy Holland, Vengeance Landing, Howling Fjord
(NULL, 24342, 2, 69, 72), -- orcs
(NULL, 24342, 5, 69, 72), -- undead
(NULL, 24342, 6, 69, 72), -- tauren
(NULL, 24342, 8, 69, 72), -- trolls
(NULL, 24342, 10, 69, 72), -- blood elves
--
-- Bori Wintertotem, Camp Winterhoof, Howling Fjord
(NULL, 24033, 2, 70, 72), -- orcs
(NULL, 24033, 5, 70, 72), -- undead
(NULL, 24033, 6, 70, 72), -- tauren
(NULL, 24033, 8, 70, 72), -- trolls
(NULL, 24033, 10, 70, 72), -- blood elves
--
-- Barracks Master Rhekku, Conquest Hold, Grizzly Hills
(NULL, 27125, 2, 70, 74), -- orcs
(NULL, 27125, 5, 70, 74), -- undead
(NULL, 27125, 6, 70, 74), -- tauren
(NULL, 27125, 8, 70, 74), -- trolls
(NULL, 27125, 10, 70, 74), -- blood elves
--
-- Aiyan Coldwind, Capm Onequah, Grizzly Hills
(NULL, 26680, 2, 70, 74), -- orcs
(NULL, 26680, 5, 70, 74), -- undead
(NULL, 26680, 6, 70, 74), -- tauren
(NULL, 26680, 8, 70, 74), -- trolls
(NULL, 26680, 10, 70, 74), -- blood elves
--
-- Mrs. Winterby, Venomspite, Dragonblight
(NULL, 27027, 2, 71, 75), -- orcs
(NULL, 27027, 5, 71, 75), -- undead
(NULL, 27027, 6, 71, 75), -- tauren
(NULL, 27027, 8, 71, 75), -- trolls
(NULL, 27027, 10, 71, 75), -- blood elves
--
-- Barracks Master Harga, Agmar's Hammer, Dragonblight
(NULL, 26985, 2, 71, 75), -- orcs
(NULL, 26985, 5, 71, 75), -- undead
(NULL, 26985, 6, 71, 75), -- tauren
(NULL, 26985, 8, 71, 75), -- trolls
(NULL, 26985, 10, 71, 75), -- blood elves
--
-- Wabada Whiteflower, Camp Tunka'lo, Storm Peaks
(NULL, 29971, 2, 77, 80), -- orcs
(NULL, 29971, 5, 77, 80), -- undead
(NULL, 29971, 6, 77, 80), -- tauren
(NULL, 29971, 8, 77, 80), -- trolls
(NULL, 29971, 10, 77, 80), -- blood elves
--
-- Jarin Dawnglow, Argent Tournament, Icecrown
(NULL, 33971, 2, 80, 80), -- orcs
(NULL, 33971, 5, 80, 80), -- undead
(NULL, 33971, 6, 80, 80), -- tauren
(NULL, 33971, 8, 80, 80), -- trolls
(NULL, 33971, 10, 80, 80), -- blood elves
--
-- NEUTRAL AREAS
--
-- Innkeeper Skindle, Booty Bay 6807 (Neutral)
(NULL, 6807, 0, 30, 45),
-- Innkeeper Wiley, Ratchet 6791 (Neutral)
(NULL, 6791, 2, 10, 25),
(NULL, 6791, 8, 10, 25),
-- Innkeeper Fizzgrimble, Tanaris 7733 (Neutral)
(NULL, 7733, 0, 40, 50),
-- Master Smith Burninate, Searing Gorge
(NULL, 14624, 0, 45, 50),
-- Marin Noggenfogger 7564 (Neutral)
-- Innkeeper Vizzie, Everlook 11118 (Neutral)
(NULL, 11118, 0, 53, 60),
-- Calandrath, Silithus 15174 (Neutral)
(NULL, 15174, 0, 55, 60),
-- Jessica Chambers, East Plaguelands 16256 (Neutral)
(NULL, 16256, 0, 53, 60),
--
-- OUTLAND
--
-- Innkeeper Coryth Stoktron, Cenarion Refuge (Neutral)
(NULL, 18907, 0, 60, 64),
-- Minalei, Aldors, Shattrath
(NULL, 19046, 0, 65, 70),
-- Innkeeper Haelthol, Scryers, Shattrath
(NULL, 19232, 0, 65, 70),
-- Shaarubo, World End Tavern
(NULL, 19182, 0, 65, 70),
-- Innkeeper Aelerya, Blade's Edge (Neutral)
(NULL, 22922, 0, 65, 68),
-- Innkeeper Eyonix, Stormspire, Netherstorm
(NULL, 19531, 0, 67, 70),
-- Innkeeper Remi Dodoso, Area 52, Netherstorm
(NULL, 19571, 0, 67, 70),
-- Caregiver Inaara, Isle if Quel'Danas
(NULL, 25036, 0, 69, 70),
--
-- NORTHREND
--
-- Amisi Azuregaze, Dalaran Inn
(NULL, 28687, 0, 72, 80),
-- Afsaneh Asrar, Dalaran Underbelly
(NULL, 32411, 0, 77, 80),
-- Caregiver Poallu, Kaluak Camp, Borean Tundra
(NULL, 27187, 0, 68, 72),
-- Caregiver Iqniq, Kamagua, Howling Fjord
(NULL, 27187, 0, 68, 72),
-- Caregiver Mumik, Mo'Aki Harbor, Dragonblight
(NULL, 27174, 0, 71, 73),
-- Marissa Everwatch, The Argent Stand, Zul'Drak
(NULL, 28791, 0, 73, 75),
-- Pan'ya, Zim'Torga, Zul'Drak
(NULL, 29583, 0, 75, 77),
-- Purser Boulian, Nesingwary Base Camp, Sholazar Basin
(NULL, 29583, 0, 75, 79),
-- Smilin' Slirk Brassknob, K3, The Storm Peaks
(NULL, 29904, 0, 77, 80),
-- Magorn, Snow Drift Plains, The Storm Peaks
(NULL, 29963, 0, 77, 80),
-- Initiate Brenners, The Argent Stand, Zul'Drak
-- (NULL, 30308, 0, 77, 80),
--
--
-- UNUSED
--
--
-- Bashana Runetotem, Thunder Bluff (Tauren npc in TB)
-- (NULL, 9087, 6),
--
-- Alchemist Arbington, West Plaguelands, Human
-- (NULL, 11056, 1),
-- (NULL, 11056, 3),
-- (NULL, 11056, 4),
-- (NULL, 11056, 7),
--
-- Lokhtos Darkbargainer, Blackrock Depths, 12944
--
-- Gregan Brewspewer, Feralas, Dwarf (Some swarf Q-giver in Feralas)
-- (NULL, 7775, 3),
--
-- Augustus the Touched, East Plaguelands, Undead (Some undead vendor near stratholme)
-- (NULL, 12384, 5),
--
-- ENDING PLACEHOLDER
(NULL, 6807, 15, 90, 90)
;

696
src/AiFactory.cpp Normal file
View File

@ -0,0 +1,696 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#include "AiFactory.h"
#include "BattlegroundMgr.h"
#include "Playerbots.h"
#include "Engine.h"
#include "Group.h"
#include "DKAiObjectContext.h"
#include "PriestAiObjectContext.h"
#include "MageAiObjectContext.h"
#include "WarlockAiObjectContext.h"
#include "WarriorAiObjectContext.h"
#include "ShamanAiObjectContext.h"
#include "PaladinAiObjectContext.h"
#include "DruidAiObjectContext.h"
#include "HunterAiObjectContext.h"
#include "RogueAiObjectContext.h"
AiObjectContext* AiFactory::createAiObjectContext(Player* player, PlayerbotAI* botAI)
{
switch (player->getClass())
{
case CLASS_PRIEST:
return new PriestAiObjectContext(botAI);
case CLASS_MAGE:
return new MageAiObjectContext(botAI);
case CLASS_WARLOCK:
return new WarlockAiObjectContext(botAI);
case CLASS_WARRIOR:
return new WarriorAiObjectContext(botAI);
case CLASS_SHAMAN:
return new ShamanAiObjectContext(botAI);
case CLASS_PALADIN:
return new PaladinAiObjectContext(botAI);
case CLASS_DRUID:
return new DruidAiObjectContext(botAI);
case CLASS_HUNTER:
return new HunterAiObjectContext(botAI);
case CLASS_ROGUE:
return new RogueAiObjectContext(botAI);
case CLASS_DEATH_KNIGHT:
return new DKAiObjectContext(botAI);
}
return new AiObjectContext(botAI);
}
uint8 AiFactory::GetPlayerSpecTab(Player* bot)
{
std::map<uint8, uint32> tabs = GetPlayerSpecTabs(bot);
if (bot->getLevel() >= 10 && ((tabs[0] + tabs[1] + tabs[2]) > 0))
{
std::map<uint8, uint32> tabs = GetPlayerSpecTabs(bot);
int8 tab = -1;
uint32 max = 0;
for (uint32 i = 0; i < uint32(3); i++)
{
if (tab == -1 || max < tabs[i])
{
tab = i;
max = tabs[i];
}
}
return tab;
}
else
{
uint8 tab = 0;
switch (bot->getClass())
{
case CLASS_MAGE:
tab = 1;
break;
case CLASS_PALADIN:
tab = 2;
break;
case CLASS_PRIEST:
tab = 1;
break;
}
return tab;
}
}
std::map<uint8, uint32> AiFactory::GetPlayerSpecTabs(Player* bot)
{
std::map<uint8, uint32> tabs;
for (uint32 i = 0; i < 3; i++)
tabs[i] = 0;
uint32 classMask = bot->getClassMask();
for (uint32 i = 0; i < sTalentStore.GetNumRows(); ++i)
{
TalentEntry const *talentInfo = sTalentStore.LookupEntry(i);
if (!talentInfo)
continue;
TalentTabEntry const *talentTabInfo = sTalentTabStore.LookupEntry(talentInfo->TalentTab);
if (!talentTabInfo)
continue;
if ((classMask & talentTabInfo->ClassMask) == 0)
continue;
uint32 maxRank = 0;
for (int32 rank = MAX_TALENT_RANK - 1; rank >= 0; --rank)
{
if (!talentInfo->RankID[rank])
continue;
uint32 spellid = talentInfo->RankID[rank];
if (spellid && bot->HasSpell(spellid))
maxRank = rank + 1;
}
tabs[talentTabInfo->tabpage] += maxRank;
}
return tabs;
}
BotRoles AiFactory::GetPlayerRoles(Player* player)
{
BotRoles role = BOT_ROLE_NONE;
uint8 tab = GetPlayerSpecTab(player);
switch (player->getClass())
{
case CLASS_PRIEST:
if (tab == 2)
role = BOT_ROLE_DPS;
else
role = BOT_ROLE_HEALER;
break;
case CLASS_SHAMAN:
if (tab == 2)
role = BOT_ROLE_HEALER;
else
role = BOT_ROLE_DPS;
break;
case CLASS_WARRIOR:
if (tab == 2)
role = BOT_ROLE_TANK;
else
role = BOT_ROLE_DPS;
break;
case CLASS_PALADIN:
if (tab == 0)
role = BOT_ROLE_HEALER;
else if (tab == 1)
role = BOT_ROLE_TANK;
else if (tab == 2)
role = BOT_ROLE_DPS;
break;
case CLASS_DRUID:
if (tab == 0)
role = BOT_ROLE_DPS;
else if (tab == 1)
role = (BotRoles)(BOT_ROLE_TANK | BOT_ROLE_DPS);
else if (tab == 2)
role = BOT_ROLE_HEALER;
break;
default:
role = BOT_ROLE_DPS;
break;
}
return role;
}
std::string AiFactory::GetPlayerSpecName(Player* player)
{
std::string specName;
int tab = GetPlayerSpecTab(player);
switch (player->getClass())
{
case CLASS_PRIEST:
if (tab == 2)
specName = "shadow";
else if (tab == 1)
specName = "holy";
else
specName = "disc";
; break;
case CLASS_SHAMAN:
if (tab == 2)
specName = "resto";
else if (tab == 1)
specName = "enhance";
else
specName = "elem";
break;
case CLASS_WARRIOR:
if (tab == 2)
specName = "prot";
else if (tab == 1)
specName = "fury";
else
specName = "arms";
break;
case CLASS_PALADIN:
if (tab == 0)
specName = "holy";
else if (tab == 1)
specName = "prot";
else if (tab == 2)
specName = "retrib";
break;
case CLASS_DRUID:
if (tab == 0)
specName = "balance";
else if (tab == 1)
specName = "feraldps";
else if (tab == 2)
specName = "resto";
break;
case CLASS_ROGUE:
if (tab == 0)
specName = "assas";
else if (tab == 1)
specName = "combat";
else if (tab == 2)
specName = "subtle";
break;
case CLASS_HUNTER:
if (tab == 0)
specName = "beast";
else if (tab == 1)
specName = "marks";
else if (tab == 2)
specName = "surv";
break;
case CLASS_DEATH_KNIGHT:
if (tab == 0)
specName = "blooddps";
else if (tab == 1)
specName = "frostdps";
else if (tab == 2)
specName = "unholydps";
break;
case CLASS_MAGE:
if (tab == 0)
specName = "arcane";
else if (tab == 1)
specName = "fire";
else if (tab == 2)
specName = "frost";
break;
case CLASS_WARLOCK:
if (tab == 0)
specName = "afflic";
else if (tab == 1)
specName = "demo";
else if (tab == 2)
specName = "destro";
break;
default:
break;
}
return std::move(specName);
}
void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const facade, Engine* engine)
{
uint8 tab = GetPlayerSpecTab(player);
if (!player->InBattleground())
{
engine->addStrategies("racials", "chat", "default", "potions", "cast time", "conserve mana", "duel", nullptr);
}
switch (player->getClass())
{
case CLASS_PRIEST:
if (tab == 2)
{
engine->addStrategies("dps", "shadow debuff", "shadow aoe", "threat", nullptr);
}
else if (tab == 0)
{
engine->addStrategies("holy", "shadow debuff", "shadow aoe", "threat", nullptr);
//if (player->getLevel() >= 4)
//engine->addStrategy("dps debuff");
}
else
engine->addStrategies("heal", "threat", nullptr);
engine->addStrategies("dps assist", "flee", "cure", "ranged", "cc", nullptr);
break;
case CLASS_MAGE:
if (tab == 0)
engine->addStrategies("arcane", "threat", nullptr);
else if (tab == 1)
engine->addStrategies("fire", "fire aoe", "threat", nullptr);
else
engine->addStrategies("frost", "frost aoe", "threat", "dps aoe", nullptr);
engine->addStrategies("dps", "dps assist", "flee", "cure", "ranged", "cc", nullptr);
break;
case CLASS_WARRIOR:
if (tab == 2)
engine->addStrategies("tank", "tank assist", "aoe", "close", "mark rti", nullptr);
else if (player->getLevel() < 30 || tab == 0)
engine->addStrategies("arms", "aoe", "dps assist", "threat", "close", nullptr);
else
engine->addStrategies("fury", "aoe", "dps assist", "threat", "close", nullptr);
break;
case CLASS_SHAMAN:
if (tab == 0)
engine->addStrategies("caster", "caster aoe", "bmana", "threat", "flee", "ranged", nullptr);
else if (tab == 2)
engine->addStrategies("heal", "bmana", "flee", "ranged", nullptr);
else
engine->addStrategies("dps", "melee aoe", "bdps", "threat", "close", nullptr);
engine->addStrategies("dps assist", "cure", "totems", nullptr);
break;
case CLASS_PALADIN:
if (tab == 1)
engine->addStrategies("tank", "tank assist", "bthreat", "cure", "barmor", "bstats", "close", "cc", nullptr);
else if (tab == 0)
engine->addStrategies("heal", "bmana", "dps assist", "cure", "flee", "barmor", nullptr);
else
engine->addStrategies("dps", "bdps", "dps assist", "cure", "baoe", "close", "cc", nullptr);
if (player->getLevel() < 14)
{
engine->addStrategy("bdps");
}
if (player->getLevel() < 16)
{
engine->addStrategy("barmor");
}
break;
case CLASS_DRUID:
if (tab == 0)
{
engine->addStrategies("caster", "cure", "caster aoe", "threat", "flee", "dps assist", "ranged", "cc", nullptr);
if (player->getLevel() > 19)
engine->addStrategy("caster debuff");
}
else if (tab == 2)
engine->addStrategies("heal", "cure", "flee", "dps assist", "ranged", "cc", nullptr);
else
{
engine->removeStrategy("ranged");
engine->addStrategies("bear", "tank assist", "flee", "close", nullptr);
}
break;
case CLASS_HUNTER:
engine->addStrategies("dps", "bdps", "threat", "dps assist", "ranged", "pet", "cc", nullptr);
if (player->getLevel() > 19)
engine->addStrategy("dps debuff");
break;
case CLASS_ROGUE:
engine->addStrategies("dps", "threat", "dps assist", "aoe", "close", "cc", "behind", "stealth", nullptr);
break;
case CLASS_WARLOCK:
if (player->getLevel() > 19)
engine->addStrategy("dps debuff");
engine->addStrategies("dps assist", "dps", "flee", "ranged", "cc", "pet", "threat", nullptr);
break;
case CLASS_DEATH_KNIGHT:
if (tab == 0)
engine->addStrategies("blood", nullptr);
else if (tab == 1)
engine->addStrategies("frost", "frost aoe", "dps assist", "threat", nullptr);
else
engine->addStrategies("unholy", "unholy aoe", "dps assist", "threat", nullptr);
engine->addStrategies("dps assist", "flee", "close", "cc", nullptr);
break;
}
if (facade->IsRealPlayer() || sRandomPlayerbotMgr->IsRandomBot(player))
{
if (!player->GetGroup())
{
engine->ChangeStrategy(sPlayerbotAIConfig->randomBotCombatStrategies);
engine->addStrategy("flee");
engine->addStrategy("boost");
if (player->getClass() == CLASS_WARLOCK)
{
engine->removeStrategy("ranged");
}
if (player->getClass() == CLASS_DRUID && tab == 2)
{
engine->addStrategies("caster", "caster aoe", nullptr);
}
if (player->getClass() == CLASS_DRUID && tab == 1 && urand(0, 100) > 50 && player->getLevel() > 19)
{
engine->addStrategy("dps");
}
if (player->getClass() == CLASS_PRIEST && tab == 1)
{
engine->removeStrategy("heal");
engine->addStrategies("holy", "shadow debuff", "shadow aoe", "threat", nullptr);
}
if (player->getClass() == CLASS_SHAMAN && tab == 2)
{
engine->addStrategies("caster", "caster aoe", nullptr);
}
if (player->getClass() == CLASS_PALADIN && tab == 0)
{
engine->addStrategies("dps", "close", nullptr);
}
}
}
else
{
engine->ChangeStrategy(sPlayerbotAIConfig->combatStrategies);
}
// Battleground switch
if (player->InBattleground())
{
BattlegroundTypeId bgType = player->GetBattlegroundTypeId();
if (bgType == BATTLEGROUND_RB)
bgType = player->GetBattleground()->GetBgTypeID(true);
if (bgType == BATTLEGROUND_WS)
engine->addStrategy("warsong");
if (bgType == BATTLEGROUND_AB)
engine->addStrategy("arathi");
if (bgType == BATTLEGROUND_AV)
engine->addStrategy("alterac");
if (bgType == BATTLEGROUND_EY)
engine->addStrategy("eye");
if (bgType == BATTLEGROUND_IC)
engine->addStrategy("isle");
if (player->InArena())
{
engine->addStrategy("arena");
}
engine->addStrategies("boost", "racials", "chat", "default", "aoe", "potions", "conserve mana", "cast time", "dps assist", nullptr);
engine->removeStrategy("custom::say");
engine->removeStrategy("flee");
engine->removeStrategy("threat");
engine->addStrategy("boost");
if ((player->getClass() == CLASS_DRUID && tab == 2) || (player->getClass() == CLASS_SHAMAN && tab == 2))
engine->addStrategies("caster", "caster aoe", nullptr);
if (player->getClass() == CLASS_DRUID && tab == 1)
engine->addStrategies("behind", "dps", nullptr);
if (player->getClass() == CLASS_ROGUE)
engine->addStrategies("behind", "stealth", nullptr);
}
}
Engine* AiFactory::createCombatEngine(Player* player, PlayerbotAI* const facade, AiObjectContext* aiObjectContext)
{
Engine* engine = new Engine(facade, aiObjectContext);
AddDefaultCombatStrategies(player, facade, engine);
return engine;
}
void AiFactory::AddDefaultNonCombatStrategies(Player* player, PlayerbotAI* const facade, Engine* nonCombatEngine)
{
uint8 tab = GetPlayerSpecTab(player);
switch (player->getClass())
{
case CLASS_PRIEST:
nonCombatEngine->addStrategies("dps assist", "cure", nullptr);
break;
case CLASS_PALADIN:
if (tab == 1)
nonCombatEngine->addStrategies("bthreat", "tank assist", "barmor", "bstats", nullptr);
else if (tab == 0)
nonCombatEngine->addStrategies("dps assist", "barmor", "bmana", nullptr);
else
nonCombatEngine->addStrategies("dps assist", "baoe", "bdps", nullptr);
nonCombatEngine->addStrategies("cure", nullptr);
if (player->getLevel() < 14)
nonCombatEngine->addStrategies("bdps", nullptr);
if (player->getLevel() < 16)
nonCombatEngine->addStrategies("barmor", nullptr);
break;
case CLASS_HUNTER:
nonCombatEngine->addStrategies("bdps", "dps assist", nullptr);
break;
case CLASS_SHAMAN:
if (tab == 0 || tab == 2)
nonCombatEngine->addStrategy("bmana");
else
nonCombatEngine->addStrategy("bdps");
nonCombatEngine->addStrategies("dps assist", "cure", nullptr);
break;
case CLASS_MAGE:
if (tab == 1)
nonCombatEngine->addStrategy("bdps");
else
nonCombatEngine->addStrategy("bmana");
nonCombatEngine->addStrategies("dps assist", "cure", nullptr);
break;
case CLASS_DRUID:
if (tab == 1)
nonCombatEngine->addStrategy("tank assist");
else
nonCombatEngine->addStrategies("dps assist", "cure", nullptr);
break;
case CLASS_WARRIOR:
if (tab == 2)
nonCombatEngine->addStrategy("tank assist");
else
nonCombatEngine->addStrategy("dps assist");
break;
case CLASS_WARLOCK:
nonCombatEngine->addStrategies("pet", "dps assist", nullptr);
break;
case CLASS_DEATH_KNIGHT:
if (tab == 0)
nonCombatEngine->addStrategy("tank assist");
else
nonCombatEngine->addStrategy("dps assist");
break;
default:
nonCombatEngine->addStrategy("dps assist");
break;
}
if (!player->InBattleground())
{
nonCombatEngine->addStrategies("nc", "food", "chat", "follow",
"default", "quest", "loot", "gather", "duel", "emote", "conserve mana", "buff", "mount", nullptr);
}
if ((facade->IsRealPlayer() || sRandomPlayerbotMgr->IsRandomBot(player)) && !player->InBattleground())
{
Player* master = facade->GetMaster();
// let 25% of free bots start duels.
if (!urand(0, 3))
nonCombatEngine->addStrategy("start duel");
if (!player->GetGroup() || player->GetGroup()->GetLeaderGUID() == player->GetGUID())
{
// let 25% of random not grouped (or grp leader) bots help other players
if (!urand(0, 3))
nonCombatEngine->addStrategy("attack tagged");
nonCombatEngine->addStrategy("pvp");
nonCombatEngine->addStrategy("collision");
nonCombatEngine->addStrategy("grind");
nonCombatEngine->addStrategy("group");
nonCombatEngine->addStrategy("guild");
if (sPlayerbotAIConfig->autoDoQuests)
{
nonCombatEngine->addStrategy("travel");
nonCombatEngine->addStrategy("rpg");
}
if (sPlayerbotAIConfig->randomBotJoinLfg)
nonCombatEngine->addStrategy("lfg");
if (sPlayerbotAIConfig->randomBotJoinBG)
nonCombatEngine->addStrategy("bg");
if (!master || GET_PLAYERBOT_AI(master))
nonCombatEngine->addStrategy("maintenance");
nonCombatEngine->ChangeStrategy(sPlayerbotAIConfig->randomBotNonCombatStrategies);
}
else
{
if (facade)
{
if (master)
{
PlayerbotAI* masterBotAI = GET_PLAYERBOT_AI(master);
if (masterBotAI || sRandomPlayerbotMgr->IsRandomBot(player))
{
nonCombatEngine->addStrategy("pvp");
nonCombatEngine->addStrategy("collision");
nonCombatEngine->addStrategy("grind");
nonCombatEngine->addStrategy("group");
nonCombatEngine->addStrategy("guild");
if (sPlayerbotAIConfig->autoDoQuests)
{
nonCombatEngine->addStrategy("travel");
nonCombatEngine->addStrategy("rpg");
}
if (masterBotAI)
nonCombatEngine->addStrategy("maintenance");
nonCombatEngine->ChangeStrategy(sPlayerbotAIConfig->randomBotNonCombatStrategies);
}
else
nonCombatEngine->ChangeStrategy(sPlayerbotAIConfig->nonCombatStrategies);
}
}
}
}
else
{
nonCombatEngine->ChangeStrategy(sPlayerbotAIConfig->nonCombatStrategies);
}
// Battleground switch
if (player->InBattleground())
{
nonCombatEngine->addStrategies("nc", "chat", "default", "buff", "food", "mount", "pvp", "collision", "dps assist", "attack tagged", "emote", nullptr);
nonCombatEngine->removeStrategy("custom::say");
nonCombatEngine->removeStrategy("travel");
nonCombatEngine->removeStrategy("rpg");
nonCombatEngine->removeStrategy("grind");
BattlegroundTypeId bgType = player->GetBattlegroundTypeId();
if (bgType == BATTLEGROUND_RB)
bgType = player->GetBattleground()->GetBgTypeID(true);
if (bgType <= BATTLEGROUND_EY || bgType == BATTLEGROUND_IC) // do not add for not supported bg
nonCombatEngine->addStrategy("battleground");
if (bgType == BATTLEGROUND_WS)
nonCombatEngine->addStrategy("warsong");
if (bgType == BATTLEGROUND_AV)
nonCombatEngine->addStrategy("alterac");
if (bgType == BATTLEGROUND_AB)
nonCombatEngine->addStrategy("arathi");
if (bgType == BATTLEGROUND_EY)
nonCombatEngine->addStrategy("eye");
if (bgType == BATTLEGROUND_IC)
nonCombatEngine->addStrategy("isle");
if (player->InArena())
{
nonCombatEngine->addStrategy("arena");
nonCombatEngine->removeStrategy("mount");
}
}
}
Engine* AiFactory::createNonCombatEngine(Player* player, PlayerbotAI* const facade, AiObjectContext* aiObjectContext)
{
Engine* nonCombatEngine = new Engine(facade, aiObjectContext);
AddDefaultNonCombatStrategies(player, facade, nonCombatEngine);
return nonCombatEngine;
}
void AiFactory::AddDefaultDeadStrategies(Player* player, PlayerbotAI* const facade, Engine* deadEngine)
{
deadEngine->addStrategies("dead", "stay", "chat", "default", "follow", nullptr);
if (sRandomPlayerbotMgr->IsRandomBot(player) && !player->GetGroup())
{
deadEngine->removeStrategy("follow");
}
}
Engine* AiFactory::createDeadEngine(Player* player, PlayerbotAI* const facade, AiObjectContext* AiObjectContext)
{
Engine* deadEngine = new Engine(facade, AiObjectContext);
AddDefaultDeadStrategies(player, facade, deadEngine);
return deadEngine;
}

36
src/AiFactory.h Normal file
View File

@ -0,0 +1,36 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#ifndef _PLAYERBOT_AIFACTORY_H
#define _PLAYERBOT_AIFACTORY_H
#include "Common.h"
#include <map>
class AiObjectContext;
class Engine;
class Player;
class PlayerbotAI;
enum BotRoles : uint8;
class AiFactory
{
public:
static AiObjectContext* createAiObjectContext(Player* player, PlayerbotAI* botAI);
static Engine* createCombatEngine(Player* player, PlayerbotAI* const facade, AiObjectContext* aiObjectContext);
static Engine* createNonCombatEngine(Player* player, PlayerbotAI* const facade, AiObjectContext* aiObjectContext);
static Engine* createDeadEngine(Player* player, PlayerbotAI* const facade, AiObjectContext* aibjectContext);
static void AddDefaultNonCombatStrategies(Player* player, PlayerbotAI* const facade, Engine* nonCombatEngine);
static void AddDefaultDeadStrategies(Player* player, PlayerbotAI* const facade, Engine* deadEngine);
static void AddDefaultCombatStrategies(Player* player, PlayerbotAI* const facade, Engine* engine);
static uint8 GetPlayerSpecTab(Player* player);
static std::map<uint8, uint32> GetPlayerSpecTabs(Player* player);
static BotRoles GetPlayerRoles(Player* player);
static std::string GetPlayerSpecName(Player* player);
};
#endif

298
src/ChatFilter.cpp Normal file
View File

@ -0,0 +1,298 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#include "ChatFilter.h"
#include "Group.h"
#include "Playerbots.h"
#include "RtiTargetValue.h"
std::string const ChatFilter::Filter(std::string& message)
{
if (message.find("@") == std::string::npos)
return message;
return message.substr(message.find(" ") + 1);
}
class StrategyChatFilter : public ChatFilter
{
public:
StrategyChatFilter(PlayerbotAI* botAI) : ChatFilter(botAI) { }
std::string const Filter(std::string& message) override
{
Player* bot = botAI->GetBot();
bool tank = message.find("@tank") == 0;
if (tank && !botAI->IsTank(bot))
return "";
bool dps = message.find("@dps") == 0;
if (dps && (botAI->IsTank(bot) || botAI->IsHeal(bot)))
return "";
bool heal = message.find("@heal") == 0;
if (heal && !botAI->IsHeal(bot))
return "";
bool ranged = message.find("@ranged") == 0;
if (ranged && !botAI->IsRanged(bot))
return "";
bool melee = message.find("@melee") == 0;
if (melee && botAI->IsRanged(bot))
return "";
if (tank || dps || heal || ranged || melee)
return ChatFilter::Filter(message);
return message;
}
};
class LevelChatFilter : public ChatFilter
{
public:
LevelChatFilter(PlayerbotAI* botAI) : ChatFilter(botAI) { }
std::string const Filter(std::string& message) override
{
Player* bot = botAI->GetBot();
if (message[0] != '@')
return message;
if (message.find("-") != std::string::npos)
{
uint32 fromLevel = atoi(message.substr(message.find("@") + 1, message.find("-")).c_str());
uint32 toLevel = atoi(message.substr(message.find("-") + 1, message.find(" ")).c_str());
if (bot->getLevel() >= fromLevel && bot->getLevel() <= toLevel)
return ChatFilter::Filter(message);
return message;
}
uint32 level = atoi(message.substr(message.find("@") + 1, message.find(" ")).c_str());
if (bot->getLevel() == level)
return ChatFilter::Filter(message);
return message;
}
};
class CombatTypeChatFilter : public ChatFilter
{
public:
CombatTypeChatFilter(PlayerbotAI* botAI) : ChatFilter(botAI) { }
std::string const Filter(std::string& message) override
{
Player* bot = botAI->GetBot();
bool melee = message.find("@melee") == 0;
bool ranged = message.find("@ranged") == 0;
if (!melee && !ranged)
return message;
switch (bot->getClass())
{
case CLASS_WARRIOR:
case CLASS_PALADIN:
case CLASS_ROGUE:
case CLASS_DEATH_KNIGHT:
if (ranged)
return "";
break;
case CLASS_HUNTER:
case CLASS_PRIEST:
case CLASS_MAGE:
case CLASS_WARLOCK:
if (melee)
return "";
break;
case CLASS_DRUID:
if (ranged && botAI->IsTank(bot))
return "";
if (melee && !botAI->IsTank(bot))
return "";
break;
case CLASS_SHAMAN:
if (melee && botAI->IsHeal(bot))
return "";
if (ranged && !botAI->IsHeal(bot))
return "";
break;
}
return ChatFilter::Filter(message);
}
};
class RtiChatFilter : public ChatFilter
{
public:
RtiChatFilter(PlayerbotAI* botAI) : ChatFilter(botAI)
{
rtis.push_back("@star");
rtis.push_back("@circle");
rtis.push_back("@diamond");
rtis.push_back("@triangle");
rtis.push_back("@moon");
rtis.push_back("@square");
rtis.push_back("@cross");
rtis.push_back("@skull");
}
std::string const Filter(std::string& message) override
{
Player* bot = botAI->GetBot();
Group* group = bot->GetGroup();
if (!group)
return message;
bool found = false;
bool isRti = false;
for (std::vector<std::string>::iterator i = rtis.begin(); i != rtis.end(); i++)
{
std::string const rti = *i;
bool isRti = message.find(rti) == 0;
if (!isRti)
continue;
ObjectGuid rtiTarget = group->GetTargetIcon(RtiTargetValue::GetRtiIndex(rti.substr(1)));
if (bot->GetGUID() == rtiTarget)
return ChatFilter::Filter(message);
Unit* target = *botAI->GetAiObjectContext()->GetValue<Unit*>("current target");
if (!target)
return "";
if (target->GetGUID() != rtiTarget)
return "";
found |= isRti;
if (found)
break;
}
if (found)
return ChatFilter::Filter(message);
return message;
}
private:
std::vector<std::string> rtis;
};
class ClassChatFilter : public ChatFilter
{
public:
ClassChatFilter(PlayerbotAI* botAI) : ChatFilter(botAI)
{
classNames["@death_knight"] = CLASS_DEATH_KNIGHT;
classNames["@druid"] = CLASS_DRUID;
classNames["@hunter"] = CLASS_HUNTER;
classNames["@mage"] = CLASS_MAGE;
classNames["@paladin"] = CLASS_PALADIN;
classNames["@priest"] = CLASS_PRIEST;
classNames["@rogue"] = CLASS_ROGUE;
classNames["@shaman"] = CLASS_SHAMAN;
classNames["@warlock"] = CLASS_WARLOCK;
classNames["@warrior"] = CLASS_WARRIOR;
}
std::string const Filter(std::string& message) override
{
Player* bot = botAI->GetBot();
bool found = false;
bool isClass = false;
for (std::map<std::string, uint8>::iterator i = classNames.begin(); i != classNames.end(); i++)
{
bool isClass = message.find(i->first) == 0;
if (isClass && bot->getClass() != i->second)
return "";
found |= isClass;
if (found)
break;
}
if (found)
return ChatFilter::Filter(message);
return message;
}
private:
std::map<std::string, uint8> classNames;
};
class SubGroupChatFilter : public ChatFilter
{
public:
SubGroupChatFilter(PlayerbotAI* botAI) : ChatFilter(botAI) { }
std::string const Filter(std::string& message) override
{
Player* bot = botAI->GetBot();
if (message.find("@group") == 0)
{
std::string const pnum = message.substr(6, message.find(" "));
uint32 from = atoi(pnum.c_str());
uint32 to = from;
if (pnum.find("-") != std::string::npos)
{
from = atoi(pnum.substr(pnum.find("@") + 1, pnum.find("-")).c_str());
to = atoi(pnum.substr(pnum.find("-") + 1, pnum.find(" ")).c_str());
}
if (!bot->GetGroup())
return message;
uint32 sg = bot->GetSubGroup() + 1;
if (sg >= from && sg <= to)
return ChatFilter::Filter(message);
}
return message;
}
};
CompositeChatFilter::CompositeChatFilter(PlayerbotAI* botAI) : ChatFilter(botAI)
{
filters.push_back(new StrategyChatFilter(botAI));
filters.push_back(new ClassChatFilter(botAI));
filters.push_back(new RtiChatFilter(botAI));
filters.push_back(new CombatTypeChatFilter(botAI));
filters.push_back(new LevelChatFilter(botAI));
filters.push_back(new SubGroupChatFilter(botAI));
}
CompositeChatFilter::~CompositeChatFilter()
{
for (std::vector<ChatFilter*>::iterator i = filters.begin(); i != filters.end(); i++)
delete (*i);
}
std::string const CompositeChatFilter::Filter(std::string& message)
{
for (uint32 j = 0; j < filters.size(); ++j)
{
for (std::vector<ChatFilter*>::iterator i = filters.begin(); i != filters.end(); i++)
{
message = (*i)->Filter(message);
if (message.empty())
break;
}
}
return message;
}

36
src/ChatFilter.h Normal file
View File

@ -0,0 +1,36 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#ifndef _PLAYERBOT_CHATFILTER_H
#define _PLAYERBOT_CHATFILTER_H
#include "Common.h"
#include "PlayerbotAIAware.h"
#include <vector>
class PlayerbotAI;
class ChatFilter : public PlayerbotAIAware
{
public:
ChatFilter(PlayerbotAI* botAI) : PlayerbotAIAware(botAI) { }
virtual ~ChatFilter() { }
virtual std::string const Filter(std::string& message);
};
class CompositeChatFilter : public ChatFilter
{
public:
CompositeChatFilter(PlayerbotAI* botAI);
virtual ~CompositeChatFilter();
std::string const Filter(std::string& message) override;
private:
std::vector<ChatFilter*> filters;
};
#endif

569
src/ChatHelper.cpp Normal file
View File

@ -0,0 +1,569 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#include "ChatHelper.h"
#include "AiFactory.h"
#include "Playerbots.h"
#include "SpellInfo.h"
std::map<std::string, uint32> ChatHelper::consumableSubClasses;
std::map<std::string, uint32> ChatHelper::tradeSubClasses;
std::map<std::string, uint32> ChatHelper::itemQualities;
std::map<std::string, uint32> ChatHelper::projectileSubClasses;
std::map<std::string, uint32> ChatHelper::slots;
std::map<std::string, uint32> ChatHelper::skills;
std::map<std::string, ChatMsg> ChatHelper::chats;
std::map<uint8, std::string> ChatHelper::classes;
std::map<uint8, std::string> ChatHelper::races;
std::map<uint8, std::map<uint8, std::string> > ChatHelper::specs;
template<class T>
static bool substrContainsInMap(std::string const searchTerm, std::map<std::string, T> searchIn)
{
for (typename std::map<std::string, T>::iterator i = searchIn.begin(); i != searchIn.end(); ++i)
{
std::string const term = i->first;
if (term.size() > 1 && searchTerm.find(term) != std::string::npos)
return true;
}
return false;
}
ChatHelper::ChatHelper(PlayerbotAI* botAI) : PlayerbotAIAware(botAI)
{
itemQualities["poor"] = ITEM_QUALITY_POOR;
itemQualities["gray"] = ITEM_QUALITY_POOR;
itemQualities["normal"] = ITEM_QUALITY_NORMAL;
itemQualities["white"] = ITEM_QUALITY_NORMAL;
itemQualities["uncommon"] = ITEM_QUALITY_UNCOMMON;
itemQualities["green"] = ITEM_QUALITY_UNCOMMON;
itemQualities["rare"] = ITEM_QUALITY_RARE;
itemQualities["blue"] = ITEM_QUALITY_RARE;
itemQualities["epic"] = ITEM_QUALITY_EPIC;
itemQualities["violet"] = ITEM_QUALITY_EPIC;
itemQualities["legendary"] = ITEM_QUALITY_LEGENDARY;
itemQualities["yellow"] = ITEM_QUALITY_LEGENDARY;
consumableSubClasses["potion"] = ITEM_SUBCLASS_POTION;
consumableSubClasses["elixir"] = ITEM_SUBCLASS_ELIXIR;
consumableSubClasses["flask"] = ITEM_SUBCLASS_FLASK;
consumableSubClasses["scroll"] = ITEM_SUBCLASS_SCROLL;
consumableSubClasses["food"] = ITEM_SUBCLASS_FOOD;
consumableSubClasses["bandage"] = ITEM_SUBCLASS_BANDAGE;
consumableSubClasses["enchant"] = ITEM_SUBCLASS_CONSUMABLE_OTHER;
projectileSubClasses["arrows"] = ITEM_SUBCLASS_ARROW;
projectileSubClasses["bullets"] = ITEM_SUBCLASS_BULLET;
//tradeSubClasses["cloth"] = ITEM_SUBCLASS_CLOTH;
//tradeSubClasses["leather"] = ITEM_SUBCLASS_LEATHER;
//tradeSubClasses["metal"] = ITEM_SUBCLASS_METAL_STONE;
//tradeSubClasses["stone"] = ITEM_SUBCLASS_METAL_STONE;
//tradeSubClasses["ore"] = ITEM_SUBCLASS_METAL_STONE;
//tradeSubClasses["meat"] = ITEM_SUBCLASS_MEAT;
//tradeSubClasses["herb"] = ITEM_SUBCLASS_HERB;
//tradeSubClasses["elemental"] = ITEM_SUBCLASS_ELEMENTAL;
//tradeSubClasses["disenchants"] = ITEM_SUBCLASS_ENCHANTING;
//tradeSubClasses["enchanting"] = ITEM_SUBCLASS_ENCHANTING;
//tradeSubClasses["gems"] = ITEM_SUBCLASS_JEWELCRAFTING;
//tradeSubClasses["jewels"] = ITEM_SUBCLASS_JEWELCRAFTING;
//tradeSubClasses["jewelcrafting"] = ITEM_SUBCLASS_JEWELCRAFTING;
slots["head"] = EQUIPMENT_SLOT_HEAD;
slots["neck"] = EQUIPMENT_SLOT_NECK;
slots["shoulder"] = EQUIPMENT_SLOT_SHOULDERS;
slots["shirt"] = EQUIPMENT_SLOT_BODY;
slots["chest"] = EQUIPMENT_SLOT_CHEST;
slots["waist"] = EQUIPMENT_SLOT_WAIST;
slots["legs"] = EQUIPMENT_SLOT_LEGS;
slots["feet"] = EQUIPMENT_SLOT_FEET;
slots["wrist"] = EQUIPMENT_SLOT_WRISTS;
slots["hands"] = EQUIPMENT_SLOT_HANDS;
slots["finger 1"] = EQUIPMENT_SLOT_FINGER1;
slots["finger 2"] = EQUIPMENT_SLOT_FINGER2;
slots["trinket 1"] = EQUIPMENT_SLOT_TRINKET1;
slots["trinket 2"] = EQUIPMENT_SLOT_TRINKET2;
slots["back"] = EQUIPMENT_SLOT_BACK;
slots["main hand"] = EQUIPMENT_SLOT_MAINHAND;
slots["off hand"] = EQUIPMENT_SLOT_OFFHAND;
slots["ranged"] = EQUIPMENT_SLOT_RANGED;
slots["tabard"] = EQUIPMENT_SLOT_TABARD;
skills["first aid"] = SKILL_FIRST_AID;
skills["fishing"] = SKILL_FISHING;
skills["cooking"] = SKILL_COOKING;
skills["alchemy"] = SKILL_ALCHEMY;
skills["enchanting"] = SKILL_ENCHANTING;
skills["engineering"] = SKILL_ENGINEERING;
skills["leatherworking"] = SKILL_LEATHERWORKING;
skills["blacksmithing"] = SKILL_BLACKSMITHING;
skills["tailoring"] = SKILL_TAILORING;
skills["herbalism"] = SKILL_HERBALISM;
skills["mining"] = SKILL_MINING;
skills["skinning"] = SKILL_SKINNING;
skills["jewelcrafting"] = SKILL_JEWELCRAFTING;
chats["party"] = CHAT_MSG_PARTY;
chats["p"] = CHAT_MSG_PARTY;
chats["guild"] = CHAT_MSG_GUILD;
chats["g"] = CHAT_MSG_GUILD;
chats["raid"] = CHAT_MSG_RAID;
chats["r"] = CHAT_MSG_RAID;
chats["whisper"] = CHAT_MSG_WHISPER;
chats["w"] = CHAT_MSG_WHISPER;
classes[CLASS_DRUID] = "druid";
specs[CLASS_DRUID][0] = "balance";
specs[CLASS_DRUID][1] = "feral combat";
specs[CLASS_DRUID][2] = "restoration";
classes[CLASS_HUNTER] = "hunter";
specs[CLASS_HUNTER][0] = "beast mastery";
specs[CLASS_HUNTER][1] = "marksmanship";
specs[CLASS_HUNTER][2] = "survival";
classes[CLASS_MAGE] = "mage";
specs[CLASS_MAGE][0] = "arcane";
specs[CLASS_MAGE][1] = "fire";
specs[CLASS_MAGE][2] = "frost";
classes[CLASS_PALADIN] = "paladin";
specs[CLASS_PALADIN][0] = "holy";
specs[CLASS_PALADIN][1] = "protection";
specs[CLASS_PALADIN][2] = "retribution";
classes[CLASS_PRIEST] = "priest";
specs[CLASS_PRIEST][0] = "discipline";
specs[CLASS_PRIEST][1] = "holy";
specs[CLASS_PRIEST][2] = "shadow";
classes[CLASS_ROGUE] = "rogue";
specs[CLASS_ROGUE][0] = "assasination";
specs[CLASS_ROGUE][1] = "combat";
specs[CLASS_ROGUE][2] = "subtlety";
classes[CLASS_SHAMAN] = "shaman";
specs[CLASS_SHAMAN][0] = "elemental";
specs[CLASS_SHAMAN][1] = "enhancement";
specs[CLASS_SHAMAN][2] = "restoration";
classes[CLASS_WARLOCK] = "warlock";
specs[CLASS_WARLOCK][0] = "affliction";
specs[CLASS_WARLOCK][1] = "demonology";
specs[CLASS_WARLOCK][2] = "destruction";
classes[CLASS_WARRIOR] = "warrior";
specs[CLASS_WARRIOR][0] = "arms";
specs[CLASS_WARRIOR][1] = "fury";
specs[CLASS_WARRIOR][2] = "protection";
classes[CLASS_DEATH_KNIGHT] = "dk";
specs[CLASS_DEATH_KNIGHT][0] = "blood";
specs[CLASS_DEATH_KNIGHT][1] = "frost";
specs[CLASS_DEATH_KNIGHT][2] = "unholy";
races[RACE_DWARF] = "Dwarf";
races[RACE_GNOME] = "Gnome";
races[RACE_HUMAN] = "Human";
races[RACE_NIGHTELF] = "Night Elf";
races[RACE_ORC] = "Orc";
races[RACE_TAUREN] = "Tauren";
races[RACE_TROLL] = "Troll";
races[RACE_UNDEAD_PLAYER] = "Undead";
races[RACE_BLOODELF] = "Blood Elf";
races[RACE_DRAENEI] = "Draenei";
}
std::string const ChatHelper::formatMoney(uint32 copper)
{
std::ostringstream out;
if (!copper)
{
out << "0";
return out.str();
}
uint32 gold = uint32(copper / 10000);
copper -= (gold * 10000);
uint32 silver = uint32(copper / 100);
copper -= (silver * 100);
bool space = false;
if (gold > 0)
{
out << gold << "g";
space = true;
}
if (silver > 0 && gold < 50)
{
if (space)
out << " ";
out << silver << "s";
space = true;
}
if (copper > 0 && gold < 10)
{
if (space)
out << " ";
out << copper << "c";
}
return out.str();
}
uint32 ChatHelper::parseMoney(std::string const text)
{
// if user specified money in ##g##s##c format
std::string acum = "";
uint32 copper = 0;
for (uint8 i = 0; i < text.length(); i++)
{
if (text[i] == 'g')
{
copper += (atol(acum.c_str()) * 100 * 100);
acum = "";
}
else if (text[i] == 'c')
{
copper += atol(acum.c_str());
acum = "";
}
else if (text[i] == 's')
{
copper += (atol(acum.c_str()) * 100);
acum = "";
}
else if (text[i] == ' ')
break;
else if (text[i] >= 48 && text[i] <= 57)
acum += text[i];
else
{
copper = 0;
break;
}
}
return copper;
}
ItemIds ChatHelper::parseItems(std::string const text)
{
ItemIds itemIds;
uint8 pos = 0;
while (true)
{
uint32 i = text.find("Hitem:", pos);
if (i == -1)
break;
pos = i + 6;
uint32 endPos = text.find(':', pos);
if (endPos == -1)
break;
std::string const idC = text.substr(pos, endPos - pos);
uint32 id = atol(idC.c_str());
pos = endPos;
if (id)
itemIds.insert(id);
}
return itemIds;
}
std::string const ChatHelper::FormatQuest(Quest const* quest)
{
std::ostringstream out;
out << "|cFFFFFF00|Hquest:" << quest->GetQuestId() << ':' << quest->GetQuestLevel() << "|h[" << quest->GetTitle() << "]|h|r";
return out.str();
}
std::string const ChatHelper::FormatGameobject(GameObject* go)
{
std::ostringstream out;
out << "|cFFFFFF00|Hfound:" << go->GetGUID().GetRawValue() << ":" << go->GetEntry() << ":" << "|h[" << go->GetGOInfo()->name << "]|h|r";
return out.str();
}
std::string const ChatHelper::FormatWorldobject(WorldObject* wo)
{
std::ostringstream out;
out << "|cFFFFFF00|Hfound:" << wo->GetGUID().GetRawValue() << ":" << wo->GetEntry() << ":" << "|h[";
out << (wo->ToGameObject() ? ((GameObject*)wo)->GetGOInfo()->name : wo->GetName()) << "]|h|r";
return out.str();
}
std::string const ChatHelper::FormatWorldEntry(int32 entry)
{
CreatureTemplate const* cInfo = nullptr;
GameObjectTemplate const* gInfo = nullptr;
if (entry > 0)
cInfo = sObjectMgr->GetCreatureTemplate(entry);
else
gInfo = sObjectMgr->GetGameObjectTemplate(entry * -1);
std::ostringstream out;
out << "|cFFFFFF00|Hentry:" << abs(entry) << ":" << "|h[";
if (entry < 0 && gInfo)
out << gInfo->name;
else if (entry > 0 && cInfo)
out << cInfo->Name;
else
out << "unknown";
out << "]|h|r";
return out.str();
}
std::string const ChatHelper::FormatSpell(SpellInfo const* spellInfo)
{
std::ostringstream out;
out << "|cffffffff|Hspell:" << spellInfo->Id << "|h[" << spellInfo->SpellName[LOCALE_enUS] << "]|h|r";
return out.str();
}
std::string const ChatHelper::FormatItem(ItemTemplate const* proto, uint32 count, uint32 total)
{
char color[32];
sprintf(color, "%x", ItemQualityColors[proto->Quality]);
std::ostringstream out;
out << "|c" << color << "|Hitem:" << proto->ItemId
<< ":0:0:0:0:0:0:0" << "|h[" << proto->Name1
<< "]|h|r";
if (count > 1)
out << "x" << count;
if (total > 0)
out << " (" << total << ")";
return out.str();
}
std::string const ChatHelper::FormatQItem(uint32 itemId)
{
char color[32];
sprintf(color, "%x", ItemQualityColors[0]);
std::ostringstream out;
out << "|c" << color << "|Hitem:" << itemId << ":0:0:0:0:0:0:0"
<< "|h[item"
<< "]|h|r";
return out.str();
}
ChatMsg ChatHelper::parseChat(std::string const text)
{
if (chats.find(text) != chats.end())
return chats[text];
return CHAT_MSG_SYSTEM;
}
std::string const ChatHelper::FormatChat(ChatMsg chat)
{
switch (chat)
{
case CHAT_MSG_GUILD:
return "guild";
case CHAT_MSG_PARTY:
return "party";
case CHAT_MSG_WHISPER:
return "whisper";
case CHAT_MSG_RAID:
return "raid";
}
return "unknown";
}
uint32 ChatHelper::parseSpell(std::string const text)
{
PlayerbotChatHandler handler(botAI->GetBot());
return handler.extractSpellId(text);
}
GuidVector ChatHelper::parseGameobjects(std::string const text)
{
GuidVector gos;
// Link format
// |cFFFFFF00|Hfound:" << guid << ':' << entry << ':' << "|h[" << gInfo->name << "]|h|r";
// |cFFFFFF00|Hfound:9582:1731|h[Copper Vein]|h|r
uint8 pos = 0;
while (true)
{
// extract GO guid
uint32 i = text.find("Hfound:", pos); // base H = 11
if (i == -1) // break if error
break;
pos = i + 7; //start of window in text 11 + 7 = 18
uint32 endPos = text.find(':', pos); // end of window in text 22
if (endPos == -1) //break if error
break;
std::istringstream stream(text.substr(pos, endPos - pos));
uint64 guid;
stream >> guid;
// extract GO entry
pos = endPos + 1;
endPos = text.find(':', pos); // end of window in text
if (endPos == -1) //break if error
break;
std::string const entryC = text.substr(pos, endPos - pos); // get std::string const within window i.e entry
uint32 entry = atol(entryC.c_str()); // convert ascii to float
ObjectGuid lootCurrent = ObjectGuid(guid);
if (guid)
gos.push_back(lootCurrent);
}
return gos;
}
std::string const ChatHelper::FormatQuestObjective(std::string const name, uint32 available, uint32 required)
{
std::ostringstream out;
out << "|cFFFFFFFF" << name << (available >= required ? "|c0000FF00: " : "|c00FF0000: ")
<< available << "/" << required << "|r";
return out.str();
}
uint32 ChatHelper::parseItemQuality(std::string const text)
{
if (itemQualities.find(text) == itemQualities.end())
return MAX_ITEM_QUALITY;
return itemQualities[text];
}
bool ChatHelper::parseItemClass(std::string const text, uint32* itemClass, uint32* itemSubClass)
{
if (text == "questitem")
{
*itemClass = ITEM_CLASS_QUEST;
*itemSubClass = ITEM_SUBCLASS_QUEST;
return true;
}
if (consumableSubClasses.find(text) != consumableSubClasses.end())
{
*itemClass = ITEM_CLASS_CONSUMABLE;
*itemSubClass = consumableSubClasses[text];
return true;
}
if (tradeSubClasses.find(text) != tradeSubClasses.end())
{
*itemClass = ITEM_CLASS_TRADE_GOODS;
*itemSubClass = tradeSubClasses[text];
return true;
}
if (projectileSubClasses.find(text) != projectileSubClasses.end())
{
*itemClass = ITEM_CLASS_PROJECTILE;
*itemSubClass = projectileSubClasses[text];
return true;
}
return false;
}
uint32 ChatHelper::parseSlot(std::string const text)
{
if (slots.find(text) != slots.end())
return slots[text];
return EQUIPMENT_SLOT_END;
}
bool ChatHelper::parseable(std::string const text)
{
return text.find("|H") != std::string::npos || text == "questitem" || text == "ammo" || substrContainsInMap<uint32>(text, consumableSubClasses) ||
substrContainsInMap<uint32>(text, tradeSubClasses) || substrContainsInMap<uint32>(text, itemQualities) || substrContainsInMap<uint32>(text, slots) ||
substrContainsInMap<ChatMsg>(text, chats) || substrContainsInMap<uint32>(text, skills) || parseMoney(text) > 0;
}
std::string const ChatHelper::FormatClass(Player* player, int8 spec)
{
uint8 cls = player->getClass();
std::ostringstream out;
out << specs[cls][spec] << " (";
std::map<uint8, uint32> tabs = AiFactory::GetPlayerSpecTabs(player);
uint32 c0 = tabs[0];
uint32 c1 = tabs[1];
uint32 c2 = tabs[2];
out << (c0 ? "|h|cff00ff00" : "") << c0 << "|h|cffffffff/";
out << (c1 ? "|h|cff00ff00" : "") << c1 << "|h|cffffffff/";
out << (c2 ? "|h|cff00ff00" : "") << c2 << "|h|cffffffff";
out << ") " << classes[cls];
return out.str();
}
std::string const ChatHelper::FormatClass(uint8 cls)
{
return classes[cls];
}
std::string const ChatHelper::FormatRace(uint8 race)
{
return races[race];
}
uint32 ChatHelper::parseSkill(std::string const text)
{
if (skills.find(text) != skills.end())
return skills[text];
return SKILL_NONE;
}
std::string const ChatHelper::FormatSkill(uint32 skill)
{
for (std::map<std::string, uint32>::iterator i = skills.begin(); i != skills.end(); ++i)
{
if (i->second == skill)
return i->first;
}
return "";
}
std::string const ChatHelper::FormatBoolean(bool flag)
{
return flag ? "|cff00ff00ON|r" : "|cffffff00OFF|r";
}
void ChatHelper::eraseAllSubStr(std::string& mainStr, std::string const toErase)
{
size_t pos = std::string::npos;
// Search for the substring in std::string const in a loop untill nothing is found
while ((pos = mainStr.find(toErase)) != std::string::npos)
{
// If found then erase it from std::string
mainStr.erase(pos, toErase.length());
}
}

77
src/ChatHelper.h Normal file
View File

@ -0,0 +1,77 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#ifndef _PLAYERBOT_CHATHELPER_H
#define _PLAYERBOT_CHATHELPER_H
#include "Common.h"
#include "ObjectGuid.h"
#include "PlayerbotAIAware.h"
#include "SharedDefines.h"
#include <map>
class GameObject;
class Quest;
class Player;
class PlayerbotAI;
class SpellInfo;
class WorldObject;
struct ItemTemplate;
typedef std::set<uint32> ItemIds;
typedef std::set<uint32> SpellIds;
class ChatHelper : public PlayerbotAIAware
{
public:
ChatHelper(PlayerbotAI* botAI);
static std::string const formatMoney(uint32 copper);
static uint32 parseMoney(std::string const text);
static ItemIds parseItems(std::string const text);
uint32 parseSpell(std::string const text);
static std::string const FormatQuest(Quest const* quest);
static std::string const FormatItem(ItemTemplate const* proto, uint32 count = 0, uint32 total = 0);
static std::string const FormatQItem(uint32 itemId);
static std::string const FormatSpell(SpellInfo const* spellInfo);
static std::string const FormatGameobject(GameObject* go);
static std::string const FormatWorldobject(WorldObject* wo);
static std::string const FormatWorldEntry(int32 entry);
static std::string const FormatQuestObjective(std::string const name, uint32 available, uint32 required);
static GuidVector parseGameobjects(std::string const text);
static ChatMsg parseChat(std::string const text);
static std::string const FormatChat(ChatMsg chat);
static std::string const FormatClass(Player* player, int8 spec);
static std::string const FormatClass(uint8 cls);
static std::string const FormatRace(uint8 race);
static std::string const FormatSkill(uint32 skill);
static std::string const FormatBoolean(bool flag);
static uint32 parseItemQuality(std::string const text);
static bool parseItemClass(std::string const text, uint32* itemClass, uint32* itemSubClass);
static uint32 parseSlot(std::string const text);
uint32 parseSkill(std::string const text);
static bool parseable(std::string const text);
void eraseAllSubStr(std::string& mainStr, std::string const toErase);
private:
static std::map<std::string, uint32> consumableSubClasses;
static std::map<std::string, uint32> tradeSubClasses;
static std::map<std::string, uint32> itemQualities;
static std::map<std::string, uint32> projectileSubClasses;
static std::map<std::string, uint32> slots;
static std::map<std::string, uint32> skills;
static std::map<std::string, ChatMsg> chats;
static std::map<uint8, std::string> classes;
static std::map<uint8, std::string> races;
static std::map<uint8, std::map<uint8, std::string>> specs;
};
#endif

171
src/FleeManager.cpp Normal file
View File

@ -0,0 +1,171 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#include "FleeManager.h"
#include "Playerbots.h"
#include "ServerFacade.h"
FleeManager::FleeManager(Player* bot, float maxAllowedDistance, float followAngle, bool forceMaxDistance, WorldPosition startPosition) :
bot(bot), maxAllowedDistance(maxAllowedDistance), followAngle(followAngle), forceMaxDistance(forceMaxDistance), startPosition(startPosition ? startPosition : WorldPosition(bot))
{
}
void FleeManager::calculateDistanceToCreatures(FleePoint *point)
{
point->minDistance = -1.0f;
point->sumDistance = 0.0f;
PlayerbotAI* botAI = GET_PLAYERBOT_AI(bot);
GuidVector units = *botAI->GetAiObjectContext()->GetValue<GuidVector>("possible targets no los");
for (GuidVector::iterator i = units.begin(); i != units.end(); ++i)
{
Unit* unit = botAI->GetUnit(*i);
if (!unit)
continue;
float d = sServerFacade->GetDistance2d(unit, point->x, point->y);
point->sumDistance += d;
if (point->minDistance < 0 || point->minDistance > d)
point->minDistance = d;
}
}
bool intersectsOri(float angle, std::vector<float>& angles, float angleIncrement)
{
for (std::vector<float>::iterator i = angles.begin(); i != angles.end(); ++i)
{
float ori = *i;
if (abs(angle - ori) < angleIncrement)
return true;
}
return false;
}
void FleeManager::calculatePossibleDestinations(std::vector<FleePoint*> &points)
{
PlayerbotAI* botAI = GET_PLAYERBOT_AI(bot);
Unit* target = *botAI->GetAiObjectContext()->GetValue<Unit*>("current target");
float botPosX = startPosition.getX();
float botPosY = startPosition.getY();
float botPosZ = startPosition.getZ();
FleePoint start(botAI, botPosX, botPosY, botPosZ);
calculateDistanceToCreatures(&start);
std::vector<float> enemyOri;
GuidVector units = *botAI->GetAiObjectContext()->GetValue<GuidVector>("possible targets no los");
for (GuidVector::iterator i = units.begin(); i != units.end(); ++i)
{
Unit* unit = botAI->GetUnit(*i);
if (!unit)
continue;
float ori = bot->GetAngle(unit);
enemyOri.push_back(ori);
}
float distIncrement = std::max(sPlayerbotAIConfig->followDistance, (maxAllowedDistance - sPlayerbotAIConfig->tooCloseDistance) / 10.0f);
for (float dist = maxAllowedDistance; dist >= sPlayerbotAIConfig->tooCloseDistance ; dist -= distIncrement)
{
float angleIncrement = std::max(M_PI / 20, M_PI / 4 / (1.0 + dist - sPlayerbotAIConfig->tooCloseDistance));
for (float add = 0.0f; add < M_PI / 4 + angleIncrement; add += angleIncrement)
{
for (float angle = add; angle < add + 2 * static_cast<float>(M_PI) + angleIncrement; angle += static_cast<float>(M_PI) / 4)
{
if (intersectsOri(angle, enemyOri, angleIncrement))
continue;
float x = botPosX + cos(angle) * maxAllowedDistance, y = botPosY + sin(angle) * maxAllowedDistance, z = botPosZ + CONTACT_DISTANCE;
if (forceMaxDistance && sServerFacade->IsDistanceLessThan(sServerFacade->GetDistance2d(bot, x, y), maxAllowedDistance - sPlayerbotAIConfig->tooCloseDistance))
continue;
bot->UpdateAllowedPositionZ(x, y, z);
Map* map = startPosition.getMap();
if (map && map->IsInWater(bot->GetPhaseMask(), x, y, z, bot->GetCollisionHeight()))
continue;
if (!bot->IsWithinLOS(x, y, z) || (target && !target->IsWithinLOS(x, y, z)))
continue;
FleePoint* point = new FleePoint(botAI, x, y, z);
calculateDistanceToCreatures(point);
if (sServerFacade->IsDistanceGreaterOrEqualThan(point->minDistance - start.minDistance, sPlayerbotAIConfig->followDistance))
points.push_back(point);
else
delete point;
}
}
}
}
void FleeManager::cleanup(std::vector<FleePoint*> &points)
{
for (std::vector<FleePoint*>::iterator i = points.begin(); i != points.end(); i++)
{
delete *i;
}
points.clear();
}
bool FleeManager::isBetterThan(FleePoint* point, FleePoint* other)
{
return point->sumDistance - other->sumDistance > 0;
}
FleePoint* FleeManager::selectOptimalDestination(std::vector<FleePoint*> &points)
{
FleePoint* best = nullptr;
for (std::vector<FleePoint*>::iterator i = points.begin(); i != points.end(); i++)
{
FleePoint* point = *i;
if (!best || isBetterThan(point, best))
best = point;
}
return best;
}
bool FleeManager::CalculateDestination(float* rx, float* ry, float* rz)
{
std::vector<FleePoint*> points;
calculatePossibleDestinations(points);
FleePoint* point = selectOptimalDestination(points);
if (!point)
{
cleanup(points);
return false;
}
*rx = point->x;
*ry = point->y;
*rz = point->z;
cleanup(points);
return true;
}
bool FleeManager::isUseful()
{
PlayerbotAI* botAI = GET_PLAYERBOT_AI(bot);
GuidVector units = *botAI->GetAiObjectContext()->GetValue<GuidVector>("possible targets no los");
for (GuidVector::iterator i = units.begin(); i != units.end(); ++i)
{
Creature* creature = botAI->GetCreature(*i);
if (!creature)
continue;
if (startPosition.sqDistance(WorldPosition(creature)) < creature->GetAttackDistance(bot) * creature->GetAttackDistance(bot))
return true;
// float d = sServerFacade->GetDistance2d(unit, bot);
// if (sServerFacade->IsDistanceLessThan(d, sPlayerbotAIConfig->aggroDistance)) return true;
}
return false;
}

54
src/FleeManager.h Normal file
View File

@ -0,0 +1,54 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#ifndef _PLAYERBOT_FLEEMANAGER_H
#define _PLAYERBOT_FLEEMANAGER_H
#include "Common.h"
#include "TravelMgr.h"
#include <vector>
class Player;
class PlayerbotAI;
class FleePoint
{
public:
FleePoint(PlayerbotAI* botAI, float x, float y, float z) : botAI(botAI), sumDistance(0.0f), minDistance(0.0f), x(x), y(y), z(z) { }
float x;
float y;
float z;
float sumDistance;
float minDistance;
private:
PlayerbotAI* botAI;
};
class FleeManager
{
public:
FleeManager(Player* bot, float maxAllowedDistance, float followAngle, bool forceMaxDistance = false, WorldPosition startPosition = WorldPosition());
bool CalculateDestination(float* rx, float* ry, float* rz);
bool isUseful();
private:
void calculatePossibleDestinations(std::vector<FleePoint*> &points);
void calculateDistanceToCreatures(FleePoint *point);
void cleanup(std::vector<FleePoint*> &points);
FleePoint* selectOptimalDestination(std::vector<FleePoint*> &points);
bool isBetterThan(FleePoint* point, FleePoint* other);
Player* bot;
float maxAllowedDistance;
float followAngle;
bool forceMaxDistance;
WorldPosition startPosition;
};
#endif

1198
src/GuildTaskMgr.cpp Normal file

File diff suppressed because it is too large Load Diff

59
src/GuildTaskMgr.h Normal file
View File

@ -0,0 +1,59 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#ifndef _PLAYERBOT_GUILDTASKMGR_H
#define _PLAYERBOT_GUILDTASKMGR_H
#include "Common.h"
#include "Transaction.h"
#include <map>
class ChatHandler;
class Player;
class Unit;
class GuildTaskMgr
{
public:
GuildTaskMgr() { };
virtual ~GuildTaskMgr() { };
static GuildTaskMgr* instance()
{
static GuildTaskMgr instance;
return &instance;
}
void Update(Player* owner, Player* guildMaster);
static bool HandleConsoleCommand(ChatHandler* handler, char const* args);
bool IsGuildTaskItem(uint32 itemId, uint32 guildId);
bool CheckItemTask(uint32 itemId, uint32 obtained, Player* owner, Player* bot, bool byMail = false);
void CheckKillTask(Player* owner, Unit* victim);
void CheckKillTaskInternal(Player* owner, Unit* victim);
bool CheckTaskTransfer(std::string const text, Player* owner, Player* bot);
private:
std::map<uint32, uint32> GetTaskValues(uint32 owner, std::string const type, uint32* validIn = nullptr);
uint32 GetTaskValue(uint32 owner, uint32 guildId, std::string const type, uint32* validIn = nullptr);
uint32 SetTaskValue(uint32 owner, uint32 guildId, std::string const type, uint32 value, uint32 validIn);
uint32 CreateTask(Player* owner, uint32 guildId);
bool SendAdvertisement(CharacterDatabaseTransaction& trans, uint32 owner, uint32 guildId);
bool SendItemAdvertisement(CharacterDatabaseTransaction& trans, uint32 itemId, uint32 owner, uint32 guildId, uint32 validIn);
bool SendKillAdvertisement(CharacterDatabaseTransaction& trans, uint32 creatureId, uint32 owner, uint32 guildId, uint32 validIn);
bool SendThanks(CharacterDatabaseTransaction& trans, uint32 owner, uint32 guildId, uint32 payment);
bool Reward(CharacterDatabaseTransaction& trans, uint32 owner, uint32 guildId);
bool CreateItemTask(Player* owner, uint32 guildId);
bool CreateKillTask(Player* owner, uint32 guildId);
uint32 GetMaxItemTaskCount(uint32 itemId);
void CleanupAdverts();
void RemoveDuplicatedAdverts();
void DeleteMail(std::vector<uint32> buffer);
void SendCompletionMessage(Player* player, std::string const verb);
};
#define sGuildTaskMgr GuildTaskMgr::instance()
#endif

52
src/Helpers.cpp Normal file
View File

@ -0,0 +1,52 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#include "Helpers.h"
char* strstri(char const* haystack, char const* needle)
{
if (!*needle)
{
return (char*)haystack;
}
for (; *haystack; ++haystack)
{
if (tolower(*haystack) == tolower(*needle))
{
char const* h = haystack, * n = needle;
for (; *h && *n; ++h, ++n)
{
if (tolower(*h) != tolower(*n))
{
break;
}
}
if (!*n)
{
return (char*)haystack;
}
}
}
return 0;
}
std::string& ltrim(std::string& s)
{
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](int c) {return !std::isspace(c); }));
return s;
}
std::string& rtrim(std::string& s)
{
s.erase(std::find_if(s.rbegin(), s.rend(), [](int c) {return !std::isspace(c); }).base(), s.end());
return s;
}
std::string& trim(std::string& s)
{
return ltrim(rtrim(s));
}

50
src/Helpers.h Normal file
View File

@ -0,0 +1,50 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#ifndef _PLAYERBOT_HELPERS_H
#define _PLAYERBOT_HELPERS_H
#include "Common.h"
#include <map>
#include <vector>
#include <functional>
#include <cctype>
#include <locale>
#include <sstream>
void split(std::vector<std::string>& dest, std::string const str, char const* delim)
{
char* pTempStr = strdup(str.c_str());
char* pWord = strtok(pTempStr, delim);
while (pWord != nullptr)
{
dest.push_back(pWord);
pWord = strtok(nullptr, delim);
}
free(pTempStr);
}
std::vector<std::string>& split(std::string const s, char delim, std::vector<std::string>& elems)
{
std::stringstream ss(s);
std::string item;
while (getline(ss, item, delim))
{
elems.push_back(item);
}
return elems;
}
std::vector<std::string> split(std::string const s, char delim)
{
std::vector<std::string> elems;
return split(s, delim, elems);
}
#endif

44
src/LazyCalculatedValue.h Normal file
View File

@ -0,0 +1,44 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#ifndef _PLAYERBOT_LAZYCALCULATEDVALUE_H
#define _PLAYERBOT_LAZYCALCULATEDVALUE_H
template <class TValue, class TOwner>
class LazyCalculatedValue
{
public:
typedef TValue (TOwner::*Calculator)();
public:
LazyCalculatedValue(TOwner* owner, Calculator calculator) : calculator(calculator), owner(owner)
{
Reset();
}
public:
TValue GetValue()
{
if (!calculated)
{
value = (owner->*calculator)();
calculated = true;
}
return value;
}
void Reset()
{
calculated = false;
}
protected:
Calculator calculator;
TOwner* owner;
bool calculated;
TValue value;
};
#endif

247
src/LootObjectStack.cpp Normal file
View File

@ -0,0 +1,247 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#include "LootObjectStack.h"
#include "LootMgr.h"
#include "Playerbots.h"
#define MAX_LOOT_OBJECT_COUNT 10
LootTarget::LootTarget(ObjectGuid guid) : guid(guid), asOfTime(time(nullptr))
{
}
LootTarget::LootTarget(LootTarget const& other)
{
guid = other.guid;
asOfTime = other.asOfTime;
}
LootTarget& LootTarget::operator=(LootTarget const& other)
{
if ((void*)this == (void*)&other)
return *this;
guid = other.guid;
asOfTime = other.asOfTime;
return *this;
}
bool LootTarget::operator<(LootTarget const& other) const
{
return guid < other.guid;
}
void LootTargetList::shrink(time_t fromTime)
{
for (std::set<LootTarget>::iterator i = begin(); i != end(); )
{
if (i->asOfTime <= fromTime)
erase(i++);
else
++i;
}
}
LootObject::LootObject(Player* bot, ObjectGuid guid) : guid(), skillId(SKILL_NONE), reqSkillValue(0), reqItem(0)
{
Refresh(bot, guid);
}
void LootObject::Refresh(Player* bot, ObjectGuid lootGUID)
{
skillId = SKILL_NONE;
reqSkillValue = 0;
reqItem = 0;
guid.Clear();
PlayerbotAI* botAI = GET_PLAYERBOT_AI(bot);
Creature* creature = botAI->GetCreature(lootGUID);
if (creature && creature->getDeathState() == CORPSE)
{
if (creature->HasFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE))
guid = lootGUID;
if (creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE))
{
skillId = creature->GetCreatureTemplate()->GetRequiredLootSkill();
uint32 targetLevel = creature->getLevel();
reqSkillValue = targetLevel < 10 ? 1 : targetLevel < 20 ? (targetLevel - 10) * 10 : targetLevel * 5;
if (botAI->HasSkill((SkillType) skillId) && bot->GetSkillValue(skillId) >= reqSkillValue)
guid = lootGUID;
}
return;
}
GameObject* go = botAI->GetGameObject(lootGUID);
if (go && go->isSpawned() && go->GetGoState() == GO_STATE_READY)
{
uint32 lockId = go->GetGOInfo()->GetLockId();
LockEntry const* lockInfo = sLockStore.LookupEntry(lockId);
if (!lockInfo)
return;
for (uint8 i = 0; i < 8; ++i)
{
switch (lockInfo->Type[i])
{
case LOCK_KEY_ITEM:
if (lockInfo->Index[i] > 0)
{
reqItem = lockInfo->Index[i];
guid = lootGUID;
}
break;
case LOCK_KEY_SKILL:
if (SkillByLockType(LockType(lockInfo->Index[i])) > 0)
{
skillId = SkillByLockType(LockType(lockInfo->Index[i]));
reqSkillValue = std::max((uint32)1, lockInfo->Skill[i]);
guid = lootGUID;
}
break;
case LOCK_KEY_NONE:
guid = lootGUID;
break;
}
}
}
}
WorldObject* LootObject::GetWorldObject(Player* bot)
{
Refresh(bot, guid);
PlayerbotAI* botAI = GET_PLAYERBOT_AI(bot);
Creature* creature = botAI->GetCreature(guid);
if (creature && creature->getDeathState() == CORPSE)
return creature;
GameObject* go = botAI->GetGameObject(guid);
if (go && go->isSpawned())
return go;
return nullptr;
}
LootObject::LootObject(LootObject const& other)
{
guid = other.guid;
skillId = other.skillId;
reqSkillValue = other.reqSkillValue;
reqItem = other.reqItem;
}
bool LootObject::IsLootPossible(Player* bot)
{
if (IsEmpty() || !GetWorldObject(bot))
return false;
PlayerbotAI* botAI = GET_PLAYERBOT_AI(bot);
if (reqItem && !bot->HasItemCount(reqItem, 1))
return false;
if (abs(GetWorldObject(bot)->GetPositionZ() - bot->GetPositionZ()) > INTERACTION_DISTANCE)
return false;
Creature* creature = botAI->GetCreature(guid);
if (creature && creature->getDeathState() == CORPSE)
{
if (!creature->loot.hasItemFor(bot) && skillId != SKILL_SKINNING)
return false;
}
if (skillId == SKILL_NONE)
return true;
if (skillId == SKILL_FISHING)
return false;
if (!botAI->HasSkill((SkillType)skillId))
return false;
if (!reqSkillValue)
return true;
uint32 skillValue = uint32(bot->GetSkillValue(skillId));
if (reqSkillValue > skillValue)
return false;
if (skillId == SKILL_MINING && !bot->HasItemCount(2901, 1))
return false;
if (skillId == SKILL_SKINNING && !bot->HasItemCount(7005, 1))
return false;
return true;
}
bool LootObjectStack::Add(ObjectGuid guid)
{
if (!availableLoot.insert(guid).second)
return false;
if (availableLoot.size() < MAX_LOOT_OBJECT_COUNT)
return true;
std::vector<LootObject> ordered = OrderByDistance();
for (size_t i = MAX_LOOT_OBJECT_COUNT; i < ordered.size(); i++)
Remove(ordered[i].guid);
return true;
}
void LootObjectStack::Remove(ObjectGuid guid)
{
LootTargetList::iterator i = availableLoot.find(guid);
if (i != availableLoot.end())
availableLoot.erase(i);
}
void LootObjectStack::Clear()
{
availableLoot.clear();
}
bool LootObjectStack::CanLoot(float maxDistance)
{
std::vector<LootObject> ordered = OrderByDistance(maxDistance);
return !ordered.empty();
}
LootObject LootObjectStack::GetLoot(float maxDistance)
{
std::vector<LootObject> ordered = OrderByDistance(maxDistance);
return ordered.empty() ? LootObject() : *ordered.begin();
}
std::vector<LootObject> LootObjectStack::OrderByDistance(float maxDistance)
{
availableLoot.shrink(time(nullptr) - 30);
std::map<float, LootObject> sortedMap;
LootTargetList safeCopy(availableLoot);
for (LootTargetList::iterator i = safeCopy.begin(); i != safeCopy.end(); i++)
{
ObjectGuid guid = i->guid;
LootObject lootObject(bot, guid);
if (!lootObject.IsLootPossible(bot))
continue;
float distance = bot->GetDistance(lootObject.GetWorldObject(bot));
if (!maxDistance || distance <= maxDistance)
sortedMap[distance] = lootObject;
}
std::vector<LootObject> result;
for (std::map<float, LootObject>::iterator i = sortedMap.begin(); i != sortedMap.end(); i++)
result.push_back(i->second);
return result;
}

82
src/LootObjectStack.h Normal file
View File

@ -0,0 +1,82 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#ifndef _PLAYERBOT_LOOTOBJECTSTACK_H
#define _PLAYERBOT_LOOTOBJECTSTACK_H
#include "ObjectGuid.h"
class AiObjectContext;
class Player;
class WorldObject;
struct ItemTemplate;
class LootStrategy
{
public:
LootStrategy() { }
virtual ~LootStrategy() { };
virtual bool CanLoot(ItemTemplate const* proto, AiObjectContext* context) = 0;
virtual std::string const GetName() = 0;
};
class LootObject
{
public:
LootObject() : skillId(0), reqSkillValue(0), reqItem(0) { }
LootObject(Player* bot, ObjectGuid guid);
LootObject(LootObject const& other);
bool IsEmpty() { return !guid; }
bool IsLootPossible(Player* bot);
void Refresh(Player* bot, ObjectGuid guid);
WorldObject* GetWorldObject(Player* bot);
ObjectGuid guid;
uint32 skillId;
uint32 reqSkillValue;
uint32 reqItem;
};
class LootTarget
{
public:
LootTarget(ObjectGuid guid);
LootTarget(LootTarget const& other);
public:
LootTarget& operator=(LootTarget const& other);
bool operator<(LootTarget const& other) const;
public:
ObjectGuid guid;
time_t asOfTime;
};
class LootTargetList : public std::set<LootTarget>
{
public:
void shrink(time_t fromTime);
};
class LootObjectStack
{
public:
LootObjectStack(Player* bot) : bot(bot) { }
bool Add(ObjectGuid guid);
void Remove(ObjectGuid guid);
void Clear();
bool CanLoot(float maxDistance);
LootObject GetLoot(float maxDistance = 0);
private:
std::vector<LootObject> OrderByDistance(float maxDistance = 0);
Player* bot;
LootTargetList availableLoot;
};
#endif

View File

@ -1,15 +0,0 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
*/
// From SC
void AddMyPlayerScripts();
// Add all
// cf. the naming convention https://github.com/azerothcore/azerothcore-wotlk/blob/master/doc/changelog/master.md#how-to-upgrade-4
// additionally replace all '-' in the module folder name with '_' here
void Addskeleton_moduleScripts()
{
AddMyPlayerScripts();
}

View File

@ -1,29 +0,0 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
*/
#include "ScriptMgr.h"
#include "Player.h"
#include "Config.h"
#include "Chat.h"
// Add player scripts
class MyPlayer : public PlayerScript
{
public:
MyPlayer() : PlayerScript("MyPlayer") { }
void OnLogin(Player* player) override
{
if (sConfigMgr->GetOption<bool>("MyModule.Enable", false))
{
ChatHandler(player->GetSession()).SendSysMessage("Hello World from Skeleton-Module!");
}
}
};
// Add all scripts in one
void AddMyPlayerScripts()
{
new MyPlayer();
}

257
src/PerformanceMonitor.cpp Normal file
View File

@ -0,0 +1,257 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#include "PerformanceMonitor.h"
#include "Playerbots.h"
PerformanceMonitorOperation* PerformanceMonitor::start(PerformanceMetric metric, std::string const name, PerformanceStack* stack)
{
if (!sPlayerbotAIConfig->perfMonEnabled)
return nullptr;
std::string stackName = name;
if (stack)
{
if (!stack->empty())
{
std::ostringstream out;
out << stackName << " [";
for (std::vector<std::string>::reverse_iterator i = stack->rbegin(); i != stack->rend(); ++i)
out << *i << (std::next(i) == stack->rend() ? "" : "|");
out << "]";
stackName = out.str().c_str();
}
stack->push_back(name);
}
std::lock_guard<std::mutex> guard(lock);
PerformanceData* pd = data[metric][stackName];
if (!pd)
{
pd = new PerformanceData();
pd->minTime = 0;
pd->maxTime = 0;
pd->totalTime = 0;
pd->count = 0;
data[metric][stackName] = pd;
}
return new PerformanceMonitorOperation(pd, name, stack);
}
void PerformanceMonitor::PrintStats(bool perTick, bool fullStack)
{
if (data.empty())
return;
uint32 total = 0;
if (!perTick)
{
for (auto& map : data[PERF_MON_TOTAL])
if (map.first.find("PlayerbotAI::UpdateAIInternal") != std::string::npos)
total += map.second->totalTime;
LOG_INFO("playerbots", "--------------------------------------[TOTAL BOT]------------------------------------------------------");
LOG_INFO("playerbots", "percentage time | min .. max ( avg of count ) - type : name ");
for (std::map<PerformanceMetric, std::map<std::string, PerformanceData*>>::iterator i = data.begin(); i != data.end(); ++i)
{
std::map<std::string, PerformanceData*> pdMap = i->second;
std::string key;
switch (i->first)
{
case PERF_MON_TRIGGER:
key = "T";
break;
case PERF_MON_VALUE:
key = "V";
break;
case PERF_MON_ACTION:
key = "A";
break;
case PERF_MON_RNDBOT:
key = "RndBot";
break;
case PERF_MON_TOTAL:
key = "Total";
break;
default:
key = "?";
break;
}
std::vector<std::string> names;
for (std::map<std::string, PerformanceData*>::iterator j = pdMap.begin(); j != pdMap.end(); ++j)
{
if (key == "Total" && j->first.find("PlayerbotAI::UpdateAIInternal") == std::string::npos)
continue;
names.push_back(j->first);
}
std::sort(names.begin(), names.end(), [pdMap](std::string const i, std::string const j)
{
return pdMap.at(i)->totalTime < pdMap.at(j)->totalTime;
});
for (auto& name : names)
{
PerformanceData* pd = pdMap[name];
float perc = (float)pd->totalTime / (float)total * 100.0f;
float secs = (float)pd->totalTime / 1000.0f;
float avg = (float)pd->totalTime / (float)pd->count;
std::string disName = name;
if (!fullStack && disName.find("|") != std::string::npos)
disName = disName.substr(0, disName.find("|")) + "]";
if (avg >= 0.5f || pd->maxTime > 10)
{
LOG_INFO("playerbots", "%7.3f%% %10.3fs | %6u .. %6u (%9.4f of %10u) - {} : {}"
, perc
, secs
, pd->minTime
, pd->maxTime
, avg
, pd->count
, key.c_str()
, disName.c_str());
}
}
LOG_INFO("playerbots", " ");
}
}
else
{
float totalCount = data[PERF_MON_TOTAL]["RandomPlayerbotMgr::FullTick"]->count;
total = data[PERF_MON_TOTAL]["RandomPlayerbotMgr::FullTick"]->totalTime;
LOG_INFO("playerbots", " ");
LOG_INFO("playerbots", " ");
LOG_INFO("playerbots", "---------------------------------------[PER TICK]------------------------------------------------------");
LOG_INFO("playerbots", "percentage time | min .. max ( avg of count ) - type : name ");
for (std::map<PerformanceMetric, std::map<std::string, PerformanceData*>>::iterator i = data.begin(); i != data.end(); ++i)
{
std::map<std::string, PerformanceData*> pdMap = i->second;
std::string key;
switch (i->first)
{
case PERF_MON_TRIGGER:
key = "T";
break;
case PERF_MON_VALUE:
key = "V";
break;
case PERF_MON_ACTION:
key = "A";
break;
case PERF_MON_RNDBOT:
key = "RndBot";
break;
case PERF_MON_TOTAL:
key = "Total";
break;
default:
key = "?";
}
std::vector<std::string> names;
for (std::map<std::string, PerformanceData*>::iterator j = pdMap.begin(); j != pdMap.end(); ++j)
{
names.push_back(j->first);
}
std::sort(names.begin(), names.end(), [pdMap](std::string const i, std::string const j)
{
return pdMap.at(i)->totalTime < pdMap.at(j)->totalTime;
});
for (auto& name : names)
{
PerformanceData* pd = pdMap[name];
float perc = (float)pd->totalTime / (float)total * 100.0f;
uint32 secs = pd->totalTime / totalCount;
float avg = (float)pd->totalTime / (float)pd->count;
float amount = (float)pd->count / (float)totalCount;
std::string disName = name;
if (!fullStack && disName.find("|") != std::string::npos)
disName = disName.substr(0, disName.find("|")) + "]";
if (avg >= 0.5f || pd->maxTime > 10)
{
LOG_INFO("playerbots", "%7.3f%% %9ums | %6u .. %6u (%9.4f of %10.3f) - {} : {}"
, perc
, secs
, pd->minTime
, pd->maxTime
, avg
, amount
, key.c_str()
, disName.c_str());
}
}
LOG_INFO("playerbots", " ");
}
}
}
void PerformanceMonitor::Reset()
{
for (std::map<PerformanceMetric, std::map<std::string, PerformanceData*> >::iterator i = data.begin(); i != data.end(); ++i)
{
std::map<std::string, PerformanceData*> pdMap = i->second;
for (std::map<std::string, PerformanceData*>::iterator j = pdMap.begin(); j != pdMap.end(); ++j)
{
PerformanceData* pd = j->second;
std::lock_guard<std::mutex> guard(pd->lock);
pd->minTime = 0;
pd->maxTime = 0;
pd->totalTime = 0;
pd->count = 0;
}
}
}
PerformanceMonitorOperation::PerformanceMonitorOperation(PerformanceData* data, std::string const name, PerformanceStack* stack) : data(data), name(name), stack(stack)
{
started = (std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now())).time_since_epoch();
}
void PerformanceMonitorOperation::finish()
{
std::chrono::milliseconds finished = (std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now())).time_since_epoch();
uint32 elapsed = (finished - started).count();
std::lock_guard<std::mutex> guard(data->lock);
if (elapsed > 0)
{
if (!data->minTime || data->minTime > elapsed)
data->minTime = elapsed;
if (!data->maxTime || data->maxTime < elapsed)
data->maxTime = elapsed;
data->totalTime += elapsed;
}
++data->count;
if (stack)
{
stack->erase(std::remove(stack->begin(), stack->end(), name), stack->end());
}
delete this;
}

72
src/PerformanceMonitor.h Normal file
View File

@ -0,0 +1,72 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#ifndef _PLAYERBOT_PERFORMANCEMONITOR_H
#define _PLAYERBOT_PERFORMANCEMONITOR_H
#include "Common.h"
#include <chrono>
#include <ctime>
#include <map>
#include <mutex>
#include <vector>
typedef std::vector<std::string> PerformanceStack;
struct PerformanceData
{
uint32 minTime;
uint32 maxTime;
uint32 totalTime;
uint32 count;
std::mutex lock;
};
enum PerformanceMetric
{
PERF_MON_TRIGGER,
PERF_MON_VALUE,
PERF_MON_ACTION,
PERF_MON_RNDBOT,
PERF_MON_TOTAL
};
class PerformanceMonitorOperation
{
public:
PerformanceMonitorOperation(PerformanceData* data, std::string const name, PerformanceStack* stack);
void finish();
private:
PerformanceData* data;
std::string const name;
PerformanceStack* stack;
std::chrono::milliseconds started;
};
class PerformanceMonitor
{
public:
PerformanceMonitor() { };
virtual ~PerformanceMonitor() { };
static PerformanceMonitor* instance()
{
static PerformanceMonitor instance;
return &instance;
}
public:
PerformanceMonitorOperation* start(PerformanceMetric metric, std::string const name, PerformanceStack* stack = nullptr);
void PrintStats(bool perTick = false, bool fullStack = false);
void Reset();
private:
std::map<PerformanceMetric, std::map<std::string, PerformanceData*> > data;
std::mutex lock;
};
#define sPerformanceMonitor PerformanceMonitor::instance()
#endif

3408
src/PlayerbotAI.cpp Normal file

File diff suppressed because it is too large Load Diff

392
src/PlayerbotAI.h Normal file
View File

@ -0,0 +1,392 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#ifndef _PLAYERBOT_PLAYERbotAI_H
#define _PLAYERBOT_PLAYERbotAI_H
#include "Chat.h"
#include "ChatHelper.h"
#include "ChatFilter.h"
#include "Common.h"
#include "Event.h"
#include "PlayerbotAIBase.h"
#include "PlayerbotAIConfig.h"
#include "PlayerbotSecurity.h"
#include "WorldPacket.h"
#include <stack>
#include <queue>
class AiObjectContext;
class Creature;
class Engine;
class ExternalEventHelper;
class Gameobject;
class Item;
class ObjectGuid;
class Player;
class PlayerbotMgr;
class Spell;
class SpellInfo;
class Unit;
class WorldObject;
class WorldPosition;
struct CreatureData;
struct GameObjectData;
enum StrategyType : uint32;
enum HealingItemDisplayId
{
HEALTHSTONE_DISPLAYID = 8026,
MAJOR_HEALING_POTION = 24152,
WHIPPER_ROOT_TUBER = 21974,
NIGHT_DRAGON_BREATH = 21975,
LIMITED_INVULNERABILITY_POTION = 24213,
GREATER_DREAMLESS_SLEEP_POTION = 17403,
SUPERIOR_HEALING_POTION = 15714,
CRYSTAL_RESTORE = 2516,
DREAMLESS_SLEEP_POTION = 17403,
GREATER_HEALING_POTION = 15713,
HEALING_POTION = 15712,
LESSER_HEALING_POTION = 15711,
DISCOLORED_HEALING_POTION = 15736,
MINOR_HEALING_POTION = 15710,
VOLATILE_HEALING_POTION = 24212,
SUPER_HEALING_POTION = 37807,
CRYSTAL_HEALING_POTION = 47132,
FEL_REGENERATION_POTION = 37864,
MAJOR_DREAMLESS_SLEEP_POTION = 37845
};
enum BotState
{
BOT_STATE_COMBAT = 0,
BOT_STATE_NON_COMBAT = 1,
BOT_STATE_DEAD = 2,
BOT_STATE_MAX
};
bool IsAlliance(uint8 race);
class PlayerbotChatHandler: protected ChatHandler
{
public:
explicit PlayerbotChatHandler(Player* pMasterPlayer);
void sysmessage(std::string const str) { SendSysMessage(str.c_str()); }
uint32 extractQuestId(std::string const str);
uint32 extractSpellId(std::string const str)
{
char* source = (char*)str.c_str();
return extractSpellIdFromLink(source);
}
};
class MinValueCalculator
{
public:
MinValueCalculator(float def = 0.0f) : param(nullptr), minValue(def) { }
void probe(float value, void* p)
{
if (!param || minValue >= value)
{
minValue = value;
param = p;
}
}
void* param;
float minValue;
};
enum RoguePoisonDisplayId
{
DEADLY_POISON_DISPLAYID = 13707,
INSTANT_POISON_DISPLAYID = 13710,
WOUND_POISON_DISPLAYID = 37278
};
enum SharpeningStoneDisplayId
{
ROUGH_SHARPENING_DISPLAYID = 24673,
COARSE_SHARPENING_DISPLAYID = 24674,
HEAVY_SHARPENING_DISPLAYID = 24675,
SOLID_SHARPENING_DISPLAYID = 24676,
DENSE_SHARPENING_DISPLAYID = 24677,
CONSECRATED_SHARPENING_DISPLAYID = 24674, // will not be used because bot can not know if it will face undead targets
ELEMENTAL_SHARPENING_DISPLAYID = 21072,
FEL_SHARPENING_DISPLAYID = 39192,
ADAMANTITE_SHARPENING_DISPLAYID = 39193
};
enum WeightStoneDisplayId
{
ROUGH_WEIGHTSTONE_DISPLAYID = 24683,
COARSE_WEIGHTSTONE_DISPLAYID = 24684,
HEAVY_WEIGHTSTONE_DISPLAYID = 24685,
SOLID_WEIGHTSTONE_DISPLAYID = 24686,
DENSE_WEIGHTSTONE_DISPLAYID = 24687,
FEL_WEIGHTSTONE_DISPLAYID = 39548,
ADAMANTITE_WEIGHTSTONE_DISPLAYID = 39549
};
enum WizardOilDisplayId
{
MINOR_WIZARD_OIL = 9731,
LESSER_WIZARD_OIL = 47903,
BRILLIANT_WIZARD_OIL = 47901,
WIZARD_OIL = 47905,
SUPERIOR_WIZARD_OIL = 47904,
/// Blessed Wizard Oil = 26865 //scourge inv
};
enum ManaOilDisplayId
{
MINOR_MANA_OIL = 34492,
LESSER_MANA_OIL = 47902,
BRILLIANT_MANA_OIL = 41488,
SUPERIOR_MANA_OIL = 36862
};
enum ShieldWardDisplayId
{
LESSER_WARD_OFSHIELDING = 38759,
GREATER_WARD_OFSHIELDING = 38760
};
enum class BotTypeNumber : uint8
{
ACTIVITY_TYPE_NUMBER = 1,
GROUPER_TYPE_NUMBER = 2,
GUILDER_TYPE_NUMBER = 3,
};
enum class GrouperType : uint8
{
SOLO = 0,
MEMBER = 1,
LEADER_2 = 2,
LEADER_3 = 3,
LEADER_4 = 4,
LEADER_5 = 5
};
enum class GuilderType : uint8
{
SOLO = 0,
TINY = 30,
SMALL = 50,
MEDIUM = 70,
LARGE = 120,
HUGE = 250
};
enum ActivityType
{
GRIND_ACTIVITY = 1,
RPG_ACTIVITY = 2,
TRAVEL_ACTIVITY = 3,
OUT_OF_PARTY_ACTIVITY = 4,
PACKET_ACTIVITY = 5,
DETAILED_MOVE_ACTIVITY = 6,
PARTY_ACTIVITY = 7,
ALL_ACTIVITY = 8,
MAX_ACTIVITY_TYPE
};
enum BotRoles : uint8
{
BOT_ROLE_NONE = 0x00,
BOT_ROLE_TANK = 0x01,
BOT_ROLE_HEALER = 0x02,
BOT_ROLE_DPS = 0x04
};
class PacketHandlingHelper
{
public:
void AddHandler(uint16 opcode, std::string const handler);
void Handle(ExternalEventHelper &helper);
void AddPacket(WorldPacket const& packet);
private:
std::map<uint16, std::string> handlers;
std::stack<WorldPacket> queue;
};
class ChatCommandHolder
{
public:
ChatCommandHolder(std::string const command, Player* owner = nullptr, uint32 type = CHAT_MSG_WHISPER, time_t time = 0) : command(command), owner(owner), type(type), time(time) { }
ChatCommandHolder(ChatCommandHolder const& other) : command(other.command), owner(other.owner), type(other.type), time(other.time) { }
std::string const GetCommand() { return command; }
Player* GetOwner() { return owner; }
uint32 GetType() { return type; }
time_t GetTime() { return time; }
private:
std::string const command;
Player* owner;
uint32 type;
time_t time;
};
class PlayerbotAI : public PlayerbotAIBase
{
public:
PlayerbotAI();
PlayerbotAI(Player* bot);
virtual ~PlayerbotAI();
void UpdateAI(uint32 elapsed, bool minimal = false) override;
void UpdateAIInternal(uint32 elapsed, bool minimal = false) override;
std::string const HandleRemoteCommand(std::string const command);
void HandleCommand(uint32 type, std::string const text, Player* fromPlayer);
void HandleBotOutgoingPacket(WorldPacket const& packet);
void HandleMasterIncomingPacket(WorldPacket const& packet);
void HandleMasterOutgoingPacket(WorldPacket const& packet);
void HandleTeleportAck();
void ChangeEngine(BotState type);
void DoNextAction(bool minimal = false);
virtual bool DoSpecificAction(std::string const name, Event event = Event(), bool silent = false, std::string const qualifier = "");
void ChangeStrategy(std::string const name, BotState type);
void ClearStrategies(BotState type);
std::vector<std::string> GetStrategies(BotState type);
bool ContainsStrategy(StrategyType type);
bool HasStrategy(std::string const name, BotState type);
BotState GetState() { return currentState; };
void ResetStrategies(bool load = true);
void ReInitCurrentEngine();
void Reset(bool full = false);
bool IsTank(Player* player);
bool IsHeal(Player* player);
bool IsRanged(Player* player);
Creature* GetCreature(ObjectGuid guid);
Unit* GetUnit(ObjectGuid guid);
Player* GetPlayer(ObjectGuid guid);
static Unit* GetUnit(CreatureData const* creatureData);
GameObject* GetGameObject(ObjectGuid guid);
static GameObject* GetGameObject(GameObjectData const* gameObjectData);
WorldObject* GetWorldObject(ObjectGuid guid);
bool TellMaster(std::ostringstream& stream, PlayerbotSecurityLevel securityLevel = PLAYERBOT_SECURITY_ALLOW_ALL);
bool TellMaster(std::string const text, PlayerbotSecurityLevel securityLevel = PLAYERBOT_SECURITY_ALLOW_ALL);
bool TellMasterNoFacing(std::ostringstream& stream, PlayerbotSecurityLevel securityLevel = PLAYERBOT_SECURITY_ALLOW_ALL);
bool TellMasterNoFacing(std::string const text, PlayerbotSecurityLevel securityLevel = PLAYERBOT_SECURITY_ALLOW_ALL);
bool TellError(std::string const text, PlayerbotSecurityLevel securityLevel = PLAYERBOT_SECURITY_ALLOW_ALL);
void SpellInterrupted(uint32 spellid);
int32 CalculateGlobalCooldown(uint32 spellid);
void InterruptSpell();
void RemoveAura(std::string const name);
void RemoveShapeshift();
void WaitForSpellCast(Spell* spell);
bool PlaySound(uint32 emote);
bool PlayEmote(uint32 emote);
void Ping(float x, float y);
Item* FindPoison() const;
Item* FindBandage() const;
Item* FindConsumable(uint32 displayId) const;
Item* FindStoneFor(Item* weapon) const;
Item* FindOilFor(Item* weapon) const;
void ImbueItem(Item* item, uint32 targetFlag, ObjectGuid targetGUID);
void ImbueItem(Item* item, uint8 targetInventorySlot);
void ImbueItem(Item* item, Unit* target);
void ImbueItem(Item* item);
void EnchantItemT(uint32 spellid, uint8 slot);
uint32 GetBuffedCount(Player* player, std::string const spellname);
virtual bool CanCastSpell(std::string const name, Unit* target, Item* itemTarget = nullptr);
virtual bool CastSpell(std::string const name, Unit* target, Item* itemTarget = nullptr);
virtual bool HasAura(std::string const spellName, Unit* player, bool maxStack = false);
virtual bool HasAnyAuraOf(Unit* player, ...);
virtual bool IsInterruptableSpellCasting(Unit* player, std::string const spell);
virtual bool HasAuraToDispel(Unit* player, uint32 dispelType);
bool CanCastSpell(uint32 spellid, Unit* target, bool checkHasSpell = true, Item* itemTarget = nullptr);
bool CanCastSpell(uint32 spellid, GameObject* goTarget, uint8 effectMask, bool checkHasSpell = true);
bool CanCastSpell(uint32 spellid, float x, float y, float z, uint8 effectMask, bool checkHasSpell = true, Item* itemTarget = nullptr);
bool HasAura(uint32 spellId, Unit const* player);
bool CastSpell(uint32 spellId, Unit* target, Item* itemTarget = nullptr);
bool CastSpell(uint32 spellId, float x, float y, float z, Item* itemTarget = nullptr);
bool canDispel(SpellInfo const* spellInfo, uint32 dispelType);
bool CanCastVehicleSpell(uint32 spellid, Unit* target);
bool CastVehicleSpell(uint32 spellId, Unit* target);
bool CastVehicleSpell(uint32 spellId, float x, float y, float z);
bool IsInVehicle(bool canControl = false, bool canCast = false, bool canAttack = false, bool canTurn = false, bool fixed = false);
uint32 GetEquipGearScore(Player* player, bool withBags, bool withBank);
bool HasSkill(SkillType skill);
bool IsAllowedCommand(std::string const text);
float GetRange(std::string const type);
Player* GetBot() { return bot; }
Player* GetMaster() { return master; }
//Checks if the bot is really a player. Players always have themselves as master.
bool IsRealPlayer() { return master ? (master == bot) : false; }
//Bot has a master that is a player.
bool HasRealPlayerMaster();
//Bot has a master that is activly playing.
bool HasActivePlayerMaster();
//Get the group leader or the master of the bot.
//Checks if the bot is summoned as alt of a player
bool IsAlt();
Player* GetGroupMaster();
//Returns a semi-random (cycling) number that is fixed for each bot.
uint32 GetFixedBotNumer(BotTypeNumber typeNumber, uint32 maxNum = 100, float cyclePerMin = 1);
GrouperType GetGrouperType();
GuilderType GetGuilderType();
bool HasPlayerNearby(WorldPosition* pos, float range = sPlayerbotAIConfig->reactDistance);
bool HasPlayerNearby(float range = sPlayerbotAIConfig->reactDistance);
bool HasManyPlayersNearby(uint32 trigerrValue = 20, float range = sPlayerbotAIConfig->sightDistance);
bool AllowActive(ActivityType activityType);
bool AllowActivity(ActivityType activityType = ALL_ACTIVITY, bool checkNow = false);
bool HasCheat(BotCheatMask mask) { return ((uint32)mask & (uint32)cheatMask) != 0 || ((uint32)mask & (uint32)sPlayerbotAIConfig->botCheatMask) != 0; }
BotCheatMask GetCheat() { return cheatMask; }
void SetCheat(BotCheatMask mask) { cheatMask = mask; }
void SetMaster(Player* newMaster) { master = newMaster; }
AiObjectContext* GetAiObjectContext() { return aiObjectContext; }
ChatHelper* GetChatHelper() { return &chatHelper; }
bool IsOpposing(Player* player);
static bool IsOpposing(uint8 race1, uint8 race2);
PlayerbotSecurity* GetSecurity() { return &security; }
private:
void _fillGearScoreData(Player* player, Item* item, std::vector<uint32>* gearScore, uint32& twoHandScore);
bool IsTellAllowed(PlayerbotSecurityLevel securityLevel = PLAYERBOT_SECURITY_ALLOW_ALL);
protected:
Player* bot;
Player* master;
uint32 accountId;
AiObjectContext* aiObjectContext;
Engine* currentEngine;
Engine* engines[BOT_STATE_MAX];
BotState currentState;
ChatHelper chatHelper;
std::queue<ChatCommandHolder> chatCommands;
PacketHandlingHelper botOutgoingPacketHandlers;
PacketHandlingHelper masterIncomingPacketHandlers;
PacketHandlingHelper masterOutgoingPacketHandlers;
CompositeChatFilter chatFilter;
PlayerbotSecurity security;
std::map<std::string, time_t> whispers;
std::pair<ChatMsg, time_t> currentChat;
static std::set<std::string> unsecuredCommands;
bool allowActive[MAX_ACTIVITY_TYPE];
time_t allowActiveCheckTimer[MAX_ACTIVITY_TYPE];
bool inCombat = false;
BotCheatMask cheatMask = BotCheatMask::none;
};
#endif

19
src/PlayerbotAIAware.h Normal file
View File

@ -0,0 +1,19 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#ifndef _PLAYERBOT_PLAYERbotAIAWARE_H
#define _PLAYERBOT_PLAYERbotAIAWARE_H
class PlayerbotAI;
class PlayerbotAIAware
{
public:
PlayerbotAIAware(PlayerbotAI* botAI) : botAI(botAI) { }
protected:
PlayerbotAI* botAI;
};
#endif

67
src/PlayerbotAIBase.cpp Normal file
View File

@ -0,0 +1,67 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#include "PlayerbotAIBase.h"
#include "Playerbots.h"
PlayerbotAIBase::PlayerbotAIBase(bool isBotAI) : nextAICheckDelay(0), _isBotAI(isBotAI)
{
}
void PlayerbotAIBase::UpdateAI(uint32 elapsed, bool minimal)
{
if (nextAICheckDelay > elapsed)
nextAICheckDelay -= elapsed;
else
nextAICheckDelay = 0;
if (!CanUpdateAI())
return;
UpdateAIInternal(elapsed, minimal);
YieldThread();
}
void PlayerbotAIBase::SetNextCheckDelay(uint32 const delay)
{
if (nextAICheckDelay < delay)
LOG_DEBUG("playerbots", "Setting lesser delay {} -> {}", nextAICheckDelay, delay);
nextAICheckDelay = delay;
if (nextAICheckDelay > sPlayerbotAIConfig->globalCoolDown)
LOG_DEBUG("playerbots", "std::set next check delay: {}", nextAICheckDelay);
}
void PlayerbotAIBase::IncreaseNextCheckDelay(uint32 delay)
{
nextAICheckDelay += delay;
if (nextAICheckDelay > sPlayerbotAIConfig->globalCoolDown)
LOG_DEBUG("playerbots", "increase next check delay: {}", nextAICheckDelay);
}
bool PlayerbotAIBase::CanUpdateAI()
{
return nextAICheckDelay < 100;
}
void PlayerbotAIBase::YieldThread(bool delay)
{
if (nextAICheckDelay < sPlayerbotAIConfig->reactDelay)
nextAICheckDelay = sPlayerbotAIConfig->reactDelay;
if (delay && nextAICheckDelay <= sPlayerbotAIConfig->reactDelay * 5)
nextAICheckDelay = sPlayerbotAIConfig->reactDelay * 5;
}
bool PlayerbotAIBase::IsActive()
{
return nextAICheckDelay < sPlayerbotAIConfig->maxWaitForMove;
}
bool PlayerbotAIBase::IsBotAI() const
{
return _isBotAI;
}

31
src/PlayerbotAIBase.h Normal file
View File

@ -0,0 +1,31 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#ifndef _PLAYERBOT_PLAYERBOTAIBASE_H
#define _PLAYERBOT_PLAYERBOTAIBASE_H
#include "Define.h"
class PlayerbotAIBase
{
public:
PlayerbotAIBase(bool isBotAI);
bool CanUpdateAI();
void SetNextCheckDelay(uint32 const delay);
void IncreaseNextCheckDelay(uint32 delay);
void YieldThread(bool delay = false);
virtual void UpdateAI(uint32 elapsed, bool minimal = false);
virtual void UpdateAIInternal(uint32 elapsed, bool minimal = false) = 0;
bool IsActive();
bool IsBotAI() const;
protected:
uint32 nextAICheckDelay;
private:
bool _isBotAI;
};
#endif

481
src/PlayerbotAIConfig.cpp Normal file
View File

@ -0,0 +1,481 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#include "PlayerbotAIConfig.h"
#include "Config.h"
#include "Playerbots.h"
#include "PlayerbotFactory.h"
#include "RandomItemMgr.h"
#include "RandomPlayerbotFactory.h"
#include "TalentSpec.h"
#include <iostream>
template <class T>
void LoadList(std::string const value, T& list)
{
std::vector<std::string> ids = split(value, ',');
for (std::vector<std::string>::iterator i = ids.begin(); i != ids.end(); i++)
{
uint32 id = atoi((*i).c_str());
if (!id)
continue;
list.push_back(id);
}
}
template <class T>
void LoadListString(std::string const value, T& list)
{
std::vector<std::string> strings = split(value, ',');
for (std::vector<std::string>::iterator i = strings.begin(); i != strings.end(); i++)
{
std::string const string = *i;
if (string.empty())
continue;
list.push_back(string);
}
}
bool PlayerbotAIConfig::Initialize()
{
LOG_INFO("server.loading", "Initializing AI Playerbots by ike3, based on the original Playerbots by blueboy");
enabled = sConfigMgr->GetBoolDefault("AiPlayerbot.Enabled", true);
if (!enabled)
{
LOG_INFO("server.loading", "AI Playerbots is Disabled in aiplayerbot.conf");
return false;
}
globalCoolDown = sConfigMgr->GetIntDefault("AiPlayerbot.GlobalCooldown", 1500);
maxWaitForMove = sConfigMgr->GetIntDefault("AiPlayerbot.MaxWaitForMove", 5000);
expireActionTime = sConfigMgr->GetIntDefault("AiPlayerbot.ExpireActionTime", 5000);
dispelAuraDuration = sConfigMgr->GetIntDefault("AiPlayerbot.DispelAuraDuration", 7000);
reactDelay = sConfigMgr->GetIntDefault("AiPlayerbot.ReactDelay", 500);
passiveDelay = sConfigMgr->GetIntDefault("AiPlayerbot.PassiveDelay", 10000);
repeatDelay = sConfigMgr->GetIntDefault("AiPlayerbot.RepeatDelay", 5000);
errorDelay = sConfigMgr->GetIntDefault("AiPlayerbot.ErrorDelay", 5000);
rpgDelay = sConfigMgr->GetIntDefault("AiPlayerbot.RpgDelay", 10000);
sitDelay = sConfigMgr->GetIntDefault("AiPlayerbot.SitDelay", 30000);
returnDelay = sConfigMgr->GetIntDefault("AiPlayerbot.ReturnDelay", 7000);
lootDelay = sConfigMgr->GetIntDefault("AiPlayerbot.LootDelay", 1000);
farDistance = sConfigMgr->GetFloatDefault("AiPlayerbot.FarDistance", 20.0f);
sightDistance = sConfigMgr->GetFloatDefault("AiPlayerbot.SightDistance", 75.0f);
spellDistance = sConfigMgr->GetFloatDefault("AiPlayerbot.SpellDistance", 22.0f);
shootDistance = sConfigMgr->GetFloatDefault("AiPlayerbot.ShootDistance", 25.0f);
healDistance = sConfigMgr->GetFloatDefault("AiPlayerbot.HealDistance", 20.0f);
lootDistance = sConfigMgr->GetFloatDefault("AiPlayerbot.LootDistance", 15.0f);
fleeDistance = sConfigMgr->GetFloatDefault("AiPlayerbot.FleeDistance", 7.5f);
aggroDistance = sConfigMgr->GetFloatDefault("AiPlayerbot.AggroDistance", 22.0f);
tooCloseDistance = sConfigMgr->GetFloatDefault("AiPlayerbot.TooCloseDistance", 5.0f);
meleeDistance = sConfigMgr->GetFloatDefault("AiPlayerbot.MeleeDistance", 1.5f);
followDistance = sConfigMgr->GetFloatDefault("AiPlayerbot.FollowDistance", 1.5f);
whisperDistance = sConfigMgr->GetFloatDefault("AiPlayerbot.WhisperDistance", 6000.0f);
contactDistance = sConfigMgr->GetFloatDefault("AiPlayerbot.ContactDistance", 0.5f);
aoeRadius = sConfigMgr->GetFloatDefault("AiPlayerbot.AoeRadius", 5.0f);
rpgDistance = sConfigMgr->GetFloatDefault("AiPlayerbot.RpgDistance", 200.0f);
grindDistance = sConfigMgr->GetFloatDefault("AiPlayerbot.GrindDistance", 75.0f);
reactDistance = sConfigMgr->GetFloatDefault("AiPlayerbot.ReactDistance", 150.0f);
criticalHealth = sConfigMgr->GetIntDefault("AiPlayerbot.CriticalHealth", 20);
lowHealth = sConfigMgr->GetIntDefault("AiPlayerbot.LowHealth", 45);
mediumHealth = sConfigMgr->GetIntDefault("AiPlayerbot.MediumHealth", 65);
almostFullHealth = sConfigMgr->GetIntDefault("AiPlayerbot.AlmostFullHealth", 85);
lowMana = sConfigMgr->GetIntDefault("AiPlayerbot.LowMana", 15);
mediumMana = sConfigMgr->GetIntDefault("AiPlayerbot.MediumMana", 40);
randomGearLoweringChance = sConfigMgr->GetFloatDefault("AiPlayerbot.RandomGearLoweringChance", 0.15f);
randomBotMaxLevelChance = sConfigMgr->GetFloatDefault("AiPlayerbot.RandomBotMaxLevelChance", 0.15f);
randomBotRpgChance = sConfigMgr->GetFloatDefault("AiPlayerbot.RandomBotRpgChance", 0.20f);
iterationsPerTick = sConfigMgr->GetIntDefault("AiPlayerbot.IterationsPerTick", 100);
allowGuildBots = sConfigMgr->GetBoolDefault("AiPlayerbot.AllowGuildBots", true);
randomBotMapsAsString = sConfigMgr->GetStringDefault("AiPlayerbot.RandomBotMaps", "0,1,530,571");
LoadList<std::vector<uint32>>(randomBotMapsAsString, randomBotMaps);
LoadList<std::vector<uint32>>(sConfigMgr->GetStringDefault("AiPlayerbot.RandomBotQuestItems", "6948,5175,5176,5177,5178,16309,12382,13704,11000"), randomBotQuestItems);
LoadList<std::vector<uint32>>(sConfigMgr->GetStringDefault("AiPlayerbot.RandomBotSpellIds", "1"), randomBotSpellIds);
LoadList<std::vector<uint32>>(sConfigMgr->GetStringDefault("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"), pvpProhibitedZoneIds);
LoadList<std::vector<uint32>>(sConfigMgr->GetStringDefault("AiPlayerbot.RandomBotQuestIds", "7848,3802,5505,6502,7761"), randomBotQuestIds);
botAutologin = sConfigMgr->GetBoolDefault("AiPlayerbot.BotAutologin", false);
randomBotAutologin = sConfigMgr->GetBoolDefault("AiPlayerbot.RandomBotAutologin", true);
minRandomBots = sConfigMgr->GetIntDefault("AiPlayerbot.MinRandomBots", 50);
maxRandomBots = sConfigMgr->GetIntDefault("AiPlayerbot.MaxRandomBots", 200);
randomBotUpdateInterval = sConfigMgr->GetIntDefault("AiPlayerbot.RandomBotUpdateInterval", MINUTE);
randomBotCountChangeMinInterval = sConfigMgr->GetIntDefault("AiPlayerbot.RandomBotCountChangeMinInterval", 30 * MINUTE);
randomBotCountChangeMaxInterval = sConfigMgr->GetIntDefault("AiPlayerbot.RandomBotCountChangeMaxInterval", 2 * HOUR);
minRandomBotInWorldTime = sConfigMgr->GetIntDefault("AiPlayerbot.MinRandomBotInWorldTime", 2 * HOUR);
maxRandomBotInWorldTime = sConfigMgr->GetIntDefault("AiPlayerbot.MaxRandomBotInWorldTime", 12 * HOUR);
minRandomBotRandomizeTime = sConfigMgr->GetIntDefault("AiPlayerbot.MinRandomBotRandomizeTime", 2 * HOUR);
maxRandomBotRandomizeTime = sConfigMgr->GetIntDefault("AiPlayerbot.MaxRandomRandomizeTime", 14 * 24 * HOUR);
minRandomBotChangeStrategyTime = sConfigMgr->GetIntDefault("AiPlayerbot.MinRandomBotChangeStrategyTime", 30 * MINUTE);
maxRandomBotChangeStrategyTime = sConfigMgr->GetIntDefault("AiPlayerbot.MaxRandomBotChangeStrategyTime", 2 * HOUR);
minRandomBotReviveTime = sConfigMgr->GetIntDefault("AiPlayerbot.MinRandomBotReviveTime", MINUTE);
maxRandomBotReviveTime = sConfigMgr->GetIntDefault("AiPlayerbot.MaxRandomBotReviveTime", 5 * MINUTE);
randomBotTeleportDistance = sConfigMgr->GetIntDefault("AiPlayerbot.RandomBotTeleportDistance", 100);
randomBotsPerInterval = sConfigMgr->GetIntDefault("AiPlayerbot.RandomBotsPerInterval", MINUTE);
minRandomBotsPriceChangeInterval = sConfigMgr->GetIntDefault("AiPlayerbot.MinRandomBotsPriceChangeInterval", 2 * HOUR);
maxRandomBotsPriceChangeInterval = sConfigMgr->GetIntDefault("AiPlayerbot.MaxRandomBotsPriceChangeInterval", 48 * HOUR);
randomBotJoinLfg = sConfigMgr->GetBoolDefault("AiPlayerbot.RandomBotJoinLfg", true);
randomBotJoinBG = sConfigMgr->GetBoolDefault("AiPlayerbot.RandomBotJoinBG", true);
logInGroupOnly = sConfigMgr->GetBoolDefault("AiPlayerbot.LogInGroupOnly", true);
logValuesPerTick = sConfigMgr->GetBoolDefault("AiPlayerbot.LogValuesPerTick", false);
fleeingEnabled = sConfigMgr->GetBoolDefault("AiPlayerbot.FleeingEnabled", true);
summonAtInnkeepersEnabled = sConfigMgr->GetBoolDefault("AiPlayerbot.SummonAtInnkeepersEnabled", true);
randomBotMinLevel = sConfigMgr->GetIntDefault("AiPlayerbot.RandomBotMinLevel", 1);
randomBotMaxLevel = sConfigMgr->GetIntDefault("AiPlayerbot.RandomBotMaxLevel", 80);
randomBotLoginAtStartup = sConfigMgr->GetBoolDefault("AiPlayerbot.RandomBotLoginAtStartup", true);
randomBotTeleLevel = sConfigMgr->GetIntDefault("AiPlayerbot.RandomBotTeleLevel", 5);
openGoSpell = sConfigMgr->GetIntDefault("AiPlayerbot.OpenGoSpell", 6477);
randomChangeMultiplier = sConfigMgr->GetFloatDefault("AiPlayerbot.RandomChangeMultiplier", 1.0);
randomBotCombatStrategies = sConfigMgr->GetStringDefault("AiPlayerbot.RandomBotCombatStrategies", "-threat");
randomBotNonCombatStrategies = sConfigMgr->GetStringDefault("AiPlayerbot.RandomBotNonCombatStrategies", "");
combatStrategies = sConfigMgr->GetStringDefault("AiPlayerbot.CombatStrategies", "+custom::say");
nonCombatStrategies = sConfigMgr->GetStringDefault("AiPlayerbot.NonCombatStrategies", "+custom::say,+return");
commandPrefix = sConfigMgr->GetStringDefault("AiPlayerbot.CommandPrefix", "");
commandSeparator = sConfigMgr->GetStringDefault("AiPlayerbot.CommandSeparator", "\\\\");
commandServerPort = sConfigMgr->GetIntDefault("AiPlayerbot.CommandServerPort", 8888);
perfMonEnabled = sConfigMgr->GetBoolDefault("AiPlayerbot.PerfMonEnabled", false);
LOG_INFO("server.loading", "---------------------------------------");
LOG_INFO("server.loading", " Loading TalentSpecs ");
LOG_INFO("server.loading", "---------------------------------------");
for (uint32 cls = 1; cls < MAX_CLASSES; ++cls)
{
classSpecs[cls] = ClassSpecs(1 << (cls - 1));
for (uint32 spec = 0; spec < MAX_LEVEL; ++spec)
{
std::ostringstream os;
os << "AiPlayerbot.PremadeSpecName." << cls << "." << spec;
std::string const specName = sConfigMgr->GetStringDefault(os.str().c_str(), "", false);
if (!specName.empty())
{
std::ostringstream os;
os << "AiPlayerbot.PremadeSpecProb." << cls << "." << spec;
uint32 probability = sConfigMgr->GetIntDefault(os.str().c_str(), 100, false);
TalentPath talentPath(spec, specName, probability);
for (uint32 level = 10; level <= 80; level++)
{
std::ostringstream os;
os << "AiPlayerbot.PremadeSpecLink." << cls << "." << spec << "." << level;
std::string specLink = sConfigMgr->GetStringDefault(os.str().c_str(), "", false);
specLink = specLink.substr(0, specLink.find("#", 0));;
specLink = specLink.substr(0, specLink.find(" ", 0));;
if (!specLink.empty())
{
std::ostringstream out;
// Ignore bad specs.
if (!classSpecs[cls].baseSpec.CheckTalentLink(specLink, &out))
{
LOG_ERROR("playerbots", "Error with premade spec link: {}", specLink.c_str());
LOG_ERROR("playerbots", "{}", out.str().c_str());
continue;
}
TalentSpec linkSpec(&classSpecs[cls].baseSpec, specLink);
if (!linkSpec.CheckTalents(level, &out))
{
LOG_ERROR("playerbots", "Error with premade spec: {}", specLink.c_str());
LOG_ERROR("playerbots", "{}", out.str().c_str());
continue;
}
talentPath.talentSpec.push_back(linkSpec);
}
}
// Only add paths that have atleast 1 spec.
if (talentPath.talentSpec.size() > 0)
classSpecs[cls].talentPath.push_back(talentPath);
}
}
}
botCheats.clear();
LoadListString<std::vector<std::string>>(sConfigMgr->GetStringDefault("AiPlayerbot.BotCheats", "taxi"), botCheats);
botCheatMask = 0;
if (std::find(botCheats.begin(), botCheats.end(), "taxi") != botCheats.end())
botCheatMask |= (uint32)BotCheatMask::taxi;
if (std::find(botCheats.begin(), botCheats.end(), "gold") != botCheats.end())
botCheatMask |= (uint32)BotCheatMask::gold;
if (std::find(botCheats.begin(), botCheats.end(), "health") != botCheats.end())
botCheatMask |= (uint32)BotCheatMask::health;
if (std::find(botCheats.begin(), botCheats.end(), "mana") != botCheats.end())
botCheatMask |= (uint32)BotCheatMask::mana;
if (std::find(botCheats.begin(), botCheats.end(), "power") != botCheats.end())
botCheatMask |= (uint32)BotCheatMask::power;
LoadListString<std::vector<std::string>>(sConfigMgr->GetStringDefault("AiPlayerbot.AllowedLogFiles", ""), allowedLogFiles);
worldBuffs.clear();
for (uint32 factionId = 0; factionId < 3; factionId++)
{
for (uint32 classId = 0; classId < MAX_CLASSES; classId++)
{
for (uint32 minLevel = 0; minLevel < MAX_LEVEL; minLevel++)
{
for (uint32 maxLevel = 0; maxLevel < MAX_LEVEL; maxLevel++)
{
loadWorldBuf(factionId, classId, minLevel, maxLevel);
}
}
}
}
randomBotAccountPrefix = sConfigMgr->GetStringDefault("AiPlayerbot.RandomBotAccountPrefix", "rndbot");
randomBotAccountCount = sConfigMgr->GetIntDefault("AiPlayerbot.RandomBotAccountCount", 200);
deleteRandomBotAccounts = sConfigMgr->GetBoolDefault("AiPlayerbot.DeleteRandomBotAccounts", false);
randomBotGuildCount = sConfigMgr->GetIntDefault("AiPlayerbot.RandomBotGuildCount", 20);
deleteRandomBotGuilds = sConfigMgr->GetBoolDefault("AiPlayerbot.DeleteRandomBotGuilds", false);
guildTaskEnabled = sConfigMgr->GetBoolDefault("AiPlayerbot.EnableGuildTasks", true);
minGuildTaskChangeTime = sConfigMgr->GetIntDefault("AiPlayerbot.MinGuildTaskChangeTime", 3 * 24 * 3600);
maxGuildTaskChangeTime = sConfigMgr->GetIntDefault("AiPlayerbot.MaxGuildTaskChangeTime", 4 * 24 * 3600);
minGuildTaskAdvertisementTime = sConfigMgr->GetIntDefault("AiPlayerbot.MinGuildTaskAdvertisementTime", 300);
maxGuildTaskAdvertisementTime = sConfigMgr->GetIntDefault("AiPlayerbot.MaxGuildTaskAdvertisementTime", 12 * 3600);
minGuildTaskRewardTime = sConfigMgr->GetIntDefault("AiPlayerbot.MinGuildTaskRewardTime", 300);
maxGuildTaskRewardTime = sConfigMgr->GetIntDefault("AiPlayerbot.MaxGuildTaskRewardTime", 3600);
guildTaskAdvertCleanupTime = sConfigMgr->GetIntDefault("AiPlayerbot.GuildTaskAdvertCleanupTime", 300);
guildTaskKillTaskDistance = sConfigMgr->GetIntDefault("AiPlayerbot.GuildTaskKillTaskDistance", 2000);
targetPosRecalcDistance = sConfigMgr->GetFloatDefault("AiPlayerbot.TargetPosRecalcDistance", 0.1f);
// cosmetics (by lidocain)
randomBotShowCloak = sConfigMgr->GetBoolDefault("AiPlayerbot.RandomBotShowCloak", true);
randomBotShowHelmet = sConfigMgr->GetBoolDefault("AiPlayerbot.RandomBotShowHelmet", true);
// SPP switches
enableGreet = sConfigMgr->GetBoolDefault("AiPlayerbot.EnableGreet", true);
disableRandomLevels = sConfigMgr->GetBoolDefault("AiPlayerbot.DisableRandomLevels", false);
randomBotRandomPassword = sConfigMgr->GetBoolDefault("AiPlayerbot.RandomBotRandomPassword", true);
playerbotsXPrate = sConfigMgr->GetIntDefault("AiPlayerbot.KillXPRate", 1);
botActiveAlone = sConfigMgr->GetIntDefault("AiPlayerbot.BotActiveAlone", 10);
randombotsWalkingRPG = sConfigMgr->GetBoolDefault("AiPlayerbot.RandombotsWalkingRPG", false);
randombotsWalkingRPGInDoors = sConfigMgr->GetBoolDefault("AiPlayerbot.RandombotsWalkingRPG.InDoors", false);
minEnchantingBotLevel = sConfigMgr->GetIntDefault("AiPlayerbot.MinEnchantingBotLevel", 60);
randombotStartingLevel = sConfigMgr->GetIntDefault("AiPlayerbot.RandombotStartingLevel", 5);
gearscorecheck = sConfigMgr->GetBoolDefault("AiPlayerbot.GearScoreCheck", false);
randomBotPreQuests = sConfigMgr->GetBoolDefault("AiPlayerbot.PreQuests", true);
// SPP automation
autoPickReward = sConfigMgr->GetStringDefault("AiPlayerbot.AutoPickReward", "yes");
autoEquipUpgradeLoot = sConfigMgr->GetBoolDefault("AiPlayerbot.AutoEquipUpgradeLoot", true);
syncQuestWithPlayer = sConfigMgr->GetBoolDefault("AiPlayerbot.SyncQuestWithPlayer", false);
syncQuestForPlayer = sConfigMgr->GetBoolDefault("AiPlayerbot.SyncQuestForPlayer", false);
autoTrainSpells = sConfigMgr->GetStringDefault("AiPlayerbot.AutoTrainSpells", "yes");
autoPickTalents = sConfigMgr->GetStringDefault("AiPlayerbot.AutoPickTalents", "full");
autoLearnTrainerSpells = sConfigMgr->GetBoolDefault("AiPlayerbot.AutoLearnTrainerSpells", false);
autoLearnQuestSpells = sConfigMgr->GetBoolDefault("AiPlayerbot.AutoLearnQuestSpells", false);
autoDoQuests = sConfigMgr->GetBoolDefault("AiPlayerbot.AutoDoQuests", false);
syncLevelWithPlayers = sConfigMgr->GetBoolDefault("AiPlayerbot.SyncLevelWithPlayers", false);
randomBotSayWithoutMaster = sConfigMgr->GetBoolDefault("AiPlayerbot.RandomBotSayWithoutMaster", false);
randomBotGroupNearby = sConfigMgr->GetBoolDefault("AiPlayerbot.RandomBotGroupNearby", true);
// arena
randomBotArenaTeamCount = sConfigMgr->GetIntDefault("AiPlayerbot.RandomBotArenaTeamCount", 20);
deleteRandomBotArenaTeams = sConfigMgr->GetBoolDefault("AiPlayerbot.DeleteRandomBotArenaTeams", false);
selfBotLevel = sConfigMgr->GetIntDefault("AiPlayerbot.SelfBotLevel", 1);
RandomPlayerbotFactory::CreateRandomBots();
PlayerbotFactory::Init();
sRandomItemMgr->Init();
sRandomItemMgr->InitAfterAhBot();
if (!sPlayerbotAIConfig->autoDoQuests)
{
LOG_INFO("server.loading", "Loading Quest Detail Data...");
sTravelMgr->LoadQuestTravelTable();
}
if (sPlayerbotAIConfig->randomBotJoinBG)
sRandomPlayerbotMgr->LoadBattleMastersCache();
LOG_INFO("server.loading", "---------------------------------------");
LOG_INFO("server.loading", " AI Playerbots initialized ");
LOG_INFO("server.loading", "---------------------------------------");
return true;
}
bool PlayerbotAIConfig::IsInRandomAccountList(uint32 id)
{
return find(randomBotAccounts.begin(), randomBotAccounts.end(), id) != randomBotAccounts.end();
}
bool PlayerbotAIConfig::IsInRandomQuestItemList(uint32 id)
{
return find(randomBotQuestItems.begin(), randomBotQuestItems.end(), id) != randomBotQuestItems.end();
}
bool PlayerbotAIConfig::IsInPvpProhibitedZone(uint32 id)
{
return find(pvpProhibitedZoneIds.begin(), pvpProhibitedZoneIds.end(), id) != pvpProhibitedZoneIds.end();
}
std::string const PlayerbotAIConfig::GetTimestampStr()
{
time_t t = time(nullptr);
tm* aTm = localtime(&t);
// YYYY year
// MM month (2 digits 01-12)
// DD day (2 digits 01-31)
// HH hour (2 digits 00-23)
// MM minutes (2 digits 00-59)
// SS seconds (2 digits 00-59)
char buf[20];
snprintf(buf, 20, "%04d-%02d-%02d %02d-%02d-%02d", aTm->tm_year + 1900, aTm->tm_mon + 1, aTm->tm_mday, aTm->tm_hour, aTm->tm_min, aTm->tm_sec);
return std::string(buf);
}
bool PlayerbotAIConfig::openLog(std::string const fileName, char const* mode)
{
if (!hasLog(fileName))
return false;
auto logFileIt = logFiles.find(fileName);
if (logFileIt == logFiles.end())
{
logFiles.insert(std::make_pair(fileName, std::make_pair(nullptr, false)));
logFileIt = logFiles.find(fileName);
}
FILE* file = logFileIt->second.first;
bool fileOpen = logFileIt->second.second;
if (fileOpen) //close log file
fclose(file);
std::string m_logsDir = sConfigMgr->GetOption<std::string>("LogsDir", "", false);
if (!m_logsDir.empty())
{
if ((m_logsDir.at(m_logsDir.length() - 1) != '/') && (m_logsDir.at(m_logsDir.length() - 1) != '\\'))
m_logsDir.append("/");
}
file = fopen((m_logsDir + fileName).c_str(), mode);
fileOpen = true;
logFileIt->second.first = file;
logFileIt->second.second = fileOpen;
return true;
}
void PlayerbotAIConfig::log(std::string const fileName, char const* str, ...)
{
if (!str)
return;
std::lock_guard<std::mutex> guard(m_logMtx);
if (!isLogOpen(fileName) && !openLog(fileName, "a"))
return;
FILE* file = logFiles.find(fileName)->second.first;
va_list ap;
va_start(ap, str);
vfprintf(file, str, ap);
fprintf(file, "\n");
va_end(ap);
fflush(file);
fflush(stdout);
}
void PlayerbotAIConfig::loadWorldBuf(uint32 factionId1, uint32 classId1, uint32 minLevel1, uint32 maxLevel1)
{
std::vector<uint32> buffs;
std::ostringstream os;
os << "AiPlayerbot.WorldBuff." << factionId1 << "." << classId1 << "." << minLevel1 << "." << maxLevel1;
LoadList<std::vector<uint32>>(sConfigMgr->GetStringDefault(os.str().c_str(), "", false), buffs);
for (auto buff : buffs)
{
worldBuff wb = { buff, factionId1, classId1, minLevel1, maxLevel1 };
worldBuffs.push_back(wb);
}
if (maxLevel1 == 0)
{
std::ostringstream os;
os << "AiPlayerbot.WorldBuff." << factionId1 << "." << classId1 << "." << minLevel1;
LoadList<std::vector<uint32>>(sConfigMgr->GetStringDefault(os.str().c_str(), "", false), buffs);
for (auto buff : buffs)
{
worldBuff wb = { buff, factionId1, classId1, minLevel1, maxLevel1 };
worldBuffs.push_back(wb);
}
}
if (maxLevel1 == 0 && minLevel1 == 0)
{
std::ostringstream os;
os << "AiPlayerbot.WorldBuff." << factionId1 << "." << factionId1 << "." << classId1;
LoadList<std::vector<uint32>>(sConfigMgr->GetStringDefault(os.str().c_str(), "", false), buffs);
for (auto buff : buffs)
{
worldBuff wb = { buff, factionId1, classId1, minLevel1, maxLevel1 };
worldBuffs.push_back(wb);
}
}
if (classId1 == 0 && maxLevel1 == 0 && minLevel1 == 0)
{
std::ostringstream os;
os << "AiPlayerbot.WorldBuff." << factionId1;
LoadList<std::vector<uint32>>(sConfigMgr->GetStringDefault(os.str().c_str(), "", false), buffs);
for (auto buff : buffs)
{
worldBuff wb = { buff, factionId1, classId1, minLevel1, maxLevel1 };
worldBuffs.push_back(wb);
}
}
if (factionId1 == 0 && classId1 == 0 && maxLevel1 == 0 && minLevel1 == 0)
{
std::ostringstream os;
os << "AiPlayerbot.WorldBuff";
LoadList<std::vector<uint32>>(sConfigMgr->GetStringDefault(os.str().c_str(), "", false), buffs);
for (auto buff : buffs)
{
worldBuff wb = { buff, factionId1, classId1, minLevel1, maxLevel1 };
worldBuffs.push_back(wb);
}
}
}

172
src/PlayerbotAIConfig.h Normal file
View File

@ -0,0 +1,172 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#ifndef _PLAYERBOT_PLAYERbotAICONFIG_H
#define _PLAYERBOT_PLAYERbotAICONFIG_H
#include "Common.h"
#include "SharedDefines.h"
#include "TalentSpec.h"
#include <mutex>
enum class BotCheatMask : uint32
{
none = 0,
taxi = 1,
gold = 2,
health = 4,
mana = 8,
power = 16,
maxMask = 32
};
class PlayerbotAIConfig
{
public:
PlayerbotAIConfig() { };
static PlayerbotAIConfig* instance()
{
static PlayerbotAIConfig instance;
return &instance;
}
bool Initialize();
bool IsInRandomAccountList(uint32 id);
bool IsInRandomQuestItemList(uint32 id);
bool IsInPvpProhibitedZone(uint32 id);
bool enabled;
bool allowGuildBots;
uint32 globalCoolDown, reactDelay, maxWaitForMove, expireActionTime, dispelAuraDuration, passiveDelay, repeatDelay,
errorDelay, rpgDelay, sitDelay, returnDelay, lootDelay;
float sightDistance, spellDistance, reactDistance, grindDistance, lootDistance, shootDistance,
fleeDistance, tooCloseDistance, meleeDistance, followDistance, whisperDistance, contactDistance,
aoeRadius, rpgDistance, targetPosRecalcDistance, farDistance, healDistance, aggroDistance;
uint32 criticalHealth, lowHealth, mediumHealth, almostFullHealth;
uint32 lowMana, mediumMana;
uint32 openGoSpell;
bool randomBotAutologin;
bool botAutologin;
std::string randomBotMapsAsString;
std::vector<uint32> randomBotMaps;
std::vector<uint32> randomBotQuestItems;
std::vector<uint32> randomBotAccounts;
std::vector<uint32> randomBotSpellIds;
std::vector<uint32> randomBotQuestIds;
uint32 randomBotTeleportDistance;
float randomGearLoweringChance;
float randomBotMaxLevelChance;
float randomBotRpgChance;
uint32 minRandomBots, maxRandomBots;
uint32 randomBotUpdateInterval, randomBotCountChangeMinInterval, randomBotCountChangeMaxInterval;
uint32 minRandomBotInWorldTime, maxRandomBotInWorldTime;
uint32 minRandomBotRandomizeTime, maxRandomBotRandomizeTime;
uint32 minRandomBotChangeStrategyTime, maxRandomBotChangeStrategyTime;
uint32 minRandomBotReviveTime, maxRandomBotReviveTime;
uint32 minRandomBotPvpTime, maxRandomBotPvpTime;
uint32 randomBotsPerInterval;
uint32 minRandomBotsPriceChangeInterval, maxRandomBotsPriceChangeInterval;
bool randomBotJoinLfg;
bool randomBotJoinBG;
bool randomBotLoginAtStartup;
uint32 randomBotTeleLevel;
bool logInGroupOnly, logValuesPerTick;
bool fleeingEnabled;
bool summonAtInnkeepersEnabled;
std::string combatStrategies, nonCombatStrategies;
std::string randomBotCombatStrategies, randomBotNonCombatStrategies;
uint32 randomBotMinLevel, randomBotMaxLevel;
float randomChangeMultiplier;
uint32 specProbability[MAX_CLASSES][10];
std::string premadeLevelSpec[MAX_CLASSES][10][91]; //lvl 10 - 100
ClassSpecs classSpecs[MAX_CLASSES];
std::string commandPrefix, commandSeparator;
std::string randomBotAccountPrefix;
uint32 randomBotAccountCount;
bool randomBotRandomPassword;
bool deleteRandomBotAccounts;
uint32 randomBotGuildCount;
bool deleteRandomBotGuilds;
std::vector<uint32> randomBotGuilds;
std::vector<uint32> pvpProhibitedZoneIds;
bool randombotsWalkingRPG;
bool randombotsWalkingRPGInDoors;
uint32 minEnchantingBotLevel;
uint32 randombotStartingLevel;
bool gearscorecheck;
bool randomBotPreQuests;
bool guildTaskEnabled;
uint32 minGuildTaskChangeTime, maxGuildTaskChangeTime;
uint32 minGuildTaskAdvertisementTime, maxGuildTaskAdvertisementTime;
uint32 minGuildTaskRewardTime, maxGuildTaskRewardTime;
uint32 guildTaskAdvertCleanupTime;
uint32 guildTaskKillTaskDistance;
uint32 iterationsPerTick;
std::mutex m_logMtx;
std::vector<std::string> allowedLogFiles;
std::unordered_map<std::string, std::pair<FILE*, bool>> logFiles;
std::vector<std::string> botCheats;
uint32 botCheatMask = 0;
struct worldBuff
{
uint32 spellId;
uint32 factionId = 0;
uint32 classId = 0;
uint32 minLevel = 0;
uint32 maxLevel = 0;
};
std::vector<worldBuff> worldBuffs;
uint32 commandServerPort;
bool perfMonEnabled;
bool enableGreet;
bool randomBotShowHelmet;
bool randomBotShowCloak;
bool disableRandomLevels;
uint32 playerbotsXPrate;
uint32 botActiveAlone;
std::string autoPickReward;
bool autoEquipUpgradeLoot;
bool syncQuestWithPlayer;
bool syncQuestForPlayer;
std::string autoTrainSpells;
std::string autoPickTalents;
bool autoLearnTrainerSpells;
bool autoDoQuests;
bool syncLevelWithPlayers;
bool autoLearnQuestSpells;
bool randomBotSayWithoutMaster;
bool randomBotGroupNearby;
uint32 tweakValue; //Debugging config
uint32 randomBotArenaTeamCount;
bool deleteRandomBotArenaTeams;
std::vector<uint32> randomBotArenaTeams;
uint32 selfBotLevel;
std::string const GetTimestampStr();
bool hasLog(std::string const fileName) { return std::find(allowedLogFiles.begin(), allowedLogFiles.end(), fileName) != allowedLogFiles.end(); };
bool openLog(std::string const fileName, char const* mode = "a");
bool isLogOpen(std::string const fileName) { auto it = logFiles.find(fileName); return it != logFiles.end() && it->second.second; }
void log(std::string const fileName, const char* str, ...);
void loadWorldBuf(uint32 factionId, uint32 classId, uint32 minLevel, uint32 maxLevel);
};
#define sPlayerbotAIConfig PlayerbotAIConfig::instance()
#endif

View File

@ -0,0 +1,99 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#include "PlayerbotCommandServer.h"
#include "IoContext.h"
#include "Playerbots.h"
#include <cstdlib>
#include <iostream>
#include <boost/bind.hpp>
#include <boost/smart_ptr.hpp>
#include <boost/asio.hpp>
#include <boost/thread/thread.hpp>
using boost::asio::ip::tcp;
typedef boost::shared_ptr<tcp::socket> socket_ptr;
bool ReadLine(socket_ptr sock, std::string* buffer, std::string* line)
{
// Do the real reading from fd until buffer has '\n'.
std::string::iterator pos;
while ((pos = find(buffer->begin(), buffer->end(), '\n')) == buffer->end())
{
char buf[1025];
boost::system::error_code error;
size_t n = sock->read_some(boost::asio::buffer(buf), error);
if (n == -1 || error == boost::asio::error::eof)
return false;
else if (error)
throw boost::system::system_error(error); // Some other error.
buf[n] = 0;
*buffer += buf;
}
*line = std::string(buffer->begin(), pos);
*buffer = std::string(pos + 1, buffer->end());
return true;
}
void session(socket_ptr sock)
{
try
{
std::string buffer, request;
while (ReadLine(sock, &buffer, &request))
{
std::string const response = sRandomPlayerbotMgr->HandleRemoteCommand(request) + "\n";
boost::asio::write(*sock, boost::asio::buffer(response.c_str(), response.size()));
request = "";
}
}
catch (std::exception& e)
{
LOG_ERROR("playerbots", "{}", e.what());
}
}
void server(Acore::Asio::IoContext& io_service, short port)
{
tcp::acceptor a(io_service, tcp::endpoint(tcp::v4(), port));
for (;;)
{
socket_ptr sock(new tcp::socket(io_service));
a.accept(*sock);
boost::thread t(boost::bind(session, sock));
}
}
void Run()
{
if (!sPlayerbotAIConfig->commandServerPort)
{
return;
}
std::ostringstream s;
s << "Starting Playerbots Command Server on port " << sPlayerbotAIConfig->commandServerPort;
LOG_INFO("playerbots", "{}", s.str().c_str());
try
{
Acore::Asio::IoContext io_service;
server(io_service, sPlayerbotAIConfig->commandServerPort);
}
catch (std::exception& e)
{
LOG_ERROR("playerbots", "{}", e.what());
}
}
void PlayerbotCommandServer::Start()
{
std::thread serverThread(Run);
serverThread.detach();
}

View File

@ -0,0 +1,24 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#ifndef _PLAYERBOT_PLAYERBOTCOMMANDSERVER_H
#define _PLAYERBOT_PLAYERBOTCOMMANDSERVER_H
class PlayerbotCommandServer
{
public:
PlayerbotCommandServer() { }
virtual ~PlayerbotCommandServer() { }
static PlayerbotCommandServer* instance()
{
static PlayerbotCommandServer instance;
return &instance;
}
void Start();
};
#define sPlayerbotCommandServer PlayerbotCommandServer::instance()
#endif

88
src/PlayerbotDbStore.cpp Normal file
View File

@ -0,0 +1,88 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#include "PlayerbotDbStore.h"
#include "Playerbots.h"
#include <iostream>
void PlayerbotDbStore::Load(PlayerbotAI* botAI)
{
ObjectGuid::LowType guid = botAI->GetBot()->GetGUID().GetCounter();
PlayerbotsDatabasePreparedStatement* stmt = PlayerbotsDatabase.GetPreparedStatement(PLAYERBOTS_SEL_DB_STORE);
stmt->SetData(0, guid);
if (PreparedQueryResult result = PlayerbotsDatabase.Query(stmt))
{
botAI->ClearStrategies(BOT_STATE_COMBAT);
botAI->ClearStrategies(BOT_STATE_NON_COMBAT);
botAI->ChangeStrategy("+chat", BOT_STATE_COMBAT);
botAI->ChangeStrategy("+chat", BOT_STATE_NON_COMBAT);
std::vector<std::string> values;
do
{
Field* fields = result->Fetch();
std::string const key = fields[0].Get<std::string>();
std::string const value = fields[1].Get<std::string>();
if (key == "value")
values.push_back(value);
else if (key == "co")
botAI->ChangeStrategy(value, BOT_STATE_COMBAT);
else if (key == "nc")
botAI->ChangeStrategy(value, BOT_STATE_NON_COMBAT);
else if (key == "dead")
botAI->ChangeStrategy(value, BOT_STATE_DEAD);
}
while (result->NextRow());
botAI->GetAiObjectContext()->Load(values);
}
}
void PlayerbotDbStore::Save(PlayerbotAI* botAI)
{
ObjectGuid::LowType guid = botAI->GetBot()->GetGUID().GetCounter();
Reset(botAI);
std::vector<std::string> data = botAI->GetAiObjectContext()->Save();
for (std::vector<std::string>::iterator i = data.begin(); i != data.end(); ++i)
{
SaveValue(guid, "value", *i);
}
SaveValue(guid, "co", FormatStrategies("co", botAI->GetStrategies(BOT_STATE_COMBAT)));
SaveValue(guid, "nc", FormatStrategies("nc", botAI->GetStrategies(BOT_STATE_NON_COMBAT)));
SaveValue(guid, "dead", FormatStrategies("dead", botAI->GetStrategies(BOT_STATE_DEAD)));
}
std::string const PlayerbotDbStore::FormatStrategies(std::string const type, std::vector<std::string> strategies)
{
std::ostringstream out;
for (std::vector<std::string>::iterator i = strategies.begin(); i != strategies.end(); ++i)
out << "+" << (*i).c_str() << ",";
std::string const res = out.str();
return res.substr(0, res.size() - 1);
}
void PlayerbotDbStore::Reset(PlayerbotAI* botAI)
{
ObjectGuid::LowType guid = botAI->GetBot()->GetGUID().GetCounter();
PlayerbotsDatabasePreparedStatement* stmt = PlayerbotsDatabase.GetPreparedStatement(PLAYERBOTS_DEL_CUSTOM_STRATEGY);
stmt->SetData(0, guid);
PlayerbotsDatabase.Execute(stmt);
}
void PlayerbotDbStore::SaveValue(uint32 guid, std::string const key, std::string const value)
{
PlayerbotsDatabasePreparedStatement* stmt = PlayerbotsDatabase.GetPreparedStatement(PLAYERBOTS_INS_DB_STORE);
stmt->SetData(0, guid);
stmt->SetData(1, key);
stmt->SetData(2, value);
PlayerbotsDatabase.Execute(stmt);
}

36
src/PlayerbotDbStore.h Normal file
View File

@ -0,0 +1,36 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#ifndef _PLAYERBOT_PLAYERBOTDBSTORE_H
#define _PLAYERBOT_PLAYERBOTDBSTORE_H
#include "Common.h"
#include <vector>
class PlayerbotAI;
class PlayerbotDbStore
{
public:
PlayerbotDbStore() { }
virtual ~PlayerbotDbStore() { }
static PlayerbotDbStore* instance()
{
static PlayerbotDbStore instance;
return &instance;
}
void Save(PlayerbotAI* botAI);
void Load(PlayerbotAI* botAI);
void Reset(PlayerbotAI* botAI);
private:
void SaveValue(uint32 guid, std::string const key, std::string const value);
std::string const FormatStrategies(std::string const type, std::vector<std::string> strategies);
};
#define sPlayerbotDbStore PlayerbotDbStore::instance()
#endif

2667
src/PlayerbotFactory.cpp Normal file

File diff suppressed because it is too large Load Diff

176
src/PlayerbotFactory.h Normal file
View File

@ -0,0 +1,176 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#ifndef _PLAYERBOT_PLAYERBOTFACTORY_H
#define _PLAYERBOT_PLAYERBOTFACTORY_H
#include "InventoryAction.h"
class Item;
class Player;
struct ItemTemplate;
struct EnchantTemplate
{
uint8 ClassId;
uint8 SpecId;
uint32 SpellId;
uint8 SlotId;
};
typedef std::vector<EnchantTemplate> EnchantContainer;
//TODO: more spec/role
/* classid+talenttree
enum spec : uint8
{
WARRIOR ARMS = 10,
WARRIOR FURY = 11,
WARRIOR PROT = 12,
ROLE_HEALER = 1,
ROLE_MDPS = 2,
ROLE_CDPS = 3,
};
*/
/*enum roles : uint8
{
ROLE_TANK = 0,
ROLE_HEALER = 1,
ROLE_MDPS = 2,
ROLE_CDPS = 3
};*/
enum PriorizedConsumables
{
CONSUM_ID_ROUGH_WEIGHTSTONE = 3239,
CONSUM_ID_COARSE_WEIGHTSTONE = 3239,
CONSUM_ID_HEAVY_WEIGHTSTONE = 3241,
CONSUM_ID_SOLID_WEIGHTSTONE = 7965,
CONSUM_ID_DENSE_WEIGHTSTONE = 12643,
CONSUM_ID_FEL_WEIGHTSTONE = 28420,
CONSUM_ID_ADAMANTITE_WEIGHTSTONE = 28421,
CONSUM_ID_ROUGH_SHARPENING_STONE = 2862,
CONSUM_ID_COARSE_SHARPENING_STONE = 2863,
CONSUM_ID_HEAVY_SHARPENING_STONE = 2871,
CONSUM_ID_SOL_SHARPENING_STONE = 7964,
CONSUM_ID_DENSE_SHARPENING_STONE = 12404,
CONSUM_ID_ELEMENTAL_SHARPENING_STONE = 18262,
CONSUM_ID_CONSECRATED_SHARPENING_STONE = 23122,
CONSUM_ID_FEL_SHARPENING_STONE = 23528,
CONSUM_ID_ADAMANTITE_SHARPENING_STONE = 23529,
CONSUM_ID_LINEN_BANDAGE = 1251,
CONSUM_ID_HEAVY_LINEN_BANDAGE = 2581,
CONSUM_ID_WOOL_BANDAGE = 3530,
CONSUM_ID_HEAVY_WOOL_BANDAGE = 3531,
CONSUM_ID_SILK_BANDAGE = 6450,
CONSUM_ID_HEAVY_SILK_BANDAGE = 6451,
CONSUM_ID_MAGEWEAVE_BANDAGE = 8544,
CONSUM_ID_HEAVY_MAGEWEAVE_BANDAGE = 8545,
CONSUM_ID_RUNECLOTH_BANDAGE = 14529,
CONSUM_ID_HEAVY_RUNECLOTH_BANDAGE = 14530,
CONSUM_ID_NETHERWEAVE_BANDAGE = 21990,
CONSUM_ID_HEAVY_NETHERWEAVE_BANDAGE = 21991,
CONSUM_ID_BRILLIANT_MANA_OIL = 20748,
CONSUM_ID_MINOR_MANA_OIL = 20745,
CONSUM_ID_SUPERIOR_MANA_OIL = 22521,
CONSUM_ID_LESSER_MANA_OIL = 20747,
CONSUM_ID_BRILLIANT_WIZARD_OIL = 20749,
CONSUM_ID_MINOR_WIZARD_OIL = 20744,
CONSUM_ID_SUPERIOR_WIZARD_OIL = 22522,
CONSUM_ID_WIZARD_OIL = 20750,
CONSUM_ID_LESSER_WIZARD_OIL = 20746,
CONSUM_ID_INSTANT_POISON = 6947,
CONSUM_ID_INSTANT_POISON_II = 6949,
CONSUM_ID_INSTANT_POISON_III = 6950,
CONSUM_ID_INSTANT_POISON_IV = 8926,
CONSUM_ID_INSTANT_POISON_V = 8927,
CONSUM_ID_INSTANT_POISON_VI = 8928,
CONSUM_ID_INSTANT_POISON_VII = 21927,
CONSUM_ID_DEADLY_POISON = 2892,
CONSUM_ID_DEADLY_POISON_II = 2893,
CONSUM_ID_DEADLY_POISON_III = 8984,
CONSUM_ID_DEADLY_POISON_IV = 8985,
CONSUM_ID_DEADLY_POISON_V = 20844,
CONSUM_ID_DEADLY_POISON_VI = 22053,
CONSUM_ID_DEADLY_POISON_VII = 22054
};
#define MAX_CONSUM_ID 28
class PlayerbotFactory : public InventoryAction
{
public:
PlayerbotFactory(Player* bot, uint32 level, uint32 itemQuality = 0);
static ObjectGuid GetRandomBot();
static void Init();
void Refresh();
void Randomize(bool incremental);
static std::list<uint32> classQuestIds;
void InitSkills();
static uint32 tradeSkills[];
private:
void Prepare();
void InitSecondEquipmentSet();
void InitEquipment(bool incremental);
void InitEquipmentNew(bool incremental);
bool CanEquipItem(ItemTemplate const* proto, uint32 desiredQuality);
bool CanEquipUnseenItem(uint8 slot, uint16& dest, uint32 item);
void InitTradeSkills();
void UpdateTradeSkills();
void SetRandomSkill(uint16 id);
void InitSpells();
void ClearSpells();
void ClearSkills();
void InitAvailableSpells();
void InitSpecialSpells();
void InitTalentsTree(bool incremental);
void InitTalents(uint32 specNo);
void InitQuests(std::list<uint32>& questMap);
void InitPet();
void ClearInventory();
void ClearAllItems();
void ResetQuests();
void InitAmmo();
void InitMounts();
void InitPotions();
void InitFood();
void InitReagents();
bool CanEquipArmor(ItemTemplate const* proto);
bool CanEquipWeapon(ItemTemplate const* proto);
void EnchantItem(Item* item);
void AddItemStats(uint32 mod, uint8& sp, uint8& ap, uint8& tank);
bool CheckItemStats(uint8 sp, uint8 ap, uint8 tank);
void CancelAuras();
bool IsDesiredReplacement(Item* item);
void InitBags();
void InitInventory();
void InitInventoryTrade();
void InitInventoryEquip();
void InitInventorySkill();
Item* StoreItem(uint32 itemId, uint32 count);
void InitGuild();
void InitArenaTeam();
void InitImmersive();
void AddConsumables();
static void AddPrevQuests(uint32 questId, std::list<uint32>& questIds);
void LoadEnchantContainer();
void ApplyEnchantTemplate();
void ApplyEnchantTemplate(uint8 spec);
EnchantContainer::const_iterator GetEnchantContainerBegin() { return m_EnchantContainer.begin(); }
EnchantContainer::const_iterator GetEnchantContainerEnd() { return m_EnchantContainer.end(); }
uint32 level;
uint32 itemQuality;
static std::list<uint32> specialQuestIds;
protected:
EnchantContainer m_EnchantContainer;
};
#endif

1070
src/PlayerbotMgr.cpp Normal file

File diff suppressed because it is too large Load Diff

111
src/PlayerbotMgr.h Normal file
View File

@ -0,0 +1,111 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#ifndef _PLAYERBOT_PLAYERBOTMGR_H
#define _PLAYERBOT_PLAYERBOTMGR_H
#include "Common.h"
#include "QueryHolder.h"
#include "QueryResult.h"
#include "Player.h"
#include "PlayerbotAIBase.h"
class ChatHandler;
class PlayerbotAI;
class PlayerbotLoginQueryHolder;
class WorldPacket;
typedef std::map<ObjectGuid, Player*> PlayerBotMap;
typedef std::map<std::string, std::set<std::string> > PlayerBotErrorMap;
class PlayerbotHolder : public PlayerbotAIBase
{
public:
PlayerbotHolder();
virtual ~PlayerbotHolder() { };
void AddPlayerBot(ObjectGuid guid, uint32 masterAccountId);
void HandlePlayerBotLoginCallback(PlayerbotLoginQueryHolder const& holder);
void LogoutPlayerBot(ObjectGuid guid);
void DisablePlayerBot(ObjectGuid guid);
Player* GetPlayerBot(ObjectGuid guid) const;
Player* GetPlayerBot(ObjectGuid::LowType lowGuid) const;
PlayerBotMap::const_iterator GetPlayerBotsBegin() const { return playerBots.begin(); }
PlayerBotMap::const_iterator GetPlayerBotsEnd() const { return playerBots.end(); }
void UpdateAIInternal(uint32 elapsed, bool minimal = false) override { };
void UpdateSessions();
void HandleBotPackets(WorldSession* session);
void LogoutAllBots();
void OnBotLogin(Player* const bot);
std::vector<std::string> HandlePlayerbotCommand(char const* args, Player* master = nullptr);
std::string const ProcessBotCommand(std::string const cmd, ObjectGuid guid, ObjectGuid masterguid, bool admin, uint32 masterAccountId, uint32 masterGuildId);
uint32 GetAccountId(std::string const name);
uint32 GetAccountId(ObjectGuid guid);
std::string const ListBots(Player* master);
protected:
virtual void OnBotLoginInternal(Player* const bot) = 0;
PlayerBotMap playerBots;
};
class PlayerbotMgr : public PlayerbotHolder
{
public:
PlayerbotMgr(Player* const master);
virtual ~PlayerbotMgr();
static bool HandlePlayerbotMgrCommand(ChatHandler* handler, char const* args);
void HandleMasterIncomingPacket(WorldPacket const& packet);
void HandleMasterOutgoingPacket(WorldPacket const& packet);
void HandleCommand(uint32 type, std::string const text);
void OnPlayerLogin(Player* player);
void CancelLogout();
void UpdateAIInternal(uint32 elapsed, bool minimal = false) override;
void TellError(std::string const botName, std::string const text);
Player* GetMaster() const { return master; };
void SaveToDB();
protected:
void OnBotLoginInternal(Player* const bot) override;
void CheckTellErrors(uint32 elapsed);
private:
Player* const master;
PlayerBotErrorMap errors;
time_t lastErrorTell;
};
class PlayerbotsMgr
{
public:
PlayerbotsMgr() { }
~PlayerbotsMgr() { }
static PlayerbotsMgr* instance()
{
static PlayerbotsMgr instance;
return &instance;
}
void AddPlayerbotData(Player* player, bool isBotAI);
void RemovePlayerBotData(ObjectGuid const& guid);
PlayerbotAI* GetPlayerbotAI(Player* player);
PlayerbotMgr* GetPlayerbotMgr(Player* player);
private:
std::unordered_map<ObjectGuid, PlayerbotAIBase*> _playerbotsMap;
};
#define sPlayerbotsMgr PlayerbotsMgr::instance()
#endif

265
src/PlayerbotSecurity.cpp Normal file
View File

@ -0,0 +1,265 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#include "PlayerbotSecurity.h"
#include "LFGMgr.h"
#include "Playerbots.h"
PlayerbotSecurity::PlayerbotSecurity(Player* const bot) : bot(bot)
{
if (bot)
account = sCharacterCache->GetCharacterAccountIdByGuid(bot->GetGUID());
}
PlayerbotSecurityLevel PlayerbotSecurity::LevelFor(Player* from, DenyReason* reason, bool ignoreGroup)
{
if (from->GetSession()->GetSecurity() >= SEC_GAMEMASTER)
return PLAYERBOT_SECURITY_ALLOW_ALL;
PlayerbotAI* botAI = GET_PLAYERBOT_AI(bot);
if (botAI->IsOpposing(from))
{
if (reason)
*reason = PLAYERBOT_DENY_OPPOSING;
return PLAYERBOT_SECURITY_DENY_ALL;
}
if (sPlayerbotAIConfig->IsInRandomAccountList(account))
{
if (botAI->IsOpposing(from))
{
if (reason)
*reason = PLAYERBOT_DENY_OPPOSING;
return PLAYERBOT_SECURITY_DENY_ALL;
}
if (sLFGMgr->GetState(bot->GetGUID()) != lfg::LFG_STATE_NONE)
{
if (!bot->GetGuildId() || bot->GetGuildId() != from->GetGuildId())
{
if (reason)
*reason = PLAYERBOT_DENY_LFG;
return PLAYERBOT_SECURITY_TALK;
}
}
Group* group = from->GetGroup();
if (group)
{
for (GroupReference* gref = group->GetFirstMember(); gref; gref = gref->next())
{
Player* player = gref->GetSource();
if (player == bot && !ignoreGroup)
return PLAYERBOT_SECURITY_ALLOW_ALL;
}
}
if ((int32)bot->getLevel() - (int8)from->getLevel() > 30)
{
if (!bot->GetGuildId() || bot->GetGuildId() != from->GetGuildId())
{
if (reason)
*reason = PLAYERBOT_DENY_LOW_LEVEL;
return PLAYERBOT_SECURITY_TALK;
}
}
int32 botGS = (int32)botAI->GetEquipGearScore(bot, false, false);
int32 fromGS = (int32)botAI->GetEquipGearScore(from, false, false);
if (sPlayerbotAIConfig->gearscorecheck)
{
if (botGS && bot->getLevel() > 15 && botGS > fromGS &&
static_cast<float>(100 * (botGS - fromGS) / botGS) >= static_cast<float>(12 * sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL) / from->getLevel()))
{
if (reason) *reason = PLAYERBOT_DENY_GEARSCORE;
return PLAYERBOT_SECURITY_TALK;
}
}
if (bot->InBattlegroundQueue())
{
if (!bot->GetGuildId() || bot->GetGuildId() != from->GetGuildId())
{
if (reason)
*reason = PLAYERBOT_DENY_BG;
return PLAYERBOT_SECURITY_TALK;
}
}
/*if (bot->isDead())
{
if (reason)
*reason = PLAYERBOT_DENY_DEAD;
return PLAYERBOT_SECURITY_TALK;
}*/
group = bot->GetGroup();
if (!group)
{
/*if (bot->GetMapId() != from->GetMapId() || bot->GetDistance(from) > sPlayerbotAIConfig->whisperDistance)
{
if (!bot->GetGuildId() || bot->GetGuildId() != from->GetGuildId())
{
if (reason)
*reason = PLAYERBOT_DENY_FAR;
return PLAYERBOT_SECURITY_TALK;
}
}*/
if (reason)
*reason = PLAYERBOT_DENY_INVITE;
return PLAYERBOT_SECURITY_INVITE;
}
for (GroupReference* gref = group->GetFirstMember(); gref; gref = gref->next())
{
Player* player = gref->GetSource();
if (player == from)
return PLAYERBOT_SECURITY_ALLOW_ALL;
}
if (group->IsFull())
{
if (reason)
*reason = PLAYERBOT_DENY_FULL_GROUP;
return PLAYERBOT_SECURITY_TALK;
}
if (group->GetLeaderGUID() != bot->GetGUID())
{
if (reason)
*reason = PLAYERBOT_DENY_NOT_LEADER;
return PLAYERBOT_SECURITY_TALK;
}
else
{
if (reason)
*reason = PLAYERBOT_DENY_IS_LEADER;
return PLAYERBOT_SECURITY_INVITE;
}
if (reason)
*reason = PLAYERBOT_DENY_INVITE;
return PLAYERBOT_SECURITY_INVITE;
}
return PLAYERBOT_SECURITY_ALLOW_ALL;
}
bool PlayerbotSecurity::CheckLevelFor(PlayerbotSecurityLevel level, bool silent, Player* from, bool ignoreGroup)
{
DenyReason reason = PLAYERBOT_DENY_NONE;
PlayerbotSecurityLevel realLevel = LevelFor(from, &reason, ignoreGroup);
if (realLevel >= level)
return true;
PlayerbotAI* fromBotAI = GET_PLAYERBOT_AI(from);
if (silent || (fromBotAI && !fromBotAI->IsRealPlayer()))
return false;
PlayerbotAI* botAI = GET_PLAYERBOT_AI(bot);
Player* master = botAI->GetMaster();
if (master && botAI && botAI->IsOpposing(master) && master->GetSession()->GetSecurity() < SEC_GAMEMASTER)
return false;
std::ostringstream out;
switch (realLevel)
{
case PLAYERBOT_SECURITY_DENY_ALL:
out << "I'm kind of busy now";
break;
case PLAYERBOT_SECURITY_TALK:
switch (reason)
{
case PLAYERBOT_DENY_NONE:
out << "I'll do it later";
break;
case PLAYERBOT_DENY_LOW_LEVEL:
out << "You are too low level: |cffff0000" << (uint32)from->getLevel() << "|cffffffff/|cff00ff00" << (uint32)bot->getLevel();
break;
case PLAYERBOT_DENY_GEARSCORE:
{
int botGS = (int)botAI->GetEquipGearScore(bot, false, false);
int fromGS = (int)botAI->GetEquipGearScore(from, false, false);
int diff = (100 * (botGS - fromGS) / botGS);
int req = 12 * sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL) / from->getLevel();
out << "Your gearscore is too low: |cffff0000" << fromGS << "|cffffffff/|cff00ff00" << botGS << " |cffff0000" << diff << "%|cffffffff/|cff00ff00" << req << "%";
}
break;
case PLAYERBOT_DENY_NOT_YOURS:
out << "I have a master already";
break;
case PLAYERBOT_DENY_IS_BOT:
out << "You are a bot";
break;
case PLAYERBOT_DENY_OPPOSING:
out << "You are the enemy";
break;
case PLAYERBOT_DENY_DEAD:
out << "I'm dead. Will do it later";
break;
case PLAYERBOT_DENY_INVITE:
out << "Invite me to your group first";
break;
case PLAYERBOT_DENY_FAR:
{
out << "You must be closer to invite me to your group. I am in ";
if (AreaTableEntry const* entry = sAreaTableStore.LookupEntry(bot->GetAreaId()))
{
out << " |cffffffff(|cffff0000" << entry->area_name[0] << "|cffffffff)";
}
}
break;
case PLAYERBOT_DENY_FULL_GROUP:
out << "I am in a full group. Will do it later";
break;
case PLAYERBOT_DENY_IS_LEADER:
out << "I am currently leading a group. I can invite you if you want.";
break;
case PLAYERBOT_DENY_NOT_LEADER:
out << "I am in a group with " << botAI->GetGroupMaster()->GetName() << ". You can ask him for invite.";
break;
case PLAYERBOT_DENY_BG:
out << "I am in a queue for BG. Will do it later";
break;
case PLAYERBOT_DENY_LFG:
out << "I am in a queue for dungeon. Will do it later";
break;
default:
out << "I can't do that";
break;
}
break;
case PLAYERBOT_SECURITY_INVITE:
out << "Invite me to your group first";
break;
default:
out << "I can't do that";
break;
}
std::string const text = out.str();
ObjectGuid guid = from->GetGUID();
time_t lastSaid = whispers[guid][text];
if (!lastSaid || (time(nullptr) - lastSaid) >= sPlayerbotAIConfig->repeatDelay / 1000)
{
whispers[guid][text] = time(nullptr);
bot->Whisper(text, LANG_UNIVERSAL, from);
}
return false;
}

55
src/PlayerbotSecurity.h Normal file
View File

@ -0,0 +1,55 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#ifndef _PLAYERBOT_PLAYERBOTSECURITY_H
#define _PLAYERBOT_PLAYERBOTSECURITY_H
#include "Common.h"
#include "ObjectGuid.h"
#include <map>
class Player;
enum PlayerbotSecurityLevel : uint32
{
PLAYERBOT_SECURITY_DENY_ALL = 0,
PLAYERBOT_SECURITY_TALK = 1,
PLAYERBOT_SECURITY_INVITE = 2,
PLAYERBOT_SECURITY_ALLOW_ALL = 3
};
enum DenyReason
{
PLAYERBOT_DENY_NONE,
PLAYERBOT_DENY_LOW_LEVEL,
PLAYERBOT_DENY_GEARSCORE,
PLAYERBOT_DENY_NOT_YOURS,
PLAYERBOT_DENY_IS_BOT,
PLAYERBOT_DENY_OPPOSING,
PLAYERBOT_DENY_DEAD,
PLAYERBOT_DENY_FAR,
PLAYERBOT_DENY_INVITE,
PLAYERBOT_DENY_FULL_GROUP,
PLAYERBOT_DENY_NOT_LEADER,
PLAYERBOT_DENY_IS_LEADER,
PLAYERBOT_DENY_BG,
PLAYERBOT_DENY_LFG
};
class PlayerbotSecurity
{
public:
PlayerbotSecurity(Player* const bot);
PlayerbotSecurityLevel LevelFor(Player* from, DenyReason* reason = nullptr, bool ignoreGroup = false);
bool CheckLevelFor(PlayerbotSecurityLevel level, bool silent, Player* from, bool ignoreGroup = false);
private:
Player* const bot;
uint32 account;
std::map<ObjectGuid, std::map<std::string, time_t> > whispers;
};
#endif

49
src/PlayerbotTextMgr.cpp Normal file
View File

@ -0,0 +1,49 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#include "PlayerbotTextMgr.h"
#include "Playerbots.h"
void replaceAll(std::string& str, std::string const from, std::string const to);
void PlayerbotTextMgr::LoadTemplates()
{
LOG_INFO("playerbots", "Loading playerbots texts...");
uint32 count = 0;
if (PreparedQueryResult result = PlayerbotsDatabase.Query(PlayerbotsDatabase.GetPreparedStatement(PLAYERBOTS_SEL_TEXT)))
{
do
{
Field* fields = result->Fetch();
std::string const key = fields[0].Get<std::string>();
std::string const text = fields[1].Get<std::string>();
templates[key].push_back(text);
++count;
}
while (result->NextRow());
}
LOG_INFO("playerbots", "{} playerbots texts loaded", count);
}
std::string const PlayerbotTextMgr::Format(std::string const key, std::map<std::string, std::string> placeholders)
{
if (templates.empty())
LoadTemplates();
std::vector<std::string>& list = templates[key];
if (list.empty())
{
std::ostringstream out;
out << "Unknown text: " << key;
return out.str();
}
std::string str = list[urand(0, list.size() - 1)];
for (std::map<std::string, std::string>::iterator i = placeholders.begin(); i != placeholders.end(); ++i)
replaceAll(str, i->first, i->second);
return str;
}

34
src/PlayerbotTextMgr.h Normal file
View File

@ -0,0 +1,34 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#ifndef _PLAYERBOT_PLAYERBOTTEXTMGR_H
#define _PLAYERBOT_PLAYERBOTTEXTMGR_H
#include "Common.h"
#include <map>
#include <vector>
class PlayerbotTextMgr
{
public:
PlayerbotTextMgr() { };
virtual ~PlayerbotTextMgr() { };
static PlayerbotTextMgr* instance()
{
static PlayerbotTextMgr instance;
return &instance;
}
std::string const Format(std::string const key, std::map<std::string, std::string> placeholders);
private:
void LoadTemplates();
std::map<std::string, std::vector<std::string>> templates;
};
#define sPlayerbotTextMgr PlayerbotTextMgr::instance()
#endif

336
src/Playerbots.cpp Normal file
View File

@ -0,0 +1,336 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "cs_playerbots.h"
#include "Channel.h"
#include "Config.h"
#include "DatabaseEnv.h"
#include "DatabaseLoader.h"
#include "GuildTaskMgr.h"
#include "Metric.h"
#include "Playerbots.h"
#include "RandomPlayerbotMgr.h"
#include "ScriptMgr.h"
class PlayerbotsDatabaseScript : public DatabaseScript
{
public:
PlayerbotsDatabaseScript() : DatabaseScript("PlayerbotsDatabaseScript") { }
bool OnDatabasesLoading() override
{
DatabaseLoader playerbotLoader("server.playerbots");
playerbotLoader.SetUpdateFlags(sConfigMgr->GetOption<bool>("Playerbots.Updates.EnableDatabases", true) ? DatabaseLoader::DATABASE_PLAYERBOTS : 0);
playerbotLoader.AddDatabase(PlayerbotsDatabase, "Playerbots");
return playerbotLoader.Load();
}
void OnDatabasesKeepAlive() override
{
PlayerbotsDatabase.KeepAlive();
}
void OnDatabasesClosing() override
{
PlayerbotsDatabase.Close();
}
void OnDatabaseWarnAboutSyncQueries(bool apply) override
{
PlayerbotsDatabase.WarnAboutSyncQueries(apply);
}
void OnDatabaseSelectIndexLogout(Player* player, uint32& statementIndex, uint32& statementParam) override
{
statementIndex = CHAR_UPD_CHAR_ONLINE;
statementParam = player->GetGUID().GetCounter();
}
void OnDatabaseGetDBRevision(std::string& revision) override
{
if (QueryResult resultPlayerbot = PlayerbotsDatabase.Query("SELECT date FROM version_db_playerbots ORDER BY date DESC LIMIT 1"))
{
Field* fields = resultPlayerbot->Fetch();
revision = fields[0].Get<std::string>();
}
if (revision.empty())
{
revision = "Unknown Playerbots Database Revision";
}
}
};
class PlayerbotsMetricScript : public MetricScript
{
public:
PlayerbotsMetricScript() : MetricScript("PlayerbotsMetricScript") { }
void OnMetricLogging() override
{
if (sMetric->IsEnabled())
{
sMetric->LogValue("db_queue_playerbots", uint64(PlayerbotsDatabase.QueueSize()), {});
}
}
};
class PlayerbotsPlayerScript : public PlayerScript
{
public:
PlayerbotsPlayerScript() : PlayerScript("PlayerbotsPlayerScript") { }
void OnLogin(Player* player) override
{
if (!player->GetSession()->IsBot())
{
sPlayerbotsMgr->AddPlayerbotData(player, false);
sRandomPlayerbotMgr->OnPlayerLogin(player);
}
}
void OnAfterUpdate(Player* player, uint32 diff) override
{
if (PlayerbotAI* botAI = GET_PLAYERBOT_AI(player))
{
botAI->UpdateAI(diff);
}
if (PlayerbotMgr* playerbotMgr = GET_PLAYERBOT_MGR(player))
{
playerbotMgr->UpdateAI(diff);
}
}
bool CanPlayerUseChat(Player* player, uint32 type, uint32 /*lang*/, std::string& msg, Player* receiver) override
{
if (type == CHAT_MSG_WHISPER)
{
if (PlayerbotAI* botAI = GET_PLAYERBOT_AI(receiver))
{
botAI->HandleCommand(type, msg, player);
player->ResetSpeakTimers();
return false;
}
}
return true;
}
void OnChat(Player* player, uint32 type, uint32 /*lang*/, std::string& msg, Group* group) override
{
for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next())
{
if (Player* member = itr->GetSource())
{
if (PlayerbotAI* botAI = GET_PLAYERBOT_AI(member))
{
botAI->HandleCommand(type, msg, player);
player->ResetSpeakTimers();
}
}
}
}
void OnChat(Player* player, uint32 type, uint32 /*lang*/, std::string& msg) override
{
if (type == CHAT_MSG_GUILD)
{
if (PlayerbotMgr* playerbotMgr = GET_PLAYERBOT_MGR(player))
{
for (PlayerBotMap::const_iterator it = playerbotMgr->GetPlayerBotsBegin(); it != playerbotMgr->GetPlayerBotsEnd(); ++it)
{
if (Player* const bot = it->second)
{
if (bot->GetGuildId() == player->GetGuildId())
{
GET_PLAYERBOT_AI(bot)->HandleCommand(type, msg, player);
}
}
}
}
}
}
void OnChat(Player* player, uint32 type, uint32 /*lang*/, std::string& msg, Channel* channel) override
{
if (PlayerbotMgr* playerbotMgr = GET_PLAYERBOT_MGR(player))
{
if (channel->GetFlags() & 0x18)
{
playerbotMgr->HandleCommand(type, msg);
}
}
sRandomPlayerbotMgr->HandleCommand(type, msg, player);
}
};
class PlayerbotsMiscScript : public MiscScript
{
public:
PlayerbotsMiscScript() : MiscScript("PlayerbotsMiscScript") { }
void OnDestructPlayer(Player* player) override
{
if (PlayerbotAI* botAI = GET_PLAYERBOT_AI(player))
{
delete botAI;
}
if (PlayerbotMgr* playerbotMgr = GET_PLAYERBOT_MGR(player))
{
delete playerbotMgr;
}
}
};
class PlayerbotsServerScript : public ServerScript
{
public:
PlayerbotsServerScript() : ServerScript("PlayerbotsServerScript") { }
void OnPacketReceived(WorldSession* session, WorldPacket const& packet) override
{
if (Player* player = session->GetPlayer())
if (PlayerbotMgr* playerbotMgr = GET_PLAYERBOT_MGR(player))
playerbotMgr->HandleMasterIncomingPacket(packet);
}
};
class PlayerbotsWorldScript : public WorldScript
{
public:
PlayerbotsWorldScript() : WorldScript("PlayerbotsWorldScript") { }
void OnBeforeWorldInitialized() override
{
uint32 oldMSTime = getMSTime();
LOG_INFO("server.loading", " ");
LOG_INFO("server.loading", "Load Playerbots Config...");
sPlayerbotAIConfig->Initialize();
LOG_INFO("server.loading", ">> Loaded playerbots config in {} ms", GetMSTimeDiffToNow(oldMSTime));
LOG_INFO("server.loading", " ");
}
};
class PlayerbotsScript : public PlayerbotScript
{
public:
PlayerbotsScript() : PlayerbotScript("PlayerbotsScript") { }
bool OnPlayerbotCheckLFGQueue(lfg::Lfg5Guids const& guidsList) override
{
bool nonBotFound = false;
for (ObjectGuid const& guid : guidsList.guids)
{
Player* player = ObjectAccessor::FindPlayer(guid);
if (guid.IsGroup() || (player && !GET_PLAYERBOT_AI(player)))
{
nonBotFound = true;
break;
}
}
return nonBotFound;
}
void OnPlayerbotCheckKillTask(Player* player, Unit* victim) override
{
if (player)
sGuildTaskMgr->CheckKillTask(player, victim);
}
void OnPlayerbotCheckPetitionAccount(Player* player, bool& found) override
{
if (found && GET_PLAYERBOT_AI(player))
found = false;
}
bool OnPlayerbotCheckUpdatesToSend(Player* player) override
{
if (PlayerbotAI* botAI = GET_PLAYERBOT_AI(player))
return botAI->IsRealPlayer();
return true;
}
void OnPlayerbotPacketSent(Player* player, WorldPacket const* packet) override
{
if (!player)
return;
if (PlayerbotAI* botAI = GET_PLAYERBOT_AI(player))
{
botAI->HandleBotOutgoingPacket(*packet);
}
else if (PlayerbotMgr* playerbotMgr = GET_PLAYERBOT_MGR(player))
{
playerbotMgr->HandleMasterOutgoingPacket(*packet);
}
}
void OnPlayerbotUpdate(uint32 diff) override
{
sRandomPlayerbotMgr->UpdateAI(diff);
sRandomPlayerbotMgr->UpdateSessions();
}
void OnPlayerbotUpdateSessions(Player* player) override
{
if (player)
if (PlayerbotMgr* playerbotMgr = GET_PLAYERBOT_MGR(player))
playerbotMgr->UpdateSessions();
}
void OnPlayerbotLogout(Player* player) override
{
if (PlayerbotMgr* playerbotMgr = GET_PLAYERBOT_MGR(player))
{
PlayerbotAI* botAI = GET_PLAYERBOT_AI(player);
if (!botAI || botAI->IsRealPlayer())
{
playerbotMgr->LogoutAllBots();
}
}
sRandomPlayerbotMgr->OnPlayerLogout(player);
}
void OnPlayerbotLogoutBots() override
{
sRandomPlayerbotMgr->LogoutAllBots();
}
};
void AddPlayerbotsScripts()
{
new PlayerbotsDatabaseScript();
new PlayerbotsMetricScript();
new PlayerbotsPlayerScript();
new PlayerbotsMiscScript();
new PlayerbotsServerScript();
new PlayerbotsWorldScript();
new PlayerbotsScript();
AddSC_playerbots_commandscript();
}

47
src/Playerbots.h Normal file
View File

@ -0,0 +1,47 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#ifndef _PLAYERBOT_H
#define _PLAYERBOT_H
#include "AiObjectContext.h"
#include "Group.h"
#include "Pet.h"
#include "PlayerbotAI.h"
#include "PlayerbotAIConfig.h"
#include "PlayerbotMgr.h"
#include "RandomPlayerbotMgr.h"
#include "SharedValueContext.h"
#include "Spell.h"
#include "TravelNode.h"
std::vector<std::string> split(std::string const s, char delim);
void split(std::vector<std::string>& dest, std::string const str, char const* delim);
#ifndef WIN32
int strcmpi(char const* s1, char const* s2);
#endif
#define CAST_ANGLE_IN_FRONT (2.f * static_cast<float>(M_PI) / 3.f)
#define EMOTE_ANGLE_IN_FRONT (2.f * static_cast<float>(M_PI) / 6.f)
#define GET_PLAYERBOT_AI(object) sPlayerbotsMgr->GetPlayerbotAI(object)
#define GET_PLAYERBOT_MGR(object) sPlayerbotsMgr->GetPlayerbotMgr(object)
#define AI_VALUE(type, name) context->GetValue<type>(name)->Get()
#define AI_VALUE2(type, name, param) context->GetValue<type>(name, param)->Get()
#define AI_VALUE_LAZY(type, name) context->GetValue<type>(name)->LazyGet()
#define AI_VALUE2_LAZY(type, name, param) context->GetValue<type>(name, param)->LazyGet()
#define SET_AI_VALUE(type, name, value) context->GetValue<type>(name)->Set(value)
#define SET_AI_VALUE2(type, name, param, value) context->GetValue<type>(name, param)->Set(value)
#define RESET_AI_VALUE(type, name) context->GetValue<type>(name)->Reset()
#define RESET_AI_VALUE2(type, name, param) context->GetValue<type>(name, param)->Reset()
#define PAI_VALUE(type, name) sPlayerbotsMgr->GetPlayerbotAI(player)->GetAiObjectContext()->GetValue<type>(name)->Get()
#define PAI_VALUE2(type, name, param) sPlayerbotsMgr->GetPlayerbotAI(player)->GetAiObjectContext()->GetValue<type>(name, param)->Get()
#define GAI_VALUE(type, name) sSharedValueContext->getGlobalValue<type>(name)->Get()
#define GAI_VALUE2(type, name, param) sSharedValueContext->getGlobalValue<type>(name, param)->Get()
#endif

2720
src/RandomItemMgr.cpp Normal file

File diff suppressed because it is too large Load Diff

204
src/RandomItemMgr.h Normal file
View File

@ -0,0 +1,204 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#ifndef _PLAYERBOT_RANDOMITEMMGR_H
#define _PLAYERBOT_RANDOMITEMMGR_H
#include "AiFactory.h"
#include "Common.h"
#include "ItemTemplate.h"
#include <map>
#include <set>
#include <vector>
class ChatHandler;
struct ItemTemplate;
enum EquipmentSlots : uint32;
enum RandomItemType
{
RANDOM_ITEM_GUILD_TASK,
RANDOM_ITEM_GUILD_TASK_REWARD_EQUIP_BLUE,
RANDOM_ITEM_GUILD_TASK_REWARD_EQUIP_GREEN,
RANDOM_ITEM_GUILD_TASK_REWARD_TRADE,
RANDOM_ITEM_GUILD_TASK_REWARD_TRADE_RARE
};
#define MAX_STAT_SCALES 32
enum ItemSource
{
ITEM_SOURCE_NONE,
ITEM_SOURCE_DROP,
ITEM_SOURCE_VENDOR,
ITEM_SOURCE_QUEST,
ITEM_SOURCE_CRAFT,
ITEM_SOURCE_PVP
};
struct WeightScaleInfo
{
uint32 id;
std::string name;
};
struct WeightScaleStat
{
std::string stat;
uint32 weight;
};
struct StatWeight
{
uint32 id;
uint32 weight;
};
struct ItemInfoEntry
{
ItemInfoEntry() : minLevel(0), source(0), sourceId(0), team(0), repRank(0), repFaction(0), quality(0), slot(0), itemId(0)
{
for (uint8 i = 1; i <= MAX_STAT_SCALES; ++i)
{
weights[i] = 0;
}
}
std::map<uint32, uint32> weights;
uint32 minLevel;
uint32 source;
uint32 sourceId;
uint32 team;
uint32 repRank;
uint32 repFaction;
uint32 quality;
uint32 slot;
uint32 itemId;
};
typedef std::vector<WeightScaleStat> WeightScaleStats;
//typedef std::map<WeightScaleInfo, WeightScaleStats> WeightScaleList;
struct WeightScale
{
WeightScaleInfo info;
WeightScaleStats stats;
};
//typedef map<uint32, WeightScale> WeightScales;
class RandomItemPredicate
{
public:
virtual ~RandomItemPredicate() { };
virtual bool Apply(ItemTemplate const* proto) = 0;
};
typedef std::vector<uint32> RandomItemList;
typedef std::map<RandomItemType, RandomItemList> RandomItemCache;
class BotEquipKey
{
public:
BotEquipKey() : level(0), clazz(0), slot(0), quality(0), key(GetKey()) { }
BotEquipKey(uint32 level, uint8 clazz, uint8 slot, uint32 quality) : level(level), clazz(clazz), slot(slot), quality(quality), key(GetKey()) { }
BotEquipKey(BotEquipKey const& other) : level(other.level), clazz(other.clazz), slot(other.slot), quality(other.quality), key(GetKey()) { }
bool operator<(BotEquipKey const& other) const
{
return other.key < this->key;
}
uint32 level;
uint8 clazz;
uint8 slot;
uint32 quality;
uint64 key;
private:
uint64 GetKey();
};
typedef std::map<BotEquipKey, RandomItemList> BotEquipCache;
class RandomItemMgr
{
public:
RandomItemMgr();
virtual ~RandomItemMgr();
static RandomItemMgr* instance()
{
static RandomItemMgr instance;
return &instance;
}
public:
void Init();
void InitAfterAhBot();
static bool HandleConsoleCommand(ChatHandler* handler, char const* args);
RandomItemList Query(uint32 level, RandomItemType type, RandomItemPredicate* predicate);
RandomItemList Query(uint32 level, uint8 clazz, uint8 slot, uint32 quality);
uint32 GetUpgrade(Player* player, std::string spec, uint8 slot, uint32 quality, uint32 itemId);
std::vector<uint32> GetUpgradeList(Player* player, std::string spec, uint8 slot, uint32 quality, uint32 itemId, uint32 amount = 1);
bool HasStatWeight(uint32 itemId);
uint32 GetMinLevelFromCache(uint32 itemId);
uint32 GetStatWeight(Player* player, uint32 itemId);
uint32 GetLiveStatWeight(Player* player, uint32 itemId);
uint32 GetRandomItem(uint32 level, RandomItemType type, RandomItemPredicate* predicate = nullptr);
uint32 GetAmmo(uint32 level, uint32 subClass);
uint32 GetRandomPotion(uint32 level, uint32 effect);
uint32 GetRandomFood(uint32 level, uint32 category);
uint32 GetFood(uint32 level, uint32 category);
uint32 GetRandomTrade(uint32 level);
uint32 CalculateStatWeight(uint8 playerclass, uint8 spec, ItemTemplate const* proto);
uint32 CalculateSingleStatWeight(uint8 playerclass, uint8 spec, std::string stat, uint32 value);
bool CanEquipArmor(uint8 clazz, uint32 level, ItemTemplate const* proto);
bool ShouldEquipArmorForSpec(uint8 playerclass, uint8 spec, ItemTemplate const* proto);
bool CanEquipWeapon(uint8 clazz, ItemTemplate const* proto);
bool ShouldEquipWeaponForSpec(uint8 playerclass, uint8 spec, ItemTemplate const* proto);
float GetItemRarity(uint32 itemId);
uint32 GetQuestIdForItem(uint32 itemId);
std::vector<uint32> GetQuestIdsForItem(uint32 itemId);
static bool IsUsedBySkill(ItemTemplate const* proto, uint32 skillId);
private:
void BuildRandomItemCache();
void BuildEquipCache();
void BuildItemInfoCache();
void BuildAmmoCache();
void BuildFoodCache();
void BuildPotionCache();
void BuildTradeCache();
void BuildRarityCache();
bool CanEquipItem(BotEquipKey key, ItemTemplate const* proto);
bool CanEquipItemNew(ItemTemplate const* proto);
void AddItemStats(uint32 mod, uint8& sp, uint8& ap, uint8& tank);
bool CheckItemStats(uint8 clazz, uint8 sp, uint8 ap, uint8 tank);
private:
std::map<uint32, RandomItemCache> randomItemCache;
std::map<RandomItemType, RandomItemPredicate*> predicates;
BotEquipCache equipCache;
std::map<EquipmentSlots, std::set<InventoryType>> viableSlots;
std::map<uint32, std::map<uint32, uint32> > ammoCache;
std::map<uint32, std::map<uint32, std::vector<uint32> > > potionCache;
std::map<uint32, std::map<uint32, std::vector<uint32> > > foodCache;
std::map<uint32, std::vector<uint32> > tradeCache;
std::map<uint32, float> rarityCache;
std::map<uint8, WeightScale> m_weightScales[MAX_CLASSES];
std::map<std::string, uint32 > weightStatLink;
std::map<std::string, uint32 > weightRatingLink;
std::map<uint32, ItemInfoEntry> itemInfoCache;
static std::set<uint32> itemCache;
};
#define sRandomItemMgr RandomItemMgr::instance()
#endif

View File

@ -0,0 +1,731 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#include "RandomPlayerbotFactory.h"
#include "ArenaTeamMgr.h"
#include "AccountMgr.h"
#include "GuildMgr.h"
#include "Playerbots.h"
#include "PlayerbotFactory.h"
#include "SocialMgr.h"
std::map<uint8, std::vector<uint8>> RandomPlayerbotFactory::availableRaces;
RandomPlayerbotFactory::RandomPlayerbotFactory(uint32 accountId) : accountId(accountId)
{
availableRaces[CLASS_WARRIOR].push_back(RACE_HUMAN);
availableRaces[CLASS_WARRIOR].push_back(RACE_NIGHTELF);
availableRaces[CLASS_WARRIOR].push_back(RACE_GNOME);
availableRaces[CLASS_WARRIOR].push_back(RACE_DWARF);
availableRaces[CLASS_WARRIOR].push_back(RACE_ORC);
availableRaces[CLASS_WARRIOR].push_back(RACE_UNDEAD_PLAYER);
availableRaces[CLASS_WARRIOR].push_back(RACE_TAUREN);
availableRaces[CLASS_WARRIOR].push_back(RACE_TROLL);
availableRaces[CLASS_WARRIOR].push_back(RACE_DRAENEI);
availableRaces[CLASS_PALADIN].push_back(RACE_HUMAN);
availableRaces[CLASS_PALADIN].push_back(RACE_DWARF);
availableRaces[CLASS_PALADIN].push_back(RACE_DRAENEI);
availableRaces[CLASS_PALADIN].push_back(RACE_BLOODELF);
availableRaces[CLASS_ROGUE].push_back(RACE_HUMAN);
availableRaces[CLASS_ROGUE].push_back(RACE_DWARF);
availableRaces[CLASS_ROGUE].push_back(RACE_NIGHTELF);
availableRaces[CLASS_ROGUE].push_back(RACE_GNOME);
availableRaces[CLASS_ROGUE].push_back(RACE_ORC);
availableRaces[CLASS_ROGUE].push_back(RACE_TROLL);
availableRaces[CLASS_ROGUE].push_back(RACE_BLOODELF);
availableRaces[CLASS_PRIEST].push_back(RACE_HUMAN);
availableRaces[CLASS_PRIEST].push_back(RACE_DWARF);
availableRaces[CLASS_PRIEST].push_back(RACE_NIGHTELF);
availableRaces[CLASS_PRIEST].push_back(RACE_TROLL);
availableRaces[CLASS_PRIEST].push_back(RACE_UNDEAD_PLAYER);
availableRaces[CLASS_PRIEST].push_back(RACE_DRAENEI);
availableRaces[CLASS_PRIEST].push_back(RACE_BLOODELF);
availableRaces[CLASS_MAGE].push_back(RACE_HUMAN);
availableRaces[CLASS_MAGE].push_back(RACE_GNOME);
availableRaces[CLASS_MAGE].push_back(RACE_UNDEAD_PLAYER);
availableRaces[CLASS_MAGE].push_back(RACE_TROLL);
availableRaces[CLASS_MAGE].push_back(RACE_DRAENEI);
availableRaces[CLASS_MAGE].push_back(RACE_BLOODELF);
availableRaces[CLASS_WARLOCK].push_back(RACE_HUMAN);
availableRaces[CLASS_WARLOCK].push_back(RACE_GNOME);
availableRaces[CLASS_WARLOCK].push_back(RACE_UNDEAD_PLAYER);
availableRaces[CLASS_WARLOCK].push_back(RACE_ORC);
availableRaces[CLASS_WARLOCK].push_back(RACE_BLOODELF);
availableRaces[CLASS_SHAMAN].push_back(RACE_ORC);
availableRaces[CLASS_SHAMAN].push_back(RACE_TAUREN);
availableRaces[CLASS_SHAMAN].push_back(RACE_TROLL);
availableRaces[CLASS_SHAMAN].push_back(RACE_DRAENEI);
availableRaces[CLASS_HUNTER].push_back(RACE_DWARF);
availableRaces[CLASS_HUNTER].push_back(RACE_NIGHTELF);
availableRaces[CLASS_HUNTER].push_back(RACE_ORC);
availableRaces[CLASS_HUNTER].push_back(RACE_TAUREN);
availableRaces[CLASS_HUNTER].push_back(RACE_TROLL);
availableRaces[CLASS_HUNTER].push_back(RACE_DRAENEI);
availableRaces[CLASS_HUNTER].push_back(RACE_BLOODELF);
availableRaces[CLASS_DRUID].push_back(RACE_NIGHTELF);
availableRaces[CLASS_DRUID].push_back(RACE_TAUREN);
availableRaces[CLASS_DEATH_KNIGHT].push_back(RACE_NIGHTELF);
availableRaces[CLASS_DEATH_KNIGHT].push_back(RACE_TAUREN);
availableRaces[CLASS_DEATH_KNIGHT].push_back(RACE_HUMAN);
availableRaces[CLASS_DEATH_KNIGHT].push_back(RACE_ORC);
availableRaces[CLASS_DEATH_KNIGHT].push_back(RACE_UNDEAD_PLAYER);
availableRaces[CLASS_DEATH_KNIGHT].push_back(RACE_TROLL);
availableRaces[CLASS_DEATH_KNIGHT].push_back(RACE_BLOODELF);
availableRaces[CLASS_DEATH_KNIGHT].push_back(RACE_DRAENEI);
availableRaces[CLASS_DEATH_KNIGHT].push_back(RACE_GNOME);
availableRaces[CLASS_DEATH_KNIGHT].push_back(RACE_DWARF);
}
Player* RandomPlayerbotFactory::CreateRandomBot(WorldSession* session, uint8 cls, std::unordered_map<uint8, std::vector<std::string>> names)
{
LOG_DEBUG("playerbots", "Creating new random bot for class {}", cls);
uint8 gender = rand() % 2 ? GENDER_MALE : GENDER_FEMALE;
uint8 race = availableRaces[cls][urand(0, availableRaces[cls].size() - 1)];
std::string name;
if (names.empty())
name = CreateRandomBotName(gender);
else
{
if (names[gender].empty())
return nullptr;
uint32 i = urand(0, names[gender].size() - 1);
name = names[gender][i];
std::swap(names[gender][i], names[gender].back());
names[gender].pop_back();
}
if (name.empty())
return nullptr;
std::vector<uint8> skinColors, facialHairTypes;
std::vector<std::pair<uint8,uint8>> faces, hairs;
for (CharSectionsEntry const* charSection : sCharSectionsStore)
{
if (charSection->Race != race || charSection->Gender != gender)
continue;
switch (charSection->GenType)
{
case SECTION_TYPE_SKIN:
skinColors.push_back(charSection->Color);
break;
case SECTION_TYPE_FACE:
faces.push_back(std::pair<uint8, uint8>(charSection->Type, charSection->Color));
break;
case SECTION_TYPE_FACIAL_HAIR:
facialHairTypes.push_back(charSection->Type);
break;
case SECTION_TYPE_HAIR:
hairs.push_back(std::pair<uint8, uint8>(charSection->Type, charSection->Color));
break;
}
}
uint8 skinColor = skinColors[urand(0, skinColors.size() - 1)];
std::pair<uint8, uint8> face = faces[urand(0, faces.size() - 1)];
std::pair<uint8, uint8> hair = hairs[urand(0, hairs.size() - 1)];
bool excludeCheck = (race == RACE_TAUREN) || (race == RACE_DRAENEI) || (gender == GENDER_FEMALE && race != RACE_NIGHTELF && race != RACE_UNDEAD_PLAYER);
uint8 facialHair = excludeCheck ? 0 : facialHairTypes[urand(0, facialHairTypes.size() - 1)];
std::unique_ptr<CharacterCreateInfo> characterInfo = std::make_unique<CharacterCreateInfo>(name, race, cls, gender, face.second, face.first, hair.first, hair.second, facialHair);
Player* player = new Player(session);
player->GetMotionMaster()->Initialize();
if (!player->Create(sObjectMgr->GetGenerator<HighGuid::Player>().Generate(), characterInfo.get()))
{
player->CleanupsBeforeDelete();
delete player;
LOG_ERROR("playerbots", "Unable to create random bot for account {} - name: \"{}\"; race: {}; class: {}", accountId, name.c_str(), race, cls);
return nullptr;
}
player->setCinematic(2);
player->SetAtLoginFlag(AT_LOGIN_NONE);
LOG_DEBUG("playerbots", "Random bot created for account {} - name: \"{}\"; race: {}; class: {}", accountId, name.c_str(), race, cls);
return player;
}
std::string const RandomPlayerbotFactory::CreateRandomBotName(uint8 gender)
{
std::string botName = "";
QueryResult result = CharacterDatabase.Query("SELECT MAX(name_id) FROM playerbots_names");
if (!result)
{
LOG_ERROR("playerbots", "No more names left for random bots");
return std::move(botName);
}
Field* fields = result->Fetch();
uint32 maxId = fields[0].Get<uint32>();
result = CharacterDatabase.Query("SELECT n.name FROM playerbots_names n "
"LEFT OUTER JOIN characters e ON e.name = n.name WHERE e.guid IS NULL AND n.gender = {} ORDER BY RAND() LIMIT 1", gender);
if (!result)
{
LOG_ERROR("playerbots", "No more names left for random bots");
return std::move(botName);
}
fields = result->Fetch();
botName = fields[0].Get<std::string>();
return std::move(botName);
}
void RandomPlayerbotFactory::CreateRandomBots()
{
// check if scheduled for delete
bool delAccs = false;
bool delFriends = false;
PlayerbotsDatabasePreparedStatement* stmt = PlayerbotsDatabase.GetPreparedStatement(PLAYERBOTS_SEL_RANDOM_BOTS_VALUE);
stmt->SetData(0, "bot_delete");
if (PreparedQueryResult result = PlayerbotsDatabase.Query(stmt))
{
delAccs = true;
Field* fields = result->Fetch();
uint32 deleteType = fields[0].Get<uint32>();
if (deleteType > 1)
delFriends = true;
PlayerbotsDatabase.Execute("DELETE FROM playerbots_random_bots WHERE event = 'bot_delete'");
}
if (sPlayerbotAIConfig->deleteRandomBotAccounts || delAccs)
{
std::vector<uint32> botAccounts;
std::vector<uint32> botFriends;
for (uint32 accountNumber = 0; accountNumber < sPlayerbotAIConfig->randomBotAccountCount; ++accountNumber)
{
std::ostringstream out;
out << sPlayerbotAIConfig->randomBotAccountPrefix << accountNumber;
std::string const accountName = out.str();
if (uint32 accountId = AccountMgr::GetId(accountName))
botAccounts.push_back(accountId);
}
if (!delFriends)
LOG_INFO("playerbots", "Deleting random bot characters without friends/guild...");
else
LOG_INFO("playerbots", "Deleting all random bot characters...");
// load list of friends
if (!delFriends)
{
QueryResult result = CharacterDatabase.Query("SELECT friend FROM character_social WHERE flags={}", SOCIAL_FLAG_FRIEND);
if (result)
{
do
{
Field* fields = result->Fetch();
uint32 guidlow = fields[0].Get<uint32>();
botFriends.push_back(guidlow);
} while (result->NextRow());
}
}
std::vector<std::future<void>> dels;
QueryResult results = LoginDatabase.Query("SELECT id FROM account WHERE username LIKE ''{}'%%'", sPlayerbotAIConfig->randomBotAccountPrefix.c_str());
if (results)
{
do
{
Field* fields = results->Fetch();
uint32 accId = fields[0].Get<uint32>();
if (!delFriends)
{
// existing characters list
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARS_BY_ACCOUNT_ID);
stmt->SetData(0, accId);
if (PreparedQueryResult result = CharacterDatabase.Query(stmt))
{
do
{
Field* fields = result->Fetch();
uint32 guidlow = fields[0].Get<uint32>();
ObjectGuid guid = ObjectGuid::Create<HighGuid::Player>(guidlow);
// if bot is someone's friend - don't delete it
if ((find(botFriends.begin(), botFriends.end(), guidlow) != botFriends.end()) && !delFriends)
continue;
// if bot is in someone's guild - don't delete it
uint32 guildId = sCharacterCache->GetCharacterGuildIdByGuid(guid);
if (guildId && !delFriends)
{
Guild* guild = sGuildMgr->GetGuildById(guildId);
uint32 accountId = sRandomPlayerbotMgr->GetAccountId(guild->GetLeaderGUID());
if (find(botAccounts.begin(), botAccounts.end(), accountId) == botAccounts.end())
continue;
}
Player::DeleteFromDB(guidlow, accId, false, true); // no need to update realm characters
} while (result->NextRow());
}
}
else
dels.push_back(std::async([accId]
{
AccountMgr::DeleteAccount(accId);
}));
} while (results->NextRow());
}
for (uint32 i = 0; i < dels.size(); i++)
{
dels[i].wait();
}
PlayerbotsDatabase.Execute(PlayerbotsDatabase.GetPreparedStatement(PLAYERBOTS_DEL_RANDOM_BOTS));
LOG_INFO("playerbots", "Random bot characters deleted");
}
uint32 totalAccCount = sPlayerbotAIConfig->randomBotAccountCount;
LOG_INFO("server.loading", "Creating random bot accounts...");
std::vector<std::future<void>> account_creations;
for (uint32 accountNumber = 0; accountNumber < sPlayerbotAIConfig->randomBotAccountCount; ++accountNumber)
{
std::ostringstream out;
out << sPlayerbotAIConfig->randomBotAccountPrefix << accountNumber;
std::string const accountName = out.str();
LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_GET_ACCOUNT_ID_BY_USERNAME);
stmt->SetData(0, accountName);
PreparedQueryResult result = LoginDatabase.Query(stmt);
if (result)
{
continue;
}
std::string password = "";
if (sPlayerbotAIConfig->randomBotRandomPassword)
{
for (int i = 0; i < 10; i++)
{
password += (char) urand('!', 'z');
}
}
else
password = accountName;
account_creations.push_back(std::async([accountName, password]
{
AccountMgr::CreateAccount(accountName, password);
}));
LOG_DEBUG("playerbots", "Account {} created for random bots", accountName.c_str());
}
for (uint32 i = 0; i < account_creations.size(); i++)
{
account_creations[i].wait();
}
//LoginDatabase.Execute("UPDATE account SET expansion = {} WHERE username LIKE ''{}'%%'", EXPANSION_WRATH_OF_THE_LICH_KING, sPlayerbotAIConfig->randomBotAccountPrefix.c_str());
LOG_INFO("server.loading", "Loading available names...");
std::unordered_map<uint8,std::vector<std::string>> names;
QueryResult result = CharacterDatabase.Query("SELECT n.gender, n.name FROM playerbots_names n LEFT OUTER JOIN characters e ON e.name = n.name WHERE e.guid IS NULL");
if (!result)
{
LOG_ERROR("server.loading", "No more names left for random bots");
return;
}
do
{
Field* fields = result->Fetch();
uint8 gender = fields[0].Get<uint8>();
std::string const bname = fields[1].Get<std::string>();
names[gender].push_back(bname);
} while (result->NextRow());
LOG_INFO("playerbots", "Creating random bot characters...");
uint32 totalRandomBotChars = 0;
uint32 totalCharCount = sPlayerbotAIConfig->randomBotAccountCount * 10;
std::vector<std::pair<Player*, uint32>> playerBots;
std::vector<WorldSession*> sessionBots;
for (uint32 accountNumber = 0; accountNumber < sPlayerbotAIConfig->randomBotAccountCount; ++accountNumber)
{
std::ostringstream out;
out << sPlayerbotAIConfig->randomBotAccountPrefix << accountNumber;
std::string const accountName = out.str();
LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_GET_ACCOUNT_ID_BY_USERNAME);
stmt->SetData(0, accountName);
PreparedQueryResult result = LoginDatabase.Query(stmt);
if (!result)
continue;
Field* fields = result->Fetch();
uint32 accountId = fields[0].Get<uint32>();
sPlayerbotAIConfig->randomBotAccounts.push_back(accountId);
uint32 count = AccountMgr::GetCharactersCount(accountId);
if (count >= 10)
{
totalRandomBotChars += count;
continue;
}
RandomPlayerbotFactory factory(accountId);
WorldSession* session = new WorldSession(accountId, "", nullptr, SEC_PLAYER, EXPANSION_WRATH_OF_THE_LICH_KING, time_t(0), LOCALE_enUS, 0, false, false, 0, true);
sessionBots.push_back(session);
for (uint8 cls = CLASS_WARRIOR; cls < MAX_CLASSES - count; ++cls)
{
if (cls != 10)
if (Player* playerBot = factory.CreateRandomBot(session, cls, names))
playerBots.emplace_back(playerBot, accountId);
}
totalRandomBotChars += AccountMgr::GetCharactersCount(accountId);
}
std::vector<std::future<void>> bot_creations;
for (auto const& itr : playerBots)
{
Player* player = itr.first;
uint32 accountId = itr.second;
bot_creations.push_back(std::async([player, accountId]
{
player->SaveToDB(true, false);
sCharacterCache->AddCharacterCacheEntry(player->GetGUID(), accountId, player->GetName(), player->getGender(), player->getRace(), player->getClass(), player->getLevel());
player->CleanupsBeforeDelete();
delete player;
}));
}
for (uint32 i = 0; i < bot_creations.size(); i++)
{
bot_creations[i].wait();
}
for (WorldSession* session : sessionBots)
delete session;
LOG_INFO("server.loading", "{} random bot accounts with {} characters available", sPlayerbotAIConfig->randomBotAccounts.size(), totalRandomBotChars);
}
void RandomPlayerbotFactory::CreateRandomGuilds()
{
std::vector<uint32> randomBots;
PlayerbotsDatabasePreparedStatement* stmt = PlayerbotsDatabase.GetPreparedStatement(PLAYERBOTS_SEL_RANDOM_BOTS_BOT);
stmt->SetData(0, "add");
if (PreparedQueryResult result = PlayerbotsDatabase.Query(stmt))
{
do
{
Field* fields = result->Fetch();
uint32 bot = fields[0].Get<uint32>();
randomBots.push_back(bot);
}
while (result->NextRow());
}
if (sPlayerbotAIConfig->deleteRandomBotGuilds)
{
LOG_INFO("playerbots", "Deleting random bot guilds...");
for (std::vector<uint32>::iterator i = randomBots.begin(); i != randomBots.end(); ++i)
{
if (Guild* guild = sGuildMgr->GetGuildByLeader(ObjectGuid::Create<HighGuid::Player>(*i)))
guild->Disband();
}
LOG_INFO("playerbots", "Random bot guilds deleted");
}
uint32 guildNumber = 0;
GuidVector availableLeaders;
for (std::vector<uint32>::iterator i = randomBots.begin(); i != randomBots.end(); ++i)
{
ObjectGuid leader = ObjectGuid::Create<HighGuid::Player>(*i);
if (Guild* guild = sGuildMgr->GetGuildByLeader(leader))
{
++guildNumber;
sPlayerbotAIConfig->randomBotGuilds.push_back(guild->GetId());
}
else
{
Player* player = ObjectAccessor::FindPlayer(leader);
if (player && !player->GetGuildId())
availableLeaders.push_back(leader);
}
}
for (; guildNumber < sPlayerbotAIConfig->randomBotGuildCount; ++guildNumber)
{
std::string const guildName = CreateRandomGuildName();
if (guildName.empty())
continue;
if (availableLeaders.empty())
{
LOG_ERROR("playerbots", "No leaders for random guilds available");
continue;
}
uint32 index = urand(0, availableLeaders.size() - 1);
ObjectGuid leader = availableLeaders[index];
Player* player = ObjectAccessor::FindPlayer(leader);
if (!player)
{
LOG_ERROR("playerbots", "Cannot find player for leader {}", player->GetName().c_str());
continue;
}
Guild* guild = new Guild();
if (!guild->Create(player, guildName))
{
LOG_ERROR("playerbots", "Error creating guild {}", guildName.c_str());
delete guild;
continue;
}
sGuildMgr->AddGuild(guild);
// create random emblem
uint32 st, cl, br, bc, bg;
bg = urand(0, 51);
bc = urand(0, 17);
cl = urand(0, 17);
br = urand(0, 7);
st = urand(0, 180);
EmblemInfo emblemInfo(st, cl, br, bc, bg);
guild->HandleSetEmblem(emblemInfo);
sPlayerbotAIConfig->randomBotGuilds.push_back(guild->GetId());
}
LOG_INFO("playerbots", "{} random bot guilds available", guildNumber);
}
std::string const RandomPlayerbotFactory::CreateRandomGuildName()
{
std::string guildName = "";
QueryResult result = CharacterDatabase.Query("SELECT MAX(name_id) FROM playerbots_guild_names");
if (!result)
{
LOG_ERROR("playerbots", "No more names left for random guilds");
return std::move(guildName);
}
Field* fields = result->Fetch();
uint32 maxId = fields[0].Get<uint32>();
uint32 id = urand(0, maxId);
result = CharacterDatabase.Query("SELECT n.name FROM playerbots_guild_names n "
"LEFT OUTER JOIN guild e ON e.name = n.name WHERE e.guildid IS NULL AND n.name_id >= {} LIMIT 1", id);
if (!result)
{
LOG_ERROR("playerbots", "No more names left for random guilds");
return std::move(guildName);
}
fields = result->Fetch();
guildName = fields[0].Get<std::string>();
return std::move(guildName);
}
void RandomPlayerbotFactory::CreateRandomArenaTeams()
{
std::vector<uint32> randomBots;
PlayerbotsDatabasePreparedStatement* stmt = PlayerbotsDatabase.GetPreparedStatement(PLAYERBOTS_SEL_RANDOM_BOTS_BOT);
stmt->SetData(0, "add");
if (PreparedQueryResult result = PlayerbotsDatabase.Query(stmt))
{
do
{
Field* fields = result->Fetch();
uint32 bot = fields[0].Get<uint32>();
randomBots.push_back(bot);
}
while (result->NextRow());
}
if (sPlayerbotAIConfig->deleteRandomBotArenaTeams)
{
LOG_INFO("playerbots", "Deleting random bot arena teams...");
for (std::vector<uint32>::iterator i = randomBots.begin(); i != randomBots.end(); ++i)
{
ObjectGuid captain = ObjectGuid::Create<HighGuid::Player>(*i);
ArenaTeam* arenateam = sArenaTeamMgr->GetArenaTeamByCaptain(captain);
if (arenateam)
//sObjectMgr->RemoveArenaTeam(arenateam->GetId());
arenateam->Disband(nullptr);
}
LOG_INFO("playerbots", "Random bot arena teams deleted");
}
uint32 arenaTeamNumber = 0;
GuidVector availableCaptains;
for (std::vector<uint32>::iterator i = randomBots.begin(); i != randomBots.end(); ++i)
{
ObjectGuid captain = ObjectGuid::Create<HighGuid::Player>(*i);
ArenaTeam* arenateam = sArenaTeamMgr->GetArenaTeamByCaptain(captain);
if (arenateam)
{
++arenaTeamNumber;
sPlayerbotAIConfig->randomBotArenaTeams.push_back(arenateam->GetId());
}
else
{
Player* player = ObjectAccessor::FindConnectedPlayer(captain);
if (!arenateam && player && player->getLevel() >= 70)
availableCaptains.push_back(captain);
}
}
for (; arenaTeamNumber < sPlayerbotAIConfig->randomBotArenaTeamCount; ++arenaTeamNumber)
{
std::string const arenaTeamName = CreateRandomArenaTeamName();
if (arenaTeamName.empty())
continue;
if (availableCaptains.empty())
{
LOG_ERROR("playerbots", "No captains for random arena teams available");
continue;
}
uint32 index = urand(0, availableCaptains.size() - 1);
ObjectGuid captain = availableCaptains[index];
Player* player = ObjectAccessor::FindConnectedPlayer(captain);
if (!player)
{
LOG_ERROR("playerbots", "Cannot find player for captain {}", captain.ToString().c_str());
continue;
}
if (player->getLevel() < 70)
{
LOG_ERROR("playerbots", "Bot {} must be level 70 to create an arena team", captain.ToString().c_str());
continue;
}
QueryResult results = CharacterDatabase.Query("SELECT `type` FROM playerbots_arena_team_names WHERE name = '{}'", arenaTeamName.c_str());
if (!results)
{
LOG_ERROR("playerbots", "No valid types for arena teams");
return;
}
Field* fields = results->Fetch();
uint8 slot = fields[0].Get<uint8>();
ArenaType type;
switch (slot)
{
case 2:
type = ARENA_TYPE_2v2;
break;
case 3:
type = ARENA_TYPE_3v3;
break;
case 5:
type = ARENA_TYPE_5v5;
break;
}
ArenaTeam* arenateam = new ArenaTeam();
if (!arenateam->Create(player->GetGUID(), type, arenaTeamName, 0, 0, 0, 0, 0))
{
LOG_ERROR("playerbots", "Error creating arena team {}", arenaTeamName.c_str());
continue;
}
arenateam->SetCaptain(player->GetGUID());
// set random rating
arenateam->SetRatingForAll(urand(1500, 2700));
// set random emblem
uint32 backgroundColor = urand(0xFF000000, 0xFFFFFFFF);
uint32 emblemStyle = urand(0, 5);
uint32 emblemColor = urand(0xFF000000, 0xFFFFFFFF);
uint32 borderStyle = urand(0, 5);
uint32 borderColor = urand(0xFF000000, 0xFFFFFFFF);
arenateam->SetEmblem(backgroundColor, emblemStyle, emblemColor, borderStyle, borderColor);
// set random kills (wip)
//arenateam->SetStats(STAT_TYPE_GAMES_WEEK, urand(0, 30));
//arenateam->SetStats(STAT_TYPE_WINS_WEEK, urand(0, arenateam->GetStats().games_week));
//arenateam->SetStats(STAT_TYPE_GAMES_SEASON, urand(arenateam->GetStats().games_week, arenateam->GetStats().games_week * 5));
//arenateam->SetStats(STAT_TYPE_WINS_SEASON, urand(arenateam->GetStats().wins_week, arenateam->GetStats().games
arenateam->SaveToDB();
sArenaTeamMgr->AddArenaTeam(arenateam);
sPlayerbotAIConfig->randomBotArenaTeams.push_back(arenateam->GetId());
}
LOG_INFO("playerbots", "{} random bot arena teams available", arenaTeamNumber);
}
std::string const RandomPlayerbotFactory::CreateRandomArenaTeamName()
{
std::string arenaTeamName = "";
QueryResult result = CharacterDatabase.Query("SELECT MAX(name_id) FROM playerbots_arena_team_names");
if (!result)
{
LOG_ERROR("playerbots", "No more names left for random arena teams");
return std::move(arenaTeamName);
}
Field* fields = result->Fetch();
uint32 maxId = fields[0].Get<uint32>();
uint32 id = urand(0, maxId);
result = CharacterDatabase.Query("SELECT n.name FROM playerbots_arena_team_names n LEFT OUTER JOIN arena_team e ON e.name = n.name "
"WHERE e.arenateamid IS NULL AND n.name_id >= {} LIMIT 1", id);
if (!result)
{
LOG_ERROR("playerbots", "No more names left for random arena teams");
return std::move(arenaTeamName);
}
fields = result->Fetch();
arenaTeamName = fields[0].Get<std::string>();
return std::move(arenaTeamName);
}

View File

@ -0,0 +1,36 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#ifndef _PLAYERBOT_RANDOMPLAYERBOTFACTORY_H
#define _PLAYERBOT_RANDOMPLAYERBOTFACTORY_H
#include "Common.h"
#include <map>
#include <unordered_map>
class Player;
class WorldSession;
class RandomPlayerbotFactory
{
public:
RandomPlayerbotFactory(uint32 accountId);
virtual ~RandomPlayerbotFactory() { }
Player* CreateRandomBot(WorldSession* session, uint8 cls, std::unordered_map<uint8, std::vector<std::string>> names);
static void CreateRandomBots();
static void CreateRandomGuilds();
static void CreateRandomArenaTeams();
static std::string const CreateRandomGuildName();
private:
std::string const CreateRandomBotName(uint8 gender);
static std::string const CreateRandomArenaTeamName();
uint32 accountId;
static std::map<uint8, std::vector<uint8>> availableRaces;
};
#endif

2242
src/RandomPlayerbotMgr.cpp Normal file

File diff suppressed because it is too large Load Diff

134
src/RandomPlayerbotMgr.h Normal file
View File

@ -0,0 +1,134 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#ifndef _PLAYERBOT_RANDOMPLAYERBOTMGR_H
#define _PLAYERBOT_RANDOMPLAYERBOTMGR_H
#include "PlayerbotMgr.h"
class ChatHandler;
class PerformanceMonitorOperation;
class WorldLocation;
class CachedEvent
{
public:
CachedEvent() : value(0), lastChangeTime(0), validIn(0), data("") { }
CachedEvent(const CachedEvent& other) : value(other.value), lastChangeTime(other.lastChangeTime), validIn(other.validIn), data(other.data) { }
CachedEvent(uint32 value, uint32 lastChangeTime, uint32 validIn, std::string const data = "") : value(value), lastChangeTime(lastChangeTime), validIn(validIn), data(data) { }
bool IsEmpty() { return !lastChangeTime; }
public:
uint32 value;
uint32 lastChangeTime;
uint32 validIn;
std::string data;
};
class RandomPlayerbotMgr : public PlayerbotHolder
{
public:
RandomPlayerbotMgr();
virtual ~RandomPlayerbotMgr();
static RandomPlayerbotMgr* instance()
{
static RandomPlayerbotMgr instance;
return &instance;
}
void LogPlayerLocation();
void UpdateAIInternal(uint32 elapsed, bool minimal = false) override;
public:
uint32 activeBots = 0;
static bool HandlePlayerbotConsoleCommand(ChatHandler* handler, char const* args);
bool IsRandomBot(Player* bot);
bool IsRandomBot(ObjectGuid::LowType bot);
void Randomize(Player* bot);
void RandomizeFirst(Player* bot);
void IncreaseLevel(Player* bot);
void ScheduleTeleport(uint32 bot, uint32 time = 0);
void ScheduleChangeStrategy(uint32 bot, uint32 time = 0);
void HandleCommand(uint32 type, std::string const text, Player* fromPlayer);
std::string const HandleRemoteCommand(std::string const request);
void OnPlayerLogout(Player* player);
void OnPlayerLogin(Player* player);
void OnPlayerLoginError(uint32 bot);
Player* GetRandomPlayer();
std::vector<Player*> GetPlayers() { return players; };
PlayerBotMap GetAllBots() { return playerBots; };
void PrintStats();
double GetBuyMultiplier(Player* bot);
double GetSellMultiplier(Player* bot);
void AddTradeDiscount(Player* bot, Player* master, int32 value);
void SetTradeDiscount(Player* bot, Player* master, uint32 value);
uint32 GetTradeDiscount(Player* bot, Player* master);
void Refresh(Player* bot);
void RandomTeleportForLevel(Player* bot);
void RandomTeleportForRpg(Player* bot);
uint32 GetMaxAllowedBotCount();
bool ProcessBot(Player* player);
void Revive(Player* player);
void ChangeStrategy(Player* player);
uint32 GetValue(Player* bot, std::string const type);
uint32 GetValue(uint32 bot, std::string const type);
std::string const GetData(uint32 bot, std::string const type);
void SetValue(uint32 bot, std::string const type, uint32 value, std::string const data = "");
void SetValue(Player* bot, std::string const type, uint32 value, std::string const data = "");
void Remove(Player* bot);
ObjectGuid const GetBattleMasterGUID(Player* bot, BattlegroundTypeId bgTypeId);
CreatureData const* GetCreatureDataByEntry(uint32 entry);
void LoadBattleMastersCache();
std::map<uint32, std::map<uint32, std::map<TeamId, bool>>> NeedBots;
std::map<uint32, std::map<uint32, std::map<TeamId, uint32>>> BgBots;
std::map<uint32, std::map<uint32, std::map<TeamId, uint32>>> VisualBots;
std::map<uint32, std::map<uint32, std::map<TeamId, uint32>>> BgPlayers;
std::map<uint32, std::map<uint32, std::map<TeamId, std::map<TeamId, uint32>>>> ArenaBots;
std::map<uint32, std::map<uint32, std::map<uint32, uint32>>> Rating;
std::map<uint32, std::map<uint32, std::map<uint32, uint32>>> Supporters;
std::map<TeamId, std::vector<uint32>> LfgDungeons;
void CheckBgQueue();
void CheckLfgQueue();
void CheckPlayers();
std::map<TeamId, std::map<BattlegroundTypeId, std::vector<uint32>>> getBattleMastersCache() { return BattleMastersCache; }
protected:
void OnBotLoginInternal(Player* const bot) override;
private:
uint32 GetEventValue(uint32 bot, std::string const event);
std::string const GetEventData(uint32 bot, std::string const event);
uint32 SetEventValue(uint32 bot, std::string const event, uint32 value, uint32 validIn, std::string const data = "");
std::list<uint32> GetBots();
std::vector<uint32> GetBgBots(uint32 bracket);
time_t BgCheckTimer;
time_t LfgCheckTimer;
time_t PlayersCheckTimer;
uint32 AddRandomBots();
bool ProcessBot(uint32 bot);
void ScheduleRandomize(uint32 bot, uint32 time);
void RandomTeleport(Player* bot);
void RandomTeleport(Player* bot, std::vector<WorldLocation>& locs, bool hearth = false);
uint32 GetZoneLevel(uint16 mapId, float teleX, float teleY, float teleZ);
void PrepareTeleportCache();
typedef void(RandomPlayerbotMgr::*ConsoleCommandHandler)(Player*);
std::vector<Player*> players;
uint32 processTicks;
std::map<uint8, std::vector<WorldLocation>> locsPerLevelCache;
std::map<uint32, std::vector<WorldLocation>> rpgLocsCache;
std::map<uint32, std::map<uint32, std::vector<WorldLocation>>> rpgLocsCacheLevel;
std::map<TeamId, std::map<BattlegroundTypeId, std::vector<uint32>>> BattleMastersCache;
std::map<uint32, std::map<std::string, CachedEvent>> eventCache;
std::list<uint32> currentBots;
uint32 bgBotsCount;
uint32 playersLevel;
PerformanceMonitorOperation* totalPmo;
};
#define sRandomPlayerbotMgr RandomPlayerbotMgr::instance()
#endif

72
src/ServerFacade.cpp Normal file
View File

@ -0,0 +1,72 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#include "ServerFacade.h"
#include "Playerbots.h"
#include "TargetedMovementGenerator.h"
float ServerFacade::GetDistance2d(Unit* unit, WorldObject* wo)
{
ASSERT_NOTNULL(unit);
ASSERT_NOTNULL(wo);
float dist = unit->GetDistance2d(wo);
return std::round(dist * 10.0f) / 10.0f;
}
float ServerFacade::GetDistance2d(Unit *unit, float x, float y)
{
float dist = unit->GetDistance2d(x, y);
return std::round(dist * 10.0f) / 10.0f;
}
bool ServerFacade::IsDistanceLessThan(float dist1, float dist2)
{
return dist1 - dist2 < sPlayerbotAIConfig->targetPosRecalcDistance;
}
bool ServerFacade::IsDistanceGreaterThan(float dist1, float dist2)
{
return dist1 - dist2 > sPlayerbotAIConfig->targetPosRecalcDistance;
}
bool ServerFacade::IsDistanceGreaterOrEqualThan(float dist1, float dist2)
{
return !IsDistanceLessThan(dist1, dist2);
}
bool ServerFacade::IsDistanceLessOrEqualThan(float dist1, float dist2)
{
return !IsDistanceGreaterThan(dist1, dist2);
}
void ServerFacade::SetFacingTo(Player* bot, WorldObject* wo, bool force)
{
float angle = bot->GetAngle(wo);
if (!force && bot->isMoving())
bot->SetFacingTo(bot->GetAngle(wo));
else
{
bot->SetOrientation(angle);
bot->SendMovementFlagUpdate();
}
}
Unit* ServerFacade::GetChaseTarget(Unit* target)
{
MovementGenerator* movementGen = target->GetMotionMaster()->top();
if (movementGen && movementGen->GetMovementGeneratorType() == CHASE_MOTION_TYPE)
{
if (target->GetTypeId() == TYPEID_PLAYER)
{
return static_cast<ChaseMovementGenerator<Player> const*>(movementGen)->GetTarget();
}
else
{
return static_cast<ChaseMovementGenerator<Creature> const*>(movementGen)->GetTarget();
}
}
return nullptr;
}

40
src/ServerFacade.h Normal file
View File

@ -0,0 +1,40 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#ifndef _PLAYERBOT_SERVERFACADE_H
#define _PLAYERBOT_SERVERFACADE_H
#include "Common.h"
class Player;
class Unit;
class WorldObject;
class ServerFacade
{
public:
ServerFacade() { };
virtual ~ServerFacade() { };
static ServerFacade* instance()
{
static ServerFacade instance;
return &instance;
}
public:
float GetDistance2d(Unit* unit, WorldObject* wo);
float GetDistance2d(Unit* unit, float x, float y);
bool IsDistanceLessThan(float dist1, float dist2);
bool IsDistanceGreaterThan(float dist1, float dist2);
bool IsDistanceGreaterOrEqualThan(float dist1, float dist2);
bool IsDistanceLessOrEqualThan(float dist1, float dist2);
void SetFacingTo(Player* bot, WorldObject* wo, bool force = false);
Unit* GetChaseTarget(Unit* target);
};
#define sServerFacade ServerFacade::instance()
#endif

517
src/Talentspec.cpp Normal file
View File

@ -0,0 +1,517 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#include "Talentspec.h"
#include "Event.h"
#include "Playerbots.h"
uint32 TalentSpec::TalentListEntry::tabPage() const
{
return talentTabInfo->TalentTabID == 41 ? 1 : talentTabInfo->tabpage;
}
//Checks a talent link on basic validity.
bool TalentSpec::CheckTalentLink(std::string const link, std::ostringstream* out)
{
std::string const validChar = "-";
std::string const validNums = "012345";
uint32 nums = 0;
for (char const& c : link)
{
if (validChar.find(c) == std::string::npos && validNums.find(c) == std::string::npos)
{
*out << "talent link is invalid. Must be in format 0-0-0";
return false;
}
if (validNums.find(c) != std::string::npos)
nums++;
}
if (nums == 0)
{
*out << "talent link is invalid. Needs atleast one number.";
return false;
}
return true;
}
uint32 TalentSpec::LeveltoPoints(uint32 level) const
{
uint32 talentPointsForLevel = level < 10 ? 0 : level - 9;
return uint32(talentPointsForLevel * sWorld->getRate(RATE_TALENT));
}
uint32 TalentSpec::PointstoLevel(uint32 points) const
{
return uint32(ceil(points / sWorld->getRate(RATE_TALENT))) + 9;
}
TalentSpec::TalentSpec(uint32 classMask)
{
GetTalents(classMask);
}
TalentSpec::TalentSpec(TalentSpec* base, std::string const link)
{
talents = base->talents;
ReadTalents(link);
}
TalentSpec::TalentSpec(Player* bot)
{
GetTalents(bot->getClassMask());
ReadTalents(bot);
}
TalentSpec::TalentSpec(Player* bot, std::string const link)
{
GetTalents(bot->getClassMask());
ReadTalents(link);
}
//Check the talentspec for errors.
bool TalentSpec::CheckTalents(uint32 level, std::ostringstream* out)
{
for (auto& entry : talents)
{
if (entry.rank > entry.maxRank)
{
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(entry.talentInfo->RankID[0]);
*out << "spec is not for this class. " << spellInfo->SpellName[0] << " has " << (entry.rank - entry.maxRank) << " points above max rank.";
return false;
}
if (entry.rank > 0 && entry.talentInfo->DependsOn)
{
if (sTalentStore.LookupEntry(entry.talentInfo->DependsOn))
{
bool found = false;
SpellInfo const* spellInfodep = nullptr;
for (auto& dep : talents)
if (dep.talentInfo->TalentID == entry.talentInfo->DependsOn)
{
spellInfodep = sSpellMgr->GetSpellInfo(dep.talentInfo->RankID[0]);
if (dep.rank >= entry.talentInfo->DependsOnRank)
found = true;
}
if (!found)
{
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(entry.talentInfo->RankID[0]);
*out << "spec is invalid. Talent:" << spellInfo->SpellName[0] << " needs: " << spellInfodep->SpellName[0] << " at rank: " << entry.talentInfo->DependsOnRank;
return false;
}
}
}
}
for (uint8 i = 0; i < 3; i++)
{
std::vector<TalentListEntry> talentTree = GetTalentTree(i);
uint32 points = 0;
for (auto& entry : talentTree)
{
if (entry.rank > 0 && entry.talentInfo->Row * 5 > points)
{
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(entry.talentInfo->RankID[0]);
*out << "spec is is invalid. Talent " << spellInfo->SpellName[0] << " is selected with only " << points << " in row below it.";
return false;
}
points += entry.rank;
}
}
if (points > LeveltoPoints(level))
{
*out << "spec is for a higher level. (" << PointstoLevel(points) << ")";
return false;
}
return true;
}
//Set the talents for the bots to the current spec.
void TalentSpec::ApplyTalents(Player* bot, std::ostringstream* out)
{
for (auto& entry : talents)
for (uint8 rank = 0; rank < MAX_TALENT_RANK; ++rank)
{
uint32 spellId = entry.talentInfo->RankID[rank];
if (!spellId)
continue;
if (bot->HasSpell(spellId) && entry.rank - 1 != rank)
{
bot->removeSpell(spellId, false, false);
}
else if (!bot->HasSpell(spellId) && entry.rank - 1 == rank)
{
bot->learnSpell(spellId);
}
}
}
//Returns a base talentlist for a class.
void TalentSpec::GetTalents(uint32 classMask)
{
TalentListEntry entry;
for (uint32 i = 0; i < sTalentStore.GetNumRows(); ++i)
{
TalentEntry const* talentInfo = sTalentStore.LookupEntry(i);
if (!talentInfo)
continue;
TalentTabEntry const* talentTabInfo = sTalentTabStore.LookupEntry(talentInfo->TalentTab);
if (!talentTabInfo)
continue;
if ((classMask & talentTabInfo->ClassMask) == 0)
continue;
entry.entry = i;
entry.rank = 0;
entry.talentInfo = talentInfo;
entry.talentTabInfo = talentTabInfo;
for (uint8 rank = 0; rank < MAX_TALENT_RANK; ++rank)
{
uint32 spellId = talentInfo->RankID[rank];
if (!spellId)
continue;
entry.maxRank = rank + 1;
}
talents.push_back(entry);
}
SortTalents(talents, SORT_BY_DEFAULT);
}
//Sorts a talent list by page, row, column.
bool sortTalentMap(TalentSpec::TalentListEntry i, TalentSpec::TalentListEntry j, uint32* tabSort)
{
uint32 itab = i.tabPage();
uint32 jtab = j.tabPage();
if (tabSort[itab] < tabSort[jtab])
return true;
if (tabSort[itab] > tabSort[jtab])
return false;
if (i.talentInfo->Row < j.talentInfo->Row)
return true;
if (i.talentInfo->Row > j.talentInfo->Row)
return false;
if (i.talentInfo->Col < j.talentInfo->Col)
return true;
return false;
}
void TalentSpec::SortTalents(uint32 sortBy)
{
SortTalents(talents, sortBy);
}
//Sort the talents.
void TalentSpec::SortTalents(std::vector<TalentListEntry>& talents, uint32 sortBy)
{
switch (sortBy)
{
case SORT_BY_DEFAULT:
{
uint32 tabSort[] = { 0, 1, 2 };
std::sort(talents.begin(), talents.end(), [&tabSort](TalentSpec::TalentListEntry i, TalentSpec::TalentListEntry j)
{
return sortTalentMap(i, j, tabSort);
});
break;
}
case SORT_BY_POINTS_TREE:
{
uint32 tabSort[] = { GetTalentPoints(talents, 0) * 100 - urand(0, 99), GetTalentPoints(talents, 1) * 100 - urand(0, 99), GetTalentPoints(talents, 2) * 100 - urand(0, 99) };
std::sort(talents.begin(), talents.end(), [&tabSort](TalentSpec::TalentListEntry i, TalentSpec::TalentListEntry j)
{
return sortTalentMap(i, j, tabSort);
});
break;
}
}
}
//Set the talent ranks to the current rank of the player.
void TalentSpec::ReadTalents(Player* bot)
{
for (auto& entry : talents)
for (uint8 rank = 0; rank < MAX_TALENT_RANK; ++rank)
{
uint32 spellId = entry.talentInfo->RankID[rank];
if (!spellId)
continue;
if (bot->HasSpell(spellId))
{
entry.rank = rank + 1;
points += 1;
}
}
}
//Set the talent ranks to the ranks of the link.
void TalentSpec::ReadTalents(std::string const link)
{
uint32 rank = 0;
uint32 pos = 0;
uint32 tab = 0;
std::string chr;
if (link.substr(pos, 1) == "-")
{
pos++;
tab++;
}
if (link.substr(pos, 1) == "-")
{
pos++;
tab++;
}
for (auto& entry : talents)
{
if (entry.tabPage() == tab)
{
chr = link.substr(pos, 1);
if (chr == " " || chr == "#")
break;
entry.rank = stoi(chr);
points += entry.rank;
pos++;
if (pos <= link.size() && link.substr(pos, 1) == "-")
{
pos++;
tab++;
}
if (pos <= link.size() && link.substr(pos, 1) == "-")
{
pos++;
tab++;
}
}
if (pos > link.size() - 1)
break;
}
}
//Returns only a specific tree from a talent list.
std::vector<TalentSpec::TalentListEntry> TalentSpec::GetTalentTree(uint32 tabpage)
{
std::vector<TalentListEntry> retList;
for (auto& entry : talents)
if (entry.tabPage() == tabpage)
retList.push_back(entry);
return std::move(retList);
}
uint32 TalentSpec::GetTalentPoints(int32 tabpage)
{
return GetTalentPoints(talents, tabpage);
};
//Counts the point in a talent list.
uint32 TalentSpec::GetTalentPoints(std::vector<TalentListEntry>& talents, int32 tabpage)
{
if (tabpage == -1)
return points;
uint32 tPoints = 0;
for (auto& entry : talents)
if (entry.tabPage() == tabpage)
tPoints = tPoints + entry.rank;
return tPoints;
}
//Generates a wow-head link from a talent list.
std::string const TalentSpec::GetTalentLink()
{
std::string link = "";
std::string treeLink[3];
uint32 points[3];
uint32 curPoints = 0;
for (uint8 i = 0; i < 3; i++)
{
points[i] = GetTalentPoints(i);
for (auto& entry : GetTalentTree(i))
{
curPoints += entry.rank;
treeLink[i] += std::to_string(entry.rank);
if (curPoints >= points[i])
{
curPoints = 0;
break;
}
}
}
link = treeLink[0];
if (treeLink[1] != "0" || treeLink[2] != "0")
link = link + "-" + treeLink[1];
if (treeLink[2] != "0")
link = link + "-" + treeLink[2];
return std::move(link);
}
uint32 TalentSpec::highestTree()
{
uint32 p1 = GetTalentPoints(0);
uint32 p2 = GetTalentPoints(1);
uint32 p3 = GetTalentPoints(2);
if (p1 > p2 && p1 > p3)
return 0;
if (p2 > p1 && p2 > p3)
return 1;
if (p3 > p1 && p3 > p2)
return 2;
if (p1 > p2 || p1 > p3)
return 0;
if (p2 > p3 || p2 > p1)
return 1;
return 0;
}
std::string const TalentSpec::FormatSpec(Player* bot)
{
uint8 cls = bot->getClass();
std::ostringstream out;
//out << chathelper:: specs[cls][highestTree()] << " (";
uint32 c0 = GetTalentPoints(0);
uint32 c1 = GetTalentPoints(1);
uint32 c2 = GetTalentPoints(2);
out << (c0 ? "|h|cff00ff00" : "") << c0 << "|h|cffffffff/";
out << (c1 ? "|h|cff00ff00" : "") << c1 << "|h|cffffffff/";
out << (c2 ? "|h|cff00ff00" : "") << c2 << "|h|cffffffff";
return out.str();
}
//Removes talentpoints to match the level
void TalentSpec::CropTalents(uint32 level)
{
if (points <= LeveltoPoints(level))
return;
SortTalents(talents, SORT_BY_POINTS_TREE);
uint32 points = 0;
for (auto& entry : talents)
{
if (points + entry.rank > LeveltoPoints(level))
entry.rank = std::max(0u, LeveltoPoints(level) - points);
points += entry.rank;
}
SortTalents(talents, SORT_BY_DEFAULT);
}
//Substracts ranks. Follows the sorting of the newList.
std::vector<TalentSpec::TalentListEntry> TalentSpec::SubTalentList(std::vector<TalentListEntry>& oldList, std::vector<TalentListEntry>& newList, uint32 reverse = SUBSTRACT_OLD_NEW)
{
std::vector<TalentSpec::TalentListEntry> deltaList = newList;
for (auto& newentry : deltaList)
for (auto& oldentry : oldList)
if (oldentry.entry == newentry.entry)
{
if (reverse == ABSOLUTE_DIST)
newentry.rank = std::abs(int32(newentry.rank - oldentry.rank));
else if (reverse == ADDED_POINTS || reverse == REMOVED_POINTS)
newentry.rank = std::max(0u, (newentry.rank - oldentry.rank) * (reverse / 2));
else
newentry.rank = (newentry.rank - oldentry.rank) * reverse;
}
return deltaList;
}
bool TalentSpec::isEarlierVersionOf(TalentSpec& newSpec)
{
for (auto& newentry : newSpec.talents)
for (auto& oldentry : talents)
if (oldentry.entry == newentry.entry)
if (oldentry.rank > newentry.rank)
return false;
return true;
}
//Modifies current talents towards new talents up to a maxium of points.
void TalentSpec::ShiftTalents(TalentSpec* currentSpec, uint32 level)
{
uint32 currentPoints = currentSpec->GetTalentPoints();
if (points >= LeveltoPoints(level)) //We have no more points to spend. Better reset and crop
{
CropTalents(level);
return;
}
SortTalents(SORT_BY_POINTS_TREE); //Apply points first to the largest new tree.
std::vector<TalentSpec::TalentListEntry> deltaList = SubTalentList(currentSpec->talents, talents);
for (auto& entry : deltaList)
{
if (entry.rank < 0) //We have to remove talents. Might as well reset and crop the new list.
{
CropTalents(level);
return;
}
}
//Start from the current spec.
talents = currentSpec->talents;
for (auto& entry : deltaList)
{
if (entry.rank + points > LeveltoPoints(level)) //Running out of points. Only apply what we have left.
entry.rank = std::max(0, std::abs(int32(LeveltoPoints(level) - points)));
for (auto& subentry : talents)
if (entry.entry == subentry.entry)
subentry.rank = subentry.rank + entry.rank;
points = points + entry.rank;
}
}

103
src/Talentspec.h Normal file
View File

@ -0,0 +1,103 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#ifndef _PLAYERBOT_TALENTSPEC_H
#define _PLAYERBOT_TALENTSPEC_H
#include "Action.h"
struct TalentEntry;
struct TalentTabEntry;
#define SORT_BY_DEFAULT 0
#define SORT_BY_POINTS_TREE 1
#define ABSOLUTE_DIST 0
#define SUBSTRACT_OLD_NEW 1
#define SUBSTRACT_NEW_OLD -1
#define ADDED_POINTS 2
#define REMOVED_POINTS -2
class TalentSpec
{
public:
struct TalentListEntry
{
uint32 entry;
uint32 rank;
uint32 maxRank;
TalentEntry const* talentInfo;
TalentTabEntry const* talentTabInfo;
uint32 tabPage() const;
};
TalentSpec() { };
TalentSpec(uint32 classMask);
TalentSpec(TalentSpec* base, std::string const link);
TalentSpec(Player* bot);
TalentSpec(Player* bot, std::string const link);
uint32 points = 0;
std::vector<TalentListEntry> talents;
bool CheckTalentLink(std::string const link, std::ostringstream* out);
virtual bool CheckTalents(uint32 maxPoints, std::ostringstream* out);
void CropTalents(uint32 level);
void ShiftTalents(TalentSpec* oldTalents, uint32 level);
void ApplyTalents(Player* bot, std::ostringstream* out);
uint32 GetTalentPoints(std::vector<TalentListEntry>& talents, int32 tabpage = -1);
uint32 GetTalentPoints(int32 tabpage = -1);
bool isEarlierVersionOf(TalentSpec& newSpec);
std::string const GetTalentLink();
uint32 highestTree();
std::string const FormatSpec(Player* bot);
protected:
uint32 LeveltoPoints(uint32 level) const;
uint32 PointstoLevel(uint32 points) const;
void GetTalents(uint32 classMask);
void SortTalents(std::vector<TalentListEntry>& talents, uint32 sortBy);
void SortTalents(uint32 sortBy);
void ReadTalents(Player* bot);
void ReadTalents(std::string const link);
std::vector<TalentListEntry> GetTalentTree(uint32 tabpage);
std::vector<TalentListEntry> SubTalentList(std::vector<TalentListEntry>& oldList, std::vector<TalentListEntry>& newList, uint32 reverse);
};
class TalentPath
{
public:
TalentPath(uint32 pathId, std::string const pathName, uint32 pathProbability)
{
id = pathId;
name = pathName;
probability = pathProbability;
};
uint32 id = 0;
std::string name = "";
uint32 probability = 100;
std::vector<TalentSpec> talentSpec;
};
class ClassSpecs
{
public:
ClassSpecs() { };
ClassSpecs(uint32 specsClassMask)
{
classMask = specsClassMask;
baseSpec = TalentSpec(specsClassMask);
}
uint32 classMask = 0;
TalentSpec baseSpec;
std::vector<TalentPath> talentPath;
};
#endif

4343
src/TravelMgr.cpp Normal file

File diff suppressed because it is too large Load Diff

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