diff --git a/BulwarkFrame.toc b/BulwarkFrame.toc index 3f88c8e..bc449b2 100644 --- a/BulwarkFrame.toc +++ b/BulwarkFrame.toc @@ -2,7 +2,7 @@ ## Title: BulwarkFrame ## Notes: Compact real-time readout for the shaman Earthen Bulwark. Requires SuperWoW. ## Author: ShempError -## Version: 0.3.0 +## Version: 0.3.1 ## SavedVariables: BulwarkFrameDB core\env.lua diff --git a/CHANGELOG.md b/CHANGELOG.md index b5ce4f8..b3a9049 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,22 @@ All notable changes to BulwarkFrame are documented here. +## v0.3.1 — 2026-08-31 + +### Fixed +- **Aura-id edit boxes no longer accept 0.** A QA pass on the options panel + found that `tonumber("0")` is truthy, so typing `0` into the pool or time + aura spell-id field was accepted as a valid id and silently written -- + spell ids never start at 0, so this was a silent no-op buffer. `0` (and + negative values) are now rejected exactly like any unparsable entry: the + field reverts to the currently stored id. +- **Pool/expiry red and yellow thresholds can no longer cross.** The four + threshold sliders had no cross-validation, so dragging the red slider + past yellow (or yellow past red) inverted the colour chain in + `core/calc.lua`'s bucket logic. The slider being moved now pulls its + partner along with it instead of letting the pair invert, and the panel + display re-syncs immediately. + ## v0.3.0 — 2026-08-30 ### Added diff --git a/README.md b/README.md index bef91fb..0fb82f7 100644 --- a/README.md +++ b/README.md @@ -10,15 +10,17 @@ stands. Three thin bars, nothing else. No dependencies beyond SuperWoW; adopts t The readout: hit threshold, expiry bar with the swing marker riding on it -## What's new — v0.3.0 · 2026-08-30 +## What's new — v0.3.1 · 2026-08-31 -- **Every setting has a control now.** Ten saved settings could only be changed by editing the - SavedVariables file; the options panel now covers bar spacing, the attack-speed text, expiry - bar opacity, background colour and opacity, the four colour thresholds, the set-bonus value, - the latency share and the two aura ids. +- **Aura-id edit boxes no longer accept 0.** `0` and negative values are now rejected like any + unparsable entry instead of being written as a spell id. +- **Pool/expiry red and yellow thresholds can no longer cross.** Dragging one past its partner + now pulls the partner along instead of inverting the colour chain. **Version history** — details in [CHANGELOG.md](CHANGELOG.md): +- **v0.3.1** (2026-08-31) — aura-id edit boxes reject `0`; pool/expiry threshold sliders can + no longer cross. - **v0.3.0** (2026-08-30) — options-panel controls for every setting that had none. - **v0.2.0** (2026-08-15) — max health stays accurate through stamina buffs and level-ups, "Combat only" no longer sticks off after a mid-fight reload, `/bulwark reset` really moves a diff --git a/options.lua b/options.lua index 4bd4fa4..d1f48d1 100644 --- a/options.lua +++ b/options.lua @@ -218,7 +218,10 @@ local function CreateEditBox(parent, label, tip, getter, setter) local function commit() local v = tonumber(eb:GetText()) - if v then + -- Spell ids start at 1 -- 0 (or negative) is never a real aura id, and tonumber("0") + -- is truthy, so it has to be rejected explicitly rather than falling through as if it + -- were a valid id. Treated exactly like any other unparsable entry: revert, don't write. + if v and math.floor(v) >= 1 then eb.bfSet(math.floor(v)) else eb:SetText(tostring(getter())) @@ -481,30 +484,50 @@ local function BuildPanel() headR("Thresholds") + -- Keeps a red/yellow threshold pair from inverting (red > yellow would break the colour + -- chain in core/calc.lua's poolColorName/timeColorName -- values below "green" would never + -- reach it, since "red" already claims everything up to its now-higher bound). The slider + -- the user is actively moving wins; its partner is pulled along to match instead of being + -- left crossed. Only refreshes the panel when a clamp actually fired, so an ordinary + -- (non-crossing) drag stays a single write. This is the one place both keys of a pair are + -- ever written from the panel -- there is no slash-command path for these -- so the clamp + -- lives here rather than in a shared config setter. + local function clampPair(loKey, hiKey, movedKey, v) + local d = db() + d[movedKey] = v + if movedKey == loKey and d[hiKey] and d[loKey] > d[hiKey] then + d[hiKey] = d[loKey] + BF.RefreshOptions() + elseif movedKey == hiKey and d[loKey] and d[hiKey] < d[loKey] then + d[loKey] = d[hiKey] + BF.RefreshOptions() + end + end + local poolRed = CreateSlider(panel, "Pool red threshold", 0, 100, 5, "Pool turns red below: %.0f%%", "The threshold bar turns red at or below this fraction of the pool.", function() return (db().poolRed or 0.30) * 100 end, - function(v) db().poolRed = v / 100 end) + function(v) clampPair("poolRed", "poolYellow", "poolRed", v / 100) end) sliderR(poolRed) local poolYellow = CreateSlider(panel, "Pool yellow threshold", 0, 100, 5, "Pool turns green above: %.0f%%", "The threshold bar turns green above this fraction of the pool (yellow in between).", function() return (db().poolYellow or 0.70) * 100 end, - function(v) db().poolYellow = v / 100 end) + function(v) clampPair("poolRed", "poolYellow", "poolYellow", v / 100) end) sliderR(poolYellow) local timeRed = CreateSlider(panel, "Expiry red threshold", 0, BF.BUFFER_DURATION, 0.5, "Expiry turns red below: %.1fs", "The expiry bar turns red once fewer than this many seconds remain.", function() return db().timeRed or 2.0 end, - function(v) db().timeRed = v end) + function(v) clampPair("timeRed", "timeYellow", "timeRed", v) end) sliderR(timeRed) local timeYellow = CreateSlider(panel, "Expiry yellow threshold", 0, BF.BUFFER_DURATION, 0.5, "Expiry turns green above: %.1fs", "The expiry bar turns green once more than this many seconds remain (yellow in between).", function() return db().timeYellow or 5.0 end, - function(v) db().timeYellow = v end) + function(v) clampPair("timeRed", "timeYellow", "timeYellow", v) end) sliderR(timeYellow) headR("Absorb model") @@ -609,7 +632,7 @@ local function BuildPanel() probeBtn:SetWidth(btnW) resetBtn:SetWidth(btnW) - local ver = (GetAddOnMetadata and GetAddOnMetadata("BulwarkFrame", "Version")) or "0.2.0" + local ver = (GetAddOnMetadata and GetAddOnMetadata("BulwarkFrame", "Version")) or "0.3.1" local verFS = panel:CreateFontString("BulwarkFrameOptionsVersion", "OVERLAY", "GameFontNormalSmall") ApplyFont(verFS, 10) verFS:SetPoint("BOTTOM", panel, "BOTTOM", 0, 6)