forked from Dusk/ShaguTweaks-ClassicAPI
156 lines
10 KiB
Lua
156 lines
10 KiB
Lua
local root=(arg[1] or '.')..'/'
|
|
local function read(path)local f=assert(io.open(root..path));local s=f:read('*a');f:close();return s end
|
|
local function Check(native)
|
|
local env=setmetatable({},{__index=getfenv(0)});env._G=env
|
|
local frames,modules,timers,queue={},{},{},{}
|
|
local now,cast,channel,selfTarget,queries=10,nil,nil,false,0
|
|
local keys,remote=false,nil
|
|
local methods={}
|
|
local function object(kind,name,parent)
|
|
local f=setmetatable({kind=kind,name=name,parent=parent,scripts={},events={},shown=true,width=140,alpha=1},
|
|
{__index=function(_,key)return methods[key] or (string.find(key,'^[A-Z]') and function()end or nil)end})
|
|
table.insert(frames,f);if name then env[name]=f end;return f
|
|
end
|
|
function methods:SetScript(k,v)self.scripts[k]=v end
|
|
function methods:GetScript(k)return self.scripts[k]end
|
|
function methods:RegisterEvent(k)self.events[k]=true end
|
|
function methods:Hide()self.shown=false end
|
|
function methods:Show()self.shown=true end
|
|
function methods:IsShown()return self.shown end
|
|
function methods:SetPoint(...)self.point=arg end
|
|
function methods:ClearAllPoints()self.point=nil end
|
|
function methods:GetFont()return 'font',12,'' end
|
|
function methods:GetAlpha()return self.alpha end
|
|
function methods:SetAlpha(a)self.alpha=a end
|
|
function methods:SetWidth(w)self.width=w end
|
|
function methods:GetWidth()return self.width end
|
|
function methods:GetHeight()return 10 end
|
|
function methods:GetEffectiveScale()return 1 end
|
|
function methods:SetTexture(t)self.path=t end
|
|
function methods:SetText(t)self.text=t end
|
|
function methods:SetVertexColor(...)self.tint=arg end
|
|
function methods:SetBackdropBorderColor(...)self.rim=arg end
|
|
function methods:SetMinMaxValues(a,b)self.low,self.high=a,b;self.timer=nil end
|
|
function methods:SetValue(v)self.value=v;self.writes=(self.writes or 0)+1 end
|
|
function methods:SetTimerDuration(d,_,direction)self.timer,self.direction=d,direction end
|
|
function methods:GetStatusBarTexture()if not self.fill then self.fill=object('Texture')end;return self.fill end
|
|
function methods:CreateTexture()return object('Texture')end
|
|
function methods:CreateFontString()return object('FontString')end
|
|
env.CreateFrame=object
|
|
env.UIParent=object('Frame');env.TargetFrame=object('Frame');env.TargetofTargetFrame=object('Frame')
|
|
env.TargetFrameBuff1=object('Texture');env.TargetFrameBuff1:Hide()
|
|
env.TargetofTargetFrame:Hide()
|
|
env.CastingBarFrame=object('StatusBar');env.CastingBarText=object('FontString')
|
|
env.GetTime=function()return now end
|
|
env.UnitExists=function()return true end
|
|
env.UnitIsUnit=function(a,b)return a==b or selfTarget and ((a=='target' and b=='player') or (b=='target' and a=='player'))end
|
|
env.Enum={StatusBarInterpolation={Immediate=0},StatusBarTimerDirection={ElapsedTime=0,RemainingTime=1}}
|
|
env.C_EventUtils={IsEventValid=function()return true end}
|
|
env.C_Timer={NewTimer=function(delay,callback)
|
|
local t={at=now+delay,callback=callback};function t:Cancel()self.cancelled=true end
|
|
table.insert(timers,t);return t
|
|
end}
|
|
env.C_DurationUtil={CreateDuration=function()
|
|
local d={}
|
|
function d:SetTimeSpan(a,b)self.start,self.finish=a,b end
|
|
function d:GetStartTime()return self.start end
|
|
function d:GetEndTime()return self.finish end
|
|
return d
|
|
end,CreateDurationTextBinding=function()
|
|
local b={};function b:SetFontString(v)self.text=v end
|
|
function b:SetFormatter(v)self.formatter=v end
|
|
function b:SetExpiredText(v)self.expired=v end
|
|
function b:SetDuration(v)self.duration=v end
|
|
function b:Enable()self.enabled=true end
|
|
function b:Disable()self.enabled=false end
|
|
return b
|
|
end}
|
|
env.C_StringUtil={CreateNumericRuleFormatter=function()return {AddBreakpoint=function(self,v)self.rule=v end}end}
|
|
local suppliedDuration
|
|
env.UnitCastingDuration=function()return suppliedDuration end
|
|
env.UnitChannelDuration=env.UnitCastingDuration
|
|
env.ShaguTweaks={T=setmetatable({},{__index=function(_,k)return k end}),API={durationtimers=native,casts=true,eventutils=true,timer=true},
|
|
libcast={db={}},GetGlobalEnv=function()return env end}
|
|
env.ShaguTweaks.UnitCastingInfo=function()
|
|
if remote then return 'Remote','','','remote',remote.start*1000,remote.finish*1000 end
|
|
end
|
|
function env.ShaguTweaks:register(m)modules[m.title]=m;return m end
|
|
env.ShaguTweaks.HookScript=function(frame,name,callback)
|
|
local original=frame.scripts[name];frame.scripts[name]=function()if original then original()end;callback()end
|
|
end
|
|
env.ShaguTweaks.QueueFunction=function(callback)table.insert(queue,callback)end
|
|
local API=env.ShaguTweaks.API
|
|
API.Defer=env.ShaguTweaks.QueueFunction
|
|
API.RegisterUnitEvent=function(f,e,a,b)f.events[e]={a,b}end
|
|
API.AreMoveModifiersDown=function()return keys end
|
|
API.UnitGUID=function()return 'guid' end
|
|
API.GetCastInfo=function()queries=queries+1;if cast then return cast.name or 'Cast','','','icon',cast.start*1000,cast.finish*1000 end end
|
|
API.GetChannelInfo=function()if channel then return 'Channel','','','icon',channel.start*1000,channel.finish*1000 end end
|
|
local src=read('api.lua');local a=assert(string.find(src,'API.GetCastDuration = function',1,true));local b=assert(string.find(src,'API.IsSpellInRange =',a,true))
|
|
local helper=assert(loadstring('local API=ShaguTweaks.API;local _G=ShaguTweaks.GetGlobalEnv();'..string.sub(src,a,b-1)));setfenv(helper,env);helper()
|
|
local function load(path)local fn=assert(loadfile(root..path));setfenv(fn,env);fn()end
|
|
load('mods/target-castbar.lua');modules['Enemy Castbars']:enable()
|
|
load('mods/improved-castbar.lua');modules['Improved Castbar']:enable()
|
|
local target,player=env.ShaguTargetCastbar,env.STImprovedCastbar
|
|
local function emit(name,unit)
|
|
env.event,env.arg1=name,unit
|
|
for _,frame in ipairs(frames)do if frame.events[name] and frame.scripts.OnEvent then env.this=frame;frame.scripts.OnEvent()end end
|
|
env.this=nil
|
|
end
|
|
local function runQueue()local work=queue;queue={};for _,fn in ipairs(work)do fn()end end
|
|
cast={start=9,finish=15}
|
|
suppliedDuration=env.C_DurationUtil.CreateDuration();suppliedDuration:SetTimeSpan(9,15)
|
|
emit('UNIT_SPELLCAST_START','target');emit('UNIT_SPELLCAST_START','player')
|
|
assert(target.shown and player.shown)
|
|
if native then
|
|
assert(target.timer==suppliedDuration and target.direction==0 and not target.scripts.OnUpdate)
|
|
assert(target.spark.point[2]==target:GetStatusBarTexture())
|
|
assert(player.timerBinding.enabled and player.timerBinding.duration==suppliedDuration and not player.scripts.OnUpdate)
|
|
assert(player.timerBinding.formatter.rule.format=='%.1fs')
|
|
assert(env.CastingBarFrame.timer==nil,'player native fill/fade must remain untouched')
|
|
local old=target.expiry
|
|
-- Pushback replaces the snapshot and cancels the previous expiry.
|
|
cast.finish=17;emit('UNIT_SPELLCAST_DELAYED','target');emit('UNIT_SPELLCAST_DELAYED','player')
|
|
assert(old.cancelled and target.timer.finish==17 and player.timerBinding.duration.finish==17)
|
|
assert(suppliedDuration.finish==15,'a mismatched engine snapshot must not be mutated')
|
|
local fallback=target.fallbackDuration
|
|
cast=nil;suppliedDuration=nil;channel={start=10,finish=18};emit('UNIT_SPELLCAST_CHANNEL_START','target');emit('UNIT_SPELLCAST_CHANNEL_START','player')
|
|
assert(target.direction==1 and target.fallbackDuration==fallback and player.timerBinding.enabled)
|
|
channel.finish=16;emit('UNIT_SPELLCAST_CHANNEL_UPDATE','target');assert(target.timer.finish==16)
|
|
-- Aura layout work coalesces; animation does not query casts or write values.
|
|
emit('UNIT_AURA','target');emit('UNIT_AURA','target');assert(table.getn(queue)==1);runQueue()
|
|
env.TargetofTargetFrame:Show();env.TargetofTargetFrame.scripts.OnShow();runQueue();assert(target.positionY==-24)
|
|
local activeTimer=target.timer
|
|
env.ShaguTweaks.UITint={r=1,g=.78,b=.4,a=1};env.ShaguTweaks.UIBorder={r=.8,g=.62,b=.32,a=1}
|
|
keys=true;emit('MODIFIER_STATE_CHANGED');assert(env.ShaguTweaksTargetCastBarMover.shown and target.timer==activeTimer)
|
|
assert(env.ShaguTweaksTargetCastBarMover.border.tint[2]==.78 and env.ShaguTweaksTargetCastBarMover.icon.rim[1]==.8)
|
|
keys=false;emit('MODIFIER_STATE_CHANGED');assert(not env.ShaguTweaksTargetCastBarMover.shown)
|
|
local before=queries;now=11;assert(queries==before and not target.writes)
|
|
-- Cancel/stop clears target immediately, retaining player text for native fade.
|
|
channel=nil;emit('UNIT_SPELLCAST_INTERRUPTED','target');emit('UNIT_SPELLCAST_STOP','player')
|
|
assert(not target.shown and not target.timer and not player.timerBinding.enabled and player.shown)
|
|
env.CastingBarFrame.scripts.OnHide();assert(not player.shown)
|
|
-- Missing STOP still expires; replacement casts cannot be hidden by old timers.
|
|
cast={start=11,finish=15};emit('UNIT_SPELLCAST_START','target');local expiry=target.expiry
|
|
cast.finish=19;emit('UNIT_SPELLCAST_DELAYED','target');assert(expiry.cancelled)
|
|
now=19;target.expiry.callback();assert(not target.shown and not target.timer)
|
|
-- Player-only events refresh a self-target; unrelated player casts do not.
|
|
now=20;cast={start=20,finish=25};selfTarget=true;emit('UNIT_SPELLCAST_START','player');assert(target.shown)
|
|
cast=nil;emit('UNIT_SPELLCAST_STOP','player');assert(not target.shown)
|
|
selfTarget=false;cast={start=20,finish=25};emit('UNIT_SPELLCAST_START','player');assert(not target.shown)
|
|
cast=nil;emit('PLAYER_TARGET_CHANGED');assert(not target.shown)
|
|
-- Complete remote timing still uses the optional GUID cache complement.
|
|
env.ShaguTweaks.superwow_active=true;env.ShaguTweaks.libcast.db.guid={cast='Remote'}
|
|
remote={start=20,finish=26};env.ShaguTweaks.libcast.OnRemoteChanged('guid')
|
|
assert(target.shown and target.timer.finish==26 and target.text.text=='Remote')
|
|
remote=nil;env.ShaguTweaks.libcast.db.guid=nil;env.ShaguTweaks.libcast.OnRemoteChanged('guid')
|
|
assert(not target.shown)
|
|
else
|
|
assert(target.scripts.OnUpdate and player.scripts.OnUpdate and not player.timerBinding)
|
|
env.this=target;target.scripts.OnUpdate();assert(target.value==1)
|
|
env.this=player;env.arg1=.1;player.scripts.OnUpdate();assert(player.timerText.text=='5.0s')
|
|
end
|
|
end
|
|
Check(true);Check(false)
|
|
print('Castbars: native snapshot/fallback durations, fill/spark/text ownership, delay/channel replacement, cancellation/expiry, player fade, self-target routing and older API animation passed')
|