Skip to content

Commit cb2dc1b

Browse files
author
Mikolaj Graf
committed
Merge branch '3.5'
# Conflicts: # .luacheckrc # AutoSellPlus/Selling.lua
2 parents 1ebe834 + 32ac664 commit cb2dc1b

12 files changed

Lines changed: 408 additions & 90 deletions

.luacheckrc

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,13 @@ read_globals = {
9191

9292
-- WoW API: Tooltip
9393
"TooltipDataProcessor",
94+
"C_TooltipInfo",
95+
96+
-- WoW API: Binding globals (localized by Blizzard)
97+
"ITEM_BIND_TO_BNETACCOUNT",
98+
"ITEM_BNETACCOUNTBOUND",
99+
"ITEM_ACCOUNTBOUND",
100+
"ITEM_BIND_TO_ACCOUNT",
94101

95102
-- WoW API: Chat
96103
"ChatEdit_InsertLink",
@@ -109,6 +116,8 @@ read_globals = {
109116
-- WoW API: Instance
110117
"GetInstanceInfo",
111118
"GetExpansionLevel",
119+
"NUM_TOTAL_EQUIPPED_BAG_SLOTS",
120+
"C_DateAndTime",
112121

113122
-- WoW API: Misc
114123
"strsplit",
@@ -118,6 +127,7 @@ read_globals = {
118127
"GetAddOnMetadata",
119128
"date",
120129
"time",
130+
"GetBuybackItemLink",
121131
"GetLootSlotLink",
122132
"LootSlot",
123133
"CursorHasItem",

AutoSellPlus/Bindings.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<Bindings>
2-
<Binding name="ASP_TOGGLE_POPUP" header="AUTOSELLPLUS" runOnUp="false">
2+
<Binding name="ASP_TOGGLE_POPUP" runOnUp="false">
33
AutoSellPlus_KeybindSell()
44
</Binding>
55
</Bindings>

AutoSellPlus/Config.lua

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ ns.globalDefaults = {
5151
allowBoESell = false,
5252
onlySoulbound = false,
5353
protectQuestItems = true,
54+
protectMountEquipment = true,
55+
protectWarband = false,
5456
-- Display
5557
showSummary = true,
5658
showItemized = false,

AutoSellPlus/ConfirmList.lua

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,37 @@ local function CreateDividerRow(parent, index)
159159
return row
160160
end
161161

162+
-- ============================================================
163+
-- Row Creation & Pooling
164+
-- ============================================================
165+
166+
local rowPool = {}
167+
168+
local function GetRow(parent, index, isDivider)
169+
local row
170+
-- Find an existing hidden row of the correct type
171+
for i, r in ipairs(rowPool) do
172+
if not r:IsShown() and ((isDivider and r.isDivider) or (not isDivider and not r.isDivider)) then
173+
row = r
174+
row:SetParent(parent)
175+
row:ClearAllPoints()
176+
row:SetPoint("TOPLEFT", parent, "TOPLEFT", 0, -(index - 1) * ROW_HEIGHT)
177+
break
178+
end
179+
end
180+
181+
if not row then
182+
if isDivider then
183+
row = CreateDividerRow(parent, index)
184+
else
185+
row = CreateRow(parent, index)
186+
end
187+
rowPool[#rowPool + 1] = row
188+
end
189+
190+
return row
191+
end
192+
162193
-- ============================================================
163194
-- Public API
164195
-- ============================================================
@@ -168,10 +199,9 @@ function ns:ShowConfirmList(queue, parentFrame)
168199

169200
local f = GetOrCreatePanel()
170201

171-
-- Clear old rows
172-
for _, row in ipairs(f.rows) do
202+
-- Hide all pooled rows first
203+
for _, row in ipairs(rowPool) do
173204
row:Hide()
174-
row:SetParent(nil)
175205
end
176206
wipe(f.rows)
177207

@@ -184,13 +214,13 @@ function ns:ShowConfirmList(queue, parentFrame)
184214
-- Insert divider before item 13
185215
if i == BUYBACK_LIMIT + 1 then
186216
rowIndex = rowIndex + 1
187-
local divider = CreateDividerRow(scrollChild, rowIndex)
217+
local divider = GetRow(scrollChild, rowIndex, true)
188218
f.rows[#f.rows + 1] = divider
189219
divider:Show()
190220
end
191221

192222
rowIndex = rowIndex + 1
193-
local row = CreateRow(scrollChild, rowIndex)
223+
local row = GetRow(scrollChild, rowIndex, false)
194224
f.rows[#f.rows + 1] = row
195225

196226
-- Icon

AutoSellPlus/Helpers.lua

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -250,10 +250,20 @@ function ns:DeserializeList(str)
250250
return imported > 0, imported
251251
end
252252

253+
function ns:GetMaxBagID()
254+
-- On Retail/Midnight, bag 5 is the reagent bag.
255+
-- Future-proofing: use NUM_TOTAL_EQUIPPED_BAG_SLOTS if available (Modern WoW).
256+
return (NUM_TOTAL_EQUIPPED_BAG_SLOTS or 5)
257+
end
258+
259+
function ns:GetServerTime()
260+
return C_DateAndTime and C_DateAndTime.GetServerTime() or GetServerTime()
261+
end
262+
253263
-- Count free bag slots
254264
function ns:CountFreeSlots()
255265
local free = 0
256-
for bag = 0, 4 do
266+
for bag = 0, self:GetMaxBagID() do
257267
local numSlots = C_Container.GetContainerNumSlots(bag)
258268
for slot = 1, numSlots do
259269
local itemInfo = C_Container.GetContainerItemInfo(bag, slot)
@@ -265,11 +275,10 @@ function ns:CountFreeSlots()
265275
return free
266276
end
267277

268-
-- Calculate total vendor value of all bag items
269278
-- Count total quantity of an item across all bags
270279
function ns:GetItemCount(itemID)
271280
local count = 0
272-
for bag = 0, 4 do
281+
for bag = 0, self:GetMaxBagID() do
273282
local numSlots = C_Container.GetContainerNumSlots(bag)
274283
for slot = 1, numSlots do
275284
local itemInfo = C_Container.GetContainerItemInfo(bag, slot)
@@ -281,21 +290,9 @@ function ns:GetItemCount(itemID)
281290
return count
282291
end
283292

284-
-- Check if item exceeds its stack limit, returns excess count (0 if within limit)
285-
function ns:ExceedsStackLimit(itemID)
286-
local limits = self.db.stackLimits
287-
if not limits or not limits[itemID] then return 0 end
288-
local limit = limits[itemID]
289-
local current = self:GetItemCount(itemID)
290-
if current > limit then
291-
return current - limit
292-
end
293-
return 0
294-
end
295-
296293
function ns:GetTotalBagVendorValue()
297294
local total = 0
298-
for bag = 0, 4 do
295+
for bag = 0, self:GetMaxBagID() do
299296
local numSlots = C_Container.GetContainerNumSlots(bag)
300297
for slot = 1, numSlots do
301298
local itemInfo = C_Container.GetContainerItemInfo(bag, slot)
@@ -312,7 +309,7 @@ end
312309

313310
-- Iterate all bag items. Callback receives (bag, slot, itemInfo). Return true to stop.
314311
function ns:IterateBagItems(callback)
315-
for bag = 0, 4 do
312+
for bag = 0, self:GetMaxBagID() do
316313
local numSlots = C_Container.GetContainerNumSlots(bag)
317314
for slot = 1, numSlots do
318315
local itemInfo = C_Container.GetContainerItemInfo(bag, slot)
@@ -327,7 +324,7 @@ end
327324

328325
-- Format a timestamp as "Xs ago", "Xm ago", "Xh ago", "Xd ago"
329326
function ns:FormatTimeAgo(timestamp)
330-
local elapsed = GetServerTime() - timestamp
327+
local elapsed = self:GetServerTime() - timestamp
331328
if elapsed < 60 then
332329
return elapsed .. "s ago"
333330
elseif elapsed < 3600 then

AutoSellPlus/Popup.lua

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ local addonName, ns = ...
33
-- Layout constants
44
local ROW_HEIGHT = 28
55
local POPUP_WIDTH = 580
6-
local POPUP_HEIGHT = 650
6+
local POPUP_HEIGHT = 694
77

88
local FLAT_BACKDROP = ns.FLAT_BACKDROP
99

@@ -718,6 +718,38 @@ local function CreateFilterSection(f)
718718
end)
719719
f.soulboundCheck = soulboundCheck
720720
rowY = rowY - 22
721+
722+
-- Protect mount equipment checkbox
723+
local mountEquipCheck = CreateStyledCheck(f, 18)
724+
mountEquipCheck:SetPoint("TOPLEFT", filterLeft, filterTop + rowY)
725+
local mountEquipLabel = f:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
726+
mountEquipLabel:SetPoint("LEFT", mountEquipCheck, "RIGHT", 6, 0)
727+
mountEquipLabel:SetText("Protect Mount Equipment")
728+
mountEquipLabel:SetTextColor(0.70, 0.70, 0.70)
729+
mountEquipCheck:SetScript("OnClick", function(self)
730+
ns.db.protectMountEquipment = self:GetChecked()
731+
displayList = ns:BuildDisplayList()
732+
ns:ApplyFilters(displayList, userUnchecked)
733+
ns:RefreshPopupList()
734+
end)
735+
f.mountEquipCheck = mountEquipCheck
736+
rowY = rowY - 22
737+
738+
-- Protect warband checkbox
739+
local warbandCheck = CreateStyledCheck(f, 18)
740+
warbandCheck:SetPoint("TOPLEFT", filterLeft, filterTop + rowY)
741+
local warbandLabel = f:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
742+
warbandLabel:SetPoint("LEFT", warbandCheck, "RIGHT", 6, 0)
743+
warbandLabel:SetText("Protect Warband")
744+
warbandLabel:SetTextColor(0.70, 0.70, 0.70)
745+
warbandCheck:SetScript("OnClick", function(self)
746+
ns.db.protectWarband = self:GetChecked()
747+
displayList = ns:BuildDisplayList()
748+
ns:ApplyFilters(displayList, userUnchecked)
749+
ns:RefreshPopupList()
750+
end)
751+
f.warbandCheck = warbandCheck
752+
rowY = rowY - 22
721753
rowY = rowY - 4
722754

723755
-- Category filters
@@ -992,7 +1024,7 @@ local function CreateBottomBar(f)
9921024
return
9931025
end
9941026
-- Find the item in bags and sell it
995-
for bag = 0, 4 do
1027+
for bag = 0, ns:GetMaxBagID() do
9961028
local numSlots = C_Container.GetContainerNumSlots(bag)
9971029
for slot = 1, numSlots do
9981030
local itemInfo = C_Container.GetContainerItemInfo(bag, slot)
@@ -1210,6 +1242,8 @@ local function SyncFiltersFromDB(f)
12101242
f.equipCheck:SetChecked(ns.db.onlyEquippable)
12111243
f.transmogCheck:SetChecked(not ns.db.protectUncollectedTransmog)
12121244
f.soulboundCheck:SetChecked(ns.db.onlySoulbound)
1245+
f.mountEquipCheck:SetChecked(ns.db.protectMountEquipment)
1246+
f.warbandCheck:SetChecked(ns.db.protectWarband)
12131247

12141248
if f.whiteSlider then
12151249
f.whiteSlider:SetValue(ns.db.whiteMaxIlvl)

AutoSellPlus/PopupFilters.lua

Lines changed: 29 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ local addonName, ns = ...
66

77
function ns:BuildDisplayList()
88
local list = {}
9-
for bag = 0, 4 do
9+
for bag = 0, self:GetMaxBagID() do
1010
local numSlots = C_Container.GetContainerNumSlots(bag)
1111
for slot = 1, numSlots do
1212
local itemInfo = C_Container.GetContainerItemInfo(bag, slot)
@@ -23,11 +23,13 @@ function ns:BuildDisplayList()
2323
local isAlwaysSell = self:IsAlwaysSell(itemID)
2424
local isMarked = self:IsMarked(itemID)
2525

26+
local _, _, _, _, _, bClassID, bSubclassID = C_Item.GetItemInfoInstant(itemID)
2627
if not self:IsNeverSell(itemID)
2728
and not isLocked
2829
and not self:IsRefundable(bag, slot)
2930
and (sellPrice and sellPrice > 0 or isAlwaysSell)
3031
and not hasNoValue
32+
and not (self.db.protectMountEquipment and bClassID == 15 and bSubclassID == 6)
3133
and not (self.db.protectEquipmentSets and self:IsInEquipmentSet(itemID))
3234
and not (self.db.protectUncollectedTransmog and self:HasTransmogAppearance(itemID) and self:IsUncollectedTransmog(itemID))
3335
and not (self.db.protectTransmogSource and self:HasTransmogAppearance(itemID) and self:IsUncollectedTransmogSource(itemID))
@@ -37,28 +39,20 @@ function ns:BuildDisplayList()
3739
-- Skip: soulbound-only mode, item is not bound to player
3840
elseif self.db.protectBoE and isBoe and not self.db.allowBoESell and not isAlwaysSell then
3941
-- Skip: BoE protection
42+
elseif self.db.protectWarband and self:IsWarband(bag, slot) and not isAlwaysSell then
43+
-- Skip: Warband protection
4044
elseif self.db.protectCurrentExpMaterials
41-
and self:GetItemClassID(itemID) == 7
45+
and bClassID == 7
4246
and self:GetItemExpansion(itemLink) == ns.CURRENT_EXPANSION
4347
and not isAlwaysSell then
4448
-- Skip current expansion trade goods
4549
else
4650
local ilvl = self:GetEffectiveItemLevel(itemLink)
4751
local isEquippable = self:IsEquippable(itemID)
4852
local equippedIlvl = isEquippable and self:GetEquippedIlvlForItem(itemID) or 0
49-
local classID = self:GetItemClassID(itemID)
53+
local classID = bClassID
5054
local expansionID = self:GetItemExpansion(itemLink)
5155

52-
-- AH value lookup
53-
local ahValue = 0
54-
if TSM_API and TSM_API.GetCustomPriceValue then
55-
local ok, val = pcall(TSM_API.GetCustomPriceValue, "DBMarket", "i:" .. itemID)
56-
if ok and val then ahValue = val end
57-
elseif Auctionator and Auctionator.API and Auctionator.API.v1 and Auctionator.API.v1.GetAuctionPriceByItemLink then
58-
local ok, val = pcall(Auctionator.API.v1.GetAuctionPriceByItemLink, "AutoSellPlus", itemLink)
59-
if ok and val then ahValue = val end
60-
end
61-
6256
list[#list + 1] = {
6357
bag = bag,
6458
slot = slot,
@@ -74,9 +68,10 @@ function ns:BuildDisplayList()
7468
isAlwaysSell = isAlwaysSell,
7569
isMarked = isMarked,
7670
isBoe = isBoe,
77-
classID = classID,
71+
classID = bClassID,
72+
subclassID = bSubclassID,
7873
expansionID = expansionID,
79-
ahValue = ahValue,
74+
ahValue = 0,
8075
checked = false,
8176
visible = false,
8277
}
@@ -204,6 +199,7 @@ function ns:ApplyFilters(displayList, userUnchecked)
204199

205200
-- Category filters (non-equippable items)
206201
if not visible then
202+
local isMountEquip = (item.classID == 15 and item.subclassID == 6)
207203
if item.classID == 0 and db.sellConsumables then
208204
visible = true
209205
autoChecked = true
@@ -214,13 +210,29 @@ function ns:ApplyFilters(displayList, userUnchecked)
214210
visible = true
215211
autoChecked = not db.protectQuestItems
216212
elseif item.classID == 15 and db.sellMiscItems then
217-
visible = true
218-
autoChecked = true
213+
if db.protectMountEquipment and isMountEquip then
214+
visible = false
215+
autoChecked = false
216+
else
217+
visible = true
218+
autoChecked = true
219+
end
219220
end
220221
end
221222

222223
item.visible = visible
223224

225+
-- Deferred AH value lookup: only query for visible items
226+
if visible and item.ahValue == 0 then
227+
if TSM_API and TSM_API.GetCustomPriceValue then
228+
local ok, val = pcall(TSM_API.GetCustomPriceValue, "DBMarket", "i:" .. item.itemID)
229+
if ok and val then item.ahValue = val end
230+
elseif Auctionator and Auctionator.API and Auctionator.API.v1 and Auctionator.API.v1.GetAuctionPriceByItemLink then
231+
local ok, val = pcall(Auctionator.API.v1.GetAuctionPriceByItemLink, "AutoSellPlus", item.itemLink)
232+
if ok and val then item.ahValue = val end
233+
end
234+
end
235+
224236
local key = item.bag .. ":" .. item.slot
225237
if userUnchecked[key] then
226238
item.checked = false

0 commit comments

Comments
 (0)