diff --git a/AutoShop/AutoShop.lua b/AutoShop/AutoShop.lua index d7eea31..8cd7701 100644 --- a/AutoShop/AutoShop.lua +++ b/AutoShop/AutoShop.lua @@ -1,6 +1,74 @@ ----------------------------------------------------------------------------------------------------- +local _G, env = getfenv(0), {} +setmetatable(env, { __index = _G }) +setfenv(1, env) + +local BuyMerchantItem = BuyMerchantItem +local BuybackItem = BuybackItem +local CanMerchantRepair = CanMerchantRepair +local ClearCursor = ClearCursor +local CloseDropDownMenus = CloseDropDownMenus +local GameFontNormal = GameFontNormal +local GameFontNormalSmall = GameFontNormalSmall +local GetBuildInfo = GetBuildInfo +local GetBuybackItemInfo = GetBuybackItemInfo +local GetBuybackItemLink = GetBuybackItemLink -- tbc+ +local GetContainerItemInfo = GetContainerItemInfo +local GetContainerItemLink = GetContainerItemLink +local GetContainerNumSlots = GetContainerNumSlots +local GetCurrentKeyBoardFocus = GetCurrentKeyBoardFocus -- tbc+ +local GetCursorInfo = GetCursorInfo -- tbc+ +local GetItemCount = GetItemCount -- tbc+ +local GetItemInfo = GetItemInfo +local GetMerchantItemInfo = GetMerchantItemInfo +local GetMerchantItemLink = GetMerchantItemLink +local GetMerchantItemMaxStack = GetMerchantItemMaxStack +local GetMerchantNumItems = GetMerchantNumItems +local GetMoney = GetMoney +local GetNumBuybackItems = GetNumBuybackItems +local GetRepairAllCost = GetRepairAllCost +local RepairAllItems = RepairAllItems +local UnitExists = UnitExists +local UseContainerItem = UseContainerItem + +local ceil, floor = math.ceil, math.floor +local gmatch = string.gmatch +local tinsert, tconcat, sort = table.insert, table.concat, table.sort + +-------------------------------------------------------------------------------- +-- game version compatibility +-------------------------------------------------------------------------------- + +local function getClient() + local display_version, build_number, build_date, ui_version = GetBuildInfo() + ui_version = ui_version or 11200 + return ui_version, display_version, build_number, build_date +end + +local ui_version = getClient() +local is_tbc = false +if ui_version >= 20000 and ui_version <= 20400 then + is_tbc = true +end + +local ScrollingEdit_OnCursorChanged = _G.ScrollingEdit_OnCursorChanged +local ScrollingEdit_OnUpdate = _G.ScrollingEdit_OnUpdate + +if is_tbc then + local onCursorChanged = ScrollingEdit_OnCursorChanged + local onUpdate = ScrollingEdit_OnUpdate + + ScrollingEdit_OnCursorChanged = function(self, x, y, w, h) + onCursorChanged(x, y, w, h) + end + + ScrollingEdit_OnUpdate = function(self, elapsed, scrollFrame) + onUpdate(scrollFrame) + end +end + +-------------------------------------------------------------------------------- -- helper functions ----------------------------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- -- clear focus from any input field local function ClearFocus() if GetCurrentKeyBoardFocus() then GetCurrentKeyBoardFocus():ClearFocus() end @@ -18,15 +86,16 @@ local function FormatMoney(amount) return text ~= "" and text or "none" end ----------------------------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- -- tooltip scanning ----------------------------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- -- create a scanning tooltip and references to the first few lines local tooltipFrame = CreateFrame("GameTooltip", "AutoShopTooltip", UIParent) local tooltipLeftLines = {} local tooltipRightLines = {} for i=1,5 do - local left, right = tooltipFrame:CreateFontString(), tooltipFrame:CreateFontString() + local left, right = tooltipFrame:CreateFontString(), + tooltipFrame:CreateFontString() left:SetFontObject(GameFontNormal) right:SetFontObject(GameFontNormal) tooltipFrame:AddFontStrings(left, right) @@ -39,22 +108,25 @@ local function IsBoundAndUnusable(bag, slot) tooltipFrame:ClearLines() tooltipFrame:SetBagItem(bag, slot) local r, g, b, found - -- red text can be on the right side on lines 3 or 4, and on the left side on line 3 to 5. If - -- on the left, 3-4 is "Main Hand/Off Hand" text and 5 is a class restriction. Check if unusable - -- first since those will be much rarer than soulbound items. + -- red text can be on the right side on lines 3 or 4, and on the left side on + -- line 3 to 5. If on the left, 3-4 is "Main Hand/Off Hand" text and 5 is a + -- class restriction. Check if unusable first since those will be much rarer + -- than soulbound items. for i=3,5 do - -- the values are like 0.99999779462814. Also, make sure text is actually there for the right - -- side or else these will be old values. + -- the values are like 0.99999779462814. Also, make sure text is actually + -- there for the right side or else these will be old values. -- check right side first - if GetText() returns nil then the values are old if i < 5 then r, g, b = tooltipRightLines[i]:GetTextColor() - -- the values are like 0.99999779462814 instead of the nice 1, 0, 0 I was expecting + -- the values are like 0.99999779462814 instead of the nice 1, 0, 0 I was + -- expecting if b < .13 and g < .13 and r > .99 and tooltipRightLines[i]:GetText() then found = true end end - -- now check left side if needed - it will always have text so no need to check for old values + -- now check left side if needed - it will always have text so no need to + -- check for old values if not found then r, g, b = tooltipLeftLines[i]:GetTextColor() if b < .13 and g < .13 and r > .99 then @@ -62,7 +134,8 @@ local function IsBoundAndUnusable(bag, slot) end end if found then - -- The soulbound line can be from line 2 to the line before the red text from above + -- The soulbound line can be from line 2 to the line before the red text + -- from above for j=2,i-1 do if tooltipLeftLines[j]:GetText() == ITEM_SOULBOUND then return true @@ -75,7 +148,8 @@ local function IsBoundAndUnusable(bag, slot) end -- do some final checking to see if the item should really be sold -local tooltipMoneyName -- the item name of the last tooltip that had a money line added to it +-- the item name of the last tooltip that had a money line added to it +local tooltipMoneyName local tooltipMoneyAmount tooltipFrame:SetScript("OnTooltipAddMoney", function(self, amount) tooltipMoneyName = tooltipLeftLines[1]:GetText() @@ -84,7 +158,8 @@ end) local function FinalSellChecks(bag, slot, name) -- it must have a sale price tooltipFrame:ClearLines() - tooltipFrame:SetBagItem(bag, slot) -- OnTooltipAddMoney will be used now if it has money + -- OnTooltipAddMoney will be used now if it has money + tooltipFrame:SetBagItem(bag, slot) if tooltipMoneyName ~= name then return nil end @@ -92,20 +167,22 @@ local function FinalSellChecks(bag, slot, name) local text for i=2,4 do text = tooltipLeftLines[i]:GetText() - if (text == INVTYPE_TABARD or text == INVTYPE_BODY) and not AutoShopSave.autoSellList[name:lower()] then + if (text == INVTYPE_TABARD or text == INVTYPE_BODY) + and not AutoShopSave.autoSellList[name:lower()] then return nil end end return true end ----------------------------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- -- handling events ----------------------------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- local eventFrame = CreateFrame("frame") eventFrame:Hide() -- so OnUpdate won't be used --- white quality armor and weapons used in professions and shouldn't be sold automatically +-- white quality armor and weapons used in professions and shouldn't be sold +-- automatically local professionItemIds = { [6219] = true, -- Arclight Spanner [5956] = true, -- Blacksmith Hammer @@ -116,7 +193,8 @@ local professionItemIds = { [12225] = true, -- Blump Family Fishing Pole [6367] = true, -- Big Iron Fishing Pole [6366] = true, -- Darkwood Fishing Pole - [7996] = true, -- Lucky Fishing Hat - not sure this white version exists, but just in case + -- Lucky Fishing Hat - not sure this white version exists, but just in case + [7996] = true, } -- Autosell things @@ -124,17 +202,25 @@ local function AutoSell() local sell_list = AutoShopSave.autoSellList local sell_gray = AutoShopSave.autoSellGray local sell_white = AutoShopSave.autoSellWhite - local sell_green_ilvl = AutoShopSave.autoSellGreen and AutoShopSave.autoSellGreenIlvl or 0 - local sell_blue_ilvl = AutoShopSave.autoSellBlue and AutoShopSave.autoSellBlueIlvl or 0 - local sell_purple_ilvl = AutoShopSave.autoSellPurple and AutoShopSave.autoSellPurpleIlvl or 0 - local sell_green_unusable = sell_green_ilvl > 0 and AutoShopSave.autoSellGreenUnusable - local sell_blue_unusable = sell_blue_ilvl > 0 and AutoShopSave.autoSellBlueUnusable - local sell_purple_unusable = sell_purple_ilvl > 0 and AutoShopSave.autoSellPurpleUnusable + local sell_green_ilvl = AutoShopSave.autoSellGreen + and AutoShopSave.autoSellGreenIlvl or 0 + local sell_blue_ilvl = AutoShopSave.autoSellBlue + and AutoShopSave.autoSellBlueIlvl or 0 + local sell_purple_ilvl = AutoShopSave.autoSellPurple + and AutoShopSave.autoSellPurpleIlvl or 0 + local sell_green_unusable = sell_green_ilvl > 0 + and AutoShopSave.autoSellGreenUnusable + local sell_blue_unusable = sell_blue_ilvl > 0 + and AutoShopSave.autoSellBlueUnusable + local sell_purple_unusable = sell_purple_ilvl > 0 + and AutoShopSave.autoSellPurpleUnusable local sell_recipe = AutoShopSave.autoSellRecipe - local use_item_destroyer = AutoShopSave.useItemDestroyer and ItemDestroyerSave + local use_item_destroyer = AutoShopSave.useItemDestroyer + and ItemDestroyerSave local link, id - local sold_list = {} -- to save how many of each item is sold instead of spamming multiple lines + -- to save how many of each item is sold instead of spamming multiple lines + local sold_list = {} local profit = 0 local lower_name @@ -148,14 +234,22 @@ local function AutoSell() if (sell_gray and quality == 0) or ((itype == "Armor" or itype == "Weapon") and ((quality == 1 and sell_white and not professionItemIds[id]) - or (quality == 2 and (ilvl < sell_green_ilvl or (sell_green_unusable and IsBoundAndUnusable(bag, slot)))) - or (quality == 3 and (ilvl < sell_blue_ilvl or (sell_blue_unusable and IsBoundAndUnusable(bag, slot)))) - or (quality == 4 and (ilvl < sell_purple_ilvl or (sell_purple_unusable and IsBoundAndUnusable(bag, slot)))))) - or (sell_recipe and itype == "Recipe" and IsBoundAndUnusable(bag, slot)) + or (quality == 2 and (ilvl < sell_green_ilvl + or (sell_green_unusable and IsBoundAndUnusable(bag, slot)))) + or (quality == 3 and (ilvl < sell_blue_ilvl + or (sell_blue_unusable and IsBoundAndUnusable(bag, slot)))) + or (quality == 4 and (ilvl < sell_purple_ilvl + or (sell_purple_unusable and IsBoundAndUnusable(bag, slot)))))) + or (sell_recipe and itype == "Recipe" + and IsBoundAndUnusable(bag, slot)) or sell_list[lower_name] then - if not AutoShopSave.excludeList[lower_name] and (not use_item_destroyer or not ItemDestroyerSave.protectedItems[lower_name]) and FinalSellChecks(bag, slot, name) then + if not AutoShopSave.excludeList[lower_name] and + (not use_item_destroyer + or not ItemDestroyerSave.protectedItems[lower_name]) + and FinalSellChecks(bag, slot, name) then local _, amount = GetContainerItemInfo(bag, slot) - sold_list[link] = sold_list[link] and sold_list[link] + amount or amount + sold_list[link] = sold_list[link] and sold_list[link] + amount + or amount UseContainerItem(bag, slot) profit = profit + tooltipMoneyAmount end @@ -165,7 +259,8 @@ local function AutoSell() end if next(sold_list) ~= nil and AutoShopSave.showSellActivity then for link,amount in pairs(sold_list) do - DEFAULT_CHAT_FRAME:AddMessage("Selling " .. (amount > 1 and (amount .. " ") or " ") .. link) + DEFAULT_CHAT_FRAME:AddMessage("Selling " + .. (amount > 1 and (amount .. " ") or " ") .. link) end if profit > 0 then DEFAULT_CHAT_FRAME:AddMessage("Selling profit: " .. FormatMoney(profit)) @@ -180,12 +275,14 @@ local function AutoBuy() return end - -- Items not cached by the client won't have any information yet. If the recheck flag is set to - -- true after seeing an unknown item, then AutoBuy() will be tried again soon + -- Items not cached by the client won't have any information yet. If the + -- recheck flag is set to true after seeing an unknown item, then AutoBuy() + -- will be tried again soon local recheck local wanted for i=1,GetMerchantNumItems() do - local name, _, _, quantity, available = GetMerchantItemInfo(i) -- name (and GetMerchantItemLink()) may not exist yet + -- name (and GetMerchantItemLink()) may not exist yet + local name, _, _, quantity, available = GetMerchantItemInfo(i) if not name then recheck = true end @@ -193,17 +290,22 @@ local function AutoBuy() if wanted and available ~= 0 then -- if wanted is 0 then get as many as possible if it's a limited item - local buy = wanted == 0 and (available ~= -1 and available*quantity or 0) or wanted - GetItemCount(name) - buy = AutoShopSave.hardWantedLimit and math.floor(buy / quantity) or math.ceil(buy / quantity) + local buy = wanted == 0 and (available ~= -1 and available*quantity or 0) + or wanted - GetItemCount(name) + buy = AutoShopSave.hardWantedLimit and floor(buy / quantity) + or ceil(buy / quantity) if available ~= -1 and buy > available then buy = available end if buy > 0 then if AutoShopSave.showBuyActivity then local amount = buy * quantity - DEFAULT_CHAT_FRAME:AddMessage("Buying " .. (amount > 1 and (amount .. " ") or " ") .. GetMerchantItemLink(i)) + DEFAULT_CHAT_FRAME:AddMessage("Buying " + .. (amount > 1 and (amount .. " ") or " ") + .. GetMerchantItemLink(i)) end - -- buy in stacks/batches in case there's not enough inventory space for all of it + -- buy in stacks/batches in case there's not enough inventory space for + -- all of it local stack_buy = quantity > 1 and 1 or GetMerchantItemMaxStack(i) while buy > 0 do local amount = buy > stack_buy and stack_buy or buy @@ -218,8 +320,9 @@ local function AutoBuy() end end --- unknown items won't have any information when the merchant window is first opened - this will --- check AutoBuy() again after waiting a second for the data to download +-- unknown items won't have any information when the merchant window is first +-- opened - this will check AutoBuy() again after waiting a second for the data +-- to download local recheckTime = 0 eventFrame:SetScript("OnShow", function() recheckTime = 0 end) eventFrame:SetScript("OnUpdate", function(self, elapsed) @@ -233,17 +336,20 @@ eventFrame:SetScript("OnUpdate", function(self, elapsed) end) -- handle events -eventFrame:SetScript("OnEvent", function(self, event, ...) +eventFrame:SetScript("OnEvent", function() -- check if an item needs to be bought back if event == "MERCHANT_UPDATE" then local excluded = AutoShopSave.excludeList local name - local use_item_destroyer = AutoShopSave.useItemDestroyer and ItemDestroyerSave + local use_item_destroyer = AutoShopSave.useItemDestroyer + and ItemDestroyerSave for i=1,GetNumBuybackItems() do name = (GetBuybackItemInfo(i)) name = name and name:lower() - if name and (excluded[name] or (use_item_destroyer and ItemDestroyerSave.protectedItems[name])) then - DEFAULT_CHAT_FRAME:AddMessage("AutoShop: Buying back protected item: " .. GetBuybackItemLink(i), 1, 0, 0) + if name and (excluded[name] or (use_item_destroyer and + ItemDestroyerSave.protectedItems[name])) then + DEFAULT_CHAT_FRAME:AddMessage("AutoShop: Buying back protected item: " + .. GetBuybackItemLink(i), 1, 0, 0) BuybackItem(i) end end @@ -268,9 +374,9 @@ eventFrame:SetScript("OnEvent", function(self, event, ...) end -- set up default settings if needed - if event == "ADDON_LOADED" and ... == "AutoShop" then + if event == "ADDON_LOADED" and arg1 == "AutoShop" then eventFrame:UnregisterEvent(event) - if AutoShopSave == nil then AutoShopSave = {} end + if _G.AutoShopSave == nil then _G.AutoShopSave = {} end if AutoShopSave.autoSellGray == nil then AutoShopSave.autoSellGray = false end if AutoShopSave.autoSellWhite == nil then AutoShopSave.autoSellWhite = false end if AutoShopSave.autoSellGreen == nil then AutoShopSave.autoSellGreen = false end @@ -295,17 +401,20 @@ eventFrame:SetScript("OnEvent", function(self, event, ...) if AutoShopSave.autoBuyList == nil then AutoShopSave.autoBuyList = {} end if AutoShopSave.protectExcluded then - eventFrame:RegisterEvent("MERCHANT_UPDATE") -- to check buy back for protected items + -- to check buy back for protected items + eventFrame:RegisterEvent("MERCHANT_UPDATE") end return end end) -eventFrame:RegisterEvent("ADDON_LOADED") -- temporary - to set up default settings if needed -eventFrame:RegisterEvent("MERCHANT_SHOW") -- to know when a shop window has opened +-- temporary - to set up default settings if needed +eventFrame:RegisterEvent("ADDON_LOADED") +-- to know when a shop window has opened +eventFrame:RegisterEvent("MERCHANT_SHOW") ----------------------------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- -- options window ----------------------------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- local guiFrame = nil -- created on first use local function CreateGUI() if guiFrame then @@ -313,7 +422,8 @@ local function CreateGUI() end guiFrame = CreateFrame("Frame", "AutoShopFrame", UIParent) - table.insert(UISpecialFrames, guiFrame:GetName()) -- make it closable with escape key + -- make it closable with escape key + tinsert(UISpecialFrames, guiFrame:GetName()) guiFrame:SetFrameStrata("HIGH") guiFrame:SetBackdrop({ bgFile="Interface/Tooltips/UI-Tooltip-Background", @@ -323,7 +433,8 @@ local function CreateGUI() }) guiFrame:SetBackdropColor(0,0,0,1) guiFrame:SetPoint("CENTER") - guiFrame:SetWidth(32+(242*2)+240) -- left/right edges + 3 editboxes and space between 2 of them + -- left/right edges + 3 editboxes and space between 2 of them + guiFrame:SetWidth(32+(242*2)+240) guiFrame:SetHeight(450) guiFrame:SetMovable(true) guiFrame:EnableMouse(true) @@ -367,16 +478,20 @@ local function CreateGUI() -------------------------------------------------- -- create a checkbox and fix the hit detection on it local function CreateCheckbox(name, text, tooltip) - local frame = CreateFrame("CheckButton", "AutoshopCheckbox"..name, guiFrame, "OptionsCheckButtonTemplate") - _G[frame:GetName().."Text"]:SetText(text) - local width = _G[frame:GetName().."Text"]:GetStringWidth() + local frame = CreateFrame("CheckButton", "AutoshopCheckbox"..name, guiFrame, + "OptionsCheckButtonTemplate") + local fontstring = _G[frame:GetName().."Text"] + fontstring:SetFontObject(GameFontNormalSmall) + fontstring:SetText(text) + local width = fontstring:GetStringWidth() frame:SetHitRectInsets(0, -width, 4, 4) frame.tooltipText = tooltip return frame end -- Autosell gray items - local checkboxAutoSellGray = CreateCheckbox("AutoSellGray", "Sell gray quality items.") + local checkboxAutoSellGray = CreateCheckbox("AutoSellGray", + "Sell gray quality items.") checkboxAutoSellGray:SetPoint("TOPLEFT", guiFrame, "TOPLEFT", 12, -28) checkboxAutoSellGray:SetScript("OnClick", function() ClearFocus() @@ -384,9 +499,12 @@ local function CreateGUI() end) -- Autosell white equipment - local checkboxAutoSellWhite = CreateCheckbox("AutoSellWhite", "Sell white equipment except profession tools.", - "Only sells armor and weapons (but not shirts and tabards) - the excluded tools are like blacksmith hammers and fishing poles.") - checkboxAutoSellWhite:SetPoint("TOPLEFT", checkboxAutoSellGray, "BOTTOMLEFT", 0, 6) + local checkboxAutoSellWhite = CreateCheckbox("AutoSellWhite", + "Sell white equipment except profession tools.", + "Only sells armor and weapons (but not shirts and tabards) -" + .. " the excluded tools are like blacksmith hammers and fishing poles.") + checkboxAutoSellWhite:SetPoint("TOPLEFT", checkboxAutoSellGray, "BOTTOMLEFT", + 0, 6) checkboxAutoSellWhite:SetScript("OnClick", function() ClearFocus() AutoShopSave.autoSellWhite = this:GetChecked() or false @@ -395,7 +513,8 @@ local function CreateGUI() -- Autosell green/blue/purple equipment local function CreateQualityOption(color, widget_above_this) -- checkbox to enable the option - local checkbox1 = CreateCheckbox("AutoSell"..color, "Sell " .. color:lower() .. " equipment below ilvl") + local checkbox1 = CreateCheckbox("AutoSell"..color, "Sell " .. color:lower() + .. " equipment below ilvl") checkbox1:SetPoint("TOPLEFT", widget_above_this, "BOTTOMLEFT", 0, 6) checkbox1:SetScript("OnClick", function() ClearFocus() @@ -403,7 +522,8 @@ local function CreateGUI() end) -- input to set the ilvl - local input = CreateFrame("EditBox", "AutoshopInputAutoSell"..color, guiFrame, "InputBoxTemplate") + local input = CreateFrame("EditBox", "AutoshopInputAutoSell"..color, + guiFrame, "InputBoxTemplate") input:SetWidth(28) input:SetHeight(16) input:SetNumeric(true) @@ -416,11 +536,18 @@ local function CreateGUI() input:SetText(AutoShopSave["autoSell"..color.."Ilvl"]) end) - -- checkbox to also sell soulbound/unusable equipment no matter what the ilvl is - local checkbox2 = CreateFrame("CheckButton", "AutoshopCheckboxUnusable"..color, guiFrame, "OptionsCheckButtonTemplate") + -- checkbox to also sell soulbound/unusable equipment no matter what the + -- ilvl is + local checkbox2 = CreateFrame("CheckButton", + "AutoshopCheckboxUnusable"..color, guiFrame, "OptionsCheckButtonTemplate") checkbox2:SetPoint("LEFT", input, "RIGHT", 0, 0) - _G[checkbox2:GetName().."Text"]:SetText("or unusable & bound.") - checkbox2.tooltipText = "It only counts as unusable from incompatible wear types (like plate or wand) or class restrictions." + + local fontstring = _G[checkbox2:GetName().."Text"] + fontstring:SetFontObject(GameFontNormalSmall) + fontstring:SetText("or unusable & bound.") + + checkbox2.tooltipText = "It only counts as unusable from incompatible wear" + .. " types (like plate or wand) or class restrictions." checkbox2:SetScript("OnClick", function() ClearFocus() AutoShopSave["autoSell"..color.."Unusable"] = this:GetChecked() or false @@ -428,35 +555,51 @@ local function CreateGUI() return checkbox1, input, checkbox2 end - local checkboxAutoSellGreen, inputGreenIlvl, checkboxAutoSellGreenUnusable = CreateQualityOption("Green", checkboxAutoSellWhite) - local checkboxAutoSellBlue, inputBlueIlvl, checkboxAutoSellBlueUnusable = CreateQualityOption("Blue", checkboxAutoSellGreen) - local checkboxAutoSellPurple, inputPurpleIlvl, checkboxAutoSellPurpleUnusable = CreateQualityOption("Purple", checkboxAutoSellBlue) - checkboxAutoSellGreen.tooltipText = "Only sells armor and weapons (but not shirts and tabards) - 79 may be the lowest green ilvl to disenchant into TBC mats." - checkboxAutoSellBlue.tooltipText = "Only sells armor and weapons (but not shirts and tabards) - 71 may be the lowest blue ilvl to disenchant into TBC mats." - checkboxAutoSellPurple.tooltipText = "Only sells armor and weapons (but not shirts and tabards) - 95 may be the lowest purple ilvl to disenchant into TBC mats." + local checkboxAutoSellGreen, inputGreenIlvl, checkboxAutoSellGreenUnusable + = CreateQualityOption("Green", checkboxAutoSellWhite) + local checkboxAutoSellBlue, inputBlueIlvl, checkboxAutoSellBlueUnusable + = CreateQualityOption("Blue", checkboxAutoSellGreen) + local checkboxAutoSellPurple, inputPurpleIlvl, checkboxAutoSellPurpleUnusable + = CreateQualityOption("Purple", checkboxAutoSellBlue) + checkboxAutoSellGreen.tooltipText = "Only sells armor and weapons" + .. " (but not shirts and tabards) -" + .. " 79 may be the lowest green ilvl to disenchant into TBC mats." + checkboxAutoSellBlue.tooltipText = "Only sells armor and weapons" + .. " (but not shirts and tabards) -" + .. " 71 may be the lowest blue ilvl to disenchant into TBC mats." + checkboxAutoSellPurple.tooltipText = "Only sells armor and weapons" + .. " (but not shirts and tabards) -" + .. " 95 may be the lowest purple ilvl to disenchant into TBC mats." -- Autosell recipes - local checkboxAutoSellRecipe = CreateCheckbox("AutoSellRecipe", "Sell recipes that are both unusable & bound.", - "|cffff0000Warning: this includes recipes you don't have a high enough skill for, so you may want to wait until 375 to enable this.|r") - checkboxAutoSellRecipe:SetPoint("TOPLEFT", checkboxAutoSellPurple, "BOTTOMLEFT", 0, 6) + local checkboxAutoSellRecipe = CreateCheckbox( + "AutoSellRecipe", "Sell recipes that are both unusable & bound.", + "|cffff0000Warning: this includes recipes you don't have a high enough" + .. " skill for, so you may want to wait until 375 to enable this.|r") + checkboxAutoSellRecipe:SetPoint("TOPLEFT", checkboxAutoSellPurple, + "BOTTOMLEFT", 0, 6) checkboxAutoSellRecipe:SetScript("OnClick", function() ClearFocus() AutoShopSave.autoSellRecipe = this:GetChecked() or false end) -- Hard wanted amount limit - local checkboxHardLimit = CreateCheckbox("HardLimit", "Don't buy over the wanted amount with batches.", + local checkboxHardLimit = CreateCheckbox("HardLimit", + "Don't buy over the wanted amount with batches.", "For example, it won't buy 5x water if only 3 more are wanted.") - checkboxHardLimit:SetPoint("TOPLEFT", checkboxAutoSellGray, "TOPLEFT", guiFrame:GetWidth()/2+24, 0) + checkboxHardLimit:SetPoint("TOPLEFT", checkboxAutoSellGray, "TOPLEFT", + guiFrame:GetWidth()/2+24, 0) checkboxHardLimit:SetScript("OnClick", function() ClearFocus() AutoShopSave.hardWantedLimit = this:GetChecked() or false end) -- buy back protected items - local checkboxProtectExcluded = CreateCheckbox("ProtectExcluded", 'Buy back items in the "sell exclusions" list.', + local checkboxProtectExcluded = CreateCheckbox("ProtectExcluded", + 'Buy back items in the "sell exclusions" list.', "This is to protect against manual accidental selling.") - checkboxProtectExcluded:SetPoint("TOPLEFT", checkboxHardLimit, "BOTTOMLEFT", 0, 6) + checkboxProtectExcluded:SetPoint("TOPLEFT", checkboxHardLimit, "BOTTOMLEFT", + 0, 6) checkboxProtectExcluded:SetScript("OnClick", function() ClearFocus() AutoShopSave.protectExcluded = this:GetChecked() or false @@ -468,31 +611,39 @@ local function CreateGUI() end) -- repair items - local checkboxAutoRepair = CreateCheckbox("AutoRepair", "Repair automatically") - checkboxAutoRepair:SetPoint("TOPLEFT", checkboxProtectExcluded, "BOTTOMLEFT", 0, 6) + local checkboxAutoRepair = CreateCheckbox("AutoRepair", + "Repair automatically") + checkboxAutoRepair:SetPoint("TOPLEFT", checkboxProtectExcluded, "BOTTOMLEFT", + 0, 6) checkboxAutoRepair:SetScript("OnClick", function() ClearFocus() AutoShopSave.autoRepair = this:GetChecked() or false end) - local checkboxAutoRepairGuild = CreateCheckbox("AutoRepairGuild", "and try using guild money.") - checkboxAutoRepairGuild:SetPoint("LEFT", _G[checkboxAutoRepair:GetName().."Text"], "RIGHT", 0, 0) + local checkboxAutoRepairGuild = CreateCheckbox("AutoRepairGuild", + "and try using guild money.") + checkboxAutoRepairGuild:SetPoint("LEFT", + _G[checkboxAutoRepair:GetName().."Text"], "RIGHT", 0, 0) checkboxAutoRepairGuild:SetScript("OnClick", function() ClearFocus() AutoShopSave.autoRepairGuild = this:GetChecked() or false end) -- show buy activity - local checkboxShowBuyActivity = CreateCheckbox("ShowBuyActivity", "Show chat window messages about buying items.") - checkboxShowBuyActivity:SetPoint("TOPLEFT", checkboxAutoRepair, "BOTTOMLEFT", 0, 6) + local checkboxShowBuyActivity = CreateCheckbox("ShowBuyActivity", + "Show chat window messages about buying items.") + checkboxShowBuyActivity:SetPoint("TOPLEFT", checkboxAutoRepair, "BOTTOMLEFT", + 0, 6) checkboxShowBuyActivity:SetScript("OnClick", function() ClearFocus() AutoShopSave.showBuyActivity = this:GetChecked() or false end) -- show sell activity - local checkboxShowSellActivity = CreateCheckbox("ShowSellActivity", "Show chat window messages about selling items.") - checkboxShowSellActivity:SetPoint("TOPLEFT", checkboxShowBuyActivity, "BOTTOMLEFT", 0, 6) + local checkboxShowSellActivity = CreateCheckbox("ShowSellActivity", + "Show chat window messages about selling items.") + checkboxShowSellActivity:SetPoint("TOPLEFT", checkboxShowBuyActivity, + "BOTTOMLEFT", 0, 6) checkboxShowSellActivity:SetScript("OnClick", function() ClearFocus() AutoShopSave.showSellActivity = this:GetChecked() or false @@ -501,9 +652,12 @@ local function CreateGUI() -- use ItemDestroyer list local checkboxUseItemDestroyer = nil -- only created if ItemDestroyer exists if ItemDestroyerSave then - checkboxUseItemDestroyer = CreateCheckbox("UseItemDestroyer", "Add ItemDestroyer's protection list to sell exclusions.", - "They won't be visually added here, but when the sell exclusion list is checked for something then ItemDestroyer's list will be too.") - checkboxUseItemDestroyer:SetPoint("TOPLEFT", checkboxShowSellActivity, "BOTTOMLEFT", 0, 6) + checkboxUseItemDestroyer = CreateCheckbox("UseItemDestroyer", + "Add ItemDestroyer's protection list to sell exclusions.", + "They won't be visually added here, but when the sell exclusion list is" + .. " checked for something then ItemDestroyer's list will be too.") + checkboxUseItemDestroyer:SetPoint("TOPLEFT", checkboxShowSellActivity, + "BOTTOMLEFT", 0, 6) checkboxUseItemDestroyer:SetScript("OnClick", function() ClearFocus() AutoShopSave.useItemDestroyer = this:GetChecked() or false @@ -513,21 +667,28 @@ local function CreateGUI() -------------------------------------------------- -- bottom help text -------------------------------------------------- - local textTips = guiFrame:CreateFontString(nil, "ARTWORK", "GameFontNormalSmall") + local textTips = guiFrame:CreateFontString(nil, "ARTWORK", + "GameFontNormalSmall") textTips:SetPoint("BOTTOM", guiFrame, "BOTTOM", 0, 13) - textTips:SetText("You can drag items to the lists. To buy all of a limited quantity item, don't put a wanted amount.") + textTips:SetText("You can drag items to the lists." + .. " To buy all of a limited quantity item, don't put a wanted amount.") -------------------------------------------------- -- editboxes -------------------------------------------------- - local function CreateEditBox(type_name, position_number, title_left, title_right) + local function CreateEditBox(type_name, position_number, title_left, + title_right) local container = CreateFrame("Frame", "AutoshopEdit"..type_name, guiFrame) - local input = CreateFrame("EditBox", "AutoshopEdit"..type_name.."Input", container) - local scroll = CreateFrame("ScrollFrame", "AutoshopEdit"..type_name.."Scroll", container, "UIPanelScrollFrameTemplate") + local input = CreateFrame("EditBox", "AutoshopEdit"..type_name.."Input", + container) + local scroll = CreateFrame("ScrollFrame", + "AutoshopEdit"..type_name.."Scroll", container, + "UIPanelScrollFrameTemplate") -- header title (left) local title1 = guiFrame:CreateFontString(nil, "ARTWORK", "GameFontNormal") - title1:SetPoint("LEFT", guiFrame, "LEFT", 16 + ((position_number-1) * 242), 0) + title1:SetPoint("LEFT", guiFrame, "LEFT", 16 + ((position_number-1) * 242), + 0) title1:SetPoint("TOP", checkboxAutoSellRecipe, "BOTTOM", 0, -18) title1:SetText(title_left) @@ -544,7 +705,8 @@ local function CreateGUI() -- header title (right) if title_right then - local title2 = guiFrame:CreateFontString(nil, "ARTWORK", "GameFontNormalSmall") + local title2 = guiFrame:CreateFontString(nil, "ARTWORK", + "GameFontNormalSmall") title2:SetPoint("TOP", title1, "TOP", 0, 0) title2:SetPoint("RIGHT", container, "RIGHT", 0, 0) title2:SetText(title_right) @@ -575,11 +737,13 @@ local function CreateGUI() scrollbar:SetValue(max) end end) - input:SetScript("OnUpdate", function(this) - ScrollingEdit_OnUpdate(scroll) + input:SetScript("OnUpdate", function(self) + local self = self or this + ScrollingEdit_OnUpdate(self, arg1, scroll) end) - input:SetScript("OnCursorChanged", function() - ScrollingEdit_OnCursorChanged(arg1, arg2, arg3, arg4) + input:SetScript("OnCursorChanged", function(self) + local self = self or this + ScrollingEdit_OnCursorChanged(self, arg1, arg2, arg3, arg4) end) -- allow items to be dragged into the lists @@ -595,128 +759,136 @@ local function CreateGUI() end input:SetFocus() CloseDropDownMenus() - ClearCursor() - end - end - - local function SetReceivable(widget, input) - widget:SetScript("OnReceiveDrag", function() InputReceiveItem(input) end) - widget.OnMouseDownOriginal = widget:GetScript("OnMouseDown") - widget:SetScript("OnMouseDown", function(self, button) - if button == "LeftButton" then InputReceiveItem(input) end - if self.OnMouseDownOriginal then - self:OnMouseDownOriginal(button) - end - end) - end - - SetReceivable(scroll, input) -- has to affect the scroll part too to cover all areas - SetReceivable(input, input) - return input - end - - local inputSell = CreateEditBox("Sell", 1, "Sell:") - local inputExclude = CreateEditBox("Exclude", 2, "Sell exclusions:") - local inputBuy = CreateEditBox("Buy", 3, "Buy:", "(example: 60 Wild Quillvine)") - - -- saving the lists - inputSell:SetScript("OnEditFocusLost", function() - AutoShopSave.autoSellList = {} - for line in string.gmatch(this:GetText(), "[^\r\n]+") do - AutoShopSave.autoSellList[line:trim():lower()] = true - end - end) - - inputExclude:SetScript("OnEditFocusLost", function() - AutoShopSave.excludeList = {} - for line in string.gmatch(this:GetText(), "[^\r\n]+") do - AutoShopSave.excludeList[line:trim():lower()] = true - end - end) - - inputBuy:SetScript("OnEditFocusLost", function() - AutoShopSave.autoBuyList = {} - for line in string.gmatch(this:GetText(), "[^\r\n]+") do - local amount, name = line:match("^%s*(%d*)%s*(.+)") - AutoShopSave.autoBuyList[name:trim():lower()] = amount == "" and 0 or tonumber(amount) - end - end) - - -------------------------------------------------- - -- close button - -------------------------------------------------- - local buttonClose = CreateFrame("Button", "AutoshopButtonClose", guiFrame, "UIPanelCloseButton") - buttonClose:SetPoint("TOPRIGHT", guiFrame, "TOPRIGHT", -8, -8) - buttonClose:SetScript("OnClick", function() - ClearFocus() - guiFrame:Hide() - end) - - -------------------------------------------------- - -- showing the window - -------------------------------------------------- - guiFrame:SetScript("OnShow", function() - checkboxAutoSellGray:SetChecked(AutoShopSave.autoSellGray) - checkboxAutoSellWhite:SetChecked(AutoShopSave.autoSellWhite) - checkboxAutoSellGreen:SetChecked(AutoShopSave.autoSellGreen) - checkboxAutoSellGreenUnusable:SetChecked(AutoShopSave.autoSellGreenUnusable) - checkboxAutoSellBlue:SetChecked(AutoShopSave.autoSellBlue) - checkboxAutoSellBlueUnusable:SetChecked(AutoShopSave.autoSellBlueUnusable) - checkboxAutoSellPurple:SetChecked(AutoShopSave.autoSellPurple) - checkboxAutoSellPurpleUnusable:SetChecked(AutoShopSave.autoSellPurpleUnusable) - checkboxAutoSellRecipe:SetChecked(AutoShopSave.autoSellRecipe) - - checkboxHardLimit:SetChecked(AutoShopSave.hardWantedLimit) - checkboxShowBuyActivity:SetChecked(AutoShopSave.showBuyActivity) - checkboxShowSellActivity:SetChecked(AutoShopSave.showSellActivity) - checkboxProtectExcluded:SetChecked(AutoShopSave.protectExcluded) - checkboxAutoRepair:SetChecked(AutoShopSave.autoRepair) - checkboxAutoRepairGuild:SetChecked(AutoShopSave.autoRepairGuild) - if checkboxUseItemDestroyer then - checkboxUseItemDestroyer:SetChecked(AutoShopSave.useItemDestroyer) - end - - inputGreenIlvl:SetText(AutoShopSave.autoSellGreenIlvl) - inputBlueIlvl:SetText(AutoShopSave.autoSellBlueIlvl) - inputPurpleIlvl:SetText(AutoShopSave.autoSellPurpleIlvl) - - -- put lists in alphabetical order - local list = {} - for name in pairs(AutoShopSave.autoSellList) do - list[#list+1] = name - end - table.sort(list) - inputSell:SetText(table.concat(list, "\n")) - - list = {} - for name in pairs(AutoShopSave.excludeList) do - list[#list+1] = name - end - table.sort(list) - inputExclude:SetText(table.concat(list, "\n")) - - list = {} - for name,amount in pairs(AutoShopSave.autoBuyList) do - if amount and amount > 0 then - list[#list+1] = amount .. " " .. name - else - list[#list+1] = name - end - end - table.sort(list, function(text1, text2) return text1:match("^%d*%s*(.+)") < text2:match("^%d*%s*(.+)") end) - inputBuy:SetText(table.concat(list, "\n")) - end) - - return + ClearCursor() + end + end + + local function SetReceivable(widget, input) + widget:SetScript("OnReceiveDrag", function() InputReceiveItem(input) end) + widget.OnMouseDownOriginal = widget:GetScript("OnMouseDown") + widget:SetScript("OnMouseDown", function(self, button) + if button == "LeftButton" then InputReceiveItem(input) end + if self.OnMouseDownOriginal then + self:OnMouseDownOriginal(button) + end + end) + end + + -- has to affect the scroll part too to cover all areas + SetReceivable(scroll, input) + SetReceivable(input, input) + return input + end + + local inputSell = CreateEditBox("Sell", 1, "Sell:") + local inputExclude = CreateEditBox("Exclude", 2, "Sell exclusions:") + local inputBuy = CreateEditBox("Buy", 3, "Buy:", + "(example: 60 Wild Quillvine)") + + -- saving the lists + inputSell:SetScript("OnEditFocusLost", function() + AutoShopSave.autoSellList = {} + for line in gmatch(this:GetText(), "[^\r\n]+") do + AutoShopSave.autoSellList[line:trim():lower()] = true + end + end) + + inputExclude:SetScript("OnEditFocusLost", function() + AutoShopSave.excludeList = {} + for line in gmatch(this:GetText(), "[^\r\n]+") do + AutoShopSave.excludeList[line:trim():lower()] = true + end + end) + + inputBuy:SetScript("OnEditFocusLost", function() + AutoShopSave.autoBuyList = {} + for line in gmatch(this:GetText(), "[^\r\n]+") do + local amount, name = line:match("^%s*(%d*)%s*(.+)") + AutoShopSave.autoBuyList[name:trim():lower()] = amount == "" and 0 + or tonumber(amount) + end + end) + + -------------------------------------------------- + -- close button + -------------------------------------------------- + local buttonClose = CreateFrame("Button", "AutoshopButtonClose", guiFrame, + "UIPanelCloseButton") + buttonClose:SetPoint("TOPRIGHT", guiFrame, "TOPRIGHT", -8, -8) + buttonClose:SetScript("OnClick", function() + ClearFocus() + guiFrame:Hide() + end) + + -------------------------------------------------- + -- showing the window + -------------------------------------------------- + guiFrame:SetScript("OnShow", function() + checkboxAutoSellGray:SetChecked(AutoShopSave.autoSellGray) + checkboxAutoSellWhite:SetChecked(AutoShopSave.autoSellWhite) + checkboxAutoSellGreen:SetChecked(AutoShopSave.autoSellGreen) + checkboxAutoSellGreenUnusable:SetChecked(AutoShopSave.autoSellGreenUnusable) + checkboxAutoSellBlue:SetChecked(AutoShopSave.autoSellBlue) + checkboxAutoSellBlueUnusable:SetChecked(AutoShopSave.autoSellBlueUnusable) + checkboxAutoSellPurple:SetChecked(AutoShopSave.autoSellPurple) + checkboxAutoSellPurpleUnusable:SetChecked( + AutoShopSave.autoSellPurpleUnusable) + checkboxAutoSellRecipe:SetChecked(AutoShopSave.autoSellRecipe) + + checkboxHardLimit:SetChecked(AutoShopSave.hardWantedLimit) + checkboxShowBuyActivity:SetChecked(AutoShopSave.showBuyActivity) + checkboxShowSellActivity:SetChecked(AutoShopSave.showSellActivity) + checkboxProtectExcluded:SetChecked(AutoShopSave.protectExcluded) + checkboxAutoRepair:SetChecked(AutoShopSave.autoRepair) + checkboxAutoRepairGuild:SetChecked(AutoShopSave.autoRepairGuild) + if checkboxUseItemDestroyer then + checkboxUseItemDestroyer:SetChecked(AutoShopSave.useItemDestroyer) + end + + inputGreenIlvl:SetText(AutoShopSave.autoSellGreenIlvl) + inputBlueIlvl:SetText(AutoShopSave.autoSellBlueIlvl) + inputPurpleIlvl:SetText(AutoShopSave.autoSellPurpleIlvl) + + -- put lists in alphabetical order + local list = {} + for name in pairs(AutoShopSave.autoSellList) do + tinsert(list, name) + end + sort(list) + inputSell:SetText(tconcat(list, "\n")) + + list = {} + for name in pairs(AutoShopSave.excludeList) do + tinsert(list, name) + end + sort(list) + inputExclude:SetText(tconcat(list, "\n")) + + list = {} + for name,amount in pairs(AutoShopSave.autoBuyList) do + if amount and amount > 0 then + tinsert(list, amount .. " " .. name) + else + tinsert(list, name) + end + end + sort(list, function(text1, text2) + return text1:match("^%d*%s*(.+)") < text2:match("^%d*%s*(.+)") + end) + inputBuy:SetText(tconcat(list, "\n")) + end) + + return end ----------------------------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- -- slash command to open the options window ----------------------------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- _G.SLASH_AUTOSHOP1 = "/autoshop" +_G.SLASH_AUTOSHOP2 = "/as" function SlashCmdList.AUTOSHOP() - if not guiFrame then - CreateGUI() - end - guiFrame:Show() + if not guiFrame then + CreateGUI() + end + guiFrame:Show() end diff --git a/AutoShop/AutoShop.toc b/AutoShop/AutoShop.toc index 3e8b8de..c88d298 100644 --- a/AutoShop/AutoShop.toc +++ b/AutoShop/AutoShop.toc @@ -1,7 +1,7 @@ -## Interface: 20400 +## Interface: 30300 ## Title: AutoShop -## Author: Pyralis -## Version: 1.0 +## Author: Pyralis, fondlez +## Version: 2.0 ## Notes: Automatically buy and sell items. ## SavedVariablesPerCharacter: AutoShopSave ## DefaultState: Enabled diff --git a/README.md b/README.md index ad146aa..91ff307 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,6 @@ # AutoShop -###### Scary warning: Most of these addons were made long ago during Feenix days, then a lot was changed/added to prepare for Corecraft. Since it died, they still haven't been extensively tested on modern servers. - -### [Downloads](https://github.com/Shanghi/AutoShop/releases) +### [Download Latest](https://github.com/fondlez/AutoShop/releases/latest) *** @@ -12,7 +10,10 @@ * Can automatically repair. * Can protect against you accidentally selling specific items by immediately buying them back. -To open the settings, use: **`/autoshop`** +To open the settings, use: **`/autoshop`** or **`/as`** + +### Caution +* Using the buyback feature while also using a different addon for selling to a merchant may result in cycles of selling and buying, since the other addon may not know about sale exceptions. ## Screenshot: ![!](https://i.imgur.com/85zHWXG.png)