diff --git a/config.lua b/config.lua index a672947..8b14109 100644 --- a/config.lua +++ b/config.lua @@ -14,7 +14,7 @@ ns.config = { ["size"] = 1 }, ["gametooltip"] = true, -- enabled tooltips - ["dev"] = false, -- enables dev/development.lua commands + ["dev"] = true, -- enables dev/development.lua commands } } diff --git a/core/button.lua b/core/button.lua index 7cadeb0..e35e616 100644 --- a/core/button.lua +++ b/core/button.lua @@ -51,6 +51,8 @@ do else GameTooltip:SetUnitBuffByAuraInstanceID(self.unit, self.auraInstanceID) end + elseif self.itemId then + GameTooltip:SetItemByID(self.itemId) elseif self.slotId then GameTooltip:SetInventoryItem(self.unit, self.slotId) elseif self.spellId then diff --git a/core/data.lua b/core/data.lua index c782cce..f8a6860 100644 --- a/core/data.lua +++ b/core/data.lua @@ -50,6 +50,14 @@ function data.CreateSlotCooldown(slotId, enabled) return { slotId = slotId, enabled = enabled } end +-- one row for the shared potion cooldown; the element resolves it to whichever potion is in the bags +function data.CreatePotionCooldown(enabled) + if (enabled == nil) then + enabled = true + end + return { potion = true, enabled = enabled } +end + -- true when the client's expansion is within from..to (inclusive; `to` optional); -- reads ns.client at call time, since core\init.xml loads after this file function data.In(from, to) @@ -117,7 +125,7 @@ local collectCooldowns = function(class, seen, out, invalid) table.insert(invalid, { kind = "duplicate", class = class, id = row.spellId }) elseif row.enabled then if row.spellId then seen[row.spellId] = true end - if row.slotId or GetSpellInfo(row.spellId) then + if row.slotId or row.potion or GetSpellInfo(row.spellId) then if out then table.insert(out, row) end else table.insert(invalid, { kind = "cooldown", class = class, id = row.spellId }) diff --git a/data/Mists/spells.lua b/data/Mists/spells.lua index dc58d68..ab161f0 100644 --- a/data/Mists/spells.lua +++ b/data/Mists/spells.lua @@ -7,15 +7,9 @@ local AddSpells = ns.data.AddSpells -- Mists of Pandaria Classic -------------------------------------------------- local data = { - ["PALADIN"] = { - -- Holy - [82327] = CreateSpellPriority(5), -- Holy Radiance - [86273] = CreateSpellPriority(5), -- Illuminated Healing - }, - ["PRIEST"] = { - -- Discipline - [81661] = CreateSpellPriority(8), -- Evangelism - [59889] = CreateSpellPriority(7), -- Borrowed Time + ["MAGE"] = { + -- Arcane + [36032] = CreateSpellPriority(10), -- Arcane Charges }, ["MONK"] = { [115080] = CreateSpellPriority(false), -- Touch of Death @@ -28,7 +22,17 @@ local data = { [125359] = CreateSpellPriority(8), -- Tiger Power [128939] = CreateSpellPriority(9), -- Elusive Brew [132365] = CreateSpellPriority(10), -- Vengeance - } + }, + ["PALADIN"] = { + -- Holy + [82327] = CreateSpellPriority(5), -- Holy Radiance + [86273] = CreateSpellPriority(5), -- Illuminated Healing + }, + ["PRIEST"] = { + -- Discipline + [81661] = CreateSpellPriority(8), -- Evangelism + [59889] = CreateSpellPriority(7), -- Borrowed Time + }, } AddSpells(data) diff --git a/data/shared/cooldowns.lua b/data/shared/cooldowns.lua index 3c587ce..06d9282 100644 --- a/data/shared/cooldowns.lua +++ b/data/shared/cooldowns.lua @@ -2,6 +2,7 @@ local _, ns = ... local CreateSpellCooldown = ns.data.CreateSpellCooldown local CreateSlotCooldown = ns.data.CreateSlotCooldown +local CreatePotionCooldown = ns.data.CreatePotionCooldown local AddCooldowns = ns.data.AddCooldowns local expansion = ns.client.expansion @@ -26,6 +27,7 @@ local gear = { CreateSlotCooldown(6), -- Waist CreateSlotCooldown(13), -- Trinket 1 CreateSlotCooldown(14), -- Trinket 2 + CreatePotionCooldown(true), -- Potions (shared cooldown) } -- racials and gear slots go after the player class cooldowns diff --git a/dev/development.lua b/dev/development.lua index bc51ff1..96f95cd 100644 --- a/dev/development.lua +++ b/dev/development.lua @@ -142,7 +142,8 @@ local dump = function() -- cooldown order is display order, so it is not sorted local cooldowns = {} for _, row in ipairs(ns.data.cooldowns) do - table.insert(cooldowns, row.spellId and ("spell" .. row.spellId) or ("slot" .. row.slotId)) + table.insert(cooldowns, row.spellId and ("spell" .. row.spellId) + or row.slotId and ("slot" .. row.slotId) or "potion") end print(Filger.title, "dump: blacklist", #ids, "ids", checksum(ids), "/", #names, "names", checksum(names)) diff --git a/docs/todo.md b/docs/todo.md new file mode 100644 index 0000000..8f3545b --- /dev/null +++ b/docs/todo.md @@ -0,0 +1,9 @@ +# To do + +Open checks that need a client. + +- **Forever runtime:** does the Mainline aura and cooldown path work on Forever? All the required + APIs are in the Forever docs. Check with `/reload` on Forever and look at every frame. +- **Forever blacklist:** Forever inherits every shared blacklist range starting at `LE.Classic` + (same as Era minus Hardcore and Season of Discovery). Check `/filger validate` reports nothing + and `/filger dump` matches `lua tests/dump.lua` for Camelot. diff --git a/elements/cooldowns.lua b/elements/cooldowns.lua index 99bdbcc..0c0c5c5 100644 --- a/elements/cooldowns.lua +++ b/elements/cooldowns.lua @@ -6,6 +6,13 @@ local GetInventoryItemLink = _G.GetInventoryItemLink local GetItemInfo = C_Item.GetItemInfo local GetInventoryItemCooldown = _G.GetInventoryItemCooldown local GetOverrideSpell = C_Spell and C_Spell.GetOverrideSpell +local GetItemCooldown = C_Container.GetItemCooldown +local GetContainerNumSlots = C_Container.GetContainerNumSlots +local GetContainerItemID = C_Container.GetContainerItemID +local GetItemInfoInstant = C_Item.GetItemInfoInstant +local GetItemSpell = C_Item.GetItemSpell +local NUM_BAG_SLOTS = _G.NUM_BAG_SLOTS +local Enum = _G.Enum -- Compat local GetSpellInfo = ns.compat.GetSpellInfo @@ -18,6 +25,26 @@ local IsSecret = ns.compat.IsSecret -------------------------------------------------- local cooldown_proto = {} +-- adds use spell ID -> item ID for every potion in the bags; never wiped, so the last potion +-- still maps if the bags update before its cast event. +-- some potion-class items have their own cooldown, so the drunk one is picked by its cast +local scanPotions = function(potions) + for bag = 0, NUM_BAG_SLOTS do + for slot = 1, GetContainerNumSlots(bag) do + local itemId = GetContainerItemID(bag, slot) + if itemId then + local _, _, _, _, _, classId, subClassId = GetItemInfoInstant(itemId) + if classId == Enum.ItemClass.Consumable and subClassId == Enum.ItemConsumableSubclass.Potion then + local _, spellId = GetItemSpell(itemId) + if spellId then + potions[spellId] = itemId + end + end + end + end + end +end + do --[[ Callback: cooldown_proto:Update(unit, data, index) Update the cooldown button and its components. @@ -38,6 +65,7 @@ do button.unit = unit button.spellId = data.spellId button.slotId = data.slotId + button.itemId = data.itemId -- timers button.expirationTime = data.expirationTime or GetTime() @@ -112,7 +140,8 @@ do local d = self.rows[data] if not d then d = { - index = data.spellId and ("SPELL_" .. data.spellId) or ("SLOT_" .. data.slotId), + index = data.spellId and ("SPELL_" .. data.spellId) + or data.slotId and ("SLOT_" .. data.slotId) or "POTION", spellId = data.spellId, slotId = data.slotId } @@ -162,6 +191,20 @@ do d.itemLink = nil enabled = 0 end + elseif data.potion then + local itemId = self.potionId + if itemId and itemId ~= d.itemId then + local name, _, _, _, _, _, _, _, _, icon = GetItemInfo(itemId) + d.name = name + d.icon = icon + -- item info can be uncached on first lookup; keep retrying until it returns a name + d.itemId = name and itemId + end + if d.itemId then + start, duration, enabled = GetItemCooldown(d.itemId) + else + enabled = 0 + end end duration = duration or 0 @@ -240,6 +283,11 @@ do end end + -- potionId is kept when the potion leaves the bags, so a running cooldown stays shown + function cooldown_proto:BAG_UPDATE_DELAYED() + scanPotions(self.potions) + end + -- talent/spec changes alter isKnown and overrides function cooldown_proto:SPELLS_CHANGED() self:ForceUpdate() @@ -249,6 +297,13 @@ do function cooldown_proto:UNIT_SPELLCAST_SUCCEEDED(unit, guid, spellId) if IsSecret(spellId) then return end self.casted[spellId] = true + + -- SPELL_UPDATE_COOLDOWN can fire before this, so refresh once the drunk potion is known + local itemId = self.potions and self.potions[spellId] + if itemId and itemId ~= self.potionId then + self.potionId = itemId + self:ForceUpdate() + end end function cooldown_proto:Enable(data) @@ -264,6 +319,15 @@ do self:RegisterEvent("PLAYER_EQUIPMENT_CHANGED") self:RegisterEvent("SPELLS_CHANGED") self:RegisterUnitEvent("UNIT_SPELLCAST_SUCCEEDED", self.unit) + + for _, row in next, self.spells do + if row.potion then + self.potions = {} + scanPotions(self.potions) + self:RegisterEvent("BAG_UPDATE_DELAYED") + break + end + end end end diff --git a/tests/dump.lua b/tests/dump.lua index 5070095..09ecb40 100644 --- a/tests/dump.lua +++ b/tests/dump.lua @@ -114,7 +114,8 @@ for _, game in ipairs(games) do for _, class in ipairs(classes) do if class ~= classes[1] then data = build(game, class) end for i, row in ipairs(data.cooldowns) do - emit(tag, "cooldown", class, i, row.spellId and ("spell " .. row.spellId) or ("slot " .. row.slotId)) + emit(tag, "cooldown", class, i, row.spellId and ("spell " .. row.spellId) + or row.slotId and ("slot " .. row.slotId) or "potion") end local invalid = {} for _, entry in ipairs(data.invalid) do