├── .editorconfig ├── .gitattributes ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.yml │ └── feature_request.yml └── workflows │ └── core-build.yml ├── .gitignore ├── README.md ├── conf └── mod_ahbot.conf.dist ├── data ├── .gitkeep └── sql │ ├── db-auth │ ├── base │ │ └── .gitkeep │ └── updates │ │ └── .gitkeep │ ├── db-characters │ ├── base │ │ └── .gitkeep │ └── updates │ │ └── .gitkeep │ └── db-world │ ├── base │ ├── .gitkeep │ └── mod_auctionhousebot.sql │ └── updates │ └── .gitkeep ├── include.sh ├── pull_request_template.md └── src ├── AuctionHouseBot.cpp ├── AuctionHouseBot.h ├── AuctionHouseBotScript.cpp └── ah_bot_loader.cpp /.editorconfig: -------------------------------------------------------------------------------- 1 | [*] 2 | charset = utf-8 3 | indent_style = space 4 | indent_size = 4 5 | tab_width = 4 6 | insert_final_newline = true 7 | trim_trailing_whitespace = true 8 | max_line_length = 80 9 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ## AUTO-DETECT 2 | ## Handle line endings automatically for files detected as 3 | ## text and leave all files detected as binary untouched. 4 | ## This will handle all files NOT defined below. 5 | * text=auto eol=lf 6 | 7 | # Text 8 | *.conf 9 | *.conf.dist 10 | *.txt 11 | *.md 12 | *.cmake 13 | 14 | # Bash 15 | *.sh text 16 | 17 | # Lua if lua module? 18 | *.lua 19 | 20 | # SQL 21 | *.sql 22 | 23 | # C++ 24 | *.c text 25 | *.cc text 26 | *.cxx text 27 | *.cpp text 28 | *.c++ text 29 | *.hpp text 30 | *.h text 31 | *.h++ text 32 | *.hh text 33 | 34 | 35 | ## For documentation 36 | 37 | # Documents 38 | *.doc diff=astextplain 39 | *.DOC diff=astextplain 40 | *.docx diff=astextplain 41 | *.DOCX diff=astextplain 42 | *.dot diff=astextplain 43 | *.DOT diff=astextplain 44 | *.pdf diff=astextplain 45 | *.PDF diff=astextplain 46 | *.rtf diff=astextplain 47 | *.RTF diff=astextplain 48 | 49 | 50 | # Graphics 51 | *.png binary 52 | *.jpg binary 53 | *.jpeg binary 54 | *.gif binary 55 | *.tif binary 56 | *.tiff binary 57 | *.ico binary 58 | # SVG treated as an asset (binary) by default. If you want to treat it as text, 59 | # comment-out the following line and uncomment the line after. 60 | *.svg binary 61 | #*.svg text 62 | *.eps binary 63 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.yml: -------------------------------------------------------------------------------- 1 | name: Bug report 2 | description: Create a bug report to help us improve. 3 | title: "Bug: " 4 | body: 5 | - type: textarea 6 | id: current 7 | attributes: 8 | label: Current Behaviour 9 | description: | 10 | Description of the problem or issue here. 11 | Include entries of affected creatures / items / quests / spells etc. 12 | If this is a crash, post the crashlog (upload to https://gist.github.com/) and include the link here. 13 | Never upload files! Use GIST for text and YouTube for videos! 14 | validations: 15 | required: true 16 | - type: textarea 17 | id: expected 18 | attributes: 19 | label: Expected Behaviour 20 | description: | 21 | Tell us what should happen instead. 22 | validations: 23 | required: true 24 | - type: textarea 25 | id: reproduce 26 | attributes: 27 | label: Steps to reproduce the problem 28 | description: | 29 | What does someone else need to do to encounter the same bug? 30 | placeholder: | 31 | 1. Step 1 32 | 2. Step 2 33 | 3. Step 3 34 | validations: 35 | required: true 36 | - type: textarea 37 | id: extra 38 | attributes: 39 | label: Extra Notes 40 | description: | 41 | Do you have any extra notes that can help solve the issue that does not fit any other field? 42 | placeholder: | 43 | None 44 | validations: 45 | required: false 46 | - type: textarea 47 | id: commit 48 | attributes: 49 | label: AC rev. hash/commit 50 | description: | 51 | Copy the result of the `.server debug` command (if you need to run it from the client get a prat addon) 52 | validations: 53 | required: true 54 | - type: input 55 | id: os 56 | attributes: 57 | label: Operating system 58 | description: | 59 | The Operating System the Server is running on. 60 | i.e. Windows 11 x64, Debian 10 x64, macOS 12, Ubuntu 20.04 61 | validations: 62 | required: true 63 | - type: textarea 64 | id: custom 65 | attributes: 66 | label: Custom changes or Modules 67 | description: | 68 | List which custom changes or modules you have applied, i.e. Eluna module, etc. 69 | placeholder: | 70 | None 71 | validations: 72 | required: false 73 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.yml: -------------------------------------------------------------------------------- 1 | name: Feature request 2 | description: Suggest an idea for this project 3 | title: "Feature: " 4 | body: 5 | - type: markdown 6 | attributes: 7 | value: | 8 | Thank you for taking your time to fill out a feature request. Remember to fill out all fields including the title above. 9 | An issue that is not properly filled out will be closed. 10 | - type: textarea 11 | id: description 12 | attributes: 13 | label: Describe your feature request or suggestion in detail 14 | description: | 15 | A clear and concise description of what you want to happen. 16 | validations: 17 | required: true 18 | - type: textarea 19 | id: solution 20 | attributes: 21 | label: Describe a possible solution to your feature or suggestion in detail 22 | description: | 23 | A clear and concise description of any alternative solutions or features you've considered. 24 | validations: 25 | required: false 26 | - type: textarea 27 | id: additional 28 | attributes: 29 | label: Additional context 30 | description: | 31 | Add any other context or screenshots about the feature request here. 32 | validations: 33 | required: false 34 | -------------------------------------------------------------------------------- /.github/workflows/core-build.yml: -------------------------------------------------------------------------------- 1 | name: core-build 2 | on: 3 | push: 4 | branches: 5 | - 'master' 6 | pull_request: 7 | 8 | jobs: 9 | build: 10 | uses: azerothcore/reusable-workflows/.github/workflows/core_build_modules.yml@main 11 | with: 12 | module_repo: ${{ github.event.repository.name }} 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | !.gitignore 2 | 3 | # 4 | #Generic 5 | # 6 | 7 | .directory 8 | .mailmap 9 | *.orig 10 | *.rej 11 | *~ 12 | .hg/ 13 | *.kdev* 14 | .DS_Store 15 | CMakeLists.txt.user 16 | *.bak 17 | *.patch 18 | *.diff 19 | *.REMOTE.* 20 | *.BACKUP.* 21 | *.BASE.* 22 | *.LOCAL.* 23 | 24 | # 25 | # IDE & other softwares 26 | # 27 | /.settings/ 28 | /.externalToolBuilders/* 29 | # exclude in all levels 30 | nbproject/ 31 | .sync.ffs_db 32 | *.kate-swp 33 | 34 | # 35 | # Eclipse 36 | # 37 | *.pydevproject 38 | .metadata 39 | .gradle 40 | tmp/ 41 | *.tmp 42 | *.swp 43 | *~.nib 44 | local.properties 45 | .settings/ 46 | .loadpath 47 | .project 48 | .cproject 49 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Description 2 | 3 | A fork of the auction house bot for AzerothCore. This fork gives a much more blizzlike experience in the offerings on the auction house. Most notable differences: 4 | - Things like Glyphs show up 5 | - Auction item stack sizes are customizable and more 'realistic' 6 | - The buyer bot's buying amounts and behavior was changed substantially 7 | - A separate set of exclusion item IDs was added to have crafted items listed, to encourage gathing professions. 8 | - Empty the list to have crafted goods appear in the AH, or use other IDs you want to keep separate 9 | - Moved database configuration completely to config 10 | 11 | ## Installation 12 | 13 | ``` 14 | 1. Simply place the module under the `modules` directory of your AzerothCore source. 15 | 2. Re-run cmake and launch a clean build of AzerothCore. 16 | ``` 17 | 18 | ## Usage 19 | 20 | Edit the module configuration and add a character GUID ID to the "AuctionHouseBot.GUIDs" variable, which is sourced from your character table in the character database. These names will be visable in the auction house, so pick good names. Find the configuration as named mod_ahbot.conf.dist / mod_ahbot.conf 21 | 22 | Notes: 23 | - These accounts do not need any security level and can be a player accounts. 24 | - The characters used by the ahbot are not meant to be used ingame. If you use it to browse the auction house, you might have issues like "Searching for items..." displaying forever. 25 | - Important! By default, most player crafted items (except glyphs, bolts, maybe a few other things) are disabled from showing up in the auction house in order to encourage player crafting on lower pop servers. If you want different behavior, alter the config variable "AuctionHouseBot.DisabledCraftedItemIDs" by deleting IDs you wish to show up. Note that fish are also disabled to encourage fishing, and that's also managed by disabled lists. 26 | - It takes a few hours for the auction house to fully populate, as only 75 items gets added by default every 'tick'. You can change this in the config with the AuctionHouseBot.ItemsPerCycle variable. 27 | 28 | ## Credits 29 | 30 | - NathanHandley: Created this rewrite of the one that was ported to AzerothCore 31 | - Ayase: ported the bot to AzerothCore 32 | - Other contributors (check the contributors list) 33 | -------------------------------------------------------------------------------- /conf/mod_ahbot.conf.dist: -------------------------------------------------------------------------------- 1 | [worldserver] 2 | 3 | ############################################################################### 4 | # AUCTION HOUSE BOT SETTINGS 5 | # AuctionHouseBot.DEBUG 6 | # Enable/Disable Debugging output 7 | # Default 0 (disabled) 8 | # 9 | # AuctionHouseBot.DEBUG_FILTERS 10 | # Enable/Disable Debugging output from Filters 11 | # Default 0 (disabled) 12 | # 13 | # AuctionHouseBot.EnableSeller 14 | # Enable/Disable the part of AHBot that puts items up for auction 15 | # Default 0 (disabled) 16 | # 17 | # AuctionHouseBot.EnableBuyer 18 | # Enable/Disable the part of AHBot that buys items from players 19 | # Default 0 (disabled) 20 | # 21 | # AuctionHouseBot.GUIDs 22 | # These are the character GUIDS (from characters->characters table) that 23 | # will be used to create auctions and otherwise interact with auctions. 24 | # It can be a single value or multiple values that are separated by a 25 | # comma. Note: a GUID of "0" will be ignored! 26 | # Examples: 27 | # AuctionHouseBot.GUIDs = 3 <- Only character with GUID 3 28 | # AuctionHouseBot.GUIDs = 3,4 <- Both characters with GUID 3 and 4 29 | # 30 | # AuctionHouseBot.ItemsPerCycle 31 | # How many items to post on the auction house every house update. Items 32 | # in a cycle will be posted by a single randomly selected bot, so Keep 33 | # this value low if you want highly diverse postings 34 | # Default 75 35 | ############################################################################### 36 | 37 | AuctionHouseBot.DEBUG = 0 38 | AuctionHouseBot.DEBUG_FILTERS = 0 39 | AuctionHouseBot.EnableSeller = 0 40 | AuctionHouseBot.EnableBuyer = 0 41 | AuctionHouseBot.GUIDs = 0 42 | AuctionHouseBot.ItemsPerCycle = 75 43 | 44 | ############################################################################### 45 | # AuctionHouseBot.ListedItemLevelRestrict.Enabled 46 | # If true, the item level will be restricted in listings 47 | # Default: false 48 | # 49 | # AuctionHouseBot.ListedItemLevelRestrict.MaxItemLevel 50 | # The highest item level that will show up in listings 51 | # Default: 999 52 | # 53 | # AuctionHouseBot.ListedItemLevelRestrict.MinItemLevel 54 | # The lowest item level that will show up in listings 55 | # Default: 0 56 | # 57 | # AuctionHouseBot.ListedItemLevelRestrict.ExceptionItemIDs 58 | # Comma separated list of itemIDs to exclude from any item level restriction logic 59 | # Ranges using a dash (-) can also be used 60 | # NOTE: The disabled item list will still be honored even if it's listed here 61 | ############################################################################### 62 | AuctionHouseBot.ListedItemLevelRestrict.Enabled = false 63 | AuctionHouseBot.ListedItemLevelRestrict.MaxItemLevel = 999 64 | AuctionHouseBot.ListedItemLevelRestrict.MinItemLevel = 0 65 | AuctionHouseBot.ListedItemLevelRestrict.ExceptionItemIDs = 66 | 67 | ############################################################################### 68 | # AuctionHouseBot..MinItems 69 | # AuctionHouseBot..MaxItems 70 | # The minimum and maximum number of items to post on that auction house 71 | # Default: 15000 for both 72 | # 73 | # AuctionHouseBot..BidInterval 74 | # How long to wait between bidding 75 | # Default: 1 76 | # 77 | # AuctionHouseBot..BidInterval 78 | # How many to bid on at a time 79 | # Default: 1 80 | ############################################################################### 81 | 82 | AuctionHouseBot.Alliance.MinItems = 15000 83 | AuctionHouseBot.Alliance.MaxItems = 15000 84 | AuctionHouseBot.Alliance.BidInterval = 1 85 | AuctionHouseBot.Alliance.BidsPerInterval = 1 86 | AuctionHouseBot.Horde.MinItems = 15000 87 | AuctionHouseBot.Horde.MaxItems = 15000 88 | AuctionHouseBot.Horde.BidInterval = 1 89 | AuctionHouseBot.Horde.BidsPerInterval = 1 90 | AuctionHouseBot.Neutral.MinItems = 15000 91 | AuctionHouseBot.Neutral.MaxItems = 15000 92 | AuctionHouseBot.Neutral.BidInterval = 1 93 | AuctionHouseBot.Neutral.BidsPerInterval = 1 94 | 95 | ############################################################################### 96 | # AuctionHouseBot.ListProportion.* 97 | # Determines how many of the listings, proportionally, show up as new auctions 98 | # "0" will mean the item never shows up. Values must be whole numbers. 99 | # Defaults: Consumable: 2 100 | # Container: 2 101 | # Weapon: 6 102 | # Gem: 2 103 | # Armor: 6 104 | # Reagent: 1 105 | # Projectile: 2 106 | # TradeGood: 22 107 | # Generic: 1 108 | # Recipe: 3 109 | # Quiver: 1 110 | # Quest: 2 111 | # Key: 1 112 | # Misc: 0 113 | # Glyph: 2 114 | ############################################################################### 115 | 116 | AuctionHouseBot.ListProportion.Consumable = 2 117 | AuctionHouseBot.ListProportion.Container = 2 118 | AuctionHouseBot.ListProportion.Weapon = 6 119 | AuctionHouseBot.ListProportion.Gem = 2 120 | AuctionHouseBot.ListProportion.Armor = 6 121 | AuctionHouseBot.ListProportion.Reagent = 1 122 | AuctionHouseBot.ListProportion.Projectile = 2 123 | AuctionHouseBot.ListProportion.TradeGood = 22 124 | AuctionHouseBot.ListProportion.Generic = 1 125 | AuctionHouseBot.ListProportion.Recipe = 3 126 | AuctionHouseBot.ListProportion.Quiver = 1 127 | AuctionHouseBot.ListProportion.Quest = 2 128 | AuctionHouseBot.ListProportion.Key = 1 129 | AuctionHouseBot.ListProportion.Misc = 0 130 | AuctionHouseBot.ListProportion.Glyph = 2 131 | 132 | ############################################################################### 133 | # AuctionHouseBot.PriceMinimumCenterBase.* 134 | # Category-level price minimums, in copper, before any multipliers come 135 | # into play. Value shouldn't be zero, and the base minimum price will 136 | # actually be a +/- 25% range of this value. Used to catch 0 cost or 137 | # extremely low cost items 138 | ############################################################################### 139 | 140 | AuctionHouseBot.PriceMinimumCenterBase.Consumable = 1000 141 | AuctionHouseBot.PriceMinimumCenterBase.Container = 1000 142 | AuctionHouseBot.PriceMinimumCenterBase.Weapon = 1000 143 | AuctionHouseBot.PriceMinimumCenterBase.Gem = 1000 144 | AuctionHouseBot.PriceMinimumCenterBase.Armor = 1000 145 | AuctionHouseBot.PriceMinimumCenterBase.Reagent = 1000 146 | AuctionHouseBot.PriceMinimumCenterBase.Projectile = 5 147 | AuctionHouseBot.PriceMinimumCenterBase.TradeGood = 1000 148 | AuctionHouseBot.PriceMinimumCenterBase.Generic = 1000 149 | AuctionHouseBot.PriceMinimumCenterBase.Recipe = 1000 150 | AuctionHouseBot.PriceMinimumCenterBase.Quiver = 1000 151 | AuctionHouseBot.PriceMinimumCenterBase.Quest = 1000 152 | AuctionHouseBot.PriceMinimumCenterBase.Key = 1000 153 | AuctionHouseBot.PriceMinimumCenterBase.Misc = 1000 154 | AuctionHouseBot.PriceMinimumCenterBase.Glyph = 1000 155 | 156 | ############################################################################### 157 | # AuctionHouseBot.PriceMinimumCenterBase.OverrideItems 158 | # Comma separated list of items in the format of "itemID:PriceMinCopper" 159 | # which is an override of the PriceMinimumCenterBase", a value that is 160 | # used before variation and multipliers 161 | # Example: "2589:1000000,4306:100000" would set the minimum price center 162 | # of linen cloth to 100 gold and silk cloth to 10 gold each 163 | ############################################################################### 164 | 165 | AuctionHouseBot.PriceMinimumCenterBase.OverrideItems = 166 | 167 | ############################################################################### 168 | # AuctionHouseBot.PriceMultiplier.* 169 | # Category/Quality-level modifier values for the prices of items, which can be 170 | # represented as decimal numbers, and must be > 0. Keep in mind that 171 | # the pricing algorithm has many steps to it and this is just a tuning 172 | # modifier. 173 | ############################################################################### 174 | 175 | AuctionHouseBot.PriceMultiplier.Category.Consumable = 1 176 | AuctionHouseBot.PriceMultiplier.Category.Container = 1 177 | AuctionHouseBot.PriceMultiplier.Category.Weapon = 1 178 | AuctionHouseBot.PriceMultiplier.Category.Gem = 1 179 | AuctionHouseBot.PriceMultiplier.Category.Armor = 1 180 | AuctionHouseBot.PriceMultiplier.Category.Reagent = 1 181 | AuctionHouseBot.PriceMultiplier.Category.Projectile = 1 182 | AuctionHouseBot.PriceMultiplier.Category.TradeGood = 2 183 | AuctionHouseBot.PriceMultiplier.Category.Generic = 1 184 | AuctionHouseBot.PriceMultiplier.Category.Recipe = 1 185 | AuctionHouseBot.PriceMultiplier.Category.Quiver = 1 186 | AuctionHouseBot.PriceMultiplier.Category.Quest = 1 187 | AuctionHouseBot.PriceMultiplier.Category.Key = 1 188 | AuctionHouseBot.PriceMultiplier.Category.Misc = 1 189 | AuctionHouseBot.PriceMultiplier.Category.Glyph = 1 190 | 191 | AuctionHouseBot.PriceMultiplier.Quality.Poor = 1 192 | AuctionHouseBot.PriceMultiplier.Quality.Normal = 1 193 | AuctionHouseBot.PriceMultiplier.Quality.Uncommon = 1.8 194 | AuctionHouseBot.PriceMultiplier.Quality.Rare = 1.9 195 | AuctionHouseBot.PriceMultiplier.Quality.Epic = 2.1 196 | AuctionHouseBot.PriceMultiplier.Quality.Legendary = 3 197 | AuctionHouseBot.PriceMultiplier.Quality.Artifact = 3 198 | AuctionHouseBot.PriceMultiplier.Quality.Heirloom = 3 199 | 200 | ############################################################################### 201 | # AuctionHouseBot.RandomStackRatio.* 202 | # Used to determine how often a stack of the class will be single or randomly-size stacked when posted 203 | # Value needs to be between 0 and 100, no decimal. Anything higher than 100 will be treated as 100 204 | # Examples: 100 = stacks will always be random in size 205 | # 50 = half the time the stacks are random, the other half being single stack 206 | # 0 = stacks will always single size 207 | # Defaults: Consumable: 20 (20% random stack size, 80% single stack size) 208 | # Container: 0 (100% single stack size) 209 | # Weapon: 0 (100% single stack size) 210 | # Gem: 5 (5% random stack size, 95% single stack size) 211 | # Armor: 0 (100% single stack size) 212 | # Reagent: 50 (50% random stack size, 50% single stack size) 213 | # Projectile: 100 (100% random stack size) 214 | # TradeGood: 50 (50% random stack size, 50% single stack size) 215 | # Generic: 100 (100% random stack size) 216 | # Recipe: 0 (100% single stack size) 217 | # Quiver: 0 (100% single stack size) 218 | # Quest: 10 (10% random stack size, 90% single stack size) 219 | # Key: 10 (10% random stack size, 90% single stack size) 220 | # Misc: 100 (100% random stack size) 221 | # Glyph: 0 (100% single stack size) 222 | ############################################################################### 223 | 224 | AuctionHouseBot.RandomStackRatio.Consumable = 20 225 | AuctionHouseBot.RandomStackRatio.Container = 0 226 | AuctionHouseBot.RandomStackRatio.Weapon = 0 227 | AuctionHouseBot.RandomStackRatio.Gem = 30 228 | AuctionHouseBot.RandomStackRatio.Armor = 0 229 | AuctionHouseBot.RandomStackRatio.Reagent = 50 230 | AuctionHouseBot.RandomStackRatio.Projectile = 100 231 | AuctionHouseBot.RandomStackRatio.TradeGood = 75 232 | AuctionHouseBot.RandomStackRatio.Generic = 100 233 | AuctionHouseBot.RandomStackRatio.Recipe = 0 234 | AuctionHouseBot.RandomStackRatio.Quiver = 0 235 | AuctionHouseBot.RandomStackRatio.Quest = 10 236 | AuctionHouseBot.RandomStackRatio.Key = 10 237 | AuctionHouseBot.RandomStackRatio.Misc = 100 238 | AuctionHouseBot.RandomStackRatio.Glyph = 0 239 | 240 | ############################################################################### 241 | # AuctionHouseBot.DisabledItemTextFilter 242 | # If true, this will hide items with bad names like "OLD" and "D'Sak" 243 | # Default: True 244 | # 245 | # AuctionHouseBot.DisabledItemIDs 246 | # Comma separated list of itemIDs to exclude from listing by the seller 247 | # Ranges using a dash (-) can also be used 248 | # 249 | # AuctionHouseBot.DisabledCraftedItemIDs 250 | # Additional Comma separated list of itemIDs to exclude from listing by the seller 251 | # which were originally put in to remove crafted items and fish, in order 252 | # encourage people to level their tradeskills 253 | # Ranges using a dash (-) can also be used 254 | ############################################################################### 255 | 256 | AuctionHouseBot.DisabledItemTextFilter = 1 257 | AuctionHouseBot.DisabledItemIDs = 17,37,88,91,100,119,128,138,143,156,734,763,813,862,876,895,896,900,913,931,956,958,960,964,996,997,1014,1020,1021,1024,1025,1027,1028,1029,1041,1057,1113,1114,1133,1134,1162,1166,1167,1189,1192,1193,1222,1255,1259,1298,1324,1352,1356,1389,1402,1450,1487,1623,1672,1902,1911,1914,1923,1977,2016,2055,2064,2081,2128,2133,2136,2184,2273,2275,2288,2305,2306,2320,2321,2324,2325,2377,2410,2413,2415,2441,2442,2443,2444,2477,2481,2482,2483,2484,2485,2486,2487,2496,2497,2498,2499,2500,2501,2502,2503,2550,2556,2588,2599,2604,2605,2638,2664,2665,2668,2678,2688,2692,2693,2705,2715,2755,2810,2880,2891-2893,2918,2920,2921,2922,2927,2929,2931,2932,2946,2947,2995,3003,3004,3005,3031,3034,3046,3052,3062,3063,3068,3107,3111,3122,3131,3135,3137,3144,3148,3168,3222,3245,3260,3316,3320,3368,3371,3372,3466,3513,3516,3536,3584,3648,3675,3686,3707,3713,3744,3772,3774,3775,3776,3777,3857,3861,3884,3895,3934,3952,3953,3954,3955,3956,3957,3958,3959,3977,3978,3979,3980,3981,3982,3983,3984,3988,3991,4008,4009,4010,4011,4012,4013,4014,4015,4143,4191,4193,4196,4200,4273,4289,4291,4340,4341,4342,4399,4400,4470,4471,4524,4603,4688,4703,4749,4761,4763,4773,4774,4868,4912,4959,5004,5005,5008,5010,5013,5024,5043,5044,5049,5056,5105,5106,5108,5150,5184,5220,5229,5235,5255,5259,5283,5330,5333,5349,5350,5353,5362,5363,5364,5367,5370,5371,5377,5379,5389,5400,5417,5418,5435,5455,5468,5495,5509,5510,5511,5512,5515,5517,5518,5523,5531,5549,5550,5555,5560,5562,5563,5577,5600,5625,5632,5639,5641,5645,5646,5654,5657,5660,5663,5670,5681,5748,5823,5828,5845,5859,5874,5875,5878,5968,6130,6131,6150,6174,6182,6183,6216,6222,6225,6227,6232,6260,6261,6273,6276,6277,6278,6279,6280,6289,6291,6292,6294,6295,6297,6301,6303,6307,6308,6309,6310,6311,6317,6343,6345,6351,6352,6353,6354,6355,6356,6357,6358,6360,6361,6362,6363,6364,6366,6374,6376,6435,6455,6490,6491,6492,6495,6496,6497,6498,6500,6501,6516,6544,6589,6623,6643,6645,6647,6648,6649,6650,6651,6698,6707,6708,6711,6715,6717,6718,6728,6734,6736,6834,6891,6927,6949-6951,6988,7093,7134,7135,7170,7187,7188,7190,7192,7206,7208,7268,7271,7286,7287,7333,7392,7426,7427,7428,7466,7467,7497,7547,7548,7550,7678,7679,7680,7681,7733,7737,7769,7770,7771,7807,7808,7867,7923,7973,7977,8072,8075,8076,8077,8078,8079,8147,8164,8171,8343,8350,8365,8366,8368,8383,8388,8425,8426,8427,8546,8583,8546,8547,8585,8589,8590,8627,8628,8630,8633,8756-8765,8767-8826,8828-8830,8832-8835,8837,8840-8844,8847-8922,8925-8928,8929-8931,8933-8947,8954,8955,8958,8959,8960-8972,8974-8984,8985-9029,9031-9035,9037-9059,9062-9087,9089-9143,9145-9148,9150-9152,9156-9171,9174-9178,9180-9185,9188,9190-9196,9198-9205,9207-9209,9211-9223,9225-9233,9239,9254,9280,9281,9282,9284,9311,9316,9319,9325,9330,9365,9421,9438,9440,9441,9443,9484,9593,9594,9595,9596,9597,9700,9701,9718,9888,10290,10303,10304,10313,10319,10322,10324,10450,10457,10464,10579,10580,10595,10647,10648,10662,10691,10692,10693,10694,10918,10920-10922,11111,11131,11149,11170,11222,11230,11264,11270,11282,11283,11291,11413,11470,11507,11511,11602,11609,11613,11616,11903,11947,11949,11954,12238,12241,12258,12263,12347,12348,12349,12468,12567,12615,12616,12617,12648,12649,12723,12731,12787,12816,12817,12826,12831,12832,12847,12866,12885,12904,12943,12947,12991,13155,13159,13316,13370,13422,13477,13480,13500,13612,13673,13754,13755,13756,13757,13758,13759,13760,13875,13876,13877,13878,13879,13880,13881,13882,13883,13884,13885,13886,13887,13888,13889,13890,13891,13893,13901,13902,13903,13904,13905,13906,13907,13908,13910,13911,13912,13914,13915,13916,13917,13918,14062,14083,14339,14341,14390,14392,14481,14488,14550,14586,14645,14891,15326,15327,15409,15410,15415,15417,15419,15422,15423,15448,15756,15769,15843,15845,16026,16041,16042,16047,16072,16073,16082,16083-16085,16165,16171,16180,16339,16664,16792,16967,16968,16969,16970,16971,16973,16999,17012,17024,17027,17195,17242,17262,17302,17305,17308,17323,17325,17362,17363,17696,17758,17882,17887,17967,17968,18002,18151,18153,18154,18235,18256,18341,18342,18492,18540,18566,18567,18599,18636,18642,18643,18651,18964,19004,19005,19006,19007,19008,19009,19010,19011,19012,19013,19296,19297,19298,19642,19725,19775,19808,19880,19882,19924,19960,20018,20020,20021,20030,20337,20364,20381,20404,20416,20418,20419,20420,20432,20433,20435,20436,20447,20448,20449,20450,20454,20455,20456,20498,20500,20501,20541,20545,20552,20591,20596,20676-20679,20696,20698,20708,20709,20720,20721,20722,20815,20819,20822,20824,20825,20829,20834,20844,20902,20903,20904,20913,20952,20953,20957,20962,20965,20977,20979,20981,20984,21043,21071,21113,21114,21140,21141,21150,21153,21162,21164,21168,21171,21228,21243,21281,21282,21283,21293,21302,21442,21536,21560,21577,21578,21591,21772,21773,21785,21786,21816,21817,21818,21819,21820,21821,21822,21823,21831,21835,21878,21927,21975,21979-21981,21992,22012,22018,22019,22020,22042,22045,22053,22054,22058,22103,22104,22105,21369,22140,22141,22142,22143,22144,22145,22154,22155,22156,22157,22158,22159,22160,22161,22162,22163,22164,22165,22166,22167,22168,22169,22170,22171,22172,22178,22202,22262,22263,22283,22284,22285,22286,22287,22288,22289,22290,22291,22292,22293,22294,22295,22296,22297,22298,22299,22300,22373,22374,22375,22376,22386,22387,22584,22709,22710,22733,22782,22788,22795,22797,22822,22891,22895,22896,22899,23003,23055,23076,23131,23135,23137,23140,23141,23144,23147,23148,23151,23152,23153,23157,23214,23227,23233,23234,23235,23248,23330,23340,23341,23342,23350,23352,23355,23360,23362-23364,23366,23378,23471,23486,23552,23567,23578,23579,23670,23683,23684,23686,23725-23728,23750,23754,23773,23840,23858,23866,23867,23868,23878,23879,23880,23885,23952,23980,24071,24100,24156,24188,24190,24226,24234,24235,24242,24243,24283,24288,24317,24368,24412,24476,24506,24509,24573,25145,25159,25173,25285,25407,25582,25627,25635,25677,25699,25700,25747,25748,25749,25750,25754,25755,25756,25757,25813,25814,25850,25877,26128,26129,26130,26131,26132,26133,26134,26135,26173,26174,26175,26180,26235,26324,26368,26372,26464,26465,26513,26527,26541,26548,26569,26655,26738,26765,26779,26792,26843,27002,27007,27196,27218,27419,27422,27425,27429,27435,27437,27438,27439,27441,27443,27446,27481,27511,27513,27515,27516,27590,27736,27774,27811,27863,27864,27965,28023,28039,28047,28099,28117,28122,28291,28388,28389,28489,28500,28596,28676,28784,28905,29041,29120,29311,29410,29419,29539,29547,29548,29565,29569,29571,29575,29576,29645,29712,29749,29751,29769,29790,29805,29839,29840,29841,29842,29852,29856,29857,29860,29861,29863,29868,29871,29872,29874,29885,29887,29961,29963,30193,30197,30414,30418,30427,30430,30438,30524,30525,30526,30539,30567,30595,30613,30630,30658,30659,30703,30717,30760,30805,30817,31123,31130,31246,31252,31266,31346,31365,31530,31607,31813,31824,31843,31845,31849,31942,32320,32364,32594,32595,32598,32601,32615,32618,32633,32642,32655,32656,32658,32659,32660,32661,32662,32663,32664,32665,32725,32734,32762,32763,32764,32765,32766,32767,32773,32839,32841,32906,32911,32914,32971,33041,33051,33063,33081,33087,33089,33096,33111,33183,33197,33218,33315,33316,33336,33341,33350,33558,33599,33604,33610,33614,33615,33616,33617,33781,33803,33823,33824,33839,33848,33850,33929,34024,34025,34030,34044,34062,34112,34115,34116,34117,34120,34123,34135,34142,34143,34171,34187,34191,34221,34467,34476,34494,34497,34501,34518,34519,34589,34590,34591,34622,34623,34627,34645,34647,34663,34694,34716,34718,34735,34737,34738,34739,34740,34741,34742,34743,34744,34745,34746,34784,34835,34842,34864,34865,34867,34868,34880,34907,35126,35202,35229,35285,35286,35289,35396,35397,35398,35399,35400,35417,35418,35419,35420,35421,35422,35423,35424,35425,35426,35427,35428,35429,35430,35431,35432,35433,35434,35435,35436,35437,35438,35439,35440,35441,35442,35443,35444,35445,35446,35447,35448,35449,35450,35451,35452,35453,35454,35455,35456,35457,35458,35459,35460,35461,35462,35512,35517,35518,35519,35520,35526,35527,35529,35531,35538,35541,35544,35546,35550,35551,35553,35555,35626,35664,35665,35666,35692,35701,35718,35738,35757,35777,35803,35806,35840,35854,36454,36477,36491,36505,36519,36533,36547,36575,36589,36603,36617,36631,36645,36659,36673,36687,36701,36715,36733,36743,36765,36768,36772,36781,36794,36795,36828,36829,36830,36836,36846,36848,36862,36863,36889,36890,36891,36892,36893,36894,36914,36915,37063,37089,37090,37100,37126,37148,37154,37174,37175,37176,37196,37197,37243,37244,37245,37250,37290,37301,37303,37326,37329,37335,37336,37337,37338,37343,37345,37346,37348,37364,37365,37366,37372,37410,37430,37452,37467,37501,37579,37587,37590,37611,37624,37625,37646,37647,37648,37671,37672,37673,37697,37698,37699,37706,37799,37800,37801,37839,37856,37857,37858,37878,38082,38089,38261,38263,38264,38266,38268,38269,38270,38271,38272,38273,38274,38292,38307,38324,38333,38380,38382,38387,38388,38389,38390,38426,38442,38443,38444,38445,38448,38483,38496,38497,38498,38512,38538,38561,38587,38597,38600,38605,38606,38619,38621,38622,38623,38624,38625,38629,38630,38631,38640,38643,38687,38916,38957,38958,38970,38983,38994,38996,39148,39151,39162,39163,39213,39302,39314,39334,39338,39339,39340,39341,39342,39343,39354,39472,39501,39502,39505,39526,39527,39575,39576,39614,39684,39685,39686,39687,39707,39708,39709,39710,39711,39738,39739,39743,39748,39754,39969,40110,40199,40218,40219,40220,40221,40222,40223,40224,40225,40226,40227,40228,40229,40230,40231,40232,40389,40411,40484,40533,40553,40686,40725,40727,40754,40776,40839,40892,40893,40948,41091,41093,41111,41118,41132,41147,41166,41178,41403-41423,41741,41750,41753,41800,41801,41802,41803,41804,41805,41806,41807,41808,41809,41810,41811,41812,41813,41814,42170,42171,42174,42179,42432,42433,42434,42440,42474,42545,42733,42776,42894,42940,42953,42975,42976,42977,42978,42979,42980,42981,42982,42983,42986,43002,43003,43006,43038,43087,43097,43099,43103,43104,43105,43106,43107,43108,43109,43136,43144,43149,43215,43230-43235,43237,43269,43270,43272,43274,43275,43276,43288,43298,43307,43321,43325,43326,43328,43329,43330,43333,43336,43337,43341,43362,43384,43468,43518,43523,43557,43558,43559,43560,43561,43562,43563,43571,43572,43576,43577,43611,43612,43613,43614,43620,43621,43643,43644,43645,43646,43647,43652,43653,43658,43659,43675,43676,43677,43678,43679,43680,43681,43682,43683,43684,43685,43686,43687,43694,43695,43701,43702,43703,43704,43705,43706,43707,43708,43709,43710,43711,43712,43713,43714,43715,43716,43717,43718,43719,43720,43721,43722,43723,44148,44158,44236,44299,44300,44304,44310,44311,44432,44434,44462,44475,44480,44499,44500,44501,44505,44506,44507,44508,44578,44580,44598,44600,44604,44607,44608,44609,44619,44620,44627,44629,44646,44656,44680,44700,44703,44705,44743,44755,44760,44761,44832,44833,44851,44852,44856,44915,44926,44948,44981,44994,45003,45006,45007,45008,45009,45026,45028,45029,45030,45031,45032,45033,45034,45035,45036,45045,45052,45082,45120,45172,45173,45174,45175,45188,45189,45190,45191,45194,45195,45196,45197,45198,45199,45200,45201,45202,45276,45277,45278,45280,45328,45568,45569,45575,45629,45630,45850,45851,45852,45853,45900,45901,45902,45903,45904,45905,45907,45908,45909,45942,46054,46055,46103,46104,46105,46319,46395,46399,46400,46401,46402,46403,46783,46830,46847,46849,46852,46887,46957,47030,47036,48601,48679,48945,49209,49223,49334,49373,49640,49680,49689,49739,49750,49873,49915,49916,49984,50248,50431,51809,52189,52202,52272,52275,52276,52345,52562,52563,52565,53510,54069,54291,54470,54822,81000-81013,81100-81108 258 | AuctionHouseBot.DisabledCraftedItemIDs = 724,733,787,954,955,1017,1082,1180,1181,1251,1477,1711,1712,2289,2290,2300,2302,2303,2304,2305,2306,2307,2308,2309,2310,2311,2312,2313,2314,2315,2316,2317,2454,2456,2457,2458,2459,2460,2568,2569,2570,2572,2575,2576,2577,2578,2579,2580,2581,2582,2583,2584,2585,2587,2679,2680,2681,2682,2683,2684,2685,2687,2844,2845,2847,2848,2849,2850,2851,2852,2853,2854,2857,2862,2863,2864,2865,2866,2867,2868,2869,2870,2871,2888,3012,3220,3239,3240,3241,3382,3383,3384,3386,3387,3388,3389,3390,3391,3469,3470,3471,3472,3473,3474,3478,3480,3481,3482,3483,3484,3485,3486,3487,3488,3489,3490,3491,3492,3530,3531,3662,3663,3664,3665,3666,3719,3726,3727,3728,3729,3823,3824,3825,3826,3828,3829,3835,3836,3837,3840,3841,3842,3843,3844,3845,3846,3847,3848,3849,3850,3851,3852,3853,3854,3855,3856,3859,4231,4233,4236,4237,4238,4239,4240,4241,4242,4243,4244,4245,4246,4247,4248,4249,4250,4251,4252,4253,4254,4255,4256,4257,4258,4259,4260,4262,4264,4265,4307,4308,4309,4310,4311,4312,4313,4314,4315,4316,4317,4318,4319,4320,4321,4322,4323,4324,4325,4326,4327,4328,4329,4330,4331,4332,4333,4334,4335,4336,4343,4344,4357,4358,4359,4360,4361,4362,4363,4364,4365,4366,4367,4368,4369,4370,4371,4372,4373,4374,4375,4376,4377,4378,4379,4380,4381,4382,4383,4384,4385,4386,4387,4388,4389,4390,4391,4392,4393,4394,4395,4396,4397,4398,4401,4403,4404,4405,4406,4407,4419,4422,4424,4425,4426,4455,4456,4457,4592,4593,4594,4623,4852,5081,5095,5472,5473,5474,5476,5477,5478,5479,5480,5507,5524,5525,5526,5527,5540,5541,5542,5631,5633,5634,5739,5762,5763,5764,5765,5766,5770,5780,5781,5782,5783,5957,5958,5961,5962,5963,5964,5965,5966,5996,5997,6038,6040,6041,6042,6043,6048,6049,6050,6051,6052,6182,6214,6219,6238,6239,6240,6241,6242,6243,6263,6264,6290,6316,6350,6370,6371,6372,6373,6384,6385,6450,6451,6452,6453,6466,6467,6468,6533,6657,6662,6709,6712,6714,6730,6731,6733,6786,6787,6795,6796,6836,6887,6888,6890,7026,7027,7046,7047,7048,7049,7050,7051,7052,7053,7054,7055,7056,7057,7058,7059,7060,7061,7062,7063,7064,7065,7071,7148,7166,7189,7191,7276,7277,7278,7279,7280,7281,7282,7283,7284,7285,7348,7349,7352,7358,7359,7371,7372,7373,7374,7375,7377,7378,7386,7387,7390,7391,7506,7676,7913,7914,7915,7916,7917,7918,7919,7920,7921,7922,7924,7925,7926,7927,7928,7929,7930,7931,7932,7933,7934,7935,7936,7937,7938,7939,7941,7942,7943,7944,7945,7946,7947,7954,7955,7956,7957,7958,7959,7960,7961,7963,7964,7965,7966,7967,7969,8172,8173,8174,8175,8176,8185,8187,8189,8191,8192,8193,8195,8197,8198,8200,8201,8202,8203,8204,8205,8206,8207,8208,8209,8210,8211,8212,8213,8214,8215,8216,8217,8218,8345,8346,8347,8348,8349,8364,8367,8544,8545,8827,8949,8951,8956,9030,9036,9060,9061,9088,9144,9149,9154,9155,9172,9179,9187,9197,9206,9210,9224,9233,9264,9312,9313,9318,9366,9718,9998,9999,10001,10002,10003,10004,10007,10008,10009,10010,10011,10018,10019,10020,10021,10023,10024,10025,10026,10027,10028,10029,10030,10031,10032,10033,10034,10035,10036,10038,10039,10040,10041,10042,10044,10045,10046,10047,10048,10050,10051,10052,10053,10054,10055,10056,10306,10307,10308,10309,10310,10421,10423,10498,10499,10500,10501,10502,10503,10504,10505,10506,10507,10508,10510,10514,10518,10542,10543,10545,10546,10548,10558,10559,10560,10561,10562,10576,10577,10580,10585,10586,10587,10588,10592,10644,10645,10646,10713,10716,10719,10720,10721,10723,10724,10725,10726,10727,10841,11287,11288,11289,11290,11371,11590,11604,11605,11606,11607,11608,11811,11825,11826,12190,12209,12210,12212,12213,12214,12215,12216,12217,12218,12224,12259,12260,12360,12404,12405,12406,12408,12409,12410,12414,12415,12416,12417,12418,12419,12420,12422,12424,12425,12426,12427,12428,12429,12610,12611,12612,12613,12614,12618,12619,12620,12624,12625,12628,12631,12632,12633,12636,12639,12640,12641,12643,12644,12645,12655,12764,12769,12772,12773,12774,12775,12776,12777,12779,12781,12782,12783,12784,12790,12792,12794,12795,12796,12797,12798,12802,12810,13423,13442,13445,13447,13452,13453,13454,13455,13456,13457,13458,13459,13460,13461,13462,13503,13506,13510,13511,13512,13513,13851,13856,13857,13858,13860,13863,13864,13865,13866,13867,13868,13869,13870,13871,13927,13928,13929,13930,13931,13932,13933,13934,13935,14042,14043,14044,14045,14046,14100,14101,14103,14104,14106,14107,14108,14111,14112,14128,14130,14132,14134,14136,14137,14138,14139,14140,14141,14142,14143,14144,14146,14152,14153,14154,14155,14156,14342,14529,14530,15045,15046,15047,15048,15049,15050,15051,15052,15053,15054,15055,15056,15057,15058,15059,15060,15061,15062,15063,15064,15065,15066,15067,15068,15069,15070,15071,15072,15073,15074,15075,15076,15077,15078,15079,15080,15081,15082,15083,15084,15085,15086,15087,15088,15090,15091,15092,15093,15094,15095,15096,15138,15141,15407,15409,15564,15802,15846,15869,15870,15871,15872,15992,15993,15994,15995,15996,15999,16000,16004,16005,16006,16007,16008,16009,16022,16023,16040,16766,16979,16980,16982,16983,16984,16988,16989,17013,17014,17015,17016,17182,17193,17197,17198,17202,17222,17704,17708,17716,17721,17723,17771,18045,18168,18232,18238,18251,18253,18254,18258,18262,18263,18282,18283,18294,18405,18407,18408,18409,18413,18486,18504,18506,18508,18509,18510,18511,18587,18588,18594,18631,18634,18637,18638,18639,18641,18645,18660,18662,18948,18984,18986,19026,19043,19044,19047,19048,19049,19050,19051,19052,19056,19057,19058,19059,19148,19149,19156,19157,19162,19163,19164,19165,19166,19167,19168,19169,19170,19440,19682,19683,19684,19685,19686,19687,19688,19689,19690,19691,19692,19693,19694,19695,19931,19998,19999,20002,20004,20007,20008,20039,20074,20295,20296,20380,20452,20476,20477,20478,20479,20480,20481,20537,20538,20539,20549,20550,20551,20575,20744,20745,20746,20747,20748,20749,20750,20816,20817,20818,20820,20821,20823,20826,20827,20828,20830,20831,20832,20833,20906,20907,20909,20950,20954,20955,20956,20958,20959,20960,20961,20963,20964,20966,20967,20969,21023,21072,21154,21217,21277,21278,21340,21341,21342,21542,21546,21557,21558,21559,21569,21570,21571,21574,21576,21589,21590,21592,21714,21716,21718,21748,21752,21753,21754,21755,21756,21758,21760,21763,21764,21765,21766,21767,21768,21769,21774,21775,21777,21778,21779,21780,21784,21785,21786,21789,21790,21791,21792,21793,21841,21842,21843,21844,21845,21846,21847,21848,21849,21850,21851,21852,21853,21854,21855,21858,21859,21860,21861,21862,21863,21864,21865,21866,21867,21868,21869,21870,21871,21872,21873,21874,21875,21876,21931,21932,21933,21934,21990,21991,22191,22194,22195,22196,22197,22198,22246,22248,22249,22251,22252,22383,22384,22385,22448,22459,22460,22521,22522,22645,22652,22654,22655,22658,22660,22661,22662,22663,22664,22665,22666,22669,22670,22671,22728,22756,22757,22758,22759,22760,22761,22762,22763,22764,22823,22824,22825,22826,22827,22828,22830,22831,22833,22834,22835,22836,22837,22838,22839,22840,22841,22842,22844,22845,22846,22847,22848,22849,22850,22851,22853,22854,22861,22866,22871,23094,23095,23096,23097,23098,23099,23100,23101,23103,23104,23105,23106,23108,23109,23110,23111,23113,23114,23115,23116,23118,23119,23120,23121,23448,23482,23484,23487,23488,23489,23490,23491,23493,23494,23497,23498,23499,23502,23503,23504,23505,23506,23507,23508,23509,23510,23511,23512,23513,23514,23515,23516,23517,23518,23519,23520,23521,23522,23523,23524,23525,23526,23527,23528,23529,23530,23531,23532,23533,23534,23535,23536,23537,23538,23539,23540,23541,23542,23543,23544,23546,23554,23555,23556,23559,23563,23564,23565,23571,23573,23575,23576,23736,23737,23742,23746,23747,23748,23758,23761,23762,23763,23764,23765,23766,23767,23768,23769,23770,23771,23774,23775,23781,23782,23783,23784,23785,23786,23787,23819,23820,23821,23824,23825,23826,23827,23828,23829,23831,23832,23835,23836,23838,23839,23840,23841,23854,23855,24027,24028,24029,24030,24031,24032,24033,24035,24036,24037,24039,24047,24048,24050,24051,24052,24053,24054,24055,24056,24057,24058,24059,24060,24061,24062,24065,24066,24067,24074,24075,24076,24077,24078,24079,24080,24082,24085,24086,24087,24088,24089,24092,24093,24095,24097,24098,24105,24106,24110,24114,24116,24117,24121,24122,24123,24124,24125,24126,24127,24128,24249,24250,24251,24252,24253,24254,24255,24256,24257,24258,24259,24260,24261,24262,24263,24264,24266,24267,24268,24269,24270,24271,24272,24273,24274,24275,24276,25438,25439,25498,25521,25650,25651,25652,25653,25654,25655,25656,25657,25659,25660,25661,25662,25668,25669,25670,25671,25673,25674,25675,25676,25679,25680,25681,25682,25683,25685,25686,25687,25689,25690,25691,25692,25693,25694,25695,25696,25697,25867,25868,25880,25881,25882,25883,25884,25886,25890,25893,25894,25895,25896,25897,25898,25899,25901,27498,27499,27501,27502,27503,27635,27636,27651,27655,27656,27657,27658,27659,27660,27661,27662,27663,27664,27665,27666,27667,28101,28102,28103,28104,28118,28119,28120,28123,28290,28362,28363,28420,28421,28425,28426,28427,28428,28429,28430,28431,28432,28433,28434,28435,28436,28437,28438,28439,28440,28441,28442,28483,28484,28485,28595,29157,29158,29159,29160,29201,29202,29203,29204,29483,29485,29486,29487,29488,29489,29490,29491,29492,29493,29494,29495,29496,29497,29498,29499,29500,29502,29503,29504,29505,29506,29507,29508,29509,29510,29511,29512,29514,29515,29516,29517,29519,29520,29521,29522,29523,29524,29525,29526,29527,29528,29529,29530,29531,29532,29533,29534,29535,29536,29540,29964,29970,29971,29973,29974,29975,30031,30032,30033,30034,30035,30036,30037,30038,30039,30040,30041,30042,30043,30044,30045,30046,30069,30070,30071,30072,30073,30074,30076,30077,30086,30087,30088,30089,30093,30155,30419,30420,30421,30422,30459,30460,30461,30463,30464,30465,30542,30544,30804,30816,30825,30831,30837,30838,30839,31079,31080,31154,31364,31367,31368,31369,31370,31371,31398,31399,31530,31672,31673,31676,31677,31679,31860,31861,31862,31863,31864,31865,31866,31867,31868,31869,31942,32062,32063,32067,32068,32193,32194,32195,32196,32197,32198,32199,32200,32201,32202,32203,32204,32205,32206,32207,32208,32209,32210,32211,32212,32213,32214,32215,32216,32217,32218,32219,32220,32221,32222,32223,32224,32225,32226,32230,32389,32390,32391,32392,32393,32394,32395,32396,32397,32398,32399,32400,32401,32402,32403,32404,32409,32410,32413,32420,32423,32461,32472,32473,32474,32475,32476,32478,32479,32480,32494,32495,32508,32568,32570,32571,32573,32574,32575,32577,32579,32580,32581,32582,32583,32584,32585,32586,32587,32594,32655,32656,32658,32659,32660,32661,32662,32663,32664,32665,32756,32772,32774,32776,32833,32836,32839,32849,32850,32851,32852,32854,33004,33048,33052,33053,33092,33093,33122,33131,33133,33134,33135,33140,33143,33144,33173,33185,33204,33208,33447,33457,33458,33460,33461,33462,33782,33791,33803,33825,33839,33848,33850,33866,33867,33872,33874,33924,34060,34061,34085,34086,34087,34099,34100,34105,34106,34113,34125,34207,34220,34330,34353,34354,34355,34356,34357,34358,34359,34360,34361,34362,34363,34364,34365,34366,34367,34369,34370,34371,34372,34373,34374,34375,34376,34377,34378,34379,34380,34411,34440,34482,34490,34504,34663,34721,34722,34747,34748,34749,34750,34751,34752,34753,34754,34755,34756,34757,34758,34759,34760,34761,34762,34763,34764,34765,34766,34767,34768,34769,34832,34847,35128,35181,35182,35183,35184,35185,35315,35316,35318,35501,35503,35563,35565,35581,35693,35694,35700,35702,35703,35707,35748,35749,35750,35751,35758,35759,35760,35761,35945,36766,36767,37091,37092,37093,37094,37097,37098,37101,37118,37168,37312,37503,37567,37602,37603,37663,37706,38225,38277,38278,38322,38347,38371,38372,38373,38374,38375,38376,38378,38387,38388,38389,38390,38399,38400,38401,38402,38403,38404,38405,38406,38407,38408,38409,38410,38411,38412,38413,38414,38415,38416,38417,38418,38419,38420,38421,38422,38424,38433,38434,38435,38436,38437,38438,38439,38440,38441,38590,38591,38592,38679,38682,38766,38767,38768,38769,38770,38771,38772,38773,38774,38775,38776,38777,38778,38779,38780,38781,38782,38783,38784,38785,38786,38787,38788,38789,38790,38791,38792,38793,38794,38795,38796,38797,38798,38799,38800,38801,38802,38803,38804,38805,38806,38807,38808,38809,38810,38811,38812,38813,38814,38815,38816,38817,38818,38819,38820,38821,38822,38823,38824,38825,38826,38827,38828,38829,38830,38831,38832,38833,38834,38835,38836,38838,38839,38840,38841,38842,38843,38844,38845,38846,38847,38848,38849,38850,38851,38852,38853,38854,38855,38856,38857,38858,38859,38860,38861,38862,38863,38864,38865,38866,38867,38868,38869,38870,38871,38872,38873,38874,38875,38876,38877,38878,38879,38880,38881,38882,38883,38884,38885,38886,38887,38888,38889,38890,38891,38892,38893,38894,38895,38896,38897,38898,38899,38900,38901,38902,38903,38904,38905,38906,38907,38908,38909,38910,38911,38912,38913,38914,38915,38916,38917,38918,38919,38920,38921,38922,38923,38924,38925,38926,38927,38928,38929,38930,38931,38932,38933,38934,38935,38936,38937,38938,38939,38940,38941,38942,38943,38944,38945,38946,38947,38948,38949,38950,38951,38953,38954,38955,38956,38959,38960,38961,38962,38963,38964,38965,38966,38967,38968,38969,38971,38972,38973,38974,38975,38976,38977,38978,38979,38980,38981,38982,38984,38985,38986,38987,38988,38989,38990,38991,38992,38993,38995,38997,38998,38999,39000,39001,39002,39003,39004,39005,39006,39083,39084,39085,39086,39087,39088,39349,39350,39469,39520,39666,39671,39681,39682,39683,39688,39690,39691,39707,39708,39709,39710,39711,39774,39900,39905,39906,39907,39908,39909,39910,39911,39912,39914,39915,39916,39917,39918,39919,39920,39927,39932,39933,39934,39935,39936,39937,39938,39939,39940,39941,39942,39943,39944,39945,39946,39947,39948,39949,39950,39951,39952,39953,39954,39955,39956,39957,39958,39959,39960,39961,39962,39963,39964,39965,39966,39967,39968,39974,39975,39976,39977,39978,39979,39980,39981,39982,39983,39984,39985,39986,39988,39989,39990,39991,39992,39996,39997,39998,39999,40000,40001,40002,40003,40008,40009,40010,40011,40012,40013,40014,40015,40016,40017,40022,40023,40024,40025,40026,40027,40028,40029,40030,40031,40032,40033,40034,40037,40038,40039,40040,40041,40043,40044,40045,40046,40047,40048,40049,40050,40051,40052,40053,40054,40055,40056,40057,40058,40059,40067,40068,40070,40072,40073,40076,40077,40078,40079,40081,40085,40086,40087,40088,40089,40090,40091,40092,40093,40094,40095,40096,40097,40098,40099,40100,40101,40102,40103,40104,40105,40106,40109,40111,40112,40113,40114,40115,40116,40117,40118,40119,40120,40121,40122,40123,40124,40125,40126,40127,40128,40129,40130,40131,40132,40133,40134,40135,40136,40137,40138,40139,40140,40141,40142,40143,40144,40145,40146,40147,40148,40149,40150,40151,40152,40153,40154,40155,40156,40157,40158,40159,40160,40161,40162,40163,40164,40165,40166,40167,40168,40169,40170,40171,40172,40173,40174,40175,40176,40177,40178,40179,40180,40181,40182,40195,40211,40212,40213,40214,40215,40216,40217,40248,40536,40668,40669,40670,40671,40672,40673,40674,40675,40767,40768,40769,40771,40772,40865,40892,40893,40895,40942,40943,40949,40950,40951,40952,40953,40954,40955,40956,40957,40958,40959,41112,41113,41114,41116,41117,41119,41121,41126,41127,41128,41129,41146,41165,41167,41168,41181,41182,41183,41184,41185,41186,41187,41188,41189,41190,41238,41239,41240,41241,41242,41243,41245,41248,41249,41250,41251,41252,41253,41254,41255,41257,41264,41266,41285,41307,41333,41334,41335,41339,41344,41345,41346,41347,41348,41349,41350,41351,41352,41353,41354,41355,41356,41357,41367,41375,41376,41377,41378,41379,41380,41381,41382,41383,41384,41385,41386,41387,41388,41389,41391,41392,41394,41395,41396,41397,41398,41400,41401,41508,41509,41511,41512,41513,41515,41516,41519,41520,41521,41522,41523,41525,41528,41543,41544,41545,41546,41548,41549,41550,41551,41553,41554,41555,41593,41594,41595,41597,41598,41599,41600,41601,41602,41603,41604,41607,41608,41609,41610,41611,41974,41975,41976,41984,41985,41986,42093,42095,42096,42100,42101,42102,42103,42111,42113,42142,42143,42144,42145,42146,42148,42149,42150,42151,42152,42153,42154,42155,42156,42157,42158,42336,42337,42338,42339,42340,42341,42395,42413,42418,42420,42421,42435,42443,42500,42508,42546,42549,42550,42551,42552,42553,42554,42555,42641,42642,42643,42644,42645,42646,42647,42701,42702,42723,42724,42725,42726,42727,42728,42729,42730,42731,42897,42942,42993,42994,42995,42996,42997,42998,42999,43000,43001,43004,43005,43015,43099,43115,43116,43117,43118,43119,43120,43121,43122,43123,43124,43125,43126,43127,43129,43130,43131,43132,43133,43136,43144,43145,43146,43149,43244,43245,43246,43247,43248,43249,43250,43251,43252,43253,43255,43256,43257,43258,43260,43261,43262,43263,43264,43265,43266,43268,43269,43270,43271,43272,43273,43274,43275,43276,43298,43433,43434,43435,43436,43437,43438,43439,43442,43443,43444,43445,43446,43447,43448,43449,43450,43451,43452,43453,43454,43455,43456,43457,43458,43459,43461,43463,43464,43465,43466,43469,43478,43480,43481,43482,43484,43488,43490,43491,43492,43495,43498,43502,43515,43565,43566,43569,43570,43582,43583,43584,43585,43586,43587,43588,43590,43591,43592,43593,43594,43595,43654,43655,43656,43657,43660,43661,43663,43664,43666,43667,43850,43853,43854,43860,43864,43865,43870,43871,43969,43970,43971,43972,43973,43974,43975,43987,44063,44142,44161,44163,44210,44211,44314,44315,44322,44323,44324,44325,44327,44328,44329,44330,44331,44332,44413,44436,44437,44438,44440,44441,44442,44443,44444,44445,44446,44447,44448,44449,44453,44455,44456,44457,44458,44463,44465,44466,44467,44469,44470,44493,44497,44504,44554,44555,44556,44557,44558,44739,44740,44741,44742,44815,44836,44837,44838,44839,44840,44930,44931,44936,44939,44943,44946,44947,44949,44951,44953,44958,44963,45054,45056,45060,45085,45550,45551,45552,45553,45554,45555,45556,45557,45558,45559,45560,45561,45562,45563,45564,45565,45566,45567,45621,45626,45627,45628,45631,45773,45808,45809,45810,45811,45812,45813,45849,45854,45862,45874,45879,45880,45881,45882,45883,45932,45987,46026,46098,46376,46377,46378,46379,46691,47499,47570,47571,47572,47573,47574,47575,47576,47577,47579,47580,47581,47582,47583,47584,47585,47586,47587,47588,47589,47590,47591,47592,47593,47594,47595,47596,47597,47598,47599,47600,47601,47602,47603,47604,47605,47606,47828,48933,48945,49040,49110,49632,49633,49634,49768,49890,49891,49892,49893,49894,49895,49896,49897,49898,49899,49900,49901,49902,49903,49904,49905,49906,49907,50816,54797,81000,81001,81002,81003,81004,81005,81006,81007,81008 -------------------------------------------------------------------------------- /data/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NathanHandley/mod-ah-bot/694f3a8853bbaec3afb6ec641d26b9a3f8f28b79/data/.gitkeep -------------------------------------------------------------------------------- /data/sql/db-auth/base/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NathanHandley/mod-ah-bot/694f3a8853bbaec3afb6ec641d26b9a3f8f28b79/data/sql/db-auth/base/.gitkeep -------------------------------------------------------------------------------- /data/sql/db-auth/updates/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NathanHandley/mod-ah-bot/694f3a8853bbaec3afb6ec641d26b9a3f8f28b79/data/sql/db-auth/updates/.gitkeep -------------------------------------------------------------------------------- /data/sql/db-characters/base/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NathanHandley/mod-ah-bot/694f3a8853bbaec3afb6ec641d26b9a3f8f28b79/data/sql/db-characters/base/.gitkeep -------------------------------------------------------------------------------- /data/sql/db-characters/updates/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NathanHandley/mod-ah-bot/694f3a8853bbaec3afb6ec641d26b9a3f8f28b79/data/sql/db-characters/updates/.gitkeep -------------------------------------------------------------------------------- /data/sql/db-world/base/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NathanHandley/mod-ah-bot/694f3a8853bbaec3afb6ec641d26b9a3f8f28b79/data/sql/db-world/base/.gitkeep -------------------------------------------------------------------------------- /data/sql/db-world/base/mod_auctionhousebot.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE IF EXISTS `mod_auctionhousebot`; -------------------------------------------------------------------------------- /data/sql/db-world/updates/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NathanHandley/mod-ah-bot/694f3a8853bbaec3afb6ec641d26b9a3f8f28b79/data/sql/db-world/updates/.gitkeep -------------------------------------------------------------------------------- /include.sh: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NathanHandley/mod-ah-bot/694f3a8853bbaec3afb6ec641d26b9a3f8f28b79/include.sh -------------------------------------------------------------------------------- /pull_request_template.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Changes Proposed: 4 | - 5 | - 6 | 7 | ## Issues Addressed: 8 | 9 | - Closes 10 | 11 | ## SOURCE: 12 | 13 | 14 | ## Tests Performed: 15 | 16 | - 17 | - 18 | 19 | 20 | ## How to Test the Changes: 21 | 22 | 23 | 1. 24 | 2. 25 | 3. 26 | -------------------------------------------------------------------------------- /src/AuctionHouseBot.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2008-2010 Trinity 3 | * Copyright (C) 2005-2009 MaNGOS 4 | * Copyright (C) 2023+ Nathan Handley 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 | */ 20 | 21 | #include "ObjectMgr.h" 22 | #include "AuctionHouseMgr.h" 23 | #include "AuctionHouseBot.h" 24 | #include "Config.h" 25 | #include "Player.h" 26 | #include "WorldSession.h" 27 | #include "GameTime.h" 28 | #include "DatabaseEnv.h" 29 | 30 | #include 31 | 32 | using namespace std; 33 | 34 | AuctionHouseBot::AuctionHouseBot() 35 | { 36 | debug_Out = false; 37 | debug_Out_Filters = false; 38 | AHBSeller = false; 39 | AHBBuyer = false; 40 | 41 | _lastrun_a = time(NULL); 42 | _lastrun_h = time(NULL); 43 | _lastrun_n = time(NULL); 44 | 45 | AllianceConfig = AHBConfig(2); 46 | HordeConfig = AHBConfig(6); 47 | NeutralConfig = AHBConfig(7); 48 | } 49 | 50 | AuctionHouseBot::~AuctionHouseBot() 51 | { 52 | } 53 | 54 | uint32 AuctionHouseBot::getStackSizeForItem(ItemTemplate const* itemProto) const 55 | { 56 | // Determine the stack ratio based on class type 57 | if (itemProto == NULL) 58 | return 1; 59 | 60 | // TODO: Move this to a config 61 | uint32 stackRatio = 0; 62 | switch (itemProto->Class) 63 | { 64 | case ITEM_CLASS_CONSUMABLE: stackRatio = RandomStackRatioConsumable; break; 65 | case ITEM_CLASS_CONTAINER: stackRatio = RandomStackRatioContainer; break; 66 | case ITEM_CLASS_WEAPON: stackRatio = RandomStackRatioWeapon; break; 67 | case ITEM_CLASS_GEM: stackRatio = RandomStackRatioGem; break; 68 | case ITEM_CLASS_REAGENT: stackRatio = RandomStackRatioReagent; break; 69 | case ITEM_CLASS_ARMOR: stackRatio = RandomStackRatioArmor; break; 70 | case ITEM_CLASS_PROJECTILE: stackRatio = RandomStackRatioProjectile; break; 71 | case ITEM_CLASS_TRADE_GOODS: stackRatio = RandomStackRatioTradeGood; break; 72 | case ITEM_CLASS_GENERIC: stackRatio = RandomStackRatioGeneric; break; 73 | case ITEM_CLASS_RECIPE: stackRatio = RandomStackRatioRecipe; break; 74 | case ITEM_CLASS_QUIVER: stackRatio = RandomStackRatioQuiver; break; 75 | case ITEM_CLASS_QUEST: stackRatio = RandomStackRatioQuest; break; 76 | case ITEM_CLASS_KEY: stackRatio = RandomStackRatioKey; break; 77 | case ITEM_CLASS_MISC: stackRatio = RandomStackRatioMisc; break; 78 | case ITEM_CLASS_GLYPH: stackRatio = RandomStackRatioGlyph; break; 79 | default: stackRatio = 0; break; 80 | } 81 | 82 | if (stackRatio > urand(0, 99)) 83 | return urand(1, itemProto->GetMaxStackSize()); 84 | else 85 | return 1; 86 | } 87 | 88 | void AuctionHouseBot::calculateItemValue(ItemTemplate const* itemProto, uint64& outBidPrice, uint64& outBuyoutPrice) 89 | { 90 | // Start with a buyout price related to the sell price 91 | outBuyoutPrice = itemProto->SellPrice; 92 | 93 | // Get the price multipliers 94 | float classPriceMultiplier = 1; 95 | switch (itemProto->Class) 96 | { 97 | case ITEM_CLASS_CONSUMABLE: classPriceMultiplier = PriceMultiplierCategoryConsumable; break; 98 | case ITEM_CLASS_CONTAINER: classPriceMultiplier = PriceMultiplierCategoryContainer; break; 99 | case ITEM_CLASS_WEAPON: classPriceMultiplier = PriceMultiplierCategoryWeapon; break; 100 | case ITEM_CLASS_GEM: classPriceMultiplier = PriceMultiplierCategoryGem; break; 101 | case ITEM_CLASS_REAGENT: classPriceMultiplier = PriceMultiplierCategoryReagent; break; 102 | case ITEM_CLASS_ARMOR: classPriceMultiplier = PriceMultiplierCategoryArmor; break; 103 | case ITEM_CLASS_PROJECTILE: classPriceMultiplier = PriceMultiplierCategoryProjectile; break; 104 | case ITEM_CLASS_TRADE_GOODS: classPriceMultiplier = PriceMultiplierCategoryTradeGood; break; 105 | case ITEM_CLASS_GENERIC: classPriceMultiplier = PriceMultiplierCategoryGeneric; break; 106 | case ITEM_CLASS_RECIPE: classPriceMultiplier = PriceMultiplierCategoryRecipe; break; 107 | case ITEM_CLASS_QUIVER: classPriceMultiplier = PriceMultiplierCategoryQuiver; break; 108 | case ITEM_CLASS_QUEST: classPriceMultiplier = PriceMultiplierCategoryQuest; break; 109 | case ITEM_CLASS_KEY: classPriceMultiplier = PriceMultiplierCategoryKey; break; 110 | case ITEM_CLASS_MISC: classPriceMultiplier = PriceMultiplierCategoryMisc; break; 111 | case ITEM_CLASS_GLYPH: classPriceMultiplier = PriceMultiplierCategoryGlyph; break; 112 | default: break; 113 | } 114 | 115 | float qualityPriceMultplier = 1; 116 | switch (itemProto->Quality) 117 | { 118 | case ITEM_QUALITY_POOR: qualityPriceMultplier = PriceMultiplierQualityPoor; break; 119 | case ITEM_QUALITY_NORMAL: qualityPriceMultplier = PriceMultiplierQualityNormal; break; 120 | case ITEM_QUALITY_UNCOMMON: qualityPriceMultplier = PriceMultiplierQualityUncommon; break; 121 | case ITEM_QUALITY_RARE: qualityPriceMultplier = PriceMultiplierQualityRare; break; 122 | case ITEM_QUALITY_EPIC: qualityPriceMultplier = PriceMultiplierQualityEpic; break; 123 | case ITEM_QUALITY_LEGENDARY: qualityPriceMultplier = PriceMultiplierQualityLegendary; break; 124 | case ITEM_QUALITY_ARTIFACT: qualityPriceMultplier = PriceMultiplierQualityArtifact; break; 125 | case ITEM_QUALITY_HEIRLOOM: qualityPriceMultplier = PriceMultiplierQualityHeirloom; break; 126 | default: break; 127 | } 128 | 129 | // Grab the minimum prices 130 | uint64 PriceMinimumCenterBase = 1000; 131 | auto it = PriceMinimumCenterBaseOverridesByItemID.find(itemProto->ItemId); 132 | if (it != PriceMinimumCenterBaseOverridesByItemID.end()) 133 | PriceMinimumCenterBase = it->second; 134 | else 135 | { 136 | switch (itemProto->Class) 137 | { 138 | case ITEM_CLASS_CONSUMABLE: PriceMinimumCenterBase = PriceMinimumCenterBaseConsumable; break; 139 | case ITEM_CLASS_CONTAINER: PriceMinimumCenterBase = PriceMinimumCenterBaseContainer; break; 140 | case ITEM_CLASS_WEAPON: PriceMinimumCenterBase = PriceMinimumCenterBaseWeapon; break; 141 | case ITEM_CLASS_GEM: PriceMinimumCenterBase = PriceMinimumCenterBaseGem; break; 142 | case ITEM_CLASS_REAGENT: PriceMinimumCenterBase = PriceMinimumCenterBaseReagent; break; 143 | case ITEM_CLASS_ARMOR: PriceMinimumCenterBase = PriceMinimumCenterBaseArmor; break; 144 | case ITEM_CLASS_PROJECTILE: PriceMinimumCenterBase = PriceMinimumCenterBaseProjectile; break; 145 | case ITEM_CLASS_TRADE_GOODS: PriceMinimumCenterBase = PriceMinimumCenterBaseTradeGood; break; 146 | case ITEM_CLASS_GENERIC: PriceMinimumCenterBase = PriceMinimumCenterBaseGeneric; break; 147 | case ITEM_CLASS_RECIPE: PriceMinimumCenterBase = PriceMinimumCenterBaseRecipe; break; 148 | case ITEM_CLASS_QUIVER: PriceMinimumCenterBase = PriceMinimumCenterBaseQuiver; break; 149 | case ITEM_CLASS_QUEST: PriceMinimumCenterBase = PriceMinimumCenterBaseQuest; break; 150 | case ITEM_CLASS_KEY: PriceMinimumCenterBase = PriceMinimumCenterBaseKey; break; 151 | case ITEM_CLASS_MISC: PriceMinimumCenterBase = PriceMinimumCenterBaseMisc; break; 152 | case ITEM_CLASS_GLYPH: PriceMinimumCenterBase = PriceMinimumCenterBaseGlyph; break; 153 | default: break; 154 | } 155 | } 156 | 157 | // Set the minimum price 158 | if (outBuyoutPrice < PriceMinimumCenterBase) 159 | outBuyoutPrice = urand(PriceMinimumCenterBase * 0.75, PriceMinimumCenterBase * 1.25); 160 | else 161 | outBuyoutPrice = urand(outBuyoutPrice * 0.75, outBuyoutPrice * 1.25); 162 | 163 | // Multiply the price based on multipliers 164 | outBuyoutPrice *= qualityPriceMultplier; 165 | outBuyoutPrice *= classPriceMultiplier; 166 | 167 | // If a vendor sells this item, make the price at least that high 168 | if (itemProto->SellPrice > outBuyoutPrice) 169 | outBuyoutPrice = itemProto->SellPrice; 170 | 171 | // Calculate buyout price with a variance 172 | float sellVarianceBuyoutPriceTopPercent = 1.30; 173 | float sellVarianceBuyoutPriceBottomPercent = 0.70; 174 | outBuyoutPrice = urand(sellVarianceBuyoutPriceBottomPercent * outBuyoutPrice, sellVarianceBuyoutPriceTopPercent * outBuyoutPrice); 175 | 176 | // Calculate a bid price based on a variance against buyout price 177 | float sellVarianceBidPriceTopPercent = 1; 178 | float sellVarianceBidPriceBottomPercent = .75; 179 | outBidPrice = urand(sellVarianceBidPriceBottomPercent * outBuyoutPrice, sellVarianceBidPriceTopPercent * outBuyoutPrice); 180 | 181 | // If variance brought price below sell price, bring it back up to avoid making money off vendoring AH items 182 | if (outBuyoutPrice < itemProto->SellPrice) 183 | { 184 | float minLowPriceAddVariancePercent = 1.25; 185 | outBuyoutPrice = urand(itemProto->SellPrice, minLowPriceAddVariancePercent * itemProto->SellPrice); 186 | } 187 | 188 | // Bid price can never be below sell price 189 | if (outBidPrice < itemProto->SellPrice) 190 | { 191 | outBidPrice = itemProto->SellPrice; 192 | } 193 | } 194 | 195 | void AuctionHouseBot::populatetemClassSeedListForItemClass(uint32 itemClass, uint32 itemClassSeedWeight) 196 | { 197 | for (uint32 i = 0; i < itemClassSeedWeight; ++i) 198 | itemCandidateClassWeightedProportionList.push_back(itemClass); 199 | } 200 | 201 | void AuctionHouseBot::populateItemClassProportionList() 202 | { 203 | // Determine how many of what kinds of items to use based on a seeded weight list, 0 = none 204 | 205 | // Clear old list 206 | itemCandidateClassWeightedProportionList.clear(); 207 | 208 | // Fill the list 209 | populatetemClassSeedListForItemClass(ITEM_CLASS_CONSUMABLE, ListProportionConsumable); 210 | populatetemClassSeedListForItemClass(ITEM_CLASS_CONTAINER, ListProportionContainer); 211 | populatetemClassSeedListForItemClass(ITEM_CLASS_WEAPON, ListProportionWeapon); 212 | populatetemClassSeedListForItemClass(ITEM_CLASS_GEM, ListProportionGem); 213 | populatetemClassSeedListForItemClass(ITEM_CLASS_ARMOR, ListProportionArmor); 214 | populatetemClassSeedListForItemClass(ITEM_CLASS_REAGENT, ListProportionReagent); 215 | populatetemClassSeedListForItemClass(ITEM_CLASS_PROJECTILE, ListProportionProjectile); 216 | populatetemClassSeedListForItemClass(ITEM_CLASS_TRADE_GOODS, ListProportionTradeGood); 217 | populatetemClassSeedListForItemClass(ITEM_CLASS_GENERIC, ListProportionGeneric); 218 | populatetemClassSeedListForItemClass(ITEM_CLASS_RECIPE, ListProportionRecipe); 219 | populatetemClassSeedListForItemClass(ITEM_CLASS_QUIVER, ListProportionQuiver); 220 | populatetemClassSeedListForItemClass(ITEM_CLASS_QUEST, ListProportionQuest); 221 | populatetemClassSeedListForItemClass(ITEM_CLASS_KEY, ListProportionKey); 222 | populatetemClassSeedListForItemClass(ITEM_CLASS_MISC, ListProportionMisc); 223 | populatetemClassSeedListForItemClass(ITEM_CLASS_GLYPH, ListProportionGlyph); 224 | } 225 | 226 | void AuctionHouseBot::populateItemCandidateList() 227 | { 228 | // Clear old list and rebuild it 229 | itemCandidatesByItemClass.clear(); 230 | itemCandidatesByItemClass[ITEM_CLASS_CONSUMABLE] = vector(); 231 | itemCandidatesByItemClass[ITEM_CLASS_CONTAINER] = vector(); 232 | itemCandidatesByItemClass[ITEM_CLASS_WEAPON] = vector(); 233 | itemCandidatesByItemClass[ITEM_CLASS_GEM] = vector(); 234 | itemCandidatesByItemClass[ITEM_CLASS_ARMOR] = vector(); 235 | itemCandidatesByItemClass[ITEM_CLASS_REAGENT] = vector(); 236 | itemCandidatesByItemClass[ITEM_CLASS_PROJECTILE] = vector(); 237 | itemCandidatesByItemClass[ITEM_CLASS_TRADE_GOODS] = vector(); 238 | itemCandidatesByItemClass[ITEM_CLASS_GENERIC] = vector(); 239 | itemCandidatesByItemClass[ITEM_CLASS_RECIPE] = vector(); 240 | itemCandidatesByItemClass[ITEM_CLASS_QUIVER] = vector(); 241 | itemCandidatesByItemClass[ITEM_CLASS_QUEST] = vector(); 242 | itemCandidatesByItemClass[ITEM_CLASS_KEY] = vector(); 243 | itemCandidatesByItemClass[ITEM_CLASS_MISC] = vector(); 244 | itemCandidatesByItemClass[ITEM_CLASS_GLYPH] = vector(); 245 | 246 | // Item include exceptions 247 | set includeItemIDExecptions; 248 | includeItemIDExecptions.insert(11732); 249 | includeItemIDExecptions.insert(11733); 250 | includeItemIDExecptions.insert(11734); 251 | includeItemIDExecptions.insert(11736); 252 | includeItemIDExecptions.insert(11737); 253 | includeItemIDExecptions.insert(18332); 254 | includeItemIDExecptions.insert(18333); 255 | includeItemIDExecptions.insert(18334); 256 | includeItemIDExecptions.insert(18335); 257 | 258 | // Fill list 259 | ItemTemplateContainer const* its = sObjectMgr->GetItemTemplateStore(); 260 | for (ItemTemplateContainer::const_iterator itr = its->begin(); itr != its->end(); ++itr) 261 | { 262 | // Never store curBlock zero 263 | if (itr->second.ItemId == 0) 264 | continue; 265 | 266 | // If there is an iLevel exception, honor it 267 | if (ListedItemLevelRestrictedEnabled == true) 268 | { 269 | // Only test if it's not an exception 270 | if (ListedItemLevelExceptionItems.find(itr->second.ItemId) == ListedItemLevelExceptionItems.end()) 271 | { 272 | if (itr->second.ItemLevel < ListedItemLevelMin) 273 | continue; 274 | if (itr->second.ItemLevel > ListedItemLevelMax) 275 | continue; 276 | } 277 | } 278 | 279 | // Disabled items by Id 280 | if (DisabledItems.find(itr->second.ItemId) != DisabledItems.end()) 281 | { 282 | if (debug_Out_Filters) 283 | LOG_ERROR("module", "AuctionHouseBot: Item {} disabled (PTR/Beta/Unused Item)", itr->second.ItemId); 284 | continue; 285 | } 286 | 287 | // These items should be included and would otherwise be skipped due to conditions below 288 | if (includeItemIDExecptions.find(itr->second.ItemId) != includeItemIDExecptions.end()) 289 | { 290 | // Store the item ID 291 | itemCandidatesByItemClass[itr->second.Class].push_back(itr->second.ItemId); 292 | continue; 293 | } 294 | 295 | // Skip any items not in the seed list 296 | if (std::find(itemCandidateClassWeightedProportionList.begin(), itemCandidateClassWeightedProportionList.end(), itr->second.Class) == itemCandidateClassWeightedProportionList.end()) 297 | continue; 298 | 299 | // Skip any BOP items 300 | if (itr->second.Bonding == BIND_WHEN_PICKED_UP || itr->second.Bonding == BIND_QUEST_ITEM) 301 | { 302 | if (debug_Out_Filters) 303 | LOG_ERROR("module", "AuctionHouseBot: Item {} disabled (BOP or BQI)", itr->second.ItemId); 304 | continue; 305 | } 306 | 307 | // Restrict quality to anything under 7 (artifact and below) or above poor 308 | if (itr->second.Quality == 0 || itr->second.Quality > 6) 309 | continue; 310 | 311 | // Disable conjured items 312 | if (itr->second.IsConjuredConsumable()) 313 | { 314 | if (debug_Out_Filters) 315 | LOG_ERROR("module", "AuctionHouseBot: Item {} disabled (Conjured Consumable)", itr->second.ItemId); 316 | continue; 317 | } 318 | 319 | // Disable money 320 | if (itr->second.Class == ITEM_CLASS_MONEY) 321 | { 322 | if (debug_Out_Filters) 323 | LOG_ERROR("module", "AuctionHouseBot: Item {} disabled (Money)", itr->second.ItemId); 324 | continue; 325 | } 326 | 327 | // Disable moneyloot 328 | if (itr->second.MinMoneyLoot > 0) 329 | { 330 | if (debug_Out_Filters) 331 | LOG_ERROR("module", "AuctionHouseBot: Item {} disabled (MoneyLoot)", itr->second.ItemId); 332 | continue; 333 | } 334 | 335 | // Disable items with duration 336 | if (itr->second.Duration > 0) 337 | { 338 | if (debug_Out_Filters) 339 | LOG_ERROR("module", "AuctionHouseBot: Item {} disabled (Has a Duration)", itr->second.ItemId); 340 | continue; 341 | } 342 | 343 | // Disable containers with zero slots 344 | if (itr->second.Class == ITEM_CLASS_CONTAINER && itr->second.ContainerSlots == 0) 345 | { 346 | if (debug_Out_Filters) 347 | LOG_ERROR("module", "AuctionHouseBot: Item {} disabled (Container with no slots)", itr->second.ItemId); 348 | continue; 349 | } 350 | 351 | // Disable normal class 'book' recipies, since they are junk 352 | if (itr->second.Class == ITEM_CLASS_RECIPE && itr->second.SubClass == ITEM_SUBCLASS_BOOK && itr->second.Quality <= ITEM_QUALITY_NORMAL) 353 | { 354 | if (debug_Out_Filters) 355 | LOG_ERROR("module", "AuctionHouseBot: Item {} disabled (Normal or lower recipe book)", itr->second.ItemId); 356 | continue; 357 | } 358 | 359 | // Disable anything with the string literal of a testing or depricated item 360 | if (DisabledItemTextFilter == true && 361 | (itr->second.Name1.find("Test ") != std::string::npos || 362 | itr->second.Name1.find("TEST") != std::string::npos || 363 | itr->second.Name1.find("Deprecated") != std::string::npos || 364 | itr->second.Name1.find("Depricated") != std::string::npos || 365 | itr->second.Name1.find(" Epic ") != std::string::npos || 366 | itr->second.Name1.find("]") != std::string::npos || 367 | itr->second.Name1.find("D'Sak") != std::string::npos || 368 | itr->second.Name1.find("(") != std::string::npos || 369 | itr->second.Name1.find("OLD") != std::string::npos)) 370 | { 371 | if (debug_Out_Filters) 372 | LOG_ERROR("module", "AuctionHouseBot: Item {} disabled item with a temp or unused item name", itr->second.ItemId); 373 | continue; 374 | } 375 | 376 | // Disabled crafted gems that start with "Perfect" 377 | if (itr->second.Class == ITEM_CLASS_GEM && itr->second.Name1.find("Perfect ") != std::string::npos) 378 | { 379 | if (debug_Out_Filters) 380 | LOG_ERROR("module", "AuctionHouseBot: Item {} disabled as it's a perfect crafted gem", itr->second.ItemId); 381 | continue; 382 | } 383 | 384 | // Disable all items that have neither a sell or a buy price, with exception of item enhancements and trade goods 385 | bool isEnchantingTradeGood = (itr->second.Class == ITEM_CLASS_TRADE_GOODS && itr->second.SubClass == ITEM_SUBCLASS_ENCHANTING); 386 | bool isItemEnhancement = (itr->second.Class == ITEM_CLASS_CONSUMABLE && itr->second.SubClass == ITEM_SUBCLASS_ITEM_ENHANCEMENT); 387 | bool hasNoPrice = (itr->second.SellPrice == 0 && itr->second.BuyPrice == 0); 388 | if (hasNoPrice == true && isItemEnhancement == false && isEnchantingTradeGood == false) 389 | { 390 | if (debug_Out_Filters) 391 | LOG_ERROR("module", "AuctionHouseBot: Item {} disabled misc item", itr->second.ItemId); 392 | continue; 393 | } 394 | 395 | // Disable common weapons 396 | if (itr->second.Quality == ITEM_QUALITY_NORMAL && itr->second.Class == ITEM_CLASS_WEAPON) 397 | { 398 | if (debug_Out_Filters) 399 | LOG_ERROR("module", "AuctionHouseBot: Item {} disabled common weapon", itr->second.ItemId); 400 | continue; 401 | } 402 | 403 | // Disable common armor 404 | if (itr->second.Quality == ITEM_QUALITY_NORMAL && itr->second.Class == ITEM_CLASS_ARMOR) 405 | { 406 | if (debug_Out_Filters) 407 | LOG_ERROR("module", "AuctionHouseBot: Item {} disabled common non-misc armor", itr->second.ItemId); 408 | continue; 409 | } 410 | 411 | // Store the item ID 412 | itemCandidatesByItemClass[itr->second.Class].push_back(itr->second.ItemId); 413 | 414 | // Store a second copy if it's a trade good of certain types to double the chances 415 | if (itr->second.Class == ITEM_CLASS_TRADE_GOODS) 416 | { 417 | if (itr->second.SubClass == ITEM_SUBCLASS_CLOTH || itr->second.SubClass == ITEM_SUBCLASS_LEATHER || 418 | itr->second.SubClass == ITEM_SUBCLASS_ENCHANTING || itr->second.SubClass == ITEM_SUBCLASS_HERB || 419 | itr->second.SubClass == ITEM_SUBCLASS_METAL_STONE) 420 | { 421 | itemCandidatesByItemClass[itr->second.Class].push_back(itr->second.ItemId); 422 | } 423 | } 424 | } 425 | 426 | if (debug_Out) 427 | { 428 | for (auto& itemCandidatesInClass : itemCandidatesByItemClass) 429 | { 430 | LOG_INFO("module", "Item count in class {} is {}", itemCandidatesInClass.first, itemCandidatesInClass.second.size()); 431 | } 432 | } 433 | } 434 | 435 | void AuctionHouseBot::addNewAuctions(Player* AHBplayer, AHBConfig *config) 436 | { 437 | if (!AHBSeller) 438 | { 439 | if (debug_Out) 440 | LOG_INFO("module", "AHSeller: Disabled"); 441 | return; 442 | } 443 | 444 | uint32 minItems = config->GetMinItems(); 445 | uint32 maxItems = config->GetMaxItems(); 446 | 447 | if (maxItems == 0) 448 | return; 449 | 450 | AuctionHouseEntry const* ahEntry = sAuctionMgr->GetAuctionHouseEntryFromFactionTemplate(config->GetAHFID()); 451 | if (!ahEntry) 452 | { 453 | return; 454 | } 455 | AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(config->GetAHFID()); 456 | if (!auctionHouse) 457 | { 458 | return; 459 | } 460 | 461 | uint32 auctions = auctionHouse->Getcount(); 462 | 463 | uint32 items = 0; 464 | 465 | if (auctions >= minItems) 466 | { 467 | if (debug_Out) 468 | LOG_ERROR("module", "AHSeller: Auctions above minimum"); 469 | return; 470 | } 471 | 472 | if (auctions >= maxItems) 473 | { 474 | if (debug_Out) 475 | LOG_ERROR("module", "AHSeller: Auctions at or above maximum"); 476 | return; 477 | } 478 | 479 | if ((maxItems - auctions) >= ItemsPerCycle) 480 | items = ItemsPerCycle; 481 | else 482 | items = (maxItems - auctions); 483 | 484 | if (debug_Out) 485 | LOG_INFO("module", "AHSeller: Adding {} Auctions", items); 486 | 487 | if (debug_Out) 488 | LOG_ERROR("module", "AHSeller: Current house id is {}", config->GetAHID()); 489 | 490 | if (debug_Out) 491 | LOG_ERROR("module", "AHSeller: {} items", items); 492 | 493 | // only insert a few at a time, so as not to peg the processor 494 | for (uint32 cnt = 1; cnt <= items; cnt++) 495 | { 496 | if (debug_Out) 497 | LOG_ERROR("module", "AHSeller: {} count", cnt); 498 | 499 | // Pull a random item out of the candidate list 500 | uint32 chosenItemClass = itemCandidateClassWeightedProportionList[urand(0, itemCandidateClassWeightedProportionList.size() - 1)]; 501 | uint32 itemID = 0; 502 | if (itemCandidatesByItemClass[chosenItemClass].size() != 0) 503 | itemID = itemCandidatesByItemClass[chosenItemClass][urand(0, itemCandidatesByItemClass[chosenItemClass].size() - 1)]; 504 | 505 | // Prevent invalid IDs 506 | if (itemID == 0) 507 | { 508 | if (debug_Out) 509 | LOG_ERROR("module", "AHSeller: Item::CreateItem() - ItemID is 0", chosenItemClass); 510 | continue; 511 | } 512 | 513 | ItemTemplate const* prototype = sObjectMgr->GetItemTemplate(itemID); 514 | if (prototype == NULL) 515 | { 516 | if (debug_Out) 517 | LOG_ERROR("module", "AHSeller: prototype == NULL"); 518 | continue; 519 | } 520 | 521 | Item* item = Item::CreateItem(itemID, 1, AHBplayer); 522 | if (item == NULL) 523 | { 524 | if (debug_Out) 525 | LOG_ERROR("module", "AHSeller: Item::CreateItem() returned NULL"); 526 | break; 527 | } 528 | item->AddToUpdateQueueOf(AHBplayer); 529 | 530 | uint32 randomPropertyId = Item::GenerateItemRandomPropertyId(itemID); 531 | if (randomPropertyId != 0) 532 | item->SetItemRandomProperties(randomPropertyId); 533 | 534 | // Determine price 535 | uint64 buyoutPrice = 0; 536 | uint64 bidPrice = 0; 537 | calculateItemValue(prototype, bidPrice, buyoutPrice); 538 | 539 | // Define a duration 540 | uint32 etime = urand(900, 43200); 541 | 542 | // Set stack size 543 | uint32 stackCount = getStackSizeForItem(prototype); 544 | item->SetCount(stackCount); 545 | 546 | uint32 dep = sAuctionMgr->GetAuctionDeposit(ahEntry, etime, item, stackCount); 547 | 548 | auto trans = CharacterDatabase.BeginTransaction(); 549 | AuctionEntry* auctionEntry = new AuctionEntry(); 550 | auctionEntry->Id = sObjectMgr->GenerateAuctionID(); 551 | auctionEntry->houseId = AuctionHouseId(config->GetAHID()); 552 | auctionEntry->item_guid = item->GetGUID(); 553 | auctionEntry->item_template = item->GetEntry(); 554 | auctionEntry->itemCount = item->GetCount(); 555 | auctionEntry->owner = AHBplayer->GetGUID(); 556 | auctionEntry->startbid = bidPrice * stackCount; 557 | auctionEntry->buyout = buyoutPrice * stackCount; 558 | auctionEntry->bid = 0; 559 | auctionEntry->deposit = dep; 560 | auctionEntry->expire_time = (time_t) etime + time(NULL); 561 | auctionEntry->auctionHouseEntry = ahEntry; 562 | item->SaveToDB(trans); 563 | item->RemoveFromUpdateQueueOf(AHBplayer); 564 | sAuctionMgr->AddAItem(item); 565 | auctionHouse->AddAuction(auctionEntry); 566 | auctionEntry->SaveToDB(trans); 567 | CharacterDatabase.CommitTransaction(trans); 568 | } 569 | } 570 | 571 | void AuctionHouseBot::addNewAuctionBuyerBotBid(Player* AHBplayer, AHBConfig *config) 572 | { 573 | if (!AHBBuyer) 574 | { 575 | if (debug_Out) 576 | LOG_ERROR("module", "AHBuyer: Disabled"); 577 | return; 578 | } 579 | 580 | QueryResult result = CharacterDatabase.Query("SELECT id FROM auctionhouse WHERE itemowner NOT IN ({}) AND buyguid NOT IN ({})", AHCharactersGUIDsForQuery, AHCharactersGUIDsForQuery); 581 | 582 | if (!result) 583 | return; 584 | 585 | if (result->GetRowCount() == 0) 586 | return; 587 | 588 | // Fetches content of selected AH 589 | AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(config->GetAHFID()); 590 | vector possibleBids; 591 | 592 | do 593 | { 594 | uint32 tmpdata = result->Fetch()->Get(); 595 | possibleBids.push_back(tmpdata); 596 | }while (result->NextRow()); 597 | 598 | for (uint32 count = 1; count <= config->GetBidsPerInterval(); ++count) 599 | { 600 | // Do we have anything to bid? If not, stop here. 601 | if (possibleBids.empty()) 602 | { 603 | //if (debug_Out) sLog->outError( "AHBuyer: I have no items to bid on."); 604 | count = config->GetBidsPerInterval(); 605 | continue; 606 | } 607 | 608 | // Choose random auction from possible auctions 609 | uint32 vectorPos = urand(0, possibleBids.size() - 1); 610 | vector::iterator iter = possibleBids.begin(); 611 | advance(iter, vectorPos); 612 | 613 | // from auctionhousehandler.cpp, creates auction pointer & player pointer 614 | AuctionEntry* auction = auctionHouse->GetAuction(*iter); 615 | 616 | // Erase the auction from the vector to prevent bidding on item in next iteration. 617 | possibleBids.erase(iter); 618 | 619 | if (!auction) 620 | continue; 621 | 622 | // get exact item information 623 | Item *pItem = sAuctionMgr->GetAItem(auction->item_guid); 624 | if (!pItem || pItem->GetCount() == 0) 625 | { 626 | if (debug_Out) 627 | LOG_ERROR("module", "AHBuyer: Item {} doesn't exist, perhaps bought already?", auction->item_guid.ToString()); 628 | continue; 629 | } 630 | 631 | // get item prototype 632 | ItemTemplate const* prototype = sObjectMgr->GetItemTemplate(auction->item_template); 633 | 634 | // Calculate a potential price for the item 635 | uint64 willingToSpendPerItemPrice = 0; 636 | uint64 discardBidPrice = 0; 637 | calculateItemValue(prototype, discardBidPrice, willingToSpendPerItemPrice); 638 | uint64 willingToSpendForStackPrice = willingToSpendPerItemPrice * pItem->GetCount(); 639 | 640 | // Buy it if the price is greater than buy out, bid if the price is greater than current bid, otherwise skip 641 | bool doBuyout = false; 642 | bool doBid = false; 643 | uint32 minBidPrice = 0; 644 | if (auction->buyout != 0 && willingToSpendForStackPrice >= auction->buyout) 645 | doBuyout = true; 646 | else 647 | { 648 | if (auction->bid >= auction->startbid) 649 | minBidPrice = auction->GetAuctionOutBid(); 650 | else 651 | minBidPrice = auction->startbid; 652 | 653 | if (minBidPrice <= willingToSpendForStackPrice) 654 | { 655 | if (auction->buyout != 0 && minBidPrice >= auction->buyout) 656 | doBuyout = true; 657 | else 658 | doBid = true; 659 | } 660 | } 661 | 662 | if (doBuyout == true || doBid == true) 663 | { 664 | if (debug_Out) 665 | { 666 | LOG_INFO("module", "-------------------------------------------------"); 667 | LOG_INFO("module", "AHBuyer: Info for Auction #{}:", auction->Id); 668 | LOG_INFO("module", "AHBuyer: AuctionHouse: {}", auction->GetHouseId()); 669 | LOG_INFO("module", "AHBuyer: Owner: {}", auction->owner.ToString()); 670 | LOG_INFO("module", "AHBuyer: Bidder: {}", auction->bidder.ToString()); 671 | LOG_INFO("module", "AHBuyer: Starting Bid: {}", auction->startbid); 672 | LOG_INFO("module", "AHBuyer: Current Bid: {}", auction->bid); 673 | LOG_INFO("module", "AHBuyer: Buyout: {}", auction->buyout); 674 | LOG_INFO("module", "AHBuyer: Deposit: {}", auction->deposit); 675 | LOG_INFO("module", "AHBuyer: Expire Time: {}", uint32(auction->expire_time)); 676 | LOG_INFO("module", "AHBuyer: Willing To Spend For Stack Price: {}", willingToSpendForStackPrice); 677 | LOG_INFO("module", "AHBuyer: Minimum Bid Price: {}", minBidPrice); 678 | LOG_INFO("module", "AHBuyer: Item GUID: {}", auction->item_guid.ToString()); 679 | LOG_INFO("module", "AHBuyer: Item Template: {}", auction->item_template); 680 | LOG_INFO("module", "AHBuyer: Item Info:"); 681 | LOG_INFO("module", "AHBuyer: Item ID: {}", prototype->ItemId); 682 | LOG_INFO("module", "AHBuyer: Buy Price: {}", prototype->BuyPrice); 683 | LOG_INFO("module", "AHBuyer: Sell Price: {}", prototype->SellPrice); 684 | LOG_INFO("module", "AHBuyer: Bonding: {}", prototype->Bonding); 685 | LOG_INFO("module", "AHBuyer: Quality: {}", prototype->Quality); 686 | LOG_INFO("module", "AHBuyer: Item Level: {}", prototype->ItemLevel); 687 | LOG_INFO("module", "AHBuyer: Ammo Type: {}", prototype->AmmoType); 688 | LOG_INFO("module", "-------------------------------------------------"); 689 | } 690 | 691 | if (doBid) 692 | { 693 | // Return money of prior bidder 694 | if (auction->bidder) 695 | { 696 | if (auction->bidder == AHBplayer->GetGUID()) 697 | { 698 | //pl->ModifyMoney(-int32(price - auction->bid)); 699 | } 700 | else 701 | { 702 | // mail to last bidder and return money 703 | auto trans = CharacterDatabase.BeginTransaction(); 704 | sAuctionMgr->SendAuctionOutbiddedMail(auction, minBidPrice, AHBplayer, trans); 705 | CharacterDatabase.CommitTransaction(trans); 706 | //pl->ModifyMoney(-int32(price)); 707 | } 708 | } 709 | 710 | auction->bidder = AHBplayer->GetGUID(); 711 | auction->bid = minBidPrice; 712 | 713 | // Saving auction into database 714 | CharacterDatabase.Execute("UPDATE auctionhouse SET buyguid = '{}',lastbid = '{}' WHERE id = '{}'", auction->bidder.GetCounter(), auction->bid, auction->Id); 715 | } 716 | else if (doBuyout) 717 | { 718 | auto trans = CharacterDatabase.BeginTransaction(); 719 | //buyout 720 | if ((auction->bidder) && (AHBplayer->GetGUID() != auction->bidder)) 721 | { 722 | sAuctionMgr->SendAuctionOutbiddedMail(auction, auction->buyout, AHBplayer, trans); 723 | } 724 | auction->bidder = AHBplayer->GetGUID(); 725 | auction->bid = auction->buyout; 726 | 727 | // Send mails to buyer & seller 728 | sAuctionMgr->SendAuctionSuccessfulMail(auction, trans); 729 | sAuctionMgr->SendAuctionWonMail(auction, trans); 730 | auction->DeleteFromDB(trans); 731 | 732 | sAuctionMgr->RemoveAItem(auction->item_guid); 733 | auctionHouse->RemoveAuction(auction); 734 | CharacterDatabase.CommitTransaction(trans); 735 | } 736 | } 737 | } 738 | } 739 | 740 | void AuctionHouseBot::Update() 741 | { 742 | if ((AHBSeller == false) && (AHBBuyer == false)) 743 | return; 744 | if (AHCharacters.size() == 0) 745 | return; 746 | time_t _newrun = time(NULL); 747 | 748 | // Randomly select the bot to load, and load it 749 | uint32 botIndex = urand(0, AHCharacters.size() - 1); 750 | CurrentBotCharGUID = AHCharacters[botIndex].CharacterGUID; 751 | std::string accountName = "AuctionHouseBot" + std::to_string(AHCharacters[botIndex].AccountID); 752 | WorldSession _session(AHCharacters[botIndex].AccountID, std::move(accountName), nullptr, SEC_PLAYER, sWorld->getIntConfig(CONFIG_EXPANSION), 0, LOCALE_enUS, 0, false, false, 0); 753 | Player _AHBplayer(&_session); 754 | _AHBplayer.Initialize(AHCharacters[botIndex].CharacterGUID); 755 | ObjectAccessor::AddObject(&_AHBplayer); 756 | 757 | // Add New Bids 758 | if (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION)) 759 | { 760 | addNewAuctions(&_AHBplayer, &AllianceConfig); 761 | if (((_newrun - _lastrun_a) >= (AllianceConfig.GetBiddingInterval() * MINUTE)) && (AllianceConfig.GetBidsPerInterval() > 0)) 762 | { 763 | addNewAuctionBuyerBotBid(&_AHBplayer, &AllianceConfig); 764 | _lastrun_a = _newrun; 765 | } 766 | 767 | addNewAuctions(&_AHBplayer, &HordeConfig); 768 | if (((_newrun - _lastrun_h) >= (HordeConfig.GetBiddingInterval() * MINUTE)) && (HordeConfig.GetBidsPerInterval() > 0)) 769 | { 770 | addNewAuctionBuyerBotBid(&_AHBplayer, &HordeConfig); 771 | _lastrun_h = _newrun; 772 | } 773 | } 774 | 775 | addNewAuctions(&_AHBplayer, &NeutralConfig); 776 | if (((_newrun - _lastrun_n) >= (NeutralConfig.GetBiddingInterval() * MINUTE)) && (NeutralConfig.GetBidsPerInterval() > 0)) 777 | { 778 | addNewAuctionBuyerBotBid(&_AHBplayer, &NeutralConfig); 779 | _lastrun_n = _newrun; 780 | } 781 | 782 | ObjectAccessor::RemoveObject(&_AHBplayer); 783 | } 784 | 785 | void AuctionHouseBot::Initialize() 786 | { 787 | // Build a list of items that can be pulled from for auction 788 | populateItemClassProportionList(); 789 | populateItemCandidateList(); 790 | } 791 | 792 | void AuctionHouseBot::InitializeConfiguration() 793 | { 794 | debug_Out = sConfigMgr->GetOption("AuctionHouseBot.DEBUG", false); 795 | debug_Out_Filters = sConfigMgr->GetOption("AuctionHouseBot.DEBUG_FILTERS", false); 796 | 797 | AHBSeller = sConfigMgr->GetOption("AuctionHouseBot.EnableSeller", false); 798 | AHBBuyer = sConfigMgr->GetOption("AuctionHouseBot.EnableBuyer", false); 799 | if (AHBSeller == false && AHBBuyer == false) 800 | return; 801 | string charString = sConfigMgr->GetOption("AuctionHouseBot.GUIDs", "0"); 802 | if (charString == "0") 803 | { 804 | AHBBuyer = false; 805 | AHBSeller = false; 806 | LOG_INFO("module", "AuctionHouseBot: AuctionHouseBot.GUIDs is '0' so this module will be disabled"); 807 | return; 808 | } 809 | AddCharacters(charString); 810 | 811 | ItemsPerCycle = sConfigMgr->GetOption("AuctionHouseBot.ItemsPerCycle", 75); 812 | 813 | // Item level Restrictions 814 | ListedItemLevelRestrictedEnabled = sConfigMgr->GetOption("AuctionHouseBot.ListedItemLevelRestrict.Enabled", false); 815 | ListedItemLevelMax = sConfigMgr->GetOption("AuctionHouseBot.ListedItemLevelRestrict.MaxItemLevel", 999); 816 | ListedItemLevelMin = sConfigMgr->GetOption("AuctionHouseBot.ListedItemLevelRestrict.MinItemLevel", 0); 817 | AddItemLevelExceptionItems(sConfigMgr->GetOption("AuctionHouseBot.ListedItemLevelRestrict.ExceptionItemIDs", "")); 818 | 819 | // Stack Ratios 820 | RandomStackRatioConsumable = GetRandomStackValue("AuctionHouseBot.RandomStackRatio.Consumable", 20); 821 | RandomStackRatioContainer = GetRandomStackValue("AuctionHouseBot.RandomStackRatio.Container", 0); 822 | RandomStackRatioWeapon = GetRandomStackValue("AuctionHouseBot.RandomStackRatio.Weapon", 0); 823 | RandomStackRatioGem = GetRandomStackValue("AuctionHouseBot.RandomStackRatio.Gem", 5); 824 | RandomStackRatioArmor = GetRandomStackValue("AuctionHouseBot.RandomStackRatio.Armor", 0); 825 | RandomStackRatioReagent = GetRandomStackValue("AuctionHouseBot.RandomStackRatio.Reagent", 50); 826 | RandomStackRatioProjectile = GetRandomStackValue("AuctionHouseBot.RandomStackRatio.Projectile", 100); 827 | RandomStackRatioTradeGood = GetRandomStackValue("AuctionHouseBot.RandomStackRatio.TradeGood", 50); 828 | RandomStackRatioGeneric = GetRandomStackValue("AuctionHouseBot.RandomStackRatio.Generic", 100); 829 | RandomStackRatioRecipe = GetRandomStackValue("AuctionHouseBot.RandomStackRatio.Recipe", 0); 830 | RandomStackRatioQuiver = GetRandomStackValue("AuctionHouseBot.RandomStackRatio.Quiver", 0); 831 | RandomStackRatioQuest = GetRandomStackValue("AuctionHouseBot.RandomStackRatio.Quest", 10); 832 | RandomStackRatioKey = GetRandomStackValue("AuctionHouseBot.RandomStackRatio.Key", 10); 833 | RandomStackRatioMisc = GetRandomStackValue("AuctionHouseBot.RandomStackRatio.Misc", 100); 834 | RandomStackRatioGlyph = GetRandomStackValue("AuctionHouseBot.RandomStackRatio.Glyph", 0); 835 | 836 | // List Proportions 837 | ListProportionConsumable = sConfigMgr->GetOption("AuctionHouseBot.ListProportion.Consumable", 2); 838 | ListProportionContainer = sConfigMgr->GetOption("AuctionHouseBot.ListProportion.Container", 2); 839 | ListProportionWeapon = sConfigMgr->GetOption("AuctionHouseBot.ListProportion.Weapon", 6); 840 | ListProportionGem = sConfigMgr->GetOption("AuctionHouseBot.ListProportion.Gem", 2); 841 | ListProportionArmor = sConfigMgr->GetOption("AuctionHouseBot.ListProportion.Armor", 6); 842 | ListProportionReagent = sConfigMgr->GetOption("AuctionHouseBot.ListProportion.Reagent", 1); 843 | ListProportionProjectile = sConfigMgr->GetOption("AuctionHouseBot.ListProportion.Projectile", 2); 844 | ListProportionTradeGood = sConfigMgr->GetOption("AuctionHouseBot.ListProportion.TradeGood", 22); 845 | ListProportionGeneric = sConfigMgr->GetOption("AuctionHouseBot.ListProportion.Generic", 1); 846 | ListProportionRecipe = sConfigMgr->GetOption("AuctionHouseBot.ListProportion.Recipe", 3); 847 | ListProportionQuiver = sConfigMgr->GetOption("AuctionHouseBot.ListProportion.Quiver", 1); 848 | ListProportionQuest = sConfigMgr->GetOption("AuctionHouseBot.ListProportion.Quest", 2); 849 | ListProportionKey = sConfigMgr->GetOption("AuctionHouseBot.ListProportion.Key", 1); 850 | ListProportionMisc = sConfigMgr->GetOption("AuctionHouseBot.ListProportion.Misc", 0); 851 | ListProportionGlyph = sConfigMgr->GetOption("AuctionHouseBot.ListProportion.Glyph", 2); 852 | 853 | // Price Multipliers 854 | PriceMultiplierCategoryConsumable = sConfigMgr->GetOption("AuctionHouseBot.PriceMultiplier.Category.Consumable", 1); 855 | PriceMultiplierCategoryContainer = sConfigMgr->GetOption("AuctionHouseBot.PriceMultiplier.Category.Container", 1); 856 | PriceMultiplierCategoryWeapon = sConfigMgr->GetOption("AuctionHouseBot.PriceMultiplier.Category.Weapon", 1); 857 | PriceMultiplierCategoryGem = sConfigMgr->GetOption("AuctionHouseBot.PriceMultiplier.Category.Gem", 1); 858 | PriceMultiplierCategoryArmor = sConfigMgr->GetOption("AuctionHouseBot.PriceMultiplier.Category.Armor", 1); 859 | PriceMultiplierCategoryReagent = sConfigMgr->GetOption("AuctionHouseBot.PriceMultiplier.Category.Reagent", 1); 860 | PriceMultiplierCategoryProjectile = sConfigMgr->GetOption("AuctionHouseBot.PriceMultiplier.Category.Projectile", 1); 861 | PriceMultiplierCategoryTradeGood = sConfigMgr->GetOption("AuctionHouseBot.PriceMultiplier.Category.TradeGood", 2); 862 | PriceMultiplierCategoryGeneric = sConfigMgr->GetOption("AuctionHouseBot.PriceMultiplier.Category.Generic", 1); 863 | PriceMultiplierCategoryRecipe = sConfigMgr->GetOption("AuctionHouseBot.PriceMultiplier.Category.Recipe", 1); 864 | PriceMultiplierCategoryQuiver = sConfigMgr->GetOption("AuctionHouseBot.PriceMultiplier.Category.Quiver", 1); 865 | PriceMultiplierCategoryQuest = sConfigMgr->GetOption("AuctionHouseBot.PriceMultiplier.Category.Quest", 1); 866 | PriceMultiplierCategoryKey = sConfigMgr->GetOption("AuctionHouseBot.PriceMultiplier.Category.Key", 1); 867 | PriceMultiplierCategoryMisc = sConfigMgr->GetOption("AuctionHouseBot.PriceMultiplier.Category.Misc", 1); 868 | PriceMultiplierCategoryGlyph = sConfigMgr->GetOption("AuctionHouseBot.PriceMultiplier.Category.Glyph", 1); 869 | PriceMultiplierQualityPoor = sConfigMgr->GetOption("AuctionHouseBot.PriceMultiplier.Quality.Poor", 1); 870 | PriceMultiplierQualityNormal = sConfigMgr->GetOption("AuctionHouseBot.PriceMultiplier.Quality.Normal", 1); 871 | PriceMultiplierQualityUncommon = sConfigMgr->GetOption("AuctionHouseBot.PriceMultiplier.Quality.Uncommon", 1.8); 872 | PriceMultiplierQualityRare = sConfigMgr->GetOption("AuctionHouseBot.PriceMultiplier.Quality.Rare", 1.9); 873 | PriceMultiplierQualityEpic = sConfigMgr->GetOption("AuctionHouseBot.PriceMultiplier.Quality.Epic", 2.1); 874 | PriceMultiplierQualityLegendary = sConfigMgr->GetOption("AuctionHouseBot.PriceMultiplier.Quality.Legendary", 3); 875 | PriceMultiplierQualityArtifact = sConfigMgr->GetOption("AuctionHouseBot.PriceMultiplier.Quality.Artifact", 3); 876 | PriceMultiplierQualityHeirloom = sConfigMgr->GetOption("AuctionHouseBot.PriceMultiplier.Quality.Heirloom", 3); 877 | 878 | // Price minimums 879 | PriceMinimumCenterBaseConsumable = sConfigMgr->GetOption("AuctionHouseBot.PriceMinimumCenterBase.Consumable",1000); 880 | PriceMinimumCenterBaseContainer = sConfigMgr->GetOption("AuctionHouseBot.PriceMinimumCenterBase.Container", 1000); 881 | PriceMinimumCenterBaseWeapon = sConfigMgr->GetOption("AuctionHouseBot.PriceMinimumCenterBase.Weapon", 1000); 882 | PriceMinimumCenterBaseGem = sConfigMgr->GetOption("AuctionHouseBot.PriceMinimumCenterBase.Gem", 1000); 883 | PriceMinimumCenterBaseArmor = sConfigMgr->GetOption("AuctionHouseBot.PriceMinimumCenterBase.Armor", 1000); 884 | PriceMinimumCenterBaseReagent = sConfigMgr->GetOption("AuctionHouseBot.PriceMinimumCenterBase.Reagent", 1000); 885 | PriceMinimumCenterBaseProjectile = sConfigMgr->GetOption("AuctionHouseBot.PriceMinimumCenterBase.Projectile", 5); 886 | PriceMinimumCenterBaseTradeGood = sConfigMgr->GetOption("AuctionHouseBot.PriceMinimumCenterBase.TradeGood", 1000); 887 | PriceMinimumCenterBaseGeneric = sConfigMgr->GetOption("AuctionHouseBot.PriceMinimumCenterBase.Generic", 1000); 888 | PriceMinimumCenterBaseRecipe = sConfigMgr->GetOption("AuctionHouseBot.PriceMinimumCenterBase.Recipe", 1000); 889 | PriceMinimumCenterBaseQuiver = sConfigMgr->GetOption("AuctionHouseBot.PriceMinimumCenterBase.Quiver", 1000); 890 | PriceMinimumCenterBaseQuest = sConfigMgr->GetOption("AuctionHouseBot.PriceMinimumCenterBase.Quest", 1000); 891 | PriceMinimumCenterBaseKey = sConfigMgr->GetOption("AuctionHouseBot.PriceMinimumCenterBase.Key", 1000); 892 | PriceMinimumCenterBaseMisc = sConfigMgr->GetOption("AuctionHouseBot.PriceMinimumCenterBase.Misc", 1000); 893 | PriceMinimumCenterBaseGlyph = sConfigMgr->GetOption("AuctionHouseBot.PriceMinimumCenterBase.Glyph", 1000); 894 | AddPriceMinimumOverrides(sConfigMgr->GetOption("AuctionHouseBot.PriceMinimumCenterBase.OverrideItems", "")); 895 | 896 | // Disabled Items 897 | DisabledItemTextFilter = sConfigMgr->GetOption("AuctionHouseBot.DisabledItemTextFilter", true); 898 | DisabledItems.clear(); 899 | AddDisabledItems(sConfigMgr->GetOption("AuctionHouseBot.DisabledItemIDs", "")); 900 | AddDisabledItems(sConfigMgr->GetOption("AuctionHouseBot.DisabledCraftedItemIDs", "")); 901 | 902 | if (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION)) 903 | { 904 | AllianceConfig.SetMinItems(sConfigMgr->GetOption("AuctionHouseBot.Alliance.MinItems", 15000)); 905 | AllianceConfig.SetMaxItems(sConfigMgr->GetOption("AuctionHouseBot.Alliance.MaxItems", 15000)); 906 | AllianceConfig.SetBiddingInterval(sConfigMgr->GetOption("AuctionHouseBot.Alliance.BidInterval", 1)); 907 | AllianceConfig.SetBidsPerInterval(sConfigMgr->GetOption("AuctionHouseBot.Alliance.BidsPerInterval", 1)); 908 | 909 | HordeConfig.SetMinItems(sConfigMgr->GetOption("AuctionHouseBot.Horde.MinItems", 15000)); 910 | HordeConfig.SetMaxItems(sConfigMgr->GetOption("AuctionHouseBot.Horde.MaxItems", 15000)); 911 | HordeConfig.SetBiddingInterval(sConfigMgr->GetOption("AuctionHouseBot.Horde.BidInterval", 1)); 912 | HordeConfig.SetBidsPerInterval(sConfigMgr->GetOption("AuctionHouseBot.Horde.BidsPerInterval", 1)); 913 | } 914 | NeutralConfig.SetMinItems(sConfigMgr->GetOption("AuctionHouseBot.Neutral.MinItems", 15000)); 915 | NeutralConfig.SetMaxItems(sConfigMgr->GetOption("AuctionHouseBot.Neutral.MaxItems", 15000)); 916 | NeutralConfig.SetBiddingInterval(sConfigMgr->GetOption("AuctionHouseBot.Neutral.BidInterval", 1)); 917 | NeutralConfig.SetBidsPerInterval(sConfigMgr->GetOption("AuctionHouseBot.Neutral.BidsPerInterval", 1)); 918 | } 919 | 920 | uint32 AuctionHouseBot::GetRandomStackValue(std::string configKeyString, uint32 defaultValue) 921 | { 922 | uint32 stackValue = sConfigMgr->GetOption(configKeyString, defaultValue); 923 | if (stackValue > 100 || stackValue < 0) 924 | { 925 | LOG_ERROR("module", "{} value is invalid. Setting to default ({}).", configKeyString, defaultValue); 926 | stackValue = defaultValue; 927 | } 928 | return stackValue; 929 | } 930 | 931 | void AuctionHouseBot::AddToListedItemLevelExceptionItems(std::set& workingExceptionItemIDs, uint32 itemLevelExceptionItemID) 932 | { 933 | if (workingExceptionItemIDs.find(itemLevelExceptionItemID) != workingExceptionItemIDs.end()) 934 | { 935 | if (debug_Out) 936 | LOG_ERROR("module", "AuctionHouseBot: Duplicate item level exxception item ID of {} found, skipping", itemLevelExceptionItemID); 937 | } 938 | else 939 | { 940 | workingExceptionItemIDs.insert(itemLevelExceptionItemID); 941 | } 942 | } 943 | 944 | 945 | void AuctionHouseBot::AddToDisabledItems(std::set& workingDisabledItemIDs, uint32 disabledItemID) 946 | { 947 | if (workingDisabledItemIDs.find(disabledItemID) != workingDisabledItemIDs.end()) 948 | { 949 | if (debug_Out) 950 | LOG_ERROR("module", "AuctionHouseBot: Duplicate disabled item ID of {} found, skipping", disabledItemID); 951 | } 952 | else 953 | { 954 | workingDisabledItemIDs.insert(disabledItemID); 955 | } 956 | } 957 | 958 | void AuctionHouseBot::AddCharacters(std::string characterGUIDString) 959 | { 960 | std::string delimitedValue; 961 | std::stringstream characterGUIDStream; 962 | std::set characterGUIDs; 963 | 964 | // Grab from the string 965 | characterGUIDStream.str(characterGUIDString); 966 | while (std::getline(characterGUIDStream, delimitedValue, ',')) // Process each charecter GUID in the string, delimited by the comma "," 967 | { 968 | std::string valueOne; 969 | std::stringstream characterGUIDStream(delimitedValue); 970 | characterGUIDStream >> valueOne; 971 | auto characterGUID = atoi(valueOne.c_str()); 972 | if (characterGUID == 0) 973 | continue; 974 | if (characterGUIDs.find(characterGUID) != characterGUIDs.end()) 975 | { 976 | if (debug_Out) 977 | LOG_ERROR("module", "AuctionHouseBot: Duplicate character with GUID of {} found, skipping", characterGUID); 978 | } 979 | else 980 | characterGUIDs.insert(characterGUID); 981 | } 982 | 983 | // Lookup accounts and add them 984 | if (characterGUIDs.empty() == true) 985 | { 986 | LOG_ERROR("module", "AuctionHouseBot: No character GUIDs were supplied. Be sure to set AuctionHouseBot.GUIDs"); 987 | return; 988 | } 989 | AHCharactersGUIDsForQuery = ""; 990 | bool first = true; 991 | for (uint32 curGUID : characterGUIDs) 992 | { 993 | if (first == false) 994 | { 995 | AHCharactersGUIDsForQuery += ", "; 996 | } 997 | AHCharactersGUIDsForQuery += std::to_string(curGUID); 998 | first = false; 999 | } 1000 | QueryResult queryResult = CharacterDatabase.Query("SELECT `guid`, `account` FROM `characters` WHERE guid IN ({})", AHCharactersGUIDsForQuery); 1001 | if (!queryResult || queryResult->GetRowCount() == 0) 1002 | { 1003 | LOG_ERROR("module", "AuctionHouseBot: No character GUIDs found when looking up values from AuctionHouseBot.GUIDs from the character database 'characters.guid'."); 1004 | return; 1005 | } 1006 | do 1007 | { 1008 | // Pull the data out 1009 | Field* fields = queryResult->Fetch(); 1010 | uint32 guid = fields[0].Get(); 1011 | uint32 account = fields[1].Get(); 1012 | AuctionHouseBotCharacter curChar = AuctionHouseBotCharacter(account, guid); 1013 | AHCharacters.push_back(curChar); 1014 | } while (queryResult->NextRow()); 1015 | } 1016 | 1017 | void AuctionHouseBot::AddDisabledItems(std::string disabledItemIdString) 1018 | { 1019 | std::string delimitedValue; 1020 | std::stringstream disabledItemIdStream; 1021 | 1022 | disabledItemIdStream.str(disabledItemIdString); 1023 | while (std::getline(disabledItemIdStream, delimitedValue, ',')) // Process each item ID in the string, delimited by the comma "," 1024 | { 1025 | std::string valueOne; 1026 | std::stringstream itemPairStream(delimitedValue); 1027 | itemPairStream >> valueOne; 1028 | // If it has a hypen, then it's a range of numbers 1029 | if (valueOne.find("-") != std::string::npos) 1030 | { 1031 | std::string leftIDString = valueOne.substr(0, valueOne.find("-")); 1032 | std::string rightIDString = valueOne.substr(valueOne.find("-")+1); 1033 | 1034 | auto leftId = atoi(leftIDString.c_str()); 1035 | auto rightId = atoi(rightIDString.c_str()); 1036 | 1037 | if (leftId > rightId) 1038 | { 1039 | LOG_ERROR("module", "AuctionHouseBot: Duplicate disabled item ID range of {} to {} needs to be smallest to largest, skipping", leftId, rightId); 1040 | } 1041 | else 1042 | { 1043 | for (int32 i = leftId; i <= rightId; ++i) 1044 | AddToDisabledItems(DisabledItems, i); 1045 | } 1046 | 1047 | } 1048 | else 1049 | { 1050 | auto itemId = atoi(valueOne.c_str()); 1051 | AddToDisabledItems(DisabledItems, itemId); 1052 | } 1053 | } 1054 | } 1055 | 1056 | void AuctionHouseBot::AddItemLevelExceptionItems(std::string itemLevelExceptionIdString) 1057 | { 1058 | std::string delimitedValue; 1059 | std::stringstream itemLevelExceptionItemIdStream; 1060 | 1061 | itemLevelExceptionItemIdStream.str(itemLevelExceptionIdString); 1062 | while (std::getline(itemLevelExceptionItemIdStream, delimitedValue, ',')) // Process each item ID in the string, delimited by the comma "," 1063 | { 1064 | std::string valueOne; 1065 | std::stringstream itemPairStream(delimitedValue); 1066 | itemPairStream >> valueOne; 1067 | // If it has a hypen, then it's a range of numbers 1068 | if (valueOne.find("-") != std::string::npos) 1069 | { 1070 | std::string leftIDString = valueOne.substr(0, valueOne.find("-")); 1071 | std::string rightIDString = valueOne.substr(valueOne.find("-") + 1); 1072 | 1073 | auto leftId = atoi(leftIDString.c_str()); 1074 | auto rightId = atoi(rightIDString.c_str()); 1075 | 1076 | if (leftId > rightId) 1077 | { 1078 | LOG_ERROR("module", "AuctionHouseBot: Duplicate item level exception item ID range of {} to {} needs to be smallest to largest, skipping", leftId, rightId); 1079 | } 1080 | else 1081 | { 1082 | for (int32 i = leftId; i <= rightId; ++i) 1083 | AddToListedItemLevelExceptionItems(ListedItemLevelExceptionItems, i); 1084 | } 1085 | 1086 | } 1087 | else 1088 | { 1089 | auto itemId = atoi(valueOne.c_str()); 1090 | AddToListedItemLevelExceptionItems(ListedItemLevelExceptionItems, itemId); 1091 | } 1092 | } 1093 | } 1094 | 1095 | void AuctionHouseBot::AddPriceMinimumOverrides(std::string priceMinimimOverridesString) 1096 | { 1097 | std::string delimitedValue; 1098 | std::stringstream priceMinimumStream; 1099 | priceMinimumStream.str(priceMinimimOverridesString); 1100 | while (std::getline(priceMinimumStream, delimitedValue, ',')) // Process each item ID in the string, delimited by the comma "," 1101 | { 1102 | std::string curBlock; 1103 | std::stringstream itemPairStream(delimitedValue); 1104 | itemPairStream >> curBlock; 1105 | 1106 | // Only process if it has a colon (:) 1107 | if (curBlock.find(":") != std::string::npos) 1108 | { 1109 | std::string itemIDString = curBlock.substr(0, curBlock.find(":")); 1110 | auto itemId = atoi(itemIDString.c_str()); 1111 | std::string priceInCopper = curBlock.substr(curBlock.find(":") + 1); 1112 | auto copperPrice = atoi(priceInCopper.c_str()); 1113 | if (itemId > 0 && copperPrice > 0) 1114 | PriceMinimumCenterBaseOverridesByItemID.insert({itemId, copperPrice}); 1115 | } 1116 | } 1117 | } 1118 | -------------------------------------------------------------------------------- /src/AuctionHouseBot.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2008-2010 Trinity 3 | * Copyright (C) 2005-2009 MaNGOS 4 | * Copyright (C) 2023+ Nathan Handley 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 | */ 20 | 21 | #ifndef AUCTION_HOUSE_BOT_H 22 | #define AUCTION_HOUSE_BOT_H 23 | 24 | #include "Common.h" 25 | #include "ObjectGuid.h" 26 | 27 | #include 28 | #include 29 | 30 | struct AuctionEntry; 31 | class Player; 32 | class WorldSession; 33 | 34 | #include "ItemTemplate.h" 35 | 36 | class AHBConfig 37 | { 38 | private: 39 | uint32 AHID; 40 | uint32 AHFID; 41 | uint32 minItems; 42 | uint32 maxItems; 43 | 44 | uint32 buyerBiddingInterval; 45 | uint32 buyerBidsPerInterval; 46 | 47 | public: 48 | AHBConfig(uint32 ahid) 49 | { 50 | AHID = ahid; 51 | switch(ahid) 52 | { 53 | case 2: 54 | AHFID = 55; 55 | break; 56 | case 6: 57 | AHFID = 29; 58 | break; 59 | case 7: 60 | AHFID = 120; 61 | break; 62 | default: 63 | AHFID = 120; 64 | break; 65 | } 66 | } 67 | AHBConfig() 68 | { 69 | } 70 | uint32 GetAHID() 71 | { 72 | return AHID; 73 | } 74 | uint32 GetAHFID() 75 | { 76 | return AHFID; 77 | } 78 | void SetMinItems(uint32 value) 79 | { 80 | minItems = value; 81 | } 82 | uint32 GetMinItems() 83 | { 84 | if ((minItems == 0) && (maxItems)) 85 | return maxItems; 86 | else if ((maxItems) && (minItems > maxItems)) 87 | return maxItems; 88 | else 89 | return minItems; 90 | } 91 | void SetMaxItems(uint32 value) 92 | { 93 | maxItems = value; 94 | // CalculatePercents() needs to be called, but only if 95 | // SetPercentages() has been called at least once already. 96 | } 97 | uint32 GetMaxItems() 98 | { 99 | return maxItems; 100 | } 101 | 102 | void SetBiddingInterval(uint32 value) 103 | { 104 | buyerBiddingInterval = value; 105 | } 106 | uint32 GetBiddingInterval() 107 | { 108 | return buyerBiddingInterval; 109 | } 110 | 111 | void SetBidsPerInterval(uint32 value) 112 | { 113 | buyerBidsPerInterval = value; 114 | } 115 | uint32 GetBidsPerInterval() 116 | { 117 | return buyerBidsPerInterval; 118 | } 119 | ~AHBConfig() 120 | { 121 | } 122 | }; 123 | 124 | class AuctionHouseBotCharacter 125 | { 126 | public: 127 | AuctionHouseBotCharacter(uint32 accountID, uint32 characterGUID) : 128 | AccountID(accountID), 129 | CharacterGUID(characterGUID) { } 130 | uint32 AccountID; 131 | ObjectGuid::LowType CharacterGUID; 132 | }; 133 | 134 | class AuctionHouseBot 135 | { 136 | public: 137 | std::vector AHCharacters; 138 | uint32 CurrentBotCharGUID; 139 | 140 | private: 141 | bool debug_Out; 142 | bool debug_Out_Filters; 143 | 144 | bool AHBSeller; 145 | bool AHBBuyer; 146 | 147 | std::string AHCharactersGUIDsForQuery; 148 | uint32 ItemsPerCycle; 149 | bool DisabledItemTextFilter; 150 | std::set DisabledItems; 151 | bool ListedItemLevelRestrictedEnabled; 152 | int32 ListedItemLevelMax; 153 | int32 ListedItemLevelMin; 154 | std::set ListedItemLevelExceptionItems; 155 | uint32 RandomStackRatioConsumable; 156 | uint32 RandomStackRatioContainer; 157 | uint32 RandomStackRatioWeapon; 158 | uint32 RandomStackRatioGem; 159 | uint32 RandomStackRatioArmor; 160 | uint32 RandomStackRatioReagent; 161 | uint32 RandomStackRatioProjectile; 162 | uint32 RandomStackRatioTradeGood; 163 | uint32 RandomStackRatioGeneric; 164 | uint32 RandomStackRatioRecipe; 165 | uint32 RandomStackRatioQuiver; 166 | uint32 RandomStackRatioQuest; 167 | uint32 RandomStackRatioKey; 168 | uint32 RandomStackRatioMisc; 169 | uint32 RandomStackRatioGlyph; 170 | std::vector itemCandidateClassWeightedProportionList; 171 | std::map> itemCandidatesByItemClass; 172 | uint32 ListProportionConsumable; 173 | uint32 ListProportionContainer; 174 | uint32 ListProportionWeapon; 175 | uint32 ListProportionGem; 176 | uint32 ListProportionArmor; 177 | uint32 ListProportionReagent; 178 | uint32 ListProportionProjectile; 179 | uint32 ListProportionTradeGood; 180 | uint32 ListProportionGeneric; 181 | uint32 ListProportionRecipe; 182 | uint32 ListProportionQuiver; 183 | uint32 ListProportionQuest; 184 | uint32 ListProportionKey; 185 | uint32 ListProportionMisc; 186 | uint32 ListProportionGlyph; 187 | float PriceMultiplierCategoryConsumable; 188 | float PriceMultiplierCategoryContainer; 189 | float PriceMultiplierCategoryWeapon; 190 | float PriceMultiplierCategoryGem; 191 | float PriceMultiplierCategoryArmor; 192 | float PriceMultiplierCategoryReagent; 193 | float PriceMultiplierCategoryProjectile; 194 | float PriceMultiplierCategoryTradeGood; 195 | float PriceMultiplierCategoryGeneric; 196 | float PriceMultiplierCategoryRecipe; 197 | float PriceMultiplierCategoryQuiver; 198 | float PriceMultiplierCategoryQuest; 199 | float PriceMultiplierCategoryKey; 200 | float PriceMultiplierCategoryMisc; 201 | float PriceMultiplierCategoryGlyph; 202 | float PriceMultiplierQualityPoor; 203 | float PriceMultiplierQualityNormal; 204 | float PriceMultiplierQualityUncommon; 205 | float PriceMultiplierQualityRare; 206 | float PriceMultiplierQualityEpic; 207 | float PriceMultiplierQualityLegendary; 208 | float PriceMultiplierQualityArtifact; 209 | float PriceMultiplierQualityHeirloom; 210 | uint32 PriceMinimumCenterBaseConsumable; 211 | uint32 PriceMinimumCenterBaseContainer; 212 | uint32 PriceMinimumCenterBaseWeapon; 213 | uint32 PriceMinimumCenterBaseGem; 214 | uint32 PriceMinimumCenterBaseArmor; 215 | uint32 PriceMinimumCenterBaseReagent; 216 | uint32 PriceMinimumCenterBaseProjectile; 217 | uint32 PriceMinimumCenterBaseTradeGood; 218 | uint32 PriceMinimumCenterBaseGeneric; 219 | uint32 PriceMinimumCenterBaseRecipe; 220 | uint32 PriceMinimumCenterBaseQuiver; 221 | uint32 PriceMinimumCenterBaseQuest; 222 | uint32 PriceMinimumCenterBaseKey; 223 | uint32 PriceMinimumCenterBaseMisc; 224 | uint32 PriceMinimumCenterBaseGlyph; 225 | std::unordered_map PriceMinimumCenterBaseOverridesByItemID; 226 | 227 | AHBConfig AllianceConfig; 228 | AHBConfig HordeConfig; 229 | AHBConfig NeutralConfig; 230 | 231 | time_t _lastrun_a; 232 | time_t _lastrun_h; 233 | time_t _lastrun_n; 234 | 235 | inline uint32 minValue(uint32 a, uint32 b) { return a <= b ? a : b; }; 236 | uint32 getStackSizeForItem(ItemTemplate const* itemProto) const; 237 | void calculateItemValue(ItemTemplate const* itemProto, uint64& outBidPrice, uint64& outBuyoutPrice); 238 | void populatetemClassSeedListForItemClass(uint32 itemClass, uint32 itemClassSeedWeight); 239 | void populateItemClassProportionList(); 240 | void populateItemCandidateList(); 241 | void addNewAuctions(Player* AHBplayer, AHBConfig *config); 242 | void addNewAuctionBuyerBotBid(Player* AHBplayer, AHBConfig *config); 243 | 244 | AuctionHouseBot(); 245 | 246 | public: 247 | static AuctionHouseBot* instance() 248 | { 249 | static AuctionHouseBot instance; 250 | return &instance; 251 | } 252 | 253 | ~AuctionHouseBot(); 254 | void Update(); 255 | void Initialize(); 256 | void InitializeConfiguration(); 257 | uint32 GetRandomStackValue(std::string configKeyString, uint32 defaultValue); 258 | 259 | void AddCharacters(std::string characterGUIDString); 260 | void AddToDisabledItems(std::set& workingDisabledItemIDs, uint32 disabledItemID); 261 | void AddDisabledItems(std::string disabledItemIdString); 262 | void AddToListedItemLevelExceptionItems(std::set& workingExceptionItemIDs, uint32 itemLevelExceptionItemID); 263 | void AddItemLevelExceptionItems(std::string itemLevelExceptionIdString); 264 | void AddPriceMinimumOverrides(std::string priceMinimimOverridesString); 265 | }; 266 | 267 | #define auctionbot AuctionHouseBot::instance() 268 | 269 | #endif 270 | -------------------------------------------------------------------------------- /src/AuctionHouseBotScript.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016+ AzerothCore , released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3 3 | */ 4 | 5 | #include "ScriptMgr.h" 6 | #include "AuctionHouseBot.h" 7 | #include "Log.h" 8 | #include "Mail.h" 9 | #include "Player.h" 10 | #include "WorldSession.h" 11 | 12 | class AHBot_WorldScript : public WorldScript 13 | { 14 | public: 15 | AHBot_WorldScript() : WorldScript("AHBot_WorldScript") { } 16 | 17 | void OnAfterConfigLoad(bool /*reload*/) override 18 | { 19 | auctionbot->InitializeConfiguration(); 20 | } 21 | 22 | void OnStartup() override 23 | { 24 | LOG_INFO("server.loading", "Initialize AuctionHouseBot..."); 25 | auctionbot->Initialize(); 26 | } 27 | }; 28 | 29 | class AHBot_AuctionHouseScript : public AuctionHouseScript 30 | { 31 | public: 32 | AHBot_AuctionHouseScript() : AuctionHouseScript("AHBot_AuctionHouseScript") { } 33 | 34 | void OnBeforeAuctionHouseMgrSendAuctionSuccessfulMail(AuctionHouseMgr* /*auctionHouseMgr*/, AuctionEntry* /*auction*/, Player* owner, uint32& /*owner_accId*/, uint32& /*profit*/, bool& sendNotification, bool& updateAchievementCriteria, bool& /*sendMail*/) override 35 | { 36 | if (owner) 37 | { 38 | bool isAHBot = false; 39 | for (AuctionHouseBotCharacter character : auctionbot->AHCharacters) 40 | { 41 | if (character.CharacterGUID == owner->GetGUID().GetCounter()) 42 | { 43 | isAHBot = true; 44 | break; 45 | } 46 | } 47 | if (isAHBot == true) 48 | { 49 | sendNotification = false; 50 | updateAchievementCriteria = false; 51 | } 52 | } 53 | } 54 | 55 | void OnBeforeAuctionHouseMgrSendAuctionExpiredMail(AuctionHouseMgr* /*auctionHouseMgr*/, AuctionEntry* /*auction*/, Player* owner, uint32& /*owner_accId*/, bool& sendNotification, bool& /*sendMail*/) override 56 | { 57 | if (owner) 58 | { 59 | bool isAHBot = false; 60 | for (AuctionHouseBotCharacter character : auctionbot->AHCharacters) 61 | { 62 | if (character.CharacterGUID == owner->GetGUID().GetCounter()) 63 | { 64 | isAHBot = true; 65 | break; 66 | } 67 | } 68 | if (isAHBot == true) 69 | { 70 | sendNotification = false; 71 | } 72 | } 73 | } 74 | 75 | void OnBeforeAuctionHouseMgrSendAuctionOutbiddedMail(AuctionHouseMgr* /*auctionHouseMgr*/, AuctionEntry* auction, Player* oldBidder, uint32& /*oldBidder_accId*/, Player* newBidder, uint32& newPrice, bool& /*sendNotification*/, bool& /*sendMail*/) override 76 | { 77 | if (oldBidder && !newBidder) 78 | oldBidder->GetSession()->SendAuctionBidderNotification((uint32)auction->GetHouseId(), auction->Id, ObjectGuid::Create(auctionbot->CurrentBotCharGUID), newPrice, auction->GetAuctionOutBid(), auction->item_template); 79 | } 80 | 81 | void OnBeforeAuctionHouseMgrUpdate() override 82 | { 83 | auctionbot->Update(); 84 | } 85 | }; 86 | 87 | class AHBot_MailScript : public MailScript 88 | { 89 | public: 90 | AHBot_MailScript() : MailScript("AHBot_MailScript") { } 91 | 92 | void OnBeforeMailDraftSendMailTo(MailDraft* /*mailDraft*/, MailReceiver const& receiver, MailSender const& sender, MailCheckMask& /*checked*/, uint32& /*deliver_delay*/, uint32& /*custom_expiration*/, bool& deleteMailItemsFromDB, bool& sendMail) override 93 | { 94 | bool isAHBot = false; 95 | for (AuctionHouseBotCharacter character : auctionbot->AHCharacters) 96 | { 97 | if (character.CharacterGUID == receiver.GetPlayerGUIDLow()) 98 | { 99 | isAHBot = true; 100 | break; 101 | } 102 | } 103 | if (isAHBot == true) 104 | { 105 | if (sender.GetMailMessageType() == MAIL_AUCTION) // auction mail with items 106 | deleteMailItemsFromDB = true; 107 | sendMail = false; 108 | } 109 | } 110 | }; 111 | 112 | void AddAHBotScripts() 113 | { 114 | new AHBot_WorldScript(); 115 | new AHBot_AuctionHouseScript(); 116 | new AHBot_MailScript(); 117 | } 118 | -------------------------------------------------------------------------------- /src/ah_bot_loader.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016+ AzerothCore , released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3 3 | * Copyright (C) 2021+ WarheadCore 4 | * Copyright (C) 2023+ Nathan Handley 5 | */ 6 | 7 | // From SC 8 | void AddAHBotScripts(); 9 | 10 | // Add all 11 | void Addmod_ah_botScripts() 12 | { 13 | AddAHBotScripts(); 14 | } 15 | --------------------------------------------------------------------------------