Zerotorescue@11: -- You can access this addon's object through: LibStub("AceAddon-3.0"):GetAddon("Inventorium") Zerotorescue@17: local addon = select(2, ...); Zerotorescue@17: addon = LibStub("AceAddon-3.0"):NewAddon(addon, "Inventorium", "AceEvent-3.0"); Zerotorescue@1: Zerotorescue@1: local AceGUI = LibStub("AceGUI-3.0"); Zerotorescue@0: Zerotorescue@0: local AceConfigDialog, AceConfigRegistry, AceSerializer; Zerotorescue@30: local groupIdToName, groupIsVirtual, options = {}, {}, {}; Zerotorescue@13: local includeTradeSkillItems = 500; Zerotorescue@13: Zerotorescue@13: -- All modules must be able to retrieve our supported addons database, thus keep it public Zerotorescue@13: addon.supportedAddons = {}; Zerotorescue@13: addon.supportedAddons.auctionPricing = {}; Zerotorescue@13: addon.supportedAddons.itemCount = {}; Zerotorescue@13: addon.supportedAddons.crafting = {}; Zerotorescue@0: Zerotorescue@0: function addon:OnInitialize() Zerotorescue@0: self:Debug("OnInitialize"); Zerotorescue@0: Zerotorescue@0: -- SAVED VARIABLES Zerotorescue@0: Zerotorescue@0: local defaults = { Zerotorescue@0: global = { Zerotorescue@0: groups = {}, Zerotorescue@0: defaults = { Zerotorescue@13: auctionPricingAddon = "Auctioneer", Zerotorescue@13: itemCountAddon = "Altoholic", Zerotorescue@13: craftingAddon = "AdvancedTradeSkillWindow", Zerotorescue@0: minimumStock = 60, Zerotorescue@0: alertBelowMinimum = true, Zerotorescue@0: summaryThresholdShow = 10, Zerotorescue@0: restockTarget = 60, Zerotorescue@0: minCraftingQueue = 0.05, Zerotorescue@0: bonusQueue = 0.1, Zerotorescue@0: priceThreshold = 0, Zerotorescue@13: summaryHidePriceThreshold = false, Zerotorescue@0: trackAtCharacters = {}, Zerotorescue@31: localItemData = { Zerotorescue@31: ["Bag"] = true, Zerotorescue@31: ["Auction House"] = true, Zerotorescue@31: }, Zerotorescue@13: summary = { Zerotorescue@13: speed = 5, Zerotorescue@13: width = 650, Zerotorescue@13: height = 600, Zerotorescue@13: }, Zerotorescue@0: colors = { Zerotorescue@17: red = 0, Zerotorescue@17: orange = 0.3, Zerotorescue@17: yellow = 0.6, Zerotorescue@17: green = 0.95, Zerotorescue@0: }, Zerotorescue@0: }, Zerotorescue@0: }, Zerotorescue@0: factionrealm = { Zerotorescue@0: characters = {}, Zerotorescue@0: }, Zerotorescue@0: }; Zerotorescue@0: Zerotorescue@0: -- Register our saved variables database Zerotorescue@11: self.db = LibStub("AceDB-3.0"):New("InventoriumDB", defaults, true); Zerotorescue@0: Zerotorescue@0: -- SLASH COMMANDS Zerotorescue@0: Zerotorescue@0: -- Disable the AddonLoader slash commands Zerotorescue@11: SLASH_INVENTORIUM1 = nil; Zerotorescue@0: SLASH_IY1 = nil; Zerotorescue@0: Zerotorescue@0: -- Register our own slash commands Zerotorescue@11: SLASH_INVENTORIUM1 = "/inventorium"; Zerotorescue@11: SLASH_INVENTORIUM2 = "/im"; Zerotorescue@36: SlashCmdList["INVENTORIUM"] = InventoriumCommandHandler; Zerotorescue@0: Zerotorescue@36: -- Config command handling Zerotorescue@36: self:RegisterSlash(function(this) Zerotorescue@36: -- We don't want any other windows open at this time. Zerotorescue@36: for name, module in this:IterateModules() do Zerotorescue@36: if module.CloseFrame then Zerotorescue@36: module:CloseFrame(); Zerotorescue@36: end Zerotorescue@36: end Zerotorescue@36: Zerotorescue@36: this:Show(); Zerotorescue@36: end, { "c", "config", "conf", "option", "options", "opt", "setting", "settings" }, "|Hfunction:InventoriumCommandHandler:config|h|cff00fff7/im config|r|h (or /im c) - Open the config window to change the settings and manage groups."); Zerotorescue@36: Zerotorescue@36: -- Debug command handling Zerotorescue@36: self:RegisterSlash(function(this) Zerotorescue@36: this.debugChannel = false; Zerotorescue@36: for i = 1, NUM_CHAT_WINDOWS do Zerotorescue@36: local name = GetChatWindowInfo(i); Zerotorescue@36: Zerotorescue@36: if name:upper() == "DEBUG" then Zerotorescue@36: this.debugChannel = _G["ChatFrame" .. i]; Zerotorescue@36: Zerotorescue@36: print("A debug channel already exists, used the old one. (" .. i .. ")"); Zerotorescue@36: return; Zerotorescue@36: end Zerotorescue@36: end Zerotorescue@36: Zerotorescue@36: if not this.debugChannel then Zerotorescue@36: -- Create a new debug channel Zerotorescue@36: local chatFrame = FCF_OpenNewWindow('Debug'); Zerotorescue@36: ChatFrame_RemoveAllMessageGroups(chatFrame); Zerotorescue@36: this.debugChannel = chatFrame; Zerotorescue@36: Zerotorescue@36: print("New debug channel created."); Zerotorescue@36: end Zerotorescue@36: end, { "d", "debug" }); Zerotorescue@36: Zerotorescue@0: -- INTERFACE OPTIONS Zerotorescue@0: Zerotorescue@0: -- Attempt to remove the interface options added by AddonLoader (if enabled) Zerotorescue@0: if AddonLoader and AddonLoader.RemoveInterfaceOptions then Zerotorescue@11: AddonLoader:RemoveInterfaceOptions("Inventorium"); Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: -- Now create our own options frame Zerotorescue@0: local frame = CreateFrame("Frame", nil, UIParent); Zerotorescue@0: frame:Hide(); Zerotorescue@11: frame.name = "Inventorium"; Zerotorescue@0: frame:HookScript("OnShow", function(self) Zerotorescue@0: -- Refresh the frame to instantly show the right options Zerotorescue@0: InterfaceOptionsFrame_OpenToCategory(self.name) Zerotorescue@0: end); Zerotorescue@0: -- And add it to the interface options Zerotorescue@0: InterfaceOptions_AddCategory(frame); Zerotorescue@0: Zerotorescue@1: self:MakeItemLinkButtonWidget(); Zerotorescue@1: self:MakeConfigItemLinkButtonWidget(); Zerotorescue@0: Zerotorescue@0: -- Remember this character is mine Zerotorescue@0: local playerName = UnitName("player"); Zerotorescue@0: if not self.db.factionrealm.characters[playerName] then Zerotorescue@0: self.db.factionrealm.characters[playerName] = true; Zerotorescue@0: Zerotorescue@0: -- Default to tracking on all chars, untracking is a convenience, not tracking by default would probably get multiple issue reports. Zerotorescue@0: self.db.global.defaults.trackAtCharacters[playerName] = true; Zerotorescue@0: end Zerotorescue@23: Zerotorescue@23: self:PremadeGroupsCheck(); Zerotorescue@0: end Zerotorescue@0: Zerotorescue@24: local function InGroup(itemId) Zerotorescue@24: -- Go through all groups to see if this item is already somewhere Zerotorescue@24: for groupName, values in pairs(addon.db.global.groups) do Zerotorescue@24: if values.items and values.items[itemId] then Zerotorescue@24: return groupName; Zerotorescue@24: end Zerotorescue@24: end Zerotorescue@24: Zerotorescue@24: return; Zerotorescue@24: end Zerotorescue@24: Zerotorescue@23: function addon:PremadeGroupsCheck(updateGroupName, updateKey, accept) Zerotorescue@23: -- Compare the current premade groups with those used, notify about changes Zerotorescue@23: if addon.defaultGroups then Zerotorescue@23: for key, groupInfo in pairs(addon.defaultGroups) do Zerotorescue@23: -- Go through all default groups Zerotorescue@23: Zerotorescue@23: for groupName, values in pairs(addon.db.global.groups) do Zerotorescue@23: -- Go through all groups to find those with this premade group Zerotorescue@23: Zerotorescue@23: if values.premadeGroups and values.premadeGroups[key] and values.premadeGroups[key] < groupInfo.version then Zerotorescue@23: -- Outdated group Zerotorescue@23: Zerotorescue@23: if updateGroupName and updateKey then Zerotorescue@23: -- This function was called after pressing yes or no in a confirm box Zerotorescue@23: Zerotorescue@23: if accept then Zerotorescue@23: -- Yes was clicked Zerotorescue@23: Zerotorescue@23: for itemId, version in pairs(groupInfo.items) do Zerotorescue@23: -- Go through all items in this premade group Zerotorescue@23: Zerotorescue@23: if version > values.premadeGroups[key] then Zerotorescue@23: -- This item was added in a more recent version than this group: Add item Zerotorescue@23: Zerotorescue@23: if InGroup(itemId) then Zerotorescue@23: print(("Skipping %s (#%d) as it is already in the group |cfffed000%s|r."):format(select(2, GetItemInfo(itemId)) or "Unknown", itemId, InGroup(itemId))); Zerotorescue@23: elseif AddToGroup(groupName, itemId) then Zerotorescue@23: print(("Added %s (#%d) found in the premade group |cfffed000%s|r to the group |cfffed000%s|r."):format(select(2, GetItemInfo(itemId)) or "Unknown", itemId, InGroup(itemId))); Zerotorescue@23: end Zerotorescue@23: end Zerotorescue@23: end Zerotorescue@23: Zerotorescue@23: -- Remember the new version Zerotorescue@23: values.premadeGroups[key] = groupInfo.version; Zerotorescue@23: else Zerotorescue@23: -- No was clicked Zerotorescue@23: Zerotorescue@23: -- Let user know what was not added Zerotorescue@23: for itemId, version in pairs(groupInfo.items) do Zerotorescue@23: -- Go through all items in this premade group Zerotorescue@23: Zerotorescue@23: if version > values.premadeGroups[key] then Zerotorescue@23: -- This item was added in a more recent version than this group: don't add (since we clicked no), but announce it Zerotorescue@23: Zerotorescue@23: print(("Skipping %s (#%d) found in the premade group |cfffed000%s|r."):format(select(2, GetItemInfo(itemId)) or "Unknown", itemId, InGroup(itemId))); Zerotorescue@23: end Zerotorescue@23: end Zerotorescue@23: Zerotorescue@23: -- Remember the new version Zerotorescue@23: values.premadeGroups[key] = groupInfo.version; Zerotorescue@23: end Zerotorescue@23: else Zerotorescue@23: StaticPopupDialogs["InventoriumConfirmUpdatePremadeGroup"] = { Zerotorescue@23: text = "The premade group |cfffed000%s|r used in the group |cfffed000%s|r has been changed. Do you wish to copy these changes?", Zerotorescue@23: button1 = YES, Zerotorescue@23: button2 = NO, Zerotorescue@23: OnAccept = function(self) Zerotorescue@23: addon:PremadeGroupsCheck(groupName, key, true); Zerotorescue@23: end, Zerotorescue@23: OnCancel = function(self, _, reason) Zerotorescue@23: if reason == "clicked" then Zerotorescue@23: addon:PremadeGroupsCheck(groupName, key, false); Zerotorescue@23: end Zerotorescue@23: end, Zerotorescue@23: timeout = 0, Zerotorescue@23: whileDead = 1, Zerotorescue@23: hideOnEscape = 1, Zerotorescue@23: }; Zerotorescue@23: StaticPopup_Show("InventoriumConfirmUpdatePremadeGroup", key, groupName); Zerotorescue@23: Zerotorescue@23: return; Zerotorescue@23: end Zerotorescue@23: end Zerotorescue@23: end Zerotorescue@23: end Zerotorescue@23: end Zerotorescue@23: end Zerotorescue@23: Zerotorescue@23: Zerotorescue@1: Zerotorescue@1: function addon:MakeItemLinkButtonWidget() Zerotorescue@0: --[[ Zerotorescue@0: [ ItemLinkButton ] Zerotorescue@1: This custom widget has to show an icon with the item link next to it. Zerotorescue@1: Upon hover it must show the item tooltip. Zerotorescue@1: Upon click it must execute the function provided through user data. Zerotorescue@1: Zerotorescue@1: UserData: itemId, onClickEvent Zerotorescue@1: Zerotorescue@0: OnEnter: tooltip show Zerotorescue@1: OnLeave: tooltip hide Zerotorescue@1: OnClick: UserData.onClickEvent Zerotorescue@0: ]] Zerotorescue@0: Zerotorescue@0: local widgetType = "ItemLinkButton"; Zerotorescue@0: local widgetVersion = 1; Zerotorescue@0: Zerotorescue@1: local function Constructor() Zerotorescue@1: local widget = AceGUI:Create("InteractiveLabel"); Zerotorescue@1: widget.type = widgetType; Zerotorescue@1: Zerotorescue@1: -- We overwrite the OnAcquire as we want to set our callbacks even Zerotorescue@1: -- when the widget is re-used from the widget pool Zerotorescue@1: widget.originalOnAcquire = widget.OnAcquire; Zerotorescue@1: widget.OnAcquire = function(self, ...) Zerotorescue@36: Zerotorescue@36: Zerotorescue@1: -- We overwrite the setcallback because we don't want anything else Zerotorescue@1: -- to overwrite our OnEnter, OnLeave and OnClick events Zerotorescue@1: -- which would be done by the AceConfigDialog after a widget gets re-used Zerotorescue@1: if not self.originalSetCallBack then Zerotorescue@1: self.originalSetCallBack = self.SetCallback; Zerotorescue@1: self.SetCallback = function(this, event, func, ...) Zerotorescue@1: if event == "OnEnter" or event == "OnLeave" or event == "OnClick" then Zerotorescue@1: -- Don't allow overwriting of these events Zerotorescue@1: return; Zerotorescue@1: elseif event == "CustomOnEnter" then Zerotorescue@1: return this.originalSetCallBack(this, "OnEnter", func, ...); Zerotorescue@1: elseif event == "CustomOnLeave" then Zerotorescue@1: return this.originalSetCallBack(this, "OnLeave", func, ...); Zerotorescue@1: elseif event == "CustomOnClick" then Zerotorescue@1: return this.originalSetCallBack(this, "OnClick", func, ...); Zerotorescue@1: else Zerotorescue@1: return this.originalSetCallBack(this, event, func, ...); Zerotorescue@1: end Zerotorescue@1: end; Zerotorescue@1: end Zerotorescue@1: Zerotorescue@1: Zerotorescue@36: Zerotorescue@1: -- Set our own events, since we disabled the normal event-names, we'll call them our custom versions Zerotorescue@1: self:SetCallback("CustomOnEnter", function(this) Zerotorescue@1: local itemId = this:GetUserData("itemId"); Zerotorescue@1: Zerotorescue@1: if itemId then Zerotorescue@1: GameTooltip:SetOwner(this.frame, "ANCHOR_TOPRIGHT"); Zerotorescue@1: GameTooltip:SetHyperlink(("item:%d"):format(itemId)); Zerotorescue@1: GameTooltip:Show(); Zerotorescue@1: end Zerotorescue@1: end); Zerotorescue@1: self:SetCallback("CustomOnLeave", function(this) Zerotorescue@1: GameTooltip:Hide(); Zerotorescue@1: end); Zerotorescue@23: self:SetCallback("CustomOnClick", function(this, ...) Zerotorescue@23: -- Below is used in child widgets to prepare for onclick Zerotorescue@1: if this.OnClick then Zerotorescue@23: this.OnClick(this, ...); Zerotorescue@1: end Zerotorescue@1: Zerotorescue@1: local func = this:GetUserData("exec"); Zerotorescue@1: local itemId = this:GetUserData("itemId"); Zerotorescue@1: Zerotorescue@1: if func then Zerotorescue@1: -- If this is a config option we will need the group id Zerotorescue@1: local path = this:GetUserData("path"); Zerotorescue@1: local groupId = (path and path[2]) or nil; Zerotorescue@1: Zerotorescue@23: func(groupId, itemId, ...); Zerotorescue@1: end Zerotorescue@1: end); Zerotorescue@1: Zerotorescue@1: Zerotorescue@1: Zerotorescue@1: -- Then also do whatever it wanted to do Zerotorescue@1: self.originalOnAcquire(self, ...); Zerotorescue@1: end; Zerotorescue@1: Zerotorescue@1: -- Remember the original SetText as this might get overwritten by the config-widget Zerotorescue@1: widget.originalSetText = widget.SetText; Zerotorescue@1: Zerotorescue@1: widget.SetItemId = function(self, itemId) Zerotorescue@1: self:SetUserData("itemId", itemId); Zerotorescue@1: Zerotorescue@1: -- Put the icon in front of it Zerotorescue@1: self:SetImage(GetItemIcon(itemId)); Zerotorescue@0: -- Standardize the size Zerotorescue@0: self:SetImageSize(16, 16); Zerotorescue@0: Zerotorescue@0: -- Make readable font Zerotorescue@0: self:SetFontObject(GameFontHighlight); Zerotorescue@0: Zerotorescue@0: -- We don't want to set the itemId as text, but rather the item link, so get that. Zerotorescue@1: local itemLink = select(2, GetItemInfo(itemId)) or ("Unknown (#%d)"):format(itemId); Zerotorescue@0: Zerotorescue@1: self:originalSetText(itemLink); Zerotorescue@1: end; Zerotorescue@1: Zerotorescue@1: return widget; Zerotorescue@0: end Zerotorescue@1: Zerotorescue@1: AceGUI:RegisterWidgetType(widgetType, Constructor, widgetVersion); Zerotorescue@1: end Zerotorescue@1: Zerotorescue@1: function addon:MakeConfigItemLinkButtonWidget() Zerotorescue@1: -- Define out custom item link button widget Zerotorescue@1: -- This will be called as if it's an input element, we overwrite some of the related functions which are called for default input fields Zerotorescue@0: Zerotorescue@1: local widgetType = "ConfigItemLinkButton"; Zerotorescue@1: local widgetVersion = 1; Zerotorescue@0: Zerotorescue@1: -- Empty function for disabling functions Zerotorescue@1: local function Dummy() end Zerotorescue@0: Zerotorescue@0: -- Makes an instance of our ItemLinkButton widget Zerotorescue@0: local function GetItemLinkButton() Zerotorescue@1: local widget = AceGUI:Create("ItemLinkButton"); Zerotorescue@0: widget.type = widgetType; Zerotorescue@0: Zerotorescue@0: -- We can only provide custom widgets for input, select and multiselect fields Zerotorescue@0: -- Input being the simplest, we use that - however, it provides two parameters: label and text. We only need one, disable the other. Zerotorescue@0: widget.SetLabel = Dummy; Zerotorescue@0: Zerotorescue@1: -- SetText is called when this button is being created and contains the itemId Zerotorescue@1: -- Forward that itemId to the ItemLinkButton Zerotorescue@1: widget.SetText = function(self, value, ...) Zerotorescue@1: if value and tonumber(value) then Zerotorescue@1: self:SetItemId(tonumber(value)); Zerotorescue@1: end Zerotorescue@1: end; Zerotorescue@1: Zerotorescue@1: widget.OnClick = function(self, ...) Zerotorescue@1: local option = self:GetUserData("option"); Zerotorescue@1: Zerotorescue@1: if option and option.set then Zerotorescue@1: self:SetUserData("exec", option.set); Zerotorescue@1: end Zerotorescue@1: end; Zerotorescue@0: Zerotorescue@0: return widget; Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: AceGUI:RegisterWidgetType(widgetType, GetItemLinkButton, widgetVersion); Zerotorescue@0: end Zerotorescue@0: Zerotorescue@36: local slashArgs = {}; Zerotorescue@36: local slashError = "Wrong arguement, the following arguements are available:"; Zerotorescue@36: Zerotorescue@36: function addon:RegisterSlash(func, args, description) Zerotorescue@36: for _, arg in pairs(args) do Zerotorescue@36: slashArgs[arg] = func; Zerotorescue@36: end Zerotorescue@36: Zerotorescue@36: if description then Zerotorescue@36: slashError = slashError .. "\n" .. description; Zerotorescue@36: end Zerotorescue@36: end Zerotorescue@36: Zerotorescue@36: function InventoriumCommandHandler(message) Zerotorescue@0: local cmd, arg = string.split(" ", (message or ""), 2); Zerotorescue@0: cmd = string.lower(cmd); Zerotorescue@0: Zerotorescue@36: if slashArgs[cmd] then Zerotorescue@36: slashArgs[cmd](addon, arg); Zerotorescue@0: else Zerotorescue@36: print(slashError); Zerotorescue@0: end Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: function addon:Load() Zerotorescue@0: if not AceConfigDialog and not AceConfigRegistry then Zerotorescue@0: self:FillOptions(); Zerotorescue@0: Zerotorescue@0: -- Build options dialog Zerotorescue@0: AceConfigDialog = LibStub("AceConfigDialog-3.0"); Zerotorescue@0: AceConfigRegistry = LibStub("AceConfigRegistry-3.0"); Zerotorescue@0: -- Register options table Zerotorescue@11: LibStub("AceConfig-3.0"):RegisterOptionsTable("InventoriumOptions", options); Zerotorescue@0: -- Set a nice default size (so that 4 normal sized elements fit next to eachother) Zerotorescue@11: AceConfigDialog:SetDefaultSize("InventoriumOptions", 975, 600); Zerotorescue@0: Zerotorescue@0: -- In case the addon is loaded from another condition, always call the remove interface options Zerotorescue@0: if AddonLoader and AddonLoader.RemoveInterfaceOptions then Zerotorescue@11: AddonLoader:RemoveInterfaceOptions("Inventorium"); Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: -- Add to the blizzard addons options thing Zerotorescue@11: --AceConfigDialog:AddToBlizOptions("InventoriumOptions"); Zerotorescue@0: end Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: function addon:Show() Zerotorescue@0: self:Load(); Zerotorescue@0: Zerotorescue@11: AceConfigDialog:Open("InventoriumOptions"); Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: function addon:FillOptions() Zerotorescue@0: options = { Zerotorescue@0: type = "group", Zerotorescue@11: name = "Inventorium", Zerotorescue@0: childGroups = "tree", Zerotorescue@0: args = { Zerotorescue@0: }, Zerotorescue@0: }; Zerotorescue@0: Zerotorescue@0: self:FillGeneralOptions(); Zerotorescue@0: Zerotorescue@0: options.args.profiles = LibStub("AceDBOptions-3.0"):GetOptionsTable(self.db, true); Zerotorescue@0: options.args.profiles.order = 200; Zerotorescue@0: Zerotorescue@0: self:MakeGroupOptions(); Zerotorescue@0: Zerotorescue@0: self:FillGroupOptions(); Zerotorescue@0: end Zerotorescue@0: Zerotorescue@1: local goldText = "%s%d|cffffd700g|r "; Zerotorescue@1: local silverText = "%s%d|cffc7c7cfs|r "; Zerotorescue@1: local copperText = "%s%d|cffeda55fc|r"; Zerotorescue@1: Zerotorescue@1: function addon:ReadableMoney(copper, clean) Zerotorescue@1: local text = ""; Zerotorescue@1: Zerotorescue@1: local gold = floor( copper / COPPER_PER_GOLD ); Zerotorescue@1: if gold > 0 then Zerotorescue@1: text = goldText:format(text, gold); Zerotorescue@1: end Zerotorescue@1: Zerotorescue@13: if not clean or (not gold or gold < 10) then Zerotorescue@1: local silver = floor( ( copper % COPPER_PER_GOLD ) / COPPER_PER_SILVER ); Zerotorescue@1: if silver > 0 then Zerotorescue@1: text = silverText:format(text, silver); Zerotorescue@1: end Zerotorescue@1: Zerotorescue@13: if not clean or (not gold or gold < 1) then Zerotorescue@1: local copper = floor( copper % COPPER_PER_SILVER ); Zerotorescue@1: if copper > 0 or text == "" then Zerotorescue@1: text = copperText:format(text, copper); Zerotorescue@1: end Zerotorescue@1: end Zerotorescue@1: end Zerotorescue@1: Zerotorescue@1: Zerotorescue@1: return string.trim(text); Zerotorescue@1: end Zerotorescue@1: Zerotorescue@1: function addon:ReadableMoneyToCopper(value) Zerotorescue@1: -- If a player enters a value it will be filled without color codes Zerotorescue@1: -- If it is retrieved from the database, it will be colored coded Zerotorescue@1: -- Thus we look for both Zerotorescue@1: local gold = tonumber(string.match(value, "(%d+)|c[a-fA-F0-9]+g|r") or string.match(value, "(%d+)g")); Zerotorescue@1: local silver = tonumber(string.match(value, "(%d+)|c[a-fA-F0-9]+s|r") or string.match(value, "(%d+)s")); Zerotorescue@1: local copper = tonumber(string.match(value, "(%d+)|c[a-fA-F0-9]+c|r") or string.match(value, "(%d+)c")); Zerotorescue@1: Zerotorescue@1: return ( (gold or 0) * COPPER_PER_GOLD ) + ( (silver or 0) * COPPER_PER_SILVER ) + (copper or 0); Zerotorescue@1: end Zerotorescue@1: Zerotorescue@1: function addon:ValidateReadableMoney(info, value) Zerotorescue@1: -- If a player enters a value it will be filled without color codes Zerotorescue@1: -- If it is retrieved from the database, it will be colored coded Zerotorescue@1: -- Thus we look for both Zerotorescue@1: local gold = tonumber(string.match(value, "(%d+)|c[a-fA-F0-9]+g|r") or string.match(value, "(%d+)g")); Zerotorescue@1: local silver = tonumber(string.match(value, "(%d+)|c[a-fA-F0-9]+s|r") or string.match(value, "(%d+)s")); Zerotorescue@1: local copper = tonumber(string.match(value, "(%d+)|c[a-fA-F0-9]+c|r") or string.match(value, "(%d+)c")); Zerotorescue@1: Zerotorescue@1: if not gold and not silver and not copper then Zerotorescue@1: return "The provided amount of money is invalid. Please provide the amount of money as #g#s#c, e.g. 591617g24s43c."; Zerotorescue@1: else Zerotorescue@1: return true; Zerotorescue@1: end Zerotorescue@1: end Zerotorescue@1: Zerotorescue@0: function addon:FillGeneralOptions() Zerotorescue@0: options.args.general = { Zerotorescue@0: order = 100, Zerotorescue@0: type = "group", Zerotorescue@0: name = "General", Zerotorescue@11: desc = "Change general Inventorium settings.", Zerotorescue@0: args = { Zerotorescue@31: info = { Zerotorescue@31: order = 1, Zerotorescue@31: type = "group", Zerotorescue@31: inline = true, Zerotorescue@31: name = "BETA Information", Zerotorescue@31: args = { Zerotorescue@31: description = { Zerotorescue@31: order = 5, Zerotorescue@31: type = "description", Zerotorescue@31: name = "Please note that all multi-select |cfffed000dropdown|r boxes were turned into multi-select |cfffed000toggle|r boxes. I do not intend to keep it this way, however it can not yet be reverted due to a major bug in one of the libraries used by Inventorium. The layout of this config may look terribly organized in it's current state.\n\n" .. Zerotorescue@31: "Since this is a beta some functionality might not be implemented yet while the options are available (usually - but not always - tagged as \"NYI\"). These options are used to indicate a feature is on the way and will be implemented before Inventorium is tagged as a release.\n\n" .. Zerotorescue@31: "Please request things you want and report anything that's clunky, weird, vague or otherwise buggy at |cfffed000the Inventorium development addon page|r. You can find this by searching for \"|cfffed000Inventorium|r\" at |cfffed000CurseForge.com|r.\n\n" .. Zerotorescue@31: "Tutorials for Inventorium will be created after the first stable release. If you require any help before that you can always contact me in the |cfffed000#JMTC|r IRC channel at |cfffed000QuakeNet.org|r. You may also report issues and request things there if you wish.\n\n" .. Zerotorescue@35: "You might notice the summary window currently gets very slow when refreshed once you get over 100-200 items in the list, this is a known issue and will be fixed in |cfffed000version 1.1|r (which is after the initial release).", Zerotorescue@31: }, Zerotorescue@31: }, Zerotorescue@31: }, Zerotorescue@0: general = { Zerotorescue@31: order = 1, Zerotorescue@0: type = "group", Zerotorescue@0: inline = true, Zerotorescue@0: name = "General", Zerotorescue@0: args = { Zerotorescue@0: description = { Zerotorescue@0: order = 0, Zerotorescue@0: type = "description", Zerotorescue@35: name = function() Zerotorescue@35: local t = "Here you can set general settings. The settings entered here will be used when you choose not to override the settings within an individual group.\n\n"; Zerotorescue@35: Zerotorescue@35: local currentAddon, selectedAddonName = addon:GetItemCountAddon(); Zerotorescue@35: Zerotorescue@35: if currentAddon then Zerotorescue@35: --GetCharacterCount Zerotorescue@35: --self.supportedAddons.itemCount[selectedExternalAddon] Zerotorescue@35: t = t .. "Currently using |cfffed000" .. selectedAddonName .. "|r as your item count addon. This addon is " .. ((currentAddon.IsEnabled() and "|cff00ff00enabled|r") or "|cffff0000disabled|r") .. "."; Zerotorescue@35: Zerotorescue@35: if currentAddon.GetTotalCount and currentAddon.GetCharacterCount then Zerotorescue@35: t = t .. " This addon supports |cfffed000both total as local|r item counts."; Zerotorescue@35: elseif currentAddon.GetTotalCount then Zerotorescue@35: t = t .. " This addon supports |cfffed000only total|r item counts."; Zerotorescue@35: elseif currentAddon.GetCharacterCount then Zerotorescue@35: t = t .. " This addon supports |cfffed000only local|r item counts."; Zerotorescue@35: end Zerotorescue@35: end Zerotorescue@35: Zerotorescue@35: return t; Zerotorescue@35: end, Zerotorescue@0: }, Zerotorescue@0: header = { Zerotorescue@0: order = 5, Zerotorescue@0: type = "header", Zerotorescue@0: name = "", Zerotorescue@0: }, Zerotorescue@13: auctionPricingAddon = { Zerotorescue@0: order = 10, Zerotorescue@0: type = "select", Zerotorescue@0: name = "Prefered pricing addon", Zerotorescue@13: desc = "Select the addon you prefer data to be retrieved from. A random supported addon will be used if the selected addon can not be found.", Zerotorescue@13: values = function() Zerotorescue@13: local temp = {}; Zerotorescue@13: for name, value in pairs(self.supportedAddons.auctionPricing) do Zerotorescue@13: temp[name] = name; Zerotorescue@13: end Zerotorescue@13: Zerotorescue@13: return temp; Zerotorescue@13: end, Zerotorescue@13: get = function() return self.db.global.defaults.auctionPricingAddon; end, Zerotorescue@36: set = function(i, v) Zerotorescue@36: self.db.global.defaults.auctionPricingAddon = v; Zerotorescue@36: Zerotorescue@36: if self.supportedAddons.auctionPricing[v].OnSelect then Zerotorescue@36: self.supportedAddons.auctionPricing[v].OnSelect(); Zerotorescue@36: end Zerotorescue@36: end, Zerotorescue@0: }, Zerotorescue@0: itemCountAddon = { Zerotorescue@0: order = 20, Zerotorescue@0: type = "select", Zerotorescue@0: name = "Prefered item count addon", Zerotorescue@13: desc = "Select the addon you prefer data to be retrieved from. A random supported addon will be used if the selected addon can not be found.", Zerotorescue@13: values = function() Zerotorescue@13: local temp = {}; Zerotorescue@13: for name, value in pairs(self.supportedAddons.itemCount) do Zerotorescue@13: temp[name] = name; Zerotorescue@13: end Zerotorescue@13: Zerotorescue@13: return temp; Zerotorescue@13: end, Zerotorescue@13: get = function() return self.db.global.defaults.itemCountAddon; end, Zerotorescue@13: set = function(i, v) self.db.global.defaults.itemCountAddon = v; end, Zerotorescue@13: }, Zerotorescue@13: craftingAddon = { Zerotorescue@23: order = 30, Zerotorescue@13: type = "select", Zerotorescue@13: name = "Prefered crafting addon", Zerotorescue@13: desc = "Select the addon you prefer data to be queued into. A random supported addon will be used if the selected addon can not be found.", Zerotorescue@13: values = function() Zerotorescue@13: local temp = {}; Zerotorescue@13: for name, value in pairs(self.supportedAddons.crafting) do Zerotorescue@13: temp[name] = name; Zerotorescue@13: end Zerotorescue@13: Zerotorescue@13: return temp; Zerotorescue@13: end, Zerotorescue@13: get = function() return self.db.global.defaults.craftingAddon; end, Zerotorescue@13: set = function(i, v) self.db.global.defaults.craftingAddon = v; end, Zerotorescue@0: }, Zerotorescue@36: --[[localItemData = { Zerotorescue@23: order = 40, Zerotorescue@23: type = "multiselect", Zerotorescue@31: name = "Include in local item data", Zerotorescue@23: desc = "Select which data should be included in the local item data.", Zerotorescue@23: values = { Zerotorescue@23: ["Bag"] = "Bag", Zerotorescue@23: ["Bank"] = "Bank", Zerotorescue@23: ["Auction House"] = "Auction House", Zerotorescue@23: ["Mailbox"] = "Mailbox", Zerotorescue@23: }, Zerotorescue@23: get = function(i, v) return self.db.global.defaults.localItemData and self.db.global.defaults.localItemData[v]; end, Zerotorescue@23: set = function(i, v, e) self.db.global.defaults.localItemData[v] = e or nil; end, Zerotorescue@23: --dialogControl = "Dropdown", -- this is not standard, normal multiselect control gives us a list of all chars with toggle-boxes. UGLY! We want a multiselect-box instead. Zerotorescue@36: },]] Zerotorescue@0: }, Zerotorescue@0: }, Zerotorescue@0: minimumStock = { Zerotorescue@0: order = 10, Zerotorescue@0: type = "group", Zerotorescue@0: inline = true, Zerotorescue@0: name = "Minimum stock", Zerotorescue@0: args = { Zerotorescue@0: description = { Zerotorescue@0: order = 0, Zerotorescue@0: type = "description", Zerotorescue@0: name = "Here you can specify the default minimum amount of items you wish to keep in stock and related settings. The settings entered here will be used when you choose not to override the settings within an individual group.", Zerotorescue@0: }, Zerotorescue@0: header = { Zerotorescue@0: order = 5, Zerotorescue@0: type = "header", Zerotorescue@0: name = "", Zerotorescue@0: }, Zerotorescue@0: minimumStock = { Zerotorescue@0: order = 10, Zerotorescue@0: type = "range", Zerotorescue@0: min = 0, Zerotorescue@0: max = 100000, Zerotorescue@17: softMax = 100, Zerotorescue@0: step = 1, Zerotorescue@0: name = "Minimum stock", Zerotorescue@17: desc = "You can manually enter a value between 100 and 100.000 in the text box below if the provided range is insufficient.", Zerotorescue@0: get = function() return self.db.global.defaults.minimumStock; end, Zerotorescue@0: set = function(i, v) self.db.global.defaults.minimumStock = v; end, Zerotorescue@0: }, Zerotorescue@0: summaryThresholdShow = { Zerotorescue@0: order = 20, Zerotorescue@0: type = "range", Zerotorescue@0: min = 0, Zerotorescue@0: max = 100, Zerotorescue@0: softMax = 10, Zerotorescue@0: step = 0.05, Zerotorescue@0: isPercent = true, Zerotorescue@0: name = "Show in summary when below", Zerotorescue@0: desc = "Show items in the summary when below this percentage of the minimum stock.\n\nYou can manually enter a value between 1.000% and 10.000% in the edit box if the provided range is insufficient.", Zerotorescue@0: get = function() return self.db.global.defaults.summaryThresholdShow; end, Zerotorescue@0: set = function(i, v) self.db.global.defaults.summaryThresholdShow = v; end, Zerotorescue@0: }, Zerotorescue@0: alertBelowMinimum = { Zerotorescue@0: order = 30, Zerotorescue@0: type = "toggle", Zerotorescue@30: name = "NYI | Alert when below minimum", Zerotorescue@0: desc = "Show an alert when this item gets below this threshold.", Zerotorescue@0: get = function() return self.db.global.defaults.alertBelowMinimum; end, Zerotorescue@0: set = function(i, v) self.db.global.defaults.alertBelowMinimum = v; end, Zerotorescue@0: }, Zerotorescue@0: trackAtCharacters = { Zerotorescue@0: order = 40, Zerotorescue@0: type = "multiselect", Zerotorescue@0: name = "Track at", Zerotorescue@0: desc = "Select at which characters this should appear in the summary and generate alerts.", Zerotorescue@0: values = function() Zerotorescue@0: local temp = {}; Zerotorescue@0: for charName in pairs(self.db.factionrealm.characters) do Zerotorescue@0: temp[charName] = charName; Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: return temp; Zerotorescue@0: end, Zerotorescue@1: get = function(i, v) return self.db.global.defaults.trackAtCharacters[v]; end, Zerotorescue@23: set = function(i, v, e) self.db.global.defaults.trackAtCharacters[v] = e or nil; end, Zerotorescue@13: --dialogControl = "Dropdown", -- this is not standard, normal multiselect control gives us a list of all chars with toggle-boxes. UGLY! We want a multiselect-box instead. Zerotorescue@0: }, Zerotorescue@0: }, Zerotorescue@0: }, Zerotorescue@0: refill = { Zerotorescue@0: order = 20, Zerotorescue@0: type = "group", Zerotorescue@0: inline = true, Zerotorescue@0: name = "Replenishing stock", Zerotorescue@0: args = { Zerotorescue@0: description = { Zerotorescue@0: order = 0, Zerotorescue@0: type = "description", Zerotorescue@0: name = function() Zerotorescue@0: local r = "Here you can specify the default amount of items to which you wish to restock when you are collecting new items. This may be higher than the minimum stock. The settings entered here will be used when you choose not to override the settings within an individual group.\n\n"; Zerotorescue@0: Zerotorescue@0: r = r .. "When restocking the target amount is |cfffed000" .. self.db.global.defaults.restockTarget .. "|r of every item. Not queueing craftable items when only missing |cfffed000" .. floor( self.db.global.defaults.minCraftingQueue * self.db.global.defaults.restockTarget ) .. "|r (|cfffed000" .. ( self.db.global.defaults.minCraftingQueue * 100 ) .. "%|r) of the restock target."; Zerotorescue@0: Zerotorescue@0: return r; Zerotorescue@0: end, Zerotorescue@0: }, Zerotorescue@0: header = { Zerotorescue@0: order = 5, Zerotorescue@0: type = "header", Zerotorescue@0: name = "", Zerotorescue@0: }, Zerotorescue@0: restockTarget = { Zerotorescue@0: order = 10, Zerotorescue@0: type = "range", Zerotorescue@0: min = 0, Zerotorescue@0: max = 100000, Zerotorescue@30: softMax = 100, Zerotorescue@0: step = 1, Zerotorescue@0: name = "Restock target", Zerotorescue@30: desc = "You can manually enter a value between 100 and 100.000 in the edit box if the provided range is insufficient.", Zerotorescue@0: get = function() return self.db.global.defaults.restockTarget; end, Zerotorescue@0: set = function(i, v) self.db.global.defaults.restockTarget = v; end, Zerotorescue@0: }, Zerotorescue@0: minCraftingQueue = { Zerotorescue@0: order = 20, Zerotorescue@0: type = "range", Zerotorescue@0: min = 0, Zerotorescue@0: max = 1, Zerotorescue@0: step = 0.01, -- 1% Zerotorescue@0: isPercent = true, Zerotorescue@0: name = "Don't queue if I only miss", Zerotorescue@0: desc = "Don't add a craftable item to the queue if I only miss this much or less of the restock target.\n\nExample: if your restock target is set to 60 and this is set to 5%, an item won't be queued unless you are missing more than 3 of it.", Zerotorescue@0: get = function() return self.db.global.defaults.minCraftingQueue; end, Zerotorescue@0: set = function(i, v) self.db.global.defaults.minCraftingQueue = v; end, Zerotorescue@0: }, Zerotorescue@0: bonusQueue = { Zerotorescue@0: order = 30, Zerotorescue@0: type = "range", Zerotorescue@0: min = 0, Zerotorescue@0: max = 10, -- 1000% Zerotorescue@0: step = 0.01, -- 1% Zerotorescue@0: isPercent = true, Zerotorescue@0: name = "Bonus queue", Zerotorescue@1: desc = "Get additional items when there are none left.\n\nExample: if your restock target is set to 60 and this is set to 10%, you will get 66 items instead of just 60 if you end up with none left while queueing.", Zerotorescue@0: get = function() return self.db.global.defaults.bonusQueue; end, Zerotorescue@0: set = function(i, v) self.db.global.defaults.bonusQueue = v; end, Zerotorescue@0: }, Zerotorescue@0: priceThreshold = { Zerotorescue@0: order = 40, Zerotorescue@0: type = "input", Zerotorescue@0: name = "Price threshold", Zerotorescue@1: desc = "Only queue craftable items when they are worth at least this much according to your auction house addon.\n\nSet to 0 to ignore auction prices.", Zerotorescue@1: validate = function(info, value) return self:ValidateReadableMoney(info, value); end, Zerotorescue@1: get = function() return self:ReadableMoney(self.db.global.defaults.priceThreshold); end, Zerotorescue@1: set = function(i, v) self.db.global.defaults.priceThreshold = self:ReadableMoneyToCopper(v); end, Zerotorescue@0: }, Zerotorescue@13: summaryHidePriceThreshold = { Zerotorescue@0: order = 50, Zerotorescue@0: type = "toggle", Zerotorescue@1: name = "Hide when below threshold", Zerotorescue@0: desc = "Hide items from the summary when their value is below the set price threshold.", Zerotorescue@13: get = function() return self.db.global.defaults.summaryHidePriceThreshold; end, Zerotorescue@13: set = function(i, v) self.db.global.defaults.summaryHidePriceThreshold = v; end, Zerotorescue@0: }, Zerotorescue@23: alwaysGetAuctionValue = { Zerotorescue@23: order = 60, Zerotorescue@23: type = "toggle", Zerotorescue@23: name = "Always show auction value", Zerotorescue@31: desc = "Always cache and show the auction value of items, even if the price threshold is set to 0|cffeda55fc|r.", Zerotorescue@23: get = function() return self.db.global.defaults.alwaysGetAuctionValue; end, Zerotorescue@23: set = function(i, v) self.db.global.defaults.alwaysGetAuctionValue = v; end, Zerotorescue@23: }, Zerotorescue@0: }, Zerotorescue@0: }, Zerotorescue@0: colorCodes = { Zerotorescue@0: order = 30, Zerotorescue@0: type = "group", Zerotorescue@0: inline = true, Zerotorescue@0: name = "Color codes", Zerotorescue@0: args = { Zerotorescue@0: description = { Zerotorescue@0: order = 0, Zerotorescue@0: type = "description", Zerotorescue@0: name = "Change the color code thresholds based on the current stock remaining of the required minimum stock.", Zerotorescue@0: }, Zerotorescue@0: header = { Zerotorescue@0: order = 5, Zerotorescue@0: type = "header", Zerotorescue@0: name = "", Zerotorescue@0: }, Zerotorescue@0: green = { Zerotorescue@0: order = 10, Zerotorescue@0: type = "range", Zerotorescue@0: min = 0, Zerotorescue@0: max = 1, Zerotorescue@0: step = 0.01, Zerotorescue@0: isPercent = true, Zerotorescue@0: name = "|cff00ff00Green|r", Zerotorescue@0: desc = "Show quantity in green when at least this much of the minimum stock is available.", Zerotorescue@0: get = function() return self.db.global.defaults.colors.green; end, Zerotorescue@0: set = function(i, v) self.db.global.defaults.colors.green = v; end, Zerotorescue@0: }, Zerotorescue@0: yellow = { Zerotorescue@0: order = 20, Zerotorescue@0: type = "range", Zerotorescue@0: min = 0, Zerotorescue@0: max = 1, Zerotorescue@0: step = 0.01, Zerotorescue@0: isPercent = true, Zerotorescue@0: name = "|cffffff00Yellow|r", Zerotorescue@0: desc = "Show quantity in yellow when at least this much of the minimum stock is available.", Zerotorescue@0: get = function() return self.db.global.defaults.colors.yellow; end, Zerotorescue@0: set = function(i, v) self.db.global.defaults.colors.yellow = v; end, Zerotorescue@0: }, Zerotorescue@0: orange = { Zerotorescue@0: order = 30, Zerotorescue@0: type = "range", Zerotorescue@0: min = 0, Zerotorescue@0: max = 1, Zerotorescue@0: step = 0.01, Zerotorescue@0: isPercent = true, Zerotorescue@0: name = "|cffff9933Orange|r", Zerotorescue@0: desc = "Show quantity in orange when at least this much of the minimum stock is available.", Zerotorescue@0: get = function() return self.db.global.defaults.colors.orange; end, Zerotorescue@0: set = function(i, v) self.db.global.defaults.colors.orange = v; end, Zerotorescue@0: }, Zerotorescue@0: red = { Zerotorescue@0: order = 40, Zerotorescue@0: type = "range", Zerotorescue@0: min = 0, Zerotorescue@0: max = 1, Zerotorescue@0: step = 0.01, Zerotorescue@0: isPercent = true, Zerotorescue@0: name = "|cffff0000Red|r", Zerotorescue@0: desc = "Show quantity in red when at least this much of the minimum stock is available.", Zerotorescue@0: get = function() return self.db.global.defaults.colors.red; end, Zerotorescue@0: set = function(i, v) self.db.global.defaults.colors.red = v; end, Zerotorescue@0: }, Zerotorescue@0: }, Zerotorescue@0: }, Zerotorescue@0: }, Zerotorescue@0: }; Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: local count = 0; Zerotorescue@0: local temp = {}; Zerotorescue@0: Zerotorescue@1: local function SetOption(info, value, multiSelectEnabled) Zerotorescue@0: local groupName = groupIdToName[info[2]]; Zerotorescue@0: local optionName = info[#info]; Zerotorescue@0: Zerotorescue@23: -- Special treatment for override toggle boxes Zerotorescue@31: if optionName:find("override") then Zerotorescue@23: if not value and info.arg then Zerotorescue@23: -- If this override was disabled and a saved variable name was provided, set it to nil rather than false Zerotorescue@23: Zerotorescue@23: value = nil; Zerotorescue@23: Zerotorescue@23: -- If this is an override toggler then also set the related field to nil Zerotorescue@23: addon.db.global.groups[groupName][info.arg] = nil; Zerotorescue@23: elseif value and info.arg then Zerotorescue@23: -- If this override is now enabled, we need to copy the default into this field (unless it is not nil (which is supposed to be impossible), in which case we'll use the already selected value) Zerotorescue@23: Zerotorescue@23: addon.db.global.groups[groupName][info.arg] = addon:GetOptionByKey(groupName, info.arg); Zerotorescue@23: end Zerotorescue@0: end Zerotorescue@0: Zerotorescue@1: if multiSelectEnabled ~= nil then Zerotorescue@1: -- The saved vars for a multiselect will always be an array, it may not yet exist in which case it must be created. Zerotorescue@1: if not addon.db.global.groups[groupName][optionName] then Zerotorescue@1: addon.db.global.groups[groupName][optionName] = {}; Zerotorescue@1: end Zerotorescue@1: Zerotorescue@1: addon.db.global.groups[groupName][optionName][value] = multiSelectEnabled or nil; Zerotorescue@1: else Zerotorescue@1: addon.db.global.groups[groupName][optionName] = value; Zerotorescue@1: end Zerotorescue@0: end Zerotorescue@0: Zerotorescue@1: function addon:GetOptionByKey(groupName, optionName, noDefault) Zerotorescue@23: if groupName and self.db.global.groups[groupName] and self.db.global.groups[groupName][optionName] ~= nil then Zerotorescue@31: -- If this option exists within the settings of this group Zerotorescue@31: Zerotorescue@23: return self.db.global.groups[groupName][optionName]; Zerotorescue@31: elseif groupName and self.db.global.groups[groupName] and self.db.global.groups[groupName].virtualGroup ~= "" and not noDefault then Zerotorescue@31: -- If a virtual group was selected Zerotorescue@31: Zerotorescue@31: return self:GetOptionByKey(self.db.global.groups[groupName].virtualGroup, optionName, noDefault); Zerotorescue@23: elseif self.db.global.defaults[optionName] and not noDefault then Zerotorescue@23: return self.db.global.defaults[optionName]; Zerotorescue@0: else Zerotorescue@0: return nil; Zerotorescue@0: end Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: local function GetOption(info) Zerotorescue@0: local groupName = groupIdToName[info[2]]; Zerotorescue@0: local optionName = info[#info]; Zerotorescue@0: Zerotorescue@31: local noDefault; Zerotorescue@31: Zerotorescue@31: if optionName:find("override") then Zerotorescue@31: noDefault = true; Zerotorescue@31: end Zerotorescue@31: Zerotorescue@31: return addon:GetOptionByKey(groupName, optionName, noDefault); Zerotorescue@1: end Zerotorescue@1: Zerotorescue@1: local function GetMultiOption(info, value) Zerotorescue@1: local groupName = groupIdToName[info[2]]; Zerotorescue@1: local optionName = info[#info]; Zerotorescue@1: Zerotorescue@1: if addon.db.global.groups[groupName][optionName] ~= nil then Zerotorescue@1: return addon.db.global.groups[groupName][optionName][value]; Zerotorescue@1: elseif addon.db.global.defaults[optionName] then Zerotorescue@1: return addon.db.global.defaults[optionName][value]; Zerotorescue@1: else Zerotorescue@1: return nil; Zerotorescue@1: end Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: local function GetDisabled(info) Zerotorescue@31: local groupName = groupIdToName[info[2]]; Zerotorescue@31: local optionName = info[#info]; Zerotorescue@31: Zerotorescue@35: if optionName:find("override") or not info.arg then Zerotorescue@0: return false; Zerotorescue@0: end Zerotorescue@0: Zerotorescue@1: return (addon:GetOptionByKey(groupName, info.arg, true) == nil); Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: local function ValidateGroupName(_, value) Zerotorescue@0: value = string.lower(string.trim(value or "")); Zerotorescue@0: Zerotorescue@0: for name, _ in pairs(addon.db.global.groups) do Zerotorescue@0: if string.lower(name) == value then Zerotorescue@0: return ("A group named \"%s\" already exists."):format(name); Zerotorescue@0: end Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: return true; Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: local function AddToGroup(groupName, itemId) Zerotorescue@0: if InGroup(itemId) then Zerotorescue@0: return false; Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: if not addon.db.global.groups[groupName].items then Zerotorescue@0: addon.db.global.groups[groupName].items = {}; Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: -- Set this item Zerotorescue@0: addon.db.global.groups[groupName].items[itemId] = true; Zerotorescue@0: Zerotorescue@0: -- Now rebuild the list Zerotorescue@11: AceConfigRegistry:NotifyChange("InventoriumOptions"); Zerotorescue@0: Zerotorescue@0: return true; Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: local tblAddItemTemplate = { Zerotorescue@0: order = 0, Zerotorescue@0: type = "input", Zerotorescue@0: name = function(info) Zerotorescue@0: local itemName, _, itemRarity = GetItemInfo(info[#info]); Zerotorescue@0: return tostring( 7 - (itemRarity or 0) ) .. (itemName or ""); Zerotorescue@0: end, Zerotorescue@0: get = function(info) Zerotorescue@0: return tostring(info[#info]); -- Ace is going to be anal about this if it's a numeric value, so we transmute it into a string here then back to a number on the other side Zerotorescue@0: end, Zerotorescue@1: set = function(groupId, itemId) Zerotorescue@0: -- This is NOT a real "set", we pass the widget reference to this function which contains similar, but not the same, info. Zerotorescue@0: Zerotorescue@1: if itemId then Zerotorescue@1: local groupName = groupIdToName[groupId]; Zerotorescue@0: Zerotorescue@1: if not AddToGroup(groupName, itemId) then Zerotorescue@1: print("|cffff0000Couldn't add the item with itemId (" .. itemId .. ") because it is already in a group.|r"); Zerotorescue@0: end Zerotorescue@0: end Zerotorescue@0: end, Zerotorescue@0: width = "double", Zerotorescue@1: dialogControl = "ConfigItemLinkButton", Zerotorescue@0: }; Zerotorescue@0: Zerotorescue@0: local tblRemoveItemTemplate = { Zerotorescue@0: order = 0, Zerotorescue@0: type = "input", Zerotorescue@0: name = function(info) Zerotorescue@0: local itemName, _, itemRarity = GetItemInfo(info[#info]); Zerotorescue@0: return tostring( 7 - (itemRarity or 0) ) .. (itemName or ""); Zerotorescue@0: end, Zerotorescue@0: get = function(info) Zerotorescue@0: return tostring(info[#info]); -- Ace is going to be anal about this if it's a numeric value, so we transmute it into a string here then back to a number on the other side Zerotorescue@0: end, Zerotorescue@1: set = function(groupId, itemId) Zerotorescue@0: -- This is NOT a real "set", we pass the widget reference to this function which contains similar, but not the same, info. Zerotorescue@0: Zerotorescue@1: if itemId then Zerotorescue@1: local groupName = groupIdToName[groupId]; Zerotorescue@0: Zerotorescue@0: -- Unset this item Zerotorescue@1: addon.db.global.groups[groupName].items[itemId] = nil; Zerotorescue@0: Zerotorescue@0: -- Now rebuild the list Zerotorescue@11: AceConfigRegistry:NotifyChange("InventoriumOptions"); Zerotorescue@0: end Zerotorescue@0: end, Zerotorescue@0: width = "double", Zerotorescue@1: dialogControl = "ConfigItemLinkButton", Zerotorescue@0: }; Zerotorescue@0: Zerotorescue@0: local function UpdateAddItemList(info) Zerotorescue@0: local groupName = groupIdToName[info[2]]; Zerotorescue@0: Zerotorescue@0: if not addon.db.global.groups[groupName].items then Zerotorescue@0: addon.db.global.groups[groupName].items = {}; Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: -- Merge all items from all groups together Zerotorescue@0: local items = {}; Zerotorescue@0: for groupName, values in pairs(addon.db.global.groups) do Zerotorescue@0: if values.items then Zerotorescue@0: for itemId, _ in pairs(values.items) do Zerotorescue@0: items[itemId] = true; Zerotorescue@0: end Zerotorescue@0: end Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: local ref = options.args.groups.args[info[2]].args.add.args.list.args; Zerotorescue@0: Zerotorescue@13: -- Remaking the list, so out with the old, in with the new Zerotorescue@13: table.wipe(ref); Zerotorescue@13: Zerotorescue@0: -- Parse bags and show these Zerotorescue@0: for bagID = 4, 0, -1 do Zerotorescue@0: for slot = 1, GetContainerNumSlots(bagID) do Zerotorescue@0: local itemId = addon:GetItemId(GetContainerItemLink(bagID, slot)); Zerotorescue@0: Zerotorescue@0: if itemId then Zerotorescue@0: if not items[itemId] then Zerotorescue@0: -- If this item isn't used in any group yet Zerotorescue@0: ref[itemId] = tblAddItemTemplate; Zerotorescue@0: else Zerotorescue@0: -- It's already used in a group, don't show it Zerotorescue@0: ref[itemId] = nil; Zerotorescue@0: end Zerotorescue@0: end Zerotorescue@0: end Zerotorescue@0: end Zerotorescue@13: Zerotorescue@13: if includeTradeSkillItems ~= 500 then Zerotorescue@13: -- Include tradeskill items Zerotorescue@13: Zerotorescue@13: -- Go through all trade skills for the profession Zerotorescue@13: for i = 1, GetNumTradeSkills() do Zerotorescue@13: -- Try to retrieve the itemlink, this will be nil if current item is a group instead Zerotorescue@13: local itemLink = GetTradeSkillItemLink(i); Zerotorescue@13: Zerotorescue@13: if itemLink then Zerotorescue@13: local itemId = addon:GetItemId(itemLink); Zerotorescue@13: if not itemId then Zerotorescue@13: -- If this isn't an item, it can only be an enchant instead Zerotorescue@13: itemId = tonumber(itemLink:match("|Henchant:([-0-9]+)|h")); Zerotorescue@13: Zerotorescue@17: itemId = addon.scrollIds[itemId]; -- change enchantIds into scrollIds Zerotorescue@13: end Zerotorescue@13: Zerotorescue@17: if itemId then Zerotorescue@17: local itemLevel = select(4, GetItemInfo(itemId)) or 0; Zerotorescue@17: Zerotorescue@17: if includeTradeSkillItems == 0 or itemLevel >= includeTradeSkillItems then Zerotorescue@17: if not items[itemId] then Zerotorescue@17: -- If this item isn't used in any group yet Zerotorescue@17: ref[itemId] = tblAddItemTemplate; Zerotorescue@17: else Zerotorescue@17: -- It's already used in a group, don't show it Zerotorescue@17: ref[itemId] = nil; Zerotorescue@17: end Zerotorescue@13: end Zerotorescue@17: else Zerotorescue@17: addon:Debug("|cffff0000ERROR|r: Couldn't find proper item id for " .. itemLink); Zerotorescue@13: end Zerotorescue@13: end Zerotorescue@13: end Zerotorescue@13: end Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: local function UpdateRemoveItemList(info) Zerotorescue@0: local groupName = groupIdToName[info[2]]; Zerotorescue@0: Zerotorescue@0: if not addon.db.global.groups[groupName].items then Zerotorescue@0: addon.db.global.groups[groupName].items = {}; Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: local ref = options.args.groups.args[info[2]].args.remove.args.list.args; Zerotorescue@0: Zerotorescue@0: -- Unset all Zerotorescue@0: for itemId, _ in pairs(ref) do Zerotorescue@0: ref[itemId] = nil; Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: -- Parse items in group and show these Zerotorescue@0: for itemId, _ in pairs(addon.db.global.groups[groupName].items) do Zerotorescue@0: ref[itemId] = tblRemoveItemTemplate; Zerotorescue@0: end Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: function addon:GetItemId(itemLink) Zerotorescue@13: itemLink = itemLink and itemLink:match("|Hitem:([-0-9]+):"); -- if itemLink is nil, it won't execute the second part Zerotorescue@0: itemLink = itemLink and tonumber(itemLink); Zerotorescue@0: Zerotorescue@0: return itemLink; Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: -- Default group Zerotorescue@0: local defaultGroup = { Zerotorescue@0: order = 0, Zerotorescue@0: type = "group", Zerotorescue@0: childGroups = "tab", Zerotorescue@0: name = function(info) Zerotorescue@30: local groupId = info[#info]; Zerotorescue@30: if groupIsVirtual[groupId] then Zerotorescue@30: return ("%s |cfffed000Virtual|r"):format(groupIdToName[groupId]); Zerotorescue@30: else Zerotorescue@30: return groupIdToName[groupId]; Zerotorescue@30: end Zerotorescue@30: end, Zerotorescue@30: desc = function(info) Zerotorescue@30: local groupId = info[#info]; Zerotorescue@30: if groupIsVirtual[groupId] then Zerotorescue@30: return "This is a virtual group, you can use it to override the defaults for other groups."; Zerotorescue@30: end Zerotorescue@0: end, Zerotorescue@0: args = { Zerotorescue@0: general = { Zerotorescue@0: order = 10, Zerotorescue@0: type = "group", Zerotorescue@23: name = "General", Zerotorescue@23: desc = "Change the general settings for just this group.", Zerotorescue@0: args = { Zerotorescue@23: general = { Zerotorescue@23: order = 0, Zerotorescue@23: type = "group", Zerotorescue@23: inline = true, Zerotorescue@23: name = "General", Zerotorescue@23: set = SetOption, Zerotorescue@23: get = GetOption, Zerotorescue@23: disabled = GetDisabled, Zerotorescue@23: args = { Zerotorescue@23: description = { Zerotorescue@23: order = 0, Zerotorescue@23: type = "description", Zerotorescue@35: name = function(info) Zerotorescue@35: local groupName = groupIdToName[info[2]]; Zerotorescue@35: Zerotorescue@35: local t = "Here you can set general settings for the currently selected group. If you do not wish to override a setting, the default setting specified in the general group will be used.\n\n"; Zerotorescue@35: Zerotorescue@35: local currentAddon, selectedAddonName = addon:GetItemCountAddon(groupName); Zerotorescue@35: Zerotorescue@35: if currentAddon then Zerotorescue@35: --GetCharacterCount Zerotorescue@35: --self.supportedAddons.itemCount[selectedExternalAddon] Zerotorescue@35: t = t .. "Currently using |cfffed000" .. selectedAddonName .. "|r as your item count addon. This addon is " .. ((currentAddon.IsEnabled() and "|cff00ff00enabled|r") or "|cffff0000disabled|r") .. "."; Zerotorescue@35: Zerotorescue@35: if currentAddon.GetTotalCount and currentAddon.GetCharacterCount then Zerotorescue@35: t = t .. " This addon supports |cfffed000both total as local|r item counts."; Zerotorescue@35: elseif currentAddon.GetTotalCount then Zerotorescue@35: t = t .. " This addon supports |cfffed000only total|r item counts."; Zerotorescue@35: elseif currentAddon.GetCharacterCount then Zerotorescue@35: t = t .. " This addon supports |cfffed000only local|r item counts."; Zerotorescue@35: end Zerotorescue@35: end Zerotorescue@35: Zerotorescue@35: return t; Zerotorescue@35: end, Zerotorescue@23: }, Zerotorescue@23: header = { Zerotorescue@23: order = 5, Zerotorescue@23: type = "header", Zerotorescue@23: name = "", Zerotorescue@23: }, Zerotorescue@23: overrideAuctionPricingAddon = { Zerotorescue@23: order = 9, Zerotorescue@23: type = "toggle", Zerotorescue@23: name = "Override pricing addon", Zerotorescue@23: desc = "Allows you to override the pricing addon setting for this group.", Zerotorescue@23: arg = "auctionPricingAddon", Zerotorescue@23: }, Zerotorescue@23: auctionPricingAddon = { Zerotorescue@23: order = 10, Zerotorescue@23: type = "select", Zerotorescue@23: name = "Prefered pricing addon", Zerotorescue@23: desc = "Select the addon you prefer data for this group to be retrieved from. A random supported addon will be used if the selected addon can not be found.", Zerotorescue@23: values = function() Zerotorescue@23: local temp = {}; Zerotorescue@23: for name, value in pairs(addon.supportedAddons.auctionPricing) do Zerotorescue@23: temp[name] = name; Zerotorescue@23: end Zerotorescue@23: Zerotorescue@23: return temp; Zerotorescue@23: end, Zerotorescue@36: set = function(info, value) Zerotorescue@36: local groupName = groupIdToName[info[2]]; Zerotorescue@36: local optionName = info[#info]; Zerotorescue@36: Zerotorescue@36: addon.db.global.groups[groupName][optionName] = value ~= "" and value; Zerotorescue@36: Zerotorescue@36: if addon.supportedAddons.auctionPricing[value].OnSelect then Zerotorescue@36: addon.supportedAddons.auctionPricing[value].OnSelect(); Zerotorescue@36: end Zerotorescue@36: end, Zerotorescue@23: arg = "overrideAuctionPricingAddon", Zerotorescue@23: }, Zerotorescue@23: overrideItemCountAddon = { Zerotorescue@23: order = 19, Zerotorescue@23: type = "toggle", Zerotorescue@23: name = "Override item count addon", Zerotorescue@23: desc = "Allows you to override the item count addon setting for this group.", Zerotorescue@23: arg = "itemCountAddon", Zerotorescue@23: }, Zerotorescue@23: itemCountAddon = { Zerotorescue@23: order = 20, Zerotorescue@23: type = "select", Zerotorescue@23: name = "Prefered item count addon", Zerotorescue@23: desc = "Select the addon you prefer data for this group to be retrieved from. A random supported addon will be used if the selected addon can not be found.", Zerotorescue@23: values = function() Zerotorescue@23: local temp = {}; Zerotorescue@23: for name, value in pairs(addon.supportedAddons.itemCount) do Zerotorescue@23: temp[name] = name; Zerotorescue@23: end Zerotorescue@23: Zerotorescue@23: return temp; Zerotorescue@23: end, Zerotorescue@23: arg = "overrideItemCountAddon", Zerotorescue@23: }, Zerotorescue@23: overrideCraftingAddon = { Zerotorescue@23: order = 29, Zerotorescue@23: type = "toggle", Zerotorescue@23: name = "Override crafting addon", Zerotorescue@23: desc = "Allows you to override the crafting addon setting for this group.", Zerotorescue@23: arg = "craftingAddon", Zerotorescue@23: }, Zerotorescue@23: craftingAddon = { Zerotorescue@23: order = 30, Zerotorescue@23: type = "select", Zerotorescue@23: name = "Prefered crafting addon", Zerotorescue@23: desc = "Select the addon you prefer data from this group to be queued into. A random supported addon will be used if the selected addon can not be found.", Zerotorescue@23: values = function() Zerotorescue@23: local temp = {}; Zerotorescue@23: for name, value in pairs(addon.supportedAddons.crafting) do Zerotorescue@23: temp[name] = name; Zerotorescue@23: end Zerotorescue@23: Zerotorescue@23: return temp; Zerotorescue@23: end, Zerotorescue@23: arg = "overrideCraftingAddon", Zerotorescue@23: }, Zerotorescue@36: --[[overrideLocalItemData = { Zerotorescue@31: order = 39, Zerotorescue@31: type = "toggle", Zerotorescue@31: name = "Override local item data", Zerotorescue@31: desc = "Allows you to override the local item data setting for this group.", Zerotorescue@31: arg = "localItemData", Zerotorescue@31: }, Zerotorescue@31: localItemData = { Zerotorescue@31: order = 40, Zerotorescue@31: type = "multiselect", Zerotorescue@31: name = "Include in local item data", Zerotorescue@31: desc = "Select which data should be included in the local item data.", Zerotorescue@31: values = { Zerotorescue@31: ["Bag"] = "Bag", Zerotorescue@31: ["Bank"] = "Bank", Zerotorescue@31: ["Auction House"] = "Auction House", Zerotorescue@31: ["Mailbox"] = "Mailbox", Zerotorescue@31: }, Zerotorescue@31: get = GetMultiOption, Zerotorescue@31: --dialogControl = "Dropdown", -- this is not standard, normal multiselect control gives us a list of all chars with toggle-boxes. UGLY! We want a multiselect-box instead. Zerotorescue@31: arg = "overrideLocalItemData", Zerotorescue@36: },]] Zerotorescue@30: virtualGroup = { Zerotorescue@31: order = 50, Zerotorescue@30: type = "select", Zerotorescue@30: name = "Use virtual group settings", Zerotorescue@30: desc = "Use the settings from a virtual group before using the general defaults.\n\n|cffff9933This is an advanced option, you will probably not need it unless you manage a lot of groups.|r\n\n|cfffed000Off|r: Use the overridden options in this group and then the defaults.\n\n|cfffed000On|r: Use the overridden options in this group, then the ones in the selected virtual group and then the defaults.", Zerotorescue@31: values = function(info) Zerotorescue@31: local groupName = groupIdToName[info[2]]; Zerotorescue@31: Zerotorescue@30: local temp = {}; Zerotorescue@30: Zerotorescue@30: temp[""] = ""; Zerotorescue@31: for name, values in pairs(addon.db.global.groups) do Zerotorescue@31: if values.isVirtual and name ~= groupName then Zerotorescue@31: temp[name] = name; Zerotorescue@31: end Zerotorescue@31: end Zerotorescue@30: Zerotorescue@30: return temp; Zerotorescue@30: end, Zerotorescue@31: set = function(info, value) Zerotorescue@31: local groupName = groupIdToName[info[2]]; Zerotorescue@31: local optionName = info[#info]; Zerotorescue@31: Zerotorescue@31: addon.db.global.groups[groupName][optionName] = value ~= "" and value; Zerotorescue@31: end, Zerotorescue@35: disabled = false, Zerotorescue@30: }, Zerotorescue@23: }, Zerotorescue@23: }, Zerotorescue@0: minimumStock = { Zerotorescue@0: order = 10, Zerotorescue@0: type = "group", Zerotorescue@0: inline = true, Zerotorescue@0: name = "Minimum stock", Zerotorescue@0: set = SetOption, Zerotorescue@0: get = GetOption, Zerotorescue@0: disabled = GetDisabled, Zerotorescue@0: args = { Zerotorescue@0: description = { Zerotorescue@0: order = 0, Zerotorescue@0: type = "description", Zerotorescue@31: name = "Here you can specify the minimum amount of items you wish to keep in stock and related settings for the currently selected group. Please note the values entered here do not affect the queued quantities, you must set settings for that in the area below.", Zerotorescue@0: }, Zerotorescue@0: header = { Zerotorescue@0: order = 5, Zerotorescue@0: type = "header", Zerotorescue@0: name = "", Zerotorescue@0: }, Zerotorescue@0: overrideMinimumStock = { Zerotorescue@0: order = 9, Zerotorescue@0: type = "toggle", Zerotorescue@0: name = "Override min stock", Zerotorescue@0: desc = "Allows you to override the minimum stock setting for this group.", Zerotorescue@0: arg = "minimumStock", Zerotorescue@0: }, Zerotorescue@0: minimumStock = { Zerotorescue@0: order = 10, Zerotorescue@0: type = "range", Zerotorescue@0: min = 0, Zerotorescue@0: max = 100000, Zerotorescue@17: softMax = 100, Zerotorescue@0: step = 1, Zerotorescue@0: name = "Minimum stock", Zerotorescue@17: desc = "You can manually enter a value between 100 and 100.000 in the text box below if the provided range is insufficient.", Zerotorescue@0: arg = "overrideMinimumStock", Zerotorescue@0: }, Zerotorescue@0: overrideSummaryThresholdShow = { Zerotorescue@0: order = 19, Zerotorescue@0: type = "toggle", Zerotorescue@0: name = "Override summary showing", Zerotorescue@0: desc = "Allows you to override when this group should appear in the summary.", Zerotorescue@0: arg = "summaryThresholdShow", Zerotorescue@0: }, Zerotorescue@0: summaryThresholdShow = { Zerotorescue@0: order = 20, Zerotorescue@0: type = "range", Zerotorescue@0: min = 0, Zerotorescue@0: max = 100, Zerotorescue@0: softMax = 10, Zerotorescue@0: step = 0.05, Zerotorescue@0: isPercent = true, Zerotorescue@0: name = "Show in summary when below", Zerotorescue@0: desc = "Show items in the summary when below the specified percentage of the minimum stock.\n\nYou can manually enter a value between 1.000% and 10.000% in the edit box if the provided range is insufficient.", Zerotorescue@0: arg = "overrideSummaryThresholdShow", Zerotorescue@0: }, Zerotorescue@0: overrideAlertBelowMinimum = { Zerotorescue@0: order = 29, Zerotorescue@0: type = "toggle", Zerotorescue@0: name = "Override minimum alert", Zerotorescue@0: desc = "Allows you to override wether an alert should be shown when an item in this group gets below the minimum stock threshold.", Zerotorescue@0: arg = "alertBelowMinimum", Zerotorescue@0: }, Zerotorescue@0: alertBelowMinimum = { Zerotorescue@0: order = 30, Zerotorescue@0: type = "toggle", Zerotorescue@30: name = "NYI | Alert when below minimum", Zerotorescue@0: desc = "Show an alert when an item in this group gets below the minimum stock threshold.", Zerotorescue@0: arg = "overrideAlertBelowMinimum", Zerotorescue@0: }, Zerotorescue@1: overrideTrackAtCharacters = { Zerotorescue@1: order = 39, Zerotorescue@1: type = "toggle", Zerotorescue@1: name = "Override track at", Zerotorescue@1: desc = "Allows you to override at which characters items in this group should appear in the summary and generate alerts.", Zerotorescue@1: arg = "trackAtCharacters", Zerotorescue@1: }, Zerotorescue@1: trackAtCharacters = { Zerotorescue@1: order = 40, Zerotorescue@1: type = "multiselect", Zerotorescue@1: name = "Track at", Zerotorescue@1: desc = "Select at which characters this should appear in the summary and generate alerts.", Zerotorescue@1: values = function() Zerotorescue@1: local temp = {}; Zerotorescue@1: for charName in pairs(addon.db.factionrealm.characters) do Zerotorescue@1: temp[charName] = charName; Zerotorescue@1: end Zerotorescue@1: Zerotorescue@1: return temp; Zerotorescue@1: end, Zerotorescue@1: get = GetMultiOption, Zerotorescue@13: --dialogControl = "Dropdown", -- this is not standard, normal multiselect control gives us a list of all chars with toggle-boxes. UGLY! We want a multiselect-box instead. Zerotorescue@1: arg = "overrideTrackAtCharacters", Zerotorescue@1: }, Zerotorescue@0: }, Zerotorescue@0: }, Zerotorescue@0: refill = { Zerotorescue@0: order = 20, Zerotorescue@0: type = "group", Zerotorescue@0: inline = true, Zerotorescue@0: name = "Replenishing stock", Zerotorescue@0: set = SetOption, Zerotorescue@0: get = GetOption, Zerotorescue@0: disabled = GetDisabled, Zerotorescue@0: args = { Zerotorescue@0: description = { Zerotorescue@0: order = 0, Zerotorescue@0: type = "description", Zerotorescue@0: name = function(info) Zerotorescue@0: local groupName = groupIdToName[info[2]]; Zerotorescue@0: local r = "Here you can specify the amount of items to which you wish to restock when you are collecting new items for the currently selected group. This may be higher than the minimum stock.\n\n"; Zerotorescue@0: Zerotorescue@31: r = r .. "When restocking the target amount is |cfffed000" .. addon:GetOptionByKey(groupName, "restockTarget") .. "|r of every item. Not queueing craftable items when only missing |cfffed000" .. floor( addon:GetOptionByKey(groupName, "minCraftingQueue") * addon:GetOptionByKey(groupName, "restockTarget") ) .. "|r (|cfffed000" .. ( addon:GetOptionByKey(groupName, "minCraftingQueue") * 100 ) .. "%|r) of the restock target and making |cfffed000" .. floor( ( addon:GetOptionByKey(groupName, "bonusQueue") * addon:GetOptionByKey(groupName, "restockTarget") ) + .5 ) .. "|r (|cfffed000" .. ( addon:GetOptionByKey(groupName, "bonusQueue") * 100 ) .. "%|r) extra items when you completely ran out. "; Zerotorescue@31: Zerotorescue@31: if addon:GetOptionByKey(groupName, "priceThreshold") == 0 then Zerotorescue@31: r = r .. "Queueing items at |cfffed000any|r auction value."; Zerotorescue@31: else Zerotorescue@31: r = r .. "Queueing items worth |cfffed000" .. addon:ReadableMoney(addon:GetOptionByKey(groupName, "priceThreshold")) .. "|r or more."; Zerotorescue@31: end Zerotorescue@0: Zerotorescue@0: return r; Zerotorescue@0: end, Zerotorescue@0: }, Zerotorescue@0: header = { Zerotorescue@0: order = 5, Zerotorescue@0: type = "header", Zerotorescue@0: name = "", Zerotorescue@0: }, Zerotorescue@0: overrideRestockTarget = { Zerotorescue@0: order = 9, Zerotorescue@0: type = "toggle", Zerotorescue@0: name = "Override restock target", Zerotorescue@0: desc = "Allows you to override the restock target setting for this group.", Zerotorescue@0: arg = "restockTarget", Zerotorescue@0: }, Zerotorescue@0: restockTarget = { Zerotorescue@0: order = 10, Zerotorescue@0: type = "range", Zerotorescue@0: min = 0, Zerotorescue@0: max = 100000, Zerotorescue@30: softMax = 100, Zerotorescue@0: step = 1, Zerotorescue@0: name = "Restock target", Zerotorescue@30: desc = "You can manually enter a value between 100 and 100.000 in the edit box if the provided range is insufficient.", Zerotorescue@0: arg = "overrideRestockTarget", Zerotorescue@0: }, Zerotorescue@0: overrideMinCraftingQueue = { Zerotorescue@0: order = 19, Zerotorescue@0: type = "toggle", Zerotorescue@0: name = "Override min queue", Zerotorescue@0: desc = "Allows you to override the minimum craftable items queue setting for this group.", Zerotorescue@0: arg = "minCraftingQueue", Zerotorescue@0: }, Zerotorescue@0: minCraftingQueue = { Zerotorescue@0: order = 20, Zerotorescue@0: type = "range", Zerotorescue@0: min = 0, Zerotorescue@0: max = 1, Zerotorescue@0: step = 0.01, Zerotorescue@0: isPercent = true, Zerotorescue@0: name = "Don't queue if I only miss", Zerotorescue@0: desc = "Don't add a craftable item to the queue if I only miss this much or less of the restock target.\n\nExample: if your restock target is set to 60 and this is set to 5%, an item won't be queued unless you are missing more than 3 of it.", Zerotorescue@0: arg = "overrideMinCraftingQueue", Zerotorescue@0: }, Zerotorescue@1: overrideBonusQueue = { Zerotorescue@1: order = 29, Zerotorescue@1: type = "toggle", Zerotorescue@1: name = "Override bonus queue", Zerotorescue@1: desc = "Allows you to override the bonus craftable items queue setting for this group.", Zerotorescue@1: arg = "bonusQueue", Zerotorescue@1: }, Zerotorescue@1: bonusQueue = { Zerotorescue@1: order = 30, Zerotorescue@1: type = "range", Zerotorescue@1: min = 0, Zerotorescue@1: max = 10, -- 1000% Zerotorescue@1: step = 0.01, -- 1% Zerotorescue@1: isPercent = true, Zerotorescue@1: name = "Bonus queue", Zerotorescue@1: desc = "Get additional items when there are none left.\n\nExample: if your restock target is set to 60 and this is set to 10%, you will get 66 items instead of just 60 if you end up with none left while queueing.", Zerotorescue@1: arg = "overrideBonusQueue", Zerotorescue@1: }, Zerotorescue@1: overridePriceThreshold = { Zerotorescue@1: order = 39, Zerotorescue@1: type = "toggle", Zerotorescue@1: name = "Override price threshold", Zerotorescue@1: desc = "Allows you to override the price threshold setting for this group.", Zerotorescue@1: arg = "priceThreshold", Zerotorescue@1: }, Zerotorescue@1: priceThreshold = { Zerotorescue@1: order = 40, Zerotorescue@1: type = "input", Zerotorescue@1: name = "Price threshold", Zerotorescue@1: desc = "Only queue craftable items when they are worth at least this much according to your auction house addon.\n\nSet to 0 to ignore auction prices.", Zerotorescue@1: validate = function(info, value) return addon:ValidateReadableMoney(info, value); end, Zerotorescue@1: get = function(i) return addon:ReadableMoney(GetOption(i)); end, Zerotorescue@1: set = function(i, v) SetOption(i, addon:ReadableMoneyToCopper(v)); end, Zerotorescue@1: arg = "overridePriceThreshold", Zerotorescue@1: }, Zerotorescue@13: overrideSummaryHidePriceThreshold = { Zerotorescue@1: order = 49, Zerotorescue@1: type = "toggle", Zerotorescue@1: name = "Override summary showing", Zerotorescue@1: desc = "Allows you to override if items in this group should be hidden from the summary while their value is below the price threshold.", Zerotorescue@13: arg = "summaryHidePriceThreshold", Zerotorescue@1: }, Zerotorescue@13: summaryHidePriceThreshold = { Zerotorescue@1: order = 50, Zerotorescue@1: type = "toggle", Zerotorescue@1: name = "Hide when below threshold", Zerotorescue@1: desc = "Hide items from the summary when their value is below the set price threshold.", Zerotorescue@13: arg = "overrideSummaryHidePriceThreshold", Zerotorescue@1: }, Zerotorescue@23: overrideAlwaysGetAuctionValue = { Zerotorescue@23: order = 59, Zerotorescue@23: type = "toggle", Zerotorescue@23: name = "Override auction value showing", Zerotorescue@31: desc = "Allows you to override if the auction value of items in this group should be cached and displayed even when the price threshold is set to 0|cffeda55fc|r.", Zerotorescue@23: arg = "alwaysGetAuctionValue", Zerotorescue@23: }, Zerotorescue@23: alwaysGetAuctionValue = { Zerotorescue@23: order = 60, Zerotorescue@23: type = "toggle", Zerotorescue@23: name = "Always show auction value", Zerotorescue@31: desc = "Always cache and show the auction value of items in this group, even if the price threshold is set to 0|cffeda55fc|r.", Zerotorescue@23: arg = "overrideAlwaysGetAuctionValue", Zerotorescue@23: }, Zerotorescue@0: }, Zerotorescue@0: }, Zerotorescue@0: }, Zerotorescue@0: }, Zerotorescue@0: group = { Zerotorescue@0: order = 20, Zerotorescue@0: type = "group", Zerotorescue@23: name = "Management", Zerotorescue@23: desc = "Rename, delete, duplicate or export this group.", Zerotorescue@0: args = { Zerotorescue@10: actions = { Zerotorescue@0: order = 10, Zerotorescue@0: type = "group", Zerotorescue@10: name = "Actions", Zerotorescue@0: inline = true, Zerotorescue@0: args = { Zerotorescue@0: rename = { Zerotorescue@0: order = 10, Zerotorescue@0: type = "input", Zerotorescue@10: name = "Rename group - New name", Zerotorescue@0: desc = "Change the name of this group to something else. You can also use item links here as you wish.", Zerotorescue@0: validate = ValidateGroupName, Zerotorescue@0: set = function(info, value) Zerotorescue@0: local oldGroupName = groupIdToName[info[2]]; Zerotorescue@0: Zerotorescue@0: addon.db.global.groups[value] = CopyTable(addon.db.global.groups[oldGroupName]); Zerotorescue@0: addon.db.global.groups[oldGroupName] = nil; Zerotorescue@0: Zerotorescue@0: groupIdToName[info[2]] = value; Zerotorescue@0: groupIdToName[value] = true; Zerotorescue@0: groupIdToName[oldGroupName] = nil; Zerotorescue@0: Zerotorescue@0: addon:FillGroupOptions(); Zerotorescue@0: end, Zerotorescue@0: get = function(info) Zerotorescue@0: return groupIdToName[info[2]]; Zerotorescue@0: end, Zerotorescue@0: }, Zerotorescue@10: duplicate = { Zerotorescue@10: order = 20, Zerotorescue@10: type = "input", Zerotorescue@10: name = "Duplicate group - New name", Zerotorescue@10: desc = "Duplicate this group. You can also use item links here as you wish.\n\nAll item data will be erased.", Zerotorescue@10: validate = ValidateGroupName, Zerotorescue@10: set = function(info, value) Zerotorescue@10: local oldGroupName = groupIdToName[info[2]]; Zerotorescue@10: Zerotorescue@10: addon.db.global.groups[value] = CopyTable(addon.db.global.groups[oldGroupName]); Zerotorescue@10: Zerotorescue@10: -- Reset item data (duplicate items me no want) Zerotorescue@10: addon.db.global.groups[value].items = nil; Zerotorescue@10: Zerotorescue@10: addon:FillGroupOptions(); Zerotorescue@10: end, Zerotorescue@10: get = false, Zerotorescue@10: }, Zerotorescue@0: delete = { Zerotorescue@10: order = 30, Zerotorescue@0: type = "execute", Zerotorescue@0: name = "Delete group", Zerotorescue@0: desc = "Delete the currently selected group.", Zerotorescue@0: confirm = true, Zerotorescue@0: confirmText = "Are you sure you wish to |cffff0000DELETE|r this group? This action is not reversable!", Zerotorescue@0: func = function(info) Zerotorescue@0: local groupName = groupIdToName[info[2]]; Zerotorescue@0: Zerotorescue@0: addon.db.global.groups[groupName] = nil; Zerotorescue@0: Zerotorescue@0: addon:FillGroupOptions(); Zerotorescue@0: end, Zerotorescue@0: }, Zerotorescue@0: }, Zerotorescue@0: }, Zerotorescue@0: export = { Zerotorescue@10: order = 40, Zerotorescue@0: type = "group", Zerotorescue@0: name = "Export", Zerotorescue@0: inline = true, Zerotorescue@0: args = { Zerotorescue@0: input = { Zerotorescue@0: order = 10, Zerotorescue@0: type = "input", Zerotorescue@0: multiline = true, Zerotorescue@0: name = "Group data", Zerotorescue@0: width = "full", Zerotorescue@0: desc = "Export the group data for the currently selected group. Press CTRL-A to select all and CTRL-C to copy the text.", Zerotorescue@0: set = false, Zerotorescue@0: get = function(info) Zerotorescue@0: local groupName = groupIdToName[info[2]]; Zerotorescue@0: Zerotorescue@0: -- We want to include the group name, so we copy the table then set another value Zerotorescue@0: local temp = CopyTable(addon.db.global.groups[groupName]); Zerotorescue@0: temp.name = groupName; Zerotorescue@9: temp.trackAtCharacters = nil; Zerotorescue@9: temp.overrideTrackAtCharacters = nil; Zerotorescue@0: Zerotorescue@0: if not AceSerializer then Zerotorescue@0: AceSerializer = LibStub("AceSerializer-3.0"); Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: return AceSerializer:Serialize(temp); Zerotorescue@0: end, Zerotorescue@0: }, Zerotorescue@0: }, Zerotorescue@0: }, Zerotorescue@0: }, Zerotorescue@0: }, Zerotorescue@0: add = { Zerotorescue@0: order = 30, Zerotorescue@0: type = "group", Zerotorescue@0: name = "Add items", Zerotorescue@23: desc = "Add new items to this group.", Zerotorescue@31: hidden = function(info) return groupIsVirtual[info[2]]; end, Zerotorescue@0: args = { Zerotorescue@0: singleAdd = { Zerotorescue@0: order = 10, Zerotorescue@0: type = "group", Zerotorescue@0: inline = true, Zerotorescue@0: name = "Add items", Zerotorescue@0: args = { Zerotorescue@0: help = { Zerotorescue@0: order = 10, Zerotorescue@0: type = "description", Zerotorescue@0: name = "You can add a single item to this group at a time by pasting the item-id or an item-link in the field to the left or you can also import multiple items at once by pasting exported item data in the field to the right. Scroll further down to add items based on your inventory contents.", Zerotorescue@0: }, Zerotorescue@0: itemLink = { Zerotorescue@0: order = 20, Zerotorescue@0: type = "input", Zerotorescue@0: name = "Single item add (item-link or item-id)", Zerotorescue@0: desc = "Shift-click an item-link or enter an item-id to add the related item to this group. You can only add one item link or item id at a time.", Zerotorescue@0: validate = function(info, value) Zerotorescue@0: -- If the value is empty we'll allow passing to clear the carret Zerotorescue@0: if value == "" then return true; end Zerotorescue@0: Zerotorescue@0: local groupName = groupIdToName[info[2]]; Zerotorescue@0: Zerotorescue@0: local itemId = addon:GetItemId(string.trim(value or "")) or tonumber(string.trim(value or "")); Zerotorescue@0: Zerotorescue@0: if not itemId then Zerotorescue@0: return "This is not a valid item link."; Zerotorescue@0: elseif InGroup(itemId) then Zerotorescue@0: return ("This item is already in the group \"%s\"."):format(InGroup(itemId)); Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: return true; Zerotorescue@0: end, Zerotorescue@0: set = function(info, value) Zerotorescue@0: if value and value ~= "" then Zerotorescue@0: local groupName = groupIdToName[info[2]]; Zerotorescue@0: Zerotorescue@0: local itemId = addon:GetItemId(string.trim(value or "")) or tonumber(string.trim(value or "")); Zerotorescue@0: Zerotorescue@0: AddToGroup(groupName, itemId); Zerotorescue@0: Zerotorescue@0: print(("Added %s"):format(select(2, GetItemInfo(itemId)) or ("Unknown (#%d)"):format(itemId))); Zerotorescue@0: end Zerotorescue@0: end, Zerotorescue@0: get = false, Zerotorescue@0: }, Zerotorescue@17: importItemData = { Zerotorescue@17: order = 30, Zerotorescue@0: type = "input", Zerotorescue@0: name = "Import item data", Zerotorescue@0: desc = "Import item data from an exported item data-string. Any items already grouped will be skipped.", Zerotorescue@0: set = function(info, value) Zerotorescue@0: local groupName = groupIdToName[info[2]]; Zerotorescue@0: Zerotorescue@0: local allItemIds = { string.split(";", value or "") }; Zerotorescue@0: Zerotorescue@0: for _, value in pairs(allItemIds) do Zerotorescue@0: local itemId = tonumber(value); Zerotorescue@0: Zerotorescue@0: if not itemId then Zerotorescue@0: print(("\"%s\" is not a number."):format(value)); Zerotorescue@0: elseif InGroup(itemId) then Zerotorescue@0: print(("Skipping %s (#%d) as it is already in the group |cfffed000%s|r."):format(select(2, GetItemInfo(itemId)) or "Unknown", itemId, InGroup(itemId))); Zerotorescue@0: else Zerotorescue@0: AddToGroup(groupName, itemId); Zerotorescue@0: end Zerotorescue@0: end Zerotorescue@0: end, Zerotorescue@0: get = false, Zerotorescue@0: }, Zerotorescue@17: importPremadeData = { Zerotorescue@17: order = 40, Zerotorescue@17: type = "select", Zerotorescue@17: name = "Import premade data", Zerotorescue@17: desc = "Import item data from a premade item-group. Any items already grouped will be skipped.", Zerotorescue@17: values = function() Zerotorescue@17: local temp = {}; Zerotorescue@17: for key, group in pairs(addon.defaultGroups) do Zerotorescue@17: temp[key] = key; Zerotorescue@17: end Zerotorescue@17: Zerotorescue@17: return temp; Zerotorescue@17: end, Zerotorescue@17: set = function(info, value) Zerotorescue@17: local groupName = groupIdToName[info[2]]; Zerotorescue@17: Zerotorescue@17: print(("Importing items from the premade group \"|cfffed000%s|r\"."):format(value)); Zerotorescue@17: Zerotorescue@17: -- Remember we imported this group and it's version so if it is ever changed, people can be notified Zerotorescue@17: if not addon.db.global.groups[groupName].premadeGroups then Zerotorescue@17: addon.db.global.groups[groupName].premadeGroups = {}; Zerotorescue@17: end Zerotorescue@17: addon.db.global.groups[groupName].premadeGroups[value] = addon.defaultGroups[value].version; Zerotorescue@17: Zerotorescue@17: for itemId, _ in pairs(addon.defaultGroups[value].items) do Zerotorescue@17: itemId = itemId and tonumber(itemId); Zerotorescue@17: Zerotorescue@17: if not itemId then Zerotorescue@17: print(("\"|cfffed000%s|r\" is not a number."):format(value)); Zerotorescue@17: elseif InGroup(itemId) then Zerotorescue@17: print(("Skipping |cfffed000%s|r (#%d) as it is already in the group |cfffed000%s|r."):format(select(2, GetItemInfo(itemId)) or "Unknown", itemId, InGroup(itemId))); Zerotorescue@17: else Zerotorescue@17: AddToGroup(groupName, itemId); Zerotorescue@17: end Zerotorescue@17: end Zerotorescue@17: end, Zerotorescue@17: get = false, Zerotorescue@17: }, Zerotorescue@0: }, Zerotorescue@0: }, Zerotorescue@0: massAdd = { Zerotorescue@0: order = 20, Zerotorescue@0: type = "group", Zerotorescue@0: inline = true, Zerotorescue@0: name = "Mass add", Zerotorescue@0: args = { Zerotorescue@0: help = { Zerotorescue@0: order = 10, Zerotorescue@0: type = "description", Zerotorescue@0: name = "Click the items you wish to add to this group or add multiple of these items at once by providing a name filter in the field below.", Zerotorescue@0: }, Zerotorescue@0: massAdd = { Zerotorescue@0: order = 20, Zerotorescue@0: type = "input", Zerotorescue@0: name = "Add all items matching...", Zerotorescue@0: desc = "Add every item in your inventory matching the name entered in this field. If you enter \"Glyph\" as a filter, any items in your inventory containing this in their name will be added to this group.", Zerotorescue@13: set = function(info, value) Zerotorescue@17: local groupName = groupIdToName[info[2]]; Zerotorescue@17: Zerotorescue@13: if not value then return; end Zerotorescue@13: Zerotorescue@13: value = value:lower(); Zerotorescue@13: Zerotorescue@13: local ref = options.args.groups.args[info[2]].args.add.args.list.args; Zerotorescue@13: Zerotorescue@13: for itemId, test in pairs(ref) do Zerotorescue@13: if test then Zerotorescue@13: local itemName = GetItemInfo(itemId); Zerotorescue@13: Zerotorescue@13: if itemName:lower():find(value) then Zerotorescue@13: if not AddToGroup(groupName, itemId) then Zerotorescue@13: print("|cffff0000Couldn't add the item with itemId (" .. itemId .. ") because it is already in a group.|r"); Zerotorescue@13: end Zerotorescue@13: end Zerotorescue@13: end Zerotorescue@13: end Zerotorescue@13: end, Zerotorescue@0: get = false, Zerotorescue@0: }, Zerotorescue@13: minItemLevel = { Zerotorescue@13: order = 40, Zerotorescue@13: type = "select", Zerotorescue@13: values = function() Zerotorescue@13: local temp = {}; Zerotorescue@13: Zerotorescue@13: temp[0] = "Include everything"; Zerotorescue@13: Zerotorescue@13: local itemLevelTemplate = "Itemlevel >= %d"; Zerotorescue@13: Zerotorescue@13: for i = 1, 49 do Zerotorescue@13: temp[( i * 10 )] = itemLevelTemplate:format(( i * 10 )); Zerotorescue@13: end Zerotorescue@13: Zerotorescue@13: temp[500] = "Include nothing"; Zerotorescue@13: Zerotorescue@13: return temp; Zerotorescue@13: end, Zerotorescue@13: name = "Include tradeskill items", Zerotorescue@13: desc = "Include all items above this item level from the currently opened tradeskill window in the below item list.\n\nSetting this very low this might considerably slow down this config window.\n\nSet to 500 to disable showing of items completely.", Zerotorescue@13: set = function(i, v) includeTradeSkillItems = v; end, Zerotorescue@13: get = function() return includeTradeSkillItems; end, Zerotorescue@13: disabled = function() Zerotorescue@13: if GetTradeSkillLine() == "UNKNOWN" then Zerotorescue@13: includeTradeSkillItems = 500; Zerotorescue@13: return true; -- disabled Zerotorescue@13: else Zerotorescue@13: return false; Zerotorescue@13: end Zerotorescue@13: end, Zerotorescue@13: }, Zerotorescue@0: }, Zerotorescue@0: }, Zerotorescue@0: list = { Zerotorescue@0: order = 30, Zerotorescue@0: type = "group", Zerotorescue@0: inline = true, Zerotorescue@0: name = "Item list", Zerotorescue@0: hidden = UpdateAddItemList, Zerotorescue@0: args = { Zerotorescue@0: Zerotorescue@0: }, Zerotorescue@0: }, Zerotorescue@0: }, Zerotorescue@0: }, Zerotorescue@0: remove = { Zerotorescue@0: order = 40, Zerotorescue@0: type = "group", Zerotorescue@0: name = "Current items", Zerotorescue@23: desc = "View, export or remove items from this group.", Zerotorescue@31: hidden = function(info) return groupIsVirtual[info[2]]; end, Zerotorescue@0: args = { Zerotorescue@0: help = { Zerotorescue@0: order = 10, Zerotorescue@0: type = "group", Zerotorescue@0: inline = true, Zerotorescue@0: name = "Help", Zerotorescue@0: hidden = false, Zerotorescue@0: args = { Zerotorescue@0: help = { Zerotorescue@0: order = 10, Zerotorescue@0: type = "description", Zerotorescue@0: name = "Click the items you wish to remove from this group.", Zerotorescue@0: }, Zerotorescue@17: massRemove = { Zerotorescue@17: order = 20, Zerotorescue@17: type = "input", Zerotorescue@17: name = "Remove all items matching...", Zerotorescue@17: desc = "Remove every item in this group matching the name entered in this field. If you enter \"Glyph\" as a filter, any items in this group containing this in their name will be removed from this group.", Zerotorescue@17: set = function(info, value) Zerotorescue@17: local groupName = groupIdToName[info[2]]; Zerotorescue@17: Zerotorescue@17: if not value then return; end Zerotorescue@17: Zerotorescue@17: value = value:lower(); Zerotorescue@17: Zerotorescue@17: local ref = options.args.groups.args[info[2]].args.remove.args.list.args; Zerotorescue@17: Zerotorescue@17: for itemId, test in pairs(ref) do Zerotorescue@17: if test then Zerotorescue@17: local itemName = GetItemInfo(itemId); Zerotorescue@17: Zerotorescue@17: if itemName:lower():find(value) then Zerotorescue@17: -- Unset this item Zerotorescue@17: addon.db.global.groups[groupName].items[itemId] = nil; Zerotorescue@17: end Zerotorescue@17: end Zerotorescue@17: end Zerotorescue@17: end, Zerotorescue@17: get = false, Zerotorescue@17: }, Zerotorescue@17: premadeGroups = { Zerotorescue@17: order = 30, Zerotorescue@17: type = "select", Zerotorescue@17: name = "Imported premade groups", Zerotorescue@23: desc = "This is a list of all premade groups that were imported into this group. You will be notified when any of these premade groups have changed and you will be able to import these changes.\n\nSelect a group to stop reminding you of changes to the premade group (the item list will be unaffected). Doing so will require you to manually update this when new items are added to the game.", Zerotorescue@17: values = function(info) Zerotorescue@17: local groupName = groupIdToName[info[2]]; Zerotorescue@17: Zerotorescue@17: local temp = {}; Zerotorescue@17: if addon.db.global.groups[groupName].premadeGroups then Zerotorescue@17: for name, version in pairs(addon.db.global.groups[groupName].premadeGroups) do Zerotorescue@17: temp[name] = name; Zerotorescue@17: end Zerotorescue@17: end Zerotorescue@17: Zerotorescue@17: return temp; Zerotorescue@17: end, Zerotorescue@17: set = function(info, value) Zerotorescue@17: -- Remove premade group from this group Zerotorescue@17: local groupName = groupIdToName[info[2]]; Zerotorescue@17: Zerotorescue@17: addon.db.global.groups[groupName].premadeGroups[value] = nil; Zerotorescue@17: Zerotorescue@17: print(("No longer notifying you about changes made to the premade group named \"|cfffed000%s|r\"."):format(value)); Zerotorescue@17: end, Zerotorescue@17: get = false, Zerotorescue@17: disabled = function(info) Zerotorescue@17: local groupName = groupIdToName[info[2]]; Zerotorescue@17: Zerotorescue@17: return (not addon.db.global.groups[groupName].premadeGroups); Zerotorescue@17: end, Zerotorescue@17: }, Zerotorescue@0: }, Zerotorescue@0: }, Zerotorescue@0: list = { Zerotorescue@0: order = 20, Zerotorescue@0: type = "group", Zerotorescue@0: inline = true, Zerotorescue@0: name = "Item list", Zerotorescue@0: hidden = UpdateRemoveItemList, Zerotorescue@0: args = { Zerotorescue@0: Zerotorescue@0: }, Zerotorescue@0: }, Zerotorescue@0: export = { Zerotorescue@0: order = 30, Zerotorescue@0: type = "group", Zerotorescue@0: name = "Export", Zerotorescue@0: inline = true, Zerotorescue@0: args = { Zerotorescue@0: input = { Zerotorescue@0: order = 10, Zerotorescue@0: type = "input", Zerotorescue@0: name = "Item data", Zerotorescue@0: width = "full", Zerotorescue@0: desc = "Export the item data for the currently selected group. Press CTRL-A to select all and CTRL-C to copy the text.", Zerotorescue@0: set = false, Zerotorescue@0: get = function(info) Zerotorescue@0: local groupName = groupIdToName[info[2]]; Zerotorescue@0: Zerotorescue@0: local combinedItemIds; Zerotorescue@0: -- Parse items in group and show these Zerotorescue@0: for itemId, _ in pairs(addon.db.global.groups[groupName].items) do Zerotorescue@0: if not combinedItemIds then Zerotorescue@0: combinedItemIds = tostring(itemId); Zerotorescue@0: else Zerotorescue@0: combinedItemIds = combinedItemIds .. (";%d"):format(itemId); Zerotorescue@0: end Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: return combinedItemIds; -- We don't serialize this because we actually DO want people to be able to manually modify it - besides, parsing it isn't going to be hard Zerotorescue@0: end, Zerotorescue@0: }, Zerotorescue@0: }, Zerotorescue@0: }, Zerotorescue@0: }, Zerotorescue@0: }, Zerotorescue@0: }, Zerotorescue@0: }; Zerotorescue@0: Zerotorescue@30: local currentGroupType = "Normal"; Zerotorescue@0: function addon:MakeGroupOptions() Zerotorescue@0: options.args.groups = { Zerotorescue@0: order = 1100, Zerotorescue@0: type = "group", Zerotorescue@0: name = "Groups", Zerotorescue@0: desc = "Change a group.", Zerotorescue@0: args = { Zerotorescue@0: create = { Zerotorescue@0: order = 10, Zerotorescue@0: type = "group", Zerotorescue@0: inline = true, Zerotorescue@0: name = "Create a brand new group", Zerotorescue@0: args = { Zerotorescue@0: name = { Zerotorescue@0: order = 10, Zerotorescue@0: type = "input", Zerotorescue@0: name = "Group name", Zerotorescue@0: desc = "The name of the group. You can also use item links as you wish.", Zerotorescue@0: validate = ValidateGroupName, Zerotorescue@0: set = function(_, value) Zerotorescue@0: self.db.global.groups[value] = {}; Zerotorescue@30: if currentGroupType == "Virtual" then Zerotorescue@30: self.db.global.groups[value].isVirtual = true; Zerotorescue@30: end Zerotorescue@30: Zerotorescue@0: addon:FillGroupOptions(); Zerotorescue@0: end, Zerotorescue@0: get = false, Zerotorescue@0: width = "double", Zerotorescue@0: }, Zerotorescue@30: type = { Zerotorescue@30: order = 20, Zerotorescue@30: type = "select", Zerotorescue@30: name = "Type (advanced)", Zerotorescue@30: desc = "The type of the new group. This can not be changed at a later time.\n\n|cffff9933This is an advanced option, you will probably not need it unless you manage a lot of groups.|r\n\n|cfffed000Normal|r: A normal group with complete functionality.\n\n|cfffed000Virtual|r: A virtual group which you can use to override the defaults for a set of groups. You can not add items to virtual groups.", Zerotorescue@30: values = { Zerotorescue@30: ["Normal"] = "Normal", Zerotorescue@30: ["Virtual"] = "Virtual", Zerotorescue@30: }, Zerotorescue@30: set = function(_, value) currentGroupType = value; end, Zerotorescue@30: get = function() return currentGroupType; end, Zerotorescue@30: }, Zerotorescue@0: }, Zerotorescue@0: }, Zerotorescue@0: import = { Zerotorescue@0: order = 20, Zerotorescue@0: type = "group", Zerotorescue@0: inline = true, Zerotorescue@0: name = "Import a group", Zerotorescue@0: args = { Zerotorescue@0: input = { Zerotorescue@0: order = 10, Zerotorescue@0: type = "input", Zerotorescue@0: multiline = true, Zerotorescue@0: name = "Group data", Zerotorescue@0: desc = "Paste the group data as provided by a group export. If you are trying to import multiple groups at the same time, make sure to use newlines to seperate them.", Zerotorescue@0: set = function(info, value) Zerotorescue@9: local data = { string.split("\n", value or "") }; Zerotorescue@0: Zerotorescue@9: for _, current in pairs(data) do Zerotorescue@0: if not AceSerializer then Zerotorescue@0: AceSerializer = LibStub("AceSerializer-3.0"); Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: local result, temp = AceSerializer:Deserialize(current); Zerotorescue@0: Zerotorescue@0: if not temp.name then Zerotorescue@0: print("|cffff0000The provided data is not supported.|r"); Zerotorescue@10: elseif ValidateGroupName(nil, temp.name) ~= true then Zerotorescue@10: print(("|cffff0000Aborting: A group named \"%s\" already exists.|r"):format(temp.name)); Zerotorescue@0: else Zerotorescue@10: local name = temp.name; Zerotorescue@0: temp.name = nil; Zerotorescue@9: print(("Importing %s..."):format(name)); Zerotorescue@10: Zerotorescue@10: -- Remove items that are already in another group Zerotorescue@10: for value, _ in pairs(temp.items) do Zerotorescue@17: local itemId = tonumber(value); Zerotorescue@10: Zerotorescue@10: if not itemId then Zerotorescue@10: print(("\"%s\" is not a number."):format(value)); Zerotorescue@10: temp.items[value] = nil; Zerotorescue@10: elseif InGroup(itemId) then Zerotorescue@10: print(("Skipping %s (#%d) as it is already in the group |cfffed000%s|r."):format(select(2, GetItemInfo(itemId)) or "Unknown", itemId, InGroup(itemId))); Zerotorescue@10: temp.items[value] = nil; Zerotorescue@10: else Zerotorescue@10: -- Ensure the keys are numeric Zerotorescue@10: temp.items[value] = nil; Zerotorescue@10: temp.items[itemId] = true; Zerotorescue@10: end Zerotorescue@10: end Zerotorescue@10: Zerotorescue@23: -- Ensure this data isn't received (this would be silly/buggy as exports from other accounts - with different characters - won't know what to do with this) Zerotorescue@10: temp.trackAtCharacters = nil; Zerotorescue@10: temp.overrideTrackAtCharacters = nil; Zerotorescue@10: Zerotorescue@10: self.db.global.groups[name] = temp; Zerotorescue@0: end Zerotorescue@0: end Zerotorescue@10: Zerotorescue@10: self:FillGroupOptions(); Zerotorescue@0: end, Zerotorescue@0: get = false, Zerotorescue@0: width = "full", Zerotorescue@0: }, Zerotorescue@0: }, Zerotorescue@0: }, Zerotorescue@0: }, Zerotorescue@0: }; Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: function addon:FillGroupOptions() Zerotorescue@0: for id, name in pairs(groupIdToName) do Zerotorescue@0: if type(name) == "string" and not self.db.global.groups[name] then Zerotorescue@0: options.args.groups.args[id] = nil; Zerotorescue@0: groupIdToName[id] = nil; Zerotorescue@0: groupIdToName[name] = nil; Zerotorescue@30: groupIsVirtual[id] = nil; Zerotorescue@0: end Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: for name, values in pairs(self.db.global.groups) do Zerotorescue@0: if not groupIdToName[name] then Zerotorescue@23: options.args.groups.args[tostring(count)] = defaultGroup; Zerotorescue@0: Zerotorescue@0: groupIdToName[tostring(count)] = name; Zerotorescue@0: groupIdToName[name] = true; Zerotorescue@30: if values.isVirtual then Zerotorescue@30: groupIsVirtual[tostring(count)] = true; Zerotorescue@30: end Zerotorescue@0: Zerotorescue@0: count = ( count + 1 ); Zerotorescue@0: end Zerotorescue@0: end Zerotorescue@0: end Zerotorescue@0: Zerotorescue@13: Zerotorescue@13: Zerotorescue@13: -- General functions used addon-wide Zerotorescue@13: Zerotorescue@35: function addon:GetItemCountAddon(group) Zerotorescue@35: local selectedExternalAddon = self:GetOptionByKey(group, "itemCountAddon"); Zerotorescue@35: Zerotorescue@35: if self.supportedAddons.itemCount[selectedExternalAddon] and self.supportedAddons.itemCount[selectedExternalAddon].IsEnabled() then Zerotorescue@35: -- Try to use the default item count addon Zerotorescue@35: Zerotorescue@35: return self.supportedAddons.itemCount[selectedExternalAddon], selectedExternalAddon; Zerotorescue@35: else Zerotorescue@35: -- Default not available, get the first one then Zerotorescue@35: Zerotorescue@35: for name, value in pairs(self.supportedAddons.itemCount) do Zerotorescue@35: if value.IsEnabled() then Zerotorescue@35: return value, name; Zerotorescue@35: end Zerotorescue@35: end Zerotorescue@35: end Zerotorescue@35: Zerotorescue@35: return; Zerotorescue@35: end Zerotorescue@35: Zerotorescue@23: function addon:GetItemCount(itemId, group) Zerotorescue@13: itemId = tonumber(itemId); Zerotorescue@13: Zerotorescue@13: if not itemId then return; end Zerotorescue@13: Zerotorescue@35: local itemCountAddon = self:GetItemCountAddon(group); Zerotorescue@23: Zerotorescue@35: return (itemCountAddon and itemCountAddon.GetTotalCount(itemId)) or -1; Zerotorescue@0: end Zerotorescue@0: Zerotorescue@23: function addon:GetAuctionValue(itemLink, group) Zerotorescue@23: if not itemLink then return -5; end Zerotorescue@13: Zerotorescue@23: local selectedExternalAddon = self:GetOptionByKey(group, "auctionPricingAddon"); Zerotorescue@23: Zerotorescue@23: if self.supportedAddons.auctionPricing[selectedExternalAddon] and self.supportedAddons.auctionPricing[selectedExternalAddon].IsEnabled() then Zerotorescue@13: -- Try to use the default auction pricing addon Zerotorescue@1: Zerotorescue@23: return self.supportedAddons.auctionPricing[selectedExternalAddon].GetValue(itemLink); Zerotorescue@13: else Zerotorescue@13: -- Default not available, get the first one then Zerotorescue@1: Zerotorescue@13: for name, value in pairs(self.supportedAddons.auctionPricing) do Zerotorescue@13: if value.IsEnabled() then Zerotorescue@13: return value.GetValue(itemLink); Zerotorescue@13: end Zerotorescue@1: end Zerotorescue@1: end Zerotorescue@7: Zerotorescue@7: return -2; Zerotorescue@1: end Zerotorescue@1: Zerotorescue@0: Zerotorescue@0: Zerotorescue@13: -- Public Zerotorescue@13: Zerotorescue@36: function IMRegisterPricingAddon(name, get, enabled, onSelect) Zerotorescue@13: addon.supportedAddons.auctionPricing[name] = { Zerotorescue@13: GetValue = get, Zerotorescue@13: IsEnabled = enabled, Zerotorescue@36: OnSelect = onSelect, Zerotorescue@13: }; Zerotorescue@13: end Zerotorescue@13: Zerotorescue@17: function IMRegisterItemCountAddon(name, getTotal, getCharacter, enabled) Zerotorescue@13: addon.supportedAddons.itemCount[name] = { Zerotorescue@17: GetTotalCount = getTotal, Zerotorescue@17: GetCharacterCount = getCharacter, Zerotorescue@13: IsEnabled = enabled, Zerotorescue@13: }; Zerotorescue@13: end Zerotorescue@13: Zerotorescue@13: function IMRegisterCraftingAddon(name, queue, enabled) Zerotorescue@13: addon.supportedAddons.crafting[name] = { Zerotorescue@13: Queue = queue, Zerotorescue@13: IsEnabled = enabled, Zerotorescue@13: }; Zerotorescue@13: end Zerotorescue@13: Zerotorescue@13: Zerotorescue@13: Zerotorescue@13: -- Debug Zerotorescue@0: Zerotorescue@0: function addon:Debug(t) Zerotorescue@0: if not self.debugChannel and self.debugChannel ~= false then Zerotorescue@0: -- We want to check just once, so if you add a debug channel later just do a /reload (registering an event for this is wasted resources) Zerotorescue@0: self.debugChannel = false; Zerotorescue@0: Zerotorescue@0: for i = 1, NUM_CHAT_WINDOWS do Zerotorescue@0: local name = GetChatWindowInfo(i); Zerotorescue@0: Zerotorescue@0: if name:upper() == "DEBUG" then Zerotorescue@0: self.debugChannel = _G["ChatFrame" .. i]; Zerotorescue@0: end Zerotorescue@0: end Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: if self.debugChannel then Zerotorescue@0: self.debugChannel:AddMessage(t); Zerotorescue@0: end Zerotorescue@0: end