AnySCT 0.3.0
This commit is contained in:
@@ -216,6 +216,152 @@ function S.Format(res, opt, mode)
|
||||
return text, colourKey, isWord, mul, suffix
|
||||
end
|
||||
|
||||
-- Demo threat preview: the buffer climbs from ~300 to 1.3x the required lead over the burst (f 0..1).
|
||||
function S.DemoThreat(f, need)
|
||||
need = need or 1500
|
||||
local start = (need > 300) and 300 or need * 0.2
|
||||
if f < 0 then f = 0 elseif f > 1 then f = 1 end
|
||||
local b = start + (need * 1.3 - start) * f
|
||||
return (b >= need) and "GO" or "WAIT", b, need
|
||||
end
|
||||
-- Demo timeline: see S.BuildDemo. Event tables are reused on every run (no allocation while it plays).
|
||||
-- Fixed-anchor box and the GO / WAIT label sitting inside it (rough glyph width: 0.62 x size per char).
|
||||
S.ANCHOR_W, S.ANCHOR_H, S.ANCHOR_LABEL_SIZE, S.PLATE_LABEL_SIZE = 200, 30, 12, 14
|
||||
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).
|
||||
function S.AnchorLineOffset(showLabel) return showLabel and 16 or 2 end
|
||||
-- ---- merging identical attacks ---------------------------------------------------------------
|
||||
-- Is the result a word (Miss / Dodge / ...)? Same rule as S.Format.
|
||||
function S.IsWordResult(res, opt)
|
||||
return (S.WORDS[res.kind] ~= nil) and (((res.amount or 0) <= 0) or (opt.colourize and true or false))
|
||||
end
|
||||
|
||||
-- Result class that must match to merge: normal hits (glancing / crushing too) and crits stay apart.
|
||||
function S.MergeClass(res)
|
||||
local k = res.kind
|
||||
if k == "crit" or res.crit then return "crit" end
|
||||
if k == "hit" or k == "glancing" or k == "crushing" then return "hit" end
|
||||
return k
|
||||
end
|
||||
|
||||
-- Does line slot s (fields mKey, mWord, mCls, mSrc, mSpell, mHealer, mPet, t) absorb this result?
|
||||
-- key = the place/victim key of the line (guid, name or "anchor"); words ignore the spell.
|
||||
function S.MergeMatches(s, res, key, isWord, window)
|
||||
if not s.active or s.mKey ~= key or s.mWord ~= isWord or s.t > window then return false end
|
||||
if s.mCls ~= S.MergeClass(res) or s.mSrc ~= res.source or s.mPet ~= res.srcPet then return false end
|
||||
if isWord then return true end
|
||||
return s.mSpell == (res.spellId or res.spell) and s.mHealer == res.healer
|
||||
end
|
||||
|
||||
function S.MergeLabel(text, count, showCount)
|
||||
if showCount and count > 1 then return text .. " x" .. count end
|
||||
return text
|
||||
end
|
||||
|
||||
S.DEMO_BURST_LEN = 2.5
|
||||
|
||||
-- Demo source: the first listed targetSCT (name, class, own colour); without one a generic shaman tank.
|
||||
S.DEMO_FALLBACK_NAME = "Shemp" -- leak-gate: allow
|
||||
S.DEMO_VICTIM = "Training Dummy"
|
||||
function S.DemoSource(st)
|
||||
local e = st and st.order and st.byName and st.byName[st.order[1]]
|
||||
if e then
|
||||
return e.name, e.class, e.rgb, table.getn(st.order) > 1
|
||||
end
|
||||
return S.DEMO_FALLBACK_NAME, "SHAMAN", { 0, 0.44, 0.87 }, false
|
||||
end
|
||||
|
||||
-- Burst skill sets per class. Entry: { spell (nil = white hit, "@kind" = miss word), weight, typical
|
||||
-- amount, upper typical amount, typical crit amount, crit % , windfury-style extra hits }.
|
||||
-- SHAMAN: shares and amounts from recorded tanking fights in dungeons and raids, last 30 days
|
||||
-- (Stormstrike and Earth Shock are boosted so the preview shows them; crit rates are raised to
|
||||
-- make a few crits visible). Every other class: plausible level-60 tank numbers, ESTIMATES.
|
||||
S.DEMO_SETS = {
|
||||
SHAMAN = {
|
||||
{ "Fire Strike", 51, 2, 2, 3, 10 }, { "Lightning Strike", 15, 3, 3, 5, 12 },
|
||||
{ "Tidal Wave", 10, 29, 31, 43, 10 }, { nil, 9, 97, 118, 216, 22, 2 },
|
||||
{ "Engulfing Shadows", 6, 100, 100, 100, 0 }, { "Ancient Accord", 3, 100, 110, 150, 6 },
|
||||
{ "Thundercall", 2, 39, 56, 56, 0 }, { "Earth Shock", 8, 666, 760, 992, 15 },
|
||||
{ "Stormstrike", 10, 117, 140, 241, 30 }, { "Flame Shock", 2, 85, 100, 458, 5 },
|
||||
{ "@miss", 1 }, { "@dodge", 1 }, { "@parry", 1 }, { "@block", 1 }, { "@resist", 1 },
|
||||
},
|
||||
WARRIOR = {
|
||||
{ nil, 28, 150, 190, 320, 25 }, { "Heroic Strike", 20, 280, 340, 560, 25 },
|
||||
{ "Revenge", 14, 350, 420, 700, 25 }, { "Shield Slam", 14, 480, 560, 900, 25 },
|
||||
{ "Sunder Armor", 10, 60, 60, 60, 0 }, { "@miss", 1 }, { "@dodge", 1 }, { "@parry", 1 }, { "@block", 1 },
|
||||
},
|
||||
DRUID = {
|
||||
{ nil, 24, 120, 150, 260, 25 }, { "Maul", 22, 260, 320, 520, 25 }, { "Swipe", 30, 90, 110, 190, 25 },
|
||||
{ "Lacerate", 12, 70, 70, 70, 0 }, { "@miss", 1 }, { "@dodge", 1 }, { "@parry", 1 }, { "@block", 1 },
|
||||
},
|
||||
PALADIN = {
|
||||
{ nil, 28, 140, 175, 300, 25 }, { "Holy Shield", 18, 100, 120, 200, 0 },
|
||||
{ "Consecration", 16, 70, 70, 70, 0 }, { "Seal of Righteousness", 22, 90, 110, 190, 25 },
|
||||
{ "Hammer of the Righteous", 8, 320, 380, 640, 25 }, { "@miss", 1 }, { "@dodge", 1 }, { "@parry", 1 }, { "@block", 1 },
|
||||
},
|
||||
}
|
||||
function S.DemoSet(class)
|
||||
return S.DEMO_SETS[class or ""] or S.DEMO_SETS.WARRIOR
|
||||
end
|
||||
|
||||
-- Timeline: a 2.5 s burst starting at once, of ~9 slots/s picked from the class set
|
||||
-- by weight (deterministic credit round robin, so rare skills still show up). Each entry: t, f (0..1
|
||||
-- through the burst, nil before it), sn (spell name or nil), res (event table, reused every run).
|
||||
function S.BuildDemo(class)
|
||||
local set = S.DemoSet(class)
|
||||
local list, n = {}, 0
|
||||
local t0
|
||||
local function add(t, kind, amount, sn)
|
||||
n = n + 1
|
||||
list[n] = { t = t, sn = sn, res = { kind = kind, amount = amount } }
|
||||
if t0 then list[n].f = (t - t0) / S.DEMO_BURST_LEN end
|
||||
end
|
||||
t0 = 0
|
||||
local total = 0
|
||||
local credit, uses, critAcc = {}, {}, {}
|
||||
for i = 1, table.getn(set) do
|
||||
total = total + set[i][2]
|
||||
credit[i], uses[i], critAcc[i] = 0, 0, 60
|
||||
end
|
||||
local count = 22
|
||||
-- every word of the set is guaranteed to appear once, spread over the burst
|
||||
local forced, words = {}, {}
|
||||
for i = 1, table.getn(set) do
|
||||
if set[i][1] and string.sub(set[i][1], 1, 1) == "@" then table.insert(words, i) end
|
||||
end
|
||||
local nw = table.getn(words)
|
||||
for j = 1, nw do forced[3 + math.floor((j - 1) * (count - 4) / nw)] = words[j] end
|
||||
for slot = 1, count do
|
||||
local t = t0 + (slot - 1) * S.DEMO_BURST_LEN / count
|
||||
local best = 1
|
||||
for i = 1, table.getn(set) do
|
||||
credit[i] = credit[i] + set[i][2]
|
||||
if credit[i] > credit[best] then best = i end
|
||||
end
|
||||
credit[best] = credit[best] - total
|
||||
if forced[slot] then best = forced[slot] end
|
||||
local d = set[best]
|
||||
uses[best] = uses[best] + 1
|
||||
local word = d[1] and string.sub(d[1], 1, 1) == "@" and string.sub(d[1], 2)
|
||||
if word then
|
||||
add(t, word, 0)
|
||||
else
|
||||
local crit = false
|
||||
local rate = d[6] or 0
|
||||
if rate > 0 then
|
||||
critAcc[best] = critAcc[best] + rate
|
||||
if critAcc[best] >= 100 then critAcc[best] = critAcc[best] - 100; crit = true end
|
||||
end
|
||||
local amount = crit and d[5] or ((math.mod(uses[best], 2) == 1) and d[3] or d[4])
|
||||
add(t, crit and "crit" or "hit", amount, d[1])
|
||||
if not d[1] and d[7] and uses[best] == 2 then -- an extra attack in the same frame
|
||||
for _ = 1, d[7] do add(t, "hit", d[3], nil) end
|
||||
end
|
||||
end
|
||||
end
|
||||
return list, n, list[n].t + 1.5
|
||||
end
|
||||
|
||||
if CreateFrame then
|
||||
local W = AnySCT_W
|
||||
local C = AnySCT_Core
|
||||
@@ -258,6 +404,19 @@ if CreateFrame then
|
||||
end
|
||||
end
|
||||
|
||||
local dragging = false
|
||||
|
||||
-- UIParent's rect in the same coordinate system as the anchor's (see C.AnchorPosFromCenter).
|
||||
function S.ScreenRect()
|
||||
local l, b, r, t = UIParent:GetLeft(), UIParent:GetBottom(), UIParent:GetRight(), UIParent:GetTop()
|
||||
if not (l and b and r and t) then
|
||||
l, b, r, t = 0, 0, UIParent:GetWidth(), UIParent:GetHeight()
|
||||
end
|
||||
return l, b, r, t
|
||||
end
|
||||
|
||||
function S.IsDragging() return dragging end
|
||||
|
||||
local function placeAnchor()
|
||||
local pos = opt("pos") or AnySCT_DEFAULTS.pos
|
||||
anchor:ClearAllPoints()
|
||||
@@ -276,8 +435,8 @@ if CreateFrame then
|
||||
float:SetClampedToScreen(true)
|
||||
|
||||
local a = CreateFrame("Frame", "AnySCTAnchor", UIParent)
|
||||
a:SetWidth(160)
|
||||
a:SetHeight(30)
|
||||
a:SetWidth(S.ANCHOR_W)
|
||||
a:SetHeight(S.ANCHOR_H)
|
||||
a:SetFrameStrata("HIGH")
|
||||
a:SetFrameLevel(10)
|
||||
a:SetMovable(true)
|
||||
@@ -286,12 +445,18 @@ if CreateFrame then
|
||||
a:RegisterForDrag("LeftButton")
|
||||
a:SetBackdrop(W.SOLID_BACKDROP)
|
||||
a:SetScript("OnDragStart", function()
|
||||
if moveMode then this:StartMoving() end
|
||||
if moveMode then
|
||||
dragging = true
|
||||
this:StartMoving()
|
||||
end
|
||||
end)
|
||||
a:SetScript("OnDragStop", function()
|
||||
this:StopMovingOrSizing()
|
||||
dragging = false
|
||||
local cx, cy = this:GetCenter()
|
||||
C.SetOpt("pos", { point = "CENTER", x = cx - UIParent:GetWidth() / 2, y = cy - UIParent:GetHeight() / 2 })
|
||||
if not cx then return end
|
||||
local l, b, r, t = S.ScreenRect()
|
||||
C.SetOpt("pos", C.AnchorPosFromCenter(cx, cy, (l + r) / 2, (b + t) / 2))
|
||||
end)
|
||||
anchor = a
|
||||
|
||||
@@ -403,7 +568,11 @@ if CreateFrame then
|
||||
if y > s.lastH - margin then y = s.lastH - margin end
|
||||
s.fs:SetPoint("BOTTOM", UIParent, "BOTTOMLEFT", x, y)
|
||||
else
|
||||
s.fs:SetPoint("BOTTOM", anchor, "CENTER", s.dx, off)
|
||||
if s.dir < 0 then
|
||||
s.fs:SetPoint("TOP", anchor, "BOTTOM", s.dx, off - 2)
|
||||
else
|
||||
s.fs:SetPoint("BOTTOM", anchor, "TOP", s.dx, off + S.AnchorLineOffset(opt("showLabel")))
|
||||
end
|
||||
end
|
||||
s.fs:SetAlpha(a)
|
||||
s.fs:SetShadowColor(0, 0, 0, a)
|
||||
@@ -420,8 +589,36 @@ if CreateFrame then
|
||||
local o = C.Opts()
|
||||
local key = res.mobGuid or res.mobName or "anchor"
|
||||
if mode == 3 then key = "anchor" end
|
||||
local isWord0 = S.IsWordResult(res, o)
|
||||
if o.mergeHits ~= false then
|
||||
local window = o.mergeWindow or 0.4
|
||||
for j = 1, POOL_MAX do
|
||||
local m = slots[j]
|
||||
if m.active and S.MergeMatches(m, res, key, isWord0, window) then
|
||||
-- fold into the live line: same position and fade, only the text changes
|
||||
if not isWord0 then
|
||||
m.mSum = m.mSum + (res.amount or 0)
|
||||
m.mCount = m.mCount + 1
|
||||
local a0 = res.amount
|
||||
res.amount = m.mSum
|
||||
local text = S.Format(res, o, mode)
|
||||
res.amount = a0
|
||||
text = S.MergeLabel(text, m.mCount, o.mergeCount)
|
||||
if text ~= m.mText then
|
||||
m.mText = text
|
||||
m.fs:SetText(text)
|
||||
end
|
||||
end
|
||||
C.Ledger(res, "merged")
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
local i = acquire(key)
|
||||
local s = slots[i]
|
||||
s.mKey, s.mWord, s.mCls, s.mSrc, s.mPet = key, isWord0, S.MergeClass(res), res.source, res.srcPet
|
||||
s.mSpell, s.mHealer = res.spellId or res.spell, res.healer
|
||||
s.mSum, s.mCount = res.amount or 0, 1
|
||||
C.Ledger(res, s.active and "shown+recycled" or "shown")
|
||||
s.key = key
|
||||
ensureFs(i)
|
||||
@@ -475,6 +672,7 @@ if CreateFrame then
|
||||
local cr, cg, cb = S.PickColour(res, o, ckey)
|
||||
fs:SetTextColor(cr, cg, cb)
|
||||
fs:SetText(text)
|
||||
s.mText = text
|
||||
fs:SetAlpha(0)
|
||||
fs:SetShadowColor(0, 0, 0, 0)
|
||||
fs:Show()
|
||||
@@ -503,7 +701,7 @@ if CreateFrame then
|
||||
if o.placement ~= "anchor" and (res.mobGuid or res.mobName) then
|
||||
plate = P.Find(res.mobGuid, res.mobName, res.mobUnit)
|
||||
end
|
||||
local mode, px, py, pw, ph = P.Select(plate, o)
|
||||
local mode, px, py, pw, ph, also = P.Places(plate, o)
|
||||
if C.debug then
|
||||
C.Dbg("place " .. tostring(res.mobName) .. ": " .. (plate and "plate found" or "no plate")
|
||||
.. ", mode " .. tostring(mode) .. (mode == 0 and " (hidden by option)" or ""))
|
||||
@@ -513,11 +711,12 @@ if CreateFrame then
|
||||
return
|
||||
end
|
||||
spawn(res, mode, plate, px, py, pw, ph)
|
||||
if also then spawn(res, 3) end -- "Nameplate + anchor": a second, separately capped stack
|
||||
end
|
||||
|
||||
function S.OptionChanged(key)
|
||||
if not anchor then return end
|
||||
if key == "all" or key == "pos" then placeAnchor() end
|
||||
if (key == "all" or key == "pos") and not dragging then placeAnchor() end
|
||||
S.UpdateLabel()
|
||||
end
|
||||
|
||||
@@ -526,6 +725,7 @@ if CreateFrame then
|
||||
-- (C.ThreatDecide); this only draws. The follow OnUpdate is attached only while the label is shown.
|
||||
local TL = { fs = nil, shown = false, plate = nil, status = nil, text = nil, lastText = nil,
|
||||
lastMode = 0, lastName = nil, mobName = nil, guid = nil }
|
||||
local TL2 = { fs = nil, lastText = nil, lastMode = 0, lastName = nil } -- anchor copy ("both")
|
||||
local followFrame
|
||||
local findAcc = 0
|
||||
|
||||
@@ -536,6 +736,7 @@ if CreateFrame then
|
||||
if TL.shown then
|
||||
TL.shown = false
|
||||
if TL.fs then TL.fs:Hide() end
|
||||
if TL2.fs then TL2.fs:Hide() end
|
||||
end
|
||||
if followFrame then followFrame:SetScript("OnUpdate", nil) end
|
||||
return
|
||||
@@ -552,6 +753,31 @@ if CreateFrame then
|
||||
followFrame:SetScript("OnUpdate", followUpdate)
|
||||
end
|
||||
|
||||
-- Draw the label fs (state record L) for a placement mode; text and font change only on change.
|
||||
local function drawLabel(L, fs, mode, px, py, pw, ph, margin, lift)
|
||||
local size = (mode == 3) and S.ANCHOR_LABEL_SIZE or S.PLATE_LABEL_SIZE
|
||||
if size ~= L.size then
|
||||
L.size = size
|
||||
fs:SetFont(S.FontPath(opt("font")), size, "OUTLINE")
|
||||
L.lastText = nil
|
||||
end
|
||||
local name = (mode == 3) and TL.mobName or nil
|
||||
if TL.text ~= L.lastText or mode ~= L.lastMode or name ~= L.lastName then
|
||||
L.lastText, L.lastMode, L.lastName = TL.text, mode, name
|
||||
fs:SetText(name and (name .. ": " .. TL.text) or TL.text)
|
||||
if TL.status == "GO" then fs:SetTextColor(0.2, 1, 0.2) else fs:SetTextColor(1, 0.6, 0.1) end
|
||||
end
|
||||
fs:ClearAllPoints()
|
||||
if mode == 3 then
|
||||
fs:SetPoint("CENTER", anchor, "CENTER", 0, 0)
|
||||
else
|
||||
local x, y = px, py + lift
|
||||
if mode == 2 then x, y = AnySCT_ClampToScreen(x, y, pw, ph, margin) end
|
||||
fs:SetPoint("BOTTOM", UIParent, "BOTTOMLEFT", x, y)
|
||||
end
|
||||
fs:Show()
|
||||
end
|
||||
|
||||
followUpdate = function()
|
||||
if not TL.shown then return end
|
||||
findAcc = findAcc + arg1
|
||||
@@ -561,56 +787,47 @@ if CreateFrame then
|
||||
TL.plate = nil
|
||||
TL.mobName = UnitName("target")
|
||||
TL.guid = C.ResolveGuid("target")
|
||||
if o.placement ~= "anchor" then TL.plate = P.Find(TL.guid, TL.mobName, "target") end
|
||||
if o.placement ~= "anchor" and not TL.forceAnchor then TL.plate = P.Find(TL.guid, TL.mobName, "target") end
|
||||
end
|
||||
local margin = o.edgeMargin or 40
|
||||
local lift = S.TextSize(STYLE.sizeScale, o.sizeFactor or 1, GetScreenWidth(), GetScreenHeight()) + 6
|
||||
local mode, px, py, pw, ph = P.Select(TL.plate, o)
|
||||
if mode == 0 then TL.fs:Hide() return end
|
||||
local name = (mode == 3) and TL.mobName or nil
|
||||
if TL.text ~= TL.lastText or mode ~= TL.lastMode or name ~= TL.lastName then
|
||||
TL.lastText, TL.lastMode, TL.lastName = TL.text, mode, name
|
||||
TL.fs:SetText(name and (name .. ": " .. TL.text) or TL.text)
|
||||
if TL.status == "GO" then TL.fs:SetTextColor(0.2, 1, 0.2) else TL.fs:SetTextColor(1, 0.6, 0.1) end
|
||||
local mode, px, py, pw, ph, also = P.Places(TL.plate, o)
|
||||
if mode == 0 then
|
||||
TL.fs:Hide()
|
||||
if TL2.fs then TL2.fs:Hide() end
|
||||
return
|
||||
end
|
||||
TL.fs:ClearAllPoints()
|
||||
if mode == 3 then
|
||||
TL.fs:SetPoint("BOTTOM", anchor, "TOP", 0, 18)
|
||||
else
|
||||
local x, y = px, py + lift
|
||||
if mode == 2 then x, y = AnySCT_ClampToScreen(x, y, pw, ph, margin) end
|
||||
TL.fs:SetPoint("BOTTOM", UIParent, "BOTTOMLEFT", x, y)
|
||||
drawLabel(TL, TL.fs, mode, px, py, pw, ph, margin, lift)
|
||||
if also then
|
||||
if not TL2.fs then
|
||||
TL2.fs = float:CreateFontString("AnySCTThreatLabel2", "OVERLAY")
|
||||
TL2.fs:SetFont(S.FontPath(opt("font")), S.ANCHOR_LABEL_SIZE, "OUTLINE")
|
||||
end
|
||||
drawLabel(TL2, TL2.fs, 3, nil, nil, nil, nil, margin, lift)
|
||||
elseif TL2.fs then
|
||||
TL2.fs:Hide()
|
||||
end
|
||||
TL.fs:Show()
|
||||
end
|
||||
|
||||
-- ---- demo / move / memory ------------------------------------------------------------------
|
||||
-- Fixed sequence for side-by-side comparison with the player's own real numbers.
|
||||
local DEMO = {
|
||||
{ kind = "hit", amount = 72 }, { kind = "hit", amount = 66 }, { kind = "crit", amount = 141 },
|
||||
{ kind = "miss", amount = 0 }, { kind = "dodge", amount = 0 }, { kind = "parry", amount = 0 },
|
||||
{ kind = "block", amount = 0 },
|
||||
}
|
||||
local demoIdx, demoLeft, demoAcc, demoTicker, demoAtAnchor = 0, 0, 0, nil, false
|
||||
-- Fixed sequence for side-by-side comparison with the player's own real numbers, then the burst.
|
||||
local demoCache = {}
|
||||
local DEMO, DEMO_N, DEMO_END
|
||||
local demoIdx, demoT, demoTicker, demoAtAnchor = 1, 0, nil, false
|
||||
local dSrc, dClass, dRgb, dMulti, dVictim = nil, nil, nil, false, nil
|
||||
|
||||
-- /asct demo plays at the nameplate of the current target (the same placement rules as real
|
||||
-- events); without a target, or with atAnchor, at the fixed anchor.
|
||||
function S.Demo(atAnchor)
|
||||
build()
|
||||
demoLeft = table.getn(DEMO)
|
||||
demoIdx = 0
|
||||
demoAcc = 0
|
||||
demoAtAnchor = atAnchor and true or false
|
||||
if not demoTicker then demoTicker = CreateFrame("Frame", "AnySCTDemoFrame", UIParent) end
|
||||
demoTicker:SetScript("OnUpdate", function()
|
||||
demoAcc = demoAcc + arg1
|
||||
if demoAcc < 0.45 then return end
|
||||
demoAcc = 0
|
||||
if demoLeft <= 0 then this:SetScript("OnUpdate", nil) return end
|
||||
demoLeft = demoLeft - 1
|
||||
local function demoOnUpdate()
|
||||
demoT = demoT + arg1
|
||||
local showName = opt("showSpellName")
|
||||
while demoIdx <= DEMO_N and DEMO[demoIdx].t <= demoT do
|
||||
local e = DEMO[demoIdx]
|
||||
local res = e.res
|
||||
demoIdx = demoIdx + 1
|
||||
local res = DEMO[demoIdx]
|
||||
res.mobGuid, res.mobName, res.mobUnit = nil, nil, nil
|
||||
-- same fields a real event carries (C.Emit), so every display setting applies
|
||||
res.source, res.srcRgb, res.srcMulti, res.class = dSrc, dRgb, dMulti, dClass
|
||||
res.spell = (e.sn and showName) and e.sn or nil
|
||||
res.spellId = e.sn and 1 or nil
|
||||
res.mobGuid, res.mobName, res.mobUnit = nil, dVictim, nil
|
||||
if not demoAtAnchor and UnitExists("target") then
|
||||
res.mobGuid = C.ResolveGuid("target")
|
||||
res.mobName = UnitName("target")
|
||||
@@ -619,7 +836,37 @@ if CreateFrame then
|
||||
else
|
||||
spawn(res, 3)
|
||||
end
|
||||
end)
|
||||
if e.f then
|
||||
-- the GO / WAIT preview rides the burst (real label code path, even with threatGo off)
|
||||
local status, buf, need = S.DemoThreat(e.f, opt("threatGoLead"))
|
||||
S.SetThreat(status, buf, need, C.ThreatSrcName and C.ThreatSrcName(dSrc))
|
||||
end
|
||||
end
|
||||
if demoT >= DEMO_END then
|
||||
TL.forceAnchor = false
|
||||
S.SetThreat(nil)
|
||||
this:SetScript("OnUpdate", nil)
|
||||
end
|
||||
end
|
||||
|
||||
-- /asct demo plays at the nameplate of the current target (the same placement rules as real
|
||||
-- events); without a target, or with atAnchor, at the fixed anchor. A second call restarts it.
|
||||
function S.Demo(atAnchor)
|
||||
build()
|
||||
demoIdx, demoT = 1, 0
|
||||
demoAtAnchor = atAnchor and true or false
|
||||
dSrc, dClass, dRgb, dMulti = S.DemoSource(C.state)
|
||||
dVictim = UnitExists("target") and UnitName("target") or S.DEMO_VICTIM
|
||||
local key = S.DEMO_SETS[dClass or ""] and dClass or "WARRIOR"
|
||||
if not demoCache[key] then
|
||||
local l, n, e = S.BuildDemo(key)
|
||||
demoCache[key] = { l, n, e }
|
||||
end
|
||||
DEMO, DEMO_N, DEMO_END = demoCache[key][1], demoCache[key][2], demoCache[key][3]
|
||||
TL.forceAnchor = demoAtAnchor
|
||||
S.SetThreat(nil)
|
||||
if not demoTicker then demoTicker = CreateFrame("Frame", "AnySCTDemoFrame", UIParent) end
|
||||
demoTicker:SetScript("OnUpdate", demoOnUpdate)
|
||||
end
|
||||
|
||||
function S.FontStringCount()
|
||||
|
||||
Reference in New Issue
Block a user