-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathAHPriceChecker.lua
More file actions
487 lines (395 loc) · 17.9 KB
/
AHPriceChecker.lua
File metadata and controls
487 lines (395 loc) · 17.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
-- AH Price Checker
-- Main addon file
-- ============================================================================
-- DATA LOADING AND MERGING
-- ============================================================================
-- Global variable that will hold the merged price data
local item_price_data = nil
-- Statistics for reporting
local stats = {
fromSavedVar = 0,
fromLocal = 0,
totalItems = 0,
overrides = 0
}
-- Function to count items in a table
local function CountItems(tbl)
if not tbl then return 0 end
local count = 0
for _ in pairs(tbl) do
count = count + 1
end
return count
end
-- Function to merge two data sources
local function MergeData(base, override)
local merged = {}
-- Copy base data
if base then
for itemID, itemData in pairs(base) do
merged[itemID] = itemData
end
end
-- Apply overrides (only count if price is different)
local overrideCount = 0
if override then
for itemID, itemData in pairs(override) do
if merged[itemID] then
-- Check if the price is actually different
local basePrice = merged[itemID].vendorPrice
local newPrice = itemData.vendorPrice
if basePrice and newPrice and basePrice ~= newPrice then
overrideCount = overrideCount + 1
end
end
merged[itemID] = itemData
end
end
return merged, overrideCount
end
-- Load and merge price data from both sources
local function LoadPriceData()
local localData = nil
local savedVarData = nil
-- Try to load from local file
if AHPriceChecker_Data then
localData = AHPriceChecker_Data
stats.fromLocal = CountItems(localData)
end
-- Try to load from SavedVariable
if VendorPriceScan_Data then
savedVarData = VendorPriceScan_Data
stats.fromSavedVar = CountItems(savedVarData)
end
-- Check if we have at least one data source
if not localData and not savedVarData then
return nil
end
-- Merge data based on priority setting
local merged, overrideCount
if AHPriceChecker.SETTINGS.prioritizeScannedData then
-- Local file as base, scanned data overrides
merged, overrideCount = MergeData(localData, savedVarData)
else
-- Scanned data as base, local file overrides
merged, overrideCount = MergeData(savedVarData, localData)
end
stats.overrides = overrideCount
stats.totalItems = CountItems(merged)
return merged
end
-- ============================================================================
-- HELPER FUNCTIONS
-- ============================================================================
-- Function to get vendor price from database
local function GetVendorPrice(itemID, itemCount)
if not itemID or not item_price_data then return nil end
itemCount = itemCount or 1
local itemData = item_price_data[itemID]
if itemData and type(itemData) == "table" and itemData.vendorPrice then
return itemData.vendorPrice * itemCount
end
return nil
end
-- Function to trim whitespace from string
local function Trim(s)
return (string.gsub(s, "^%s*(.-)%s*$", "%1"))
end
-- Function to format price in gold/silver/copper with colors
local function FormatMoneyColored(money)
if not money or money == 0 then
return "|cFFFFFFFF0|r|cFFCC6600c|r"
end
-- Round up to avoid decimals
money = ceil(money)
local gold = floor(money / 10000)
local silver = floor((money - (gold * 10000)) / 100)
local copper = mod(money, 100)
local str = ""
if gold > 0 then
str = str .. "|cFFFFFFFF" .. gold .. "|r|cFFFFDB00g|r "
end
if silver > 0 then
str = str .. "|cFFFFFFFF" .. silver .. "|r|cFFC0C0C0s|r "
end
if copper > 0 or str == "" then
str = str .. "|cFFFFFFFF" .. copper .. "|r|cFFCC6600c|r"
end
return Trim(str)
end
-- Function to format price in gold/silver/copper (uncolored, for profit display)
local function FormatMoney(money)
if not money or money == 0 then return "0c" end
local gold = floor(money / 10000)
local silver = floor((money - (gold * 10000)) / 100)
local copper = mod(money, 100)
local str = ""
if gold > 0 then
str = str .. gold .. "g "
end
if silver > 0 then
str = str .. silver .. "s "
end
if copper > 0 or str == "" then
str = str .. copper .. "c"
end
return Trim(str)
end
-- Function to extract itemID from itemLink
local function GetItemIDFromLink(itemLink)
if not itemLink then return nil end
-- Find "item:" pattern
local _, _, itemID = string.find(itemLink, "item:(%d+)")
if itemID then
return tonumber(itemID)
end
return nil
end
-- ============================================================================
-- TOOLTIP FUNCTIONS
-- ============================================================================
-- Function to add unit price information to tooltip
local function AddUnitPriceToTooltip(tooltip, auctionType, index)
-- Get auction item info
local name, texture, count, quality, canUse, level, minBid, minIncrement, buyoutPrice = GetAuctionItemInfo(auctionType, index)
-- Only show if count > 1 and buyout exists
if not count or count <= 1 or not buyoutPrice or buyoutPrice == 0 then
return
end
-- Calculate buyout per unit
local buyoutPerUnit = buyoutPrice / count
-- Add blank line as spacing
tooltip:AddLine(" ")
-- Add top separator line (white)
tooltip:AddLine("-------------------------", 1, 1, 1)
-- Add buyout per unit label (white)
tooltip:AddLine("Buyout/unit:", 1, 1, 1)
-- Add the price on its own line (colored money)
tooltip:AddLine(FormatMoneyColored(buyoutPerUnit), 1, 1, 1)
-- Add bottom separator line (white)
tooltip:AddLine("-------------------------", 1, 1, 1)
-- Refresh tooltip to show new lines
tooltip:Show()
end
-- Store original SetAuctionItem function (may already be hooked by other addons)
local OriginalSetAuctionItem = GameTooltip.SetAuctionItem
-- Hook GameTooltip.SetAuctionItem to add unit price info
GameTooltip.SetAuctionItem = function(tooltip, auctionType, index)
-- Call original function (or previous hook) and store all return values
local results = {OriginalSetAuctionItem(tooltip, auctionType, index)}
-- Add our unit price info immediately if checkbox is enabled
local checkbox = getglobal("AuctionUnitPriceCheckbox")
if checkbox and checkbox:GetChecked() then
AddUnitPriceToTooltip(tooltip, auctionType, index)
end
-- Return all original values
return unpack(results)
end
-- ============================================================================
-- AUCTION HOUSE UI FUNCTIONS
-- ============================================================================
-- Function to clean all button formatting
local function CleanButton(buttonIndex)
local button = getglobal("BrowseButton" .. buttonIndex)
if not button then return end
local infoText = getglobal("BrowseButton" .. buttonIndex .. "InfoText")
-- Hide info text
if infoText then
infoText:Hide()
end
end
-- Function to mark button as profitable
local function MarkButtonAsProfitable(buttonIndex, profit, profitPercent)
local button = getglobal("BrowseButton" .. buttonIndex)
if not button then return end
-- Create or update info text
local infoText = getglobal("BrowseButton" .. buttonIndex .. "InfoText")
if not infoText then
infoText = button:CreateFontString("BrowseButton" .. buttonIndex .. "InfoText", "OVERLAY", "GameFontNormalSmall")
infoText:SetPoint("BOTTOMLEFT", button, "BOTTOMLEFT", AHPriceChecker.UI.INFO_TEXT_OFFSET_X, AHPriceChecker.UI.INFO_TEXT_OFFSET_Y)
infoText:SetJustifyH("LEFT")
end
infoText:SetText("|c" .. AHPriceChecker.COLORS.PROFIT_TEXT .. FormatMoney(profit) .. "\n" .. profitPercent .. "%|r")
infoText:Show()
end
-- Main function to update auction buttons
local function UpdateAuctionButtons()
if not item_price_data then
return
end
local numBatchAuctions, totalAuctions = GetNumAuctionItems("list")
local offset = FauxScrollFrame_GetOffset(BrowseScrollFrame)
-- First pass: Clean ALL buttons
for i = 1, NUM_BROWSE_TO_DISPLAY do
CleanButton(i)
end
-- Second pass: Mark profitable items
for i = 1, NUM_BROWSE_TO_DISPLAY do
local index = offset + i
if index <= numBatchAuctions then
local name, texture, count, quality, canUse, level, minBid, minIncrement, buyoutPrice, bidAmount, highBidder, owner = GetAuctionItemInfo("list", index)
if name and buyoutPrice and buyoutPrice > 0 then
local itemLink = GetAuctionItemLink("list", index)
if itemLink then
local itemID = GetItemIDFromLink(itemLink)
local itemCount = count or 1
if itemID then
local vendorPrice = GetVendorPrice(itemID, itemCount)
if vendorPrice and vendorPrice > 0 and buyoutPrice < vendorPrice then
local profit = vendorPrice - buyoutPrice
local profitPercent = floor((profit / vendorPrice) * 100)
MarkButtonAsProfitable(i, profit, profitPercent)
end
end
end
end
end
end
end
-- Function to clean all buttons when disabling
local function CleanAllButtons()
for i = 1, NUM_BROWSE_TO_DISPLAY do
CleanButton(i)
end
end
-- ============================================================================
-- UI CREATION
-- ============================================================================
-- Create profit checkbox UI
local function CreateProfitCheckbox()
local checkbox = CreateFrame("CheckButton", "AuctionPriceCheckerCheckbox", AuctionFrame, "UICheckButtonTemplate")
checkbox:SetWidth(24)
checkbox:SetHeight(24)
checkbox:SetPoint("TOPLEFT", AuctionFrameAuctions, "TOPLEFT", AHPriceChecker.UI.CHECKBOX_OFFSET_X, AHPriceChecker.UI.CHECKBOX_OFFSET_Y)
checkbox:SetChecked(true) -- Enabled by default
-- Checkbox label
local label = checkbox:CreateFontString(nil, "OVERLAY", "GameFontNormal")
label:SetPoint("LEFT", checkbox, "RIGHT", 0, 0)
label:SetText(AHPriceChecker.UI.CHECKBOX_LABEL)
-- Checkbox click handler
checkbox:SetScript("OnClick", function()
local isEnabled = this:GetChecked()
if isEnabled then
UpdateAuctionButtons()
else
CleanAllButtons()
end
end)
return checkbox
end
-- Create unit price checkbox UI
local function CreateUnitPriceCheckbox()
local checkbox = CreateFrame("CheckButton", "AuctionUnitPriceCheckbox", AuctionFrame, "UICheckButtonTemplate")
checkbox:SetWidth(24)
checkbox:SetHeight(24)
checkbox:SetPoint("TOPLEFT", AuctionFrameAuctions, "TOPLEFT", AHPriceChecker.UI.CHECKBOX2_OFFSET_X, AHPriceChecker.UI.CHECKBOX2_OFFSET_Y)
checkbox:SetChecked(true) -- Enabled by default
-- Checkbox label
local label = checkbox:CreateFontString(nil, "OVERLAY", "GameFontNormal")
label:SetPoint("LEFT", checkbox, "RIGHT", 0, 0)
label:SetText(AHPriceChecker.UI.CHECKBOX2_LABEL)
-- Note: No OnClick handler needed - tooltip hook checks checkbox state automatically
return checkbox
end
-- ============================================================================
-- SLASH COMMANDS
-- ============================================================================
-- Function to display addon info
local function ShowAddonInfo()
local prefix = "|c" .. AHPriceChecker.COLORS.MAGE_BLUE .. "[" .. AHPriceChecker.ADDON_PREFIX .. "]|r"
if item_price_data then
if stats.totalItems > 0 then
-- Determine if we have multiple sources
local hasMultipleSources = (stats.fromLocal > 0 and stats.fromSavedVar > 0)
-- Show data source statistics
if stats.fromLocal > 0 then
DEFAULT_CHAT_FRAME:AddMessage(prefix .. " " .. AHPriceChecker.MESSAGES.LOADED_FROM_LOCAL .. " |c" .. AHPriceChecker.COLORS.COPPER .. stats.fromLocal .. "|r " .. AHPriceChecker.MESSAGES.ITEMS_TEXT)
end
if stats.fromSavedVar > 0 then
DEFAULT_CHAT_FRAME:AddMessage(prefix .. " " .. AHPriceChecker.MESSAGES.LOADED_FROM_SAVEDVAR .. " |c" .. AHPriceChecker.COLORS.COPPER .. stats.fromSavedVar .. "|r " .. AHPriceChecker.MESSAGES.ITEMS_TEXT)
end
-- Only show overrides and final database if there are multiple sources
if hasMultipleSources then
if stats.overrides > 0 then
DEFAULT_CHAT_FRAME:AddMessage(prefix .. " |c" .. AHPriceChecker.COLORS.COPPER .. stats.overrides .. "|r " .. AHPriceChecker.MESSAGES.CUSTOM_OVERRIDES)
end
DEFAULT_CHAT_FRAME:AddMessage(prefix .. " " .. AHPriceChecker.MESSAGES.FINAL_DATABASE .. " |c" .. AHPriceChecker.COLORS.COPPER .. stats.totalItems .. "|r " .. AHPriceChecker.MESSAGES.ITEMS_TEXT)
end
else
-- Data sources exist but are empty (0 items)
DEFAULT_CHAT_FRAME:AddMessage(prefix .. " |c" .. AHPriceChecker.COLORS.GOLD .. AHPriceChecker.MESSAGES.WARNING_PREFIX .. " " .. AHPriceChecker.MESSAGES.WARNING_NO_ITEMS .. "|r")
DEFAULT_CHAT_FRAME:AddMessage(prefix .. " " .. AHPriceChecker.MESSAGES.WARNING_SOLUTION)
end
else
-- No data sources available
DEFAULT_CHAT_FRAME:AddMessage(prefix .. " |c" .. AHPriceChecker.COLORS.ERROR .. AHPriceChecker.MESSAGES.ERROR_PREFIX .. " " .. AHPriceChecker.MESSAGES.ERROR_NO_DATABASE .. "|r")
DEFAULT_CHAT_FRAME:AddMessage(prefix .. " " .. AHPriceChecker.MESSAGES.ERROR_SOLUTION_1)
DEFAULT_CHAT_FRAME:AddMessage(prefix .. " " .. AHPriceChecker.MESSAGES.ERROR_SOLUTION_2)
end
end
-- Register slash commands
SLASH_AHPRICECHECKER1 = AHPriceChecker.SLASH_COMMANDS.PRIMARY
SLASH_AHPRICECHECKER2 = AHPriceChecker.SLASH_COMMANDS.SECONDARY
SlashCmdList["AHPRICECHECKER"] = function(msg)
ShowAddonInfo()
end
-- ============================================================================
-- EVENT HANDLING
-- ============================================================================
-- Main addon frame
local frame = CreateFrame("Frame")
frame:RegisterEvent("VARIABLES_LOADED")
frame:RegisterEvent("AUCTION_HOUSE_SHOW")
frame:RegisterEvent("AUCTION_ITEM_LIST_UPDATE")
-- Event handler
local updateTimer = 0
local checkboxesCreated = false
local dataLoaded = false
frame:SetScript("OnEvent", function()
if event == "VARIABLES_LOADED" then
-- Load price data after SavedVariables are available
item_price_data = LoadPriceData()
dataLoaded = true
-- Display welcome message
if item_price_data then
DEFAULT_CHAT_FRAME:AddMessage("|c" .. AHPriceChecker.COLORS.MAGE_BLUE .. AHPriceChecker.ADDON_NAME .. "|r: |c" .. AHPriceChecker.COLORS.GOLD .. "v" .. AHPriceChecker.ADDON_VERSION .. "|r " .. AHPriceChecker.MESSAGES.WELCOME_LOADED .. " |c" .. AHPriceChecker.COLORS.COPPER .. stats.totalItems .. "|r " .. AHPriceChecker.MESSAGES.WELCOME_ITEMS .. " " .. AHPriceChecker.MESSAGES.WELCOME_TYPE .. " |c" .. AHPriceChecker.COLORS.GOLD .. AHPriceChecker.SLASH_COMMANDS.PRIMARY .. "|r " .. AHPriceChecker.MESSAGES.WELCOME_FOR_INFO)
else
DEFAULT_CHAT_FRAME:AddMessage("|c" .. AHPriceChecker.COLORS.MAGE_BLUE .. AHPriceChecker.ADDON_NAME .. "|r: |c" .. AHPriceChecker.COLORS.ERROR .. AHPriceChecker.MESSAGES.ERROR_PREFIX .. " " .. AHPriceChecker.MESSAGES.ERROR_NO_DATABASE .. "|r " .. AHPriceChecker.MESSAGES.WELCOME_TYPE .. " |c" .. AHPriceChecker.COLORS.GOLD .. AHPriceChecker.SLASH_COMMANDS.PRIMARY .. "|r " .. AHPriceChecker.MESSAGES.WELCOME_FOR_INFO)
end
elseif event == "AUCTION_HOUSE_SHOW" then
-- Verify database is loaded
if not item_price_data then
DEFAULT_CHAT_FRAME:AddMessage("|c" .. AHPriceChecker.COLORS.ERROR .. AHPriceChecker.MESSAGES.ERROR_PREFIX .. " |c" .. AHPriceChecker.COLORS.WARNING .. AHPriceChecker.MESSAGES.ERROR_NO_DATABASE .. "|r")
DEFAULT_CHAT_FRAME:AddMessage(" " .. AHPriceChecker.MESSAGES.ERROR_SOLUTION_1)
DEFAULT_CHAT_FRAME:AddMessage(" " .. AHPriceChecker.MESSAGES.ERROR_SOLUTION_2)
end
-- Create checkboxes if not created yet
if not checkboxesCreated then
CreateProfitCheckbox()
CreateUnitPriceCheckbox()
checkboxesCreated = true
end
elseif event == "AUCTION_ITEM_LIST_UPDATE" then
local checkbox = getglobal("AuctionPriceCheckerCheckbox")
if checkbox and checkbox:GetChecked() then
UpdateAuctionButtons()
end
end
end)
-- Timer to continuously update buttons when auction house is open
frame:SetScript("OnUpdate", function()
local checkbox = getglobal("AuctionPriceCheckerCheckbox")
if checkbox and checkbox:GetChecked() and AuctionFrame and AuctionFrame:IsVisible() and BrowseScrollFrame and BrowseScrollFrame:IsVisible() then
updateTimer = updateTimer + arg1
if updateTimer > AHPriceChecker.UI.UPDATE_INTERVAL then
UpdateAuctionButtons()
updateTimer = 0
end
else
updateTimer = 0
end
end)
-- ============================================================================
-- INITIALIZATION
-- ============================================================================
-- Data will be loaded on VARIABLES_LOADED event