2 Commits

Author SHA1 Message Date
ShempError 03e0fe13a8 BulwarkFrame v0.3.1 2026-08-30 23:24:22 +02:00
ShempError 2596721daf BulwarkFrame README: what's new at the top 2026-08-30 15:50:50 +02:00
4 changed files with 62 additions and 7 deletions
+1 -1
View File
@@ -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
+16
View File
@@ -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
+16
View File
@@ -10,6 +10,22 @@ stands. Three thin bars, nothing else. No dependencies beyond SuperWoW; adopts t
<img src="screenshots/readout-hit.png" alt="The readout: hit threshold, expiry bar with the swing marker riding on it" width="100%">
## What's new — v0.3.1 · 2026-08-31
- **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
frame stranded off-screen, and the update loop parks itself while idle.
## Screenshots
| The readout | Options panel |
+29 -6
View File
@@ -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)