AnySCT 0.3.1
This commit is contained in:
+1
-1
@@ -2,7 +2,7 @@
|
|||||||
## Title: AnySCT
|
## Title: AnySCT
|
||||||
## Notes: Blizzard-pet-style floating combat text for any units you pick: tanks, their pets and totems, mobs, enemy players.
|
## Notes: Blizzard-pet-style floating combat text for any units you pick: tanks, their pets and totems, mobs, enemy players.
|
||||||
## Author: ShempError
|
## Author: ShempError
|
||||||
## Version: 0.3.0
|
## Version: 0.3.1
|
||||||
## X-Website: https://octowow.st/git/ShempError/AnySCT
|
## X-Website: https://octowow.st/git/ShempError/AnySCT
|
||||||
## OptionalDeps: pfUI, CT_RaidAssist, oRA, TWThreat
|
## OptionalDeps: pfUI, CT_RaidAssist, oRA, TWThreat
|
||||||
## SavedVariables: AnySCTDB
|
## SavedVariables: AnySCTDB
|
||||||
|
|||||||
@@ -2,6 +2,12 @@
|
|||||||
|
|
||||||
All notable changes to AnySCT are documented here.
|
All notable changes to AnySCT are documented here.
|
||||||
|
|
||||||
|
## 0.3.1 — 2026-10-15
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Lines in a tower no longer overlap: each line reserves its real height (crits at the peak of their size pop) plus the suffix line hanging below the line above it, and crits now rise with the rest of the stack instead of standing still, so newer lines can no longer rise into them.
|
||||||
|
- Crits of tiny procs (relative to the source's average hit) pop at up to half size.
|
||||||
|
|
||||||
## 0.3.0 — 2026-10-15
|
## 0.3.0 — 2026-10-15
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|||||||
@@ -16,6 +16,14 @@ are on the list, your own SCT addon stays the only one that shows your damage).
|
|||||||
*A listed tank hitting the training dummies in Orgrimmar, seen from another character: an orange melee
|
*A listed tank hitting the training dummies in Orgrimmar, seen from another character: an orange melee
|
||||||
"Miss", a gold spell "Resist", and the experimental WAIT label under the dummy being attacked.*
|
"Miss", a gold spell "Resist", and the experimental WAIT label under the dummy being attacked.*
|
||||||
|
|
||||||
|
## What's new — 0.3.1 · 2026-10-15
|
||||||
|
|
||||||
|
- **The line tower no longer overlaps.** Every line reserves its real height, including the crit size pop
|
||||||
|
and the spell / name line under it, and crits now rise with the rest of the stack, so newer lines can
|
||||||
|
not run into them.
|
||||||
|
- **Crits of tiny procs pop smaller** (a crit "3" among Fire Strike ticks is half size), measured against
|
||||||
|
the source's average hit.
|
||||||
|
|
||||||
## What's new — 0.3.0 · 2026-10-15
|
## What's new — 0.3.0 · 2026-10-15
|
||||||
|
|
||||||
- **Identical hits are merged.** Fire Strike style tick storms become one line with the running sum
|
- **Identical hits are merged.** Fire Strike style tick storms become one line with the running sum
|
||||||
@@ -45,6 +53,8 @@ are on the list, your own SCT addon stays the only one that shows your damage).
|
|||||||
|
|
||||||
**Version history** — details in [CHANGELOG.md](CHANGELOG.md):
|
**Version history** — details in [CHANGELOG.md](CHANGELOG.md):
|
||||||
|
|
||||||
|
- **0.3.1** (2026-10-15) — fix: the line tower no longer overlaps (real line heights, crits rise with the
|
||||||
|
stack), crits of tiny procs pop smaller.
|
||||||
- **0.3.0** (2026-10-15) — merged identical hits, "Nameplate + anchor" placement, a demo that plays your own
|
- **0.3.0** (2026-10-15) — merged identical hits, "Nameplate + anchor" placement, a demo that plays your own
|
||||||
targetSCT's class burst and previews GO / WAIT, anchor drop fix.
|
targetSCT's class burst and previews GO / WAIT, anchor drop fix.
|
||||||
- **0.2.0** (2026-10-15) — targetSCT rename, name option, per-targetSCT colours, regrouped options with
|
- **0.2.0** (2026-10-15) — targetSCT rename, name option, per-targetSCT colours, regrouped options with
|
||||||
@@ -57,7 +67,7 @@ are on the list, your own SCT addon stays the only one that shows your damage).
|
|||||||
Everything floats over the **victim** of the event, never over the source:
|
Everything floats over the **victim** of the event, never over the source:
|
||||||
|
|
||||||
- **Melee in orange, special attacks in gold, heals in green.** Numbers use the client's own damage font,
|
- **Melee in orange, special attacks in gold, heals in green.** Numbers use the client's own damage font,
|
||||||
no outline, a black shadow. Ordinary hits rise and fade; **crits pop** at a larger size and stay in place.
|
no outline, a black shadow. Ordinary hits rise and fade; **crits pop** at a larger size and rise with the stack.
|
||||||
- **Words for what did not land**: Miss, Dodge, Parry, Block, Resist, Immune, ... in the same style.
|
- **Words for what did not land**: Miss, Dodge, Parry, Block, Resist, Immune, ... in the same style.
|
||||||
- **Every hit is shown**: up to 16 lines per mob and 60 on screen by default, so a fast burst is not
|
- **Every hit is shown**: up to 16 lines per mob and 60 on screen by default, so a fast burst is not
|
||||||
recycled early (both are sliders on the Text tab).
|
recycled early (both are sliders on the Text tab).
|
||||||
@@ -71,11 +81,18 @@ Everything floats over the **victim** of the event, never over the source:
|
|||||||
*A crit "366" popping over the Heroic Training Dummy, a "Block" in grey, and a GO label partly covered by
|
*A crit "366" popping over the Heroic Training Dummy, a "Block" in grey, and a GO label partly covered by
|
||||||
the crit.*
|
the crit.*
|
||||||
|
|
||||||
<img src="screenshots/demo-anchor-tower.png" alt="Demo at the fixed anchor: a shaman burst with spell names, merged Fire Strike ticks, words and the WAIT label inside the anchor box" width="300">
|
<table>
|
||||||
|
<tr>
|
||||||
*The Demo button at the fixed anchor (no target): a shaman burst with spell names on - a 783 Stormstrike
|
<td align="center" width="50%">
|
||||||
crit, a white hit, merged Fire Strike ticks (7), Miss / Dodge / Parry / Block, and the GO / WAIT preview
|
<a href="screenshots/anchor-wait.png"><img src="screenshots/anchor-wait.png" width="300" alt="Demo at the fixed anchor early in the burst: a tower of numbers and words and WAIT 1350 / 1500 inside the anchor box"></a><br>
|
||||||
"WAIT 1200 / 1500" inside the anchor box.*
|
<sub><b>WAIT at the anchor</b> — the Demo's shaman burst, no overlaps: a faded 783 Stormstrike on top, Dodge, 97, a merged 7 Fire Strike, Parry, Block, 100 Ancient Accord, a half-size crit 3 Fire Strike, and "WAIT 1350 / 1500" inside the anchor box</sub>
|
||||||
|
</td>
|
||||||
|
<td align="center" width="50%">
|
||||||
|
<a href="screenshots/anchor-go.png"><img src="screenshots/anchor-go.png" width="300" alt="Demo at the fixed anchor later in the burst: crits 216 and 760 in the tower and GO +1875 inside the anchor box"></a><br>
|
||||||
|
<sub><b>GO at the anchor</b> — later in the burst: a fading Ancient Accord, 3 Fire Strike, Resist, 7 Fire Strike, a big crit 216, 194, a crit 760 Earth Shock, and "GO +1875" inside the box</sub>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
## GO / WAIT threat label (experimental)
|
## GO / WAIT threat label (experimental)
|
||||||
|
|
||||||
@@ -236,7 +253,7 @@ six sliders including the line limits) below.*
|
|||||||
| Direction | text rises (Up) or sinks (Down) | Up |
|
| Direction | text rises (Up) or sinks (Down) | Up |
|
||||||
| Number size | factor on the engine size, 0.5-3 | 1.00 |
|
| Number size | factor on the engine size, 0.5-3 | 1.00 |
|
||||||
| Word size | same for Miss / Dodge / Parry ... | 1.00 |
|
| Word size | same for Miss / Dodge / Parry ... | 1.00 |
|
||||||
| Rise (px) | how far a normal text rises, 0-300; crits stay in place | 120 |
|
| Rise (px) | how far a normal text rises, 0-300; crits rise with the stack | 120 |
|
||||||
| Jitter (px) | random horizontal offset per line, 0-40 | 0 |
|
| Jitter (px) | random horizontal offset per line, 0-40 | 0 |
|
||||||
| Max lines | lines on screen over all mobs, 3-100; the oldest is recycled at the limit | 60 |
|
| Max lines | lines on screen over all mobs, 3-100; the oldest is recycled at the limit | 60 |
|
||||||
| Max lines per mob | lines over one mob, 1-30; lines live 1.5 s, so 16 shows every hit of a burst of about 10 per second | 16 |
|
| Max lines per mob | lines over one mob, 1-30; lines live 1.5 s, so 16 shows every hit of a burst of about 10 per second | 16 |
|
||||||
|
|||||||
+1
-1
@@ -97,7 +97,7 @@ if CreateFrame then
|
|||||||
"Size factor of damage numbers. Size = 0.018333 x screen diagonal x factor (crits 0.0275): 23 px at 1024x768, 54 px at 2560x1440." },
|
"Size factor of damage numbers. Size = 0.018333 x screen diagonal x factor (crits 0.0275): 23 px at 1024x768, 54 px at 2560x1440." },
|
||||||
{ "wordFactor", "Word size", 0.5, 3, 0.05, "%.2f", "Size factor of Miss / Dodge / Parry / ..." },
|
{ "wordFactor", "Word size", 0.5, 3, 0.05, "%.2f", "Size factor of Miss / Dodge / Parry / ..." },
|
||||||
{ "riseHeight", "Rise (px)", 0, 300, 5, nil,
|
{ "riseHeight", "Rise (px)", 0, 300, 5, nil,
|
||||||
"How far a normal text rises (crits stay in place). The engine rises 2 yards; the screen distance depends on the camera." },
|
"How far a normal text rises (crits rise with the stack). The engine rises 2 yards; the screen distance depends on the camera." },
|
||||||
{ "mergeWindow", "Merge window (s)", 0.1, 1.5, 0.05, "%.2f",
|
{ "mergeWindow", "Merge window (s)", 0.1, 1.5, 0.05, "%.2f",
|
||||||
"How long a line keeps absorbing identical hits, counted from its first hit. Short: more, smaller lines. Long: fewer lines that update longer. Only used with Merge identical hits." },
|
"How long a line keeps absorbing identical hits, counted from its first hit. Short: more, smaller lines. Long: fewer lines that update longer. Only used with Merge identical hits." },
|
||||||
{ "jitter", "Jitter (px)", 0, 40, 1, nil, "Random horizontal offset per line. 0 like the engine; lines stack instead." },
|
{ "jitter", "Jitter (px)", 0, 40, 1, nil, "Random horizontal offset per line. 0 like the engine; lines stack instead." },
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 403 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 371 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 301 KiB |
@@ -24,7 +24,6 @@ AnySCT_STYLE = {
|
|||||||
fadeOutWord = 1.0, -- Miss / Dodge / Parry / Block ...
|
fadeOutWord = 1.0, -- Miss / Dodge / Parry / Block ...
|
||||||
fadeOutAbsorb = 0.09, -- "Absorb" is a quick flicker
|
fadeOutAbsorb = 0.09, -- "Absorb" is a quick flicker
|
||||||
riseHeight = 120, -- px a normal text rises (engine: 2 world units; screen distance varies)
|
riseHeight = 120, -- px a normal text rises (engine: 2 world units; screen distance varies)
|
||||||
critRiseFactor = 0, -- crits do not rise, they pop in place
|
|
||||||
sizeScale = 0.018333, -- text pixel size = scale x screen diagonal (1024x768 -> 23 px)
|
sizeScale = 0.018333, -- text pixel size = scale x screen diagonal (1024x768 -> 23 px)
|
||||||
critSizeScale = 0.0275, -- crits (1024x768 -> 35 px)
|
critSizeScale = 0.0275, -- crits (1024x768 -> 35 px)
|
||||||
shadow = 0.002, -- shadow offset, fraction of the viewport per axis (down-right)
|
shadow = 0.002, -- shadow offset, fraction of the viewport per axis (down-right)
|
||||||
@@ -230,6 +229,43 @@ S.ANCHOR_W, S.ANCHOR_H, S.ANCHOR_LABEL_SIZE, S.PLATE_LABEL_SIZE = 200, 30, 12, 1
|
|||||||
function S.EstTextWidth(text, size) return string.len(text) * size * 0.62 end
|
function S.EstTextWidth(text, size) return string.len(text) * size * 0.62 end
|
||||||
-- Where anchor-mode damage lines start so they clear the box (and the list label above it).
|
-- Where anchor-mode damage lines start so they clear the box (and the list label above it).
|
||||||
function S.AnchorLineOffset(showLabel) return showLabel and 16 or 2 end
|
function S.AnchorLineOffset(showLabel) return showLabel and 16 or 2 end
|
||||||
|
-- ---- stack geometry -------------------------------------------------------------------------
|
||||||
|
-- A line occupies [bottom - suffixH, bottom + numberH]: the number sits on its anchor point, the
|
||||||
|
-- suffix (spell / name) hangs below it. Crits are reserved at the peak of their size pop. A new line
|
||||||
|
-- is inserted at the bottom; every older line of the same mob moves up by the new line's height plus
|
||||||
|
-- the suffix height of the line directly above it, which is what makes the new line fit under it.
|
||||||
|
function S.CritPeak(kf)
|
||||||
|
local m = 1
|
||||||
|
for i = 1, table.getn(kf) do if kf[i][2] > m then m = kf[i][2] end end
|
||||||
|
return m
|
||||||
|
end
|
||||||
|
-- Distance of a line's anchor point from its start: the same rise rate for every line of a tower, so
|
||||||
|
-- older lines (larger t) only ever move away from newer ones.
|
||||||
|
function S.LineOffset(t, dur, rise, push) return t / dur * rise + push end
|
||||||
|
function S.NumberHeight(base, isCrit, peak) return isCrit and base * peak or base end
|
||||||
|
function S.SuffixHeight(base, hasSuffix)
|
||||||
|
if not hasSuffix then return 0 end
|
||||||
|
local sz = math.floor(base * 0.3)
|
||||||
|
if sz < 10 then sz = 10 end
|
||||||
|
return sz + 2
|
||||||
|
end
|
||||||
|
function S.StackAdvance(base, isCrit, peak, prevSuffixH)
|
||||||
|
return S.NumberHeight(base, isCrit, peak) + (prevSuffixH or 0)
|
||||||
|
end
|
||||||
|
-- A crit of a tiny proc must not pop at full crit size: scale by the amount against the source's
|
||||||
|
-- running average hit (0.5 .. 1).
|
||||||
|
function S.CritFactor(amount, ref)
|
||||||
|
if not ref or ref <= 0 then return 1 end
|
||||||
|
local f = (amount or 0) / ref
|
||||||
|
if f > 1 then return 1 end
|
||||||
|
if f < 0.5 then return 0.5 end
|
||||||
|
return f
|
||||||
|
end
|
||||||
|
function S.UpdateRef(ref, amount)
|
||||||
|
if not ref then return amount end
|
||||||
|
return ref + (amount - ref) * 0.1
|
||||||
|
end
|
||||||
|
|
||||||
-- ---- merging identical attacks ---------------------------------------------------------------
|
-- ---- merging identical attacks ---------------------------------------------------------------
|
||||||
-- Is the result a word (Miss / Dodge / ...)? Same rule as S.Format.
|
-- Is the result a word (Miss / Dodge / ...)? Same rule as S.Format.
|
||||||
function S.IsWordResult(res, opt)
|
function S.IsWordResult(res, opt)
|
||||||
@@ -370,6 +406,8 @@ if CreateFrame then
|
|||||||
local POOL_MAX = 100 -- slot tables only; FontStrings are created on first use (ensureFs)
|
local POOL_MAX = 100 -- slot tables only; FontStrings are created on first use (ensureFs)
|
||||||
local critAnimated = S.CurveAnimated(STYLE.critKeyframes)
|
local critAnimated = S.CurveAnimated(STYLE.critKeyframes)
|
||||||
local critActive = S.CurveActive(STYLE.critKeyframes)
|
local critActive = S.CurveActive(STYLE.critKeyframes)
|
||||||
|
local avgHit = {} -- per source: running average hit, for the crit pop scale
|
||||||
|
local critPeak = S.CritPeak(STYLE.critKeyframes)
|
||||||
local GAP = 3 -- px between the plate top and the text
|
local GAP = 3 -- px between the plate top and the text
|
||||||
|
|
||||||
local anchor, float, listLabel
|
local anchor, float, listLabel
|
||||||
@@ -548,13 +586,14 @@ if CreateFrame then
|
|||||||
if t < STYLE.fadeIn then a = t / STYLE.fadeIn end
|
if t < STYLE.fadeIn then a = t / STYLE.fadeIn end
|
||||||
if t > s.fadeOut then a = a * (s.dur - t) / (s.dur - s.fadeOut) end
|
if t > s.fadeOut then a = a * (s.dur - t) / (s.dur - s.fadeOut) end
|
||||||
local rise = s.rise
|
local rise = s.rise
|
||||||
|
-- crits rise with the tower like every other line: a line that stood still would
|
||||||
|
-- let the newer, rising lines below it run into it
|
||||||
if s.crit then
|
if s.crit then
|
||||||
rise = rise * STYLE.critRiseFactor
|
|
||||||
if critAnimated then
|
if critAnimated then
|
||||||
s.fs:SetTextHeight(s.base * S.KeyScale(STYLE.critKeyframes, t / s.dur))
|
s.fs:SetTextHeight(s.base * S.KeyScale(STYLE.critKeyframes, t / s.dur))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
local off = (t / s.dur * rise + s.push) * s.dir
|
local off = S.LineOffset(t, s.dur, rise, s.push) * s.dir
|
||||||
s.fs:ClearAllPoints()
|
s.fs:ClearAllPoints()
|
||||||
if s.plate then
|
if s.plate then
|
||||||
needScan = true
|
needScan = true
|
||||||
@@ -632,9 +671,26 @@ if CreateFrame then
|
|||||||
local base = S.TextSize(scale, factor, sw, sh)
|
local base = S.TextSize(scale, factor, sw, sh)
|
||||||
s.base = base * mul
|
s.base = base * mul
|
||||||
|
|
||||||
-- older lines of the same mob move one text height away
|
-- tiny crits (procs) pop smaller: scale by the amount against the source's running average hit
|
||||||
|
local refKey = res.source or "?"
|
||||||
|
if not isWord and res.kind ~= "heal" then
|
||||||
|
if s.crit then s.base = s.base * S.CritFactor(res.amount, avgHit[refKey]) end
|
||||||
|
avgHit[refKey] = S.UpdateRef(avgHit[refKey], res.amount or 0)
|
||||||
|
end
|
||||||
|
s.sfxH = S.SuffixHeight(s.base, suffix ~= nil)
|
||||||
|
|
||||||
|
-- older lines of the same mob make room for this line's real height (crit peak included) plus
|
||||||
|
-- the suffix hanging below the line right above it
|
||||||
|
local prevSfx, prevT = 0, nil
|
||||||
for j = 1, POOL_MAX do
|
for j = 1, POOL_MAX do
|
||||||
if slots[j].active and slots[j].key == key then slots[j].push = slots[j].push + s.base end
|
local m = slots[j]
|
||||||
|
if m.active and m.key == key and j ~= i and (not prevT or m.t < prevT) then
|
||||||
|
prevT, prevSfx = m.t, m.sfxH or 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local adv = S.StackAdvance(s.base, s.crit, critPeak, prevSfx)
|
||||||
|
for j = 1, POOL_MAX do
|
||||||
|
if slots[j].active and slots[j].key == key and j ~= i then slots[j].push = slots[j].push + adv end
|
||||||
end
|
end
|
||||||
|
|
||||||
s.active = true
|
s.active = true
|
||||||
|
|||||||
Reference in New Issue
Block a user