From 87501f8e2bd147fa80f563a5d350abde2666a8fc Mon Sep 17 00:00:00 2001
From: Cinecom <42314202+Cinecom@users.noreply.github.com>
Date: Wed, 20 Nov 2024 19:27:59 +0100
Subject: [PATCH] Update 1.5-beta
- Changed Addon name to: Consumes Manager
- Fixed general styling issues
- Added a 'Use' button for tracked consumables
- Added a select/deselect all button to the options
- Changed scanning to global instead of selected items only
---
ConsumesManager.toc | 10 +
ConsumesTracker.toc | 10 -
Consumables.lua => Itemlist.lua | 224 +--
LICENSE | 674 -------
ConsumesTracker.lua => Main.lua | 3190 ++++++++++++++++---------------
README.md | 40 -
minimap_icon.xml | 16 +-
7 files changed, 1769 insertions(+), 2395 deletions(-)
create mode 100644 ConsumesManager.toc
delete mode 100644 ConsumesTracker.toc
rename Consumables.lua => Itemlist.lua (99%)
delete mode 100644 LICENSE
rename ConsumesTracker.lua => Main.lua (58%)
delete mode 100644 README.md
diff --git a/ConsumesManager.toc b/ConsumesManager.toc
new file mode 100644
index 0000000..e8e867c
--- /dev/null
+++ b/ConsumesManager.toc
@@ -0,0 +1,10 @@
+## Interface: 11200
+## Title: |cff00ff00Consumes Manager|r |cff808080[Horyoshi]|r
+## Notes: Tracks and manages consumables across your inventory, bank and mail through multiple characters. Keeps track of how much consumes you have left.
+## Author: Horyoshi
+## Version: 1.5
+## SavedVariables: ConsumesManager_Settings, ConsumesManager_Data
+
+Main.lua
+Itemlist.lua
+minimap_icon.xml
\ No newline at end of file
diff --git a/ConsumesTracker.toc b/ConsumesTracker.toc
deleted file mode 100644
index 4a094f2..0000000
--- a/ConsumesTracker.toc
+++ /dev/null
@@ -1,10 +0,0 @@
-## Interface: 11200
-## Title: |cff00ff00Consumes Tracker|r |cff808080[Horyoshi]|r
-## Notes: Tracks your inventory, bank and mail for consumables. Works through multiple characters on the same account.
-## Author: Horyoshi
-## Version: 1.4.1
-## SavedVariables: ConsumeTracker_Settings, ConsumeTracker_Data
-
-ConsumesTracker.lua
-Consumables.lua
-minimap_icon.xml
\ No newline at end of file
diff --git a/Consumables.lua b/Itemlist.lua
similarity index 99%
rename from Consumables.lua
rename to Itemlist.lua
index fe9e8b5..26a8375 100644
--- a/Consumables.lua
+++ b/Itemlist.lua
@@ -1,112 +1,112 @@
-
-consumablesCategories = {
- ["Elixirs"] = {
- { id = 13452, name = "Elixir of the Mongoose", texture = "Interface\\Icons\\INV_Potion_32", description = "Increases Agility by 25 and critical strike chance by 2% for 1 hour." },
- { id = 9187, name = "Elixir of Greater Agility", texture = "Interface\\Icons\\INV_Potion_94", description = "Increases Agility by 15 for 1 hour." },
- { id = 13453, name = "Elixir of Brute Force", texture = "Interface\\Icons\\INV_Potion_40", description = "Increases Strength and Stamina by 18 for 1 hour." },
- { id = 13447, name = "Elixir of the Sages", texture = "Interface\\Icons\\INV_Potion_29", description = "Increases Intellect and Spirit by 18 for 1 hour." },
- { id = 13454, name = "Greater Arcane Elixir", texture = "Interface\\Icons\\INV_Potion_25", description = "Increases spell damage by up to 35 for 1 hour." },
- { id = 13445, name = "Elixir of Superior Defense", texture = "Interface\\Icons\\INV_Potion_66", description = "Increases armor by 450 for 1 hour." },
- { id = 17708, name = "Elixir of Frost Power", texture = "Interface\\Icons\\INV_Potion_03", description = "Increases Frost spell damage by up to 15 for 1 hour." },
- { id = 22193, name = "Bloodkelp Elixir of Resistance", texture = "Interface\\Icons\\INV_Potion_21", description = "Increases all magical resistances by 15 for 30 minutes." },
- { id = 3825, name = "Elixir of Fortitude", texture = "Interface\\Icons\\INV_Potion_43", description = "Increases the player's maximum health by 120 for 1 hour." },
- { id = 9206, name = "Elixir of Giants", texture = "Interface\\Icons\\INV_Potion_61", description = "Increases your Strength by 25 for 1 hour." },
- { id = 9179, name = "Elixir of Greater Intellect", texture = "Interface\\Icons\\INV_Potion_10", description = "Increases Intellect by 25 for 1 hour." },
- { id = 50237, name = "Elixir of Greater Nature Power", texture = "Interface\\Icons\\INV_Potion_22", description = "Increases nature spell damage by up to 55 for 1 hour." },
- { id = 3386, name = "Elixir of Poison Resistance", texture = "Interface\\Icons\\INV_Potion_12", description = "Imbiber is cured of up to four poisons up to level 60." },
- { id = 9264, name = "Elixir of Poison Resistance", texture = "Interface\\Icons\\INV_Potion_46", description = "Increases spell shadow damage by up to 40 for 30 minutes." },
- { id = 61224, name = "Dreamshard Elixir", texture = "Interface\\Icons\\INV_Potion_12", description = " Grants 2% spell critical and 15 spell power for 1 hour." },
- },
- ["Flasks"] = {
- { id = 13513, name = "Flask of Chromatic Resistance", texture = "Interface\\Icons\\INV_Potion_48", description = "Increases your resistance to all schools of magic by 25 for 2 hours." },
- { id = 13511, name = "Flask of Distilled Wisdom", texture = "Interface\\Icons\\INV_Potion_97", description = "Increases the player's maximum mana by 2000 for 2 hours." },
- { id = 13512, name = "Flask of Supreme Power", texture = "Interface\\Icons\\INV_Potion_41", description = " Increases damage done by magical spells and effects by up to 150 for 2 hours." },
- { id = 13510, name = "Flask of the Titans", texture = "Interface\\Icons\\INV_Potion_62", description = "Increases the player's maximum health by 1200 for 2 hours." },
- { id = 13506, name = "Flask of Petrification", texture = "Interface\\Icons\\INV_Potion_26", description = "You turn to stone, protecting you from all physical attacks and spells for 60 sec." },
- },
- ["Protection Potions"] = {
- { id = 13457, name = "Greater Fire Protection Potion", texture = "Interface\\Icons\\INV_Potion_24", description = "Absorbs 1950 to 3250 Fire damage for 1 hour." },
- { id = 13456, name = "Greater Frost Protection Potion", texture = "Interface\\Icons\\INV_Potion_20", description = "Absorbs 1950 to 3250 Frost damage for 1 hour." },
- { id = 13458, name = "Greater Nature Protection Potion", texture = "Interface\\Icons\\INV_Potion_22", description = "Absorbs 1950 to 3250 Nature damage for 1 hour." },
- { id = 13459, name = "Greater Shadow Protection Potion", texture = "Interface\\Icons\\INV_Potion_23", description = "Absorbs 1950 to 3250 Shadow damage for 1 hour." },
- { id = 13461, name = "Greater Arcane Protection Potion", texture = "Interface\\Icons\\INV_Potion_83", description = "Absorbs 1950 to 3250 Arcane damage for 1 hour." },
- { id = 13460, name = "Greater Holy Protection Potion", texture = "Interface\\Icons\\INV_Potion_09", description = "Absorbs 1950 to 3251 holy damage for 1 hour." },
- },
- ["Weapon Enhancements"] = {
- { id = 12404, name = "Dense Sharpening Stone", texture = "Interface\\Icons\\INV_Stone_SharpeningStone_05", description = "Increases weapon damage by 8 for 30 minutes." },
- { id = 12645, name = "Thorium Shield Spike", texture = "Interface\\Icons\\INV_Misc_Armorkit_20", description = "Attaches a Thorium Spike to a shield, causing 20-30 damage when blocking." },
- { id = 20748, name = "Brilliant Mana Oil", texture = "Interface\\Icons\\INV_Potion_100", description = "Increases mana regeneration by 12 and spell damage by up to 25 for 30 minutes." },
- { id = 20749, name = "Brilliant Wizard Oil", texture = "Interface\\Icons\\INV_Potion_105", description = "Increases spell damage by up to 36 for 30 minutes." },
- { id = 23123, name = "Blessed Wizard Oil", texture = "Interface\\Icons\\INV_Potion_26", description = "Increases spell damage against undead by up to 60. Lasts for 1 hour." },
- { id = 3829, name = "Frost Oil", texture = "Interface\\Icons\\INV_Potion_20", description = "Adds a chance to inflict Frost damage on hit. Lasts 30 minutes." },
- { id = 23122, name = "Consecrated Sharpening Stone", texture = "Interface\\Icons\\inv_stone_sharpeningstone_02", description = "Increases melee attack power by 100 against undead for 30 minutes." },
- { id = 18262, name = "Elemental Sharpening Stone", texture = "Interface\\Icons\\INV_Stone_02", description = "Increases critical strike chance by 2% for 30 minutes." },
- { id = 8928, name = "Instant Poison VI", texture = "Interface\\Icons\\Ability_Poisons", description = "20% chance to inflict 112 to 149 Nature damage." },
- { id = 3776, name = "Crippling Poison II", texture = "Interface\\Icons\\INV_Potion_19", description = "30% chance to inflict the enemie, slowing their movement speed by 60% for 12 sec." },
- { id = 20844, name = "Deadly Poison V", texture = "Interface\\Icons\\Ability_Rogue_DualWeild", description = "30% chance of poisoning the enemy for 136 Nature damage over 12 sec. Stacks up to 5 times on a single target." },
- { id = 5763, name = "Mind-numbing Poison III", texture = "Interface\\Icons\\Spell_Nature_NullifyDisease", description = "20% chance of poisoning the enemy, increasing their casting time by 60% for 14 sec." },
- { id = 10922, name = "Wound Poison IV", texture = "Interface\\Icons\\Ability_PoisonSting", description = " 30% chance of poisoning the enemy, reducing all healing effects used on them by 135 for 15 sec. Stacks up to 5 times on a single target." }
- },
- ["Combat Potions"] = {
- { id = 13455, name = "Greater Stoneshield Potion", texture = "Interface\\Icons\\INV_Potion_69", description = "Increases armor by 2000 for 2 minutes." },
- { id = 13442, name = "Mighty Rage Potion", texture = "Interface\\Icons\\INV_Potion_41", description = "Restores 45 to 75 rage and increases Strength by 60 for 20 seconds." },
- { id = 20007, name = "Mageblood Potion", texture = "Interface\\Icons\\INV_Potion_45", description = "Regenerates 12 mana every 5 seconds for 1 hour." },
- },
- ["Utility Items"] = {
- { id = 20008, name = "Living Action Potion", texture = "Interface\\Icons\\INV_Potion_07", description = "Removes movement impairing effects and grants immunity to them for 5 seconds." },
- { id = 3387, name = "Limited Invulnerability Potion", texture = "Interface\\Icons\\INV_Potion_62", description = "Makes you immune to physical attacks for 6 seconds." },
- { id = 5634, name = "Free Action Potion", texture = "Interface\\Icons\\INV_Potion_04", description = "Grants immunity to stun and movement impairing effects for 30 seconds." },
- { id = 61225, name = "Lucidity Potion", texture = "Interface\\Icons\\INV_Potion_36", description = "Become immune to Sleep, Polymorph, and Charm effects for 30 sec." },
- { id = 9030, name = "Restorative Potion", texture = "Interface\\Icons\\INV_Potion_01", description = "Removes a magic, curse, poison, or disease effect every 5 seconds for 30 seconds." },
- { id = 4390, name = "Iron Grenade", texture = "Interface\\Icons\\INV_Misc_Bomb_08", description = "Inflicts 132 to 219 Fire damage and stuns enemies in a 3-yard radius for 3 seconds." },
- { id = 15993, name = "Thorium Grenade", texture = "Interface\\Icons\\INV_Misc_Bomb_08", description = "Inflicts 300 to 501 Fire damage and stuns enemies in a 3-yard radius for 3 seconds." },
- { id = 10646, name = "Goblin Sapper Charge", texture = "Interface\\Icons\\spell_fire_selfdestruct", description = "Deals 450-751 Fire damage to enemies within 10 yards, also damages you." },
- { id = 61675, name = "Nordanaar Herbal Tea", texture = "Interface\\Icons\\INV_Drink_Milk_05", description = "Restores 525 to 875 health and 810 to 1350 mana." },
- { id = 13462, name = "Purification Potion", texture = "Interface\\Icons\\INV_Potion_31", description = "Attempts to remove one Curse, one Disease and one Poison from the Imbiber." },
- { id = 13444, name = "Major Mana Potion", texture = "Interface\\Icons\\INV_Potion_76", description = "Restores 1350 to 2251 mana." },
- { id = 13446, name = "Major Healing Potion", texture = "Interface\\Icons\\INV_Potion_54", description = "Restores 1050 to 1751 health." },
- { id = 7676, name = "Thistle Tea", texture = "Interface\\Icons\\INV_Drink_Milk_05", description = "Instantly restores 100 energy." },
- },
- ["Food Buffs"] = {
- { id = 21023, name = "Dirge's Kickin' Chimaerok Chops", texture = "Interface\\Icons\\INV_Misc_Food_65", description = "Increases Strength by 25 for 1 hour." },
- { id = 18254, name = "Runn Tum Tuber Surprise", texture = "Interface\\Icons\\INV_Misc_Food_63", description = "Increases Intellect by 10 for 1 hour." },
- { id = 13931, name = "Nightfin Soup", texture = "Interface\\Icons\\INV_Drink_17", description = "Restores 8 mana every 5 seconds for 1 hour." },
- { id = 20452, name = "Smoked Desert Dumplings", texture = "Interface\\Icons\\INV_Misc_Food_64", description = "Increases Strength by 20 for 1 hour." },
- { id = 51711, name = "Sweet Mountain Berry (Agility)", texture = "Interface\\Icons\\INV_Misc_Food_40", description = "Increases Agility by 10 for 1 hour." },
- { id = 51714, name = "Sweet Mountain Berry (Stamina)", texture = "Interface\\Icons\\INV_Misc_Food_40", description = "Increases Stamina by 10 for 1 hour." },
- { id = 51717, name = "Hardened Mushroom", texture = "Interface\\Icons\\INV_Mushroom_11", description = "Increases 25 Stamina for 15 minutes" },
- { id = 51720, name = "Power Mushroom", texture = "Interface\\Icons\\INV_Mushroom_11", description = "Increases 20 Strength for 15 minutes" },
- { id = 21151, name = "Rumsey Rum Black Label", texture = "Interface\\Icons\\INV_Drink_04", description = "Increases Stamina by 15 for 15 minutes." },
- { id = 12218, name = "Monster Omelet", texture = "Interface\\Icons\\INV_Misc_Food_06", description = "Increases 12 Stamina and 12 Spirit for 15 minutes." },
- { id = 60977, name = "Danonzo's Tel'Abim Delight", texture = "Interface\\Icons\\INV_Misc_Food_06", description = "Gain 22 spell damage for 15 minutes." },
- { id = 60978, name = "Danonzo's Tel'Abim Medley", texture = "Interface\\Icons\\INV_Misc_Food_07", description = "Increase haste by 2% for 15 minutes." },
- { id = 60976, name = "Danonzo's Tel'Abim Surprise", texture = "Interface\\Icons\\INV_Misc_Food_09", description = "Gain 45 Ranged Attack Power for 15 minutes." },
- },
- ["Special Buffs"] = {
- { id = 12451, name = "Juju Power", texture = "Interface\\Icons\\INV_Misc_MonsterScales_11", description = "Increases Strength by 30 for 30 minutes." },
- { id = 12460, name = "Juju Might", texture = "Interface\\Icons\\INV_Misc_MonsterScales_07", description = "Increases Attack Power by 40 for 30 minutes." },
- { id = 12455, name = "Juju Ember", texture = "Interface\\Icons\\INV_Misc_MonsterScales_15", description = "Increases Fire Resistance by 15 for 30 minutes." },
- { id = 12457, name = "Juju Chill", texture = "Interface\\Icons\\INV_Misc_MonsterScales_09", description = "Increase Frost resistance by 15 for 10 minutes." },
- { id = 12820, name = "Winterfall Firewater", texture = "Interface\\Icons\\INV_Potion_92", description = "Increases Attack Power by 35 for 20 minutes." },
- { id = 20079, name = "Spirit of Zanza", texture = "Interface\\Icons\\INV_Potion_30", description = "Increases the player's Spirit by 50 and Stamina by 50 for 2 hours." },
- { id = 20081, name = "Swiftness of Zanza", texture = "Interface\\Icons\\INV_Potion_30", description = "Increases the player's run speed by 20% for 2 hours." },
- },
-}
-
-
-
-consumablesList = {}
-consumablesNameToID = {}
-consumablesTexture = {}
-consumablesDescription = {}
-
-for categoryName, consumables in pairs(consumablesCategories) do
- for _, consumable in ipairs(consumables) do
- consumablesList[consumable.id] = consumable.name
- consumablesNameToID[consumable.name] = consumable.id
- consumablesTexture[consumable.id] = consumable.texture
- consumablesDescription[consumable.id] = consumable.description
- end
-end
-
-
+
+consumablesCategories = {
+ ["Elixirs"] = {
+ { id = 13452, name = "Elixir of the Mongoose", texture = "Interface\\Icons\\INV_Potion_32", description = "Increases Agility by 25 and critical strike chance by 2% for 1 hour." },
+ { id = 9187, name = "Elixir of Greater Agility", texture = "Interface\\Icons\\INV_Potion_94", description = "Increases Agility by 15 for 1 hour." },
+ { id = 13453, name = "Elixir of Brute Force", texture = "Interface\\Icons\\INV_Potion_40", description = "Increases Strength and Stamina by 18 for 1 hour." },
+ { id = 13447, name = "Elixir of the Sages", texture = "Interface\\Icons\\INV_Potion_29", description = "Increases Intellect and Spirit by 18 for 1 hour." },
+ { id = 13454, name = "Greater Arcane Elixir", texture = "Interface\\Icons\\INV_Potion_25", description = "Increases spell damage by up to 35 for 1 hour." },
+ { id = 13445, name = "Elixir of Superior Defense", texture = "Interface\\Icons\\INV_Potion_66", description = "Increases armor by 450 for 1 hour." },
+ { id = 17708, name = "Elixir of Frost Power", texture = "Interface\\Icons\\INV_Potion_03", description = "Increases Frost spell damage by up to 15 for 1 hour." },
+ { id = 22193, name = "Bloodkelp Elixir of Resistance", texture = "Interface\\Icons\\INV_Potion_21", description = "Increases all magical resistances by 15 for 30 minutes." },
+ { id = 3825, name = "Elixir of Fortitude", texture = "Interface\\Icons\\INV_Potion_43", description = "Increases the player's maximum health by 120 for 1 hour." },
+ { id = 9206, name = "Elixir of Giants", texture = "Interface\\Icons\\INV_Potion_61", description = "Increases your Strength by 25 for 1 hour." },
+ { id = 9179, name = "Elixir of Greater Intellect", texture = "Interface\\Icons\\INV_Potion_10", description = "Increases Intellect by 25 for 1 hour." },
+ { id = 50237, name = "Elixir of Greater Nature Power", texture = "Interface\\Icons\\INV_Potion_22", description = "Increases nature spell damage by up to 55 for 1 hour." },
+ { id = 3386, name = "Elixir of Poison Resistance", texture = "Interface\\Icons\\INV_Potion_12", description = "Imbiber is cured of up to four poisons up to level 60." },
+ { id = 9264, name = "Elixir of Poison Resistance", texture = "Interface\\Icons\\INV_Potion_46", description = "Increases spell shadow damage by up to 40 for 30 minutes." },
+ { id = 61224, name = "Dreamshard Elixir", texture = "Interface\\Icons\\INV_Potion_12", description = " Grants 2% spell critical and 15 spell power for 1 hour." },
+ },
+ ["Flasks"] = {
+ { id = 13513, name = "Flask of Chromatic Resistance", texture = "Interface\\Icons\\INV_Potion_48", description = "Increases your resistance to all schools of magic by 25 for 2 hours." },
+ { id = 13511, name = "Flask of Distilled Wisdom", texture = "Interface\\Icons\\INV_Potion_97", description = "Increases the player's maximum mana by 2000 for 2 hours." },
+ { id = 13512, name = "Flask of Supreme Power", texture = "Interface\\Icons\\INV_Potion_41", description = " Increases damage done by magical spells and effects by up to 150 for 2 hours." },
+ { id = 13510, name = "Flask of the Titans", texture = "Interface\\Icons\\INV_Potion_62", description = "Increases the player's maximum health by 1200 for 2 hours." },
+ { id = 13506, name = "Flask of Petrification", texture = "Interface\\Icons\\INV_Potion_26", description = "You turn to stone, protecting you from all physical attacks and spells for 60 sec." },
+ },
+ ["Protection Potions"] = {
+ { id = 13457, name = "Greater Fire Protection Potion", texture = "Interface\\Icons\\INV_Potion_24", description = "Absorbs 1950 to 3250 Fire damage for 1 hour." },
+ { id = 13456, name = "Greater Frost Protection Potion", texture = "Interface\\Icons\\INV_Potion_20", description = "Absorbs 1950 to 3250 Frost damage for 1 hour." },
+ { id = 13458, name = "Greater Nature Protection Potion", texture = "Interface\\Icons\\INV_Potion_22", description = "Absorbs 1950 to 3250 Nature damage for 1 hour." },
+ { id = 13459, name = "Greater Shadow Protection Potion", texture = "Interface\\Icons\\INV_Potion_23", description = "Absorbs 1950 to 3250 Shadow damage for 1 hour." },
+ { id = 13461, name = "Greater Arcane Protection Potion", texture = "Interface\\Icons\\INV_Potion_83", description = "Absorbs 1950 to 3250 Arcane damage for 1 hour." },
+ { id = 13460, name = "Greater Holy Protection Potion", texture = "Interface\\Icons\\INV_Potion_09", description = "Absorbs 1950 to 3251 holy damage for 1 hour." },
+ },
+ ["Weapon Enhancements"] = {
+ { id = 12404, name = "Dense Sharpening Stone", texture = "Interface\\Icons\\INV_Stone_SharpeningStone_05", description = "Increases weapon damage by 8 for 30 minutes." },
+ { id = 12645, name = "Thorium Shield Spike", texture = "Interface\\Icons\\INV_Misc_Armorkit_20", description = "Attaches a Thorium Spike to a shield, causing 20-30 damage when blocking." },
+ { id = 20748, name = "Brilliant Mana Oil", texture = "Interface\\Icons\\INV_Potion_100", description = "Increases mana regeneration by 12 and spell damage by up to 25 for 30 minutes." },
+ { id = 20749, name = "Brilliant Wizard Oil", texture = "Interface\\Icons\\INV_Potion_105", description = "Increases spell damage by up to 36 for 30 minutes." },
+ { id = 23123, name = "Blessed Wizard Oil", texture = "Interface\\Icons\\INV_Potion_26", description = "Increases spell damage against undead by up to 60. Lasts for 1 hour." },
+ { id = 3829, name = "Frost Oil", texture = "Interface\\Icons\\INV_Potion_20", description = "Adds a chance to inflict Frost damage on hit. Lasts 30 minutes." },
+ { id = 23122, name = "Consecrated Sharpening Stone", texture = "Interface\\Icons\\inv_stone_sharpeningstone_02", description = "Increases melee attack power by 100 against undead for 30 minutes." },
+ { id = 18262, name = "Elemental Sharpening Stone", texture = "Interface\\Icons\\INV_Stone_02", description = "Increases critical strike chance by 2% for 30 minutes." },
+ { id = 8928, name = "Instant Poison VI", texture = "Interface\\Icons\\Ability_Poisons", description = "20% chance to inflict 112 to 149 Nature damage." },
+ { id = 3776, name = "Crippling Poison II", texture = "Interface\\Icons\\INV_Potion_19", description = "30% chance to inflict the enemie, slowing their movement speed by 60% for 12 sec." },
+ { id = 20844, name = "Deadly Poison V", texture = "Interface\\Icons\\Ability_Rogue_DualWeild", description = "30% chance of poisoning the enemy for 136 Nature damage over 12 sec. Stacks up to 5 times on a single target." },
+ { id = 5763, name = "Mind-numbing Poison III", texture = "Interface\\Icons\\Spell_Nature_NullifyDisease", description = "20% chance of poisoning the enemy, increasing their casting time by 60% for 14 sec." },
+ { id = 10922, name = "Wound Poison IV", texture = "Interface\\Icons\\Ability_PoisonSting", description = " 30% chance of poisoning the enemy, reducing all healing effects used on them by 135 for 15 sec. Stacks up to 5 times on a single target." }
+ },
+ ["Combat Potions"] = {
+ { id = 13455, name = "Greater Stoneshield Potion", texture = "Interface\\Icons\\INV_Potion_69", description = "Increases armor by 2000 for 2 minutes." },
+ { id = 13442, name = "Mighty Rage Potion", texture = "Interface\\Icons\\INV_Potion_41", description = "Restores 45 to 75 rage and increases Strength by 60 for 20 seconds." },
+ { id = 20007, name = "Mageblood Potion", texture = "Interface\\Icons\\INV_Potion_45", description = "Regenerates 12 mana every 5 seconds for 1 hour." },
+ },
+ ["Utility Items"] = {
+ { id = 20008, name = "Living Action Potion", texture = "Interface\\Icons\\INV_Potion_07", description = "Removes movement impairing effects and grants immunity to them for 5 seconds." },
+ { id = 3387, name = "Limited Invulnerability Potion", texture = "Interface\\Icons\\INV_Potion_62", description = "Makes you immune to physical attacks for 6 seconds." },
+ { id = 5634, name = "Free Action Potion", texture = "Interface\\Icons\\INV_Potion_04", description = "Grants immunity to stun and movement impairing effects for 30 seconds." },
+ { id = 61225, name = "Lucidity Potion", texture = "Interface\\Icons\\INV_Potion_36", description = "Become immune to Sleep, Polymorph, and Charm effects for 30 sec." },
+ { id = 9030, name = "Restorative Potion", texture = "Interface\\Icons\\INV_Potion_01", description = "Removes a magic, curse, poison, or disease effect every 5 seconds for 30 seconds." },
+ { id = 4390, name = "Iron Grenade", texture = "Interface\\Icons\\INV_Misc_Bomb_08", description = "Inflicts 132 to 219 Fire damage and stuns enemies in a 3-yard radius for 3 seconds." },
+ { id = 15993, name = "Thorium Grenade", texture = "Interface\\Icons\\INV_Misc_Bomb_08", description = "Inflicts 300 to 501 Fire damage and stuns enemies in a 3-yard radius for 3 seconds." },
+ { id = 10646, name = "Goblin Sapper Charge", texture = "Interface\\Icons\\spell_fire_selfdestruct", description = "Deals 450-751 Fire damage to enemies within 10 yards, also damages you." },
+ { id = 61675, name = "Nordanaar Herbal Tea", texture = "Interface\\Icons\\INV_Drink_Milk_05", description = "Restores 525 to 875 health and 810 to 1350 mana." },
+ { id = 13462, name = "Purification Potion", texture = "Interface\\Icons\\INV_Potion_31", description = "Attempts to remove one Curse, one Disease and one Poison from the Imbiber." },
+ { id = 13444, name = "Major Mana Potion", texture = "Interface\\Icons\\INV_Potion_76", description = "Restores 1350 to 2251 mana." },
+ { id = 13446, name = "Major Healing Potion", texture = "Interface\\Icons\\INV_Potion_54", description = "Restores 1050 to 1751 health." },
+ { id = 7676, name = "Thistle Tea", texture = "Interface\\Icons\\INV_Drink_Milk_05", description = "Instantly restores 100 energy." },
+ },
+ ["Food Buffs"] = {
+ { id = 21023, name = "Dirge's Kickin' Chimaerok Chops", texture = "Interface\\Icons\\INV_Misc_Food_65", description = "Increases Strength by 25 for 1 hour." },
+ { id = 18254, name = "Runn Tum Tuber Surprise", texture = "Interface\\Icons\\INV_Misc_Food_63", description = "Increases Intellect by 10 for 1 hour." },
+ { id = 13931, name = "Nightfin Soup", texture = "Interface\\Icons\\INV_Drink_17", description = "Restores 8 mana every 5 seconds for 1 hour." },
+ { id = 20452, name = "Smoked Desert Dumplings", texture = "Interface\\Icons\\INV_Misc_Food_64", description = "Increases Strength by 20 for 1 hour." },
+ { id = 51711, name = "Sweet Mountain Berry (Agility)", texture = "Interface\\Icons\\INV_Misc_Food_40", description = "Increases Agility by 10 for 1 hour." },
+ { id = 51714, name = "Sweet Mountain Berry (Stamina)", texture = "Interface\\Icons\\INV_Misc_Food_40", description = "Increases Stamina by 10 for 1 hour." },
+ { id = 51717, name = "Hardened Mushroom", texture = "Interface\\Icons\\INV_Mushroom_11", description = "Increases 25 Stamina for 15 minutes" },
+ { id = 51720, name = "Power Mushroom", texture = "Interface\\Icons\\INV_Mushroom_11", description = "Increases 20 Strength for 15 minutes" },
+ { id = 21151, name = "Rumsey Rum Black Label", texture = "Interface\\Icons\\INV_Drink_04", description = "Increases Stamina by 15 for 15 minutes." },
+ { id = 12218, name = "Monster Omelet", texture = "Interface\\Icons\\INV_Misc_Food_06", description = "Increases 12 Stamina and 12 Spirit for 15 minutes." },
+ { id = 60977, name = "Danonzo's Tel'Abim Delight", texture = "Interface\\Icons\\INV_Misc_Food_06", description = "Gain 22 spell damage for 15 minutes." },
+ { id = 60978, name = "Danonzo's Tel'Abim Medley", texture = "Interface\\Icons\\INV_Misc_Food_07", description = "Increase haste by 2% for 15 minutes." },
+ { id = 60976, name = "Danonzo's Tel'Abim Surprise", texture = "Interface\\Icons\\INV_Misc_Food_09", description = "Gain 45 Ranged Attack Power for 15 minutes." },
+ },
+ ["Special Buffs"] = {
+ { id = 12451, name = "Juju Power", texture = "Interface\\Icons\\INV_Misc_MonsterScales_11", description = "Increases Strength by 30 for 30 minutes." },
+ { id = 12460, name = "Juju Might", texture = "Interface\\Icons\\INV_Misc_MonsterScales_07", description = "Increases Attack Power by 40 for 30 minutes." },
+ { id = 12455, name = "Juju Ember", texture = "Interface\\Icons\\INV_Misc_MonsterScales_15", description = "Increases Fire Resistance by 15 for 30 minutes." },
+ { id = 12457, name = "Juju Chill", texture = "Interface\\Icons\\INV_Misc_MonsterScales_09", description = "Increase Frost resistance by 15 for 10 minutes." },
+ { id = 12820, name = "Winterfall Firewater", texture = "Interface\\Icons\\INV_Potion_92", description = "Increases Attack Power by 35 for 20 minutes." },
+ { id = 20079, name = "Spirit of Zanza", texture = "Interface\\Icons\\INV_Potion_30", description = "Increases the player's Spirit by 50 and Stamina by 50 for 2 hours." },
+ { id = 20081, name = "Swiftness of Zanza", texture = "Interface\\Icons\\INV_Potion_30", description = "Increases the player's run speed by 20% for 2 hours." },
+ },
+}
+
+
+
+consumablesList = {}
+consumablesNameToID = {}
+consumablesTexture = {}
+consumablesDescription = {}
+
+for categoryName, consumables in pairs(consumablesCategories) do
+ for _, consumable in ipairs(consumables) do
+ consumablesList[consumable.id] = consumable.name
+ consumablesNameToID[consumable.name] = consumable.id
+ consumablesTexture[consumable.id] = consumable.texture
+ consumablesDescription[consumable.id] = consumable.description
+ end
+end
+
+
diff --git a/LICENSE b/LICENSE
deleted file mode 100644
index f288702..0000000
--- a/LICENSE
+++ /dev/null
@@ -1,674 +0,0 @@
- GNU GENERAL PUBLIC LICENSE
- Version 3, 29 June 2007
-
- Copyright (C) 2007 Free Software Foundation, Inc.
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
- Preamble
-
- The GNU General Public License is a free, copyleft license for
-software and other kinds of works.
-
- The licenses for most software and other practical works are designed
-to take away your freedom to share and change the works. By contrast,
-the GNU General Public License is intended to guarantee your freedom to
-share and change all versions of a program--to make sure it remains free
-software for all its users. We, the Free Software Foundation, use the
-GNU General Public License for most of our software; it applies also to
-any other work released this way by its authors. You can apply it to
-your programs, too.
-
- When we speak of free software, we are referring to freedom, not
-price. Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-them if you wish), that you receive source code or can get it if you
-want it, that you can change the software or use pieces of it in new
-free programs, and that you know you can do these things.
-
- To protect your rights, we need to prevent others from denying you
-these rights or asking you to surrender the rights. Therefore, you have
-certain responsibilities if you distribute copies of the software, or if
-you modify it: responsibilities to respect the freedom of others.
-
- For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must pass on to the recipients the same
-freedoms that you received. You must make sure that they, too, receive
-or can get the source code. And you must show them these terms so they
-know their rights.
-
- Developers that use the GNU GPL protect your rights with two steps:
-(1) assert copyright on the software, and (2) offer you this License
-giving you legal permission to copy, distribute and/or modify it.
-
- For the developers' and authors' protection, the GPL clearly explains
-that there is no warranty for this free software. For both users' and
-authors' sake, the GPL requires that modified versions be marked as
-changed, so that their problems will not be attributed erroneously to
-authors of previous versions.
-
- Some devices are designed to deny users access to install or run
-modified versions of the software inside them, although the manufacturer
-can do so. This is fundamentally incompatible with the aim of
-protecting users' freedom to change the software. The systematic
-pattern of such abuse occurs in the area of products for individuals to
-use, which is precisely where it is most unacceptable. Therefore, we
-have designed this version of the GPL to prohibit the practice for those
-products. If such problems arise substantially in other domains, we
-stand ready to extend this provision to those domains in future versions
-of the GPL, as needed to protect the freedom of users.
-
- Finally, every program is threatened constantly by software patents.
-States should not allow patents to restrict development and use of
-software on general-purpose computers, but in those that do, we wish to
-avoid the special danger that patents applied to a free program could
-make it effectively proprietary. To prevent this, the GPL assures that
-patents cannot be used to render the program non-free.
-
- The precise terms and conditions for copying, distribution and
-modification follow.
-
- TERMS AND CONDITIONS
-
- 0. Definitions.
-
- "This License" refers to version 3 of the GNU General Public License.
-
- "Copyright" also means copyright-like laws that apply to other kinds of
-works, such as semiconductor masks.
-
- "The Program" refers to any copyrightable work licensed under this
-License. Each licensee is addressed as "you". "Licensees" and
-"recipients" may be individuals or organizations.
-
- To "modify" a work means to copy from or adapt all or part of the work
-in a fashion requiring copyright permission, other than the making of an
-exact copy. The resulting work is called a "modified version" of the
-earlier work or a work "based on" the earlier work.
-
- A "covered work" means either the unmodified Program or a work based
-on the Program.
-
- To "propagate" a work means to do anything with it that, without
-permission, would make you directly or secondarily liable for
-infringement under applicable copyright law, except executing it on a
-computer or modifying a private copy. Propagation includes copying,
-distribution (with or without modification), making available to the
-public, and in some countries other activities as well.
-
- To "convey" a work means any kind of propagation that enables other
-parties to make or receive copies. Mere interaction with a user through
-a computer network, with no transfer of a copy, is not conveying.
-
- An interactive user interface displays "Appropriate Legal Notices"
-to the extent that it includes a convenient and prominently visible
-feature that (1) displays an appropriate copyright notice, and (2)
-tells the user that there is no warranty for the work (except to the
-extent that warranties are provided), that licensees may convey the
-work under this License, and how to view a copy of this License. If
-the interface presents a list of user commands or options, such as a
-menu, a prominent item in the list meets this criterion.
-
- 1. Source Code.
-
- The "source code" for a work means the preferred form of the work
-for making modifications to it. "Object code" means any non-source
-form of a work.
-
- A "Standard Interface" means an interface that either is an official
-standard defined by a recognized standards body, or, in the case of
-interfaces specified for a particular programming language, one that
-is widely used among developers working in that language.
-
- The "System Libraries" of an executable work include anything, other
-than the work as a whole, that (a) is included in the normal form of
-packaging a Major Component, but which is not part of that Major
-Component, and (b) serves only to enable use of the work with that
-Major Component, or to implement a Standard Interface for which an
-implementation is available to the public in source code form. A
-"Major Component", in this context, means a major essential component
-(kernel, window system, and so on) of the specific operating system
-(if any) on which the executable work runs, or a compiler used to
-produce the work, or an object code interpreter used to run it.
-
- The "Corresponding Source" for a work in object code form means all
-the source code needed to generate, install, and (for an executable
-work) run the object code and to modify the work, including scripts to
-control those activities. However, it does not include the work's
-System Libraries, or general-purpose tools or generally available free
-programs which are used unmodified in performing those activities but
-which are not part of the work. For example, Corresponding Source
-includes interface definition files associated with source files for
-the work, and the source code for shared libraries and dynamically
-linked subprograms that the work is specifically designed to require,
-such as by intimate data communication or control flow between those
-subprograms and other parts of the work.
-
- The Corresponding Source need not include anything that users
-can regenerate automatically from other parts of the Corresponding
-Source.
-
- The Corresponding Source for a work in source code form is that
-same work.
-
- 2. Basic Permissions.
-
- All rights granted under this License are granted for the term of
-copyright on the Program, and are irrevocable provided the stated
-conditions are met. This License explicitly affirms your unlimited
-permission to run the unmodified Program. The output from running a
-covered work is covered by this License only if the output, given its
-content, constitutes a covered work. This License acknowledges your
-rights of fair use or other equivalent, as provided by copyright law.
-
- You may make, run and propagate covered works that you do not
-convey, without conditions so long as your license otherwise remains
-in force. You may convey covered works to others for the sole purpose
-of having them make modifications exclusively for you, or provide you
-with facilities for running those works, provided that you comply with
-the terms of this License in conveying all material for which you do
-not control copyright. Those thus making or running the covered works
-for you must do so exclusively on your behalf, under your direction
-and control, on terms that prohibit them from making any copies of
-your copyrighted material outside their relationship with you.
-
- Conveying under any other circumstances is permitted solely under
-the conditions stated below. Sublicensing is not allowed; section 10
-makes it unnecessary.
-
- 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
-
- No covered work shall be deemed part of an effective technological
-measure under any applicable law fulfilling obligations under article
-11 of the WIPO copyright treaty adopted on 20 December 1996, or
-similar laws prohibiting or restricting circumvention of such
-measures.
-
- When you convey a covered work, you waive any legal power to forbid
-circumvention of technological measures to the extent such circumvention
-is effected by exercising rights under this License with respect to
-the covered work, and you disclaim any intention to limit operation or
-modification of the work as a means of enforcing, against the work's
-users, your or third parties' legal rights to forbid circumvention of
-technological measures.
-
- 4. Conveying Verbatim Copies.
-
- You may convey verbatim copies of the Program's source code as you
-receive it, in any medium, provided that you conspicuously and
-appropriately publish on each copy an appropriate copyright notice;
-keep intact all notices stating that this License and any
-non-permissive terms added in accord with section 7 apply to the code;
-keep intact all notices of the absence of any warranty; and give all
-recipients a copy of this License along with the Program.
-
- You may charge any price or no price for each copy that you convey,
-and you may offer support or warranty protection for a fee.
-
- 5. Conveying Modified Source Versions.
-
- You may convey a work based on the Program, or the modifications to
-produce it from the Program, in the form of source code under the
-terms of section 4, provided that you also meet all of these conditions:
-
- a) The work must carry prominent notices stating that you modified
- it, and giving a relevant date.
-
- b) The work must carry prominent notices stating that it is
- released under this License and any conditions added under section
- 7. This requirement modifies the requirement in section 4 to
- "keep intact all notices".
-
- c) You must license the entire work, as a whole, under this
- License to anyone who comes into possession of a copy. This
- License will therefore apply, along with any applicable section 7
- additional terms, to the whole of the work, and all its parts,
- regardless of how they are packaged. This License gives no
- permission to license the work in any other way, but it does not
- invalidate such permission if you have separately received it.
-
- d) If the work has interactive user interfaces, each must display
- Appropriate Legal Notices; however, if the Program has interactive
- interfaces that do not display Appropriate Legal Notices, your
- work need not make them do so.
-
- A compilation of a covered work with other separate and independent
-works, which are not by their nature extensions of the covered work,
-and which are not combined with it such as to form a larger program,
-in or on a volume of a storage or distribution medium, is called an
-"aggregate" if the compilation and its resulting copyright are not
-used to limit the access or legal rights of the compilation's users
-beyond what the individual works permit. Inclusion of a covered work
-in an aggregate does not cause this License to apply to the other
-parts of the aggregate.
-
- 6. Conveying Non-Source Forms.
-
- You may convey a covered work in object code form under the terms
-of sections 4 and 5, provided that you also convey the
-machine-readable Corresponding Source under the terms of this License,
-in one of these ways:
-
- a) Convey the object code in, or embodied in, a physical product
- (including a physical distribution medium), accompanied by the
- Corresponding Source fixed on a durable physical medium
- customarily used for software interchange.
-
- b) Convey the object code in, or embodied in, a physical product
- (including a physical distribution medium), accompanied by a
- written offer, valid for at least three years and valid for as
- long as you offer spare parts or customer support for that product
- model, to give anyone who possesses the object code either (1) a
- copy of the Corresponding Source for all the software in the
- product that is covered by this License, on a durable physical
- medium customarily used for software interchange, for a price no
- more than your reasonable cost of physically performing this
- conveying of source, or (2) access to copy the
- Corresponding Source from a network server at no charge.
-
- c) Convey individual copies of the object code with a copy of the
- written offer to provide the Corresponding Source. This
- alternative is allowed only occasionally and noncommercially, and
- only if you received the object code with such an offer, in accord
- with subsection 6b.
-
- d) Convey the object code by offering access from a designated
- place (gratis or for a charge), and offer equivalent access to the
- Corresponding Source in the same way through the same place at no
- further charge. You need not require recipients to copy the
- Corresponding Source along with the object code. If the place to
- copy the object code is a network server, the Corresponding Source
- may be on a different server (operated by you or a third party)
- that supports equivalent copying facilities, provided you maintain
- clear directions next to the object code saying where to find the
- Corresponding Source. Regardless of what server hosts the
- Corresponding Source, you remain obligated to ensure that it is
- available for as long as needed to satisfy these requirements.
-
- e) Convey the object code using peer-to-peer transmission, provided
- you inform other peers where the object code and Corresponding
- Source of the work are being offered to the general public at no
- charge under subsection 6d.
-
- A separable portion of the object code, whose source code is excluded
-from the Corresponding Source as a System Library, need not be
-included in conveying the object code work.
-
- A "User Product" is either (1) a "consumer product", which means any
-tangible personal property which is normally used for personal, family,
-or household purposes, or (2) anything designed or sold for incorporation
-into a dwelling. In determining whether a product is a consumer product,
-doubtful cases shall be resolved in favor of coverage. For a particular
-product received by a particular user, "normally used" refers to a
-typical or common use of that class of product, regardless of the status
-of the particular user or of the way in which the particular user
-actually uses, or expects or is expected to use, the product. A product
-is a consumer product regardless of whether the product has substantial
-commercial, industrial or non-consumer uses, unless such uses represent
-the only significant mode of use of the product.
-
- "Installation Information" for a User Product means any methods,
-procedures, authorization keys, or other information required to install
-and execute modified versions of a covered work in that User Product from
-a modified version of its Corresponding Source. The information must
-suffice to ensure that the continued functioning of the modified object
-code is in no case prevented or interfered with solely because
-modification has been made.
-
- If you convey an object code work under this section in, or with, or
-specifically for use in, a User Product, and the conveying occurs as
-part of a transaction in which the right of possession and use of the
-User Product is transferred to the recipient in perpetuity or for a
-fixed term (regardless of how the transaction is characterized), the
-Corresponding Source conveyed under this section must be accompanied
-by the Installation Information. But this requirement does not apply
-if neither you nor any third party retains the ability to install
-modified object code on the User Product (for example, the work has
-been installed in ROM).
-
- The requirement to provide Installation Information does not include a
-requirement to continue to provide support service, warranty, or updates
-for a work that has been modified or installed by the recipient, or for
-the User Product in which it has been modified or installed. Access to a
-network may be denied when the modification itself materially and
-adversely affects the operation of the network or violates the rules and
-protocols for communication across the network.
-
- Corresponding Source conveyed, and Installation Information provided,
-in accord with this section must be in a format that is publicly
-documented (and with an implementation available to the public in
-source code form), and must require no special password or key for
-unpacking, reading or copying.
-
- 7. Additional Terms.
-
- "Additional permissions" are terms that supplement the terms of this
-License by making exceptions from one or more of its conditions.
-Additional permissions that are applicable to the entire Program shall
-be treated as though they were included in this License, to the extent
-that they are valid under applicable law. If additional permissions
-apply only to part of the Program, that part may be used separately
-under those permissions, but the entire Program remains governed by
-this License without regard to the additional permissions.
-
- When you convey a copy of a covered work, you may at your option
-remove any additional permissions from that copy, or from any part of
-it. (Additional permissions may be written to require their own
-removal in certain cases when you modify the work.) You may place
-additional permissions on material, added by you to a covered work,
-for which you have or can give appropriate copyright permission.
-
- Notwithstanding any other provision of this License, for material you
-add to a covered work, you may (if authorized by the copyright holders of
-that material) supplement the terms of this License with terms:
-
- a) Disclaiming warranty or limiting liability differently from the
- terms of sections 15 and 16 of this License; or
-
- b) Requiring preservation of specified reasonable legal notices or
- author attributions in that material or in the Appropriate Legal
- Notices displayed by works containing it; or
-
- c) Prohibiting misrepresentation of the origin of that material, or
- requiring that modified versions of such material be marked in
- reasonable ways as different from the original version; or
-
- d) Limiting the use for publicity purposes of names of licensors or
- authors of the material; or
-
- e) Declining to grant rights under trademark law for use of some
- trade names, trademarks, or service marks; or
-
- f) Requiring indemnification of licensors and authors of that
- material by anyone who conveys the material (or modified versions of
- it) with contractual assumptions of liability to the recipient, for
- any liability that these contractual assumptions directly impose on
- those licensors and authors.
-
- All other non-permissive additional terms are considered "further
-restrictions" within the meaning of section 10. If the Program as you
-received it, or any part of it, contains a notice stating that it is
-governed by this License along with a term that is a further
-restriction, you may remove that term. If a license document contains
-a further restriction but permits relicensing or conveying under this
-License, you may add to a covered work material governed by the terms
-of that license document, provided that the further restriction does
-not survive such relicensing or conveying.
-
- If you add terms to a covered work in accord with this section, you
-must place, in the relevant source files, a statement of the
-additional terms that apply to those files, or a notice indicating
-where to find the applicable terms.
-
- Additional terms, permissive or non-permissive, may be stated in the
-form of a separately written license, or stated as exceptions;
-the above requirements apply either way.
-
- 8. Termination.
-
- You may not propagate or modify a covered work except as expressly
-provided under this License. Any attempt otherwise to propagate or
-modify it is void, and will automatically terminate your rights under
-this License (including any patent licenses granted under the third
-paragraph of section 11).
-
- However, if you cease all violation of this License, then your
-license from a particular copyright holder is reinstated (a)
-provisionally, unless and until the copyright holder explicitly and
-finally terminates your license, and (b) permanently, if the copyright
-holder fails to notify you of the violation by some reasonable means
-prior to 60 days after the cessation.
-
- Moreover, your license from a particular copyright holder is
-reinstated permanently if the copyright holder notifies you of the
-violation by some reasonable means, this is the first time you have
-received notice of violation of this License (for any work) from that
-copyright holder, and you cure the violation prior to 30 days after
-your receipt of the notice.
-
- Termination of your rights under this section does not terminate the
-licenses of parties who have received copies or rights from you under
-this License. If your rights have been terminated and not permanently
-reinstated, you do not qualify to receive new licenses for the same
-material under section 10.
-
- 9. Acceptance Not Required for Having Copies.
-
- You are not required to accept this License in order to receive or
-run a copy of the Program. Ancillary propagation of a covered work
-occurring solely as a consequence of using peer-to-peer transmission
-to receive a copy likewise does not require acceptance. However,
-nothing other than this License grants you permission to propagate or
-modify any covered work. These actions infringe copyright if you do
-not accept this License. Therefore, by modifying or propagating a
-covered work, you indicate your acceptance of this License to do so.
-
- 10. Automatic Licensing of Downstream Recipients.
-
- Each time you convey a covered work, the recipient automatically
-receives a license from the original licensors, to run, modify and
-propagate that work, subject to this License. You are not responsible
-for enforcing compliance by third parties with this License.
-
- An "entity transaction" is a transaction transferring control of an
-organization, or substantially all assets of one, or subdividing an
-organization, or merging organizations. If propagation of a covered
-work results from an entity transaction, each party to that
-transaction who receives a copy of the work also receives whatever
-licenses to the work the party's predecessor in interest had or could
-give under the previous paragraph, plus a right to possession of the
-Corresponding Source of the work from the predecessor in interest, if
-the predecessor has it or can get it with reasonable efforts.
-
- You may not impose any further restrictions on the exercise of the
-rights granted or affirmed under this License. For example, you may
-not impose a license fee, royalty, or other charge for exercise of
-rights granted under this License, and you may not initiate litigation
-(including a cross-claim or counterclaim in a lawsuit) alleging that
-any patent claim is infringed by making, using, selling, offering for
-sale, or importing the Program or any portion of it.
-
- 11. Patents.
-
- A "contributor" is a copyright holder who authorizes use under this
-License of the Program or a work on which the Program is based. The
-work thus licensed is called the contributor's "contributor version".
-
- A contributor's "essential patent claims" are all patent claims
-owned or controlled by the contributor, whether already acquired or
-hereafter acquired, that would be infringed by some manner, permitted
-by this License, of making, using, or selling its contributor version,
-but do not include claims that would be infringed only as a
-consequence of further modification of the contributor version. For
-purposes of this definition, "control" includes the right to grant
-patent sublicenses in a manner consistent with the requirements of
-this License.
-
- Each contributor grants you a non-exclusive, worldwide, royalty-free
-patent license under the contributor's essential patent claims, to
-make, use, sell, offer for sale, import and otherwise run, modify and
-propagate the contents of its contributor version.
-
- In the following three paragraphs, a "patent license" is any express
-agreement or commitment, however denominated, not to enforce a patent
-(such as an express permission to practice a patent or covenant not to
-sue for patent infringement). To "grant" such a patent license to a
-party means to make such an agreement or commitment not to enforce a
-patent against the party.
-
- If you convey a covered work, knowingly relying on a patent license,
-and the Corresponding Source of the work is not available for anyone
-to copy, free of charge and under the terms of this License, through a
-publicly available network server or other readily accessible means,
-then you must either (1) cause the Corresponding Source to be so
-available, or (2) arrange to deprive yourself of the benefit of the
-patent license for this particular work, or (3) arrange, in a manner
-consistent with the requirements of this License, to extend the patent
-license to downstream recipients. "Knowingly relying" means you have
-actual knowledge that, but for the patent license, your conveying the
-covered work in a country, or your recipient's use of the covered work
-in a country, would infringe one or more identifiable patents in that
-country that you have reason to believe are valid.
-
- If, pursuant to or in connection with a single transaction or
-arrangement, you convey, or propagate by procuring conveyance of, a
-covered work, and grant a patent license to some of the parties
-receiving the covered work authorizing them to use, propagate, modify
-or convey a specific copy of the covered work, then the patent license
-you grant is automatically extended to all recipients of the covered
-work and works based on it.
-
- A patent license is "discriminatory" if it does not include within
-the scope of its coverage, prohibits the exercise of, or is
-conditioned on the non-exercise of one or more of the rights that are
-specifically granted under this License. You may not convey a covered
-work if you are a party to an arrangement with a third party that is
-in the business of distributing software, under which you make payment
-to the third party based on the extent of your activity of conveying
-the work, and under which the third party grants, to any of the
-parties who would receive the covered work from you, a discriminatory
-patent license (a) in connection with copies of the covered work
-conveyed by you (or copies made from those copies), or (b) primarily
-for and in connection with specific products or compilations that
-contain the covered work, unless you entered into that arrangement,
-or that patent license was granted, prior to 28 March 2007.
-
- Nothing in this License shall be construed as excluding or limiting
-any implied license or other defenses to infringement that may
-otherwise be available to you under applicable patent law.
-
- 12. No Surrender of Others' Freedom.
-
- If conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot convey a
-covered work so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you may
-not convey it at all. For example, if you agree to terms that obligate you
-to collect a royalty for further conveying from those to whom you convey
-the Program, the only way you could satisfy both those terms and this
-License would be to refrain entirely from conveying the Program.
-
- 13. Use with the GNU Affero General Public License.
-
- Notwithstanding any other provision of this License, you have
-permission to link or combine any covered work with a work licensed
-under version 3 of the GNU Affero General Public License into a single
-combined work, and to convey the resulting work. The terms of this
-License will continue to apply to the part which is the covered work,
-but the special requirements of the GNU Affero General Public License,
-section 13, concerning interaction through a network will apply to the
-combination as such.
-
- 14. Revised Versions of this License.
-
- The Free Software Foundation may publish revised and/or new versions of
-the GNU General Public License from time to time. Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
- Each version is given a distinguishing version number. If the
-Program specifies that a certain numbered version of the GNU General
-Public License "or any later version" applies to it, you have the
-option of following the terms and conditions either of that numbered
-version or of any later version published by the Free Software
-Foundation. If the Program does not specify a version number of the
-GNU General Public License, you may choose any version ever published
-by the Free Software Foundation.
-
- If the Program specifies that a proxy can decide which future
-versions of the GNU General Public License can be used, that proxy's
-public statement of acceptance of a version permanently authorizes you
-to choose that version for the Program.
-
- Later license versions may give you additional or different
-permissions. However, no additional obligations are imposed on any
-author or copyright holder as a result of your choosing to follow a
-later version.
-
- 15. Disclaimer of Warranty.
-
- THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
-APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
-HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
-OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
-THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
-IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
-ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
-
- 16. Limitation of Liability.
-
- IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
-THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
-GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
-USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
-DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
-PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
-EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
-SUCH DAMAGES.
-
- 17. Interpretation of Sections 15 and 16.
-
- If the disclaimer of warranty and limitation of liability provided
-above cannot be given local legal effect according to their terms,
-reviewing courts shall apply local law that most closely approximates
-an absolute waiver of all civil liability in connection with the
-Program, unless a warranty or assumption of liability accompanies a
-copy of the Program in return for a fee.
-
- END OF TERMS AND CONDITIONS
-
- How to Apply These Terms to Your New Programs
-
- If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
- To do so, attach the following notices to the program. It is safest
-to attach them to the start of each source file to most effectively
-state the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
-
- Copyright (C)
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see .
-
-Also add information on how to contact you by electronic and paper mail.
-
- If the program does terminal interaction, make it output a short
-notice like this when it starts in an interactive mode:
-
- Copyright (C)
- This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
- This is free software, and you are welcome to redistribute it
- under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License. Of course, your program's commands
-might be different; for a GUI interface, you would use an "about box".
-
- You should also get your employer (if you work as a programmer) or school,
-if any, to sign a "copyright disclaimer" for the program, if necessary.
-For more information on this, and how to apply and follow the GNU GPL, see
-.
-
- The GNU General Public License does not permit incorporating your program
-into proprietary programs. If your program is a subroutine library, you
-may consider it more useful to permit linking proprietary applications with
-the library. If this is what you want to do, use the GNU Lesser General
-Public License instead of this License. But first, please read
-.
diff --git a/ConsumesTracker.lua b/Main.lua
similarity index 58%
rename from ConsumesTracker.lua
rename to Main.lua
index 0dc6e9e..ef9593b 100644
--- a/ConsumesTracker.lua
+++ b/Main.lua
@@ -1,1551 +1,1639 @@
--- ConsumesTracker.lua
-
--- Metadata -------------------------------------------------------------------------------------------
-AddonName = "Consumes Tracker"
-Version = "1.4.1"
-VState = "multi character (beta)"
-WindowWidth = 310
-
--- Onload & Click/Drag Functionality ------------------------------------------------------------------
-function ConsumesTracker_OnLoad(self)
- self:RegisterForDrag("LeftButton")
- self:SetScript("OnDragStart", function() ConsumesTracker_OnDragStart(self) end)
- self:SetScript("OnDragStop", function() ConsumesTracker_OnDragStop(self) end)
- DEFAULT_CHAT_FRAME:AddMessage("|cff00ff00" .. AddonName .. " Loaded! (version " .. Version .. "-" .. VState .. ")|r |cff808080[Made by Horyoshi]|r")
-end
-
--- Click Handling -------------------------------------------------------------------------------------
-function ConsumesTracker_HandleClick(self, button)
- if not self then return end
- if button == "LeftButton" and not IsShiftKeyDown() then
- if ConsumeTracker_MainFrame and ConsumeTracker_MainFrame:IsShown() then
- ConsumeTracker_MainFrame:Hide()
- else
- ConsumeTracker_ShowMainWindow()
- end
- end
-end
-
--- Drag Functions -------------------------------------------------------------------------------------
-function ConsumesTracker_OnDragStart(self)
- if IsShiftKeyDown() then
- self:StartMoving()
- self.isMoving = true
- end
-end
-
-function ConsumesTracker_OnDragStop(self)
- if self and self.isMoving then
- self:StopMovingOrSizing()
- self.isMoving = false
- end
-end
-
--- Initialize SavedVariables ----------------------------------------------------------------------------
-if not ConsumeTracker_Settings then
- ConsumeTracker_Settings = {}
-end
-if not ConsumeTracker_Data then
- ConsumeTracker_Data = {}
-end
-
--- Event frame for updating data ----------------------------------------------------------------------
-local ConsumeTracker_EventFrame = CreateFrame("Frame")
-ConsumeTracker_EventFrame:RegisterEvent("PLAYER_LOGIN")
-ConsumeTracker_EventFrame:RegisterEvent("BAG_UPDATE")
-ConsumeTracker_EventFrame:RegisterEvent("BANKFRAME_OPENED")
-ConsumeTracker_EventFrame:RegisterEvent("PLAYERBANKSLOTS_CHANGED")
-ConsumeTracker_EventFrame:RegisterEvent("ITEM_LOCK_CHANGED")
-ConsumeTracker_EventFrame:RegisterEvent("MAIL_SHOW")
-ConsumeTracker_EventFrame:RegisterEvent("MAIL_INBOX_UPDATE")
-ConsumeTracker_EventFrame:RegisterEvent("MAIL_CLOSED")
-
-ConsumeTracker_EventFrame:SetScript("OnEvent", function()
- if event == "PLAYER_LOGIN" then
- ConsumeTracker_ScanPlayerInventory()
- ConsumeTracker_ScanPlayerBank()
- ConsumeTracker_ScanPlayerMail()
- elseif event == "BAG_UPDATE" then
- ConsumeTracker_ScanPlayerInventory()
- if BankFrame and BankFrame:IsShown() then
- ConsumeTracker_ScanPlayerBank()
- end
- if MailFrame and MailFrame:IsShown() then
- ConsumeTracker_ScanPlayerMail()
- end
- elseif event == "BANKFRAME_OPENED" then
- ConsumeTracker_ScanPlayerBank()
- elseif event == "PLAYERBANKSLOTS_CHANGED" then
- ConsumeTracker_ScanPlayerBank()
- ConsumeTracker_ScanPlayerInventory()
- elseif event == "ITEM_LOCK_CHANGED" then
- if BankFrame and BankFrame:IsShown() then
- ConsumeTracker_ScanPlayerInventory()
- ConsumeTracker_ScanPlayerBank()
- end
- if MailFrame and MailFrame:IsShown() then
- ConsumeTracker_ScanPlayerInventory()
- ConsumeTracker_ScanPlayerMail()
- end
- elseif event == "MAIL_SHOW" or event == "MAIL_INBOX_UPDATE" then
- ConsumeTracker_ScanPlayerMail()
- end
-end)
-
-
-
-function ConsumeTracker_CreateMainWindow()
- -- Main Frame
- ConsumeTracker_MainFrame = CreateFrame("Frame", "ConsumeTracker_MainFrame", UIParent)
- ConsumeTracker_MainFrame:SetWidth(WindowWidth)
- ConsumeTracker_MainFrame:SetHeight(512)
- ConsumeTracker_MainFrame:SetPoint("CENTER", UIParent, "CENTER")
- ConsumeTracker_MainFrame:SetFrameStrata("DIALOG")
- ConsumeTracker_MainFrame:SetMovable(true)
- ConsumeTracker_MainFrame:EnableMouse(true)
- ConsumeTracker_MainFrame:RegisterForDrag("LeftButton")
- ConsumeTracker_MainFrame:SetScript("OnDragStart", function()
- this:StartMoving()
- end)
- ConsumeTracker_MainFrame:SetScript("OnDragStop", function()
- this:StopMovingOrSizing()
- end)
-
- table.insert(UISpecialFrames, "ConsumeTracker_MainFrame")
-
- -- Background Texture
- local background = ConsumeTracker_MainFrame:CreateTexture(nil, "BACKGROUND")
- background:SetTexture("Interface\\DialogFrame\\UI-DialogBox-Background")
- background:SetPoint("TOPLEFT", ConsumeTracker_MainFrame, "TOPLEFT", 12, -12)
- background:SetPoint("BOTTOMRIGHT", ConsumeTracker_MainFrame, "BOTTOMRIGHT", -12, 12)
-
- -- Border
- ConsumeTracker_MainFrame:SetBackdrop({
- bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
- edgeFile = "Interface\\DialogFrame\\UI-DialogBox-Border",
- tile = true, tileSize = 32, edgeSize = 32,
- insets = { left = 11, right = 12, top = 12, bottom = 11 }
- })
- ConsumeTracker_MainFrame:SetBackdropColor(0.1, 0.1, 0.1, 1)
-
- -- Title Text
- local titleText = ConsumeTracker_MainFrame:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
- titleText:SetText(AddonName)
- titleText:SetPoint("TOP", ConsumeTracker_MainFrame, "TOP", 0, -2)
-
- -- Calculate the width of the title text and adjust the title background accordingly
- local titleWidth = titleText:GetStringWidth() + 160
-
- -- Title Background
- local titleBg = ConsumeTracker_MainFrame:CreateTexture(nil, "ARTWORK")
- titleBg:SetTexture("Interface\\DialogFrame\\UI-DialogBox-Header")
- titleBg:SetWidth(titleWidth)
- titleBg:SetHeight(64)
- titleBg:SetPoint("TOP", ConsumeTracker_MainFrame, "TOP", 0, 12)
-
-
- -- Close Button
- local closeButton = CreateFrame("Button", nil, ConsumeTracker_MainFrame, "UIPanelCloseButton")
- closeButton:SetWidth(32)
- closeButton:SetHeight(32)
- closeButton:SetPoint("TOPRIGHT", ConsumeTracker_MainFrame, "TOPRIGHT", -5, -5)
- closeButton:SetScript("OnClick", function()
- ConsumeTracker_MainFrame:Hide()
- end)
-
- -- Create a custom tooltip frame
- local tooltipFrame = CreateFrame("Frame", "ConsumeTrackerTooltip", UIParent)
- tooltipFrame:SetWidth(150)
- tooltipFrame:SetHeight(40)
- tooltipFrame:SetFrameStrata("TOOLTIP")
- tooltipFrame:SetBackdrop({
- bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
- edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
- tile = true, tileSize = 16, edgeSize = 16,
- insets = { left = 4, right = 4, top = 4, bottom = 4 }
- })
- tooltipFrame:SetBackdropColor(0, 0, 0, 1)
- tooltipFrame:Hide()
-
- -- Tooltip text
- local tooltipText = tooltipFrame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
- tooltipText:SetPoint("CENTER", tooltipFrame, "CENTER", 0, 0)
- tooltipFrame.text = tooltipText
-
- local function ShowTooltip(tab, text)
- tooltipFrame.text:SetText(text)
- tooltipFrame:SetPoint("BOTTOMLEFT", tab, "TOPLEFT", 0, 0)
- tooltipFrame:Show()
- end
-
- local function HideTooltip()
- tooltipFrame:Hide()
- end
-
- -- Tabs
- local tabs = {}
- local function CreateTab(name, texture, xOffset, tooltipText, tabIndex)
- local tab = CreateFrame("Button", name, ConsumeTracker_MainFrame)
- tab:SetWidth(36)
- tab:SetHeight(36)
- tab:SetPoint("TOPLEFT", ConsumeTracker_MainFrame, "TOPLEFT", xOffset, -30)
-
- -- Tab Icon
- local icon = tab:CreateTexture(nil, "ARTWORK")
- icon:SetTexture(texture)
- icon:SetWidth(36)
- icon:SetHeight(36)
- icon:SetPoint("CENTER", tab, "CENTER", 0, 0)
-
- tab.icon = icon
-
- -- Hover Glow
- local hoverTexture = tab:CreateTexture(nil, "HIGHLIGHT")
- hoverTexture:SetTexture("Interface\\Buttons\\CheckButtonHilight")
- hoverTexture:SetBlendMode("ADD")
- hoverTexture:SetAllPoints(tab)
-
- -- Active Highlight
- local activeHighlight = tab:CreateTexture(nil, "OVERLAY")
- activeHighlight:SetTexture("Interface\\Buttons\\CheckButtonHilight")
- activeHighlight:SetBlendMode("ADD")
- activeHighlight:SetAllPoints(tab)
- activeHighlight:SetWidth(36)
- activeHighlight:SetHeight(36)
- activeHighlight:Hide()
- tab.activeHighlight = activeHighlight
-
- -- Custom Tooltip Handlers
- tab:SetScript("OnEnter", function()
- ShowTooltip(tab, tooltipText)
- end)
- tab:SetScript("OnLeave", HideTooltip)
-
- -- Store tab for later
- tabs[tabIndex] = tab
-
- return tab
- end
-
- -- Tracker Tab
- local tab1 = CreateTab("ConsumeTracker_MainFrameTab1", "Interface\\Icons\\INV_Potion_93", 30, "Consumables Tracker", 1)
- tab1:SetScript("OnClick", function()
- ConsumeTracker_ShowTab(1)
- end)
-
- -- Options Tab
- local tab2 = CreateTab("ConsumeTracker_MainFrameTab2", "Interface\\Icons\\INV_Misc_Gear_01", 80, "Options", 2)
- tab2:SetScript("OnClick", function()
- ConsumeTracker_ShowTab(2)
- end)
-
- -- Characters Tab
- local tab3 = CreateTab("ConsumeTracker_MainFrameTab3", "Interface\\Icons\\Ability_Rogue_Disguise", 130, "Characters", 3)
- tab3:SetScript("OnClick", function()
- ConsumeTracker_ShowTab(3)
- end)
-
- -- Add Grey Line Under Tabs
- local tabsLine = ConsumeTracker_MainFrame:CreateTexture(nil, "ARTWORK")
- tabsLine:SetHeight(1)
- tabsLine:SetPoint("TOPLEFT", ConsumeTracker_MainFrame, "TOPLEFT", 12, -72)
- tabsLine:SetPoint("TOPRIGHT", ConsumeTracker_MainFrame, "TOPRIGHT", -12, -72)
- tabsLine:SetTexture("Interface\\Buttons\\WHITE8x8")
- tabsLine:SetVertexColor(0.4, 0.4, 0.4, 1)
-
- -- Tab Content
- ConsumeTracker_MainFrame.tabs = {}
- local tab1Content = CreateFrame("Frame", nil, ConsumeTracker_MainFrame)
- tab1Content:SetWidth(WindowWidth - 50)
- tab1Content:SetHeight(380)
- tab1Content:SetPoint("TOPLEFT", ConsumeTracker_MainFrame, "TOPLEFT", 30, -80)
- ConsumeTracker_MainFrame.tabs[1] = tab1Content
-
- local tab2Content = CreateFrame("Frame", nil, ConsumeTracker_MainFrame)
- tab2Content:SetWidth(WindowWidth - 50)
- tab2Content:SetHeight(380)
- tab2Content:SetPoint("TOPLEFT", ConsumeTracker_MainFrame, "TOPLEFT", 30, -80)
- ConsumeTracker_MainFrame.tabs[2] = tab2Content
-
- local tab3Content = CreateFrame("Frame", nil, ConsumeTracker_MainFrame)
- tab3Content:SetWidth(WindowWidth - 50)
- tab3Content:SetHeight(380)
- tab3Content:SetPoint("TOPLEFT", ConsumeTracker_MainFrame, "TOPLEFT", 30, -80)
- ConsumeTracker_MainFrame.tabs[3] = tab3Content
-
- -- Footer Text
- local footerText = ConsumeTracker_MainFrame:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
- footerText:SetText("Made by Horyoshi (v" .. Version .. "-" .. VState .. ")")
- footerText:SetTextColor(0.6, 0.6, 0.6)
- footerText:SetPoint("BOTTOM", ConsumeTracker_MainFrame, "BOTTOM", 0, 15)
-
- -- Add Grey Line Above Footer
- local footerLine = ConsumeTracker_MainFrame:CreateTexture(nil, "ARTWORK")
- footerLine:SetHeight(1)
- footerLine:SetPoint("BOTTOMLEFT", ConsumeTracker_MainFrame, "BOTTOMLEFT", 12, 30)
- footerLine:SetPoint("BOTTOMRIGHT", ConsumeTracker_MainFrame, "BOTTOMRIGHT", -12, 30)
- footerLine:SetTexture("Interface\\Buttons\\WHITE8x8")
- footerLine:SetVertexColor(0.4, 0.4, 0.4, 1)
-
- -- Tab Switching Function
- function ConsumeTracker_ShowTab(tabIndex)
- for index, content in pairs(ConsumeTracker_MainFrame.tabs) do
- if index == tabIndex then
- content:Show()
- tabs[index].activeHighlight:Show()
- else
- content:Hide()
- tabs[index].activeHighlight:Hide()
- end
- end
- end
-
- -- Set Default Tab
- ConsumeTracker_ShowTab(1)
-
- -- Add Custom Content for Tabs
- ConsumeTracker_CreateTrackerContent(tab1Content)
- ConsumeTracker_CreateOptionsContent(tab2Content)
- ConsumeTracker_CreateCharactersContent(tab3Content)
-end
-
-
-
--- Function to show the main window
-function ConsumeTracker_ShowMainWindow()
- if not ConsumeTracker_MainFrame then
- ConsumeTracker_CreateMainWindow()
- end
- ConsumeTracker_MainFrame:Show()
- -- Scan inventory when the window is opened
- ConsumeTracker_ScanPlayerInventory()
- -- Only scan bank and mail if they are open
- if BankFrame and BankFrame:IsShown() then
- ConsumeTracker_ScanPlayerBank()
- end
- if MailFrame and MailFrame:IsShown() then
- ConsumeTracker_ScanPlayerMail()
- end
- -- Update the tracker content
- ConsumeTracker_UpdateTrackerContent()
-end
-
--- Function to switch tabs
-function ConsumeTracker_ShowTab(tabIndex)
- if not ConsumeTracker_MainFrame or not ConsumeTracker_MainFrame.tabs then return end
- for i, tabContent in pairs(ConsumeTracker_MainFrame.tabs) do
- if i == tabIndex then
- tabContent:Show()
- -- Set the tab button to active
- local tabButton = getglobal("ConsumeTracker_MainFrameTab" .. i)
- tabButton:SetNormalTexture("Interface\\OptionsFrame\\UI-OptionsFrame-ActiveTab")
- else
- tabContent:Hide()
- -- Set the tab button to inactive
- local tabButton = getglobal("ConsumeTracker_MainFrameTab" .. i)
- tabButton:SetNormalTexture("Interface\\OptionsFrame\\UI-OptionsFrame-InActiveTab")
- end
- end
-end
-
--- Function to create the content of the Tracker tab
-function ConsumeTracker_CreateTrackerContent(parentFrame)
- -- Scroll Frame
- local scrollFrame = CreateFrame("ScrollFrame", "ConsumeTracker_ConsumablesScrollFrame", parentFrame)
- scrollFrame:SetPoint("TOPLEFT", parentFrame, "TOPLEFT", 0, 0)
- scrollFrame:SetPoint("BOTTOMRIGHT", parentFrame, "BOTTOMRIGHT", -20, 0)
- scrollFrame:EnableMouseWheel(true)
-
- -- Define the OnMouseWheelHandler method
- function scrollFrame:OnMouseWheelHandler(delta)
- local current = self:GetVerticalScroll()
- local maxScroll = self.range or 0
- local newScroll = math.max(0, math.min(current - (delta * 10), maxScroll))
- self:SetVerticalScroll(newScroll)
- parentFrame.scrollBar:SetValue(newScroll)
- end
-
- -- Set the OnMouseWheel script
- scrollFrame:SetScript("OnMouseWheel", function()
- local delta = arg1
- this:OnMouseWheelHandler(delta)
- end)
-
- -- Scroll Child Frame
- local scrollChild = CreateFrame("Frame", nil, scrollFrame)
- scrollChild:SetWidth(WindowWidth - 10)
- scrollChild:SetHeight(1) -- Will adjust later
- scrollFrame:SetScrollChild(scrollChild)
-
- -- Initialize tables to store category and consumable labels
- parentFrame.categoryLabels = {}
- parentFrame.labels = {}
-
- -- Sort categories by name for consistent order
- local sortedCategories = {}
- for categoryName, _ in pairs(consumablesCategories) do
- table.insert(sortedCategories, categoryName)
- end
- table.sort(sortedCategories, function(a, b) return a < b end)
-
- local index = 0 -- Initialize index for positioning
-
- for _, categoryName in ipairs(sortedCategories) do
- local consumables = consumablesCategories[categoryName]
-
- -- Create category label
- local categoryLabel = scrollChild:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
- categoryLabel:SetText(categoryName)
- categoryLabel:SetTextColor(1, 1, 1)
- categoryLabel:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", 0, -index * 16)
- categoryLabel:Hide() -- Initially hidden
- parentFrame.categoryLabels[categoryName] = categoryLabel
- index = index + 1 -- Reserve space for category label
-
- -- Sort consumables by name
- table.sort(consumables, function(a, b) return a.name < b.name end)
-
- for _, consumable in ipairs(consumables) do
- local itemID = consumable.id
- local itemName = consumable.name
-
- -- Create consumable label
- local label = scrollChild:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
- label:SetText(itemName)
- label:SetTextColor(1, 1, 1) -- White color
- label:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", 20, -index * 16) -- Indent consumables
- label:Hide() -- Initially hidden
- parentFrame.labels[itemID] = label
-
- -- Create a frame for tooltip
- local tooltipFrame = CreateFrame("Frame", nil, scrollChild)
- tooltipFrame:SetWidth(220)
- tooltipFrame:SetHeight(16)
- tooltipFrame:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", 20, -index * 16)
- tooltipFrame:EnableMouse(true)
- tooltipFrame:SetScript("OnEnter", function()
- ConsumeTracker_ShowConsumableTooltip(itemID)
- end)
- tooltipFrame:SetScript("OnLeave", function()
- if ConsumeTracker_CustomTooltip then
- ConsumeTracker_CustomTooltip:Hide()
- end
- end)
-
- -- Enable mouse wheel and pass events to the scroll frame
- tooltipFrame:EnableMouseWheel(true)
- tooltipFrame:SetScript("OnMouseWheel", function()
- local delta = arg1
- local scrollFrame = parentFrame.scrollFrame
- if scrollFrame and scrollFrame:IsVisible() then
- scrollFrame:OnMouseWheelHandler(delta)
- end
- end)
-
- -- Associate tooltip frame with the label
- label.tooltipFrame = tooltipFrame
-
- index = index + 1 -- Increment index for next label
- end
-
- -- Add spacing after each category
- index = index + 1
- end
-
- -- Adjust the height of the scroll child
- scrollChild.contentHeight = index * 16
- scrollChild:SetHeight(scrollChild.contentHeight)
-
- -- Message Label
- local messageLabel = scrollChild:CreateFontString(nil, "OVERLAY", "GameFontNormal")
- messageLabel:SetText("|cffff0000No consumables selected|r\n\n|cffffffffClick on |roptions|cffffffff to get started|r")
- messageLabel:SetPoint("CENTER", ConsumeTracker_MainFrame, "CENTER", 0, 0)
- messageLabel:Hide() -- Initially hidden
- parentFrame.messageLabel = messageLabel
-
- -- Scroll Bar
- local scrollBar = CreateFrame("Slider", "ConsumeTracker_TrackerScrollBar", parentFrame)
- scrollBar:SetPoint("TOPRIGHT", parentFrame, "TOPRIGHT", -2, -16)
- scrollBar:SetPoint("BOTTOMRIGHT", parentFrame, "BOTTOMRIGHT", -2, 16)
- scrollBar:SetWidth(16)
- scrollBar:SetOrientation('VERTICAL')
- scrollBar:SetThumbTexture("Interface\\Buttons\\UI-ScrollBar-Knob")
- scrollBar:SetBackdrop({
- bgFile = "Interface\\Buttons\\UI-SliderBar-Background",
- edgeFile = "Interface\\Buttons\\UI-SliderBar-Border",
- tile = true, tileSize = 8, edgeSize = 8,
- insets = { left = 3, right = 3, top = 3, bottom = 3 }
- })
- scrollBar:SetScript("OnValueChanged", function()
- local value = this:GetValue()
- parentFrame.scrollFrame:SetVerticalScroll(value)
- end)
- parentFrame.scrollBar = scrollBar
- parentFrame.scrollFrame = scrollFrame
- parentFrame.scrollChild = scrollChild
-
- -- Update the scrollbar
- ConsumeTracker_UpdateTrackerScrollBar()
-end
-
-function ConsumeTracker_CreateOptionsContent(parentFrame)
- -- Create Search Input
- local searchBox = CreateFrame("EditBox", "ConsumeTracker_SearchBox", parentFrame, "InputBoxTemplate")
- searchBox:SetWidth(WindowWidth - 50)
- searchBox:SetHeight(20)
- searchBox:SetPoint("TOPLEFT", parentFrame, "TOPLEFT", 0, -5)
- searchBox:SetAutoFocus(false)
- searchBox:SetText("Search...")
- searchBox:SetTextColor(0.5, 0.5, 0.5) -- Placeholder text color
-
- searchBox:SetScript("OnEditFocusGained", function()
- if this:GetText() == "Search..." then
- this:SetText("")
- this:SetTextColor(1, 1, 1) -- User input text color
- end
- end)
-
- searchBox:SetScript("OnEditFocusLost", function()
- if this:GetText() == "" then
- this:SetText("Search...")
- this:SetTextColor(0.5, 0.5, 0.5) -- Placeholder text color
- end
- end)
-
- -- Function to update the filter
- local function UpdateFilter()
- local filterText = string.lower(searchBox:GetText())
- if filterText == "search..." then filterText = "" end
- local index = 0 -- Position index
- local lineHeight = 18
-
- -- Iterate over categories
- for _, categoryInfo in ipairs(parentFrame.categoryInfo) do
- local categoryLabel = categoryInfo.label
- local anyOptionVisible = false
-
- -- First, check if any options in the category match the filter
- for _, optionInfo in ipairs(categoryInfo.options) do
- local itemNameLower = string.lower(optionInfo.name)
-
- if filterText == "" or string.find(itemNameLower, filterText, 1, true) then
- anyOptionVisible = true
- break
- end
- end
-
- -- If any options are visible, show the category label
- if anyOptionVisible then
- categoryLabel:SetPoint("TOPLEFT", parentFrame.scrollChild, "TOPLEFT", 0, - (index) * lineHeight)
- categoryLabel:Show()
- index = index + 1
-
- -- Now, position and show the matching options
- for _, optionInfo in ipairs(categoryInfo.options) do
- local optionFrame = optionInfo.frame
- local itemNameLower = string.lower(optionInfo.name)
-
- if filterText == "" or string.find(itemNameLower, filterText, 1, true) then
- -- Show the option
- optionFrame:SetPoint("TOPLEFT", parentFrame.scrollChild, "TOPLEFT", 0, - (index) * lineHeight)
- optionFrame:Show()
- index = index + 1
- else
- optionFrame:Hide()
- end
- end
-
- -- Add extra spacing after the category
- index = index + 1 -- Add one extra line of spacing between categories
-
- else
- categoryLabel:Hide()
- -- Hide all options under this category
- for _, optionInfo in ipairs(categoryInfo.options) do
- optionInfo.frame:Hide()
- end
- end
- end
-
- -- Adjust the scroll child height
- parentFrame.scrollChild.contentHeight = index * lineHeight
- parentFrame.scrollChild:SetHeight(parentFrame.scrollChild.contentHeight)
-
- -- Update the scrollbar
- ConsumeTracker_UpdateOptionsScrollBar()
- end
-
- searchBox:SetScript("OnTextChanged", function()
- UpdateFilter()
- end)
-
- -- Adjust the size of the scroll frame to make room for the search box and add extra spacing
- local scrollFrame = CreateFrame("ScrollFrame", "ConsumeTracker_OptionsScrollFrame", parentFrame)
- scrollFrame:SetPoint("TOPLEFT", parentFrame, "TOPLEFT", 0, -40) -- Changed from -30 to -50 for extra spacing
- scrollFrame:SetPoint("BOTTOMRIGHT", parentFrame, "BOTTOMRIGHT", -20, 0)
- scrollFrame:EnableMouseWheel(true)
- scrollFrame:SetScript("OnMouseWheel", function()
- local delta = arg1
- local current = this:GetVerticalScroll()
- local maxScroll = this.maxScroll or 0
- local newScroll = math.max(0, math.min(current - (delta * 20), maxScroll))
- this:SetVerticalScroll(newScroll)
- parentFrame.scrollBar:SetValue(newScroll)
- end)
-
- -- Scroll Child Frame
- local scrollChild = CreateFrame("Frame", nil, scrollFrame)
- scrollChild:SetWidth(WindowWidth - 10)
- scrollChild:SetHeight(1) -- Will adjust later
- scrollFrame:SetScrollChild(scrollChild)
- parentFrame.scrollChild = scrollChild
- parentFrame.scrollFrame = scrollFrame
-
- -- Sort categories alphabetically
- local sortedCategories = {}
- for categoryName, _ in pairs(consumablesCategories) do
- table.insert(sortedCategories, categoryName)
- end
- table.sort(sortedCategories)
-
- -- Checkboxes
- parentFrame.checkboxes = {}
- parentFrame.categoryInfo = {}
- local index = 0 -- Position index
- local lineHeight = 18
-
- -- Iterate over sorted categories
- for _, categoryName in ipairs(sortedCategories) do
- local consumables = consumablesCategories[categoryName]
-
- -- Create category label
- local categoryLabel = scrollChild:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
- categoryLabel:SetText(categoryName)
- categoryLabel:SetTextColor(1, 1, 1)
- categoryLabel:Show()
-
- local categoryInfo = { name = categoryName, label = categoryLabel, options = {} }
-
- index = index + 1 -- Position for the category label
-
- local numOptionsInCategory = 0 -- Counter for options in this category
-
- -- Sort the consumables by name
- table.sort(consumables, function(a, b) return a.name < b.name end)
-
- -- For each consumable in the category
- for _, consumable in ipairs(consumables) do
- local currentItemID = consumable.id
- local itemName = consumable.name
-
- -- Create a frame that encompasses the checkbox and label
- local optionFrame = CreateFrame("Frame", "ConsumeTracker_OptionsFrame" .. index, scrollChild)
- optionFrame:SetWidth(WindowWidth - 10)
- optionFrame:SetHeight(lineHeight)
- optionFrame:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", 0, - (index) * lineHeight)
- optionFrame:Show()
-
- -- Create the checkbox inside the optionFrame
- local checkbox = CreateFrame("CheckButton", "ConsumeTracker_OptionsCheckbox" .. index, optionFrame)
- checkbox:SetWidth(16)
- checkbox:SetHeight(16)
- checkbox:SetPoint("LEFT", optionFrame, "LEFT", 0, 0)
-
- -- Create Textures for the checkbox
- checkbox:SetNormalTexture("Interface\\Buttons\\UI-CheckBox-Up")
- checkbox:SetPushedTexture("Interface\\Buttons\\UI-CheckBox-Down")
- checkbox:SetHighlightTexture("Interface\\Buttons\\UI-CheckBox-Highlight")
- checkbox:SetCheckedTexture("Interface\\Buttons\\UI-CheckBox-Check")
-
- -- Create FontString for label
- local label = optionFrame:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
- label:SetPoint("LEFT", checkbox, "RIGHT", 4, 0)
- label:SetText(itemName)
-
- -- Set up the checkbox OnClick handler
- checkbox:SetScript("OnClick", function()
- ConsumeTracker_Settings[currentItemID] = checkbox:GetChecked()
- ConsumeTracker_UpdateTrackerContent()
- end)
- -- Load saved setting
- if ConsumeTracker_Settings[currentItemID] then
- checkbox:SetChecked(true)
- end
- parentFrame.checkboxes[currentItemID] = checkbox
-
- -- Make the optionFrame clickable
- optionFrame:EnableMouse(true)
- optionFrame:SetScript("OnMouseDown", function()
- checkbox:Click()
- end)
-
- -- Mouseover Tooltip
- optionFrame:SetScript("OnEnter", function()
- ConsumeTracker_ShowOptionsTooltip(currentItemID)
- end)
- optionFrame:SetScript("OnLeave", function()
- if ConsumeTracker_OptionsTooltip then
- ConsumeTracker_OptionsTooltip:Hide()
- end
- end)
-
- -- Store option info
- table.insert(categoryInfo.options, { frame = optionFrame, name = itemName })
-
- index = index + 1 -- Increment index after adding option
- numOptionsInCategory = numOptionsInCategory + 1 -- Increment options count
- end
-
- -- Position the category label above its options
- categoryLabel:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", 0, - (index - numOptionsInCategory - 1) * lineHeight)
-
- -- Store category info
- table.insert(parentFrame.categoryInfo, categoryInfo)
-
- -- Add extra spacing after the category
- index = index + 1 -- Add one extra line of spacing between categories
- end
-
- -- Adjust the scroll child height
- scrollChild.contentHeight = (index - 1) * lineHeight
- scrollChild:SetHeight(scrollChild.contentHeight)
-
- -- Scroll Bar
- local scrollBar = CreateFrame("Slider", "ConsumeTracker_OptionsScrollBar", parentFrame)
- scrollBar:SetPoint("TOPRIGHT", parentFrame, "TOPRIGHT", -2, -56) -- Adjusted for extra spacing
- scrollBar:SetPoint("BOTTOMRIGHT", parentFrame, "BOTTOMRIGHT", -2, 16)
- scrollBar:SetWidth(16)
- scrollBar:SetOrientation('VERTICAL')
- scrollBar:SetThumbTexture("Interface\\Buttons\\UI-ScrollBar-Knob")
- scrollBar:SetBackdrop({
- bgFile = "Interface\\Buttons\\UI-SliderBar-Background",
- edgeFile = "Interface\\Buttons\\UI-SliderBar-Border",
- tile = true, tileSize = 8, edgeSize = 8,
- insets = { left = 3, right = 3, top = 3, bottom = 3 }
- })
- scrollBar:SetScript("OnValueChanged", function()
- local value = this:GetValue()
- parentFrame.scrollFrame:SetVerticalScroll(value)
- end)
- parentFrame.scrollBar = scrollBar
-
- -- Update the scrollbar
- ConsumeTracker_UpdateOptionsScrollBar()
-end
-
-
-function ConsumeTracker_CreateCharactersContent(parentFrame)
- -- Scroll Frame
- local scrollFrame = CreateFrame("ScrollFrame", "ConsumeTracker_CharactersScrollFrame", parentFrame)
- scrollFrame:SetPoint("TOPLEFT", parentFrame, "TOPLEFT", 0, 0)
- scrollFrame:SetPoint("BOTTOMRIGHT", parentFrame, "BOTTOMRIGHT", -20, 0)
- scrollFrame:EnableMouseWheel(true)
- scrollFrame:SetScript("OnMouseWheel", function()
- local delta = arg1
- local current = scrollFrame:GetVerticalScroll()
- local maxScroll = scrollFrame.maxScroll or 0
- local newScroll = math.max(0, math.min(current - (delta * 20), maxScroll))
- scrollFrame:SetVerticalScroll(newScroll)
- if parentFrame.scrollBar then
- parentFrame.scrollBar:SetValue(newScroll)
- end
- end)
-
- -- Scroll Child Frame
- local scrollChild = CreateFrame("Frame", nil, scrollFrame)
- scrollChild:SetWidth(WindowWidth - 10)
- scrollChild:SetHeight(1)
- scrollFrame:SetScrollChild(scrollChild)
-
- -- Initialize variables
- parentFrame.checkboxes = {}
- local index = 0 -- Position index
-
- -- Ensure settings table for characters exists
- ConsumeTracker_Settings["Characters"] = ConsumeTracker_Settings["Characters"] or {}
-
- -- Get list of characters
- local realmName = GetRealmName()
- local faction = UnitFactionGroup("player")
- local playerName = UnitName("player")
-
- local characterList = {}
-
- -- Ensure data structure exists
- if ConsumeTracker_Data[realmName] and ConsumeTracker_Data[realmName][faction] then
- for characterName, _ in pairs(ConsumeTracker_Data[realmName][faction]) do
- table.insert(characterList, characterName)
- end
- end
-
- -- Ensure current character is included
- local playerInList = false
- for _, name in ipairs(characterList) do
- if name == playerName then
- playerInList = true
- break
- end
- end
- if not playerInList then
- table.insert(characterList, playerName)
- end
-
- -- Sort the character list
- table.sort(characterList)
-
- -- Create FontString for title
- local title = scrollChild:CreateFontString(nil, "OVERLAY", "GameFontNormal")
- title:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", 0, 0) -- Offset from the top
- title:SetText("Select Characters to Track")
- title:SetTextColor(1, 1, 1)
-
- -- Offset index to start below the title
- local startYOffset = 20
-
- -- For each character
- for _, characterName in ipairs(characterList) do
- index = index + 1
-
- -- Create a local copy of characterName for the closure
- local currentCharacterName = characterName
-
- -- Create a frame that encompasses the checkbox and label
- local optionFrame = CreateFrame("Frame", "ConsumeTracker_CharacterFrame" .. index, scrollChild)
- optionFrame:SetWidth(WindowWidth - 10)
- optionFrame:SetHeight(18)
- optionFrame:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", 0, -(startYOffset + (index - 1) * 20))
-
- -- Create the checkbox inside the optionFrame
- local checkbox = CreateFrame("CheckButton", "ConsumeTracker_CharacterCheckbox" .. index, optionFrame)
- checkbox:SetWidth(16)
- checkbox:SetHeight(16)
- checkbox:SetPoint("LEFT", optionFrame, "LEFT", 0, 0)
-
- -- Create Textures for the checkbox
- checkbox:SetNormalTexture("Interface\\Buttons\\UI-CheckBox-Up")
- checkbox:SetPushedTexture("Interface\\Buttons\\UI-CheckBox-Down")
- checkbox:SetHighlightTexture("Interface\\Buttons\\UI-CheckBox-Highlight")
- checkbox:SetCheckedTexture("Interface\\Buttons\\UI-CheckBox-Check")
-
- -- Create FontString for label
- local label = optionFrame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
- label:SetPoint("LEFT", checkbox, "RIGHT", 4, 0)
- label:SetText(currentCharacterName)
-
- -- Set up the checkbox OnClick handler
- checkbox:SetScript("OnClick", function()
- if checkbox:GetChecked() then
- ConsumeTracker_Settings["Characters"][currentCharacterName] = true
- else
- ConsumeTracker_Settings["Characters"][currentCharacterName] = false
- end
- ConsumeTracker_UpdateTrackerContent()
- end)
- -- Load saved setting
- if ConsumeTracker_Settings["Characters"][currentCharacterName] == nil then
- -- Default to checked
- checkbox:SetChecked(true)
- ConsumeTracker_Settings["Characters"][currentCharacterName] = true
- else
- checkbox:SetChecked(ConsumeTracker_Settings["Characters"][currentCharacterName])
- end
- parentFrame.checkboxes[currentCharacterName] = checkbox
-
- -- Make the optionFrame clickable (so clicking on the label checks/unchecks the box)
- optionFrame:EnableMouse(true)
- optionFrame:SetScript("OnMouseDown", function()
- checkbox:Click()
- end)
- end
-
- -- Adjust the scroll child height
- scrollChild.contentHeight = startYOffset + index * 20
- scrollChild:SetHeight(scrollChild.contentHeight)
-
- -- Scroll Bar
- local scrollBar = CreateFrame("Slider", "ConsumeTracker_CharactersScrollBar", parentFrame)
- scrollBar:SetPoint("TOPRIGHT", parentFrame, "TOPRIGHT", -2, -16)
- scrollBar:SetPoint("BOTTOMRIGHT", parentFrame, "BOTTOMRIGHT", -2, 16)
- scrollBar:SetWidth(16)
- scrollBar:SetOrientation('VERTICAL')
- scrollBar:SetThumbTexture("Interface\\Buttons\\UI-ScrollBar-Knob")
- scrollBar:SetBackdrop({
- bgFile = "Interface\\Buttons\\UI-SliderBar-Background",
- edgeFile = "Interface\\Buttons\\UI-SliderBar-Border",
- tile = true, tileSize = 8, edgeSize = 8,
- insets = { left = 3, right = 3, top = 3, bottom = 3 }
- })
- scrollBar:SetScript("OnValueChanged", function()
- local value = scrollBar:GetValue()
- scrollFrame:SetVerticalScroll(value)
- end)
- parentFrame.scrollBar = scrollBar
- parentFrame.scrollFrame = scrollFrame
- parentFrame.scrollChild = scrollChild
-
- -- Update the scrollbar
- ConsumeTracker_UpdateCharactersScrollBar()
-end
-
-
-function ConsumeTracker_UpdateTrackerContent()
- if not ConsumeTracker_MainFrame or not ConsumeTracker_MainFrame.tabs or not ConsumeTracker_MainFrame.tabs[1] then
- return
- end
-
- local trackerFrame = ConsumeTracker_MainFrame.tabs[1]
- local realmName = GetRealmName()
- local faction = UnitFactionGroup("player")
- local playerName = UnitName("player")
-
- -- Ensure data structure exists
- if not ConsumeTracker_Data[realmName] or not ConsumeTracker_Data[realmName][faction] then
- return
- end
- local data = ConsumeTracker_Data[realmName][faction]
-
- -- Check if bank and mail have been scanned for current character
- local currentCharData = data[playerName]
- local bankScanned = currentCharData and currentCharData["bank"] ~= nil
- local mailScanned = currentCharData and currentCharData["mail"] ~= nil
-
- -- If bank and mail have not been scanned, show message and hide item labels
- if not bankScanned or not mailScanned then
- -- Hide all labels
- for _, label in pairs(trackerFrame.labels) do
- label:Hide()
- if label.tooltipFrame then
- label.tooltipFrame:Hide()
- end
- end
- -- Hide category labels
- for _, categoryLabel in pairs(trackerFrame.categoryLabels) do
- categoryLabel:Hide()
- end
-
- -- Show message
- trackerFrame.messageLabel:SetText("|cffff0000This character is not scanned yet|r\n\n|cffffffffOpen your |rBank|cffffffff and |rMail |cffffffffto get started|r")
- trackerFrame.messageLabel:Show()
-
- -- Adjust scroll child height
- trackerFrame.scrollChild:SetHeight(50)
-
- -- Update the tracker scrollbar
- ConsumeTracker_UpdateTrackerScrollBar()
-
- return
- end
-
- -- Proceed with normal content update
- local index = 0 -- Positioning index for items
- local totalCounts = {} -- Track total counts for each item
- local hasAnyVisibleItems = false -- Track if any items are visible
-
- -- Sort categories alphabetically for consistent order
- local sortedCategories = {}
- for categoryName, _ in pairs(consumablesCategories) do
- table.insert(sortedCategories, categoryName)
- end
- table.sort(sortedCategories)
-
- -- Hide all labels initially to ensure proper cleanup
- for _, label in pairs(trackerFrame.labels) do
- label:Hide()
- if label.tooltipFrame then
- label.tooltipFrame:Hide()
- end
- end
-
- -- Hide all category labels initially
- for _, categoryLabel in pairs(trackerFrame.categoryLabels) do
- categoryLabel:Hide()
- end
-
- -- Ensure character settings exist
- ConsumeTracker_Settings["Characters"] = ConsumeTracker_Settings["Characters"] or {}
-
- -- Iterate over categories
- for _, categoryName in ipairs(sortedCategories) do
- local consumables = consumablesCategories[categoryName]
- local hasVisibleItems = false
- local categoryLabel = trackerFrame.categoryLabels[categoryName]
-
- -- Ensure the category label exists
- if not categoryLabel then
- -- Create category label dynamically if missing
- categoryLabel = trackerFrame.scrollChild:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
- categoryLabel:SetText(categoryName)
- categoryLabel:SetTextColor(1, 1, 1)
- trackerFrame.categoryLabels[categoryName] = categoryLabel
- end
-
- -- Position category label (always above items)
- categoryLabel:SetPoint("TOPLEFT", trackerFrame.scrollChild, "TOPLEFT", 0, -index * 16)
- categoryLabel:Hide() -- Initially hidden
-
- index = index + 1 -- Reserve space for the category label
-
- -- Calculate totals and show items if enabled
- for _, consumable in ipairs(consumables) do
- local itemID = consumable.id
- if ConsumeTracker_Settings[itemID] then
- hasVisibleItems = true
- hasAnyVisibleItems = true -- Set to true when an item is displayed
- totalCounts[itemID] = 0 -- Initialize count
-
- -- Sum counts across all selected characters
- for character, charData in pairs(data) do
- if ConsumeTracker_Settings["Characters"][character] == true then
- -- Proceed with counting
- local inventory = charData["inventory"] and charData["inventory"][itemID] or 0
- local bank = charData["bank"] and charData["bank"][itemID] or 0
- local mail = charData["mail"] and charData["mail"][itemID] or 0
- totalCounts[itemID] = totalCounts[itemID] + inventory + bank + mail
- end
- end
-
- -- Show and position item label
- local label = trackerFrame.labels[itemID]
- if not label then
- -- Create the label dynamically if missing
- label = trackerFrame.scrollChild:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
- trackerFrame.labels[itemID] = label
- -- Tooltip frame
- local tooltipFrame = CreateFrame("Frame", nil, trackerFrame.scrollChild)
- tooltipFrame:SetWidth(WindowWidth - 30)
- tooltipFrame:SetHeight(16)
- tooltipFrame:EnableMouse(true)
- tooltipFrame:SetScript("OnEnter", function() ConsumeTracker_ShowConsumableTooltip(itemID) end)
- tooltipFrame:SetScript("OnLeave", function()
- if ConsumeTracker_CustomTooltip then
- ConsumeTracker_CustomTooltip:Hide()
- end
- end)
- label.tooltipFrame = tooltipFrame
- end
-
- local totalCount = totalCounts[itemID]
- label:SetText(consumable.name .. " (" .. totalCount .. ")")
- label:SetPoint("TOPLEFT", trackerFrame.scrollChild, "TOPLEFT", 20, -index * 16)
- label:Show()
-
- -- Adjust label color based on count
- if totalCount == 0 then
- label:SetTextColor(1, 0, 0) -- Red
- elseif totalCount < 10 then
- label:SetTextColor(1, 0.4, 0) -- Orange
- elseif totalCount <= 20 then
- label:SetTextColor(1, 0.85, 0) -- Yellow
- else
- label:SetTextColor(0, 1, 0) -- Green
- end
-
- -- Show tooltip frame
- if label.tooltipFrame then
- label.tooltipFrame:SetPoint("TOPLEFT", trackerFrame.scrollChild, "TOPLEFT", 20, -index * 16)
- label.tooltipFrame:SetWidth(label:GetStringWidth())
- label.tooltipFrame:SetHeight(16)
- label.tooltipFrame:Show()
- end
-
- index = index + 1
- end
- end
-
- -- Show the category label if it has visible items
- if hasVisibleItems then
- categoryLabel:Show()
- else
- index = index - 1 -- Remove extra space if no items
- end
- end
-
- -- Adjust scroll child height based on the total number of items
- local contentHeight = index * 16
- if contentHeight < 50 then
- contentHeight = 50 -- Minimum height to display the message label
- end
- trackerFrame.scrollChild:SetHeight(contentHeight)
-
- if not hasAnyVisibleItems then
- -- Show message when no items are selected
- trackerFrame.messageLabel:SetText("|cffff0000No consumables selected|r\n\n|cffffffffClick on |roptions|cffffffff to get started|r")
- trackerFrame.messageLabel:Show()
- else
- -- Hide the message label as we have content to display
- trackerFrame.messageLabel:Hide()
- end
-
- -- Update the tracker scrollbar
- ConsumeTracker_UpdateTrackerScrollBar()
-end
-
-
-
-function ConsumeTracker_UpdateTrackerScrollBar()
- local trackerFrame = ConsumeTracker_MainFrame.tabs[1]
- local scrollBar = trackerFrame.scrollBar
- local scrollFrame = trackerFrame.scrollFrame
- local scrollChild = trackerFrame.scrollChild
-
- local totalHeight = scrollChild:GetHeight()
- local shownHeight = trackerFrame:GetHeight() - 20 -- Account for padding/margins
-
- if totalHeight > shownHeight then
- local maxScroll = totalHeight - shownHeight
- scrollFrame.range = maxScroll -- Set the scroll range
- scrollBar:SetMinMaxValues(0, maxScroll)
- scrollBar:SetValue(math.min(scrollBar:GetValue(), maxScroll))
- scrollBar:Show()
- else
- scrollFrame.range = 0 -- Also handle this case
- scrollBar:SetMinMaxValues(0, 0)
- scrollBar:SetValue(0)
- scrollBar:Hide()
- end
-end
-
-
-
-function ConsumeTracker_UpdateOptionsScrollBar()
- local optionsFrame = ConsumeTracker_MainFrame.tabs[2]
- local scrollBar = optionsFrame.scrollBar
- local scrollFrame = optionsFrame.scrollFrame
- local scrollChild = optionsFrame.scrollChild
-
- local totalHeight = scrollChild.contentHeight
- local parentHeight = optionsFrame:GetHeight()
- local searchBoxHeight = 36 -- Adjusted height including padding
- local shownHeight = parentHeight - searchBoxHeight - 20
-
- local maxScroll = math.max(0, totalHeight - shownHeight)
- scrollFrame.maxScroll = maxScroll
-
- if totalHeight > shownHeight then
- scrollBar:SetMinMaxValues(0, maxScroll)
- scrollBar:SetValue(math.min(scrollBar:GetValue(), maxScroll))
- scrollBar:Show()
- else
- scrollBar:SetMinMaxValues(0, 0)
- scrollBar:SetValue(0)
- scrollBar:Hide()
- end
-end
-
-function ConsumeTracker_UpdateCharactersScrollBar()
- local charactersFrame = ConsumeTracker_MainFrame.tabs[3]
- local scrollBar = charactersFrame.scrollBar
- local scrollFrame = charactersFrame.scrollFrame
- local scrollChild = charactersFrame.scrollChild
-
- local totalHeight = scrollChild.contentHeight
- local shownHeight = 320 -- Adjust based on your UI
-
- local maxScroll = math.max(0, totalHeight - shownHeight)
- scrollFrame.maxScroll = maxScroll
-
- if totalHeight > shownHeight then
- scrollBar:SetMinMaxValues(0, maxScroll)
- scrollBar:SetValue(math.min(scrollBar:GetValue(), maxScroll))
- scrollBar:Show()
- else
- scrollBar:SetMinMaxValues(0, 0)
- scrollBar:SetValue(0)
- scrollBar:Hide()
- end
-end
-
-
-function ConsumeTracker_ShowConsumableTooltip(itemID)
- -- Ensure item is enabled in settings
- if not ConsumeTracker_Settings[itemID] then
- return
- end
-
- -- Create or reuse custom tooltip frame
- if not ConsumeTracker_CustomTooltip then
- -- Create the frame
- local tooltipFrame = CreateFrame("Frame", "ConsumeTracker_CustomTooltip", UIParent)
- tooltipFrame:SetFrameStrata("TOOLTIP")
- tooltipFrame:SetWidth(200)
- tooltipFrame:SetBackdrop({
- bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
- edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
- tile = true, tileSize = 16, edgeSize = 16,
- insets = { left = 4, right = 4, top = 4, bottom = 4 }
- })
- tooltipFrame:SetBackdropColor(0, 0, 0, 1)
-
- -- Item icon
- local icon = tooltipFrame:CreateTexture(nil, "ARTWORK")
- icon:SetWidth(32)
- icon:SetHeight(32)
- icon:SetPoint("TOPLEFT", tooltipFrame, "TOPLEFT", 10, -10)
- tooltipFrame.icon = icon
-
- -- Item name
- local title = tooltipFrame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
- title:SetPoint("TOPLEFT", icon, "TOPRIGHT", 10, -2)
- title:SetPoint("RIGHT", tooltipFrame, "RIGHT", -10, 0)
- title:SetJustifyH("LEFT")
- title:SetTextColor(1,1,1)
- tooltipFrame.title = title
-
- -- Item Total
- local total = tooltipFrame:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
- total:SetPoint("TOPLEFT", icon, "TOPRIGHT", 10, -20)
- total:SetPoint("RIGHT", tooltipFrame, "RIGHT", -10, 0)
- total:SetJustifyH("LEFT")
- tooltipFrame.total = total
-
- -- Content text
- local content = tooltipFrame:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
- content:SetPoint("TOPLEFT", icon, "BOTTOMLEFT", 0, -10)
- content:SetPoint("RIGHT", tooltipFrame, "RIGHT", -10, 0)
- content:SetJustifyH("LEFT")
- tooltipFrame.content = content
-
- ConsumeTracker_CustomTooltip = tooltipFrame
- end
-
- local tooltipFrame = ConsumeTracker_CustomTooltip
-
- -- Get item info
- local itemName = consumablesList[itemID] or "Unknown Item"
- local itemTexture = consumablesTexture[itemID] or "Interface\\Icons\\INV_Misc_QuestionMark"
-
- -- Set icon and title
- tooltipFrame.icon:SetTexture(itemTexture)
- tooltipFrame.title:SetText(itemName)
-
- -- Prepare content text
- local contentText = ""
-
- local realmName = GetRealmName()
- local faction = UnitFactionGroup("player")
- local playerName = UnitName("player")
-
- -- Ensure data structure exists
- ConsumeTracker_Data[realmName] = ConsumeTracker_Data[realmName] or {}
- ConsumeTracker_Data[realmName][faction] = ConsumeTracker_Data[realmName][faction] or {}
-
- local data = ConsumeTracker_Data[realmName][faction]
-
- -- Initialize totals
- local totalInventory, totalBank, totalMail = 0, 0, 0
- local hasItems = false
- local characterList = {}
-
- -- Ensure character settings exist
- ConsumeTracker_Settings["Characters"] = ConsumeTracker_Settings["Characters"] or {}
-
- -- Collect data for each character
- for character, charData in pairs(data) do
- if ConsumeTracker_Settings["Characters"][character] == true then
- local inventory = charData["inventory"] and charData["inventory"][itemID] or 0
- local bank = charData["bank"] and charData["bank"][itemID] or 0
- local mail = charData["mail"] and charData["mail"][itemID] or 0
- local total = inventory + bank + mail
-
- if total > 0 then
- hasItems = true
- totalInventory = totalInventory + inventory
- totalBank = totalBank + bank
- totalMail = totalMail + mail
-
- table.insert(characterList, {
- name = character,
- inventory = inventory,
- bank = bank,
- mail = mail,
- total = total,
- isPlayer = (character == playerName)
- })
- end
- end
- end
-
- local totalItems = totalInventory + totalBank + totalMail
- -- Adjust label color based on count
- if totalItems == 0 then
- tooltipFrame.total:SetTextColor(1, 0, 0) -- Red
- elseif totalItems < 10 then
- tooltipFrame.total:SetTextColor(1, 0.4, 0) -- Orange
- elseif totalItems <= 20 then
- tooltipFrame.total:SetTextColor(1, 0.85, 0) -- Yellow
- else
- tooltipFrame.total:SetTextColor(0, 1, 0) -- Green
- end
-
- tooltipFrame.total:SetText("Total: " .. totalItems)
-
- if not hasItems then
- contentText = contentText .. "|cffff0000No items found for this consumable.|r"
- else
-
- -- Sort characters alphabetically (optional)
- table.sort(characterList, function(a, b) return a.name < b.name end)
-
- -- Display data for each character
- for _, charInfo in ipairs(characterList) do
-
- local nameColor = charInfo.isPlayer and "|cff00ff00" or "|cffffffff" -- Green for player, grey for others
- contentText = contentText .. nameColor .. charInfo.name .. " (" .. charInfo.total .. ")|r\n"
-
- local detailText = ""
- if charInfo.inventory > 0 then
- detailText = detailText .. "|cffffffffInventory:|r " .. charInfo.inventory .. " "
- end
- if charInfo.bank > 0 then
- detailText = detailText .. "|cffffffffBank:|r " .. charInfo.bank .. " "
- end
- if charInfo.mail > 0 then
- detailText = detailText .. "|cffffffffMail:|r " .. charInfo.mail .. " "
- end
-
- contentText = contentText .. " " .. detailText .. "\n\n"
- end
- end
-
- tooltipFrame.content:SetText(contentText)
-
- -- Calculate the number of lines in contentText using string.gsub
- local _, numLines = string.gsub(contentText, "\n", "")
- numLines = numLines + 2 -- Add lines for title and padding
-
- -- Adjust tooltip height based on the number of lines
- local lineHeight = 10
- local totalHeight = 50 + (numLines * lineHeight)
- tooltipFrame:SetHeight(totalHeight)
-
- -- Set the width based on content
- local maxWidth = math.max(tooltipFrame.title:GetStringWidth() + 70, tooltipFrame.content:GetStringWidth() +20)
- tooltipFrame:SetWidth(maxWidth)
-
- -- Position the tooltip near the cursor
- local x, y = GetCursorPosition()
- local scale = UIParent:GetEffectiveScale()
- tooltipFrame:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", x / scale + 10, y / scale - 10)
-
- tooltipFrame:Show()
-end
-
-
-function ConsumeTracker_ShowOptionsTooltip(itemID)
- -- Set the maximum width for the description text
- local maxDescriptionWidth = 160
-
- -- Create or reuse the tooltip frame
- if not ConsumeTracker_OptionsTooltip then
- -- Create the frame
- local tooltipFrame = CreateFrame("Frame", "ConsumeTracker_OptionsTooltip", UIParent)
- tooltipFrame:SetFrameStrata("TOOLTIP")
- tooltipFrame:SetBackdrop({
- bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
- edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
- tile = true, tileSize = 16, edgeSize = 16,
- insets = { left = 4, right = 4, top = 4, bottom = 4 }
- })
- tooltipFrame:SetBackdropColor(0, 0, 0, 1)
-
- -- Item icon
- local icon = tooltipFrame:CreateTexture(nil, "ARTWORK")
- icon:SetWidth(32)
- icon:SetHeight(32)
- icon:SetPoint("TOPLEFT", tooltipFrame, "TOPLEFT", 10, -10)
- tooltipFrame.icon = icon
-
- -- Item name
- local title = tooltipFrame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
- title:SetPoint("TOPLEFT", icon, "TOPRIGHT", 10, -2)
- title:SetJustifyH("LEFT")
- tooltipFrame.title = title
-
- -- Item description
- local description = tooltipFrame:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
- description:SetPoint("TOPLEFT", icon, "TOPRIGHT", 10, -16)
- description:SetWidth(maxDescriptionWidth)
- description:SetJustifyH("LEFT")
- description:SetTextColor(1, 1, 1)
- tooltipFrame.description = description
-
- ConsumeTracker_OptionsTooltip = tooltipFrame
- end
-
- local tooltipFrame = ConsumeTracker_OptionsTooltip
-
- -- Get item info
- local itemName = consumablesList[itemID] or "Unknown Item"
- local itemTexture = consumablesTexture[itemID] or "Interface\\Icons\\INV_Misc_QuestionMark"
- local itemDescription = consumablesDescription[itemID] or ""
-
- -- Function to add line breaks manually
- local function WrapText(text, maxWidth, fontObject)
- local wrappedText = ""
- local currentLine = ""
- local space = " "
- local testString = tooltipFrame:CreateFontString(nil, "OVERLAY", fontObject)
- testString:SetWidth(0)
- testString:SetHeight(0)
- testString:Hide() -- We don't need to display this
-
- -- Replace \n with spaces to avoid unintended line breaks
- text = string.gsub(text, "\n", " ")
-
- -- Split the text into words
- for word in string.gfind(text, "%S+") do
- local testLine = currentLine == "" and word or (currentLine .. space .. word)
- testString:SetText(testLine)
- if testString:GetStringWidth() > maxWidth then
- wrappedText = wrappedText == "" and currentLine or (wrappedText .. "\n" .. currentLine)
- currentLine = word
- else
- currentLine = testLine
- end
- end
- wrappedText = wrappedText == "" and currentLine or (wrappedText .. "\n" .. currentLine)
- return wrappedText
- end
-
- -- Wrap the description text
- local wrappedDescription = WrapText(itemDescription, maxDescriptionWidth, "GameFontNormalSmall")
-
- -- Set icon, title, and description
- tooltipFrame.icon:SetTexture(itemTexture)
- tooltipFrame.title:SetText(itemName)
- tooltipFrame.description:SetText(wrappedDescription)
-
- -- Calculate the number of lines in the wrapped description
- local _, lineCount = string.gsub(wrappedDescription, "\n", "")
- lineCount = lineCount + 1 -- Add 1 for the last line
-
- -- Set the heights for the description and the tooltip frame
- local lineHeight = 12
- tooltipFrame.description:SetHeight(lineCount * lineHeight)
-
- local totalHeight = 50 + (lineCount * lineHeight)
- tooltipFrame:SetHeight(totalHeight)
-
- -- Set the width of the tooltip
- local maxWidth = math.max(tooltipFrame.title:GetStringWidth() + 70, tooltipFrame.description:GetStringWidth() + 70)
- tooltipFrame:SetWidth(maxWidth)
-
- -- Position the tooltip near the cursor
- local x, y = GetCursorPosition()
- local scale = UIParent:GetEffectiveScale()
- tooltipFrame:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", x / scale + 10, y / scale - 10)
-
- tooltipFrame:Show()
-end
-
-
-
-
-
--- Function to scan player's inventory
-function ConsumeTracker_ScanPlayerInventory()
- local playerName = UnitName("player")
- local realmName = GetRealmName()
- local faction = UnitFactionGroup("player")
-
- ConsumeTracker_Data[realmName] = ConsumeTracker_Data[realmName] or {}
- ConsumeTracker_Data[realmName][faction] = ConsumeTracker_Data[realmName][faction] or {}
- ConsumeTracker_Data[realmName][faction][playerName] = ConsumeTracker_Data[realmName][faction][playerName] or {}
- local data = ConsumeTracker_Data[realmName][faction][playerName]
- data["inventory"] = {}
-
- for bag = 0, 4 do
- local numSlots = GetContainerNumSlots(bag)
- if numSlots then
- for slot = 1, numSlots do
- local link = GetContainerItemLink(bag, slot)
- if link then
- local _, _, itemID = string.find(link, "item:(%d+)")
- if itemID then
- itemID = tonumber(itemID)
- if ConsumeTracker_Settings[itemID] then
- local texture, itemCount = GetContainerItemInfo(bag, slot)
- data["inventory"][itemID] = (data["inventory"][itemID] or 0) + itemCount
- end
- end
- end
- end
- end
- end
-
- ConsumeTracker_UpdateTrackerContent()
-end
-
--- Function to scan player's bank
-function ConsumeTracker_ScanPlayerBank()
-
- if not BankFrame or not BankFrame:IsShown() then
- return
- end
-
- local playerName = UnitName("player")
- local realmName = GetRealmName()
- local faction = UnitFactionGroup("player")
-
- local data = ConsumeTracker_Data[realmName][faction][playerName]
- data["bank"] = {}
-
- -- Bank bags are -1 and 5 to 10 in WoW 1.12
- for bag = -1, 10 do
- if bag == -1 or (bag >= 5 and bag <= 10) then
- local numSlots = GetContainerNumSlots(bag)
- if numSlots then
- for slot = 1, numSlots do
- local link = GetContainerItemLink(bag, slot)
- if link then
- local _, _, itemID = string.find(link, "item:(%d+)")
- if itemID then
- itemID = tonumber(itemID)
- if ConsumeTracker_Settings[itemID] then
- local texture, itemCount = GetContainerItemInfo(bag, slot)
- data["bank"][itemID] = (data["bank"][itemID] or 0) + itemCount
- end
- end
- end
- end
- end
- end
- end
-
- ConsumeTracker_UpdateTrackerContent()
-end
-
--- Function to scan player's mail
-function ConsumeTracker_ScanPlayerMail()
- if not MailFrame or not MailFrame:IsShown() then
- return
- end
-
- local playerName = UnitName("player")
- local realmName = GetRealmName()
- local faction = UnitFactionGroup("player")
-
- -- Ensure data tables are initialized
- ConsumeTracker_Data[realmName] = ConsumeTracker_Data[realmName] or {}
- ConsumeTracker_Data[realmName][faction] = ConsumeTracker_Data[realmName][faction] or {}
- ConsumeTracker_Data[realmName][faction][playerName] = ConsumeTracker_Data[realmName][faction][playerName] or {}
- local data = ConsumeTracker_Data[realmName][faction][playerName]
- data["mail"] = {}
-
- local numInboxItems = GetInboxNumItems()
- if numInboxItems and numInboxItems > 0 then
- for mailIndex = 1, numInboxItems do
- local itemName, itemTexture, itemCount, itemQuality = GetInboxItem(mailIndex)
- if itemName and itemCount and itemCount > 0 then
- -- Since GetInboxItemLink is not available, use itemName to get itemID
- local itemID = consumablesNameToID[itemName]
- if itemID and ConsumeTracker_Settings[itemID] then
- data["mail"][itemID] = (data["mail"][itemID] or 0) + itemCount
- end
- end
- end
- end
-
- ConsumeTracker_UpdateTrackerContent()
-end
-
+-- Metadata ---------------------------------------------------------------------------------------------
+AddonName = "Consumes Manager"
+Version = "1.5"
+VState = "beta"
+WindowWidth = 350
+
+-- Onload & Click Functionality -------------------------------------------------------------------------
+function ConsumesManager_OnLoad(self)
+ self:RegisterForDrag("LeftButton")
+ self:SetScript("OnDragStart", function() ConsumesManager_OnDragStart(self) end)
+ self:SetScript("OnDragStop", function() ConsumesManager_OnDragStop(self) end)
+
+ -- Create a frame for the delay
+ local delayFrame = CreateFrame("Frame")
+ local elapsed = 0
+ local delay = 1
+
+ delayFrame:SetScript("OnUpdate", function()
+ elapsed = elapsed + arg1 -- arg1 provides the time since the last frame
+ if elapsed >= delay then
+ DEFAULT_CHAT_FRAME:AddMessage("|cff00ff00" .. AddonName .. "|r |cffaaaaaa(v" .. Version .. "-" .. VState .. ")|r |cffffffffLoaded!|r |cffaaaaaa- Made by Horyoshi|r")
+ delayFrame:SetScript("OnUpdate", nil) -- Stop the OnUpdate script
+ end
+ end)
+end
+
+function ConsumesManager_HandleClick(self, button)
+ if not self then return end
+ if button == "LeftButton" and not IsShiftKeyDown() then
+ if ConsumesManager_MainFrame and ConsumesManager_MainFrame:IsShown() then
+ ConsumesManager_MainFrame:Hide()
+ else
+ ConsumesManager_ShowMainWindow()
+ end
+ end
+end
+
+function ConsumesManager_OnDragStart(self)
+ if IsShiftKeyDown() then
+ self:StartMoving()
+ self.isMoving = true
+ end
+end
+
+function ConsumesManager_OnDragStop(self)
+ if self and self.isMoving then
+ self:StopMovingOrSizing()
+ self.isMoving = false
+ end
+end
+
+-- Initialize SavedVariables ----------------------------------------------------------------------------
+ if not ConsumesManager_Settings then
+ ConsumesManager_Settings = {}
+ end
+ if not ConsumesManager_Data then
+ ConsumesManager_Data = {}
+ end
+
+-- Event frame for updating data ------------------------------------------------------------------------
+ local ConsumesManager_EventFrame = CreateFrame("Frame")
+ ConsumesManager_EventFrame:RegisterEvent("PLAYER_LOGIN")
+ ConsumesManager_EventFrame:RegisterEvent("BAG_UPDATE")
+ ConsumesManager_EventFrame:RegisterEvent("BANKFRAME_OPENED")
+ ConsumesManager_EventFrame:RegisterEvent("PLAYERBANKSLOTS_CHANGED")
+ ConsumesManager_EventFrame:RegisterEvent("ITEM_LOCK_CHANGED")
+ ConsumesManager_EventFrame:RegisterEvent("MAIL_SHOW")
+ ConsumesManager_EventFrame:RegisterEvent("MAIL_INBOX_UPDATE")
+ ConsumesManager_EventFrame:RegisterEvent("MAIL_CLOSED")
+
+ ConsumesManager_EventFrame:SetScript("OnEvent", function()
+ if event == "PLAYER_LOGIN" then
+ ConsumesManager_ScanPlayerInventory()
+ ConsumesManager_ScanPlayerBank()
+ ConsumesManager_ScanPlayerMail()
+ elseif event == "BAG_UPDATE" then
+ ConsumesManager_ScanPlayerInventory()
+ if BankFrame and BankFrame:IsShown() then
+ ConsumesManager_ScanPlayerBank()
+ end
+ if MailFrame and MailFrame:IsShown() then
+ ConsumesManager_ScanPlayerMail()
+ end
+ elseif event == "BANKFRAME_OPENED" then
+ ConsumesManager_ScanPlayerBank()
+ elseif event == "PLAYERBANKSLOTS_CHANGED" then
+ ConsumesManager_ScanPlayerBank()
+ ConsumesManager_ScanPlayerInventory()
+ elseif event == "ITEM_LOCK_CHANGED" then
+ if BankFrame and BankFrame:IsShown() then
+ ConsumesManager_ScanPlayerInventory()
+ ConsumesManager_ScanPlayerBank()
+ end
+ if MailFrame and MailFrame:IsShown() then
+ ConsumesManager_ScanPlayerInventory()
+ ConsumesManager_ScanPlayerMail()
+ end
+ elseif event == "MAIL_SHOW" or event == "MAIL_INBOX_UPDATE" then
+ ConsumesManager_ScanPlayerMail()
+ end
+ end)
+
+
+-- Main Windows Setup -----------------------------------------------------------------------------------
+function ConsumesManager_CreateMainWindow()
+ -- Main Frame
+ ConsumesManager_MainFrame = CreateFrame("Frame", "ConsumesManager_MainFrame", UIParent)
+ ConsumesManager_MainFrame:SetWidth(WindowWidth)
+ ConsumesManager_MainFrame:SetHeight(512)
+ ConsumesManager_MainFrame:SetPoint("CENTER", UIParent, "CENTER")
+ ConsumesManager_MainFrame:SetFrameStrata("DIALOG")
+ ConsumesManager_MainFrame:SetMovable(true)
+ ConsumesManager_MainFrame:EnableMouse(true)
+ ConsumesManager_MainFrame:RegisterForDrag("LeftButton")
+ ConsumesManager_MainFrame:SetScript("OnDragStart", function()
+ this:StartMoving()
+ end)
+ ConsumesManager_MainFrame:SetScript("OnDragStop", function()
+ this:StopMovingOrSizing()
+ end)
+
+ table.insert(UISpecialFrames, "ConsumesManager_MainFrame")
+
+ -- Background Texture
+ local background = ConsumesManager_MainFrame:CreateTexture(nil, "BACKGROUND")
+ background:SetTexture("Interface\\DialogFrame\\UI-DialogBox-Background")
+ background:SetPoint("TOPLEFT", ConsumesManager_MainFrame, "TOPLEFT", 12, -12)
+ background:SetPoint("BOTTOMRIGHT", ConsumesManager_MainFrame, "BOTTOMRIGHT", -12, 12)
+
+ -- Border
+ ConsumesManager_MainFrame:SetBackdrop({
+ bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
+ edgeFile = "Interface\\DialogFrame\\UI-DialogBox-Border",
+ tile = true, tileSize = 32, edgeSize = 32,
+ insets = { left = 11, right = 12, top = 12, bottom = 11 }
+ })
+ ConsumesManager_MainFrame:SetBackdropColor(0.1, 0.1, 0.1, 1)
+
+ -- Title Text
+ local titleText = ConsumesManager_MainFrame:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
+ titleText:SetText(AddonName)
+ titleText:SetPoint("TOP", ConsumesManager_MainFrame, "TOP", 0, 0)
+
+ -- Calculate the width of the title text and adjust the title background accordingly
+ local titleWidth = titleText:GetStringWidth() + 200
+
+ -- Title Background
+ local titleBg = ConsumesManager_MainFrame:CreateTexture(nil, "ARTWORK")
+ titleBg:SetTexture("Interface\\DialogFrame\\UI-DialogBox-Header")
+ titleBg:SetWidth(titleWidth)
+ titleBg:SetHeight(64)
+ titleBg:SetPoint("TOP", ConsumesManager_MainFrame, "TOP", 0, 12)
+
+
+ -- Close Button
+ local closeButton = CreateFrame("Button", nil, ConsumesManager_MainFrame, "UIPanelCloseButton")
+ closeButton:SetWidth(32)
+ closeButton:SetHeight(32)
+ closeButton:SetPoint("TOPRIGHT", ConsumesManager_MainFrame, "TOPRIGHT", -5, -5)
+ closeButton:SetScript("OnClick", function()
+ ConsumesManager_MainFrame:Hide()
+ end)
+
+ -- Create a custom tooltip frame
+ local tooltipFrame = CreateFrame("Frame", "ConsumesManagerTooltip", UIParent)
+ tooltipFrame:SetWidth(150)
+ tooltipFrame:SetHeight(40)
+ tooltipFrame:SetFrameStrata("TOOLTIP")
+ tooltipFrame:SetBackdrop({
+ bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
+ edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
+ tile = true, tileSize = 16, edgeSize = 16,
+ insets = { left = 4, right = 4, top = 4, bottom = 4 }
+ })
+ tooltipFrame:SetBackdropColor(0, 0, 0, 1)
+ tooltipFrame:Hide()
+
+ -- Tooltip text
+ local tooltipText = tooltipFrame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
+ tooltipText:SetPoint("CENTER", tooltipFrame, "CENTER", 0, 0)
+ tooltipFrame.text = tooltipText
+
+ local function ShowTooltip(tab, text)
+ tooltipFrame.text:SetText(text)
+ tooltipFrame:SetPoint("BOTTOMLEFT", tab, "TOPLEFT", 0, 0)
+ tooltipFrame:Show()
+ end
+
+ local function HideTooltip()
+ tooltipFrame:Hide()
+ end
+
+ -- Tabs
+ local tabs = {}
+ local function CreateTab(name, texture, xOffset, tooltipText, tabIndex)
+ local tab = CreateFrame("Button", name, ConsumesManager_MainFrame)
+ tab:SetWidth(36)
+ tab:SetHeight(36)
+ tab:SetPoint("TOPLEFT", ConsumesManager_MainFrame, "TOPLEFT", xOffset, -30)
+
+ -- Tab Icon
+ local icon = tab:CreateTexture(nil, "ARTWORK")
+ icon:SetTexture(texture)
+ icon:SetWidth(36)
+ icon:SetHeight(36)
+ icon:SetPoint("CENTER", tab, "CENTER", 0, 0)
+
+ tab.icon = icon
+
+ -- Hover Glow
+ local hoverTexture = tab:CreateTexture(nil, "HIGHLIGHT")
+ hoverTexture:SetTexture("Interface\\Buttons\\CheckButtonHilight")
+ hoverTexture:SetBlendMode("ADD")
+ hoverTexture:SetAllPoints(tab)
+
+ -- Active Highlight
+ local activeHighlight = tab:CreateTexture(nil, "OVERLAY")
+ activeHighlight:SetTexture("Interface\\Buttons\\CheckButtonHilight")
+ activeHighlight:SetBlendMode("ADD")
+ activeHighlight:SetAllPoints(tab)
+ activeHighlight:SetWidth(36)
+ activeHighlight:SetHeight(36)
+ activeHighlight:Hide()
+ tab.activeHighlight = activeHighlight
+
+ -- Custom Tooltip Handlers
+ tab:SetScript("OnEnter", function()
+ ShowTooltip(tab, tooltipText)
+ end)
+ tab:SetScript("OnLeave", HideTooltip)
+
+ -- Store tab for later
+ tabs[tabIndex] = tab
+
+ return tab
+ end
+
+ -- Manager Tab
+ local tab1 = CreateTab("ConsumesManager_MainFrameTab1", "Interface\\Icons\\INV_Potion_93", 30, "Consumables Manager", 1)
+ tab1:SetScript("OnClick", function()
+ ConsumesManager_ShowTab(1)
+ end)
+
+ -- Options Tab
+ local tab2 = CreateTab("ConsumesManager_MainFrameTab2", "Interface\\Icons\\INV_Misc_Gear_01", 80, "Options", 2)
+ tab2:SetScript("OnClick", function()
+ ConsumesManager_ShowTab(2)
+ end)
+
+ -- Characters Tab
+ local tab3 = CreateTab("ConsumesManager_MainFrameTab3", "Interface\\Icons\\Ability_Rogue_Disguise", 130, "Characters", 3)
+ tab3:SetScript("OnClick", function()
+ ConsumesManager_ShowTab(3)
+ end)
+
+ -- Add Grey Line Under Tabs
+ local tabsLine = ConsumesManager_MainFrame:CreateTexture(nil, "ARTWORK")
+ tabsLine:SetHeight(1)
+ tabsLine:SetPoint("TOPLEFT", ConsumesManager_MainFrame, "TOPLEFT", 12, -72)
+ tabsLine:SetPoint("TOPRIGHT", ConsumesManager_MainFrame, "TOPRIGHT", -12, -72)
+ tabsLine:SetTexture("Interface\\Buttons\\WHITE8x8")
+ tabsLine:SetVertexColor(0.4, 0.4, 0.4, 1)
+
+ -- Tab Content
+ ConsumesManager_MainFrame.tabs = {}
+ local tab1Content = CreateFrame("Frame", nil, ConsumesManager_MainFrame)
+ tab1Content:SetWidth(WindowWidth - 50)
+ tab1Content:SetHeight(380)
+ tab1Content:SetPoint("TOPLEFT", ConsumesManager_MainFrame, "TOPLEFT", 30, -80)
+ ConsumesManager_MainFrame.tabs[1] = tab1Content
+
+ local tab2Content = CreateFrame("Frame", nil, ConsumesManager_MainFrame)
+ tab2Content:SetWidth(WindowWidth - 50)
+ tab2Content:SetHeight(380)
+ tab2Content:SetPoint("TOPLEFT", ConsumesManager_MainFrame, "TOPLEFT", 30, -80)
+ ConsumesManager_MainFrame.tabs[2] = tab2Content
+
+ local tab3Content = CreateFrame("Frame", nil, ConsumesManager_MainFrame)
+ tab3Content:SetWidth(WindowWidth - 50)
+ tab3Content:SetHeight(380)
+ tab3Content:SetPoint("TOPLEFT", ConsumesManager_MainFrame, "TOPLEFT", 30, -80)
+ ConsumesManager_MainFrame.tabs[3] = tab3Content
+
+ -- Footer Text
+ local footerText = ConsumesManager_MainFrame:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
+ footerText:SetText("Made by Horyoshi (v" .. Version .. "-" .. VState .. ")")
+ footerText:SetTextColor(0.6, 0.6, 0.6)
+ footerText:SetPoint("BOTTOM", ConsumesManager_MainFrame, "BOTTOM", 0, 15)
+
+ -- Add Grey Line Above Footer
+ local footerLine = ConsumesManager_MainFrame:CreateTexture(nil, "ARTWORK")
+ footerLine:SetHeight(1)
+ footerLine:SetPoint("BOTTOMLEFT", ConsumesManager_MainFrame, "BOTTOMLEFT", 12, 30)
+ footerLine:SetPoint("BOTTOMRIGHT", ConsumesManager_MainFrame, "BOTTOMRIGHT", -12, 30)
+ footerLine:SetTexture("Interface\\Buttons\\WHITE8x8")
+ footerLine:SetVertexColor(0.4, 0.4, 0.4, 1)
+
+ -- Tab Switching Function
+ function ConsumesManager_ShowTab(tabIndex)
+ for index, content in pairs(ConsumesManager_MainFrame.tabs) do
+ if index == tabIndex then
+ content:Show()
+ tabs[index].activeHighlight:Show()
+ else
+ content:Hide()
+ tabs[index].activeHighlight:Hide()
+ end
+ end
+ end
+
+ -- Set Default Tab
+ ConsumesManager_ShowTab(1)
+
+ -- Add Custom Content for Tabs
+ ConsumesManager_CreateManagerContent(tab1Content)
+ ConsumesManager_CreateOptionsContent(tab2Content)
+ ConsumesManager_CreateCharactersContent(tab3Content)
+end
+
+function ConsumesManager_ShowMainWindow()
+ if not ConsumesManager_MainFrame then
+ ConsumesManager_CreateMainWindow()
+ end
+ ConsumesManager_MainFrame:Show()
+ -- Scan inventory when the window is opened
+ ConsumesManager_ScanPlayerInventory()
+ -- Only scan bank and mail if they are open
+ if BankFrame and BankFrame:IsShown() then
+ ConsumesManager_ScanPlayerBank()
+ end
+ if MailFrame and MailFrame:IsShown() then
+ ConsumesManager_ScanPlayerMail()
+ end
+ -- Update the Manager content
+ ConsumesManager_UpdateManagerContent()
+end
+
+function ConsumesManager_ShowTab(tabIndex)
+ if not ConsumesManager_MainFrame or not ConsumesManager_MainFrame.tabs then return end
+ for i, tabContent in pairs(ConsumesManager_MainFrame.tabs) do
+ if i == tabIndex then
+ tabContent:Show()
+ -- Set the tab button to active
+ local tabButton = getglobal("ConsumesManager_MainFrameTab" .. i)
+ tabButton:SetNormalTexture("Interface\\OptionsFrame\\UI-OptionsFrame-ActiveTab")
+ else
+ tabContent:Hide()
+ -- Set the tab button to inactive
+ local tabButton = getglobal("ConsumesManager_MainFrameTab" .. i)
+ tabButton:SetNormalTexture("Interface\\OptionsFrame\\UI-OptionsFrame-InActiveTab")
+ end
+ end
+end
+
+
+
+-- Create Window Tabs -----------------------------------------------------------------------------------
+function ConsumesManager_CreateManagerContent(parentFrame)
+ -- Scroll Frame
+ local scrollFrame = CreateFrame("ScrollFrame", "ConsumesManager_ManagerScrollFrame", parentFrame)
+ scrollFrame:SetPoint("TOPLEFT", parentFrame, "TOPLEFT", 0, 0)
+ scrollFrame:SetPoint("BOTTOMRIGHT", parentFrame, "BOTTOMRIGHT", -20, 0)
+ scrollFrame:EnableMouseWheel(true)
+ scrollFrame:SetScript("OnMouseWheel", function()
+ local delta = arg1
+ local current = this:GetVerticalScroll()
+ local maxScroll = this.range or 0
+ local newScroll = math.max(0, math.min(current - (delta * 20), maxScroll))
+ this:SetVerticalScroll(newScroll)
+ parentFrame.scrollBar:SetValue(newScroll)
+ end)
+
+ -- Scroll Child Frame
+ local scrollChild = CreateFrame("Frame", nil, scrollFrame)
+ scrollChild:SetWidth(WindowWidth - 10)
+ scrollChild:SetHeight(1) -- Will adjust later
+ scrollFrame:SetScrollChild(scrollChild)
+ parentFrame.scrollChild = scrollChild
+ parentFrame.scrollFrame = scrollFrame
+
+ -- Initialize data structures
+ parentFrame.categoryInfo = {}
+ local index = 0 -- Position index
+ local lineHeight = 18
+
+ -- Sort categories alphabetically
+ local sortedCategories = {}
+ for categoryName, _ in pairs(consumablesCategories) do
+ table.insert(sortedCategories, categoryName)
+ end
+ table.sort(sortedCategories)
+
+ -- Iterate over sorted categories
+ for _, categoryName in ipairs(sortedCategories) do
+ local consumables = consumablesCategories[categoryName]
+
+ -- Create category label
+ local categoryLabel = scrollChild:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
+ categoryLabel:SetText(categoryName)
+ categoryLabel:SetTextColor(1, 1, 1)
+ categoryLabel:Show()
+
+ local categoryInfo = { name = categoryName, label = categoryLabel, options = {} }
+
+ index = index + 1 -- Position for the category label
+
+ local numOptionsInCategory = 0 -- Counter for options in this category
+
+ -- Sort the consumables by name
+ table.sort(consumables, function(a, b) return a.name < b.name end)
+
+ -- For each consumable in the category
+ for _, consumable in ipairs(consumables) do
+ local itemID = consumable.id
+ local itemName = consumable.name
+
+ -- Create a frame that encompasses the button and label
+ local optionFrame = CreateFrame("Frame", "ConsumesManager_ManagerOptionFrame" .. index, scrollChild)
+ optionFrame:SetWidth(WindowWidth - 10)
+ optionFrame:SetHeight(lineHeight)
+ optionFrame:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", 0, - (index) * lineHeight)
+ optionFrame:Show()
+ optionFrame:EnableMouse(true) -- Enable mouse events for OnEnter and OnLeave
+
+ -- Create the 'Use' button inside the optionFrame
+ local useButton = CreateFrame("Button", "ConsumesManager_UseButton" .. index, optionFrame, "UIPanelButtonTemplate")
+ useButton:SetWidth(40)
+ useButton:SetHeight(16)
+ useButton:SetPoint("LEFT", optionFrame, "LEFT", 0, 0)
+ useButton:SetText("Use")
+
+ -- Create FontString for label
+ local label = optionFrame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
+ label:SetPoint("LEFT", useButton, "RIGHT", 4, 0)
+ label:SetText(itemName)
+
+ -- Set up the button OnClick handler
+ useButton:SetScript("OnClick", function()
+ local bag, slot = ConsumesManager_FindItemInBags(itemID)
+ if bag and slot then
+ UseContainerItem(bag, slot)
+ else
+ DEFAULT_CHAT_FRAME:AddMessage("Item not found in bags.")
+ end
+ end)
+
+ -- Initialize button state
+ useButton:Disable()
+
+ -- Mouseover Tooltip
+ optionFrame:SetScript("OnEnter", function()
+ ConsumesManager_ShowConsumableTooltip(itemID)
+ end)
+ optionFrame:SetScript("OnLeave", function()
+ if ConsumesManager_CustomTooltip then
+ ConsumesManager_CustomTooltip:Hide()
+ end
+ end)
+
+ -- Store option info
+ table.insert(categoryInfo.options, {
+ frame = optionFrame,
+ label = label,
+ name = itemName,
+ itemID = itemID,
+ button = useButton
+ })
+
+ index = index + 1 -- Increment index after adding option
+ numOptionsInCategory = numOptionsInCategory + 1 -- Increment options count
+ end
+
+ -- Position the category label above its options
+ categoryLabel:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", 0, - (index - numOptionsInCategory - 1) * lineHeight)
+
+ -- Store category info
+ table.insert(parentFrame.categoryInfo, categoryInfo)
+
+ -- Add extra spacing after the category
+ index = index + 1 -- Add one extra line of spacing between categories
+ end
+
+ -- Adjust the scroll child height
+ scrollChild.contentHeight = (index - 1) * lineHeight
+ scrollChild:SetHeight(scrollChild.contentHeight)
+
+ -- Message Label (adjusted to be a child of parentFrame)
+ local messageLabel = parentFrame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
+ messageLabel:SetText("|cffff0000No consumables selected|r\n\n|cffffffffClick on |roptions|cffffffff to get started|r")
+ messageLabel:SetPoint("CENTER", parentFrame, "CENTER", 0, 0)
+ messageLabel:Hide() -- Initially hidden
+ parentFrame.messageLabel = messageLabel
+
+ -- Scroll Bar
+ local scrollBar = CreateFrame("Slider", "ConsumesManager_ManagerScrollBar", parentFrame)
+ scrollBar:SetPoint("TOPRIGHT", parentFrame, "TOPRIGHT", -2, -16)
+ scrollBar:SetPoint("BOTTOMRIGHT", parentFrame, "BOTTOMRIGHT", -2, 16)
+ scrollBar:SetWidth(16)
+ scrollBar:SetOrientation('VERTICAL')
+ scrollBar:SetThumbTexture("Interface\\Buttons\\UI-ScrollBar-Knob")
+ scrollBar:SetBackdrop({
+ bgFile = "Interface\\Buttons\\UI-SliderBar-Background",
+ edgeFile = "Interface\\Buttons\\UI-SliderBar-Border",
+ tile = true, tileSize = 8, edgeSize = 8,
+ insets = { left = 3, right = 3, top = 3, bottom = 3 }
+ })
+ scrollBar:SetScript("OnValueChanged", function()
+ local value = this:GetValue()
+ parentFrame.scrollFrame:SetVerticalScroll(value)
+ end)
+ parentFrame.scrollBar = scrollBar
+
+ -- Update the scrollbar
+ ConsumesManager_UpdateManagerScrollBar()
+end
+
+function ConsumesManager_CreateOptionsContent(parentFrame)
+ -- Create Search Input
+ local searchBox = CreateFrame("EditBox", "ConsumesManager_SearchBox", parentFrame, "InputBoxTemplate")
+ searchBox:SetWidth(WindowWidth - 50)
+ searchBox:SetHeight(25)
+ searchBox:SetPoint("TOPLEFT", parentFrame, "TOPLEFT", 0, -5)
+ searchBox:SetAutoFocus(false)
+ searchBox:SetText("Search...")
+ searchBox:SetTextColor(0.5, 0.5, 0.5) -- Placeholder text color
+
+ searchBox:SetScript("OnEditFocusGained", function()
+ if this:GetText() == "Search..." then
+ this:SetText("")
+ this:SetTextColor(1, 1, 1) -- User input text color
+ end
+ end)
+
+ searchBox:SetScript("OnEditFocusLost", function()
+ if this:GetText() == "" then
+ this:SetText("Search...")
+ this:SetTextColor(0.5, 0.5, 0.5) -- Placeholder text color
+ end
+ end)
+
+ -- Function to update the filter
+ local function UpdateFilter()
+ local filterText = string.lower(searchBox:GetText())
+ if filterText == "search..." then filterText = "" end
+ local index = 0 -- Position index
+ local lineHeight = 18
+
+ -- Iterate over categories
+ for _, categoryInfo in ipairs(parentFrame.categoryInfo) do
+ local categoryLabel = categoryInfo.label
+ local anyOptionVisible = false
+
+ -- First, check if any options in the category match the filter
+ for _, optionInfo in ipairs(categoryInfo.options) do
+ local itemNameLower = string.lower(optionInfo.name)
+
+ if filterText == "" or string.find(itemNameLower, filterText, 1, true) then
+ anyOptionVisible = true
+ break
+ end
+ end
+
+ -- If any options are visible, show the category label
+ if anyOptionVisible then
+ categoryLabel:SetPoint("TOPLEFT", parentFrame.scrollChild, "TOPLEFT", 0, - (index) * lineHeight)
+ categoryLabel:Show()
+ index = index + 1
+
+ -- Now, position and show the matching options
+ for _, optionInfo in ipairs(categoryInfo.options) do
+ local optionFrame = optionInfo.frame
+ local itemNameLower = string.lower(optionInfo.name)
+
+ if filterText == "" or string.find(itemNameLower, filterText, 1, true) then
+ -- Show the option
+ optionFrame:SetPoint("TOPLEFT", parentFrame.scrollChild, "TOPLEFT", 0, - (index) * lineHeight)
+ optionFrame:Show()
+ index = index + 1
+ else
+ optionFrame:Hide()
+ end
+ end
+
+ -- Add extra spacing after the category
+ index = index + 1 -- Add one extra line of spacing between categories
+
+ else
+ categoryLabel:Hide()
+ -- Hide all options under this category
+ for _, optionInfo in ipairs(categoryInfo.options) do
+ optionInfo.frame:Hide()
+ end
+ end
+ end
+
+ -- Adjust the scroll child height
+ parentFrame.scrollChild.contentHeight = index * lineHeight
+ parentFrame.scrollChild:SetHeight(parentFrame.scrollChild.contentHeight)
+
+ -- Update the scrollbar
+ ConsumesManager_UpdateOptionsScrollBar()
+ end
+
+ searchBox:SetScript("OnTextChanged", function()
+ UpdateFilter()
+ end)
+
+ -- Adjust the size of the scroll frame to make room for the search box and add extra spacing
+ local scrollFrame = CreateFrame("ScrollFrame", "ConsumesManager_OptionsScrollFrame", parentFrame)
+ scrollFrame:SetPoint("TOPLEFT", parentFrame, "TOPLEFT", 0, -40) -- Start below the search box
+ scrollFrame:SetPoint("BOTTOMRIGHT", parentFrame, "BOTTOMRIGHT", -20, 60) -- Leave space for buttons
+ scrollFrame:EnableMouseWheel(true)
+ scrollFrame:SetScript("OnMouseWheel", function()
+ local delta = arg1
+ local current = this:GetVerticalScroll()
+ local maxScroll = this.maxScroll or 0
+ local newScroll = math.max(0, math.min(current - (delta * 20), maxScroll))
+ this:SetVerticalScroll(newScroll)
+ parentFrame.scrollBar:SetValue(newScroll)
+ end)
+
+ -- Scroll Child Frame
+ local scrollChild = CreateFrame("Frame", nil, scrollFrame)
+ scrollChild:SetWidth(WindowWidth - 10)
+ scrollChild:SetHeight(1) -- Will adjust later
+ scrollFrame:SetScrollChild(scrollChild)
+ parentFrame.scrollChild = scrollChild
+ parentFrame.scrollFrame = scrollFrame
+
+ -- Sort categories alphabetically
+ local sortedCategories = {}
+ for categoryName, _ in pairs(consumablesCategories) do
+ table.insert(sortedCategories, categoryName)
+ end
+ table.sort(sortedCategories)
+
+ -- Checkboxes
+ parentFrame.checkboxes = {}
+ parentFrame.categoryInfo = {}
+ local index = 0 -- Position index
+ local lineHeight = 18
+
+ -- Iterate over sorted categories
+ for _, categoryName in ipairs(sortedCategories) do
+ local consumables = consumablesCategories[categoryName]
+
+ -- Create category label
+ local categoryLabel = scrollChild:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
+ categoryLabel:SetText(categoryName)
+ categoryLabel:SetTextColor(1, 1, 1)
+ categoryLabel:Show()
+
+ local categoryInfo = { name = categoryName, label = categoryLabel, options = {} }
+
+ index = index + 1 -- Position for the category label
+
+ local numOptionsInCategory = 0 -- Counter for options in this category
+
+ -- Sort the consumables by name
+ table.sort(consumables, function(a, b) return a.name < b.name end)
+
+ -- For each consumable in the category
+ for _, consumable in ipairs(consumables) do
+ local currentItemID = consumable.id
+ local itemName = consumable.name
+
+ -- Create a frame that encompasses the checkbox and label
+ local optionFrame = CreateFrame("Frame", "ConsumesManager_OptionsFrame" .. index, scrollChild)
+ optionFrame:SetWidth(WindowWidth - 10)
+ optionFrame:SetHeight(lineHeight)
+ optionFrame:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", 0, - (index) * lineHeight)
+ optionFrame:Show()
+
+ -- Create the checkbox inside the optionFrame
+ local checkbox = CreateFrame("CheckButton", "ConsumesManager_OptionsCheckbox" .. index, optionFrame)
+ checkbox:SetWidth(16)
+ checkbox:SetHeight(16)
+ checkbox:SetPoint("LEFT", optionFrame, "LEFT", 0, 0)
+
+ -- Create Textures for the checkbox
+ checkbox:SetNormalTexture("Interface\\Buttons\\UI-CheckBox-Up")
+ checkbox:SetPushedTexture("Interface\\Buttons\\UI-CheckBox-Down")
+ checkbox:SetHighlightTexture("Interface\\Buttons\\UI-CheckBox-Highlight")
+ checkbox:SetCheckedTexture("Interface\\Buttons\\UI-CheckBox-Check")
+
+ -- Create FontString for label
+ local label = optionFrame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
+ label:SetPoint("LEFT", checkbox, "RIGHT", 4, 0)
+ label:SetText(itemName)
+
+ -- Set up the checkbox OnClick handler
+ checkbox:SetScript("OnClick", function()
+ ConsumesManager_Settings[currentItemID] = checkbox:GetChecked()
+ ConsumesManager_UpdateManagerContent()
+ end)
+ -- Load saved setting
+ if ConsumesManager_Settings[currentItemID] then
+ checkbox:SetChecked(true)
+ end
+ parentFrame.checkboxes[currentItemID] = checkbox
+
+ -- Make the optionFrame clickable
+ optionFrame:EnableMouse(true)
+ optionFrame:SetScript("OnMouseDown", function()
+ checkbox:Click()
+ end)
+
+ -- Mouseover Tooltip
+ optionFrame:SetScript("OnEnter", function()
+ ConsumesManager_ShowOptionsTooltip(currentItemID)
+ end)
+ optionFrame:SetScript("OnLeave", function()
+ if ConsumesManager_OptionsTooltip then
+ ConsumesManager_OptionsTooltip:Hide()
+ end
+ end)
+
+ -- Store option info
+ table.insert(categoryInfo.options, { frame = optionFrame, name = itemName })
+
+ index = index + 1 -- Increment index after adding option
+ numOptionsInCategory = numOptionsInCategory + 1 -- Increment options count
+ end
+
+ -- Position the category label above its options
+ categoryLabel:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", 0, - (index - numOptionsInCategory - 1) * lineHeight)
+
+ -- Store category info
+ table.insert(parentFrame.categoryInfo, categoryInfo)
+
+ -- Add extra spacing after the category
+ index = index + 1 -- Add one extra line of spacing between categories
+ end
+
+ -- Adjust the scroll child height
+ scrollChild.contentHeight = (index - 1) * lineHeight
+ scrollChild:SetHeight(scrollChild.contentHeight)
+
+ -- Scroll Bar
+ local scrollBar = CreateFrame("Slider", "ConsumesManager_OptionsScrollBar", parentFrame)
+ -- Corrected Y-offsets to prevent overlapping
+ scrollBar:SetPoint("TOPRIGHT", parentFrame, "TOPRIGHT", -2, -40) -- Start below the search box
+ scrollBar:SetPoint("BOTTOMRIGHT", parentFrame, "BOTTOMRIGHT", -2, 16) -- End above the buttons
+ scrollBar:SetWidth(16)
+ scrollBar:SetOrientation('VERTICAL')
+ scrollBar:SetThumbTexture("Interface\\Buttons\\UI-ScrollBar-Knob")
+ scrollBar:SetBackdrop({
+ bgFile = "Interface\\Buttons\\UI-SliderBar-Background",
+ edgeFile = "Interface\\Buttons\\UI-SliderBar-Border",
+ tile = true, tileSize = 8, edgeSize = 8,
+ insets = { left = 3, right = 3, top = 3, bottom = 3 }
+ })
+ scrollBar:SetScript("OnValueChanged", function()
+ local value = this:GetValue()
+ parentFrame.scrollFrame:SetVerticalScroll(value)
+ end)
+ parentFrame.scrollBar = scrollBar
+
+ -- Update the scrollbar
+ ConsumesManager_UpdateOptionsScrollBar()
+
+ -- Create Select All Button
+ local selectAllButton = CreateFrame("Button", "ConsumesManager_SelectAllButton", parentFrame, "UIPanelButtonTemplate")
+ selectAllButton:SetWidth(100)
+ selectAllButton:SetHeight(24)
+ selectAllButton:SetText("Select All")
+ selectAllButton:SetPoint("BOTTOMLEFT", parentFrame, "BOTTOMLEFT", 20, 10)
+ selectAllButton:SetScript("OnClick", function()
+ for itemID, checkbox in pairs(parentFrame.checkboxes) do
+ checkbox:SetChecked(true)
+ ConsumesManager_Settings[itemID] = true
+ end
+ ConsumesManager_UpdateManagerContent()
+ end)
+
+ -- Create Deselect All Button
+ local deselectAllButton = CreateFrame("Button", "ConsumesManager_DeselectAllButton", parentFrame, "UIPanelButtonTemplate")
+ deselectAllButton:SetWidth(100)
+ deselectAllButton:SetHeight(24)
+ deselectAllButton:SetText("Deselect All")
+ deselectAllButton:SetPoint("BOTTOMRIGHT", parentFrame, "BOTTOMRIGHT", -40, 10)
+ deselectAllButton:SetScript("OnClick", function()
+ for itemID, checkbox in pairs(parentFrame.checkboxes) do
+ checkbox:SetChecked(false)
+ ConsumesManager_Settings[itemID] = false
+ end
+ ConsumesManager_UpdateManagerContent()
+ end)
+end
+
+function ConsumesManager_CreateCharactersContent(parentFrame)
+ -- Scroll Frame
+ local scrollFrame = CreateFrame("ScrollFrame", "ConsumesManager_CharactersScrollFrame", parentFrame)
+ scrollFrame:SetPoint("TOPLEFT", parentFrame, "TOPLEFT", 0, 0)
+ scrollFrame:SetPoint("BOTTOMRIGHT", parentFrame, "BOTTOMRIGHT", -20, 0)
+ scrollFrame:EnableMouseWheel(true)
+ scrollFrame:SetScript("OnMouseWheel", function()
+ local delta = arg1
+ local current = scrollFrame:GetVerticalScroll()
+ local maxScroll = scrollFrame.maxScroll or 0
+ local newScroll = math.max(0, math.min(current - (delta * 20), maxScroll))
+ scrollFrame:SetVerticalScroll(newScroll)
+ if parentFrame.scrollBar then
+ parentFrame.scrollBar:SetValue(newScroll)
+ end
+ end)
+
+ -- Scroll Child Frame
+ local scrollChild = CreateFrame("Frame", nil, scrollFrame)
+ scrollChild:SetWidth(WindowWidth - 10)
+ scrollChild:SetHeight(1)
+ scrollFrame:SetScrollChild(scrollChild)
+
+ -- Initialize variables
+ parentFrame.checkboxes = {}
+ local index = 0 -- Position index
+
+ -- Ensure settings table for characters exists
+ ConsumesManager_Settings["Characters"] = ConsumesManager_Settings["Characters"] or {}
+
+ -- Get list of characters
+ local realmName = GetRealmName()
+ local faction = UnitFactionGroup("player")
+ local playerName = UnitName("player")
+
+ local characterList = {}
+
+ -- Ensure data structure exists
+ if ConsumesManager_Data[realmName] and ConsumesManager_Data[realmName][faction] then
+ for characterName, _ in pairs(ConsumesManager_Data[realmName][faction]) do
+ table.insert(characterList, characterName)
+ end
+ end
+
+ -- Ensure current character is included
+ local playerInList = false
+ for _, name in ipairs(characterList) do
+ if name == playerName then
+ playerInList = true
+ break
+ end
+ end
+ if not playerInList then
+ table.insert(characterList, playerName)
+ end
+
+ -- Sort the character list
+ table.sort(characterList)
+
+ -- Create FontString for title
+ local title = scrollChild:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
+ title:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", 0, 0) -- Offset from the top
+ title:SetText("Select Characters to Track")
+ title:SetTextColor(1, 1, 1)
+
+ -- Offset index to start below the title
+ local startYOffset = 20
+
+ -- For each character
+ for _, characterName in ipairs(characterList) do
+ index = index + 1
+
+ -- Create a local copy of characterName for the closure
+ local currentCharacterName = characterName
+
+ -- Create a frame that encompasses the checkbox and label
+ local optionFrame = CreateFrame("Frame", "ConsumesManager_CharacterFrame" .. index, scrollChild)
+ optionFrame:SetWidth(WindowWidth - 10)
+ optionFrame:SetHeight(18)
+ optionFrame:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", 0, -(startYOffset + (index - 1) * 20))
+
+ -- Create the checkbox inside the optionFrame
+ local checkbox = CreateFrame("CheckButton", "ConsumesManager_CharacterCheckbox" .. index, optionFrame)
+ checkbox:SetWidth(16)
+ checkbox:SetHeight(16)
+ checkbox:SetPoint("LEFT", optionFrame, "LEFT", 0, 0)
+
+ -- Create Textures for the checkbox
+ checkbox:SetNormalTexture("Interface\\Buttons\\UI-CheckBox-Up")
+ checkbox:SetPushedTexture("Interface\\Buttons\\UI-CheckBox-Down")
+ checkbox:SetHighlightTexture("Interface\\Buttons\\UI-CheckBox-Highlight")
+ checkbox:SetCheckedTexture("Interface\\Buttons\\UI-CheckBox-Check")
+
+ -- Create FontString for label
+ local label = optionFrame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
+ label:SetPoint("LEFT", checkbox, "RIGHT", 4, 0)
+ label:SetText(currentCharacterName)
+
+ -- Set up the checkbox OnClick handler
+ checkbox:SetScript("OnClick", function()
+ if checkbox:GetChecked() then
+ ConsumesManager_Settings["Characters"][currentCharacterName] = true
+ else
+ ConsumesManager_Settings["Characters"][currentCharacterName] = false
+ end
+ ConsumesManager_UpdateManagerContent()
+ end)
+ -- Load saved setting
+ if ConsumesManager_Settings["Characters"][currentCharacterName] == nil then
+ -- Default to checked
+ checkbox:SetChecked(true)
+ ConsumesManager_Settings["Characters"][currentCharacterName] = true
+ else
+ checkbox:SetChecked(ConsumesManager_Settings["Characters"][currentCharacterName])
+ end
+ parentFrame.checkboxes[currentCharacterName] = checkbox
+
+ -- Make the optionFrame clickable (so clicking on the label checks/unchecks the box)
+ optionFrame:EnableMouse(true)
+ optionFrame:SetScript("OnMouseDown", function()
+ checkbox:Click()
+ end)
+ end
+
+ -- Adjust the scroll child height
+ scrollChild.contentHeight = startYOffset + index * 20
+ scrollChild:SetHeight(scrollChild.contentHeight)
+
+ -- Scroll Bar
+ local scrollBar = CreateFrame("Slider", "ConsumesManager_CharactersScrollBar", parentFrame)
+ scrollBar:SetPoint("TOPRIGHT", parentFrame, "TOPRIGHT", -2, -16)
+ scrollBar:SetPoint("BOTTOMRIGHT", parentFrame, "BOTTOMRIGHT", -2, 16)
+ scrollBar:SetWidth(16)
+ scrollBar:SetOrientation('VERTICAL')
+ scrollBar:SetThumbTexture("Interface\\Buttons\\UI-ScrollBar-Knob")
+ scrollBar:SetBackdrop({
+ bgFile = "Interface\\Buttons\\UI-SliderBar-Background",
+ edgeFile = "Interface\\Buttons\\UI-SliderBar-Border",
+ tile = true, tileSize = 8, edgeSize = 8,
+ insets = { left = 3, right = 3, top = 3, bottom = 3 }
+ })
+ scrollBar:SetScript("OnValueChanged", function()
+ local value = scrollBar:GetValue()
+ scrollFrame:SetVerticalScroll(value)
+ end)
+ parentFrame.scrollBar = scrollBar
+ parentFrame.scrollFrame = scrollFrame
+ parentFrame.scrollChild = scrollChild
+
+ -- Update the scrollbar
+ ConsumesManager_UpdateCharactersScrollBar()
+end
+
+
+
+-- Update Window Tabs -----------------------------------------------------------------------------------
+function ConsumesManager_UpdateManagerContent()
+ if not ConsumesManager_MainFrame or not ConsumesManager_MainFrame.tabs or not ConsumesManager_MainFrame.tabs[1] then
+ return
+ end
+
+ local ManagerFrame = ConsumesManager_MainFrame.tabs[1]
+ local realmName = GetRealmName()
+ local faction = UnitFactionGroup("player")
+ local playerName = UnitName("player")
+
+ -- Ensure data structure exists
+ if not ConsumesManager_Data[realmName] or not ConsumesManager_Data[realmName][faction] then
+ return
+ end
+ local data = ConsumesManager_Data[realmName][faction]
+
+ -- Check if bank and mail have been scanned for current character
+ local currentCharData = data[playerName]
+ local bankScanned = currentCharData and currentCharData["bank"] ~= nil
+ local mailScanned = currentCharData and currentCharData["mail"] ~= nil
+
+ -- If bank and mail have not been scanned, show message and hide item labels
+ if not bankScanned or not mailScanned then
+ -- Hide all option frames
+ for _, categoryInfo in ipairs(ManagerFrame.categoryInfo) do
+ categoryInfo.label:Hide()
+ for _, optionInfo in ipairs(categoryInfo.options) do
+ optionInfo.frame:Hide()
+ end
+ end
+
+ -- Show message
+ ManagerFrame.messageLabel:SetText("|cffff0000This character is not scanned yet|r\n\n|cffffffffOpen your |rBank|cffffffff and |rMail |cffffffffto get started|r")
+ ManagerFrame.messageLabel:Show()
+
+ -- Update the Manager scrollbar
+ ConsumesManager_UpdateManagerScrollBar()
+
+ return
+ end
+
+ -- Proceed with normal content update
+ local index = 0 -- Positioning index for items
+ local hasAnyVisibleItems = false -- Track if any items are visible
+ local lineHeight = 18
+
+ -- Hide the message label
+ ManagerFrame.messageLabel:Hide()
+
+ -- Iterate over categories
+ for _, categoryInfo in ipairs(ManagerFrame.categoryInfo) do
+ local anyOptionVisible = false
+
+ -- First, check if any options in the category are enabled
+ for _, optionInfo in ipairs(categoryInfo.options) do
+ local itemID = optionInfo.itemID
+ if ConsumesManager_Settings[itemID] then
+ anyOptionVisible = true
+ break
+ end
+ end
+
+ -- If any options are visible, show the category label
+ if anyOptionVisible then
+ categoryInfo.label:SetPoint("TOPLEFT", ManagerFrame.scrollChild, "TOPLEFT", 0, - (index) * lineHeight)
+ categoryInfo.label:Show()
+ index = index + 1
+
+ -- Now, position and show the enabled options
+ for _, optionInfo in ipairs(categoryInfo.options) do
+ local itemID = optionInfo.itemID
+ local itemName = optionInfo.name
+ local label = optionInfo.label
+ local button = optionInfo.button
+ local frame = optionInfo.frame
+
+ if ConsumesManager_Settings[itemID] then
+ -- Sum counts across all selected characters
+ local totalCount = 0
+ for character, charData in pairs(data) do
+ if ConsumesManager_Settings["Characters"][character] == true then
+ local inventory = charData["inventory"] and charData["inventory"][itemID] or 0
+ local bank = charData["bank"] and charData["bank"][itemID] or 0
+ local mail = charData["mail"] and charData["mail"][itemID] or 0
+ totalCount = totalCount + inventory + bank + mail
+ end
+ end
+
+ -- Update label text with counts
+ label:SetText(itemName .. " (" .. totalCount .. ")")
+
+ -- Adjust label color based on count
+ if totalCount == 0 then
+ label:SetTextColor(1, 0, 0) -- Red
+ elseif totalCount < 10 then
+ label:SetTextColor(1, 0.4, 0) -- Orange
+ elseif totalCount <= 20 then
+ label:SetTextColor(1, 0.85, 0) -- Yellow
+ else
+ label:SetTextColor(0, 1, 0) -- Green
+ end
+
+ -- Enable or disable the 'Use' button based on whether the item is in the player's inventory
+ local playerInventory = data[playerName]["inventory"] or {}
+ local countInInventory = playerInventory[itemID] or 0
+ if countInInventory > 0 then
+ button:Enable()
+ else
+ button:Disable()
+ end
+
+ -- Show and position the option frame
+ frame:SetPoint("TOPLEFT", ManagerFrame.scrollChild, "TOPLEFT", 0, - (index) * lineHeight)
+ frame:Show()
+ index = index + 1
+ hasAnyVisibleItems = true
+ else
+ frame:Hide()
+ end
+ end
+
+ -- Add extra spacing after the category
+ index = index + 1 -- Add one extra line of spacing between categories
+ else
+ categoryInfo.label:Hide()
+ -- Hide all options under this category
+ for _, optionInfo in ipairs(categoryInfo.options) do
+ optionInfo.frame:Hide()
+ end
+ end
+ end
+
+ -- Adjust the scroll child height
+ ManagerFrame.scrollChild.contentHeight = index * lineHeight
+ ManagerFrame.scrollChild:SetHeight(ManagerFrame.scrollChild.contentHeight)
+
+ -- Update the scrollbar
+ ConsumesManager_UpdateManagerScrollBar()
+
+ if not hasAnyVisibleItems then
+ -- Show message when no items are selected
+ ManagerFrame.messageLabel:SetText("|cffff0000No consumables selected|r\n\n|cffffffffClick on |roptions|cffffffff to get started|r")
+ ManagerFrame.messageLabel:Show()
+ else
+ -- Hide the message label as we have content to display
+ ManagerFrame.messageLabel:Hide()
+ end
+end
+
+
+
+
+-- Scrollbar Window Updates -----------------------------------------------------------------------------
+function ConsumesManager_UpdateManagerScrollBar()
+ local ManagerFrame = ConsumesManager_MainFrame.tabs[1]
+ local scrollBar = ManagerFrame.scrollBar
+ local scrollFrame = ManagerFrame.scrollFrame
+ local scrollChild = ManagerFrame.scrollChild
+
+ local totalHeight = scrollChild:GetHeight()
+ local shownHeight = ManagerFrame:GetHeight() - 20 -- Account for padding/margins
+
+ if totalHeight > shownHeight then
+ local maxScroll = totalHeight - shownHeight
+ scrollFrame.range = maxScroll -- Set the scroll range
+ scrollBar:SetMinMaxValues(0, maxScroll)
+ scrollBar:SetValue(math.min(scrollBar:GetValue(), maxScroll))
+ scrollBar:Show()
+ else
+ scrollFrame.range = 0 -- Also handle this case
+ scrollBar:SetMinMaxValues(0, 0)
+ scrollBar:SetValue(0)
+ scrollBar:Hide()
+ end
+end
+
+function ConsumesManager_UpdateOptionsScrollBar()
+ local optionsFrame = ConsumesManager_MainFrame.tabs[2]
+ local scrollBar = optionsFrame.scrollBar
+ local scrollFrame = optionsFrame.scrollFrame
+ local scrollChild = optionsFrame.scrollChild
+
+ local totalHeight = scrollChild.contentHeight
+ local parentHeight = optionsFrame:GetHeight()
+ local searchBoxHeight = 36 -- Adjusted height including padding
+ local buttonsHeight = 40 -- Space reserved for Select/Deselect buttons
+ local shownHeight = parentHeight - searchBoxHeight - buttonsHeight - 20 -- Additional padding
+
+ local maxScroll = math.max(0, totalHeight - shownHeight)
+ scrollFrame.maxScroll = maxScroll
+
+ if totalHeight > shownHeight then
+ scrollBar:SetMinMaxValues(0, maxScroll)
+ scrollBar:SetValue(math.min(scrollBar:GetValue(), maxScroll))
+ scrollBar:Show()
+ else
+ scrollBar:SetMinMaxValues(0, 0)
+ scrollBar:SetValue(0)
+ scrollBar:Hide()
+ end
+end
+
+
+function ConsumesManager_UpdateCharactersScrollBar()
+ local charactersFrame = ConsumesManager_MainFrame.tabs[3]
+ local scrollBar = charactersFrame.scrollBar
+ local scrollFrame = charactersFrame.scrollFrame
+ local scrollChild = charactersFrame.scrollChild
+
+ local totalHeight = scrollChild.contentHeight
+ local shownHeight = 320 -- Adjust based on your UI
+
+ local maxScroll = math.max(0, totalHeight - shownHeight)
+ scrollFrame.maxScroll = maxScroll
+
+ if totalHeight > shownHeight then
+ scrollBar:SetMinMaxValues(0, maxScroll)
+ scrollBar:SetValue(math.min(scrollBar:GetValue(), maxScroll))
+ scrollBar:Show()
+ else
+ scrollBar:SetMinMaxValues(0, 0)
+ scrollBar:SetValue(0)
+ scrollBar:Hide()
+ end
+end
+
+
+
+-- Functions to USE an item -----------------------------------------------------------------------------
+function ConsumesManager_UpdateUseButtons()
+ if not ConsumesManager_MainFrame or not ConsumesManager_MainFrame.tabs or not ConsumesManager_MainFrame.tabs[1] then
+ return
+ end
+
+ local ManagerFrame = ConsumesManager_MainFrame.tabs[1]
+ local playerName = UnitName("player")
+ local realmName = GetRealmName()
+ local faction = UnitFactionGroup("player")
+
+ -- Ensure data structure exists
+ if not ConsumesManager_Data[realmName] or not ConsumesManager_Data[realmName][faction] then
+ return
+ end
+ local data = ConsumesManager_Data[realmName][faction]
+ local charData = data[playerName]
+ if not charData then return end
+
+ local inventory = charData["inventory"] or {}
+
+ -- Iterate over the options to update the buttons
+ for _, categoryInfo in ipairs(ManagerFrame.categoryInfo) do
+ for _, optionInfo in ipairs(categoryInfo.options) do
+ local itemID = optionInfo.itemID
+ local button = optionInfo.button
+ if ConsumesManager_Settings[itemID] then
+ local count = inventory[itemID] or 0
+ if count > 0 then
+ button:Enable()
+ else
+ button:Disable()
+ end
+ else
+ button:Disable()
+ end
+ end
+ end
+end
+
+function ConsumesManager_FindItemInBags(itemID)
+ for bag = 0, 4 do
+ local numSlots = GetContainerNumSlots(bag)
+ if numSlots then
+ for slot = 1, numSlots do
+ local link = GetContainerItemLink(bag, slot)
+ if link then
+ local _, _, linkItemID = string.find(link, "item:(%d+)")
+ if linkItemID then
+ linkItemID = tonumber(linkItemID)
+ if linkItemID == itemID then
+ return bag, slot
+ end
+ end
+ end
+ end
+ end
+ end
+ return nil, nil
+end
+
+
+
+-- Tooltip Windows --------------------------------------------------------------------------------------
+function ConsumesManager_ShowConsumableTooltip(itemID)
+ -- Ensure item is enabled in settings
+ if not ConsumesManager_Settings[itemID] then
+ return
+ end
+
+ -- Create or reuse custom tooltip frame
+ if not ConsumesManager_CustomTooltip then
+ -- Create the frame
+ local tooltipFrame = CreateFrame("Frame", "ConsumesManager_CustomTooltip", UIParent)
+ tooltipFrame:SetFrameStrata("TOOLTIP")
+ tooltipFrame:SetWidth(200)
+ tooltipFrame:SetBackdrop({
+ bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
+ edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
+ tile = true, tileSize = 16, edgeSize = 16,
+ insets = { left = 4, right = 4, top = 4, bottom = 4 }
+ })
+ tooltipFrame:SetBackdropColor(0, 0, 0, 1)
+
+ -- Item icon
+ local icon = tooltipFrame:CreateTexture(nil, "ARTWORK")
+ icon:SetWidth(32)
+ icon:SetHeight(32)
+ icon:SetPoint("TOPLEFT", tooltipFrame, "TOPLEFT", 10, -10)
+ tooltipFrame.icon = icon
+
+ -- Item name
+ local title = tooltipFrame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
+ title:SetPoint("TOPLEFT", icon, "TOPRIGHT", 10, -2)
+ title:SetPoint("RIGHT", tooltipFrame, "RIGHT", -10, 0)
+ title:SetJustifyH("LEFT")
+ title:SetTextColor(1,1,1)
+ tooltipFrame.title = title
+
+ -- Item Total
+ local total = tooltipFrame:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
+ total:SetPoint("TOPLEFT", icon, "TOPRIGHT", 10, -20)
+ total:SetPoint("RIGHT", tooltipFrame, "RIGHT", -10, 0)
+ total:SetJustifyH("LEFT")
+ tooltipFrame.total = total
+
+ -- Content text
+ local content = tooltipFrame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
+ content:SetPoint("TOPLEFT", icon, "BOTTOMLEFT", 0, -10)
+ content:SetPoint("RIGHT", tooltipFrame, "RIGHT", -10, 0)
+ content:SetJustifyH("LEFT")
+ tooltipFrame.content = content
+
+ ConsumesManager_CustomTooltip = tooltipFrame
+ end
+
+ local tooltipFrame = ConsumesManager_CustomTooltip
+
+ -- Get item info
+ local itemName = consumablesList[itemID] or "Unknown Item"
+ local itemTexture = consumablesTexture[itemID] or "Interface\\Icons\\INV_Misc_QuestionMark"
+
+ -- Set icon and title
+ tooltipFrame.icon:SetTexture(itemTexture)
+ tooltipFrame.title:SetText(itemName)
+
+ -- Prepare content text
+ local contentText = ""
+
+ local realmName = GetRealmName()
+ local faction = UnitFactionGroup("player")
+ local playerName = UnitName("player")
+
+ -- Ensure data structure exists
+ ConsumesManager_Data[realmName] = ConsumesManager_Data[realmName] or {}
+ ConsumesManager_Data[realmName][faction] = ConsumesManager_Data[realmName][faction] or {}
+
+ local data = ConsumesManager_Data[realmName][faction]
+
+ -- Initialize totals
+ local totalInventory, totalBank, totalMail = 0, 0, 0
+ local hasItems = false
+ local characterList = {}
+
+ -- Ensure character settings exist
+ ConsumesManager_Settings["Characters"] = ConsumesManager_Settings["Characters"] or {}
+
+ -- Collect data for each character
+ for character, charData in pairs(data) do
+ if ConsumesManager_Settings["Characters"][character] == true then
+ local inventory = charData["inventory"] and charData["inventory"][itemID] or 0
+ local bank = charData["bank"] and charData["bank"][itemID] or 0
+ local mail = charData["mail"] and charData["mail"][itemID] or 0
+ local total = inventory + bank + mail
+
+ if total > 0 then
+ hasItems = true
+ totalInventory = totalInventory + inventory
+ totalBank = totalBank + bank
+ totalMail = totalMail + mail
+
+ table.insert(characterList, {
+ name = character,
+ inventory = inventory,
+ bank = bank,
+ mail = mail,
+ total = total,
+ isPlayer = (character == playerName)
+ })
+ end
+ end
+ end
+
+ local totalItems = totalInventory + totalBank + totalMail
+ -- Adjust label color based on count
+ if totalItems == 0 then
+ tooltipFrame.total:SetTextColor(1, 0, 0) -- Red
+ elseif totalItems < 10 then
+ tooltipFrame.total:SetTextColor(1, 0.4, 0) -- Orange
+ elseif totalItems <= 20 then
+ tooltipFrame.total:SetTextColor(1, 0.85, 0) -- Yellow
+ else
+ tooltipFrame.total:SetTextColor(0, 1, 0) -- Green
+ end
+
+ tooltipFrame.total:SetText("Total: " .. totalItems)
+
+ if not hasItems then
+ contentText = contentText .. "|cffff0000No items found for this consumable.|r"
+ else
+
+ -- Sort characters alphabetically (optional)
+ table.sort(characterList, function(a, b) return a.name < b.name end)
+
+ -- Display data for each character
+ for _, charInfo in ipairs(characterList) do
+
+ local nameColor = charInfo.isPlayer and "|cff00ff00" or "|cffffffff" -- Green for player, grey for others
+ contentText = contentText .. nameColor .. charInfo.name .. " (" .. charInfo.total .. ")|r\n"
+
+ local detailText = ""
+ if charInfo.inventory > 0 then
+ detailText = detailText .. "|cffffffffInventory:|r " .. charInfo.inventory .. " "
+ end
+ if charInfo.bank > 0 then
+ detailText = detailText .. "|cffffffffBank:|r " .. charInfo.bank .. " "
+ end
+ if charInfo.mail > 0 then
+ detailText = detailText .. "|cffffffffMail:|r " .. charInfo.mail .. " "
+ end
+
+ contentText = contentText .. " " .. detailText .. "\n\n"
+ end
+ end
+
+ tooltipFrame.content:SetText(contentText)
+
+ -- Calculate the number of lines in contentText using string.gsub
+ local _, numLines = string.gsub(contentText, "\n", "")
+ numLines = numLines + 2 -- Add lines for title and padding
+
+ -- Adjust tooltip height based on the number of lines
+ local lineHeight = 10
+ local totalHeight = 50 + (numLines * lineHeight)
+ tooltipFrame:SetHeight(totalHeight)
+
+ -- Set the width based on content
+ local maxWidth = math.max(tooltipFrame.title:GetStringWidth() + 70, tooltipFrame.content:GetStringWidth() +20)
+ tooltipFrame:SetWidth(maxWidth)
+
+ -- Position the tooltip near the cursor
+ local x, y = GetCursorPosition()
+ local scale = UIParent:GetEffectiveScale()
+ tooltipFrame:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", x / scale + 10, y / scale - 10)
+
+ tooltipFrame:Show()
+end
+
+function ConsumesManager_ShowOptionsTooltip(itemID)
+ -- Set the maximum width for the description text
+ local maxDescriptionWidth = 160
+
+ -- Create or reuse the tooltip frame
+ if not ConsumesManager_OptionsTooltip then
+ -- Create the frame
+ local tooltipFrame = CreateFrame("Frame", "ConsumesManager_OptionsTooltip", UIParent)
+ tooltipFrame:SetFrameStrata("TOOLTIP")
+ tooltipFrame:SetBackdrop({
+ bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
+ edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
+ tile = true, tileSize = 16, edgeSize = 16,
+ insets = { left = 4, right = 4, top = 4, bottom = 4 }
+ })
+ tooltipFrame:SetBackdropColor(0, 0, 0, 1)
+
+ -- Item icon
+ local icon = tooltipFrame:CreateTexture(nil, "ARTWORK")
+ icon:SetWidth(32)
+ icon:SetHeight(32)
+ icon:SetPoint("TOPLEFT", tooltipFrame, "TOPLEFT", 10, -10)
+ tooltipFrame.icon = icon
+
+ -- Item name
+ local title = tooltipFrame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
+ title:SetPoint("TOPLEFT", icon, "TOPRIGHT", 10, -2)
+ title:SetJustifyH("LEFT")
+ tooltipFrame.title = title
+
+ -- Item description
+ local description = tooltipFrame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
+ description:SetPoint("TOPLEFT", icon, "TOPRIGHT", 10, -16)
+ description:SetWidth(maxDescriptionWidth)
+ description:SetJustifyH("LEFT")
+ description:SetTextColor(1, 1, 1)
+ tooltipFrame.description = description
+
+ ConsumesManager_OptionsTooltip = tooltipFrame
+ end
+
+ local tooltipFrame = ConsumesManager_OptionsTooltip
+
+ -- Get item info
+ local itemName = consumablesList[itemID] or "Unknown Item"
+ local itemTexture = consumablesTexture[itemID] or "Interface\\Icons\\INV_Misc_QuestionMark"
+ local itemDescription = consumablesDescription[itemID] or ""
+
+ -- Function to add line breaks manually
+ local function WrapText(text, maxWidth, fontObject)
+ local wrappedText = ""
+ local currentLine = ""
+ local space = " "
+ local testString = tooltipFrame:CreateFontString(nil, "OVERLAY", fontObject)
+ testString:SetWidth(0)
+ testString:SetHeight(0)
+ testString:Hide() -- We don't need to display this
+
+ -- Replace \n with spaces to avoid unintended line breaks
+ text = string.gsub(text, "\n", " ")
+
+ -- Split the text into words
+ for word in string.gfind(text, "%S+") do
+ local testLine = currentLine == "" and word or (currentLine .. space .. word)
+ testString:SetText(testLine)
+ if testString:GetStringWidth() > maxWidth then
+ wrappedText = wrappedText == "" and currentLine or (wrappedText .. "\n" .. currentLine)
+ currentLine = word
+ else
+ currentLine = testLine
+ end
+ end
+ wrappedText = wrappedText == "" and currentLine or (wrappedText .. "\n" .. currentLine)
+ return wrappedText
+ end
+
+ -- Wrap the description text
+ local wrappedDescription = WrapText(itemDescription, maxDescriptionWidth, "GameFontNormal")
+
+ -- Set icon, title, and description
+ tooltipFrame.icon:SetTexture(itemTexture)
+ tooltipFrame.title:SetText(itemName)
+ tooltipFrame.description:SetText(wrappedDescription)
+
+ -- Calculate the number of lines in the wrapped description
+ local _, lineCount = string.gsub(wrappedDescription, "\n", "")
+ lineCount = lineCount + 1 -- Add 1 for the last line
+
+ -- Set the heights for the description and the tooltip frame
+ local lineHeight = 12
+ tooltipFrame.description:SetHeight(lineCount * lineHeight)
+
+ local totalHeight = 50 + (lineCount * lineHeight)
+ tooltipFrame:SetHeight(totalHeight)
+
+ -- Set the width of the tooltip
+ local maxWidth = math.max(tooltipFrame.title:GetStringWidth() + 70, tooltipFrame.description:GetStringWidth() + 70)
+ tooltipFrame:SetWidth(maxWidth)
+
+ -- Position the tooltip near the cursor
+ local x, y = GetCursorPosition()
+ local scale = UIParent:GetEffectiveScale()
+ tooltipFrame:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", x / scale + 10, y / scale - 10)
+
+ tooltipFrame:Show()
+end
+
+
+
+-- Scan Functions ---------------------------------------------------------------------------------------
+function ConsumesManager_ScanPlayerInventory()
+ local playerName = UnitName("player")
+ local realmName = GetRealmName()
+ local faction = UnitFactionGroup("player")
+
+ -- Initialize data structures
+ ConsumesManager_Data[realmName] = ConsumesManager_Data[realmName] or {}
+ ConsumesManager_Data[realmName][faction] = ConsumesManager_Data[realmName][faction] or {}
+ ConsumesManager_Data[realmName][faction][playerName] = ConsumesManager_Data[realmName][faction][playerName] or {}
+ local data = ConsumesManager_Data[realmName][faction][playerName]
+ data["inventory"] = {}
+
+ -- Scan all bags (0 to 4 represent backpack and additional bags)
+ for bag = 0, 4 do
+ local numSlots = GetContainerNumSlots(bag)
+ if numSlots then
+ for slot = 1, numSlots do
+ local link = GetContainerItemLink(bag, slot)
+ if link then
+ local _, _, itemID = string.find(link, "item:(%d+)")
+ if itemID then
+ itemID = tonumber(itemID)
+ -- Scan all items, regardless of selection
+ local texture, itemCount = GetContainerItemInfo(bag, slot)
+ if itemCount and itemCount > 0 then
+ data["inventory"][itemID] = (data["inventory"][itemID] or 0) + itemCount
+ end
+ end
+ end
+ end
+ end
+ end
+
+ -- Update the Manager window and use buttons
+ ConsumesManager_UpdateUseButtons()
+ ConsumesManager_UpdateManagerContent()
+end
+
+function ConsumesManager_ScanPlayerBank()
+ -- Ensure the BankFrame is open before scanning
+ if not BankFrame or not BankFrame:IsShown() then
+ return
+ end
+
+ local playerName = UnitName("player")
+ local realmName = GetRealmName()
+ local faction = UnitFactionGroup("player")
+
+ -- Initialize data structures
+ ConsumesManager_Data[realmName] = ConsumesManager_Data[realmName] or {}
+ ConsumesManager_Data[realmName][faction] = ConsumesManager_Data[realmName][faction] or {}
+ ConsumesManager_Data[realmName][faction][playerName] = ConsumesManager_Data[realmName][faction][playerName] or {}
+ local data = ConsumesManager_Data[realmName][faction][playerName]
+ data["bank"] = {}
+
+ -- In WoW 1.12, bank bags are -1 and 5 to 10
+ for bag = -1, 10 do
+ if bag == -1 or (bag >= 5 and bag <= 10) then
+ local numSlots = GetContainerNumSlots(bag)
+ if numSlots then
+ for slot = 1, numSlots do
+ local link = GetContainerItemLink(bag, slot)
+ if link then
+ local _, _, itemID = string.find(link, "item:(%d+)")
+ if itemID then
+ itemID = tonumber(itemID)
+ -- Scan all items, regardless of selection
+ local texture, itemCount = GetContainerItemInfo(bag, slot)
+ if itemCount and itemCount > 0 then
+ data["bank"][itemID] = (data["bank"][itemID] or 0) + itemCount
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+
+ -- Update the Manager window
+ ConsumesManager_UpdateManagerContent()
+end
+
+function ConsumesManager_ScanPlayerMail()
+ -- Ensure the MailFrame is open before scanning
+ if not MailFrame or not MailFrame:IsShown() then
+ return
+ end
+
+ local playerName = UnitName("player")
+ local realmName = GetRealmName()
+ local faction = UnitFactionGroup("player")
+
+ -- Initialize data structures
+ ConsumesManager_Data[realmName] = ConsumesManager_Data[realmName] or {}
+ ConsumesManager_Data[realmName][faction] = ConsumesManager_Data[realmName][faction] or {}
+ ConsumesManager_Data[realmName][faction][playerName] = ConsumesManager_Data[realmName][faction][playerName] or {}
+ local data = ConsumesManager_Data[realmName][faction][playerName]
+ data["mail"] = {}
+
+ local numInboxItems = GetInboxNumItems()
+ if numInboxItems and numInboxItems > 0 then
+ for mailIndex = 1, numInboxItems do
+ local itemName, itemTexture, itemCount, itemQuality = GetInboxItem(mailIndex)
+ if itemName and itemCount and itemCount > 0 then
+ -- Since GetInboxItemLink is not available in 1.12, use itemName to get itemID
+ local itemID = consumablesNameToID[itemName]
+ if itemID then
+ -- Scan all items, regardless of selection
+ data["mail"][itemID] = (data["mail"][itemID] or 0) + itemCount
+ end
+ end
+ end
+ end
+
+ -- Update the Manager window
+ ConsumesManager_UpdateManagerContent()
+end
diff --git a/README.md b/README.md
deleted file mode 100644
index cd338c7..0000000
--- a/README.md
+++ /dev/null
@@ -1,40 +0,0 @@
-Currently in beta and needs testing. Report bugs here: https://github.com/Cinecom/ConsumesTracker/issues
-
-# ConsumesTracker
-Created with ♥ by Horyoshi for World of Warcraft 1.12 Turtle WoW
-Tracks your inventory, bank and mail for consumables. Works through multiple characters on the same account.
-
-## How To
-
-Unzip the file and place the 'ConsumesTracker' folder in your /Interface/AddOns folder. Remove '-master' from the folder name!
-
-Click the mini-map icon to open/close the Tracker
-- Tracker: shows the consumables that you track (need innitial setup, just follow instructions)
-- Options: enable / disable items you want to track
-- Characters: exclude characters you don't want to track
-
-## Future Features
-
-- Syncing across multiple accounts on the same server (bank alts)
-- View preset lists for your class for specific raids. (ie. shows list of consumes that a mage needs to bring to BWL)
-
-
-
-## Changelog
-
-**##V1.4.1**
-```
-- Can now be updated via the Turtle WoW launcher
-```
-
-
-
-**V1.4**
-```
-- Updated consumables list
-- Fixed icons and ID's for all consumables
-- Fixed an issue where the consumables counting could be a negative value
-- Added a search filter in the options window
-- Fixed general styling issues
-- You can now close the addon window by pressing 'Esc'
-```
diff --git a/minimap_icon.xml b/minimap_icon.xml
index 7451ea7..ab5cb39 100644
--- a/minimap_icon.xml
+++ b/minimap_icon.xml
@@ -1,5 +1,5 @@
-