Files
Techmino/Zframework/init.lua
2024-11-03 01:51:46 +08:00

953 lines
30 KiB
Lua

-- WARNING: This framework has been remade and renamed to Zenitha. Do not use this deprecated framework for your project
NONE={}function NULL() end PAPER=love.graphics.newCanvas(1,1)
EDITING=""
LOADED=false
---@type 'Windows'|'Android'|'Linux'|'iOS'|'macOS'|'Web'
SYSTEM=love.system.getOS()
WEB_COMPAT_MODE=false
if SYSTEM=='OS X' then
SYSTEM='macOS'
elseif SYSTEM=='Web' then
WEB_COMPAT_MODE=not love.thread.newThread('\n'):start()
print('Web compatible mode: ', WEB_COMPAT_MODE)
end
-- Bit module
local success
success,bit=pcall(require,"bit")
if not success then
bit=require"Zframework.bitop".bit
end
-- Pure lua modules (basic)
MATH= require'Zframework.mathExtend'
COLOR= require'Zframework.color'
TABLE= require'Zframework.tableExtend'
STRING= require'Zframework.stringExtend'
PROFILE= require'Zframework.profile'
JSON= require'Zframework.json'
TEST= require'Zframework.test'
do-- Add pcall & MES for JSON lib
local encode,decode=JSON.encode,JSON.decode
JSON.encode=function(val)
local a,b=pcall(encode,val)
if a then
return b
elseif MES then
MES.traceback()
end
end
JSON.decode=function(str)
local a,b=pcall(decode,str)
if a then
return b
elseif MES then
MES.traceback()
end
end
end
-- Pure lua modules (complex)
LOG= require'Zframework.log'
REQUIRE= require'Zframework.require'
TASK= require'Zframework.task'
LANG= require'Zframework.languages'
HASH= require'Zframework.sha2'
do
local bxor=bit.bxor
local char=string.char
local function sxor(s1, s2)
local b3=""
for i=1,#s1 do
b3=b3..char(bxor(s1:byte(i),s2:byte(i)))
end
return b3
end
function HASH.pbkdf2(hashFunc, pw, salt, n)
local u=HASH.hex2bin(HASH.hmac(hashFunc, pw, salt.."\0\0\0\1"))
local t=u
for _=2,n do
u=HASH.hex2bin(HASH.hmac(hashFunc, pw, u))
t=sxor(t, u)
end
return HASH.bin2hex(t):upper()
end
end
-- Love-based modules (basic)
CLIPBOARD= require'Zframework.clipboard'
HTTP= require'Zframework.http'
WS= require'Zframework.websocket'
FILE= require'Zframework.file'
WHEELMOV= require'Zframework.wheelScroll'
SCR= require'Zframework.screen'
SCN= require'Zframework.scene'
-- Love-based modules (complex)
GC= require'Zframework.gcExtend'
FONT= require'Zframework.font'
TEXT= require'Zframework.text'
SYSFX= require'Zframework.sysFX'
WAIT= require'Zframework.wait'
MES= require'Zframework.message'
BG= require'Zframework.background'
WIDGET= require'Zframework.widget'
VIB= require'Zframework.vibrate'
SFX= require'Zframework.sfx'
IMG= require'Zframework.image'
BGM= require'Zframework.bgm'
VOC= require'Zframework.voice'
if SYSTEM=='Web' then
JS=require'Zframework.js'
end
local ms,kb=love.mouse,love.keyboard
local KBisDown=kb.isDown
local gc=love.graphics
local gc_push,gc_pop,gc_clear,gc_discard=gc.push,gc.pop,gc.clear,gc.discard
local gc_replaceTransform,gc_present=gc.replaceTransform,gc.present
local gc_setColor,gc_setLineWidth=gc.setColor,gc.setLineWidth
local gc_draw,gc_line,gc_circle,gc_print=gc.draw,gc.line,gc.circle,gc.print
local BG,WIDGET,SCR,SCN,WAIT=BG,WIDGET,SCR,SCN,WAIT
local xOy=SCR.xOy
local ITP=xOy.inverseTransformPoint
local max,min=math.max,math.min
local debugMode
local mx,my,mouseShow,cursorSpd=640,360,false,0
local jsState={}-- map, joystickID->axisStates: {axisName->axisVal}
local errData={}-- list, each error create {mes={errMes strings},scene=sceneNameStr}
local function drawCursor(_,x,y)
gc_setColor(1,1,1)
gc_setLineWidth(2)
gc_circle(ms.isDown(1) and 'fill' or 'line',x,y,6)
end
local showPowerInfo=true
local showClickFX=true
local discardCanvas=false
local frameMul=100
local sleepInterval=1/60
local onQuit=NULL
local onBeforeQuit=false
local versionText=""
local batteryImg=GC.DO{31,20,
{'fRect',1,0,26,2},
{'fRect',1,18,26,2},
{'fRect',0,1,2,18},
{'fRect',26,1,2,18},
{'fRect',29,3,2,14},
}
local infoCanvas=gc.newCanvas(108,27)
local function updatePowerInfo()
local state,pow=love.system.getPowerInfo()
gc.setCanvas(infoCanvas)
gc_push('transform')
gc.origin()
gc_clear(0,0,0,.25)
if state~='unknown' then
gc_setLineWidth(4)
if state=='nobattery' then
gc_setColor(1,1,1)
gc_setLineWidth(2)
gc_line(74,5,100,22)
elseif pow then
if state=='charging' then gc_setColor(0,1,0)
elseif pow>50 then gc_setColor(1,1,1)
elseif pow>26 then gc_setColor(1,1,0)
elseif pow==26 then gc_setColor(.5,0,1)
else gc_setColor(1,0,0)
end
gc.rectangle('fill',76,6,pow*.22,14)
if pow<100 then
FONT.set(15)
gc.setColor(COLOR.D)
gc_print(pow,77,1)
gc_print(pow,77,3)
gc_print(pow,79,1)
gc_print(pow,79,3)
gc_setColor(COLOR.Z)
gc_print(pow,78,2)
end
end
gc_draw(batteryImg,73,3)
end
FONT.set(25)
gc_print(os.date("%H:%M"),3,-5)
gc_pop()
gc.setCanvas()
end
-------------------------------------------------------------
local lastX,lastY=0,0-- Last click pos
local function _updateMousePos(x,y,dx,dy)
if SCN.swapping or WAIT.state then return end
dx,dy=dx/SCR.k,dy/SCR.k
if SCN.mouseMove then SCN.mouseMove(x,y,dx,dy) end
if ms.isDown(1) then
WIDGET.drag(x,y,dx,dy)
else
WIDGET.cursorMove(x,y)
end
end
local function mouse_update(dt)
if not KBisDown('lctrl','rctrl') and KBisDown('up','down','left','right') then
local dx,dy=0,0
if KBisDown('up') then dy=dy-cursorSpd end
if KBisDown('down') then dy=dy+cursorSpd end
if KBisDown('left') then dx=dx-cursorSpd end
if KBisDown('right') then dx=dx+cursorSpd end
mx=max(min(mx+dx,1280),0)
my=max(min(my+dy,720),0)
if my==0 or my==720 then
WIDGET.sel=false
WIDGET.drag(0,0,0,-dy)
end
_updateMousePos(mx,my,dx,dy)
cursorSpd=min(cursorSpd+dt*26,12.6)
else
cursorSpd=6
end
end
local function gp_update(js,dt)
local sx,sy=js._jsObj:getGamepadAxis('leftx'),js._jsObj:getGamepadAxis('lefty')
if math.abs(sx)>.1 or math.abs(sy)>.1 then
local dx,dy=0,0
if sy<-.1 then dy=dy+2*sy*cursorSpd end
if sy>.1 then dy=dy+2*sy*cursorSpd end
if sx<-.1 then dx=dx+2*sx*cursorSpd end
if sx>.1 then dx=dx+2*sx*cursorSpd end
mx=max(min(mx+dx,1280),0)
my=max(min(my+dy,720),0)
if my==0 or my==720 then
WIDGET.sel=false
WIDGET.drag(0,0,0,-dy)
end
_updateMousePos(mx,my,dx,dy)
cursorSpd=min(cursorSpd+dt*26,12.6)
else
cursorSpd=6
end
end
function love.mousepressed(x,y,k,touch)
if touch or WAIT.state then return end
mouseShow=true
mx,my=ITP(xOy,x,y)
if debugMode==1 then
print(("(%d,%d)<-%d,%d ~~(%d,%d)<-%d,%d"):format(
mx,my,
mx-lastX,my-lastY,
math.floor(mx/10)*10,math.floor(my/10)*10,
math.floor((mx-lastX)/10)*10,math.floor((my-lastY)/10)*10
))
end
if SCN.swapping then return end
if SCN.mouseDown then SCN.mouseDown(mx,my,k) end
WIDGET.press(mx,my,k)
lastX,lastY=mx,my
if showClickFX then SYSFX.newTap(3,mx,my) end
end
function love.mousemoved(x,y,dx,dy,touch)
if touch then return end
mouseShow=true
mx,my=ITP(xOy,x,y)
_updateMousePos(mx,my,dx,dy)
end
function love.mousereleased(x,y,k,touch)
if touch or WAIT.state or SCN.swapping then return end
mx,my=ITP(xOy,x,y)
if SCN.mouseUp then SCN.mouseUp(mx,my,k) end
if WIDGET.sel then
WIDGET.release(mx,my,k)
else
if lastX and SCN.mouseClick and (mx-lastX)^2+(my-lastY)^2<62 then
SCN.mouseClick(mx,my,k)
end
end
end
function love.wheelmoved(x,y)
if math.abs(x)>=100 then x=x/100 end
if math.abs(y)>=100 then y=y/100 end
if WAIT.state or SCN.swapping then return end
if SCN.wheelMoved then
SCN.wheelMoved(x,y)
else
WIDGET.unFocus()
WIDGET.drag(0,0,0,100*y)
end
end
function love.touchpressed(id,x,y)
mouseShow=false
if WAIT.state or SCN.swapping then return end
if not SCN.mainTouchID then
SCN.mainTouchID=id
WIDGET.unFocus(true)
love.touchmoved(id,x,y,0,0)
end
x,y=ITP(xOy,x,y)
lastX,lastY=x,y
if SCN.touchDown then SCN.touchDown(x,y,id) end
if kb.hasTextInput() then kb.setTextInput(false) end
WIDGET.cursorMove(x,y)
WIDGET.press(x,y,1)
end
function love.touchmoved(id,x,y,dx,dy)
if WAIT.state or SCN.swapping then return end
x,y=ITP(xOy,x,y)
if SCN.touchMove then SCN.touchMove(x,y,dx/SCR.k,dy/SCR.k,id) end
WIDGET.drag(x,y,dx/SCR.k,dy/SCR.k)
end
function love.touchreleased(id,x,y)
if WAIT.state or SCN.swapping then return end
x,y=ITP(xOy,x,y)
if id==SCN.mainTouchID then
WIDGET.release(x,y,1)
WIDGET.cursorMove(x,y)
WIDGET.unFocus()
SCN.mainTouchID=false
end
if SCN.touchUp then SCN.touchUp(x,y,id) end
if (x-lastX)^2+(y-lastY)^2<62 then
if SCN.touchClick then SCN.touchClick(x,y) end
if showClickFX then SYSFX.newTap(3,x,y) end
end
end
-- function love.mousepressed(x,y,k) love.touchpressed(1,x,y) end
-- function love.mousemoved(x,y,dx,dy,touch) love.touchmoved(1,x,y,dx,dy) end
-- function love.mousereleased(x,y,k) love.touchreleased(1,x,y) end
local globalKey={
f8=function()
debugMode=1
MES.new('info',"DEBUG ON",.2)
end
}
local fnKey={NULL,NULL,NULL,NULL,NULL,NULL,NULL}
local function debugKeyPressed(key)
if key=='f1' then fnKey[1]()
elseif key=='f2' then fnKey[2]()
elseif key=='f3' then fnKey[3]()
elseif key=='f4' then fnKey[4]()
elseif key=='f5' then fnKey[5]()
elseif key=='f6' then fnKey[6]()
elseif key=='f7' then fnKey[7]()
elseif key=='f8' then debugMode=nil MES.new('info',"DEBUG OFF",.2)
elseif key=='f9' then debugMode=1 MES.new('info',"DEBUG 1")
elseif key=='f10' then debugMode=2 MES.new('info',"DEBUG 2")
elseif key=='f11' then debugMode=3 MES.new('info',"DEBUG 3")
elseif key=='f12' then debugMode=4 MES.new('info',"DEBUG 4")
elseif debugMode==2 then
local W=WIDGET.sel
if W then
if key=='left' then W.x=W.x-10
elseif key=='right' then W.x=W.x+10
elseif key=='up' then W.y=W.y-10
elseif key=='down' then W.y=W.y+10
elseif key==',' then W.w=W.w-10
elseif key=='.' then W.w=W.w+10
elseif key=='/' then W.h=W.h-10
elseif key=='\'' then W.h=W.h+10
elseif key=='[' then W.font=W.font-5
elseif key==']' then W.font=W.font+5
else return
end
else
return
end
else
return
end
return true
end
function love.keypressed(key,_,isRep)
mouseShow=false
if debugMode and debugKeyPressed(key) then
-- Do nothing
elseif globalKey[key] then
globalKey[key]()
else
if SCN.swapping then return end
if WAIT.state then
if key=='escape' and WAIT.arg.escapable then WAIT.interrupt() end
return
end
if EDITING=="" and (not SCN.keyDown or SCN.keyDown(key,isRep)) then
local W=WIDGET.sel
if key=='escape' and not isRep then
SCN.back()
elseif key=='up' or key=='down' or key=='left' or key=='right' then
mouseShow=true
if KBisDown('lctrl','rctrl') then
if W and W.arrowKey then W:arrowKey(key) end
end
elseif key=='space' or key=='return' then
mouseShow=true
if not isRep then
if showClickFX then SYSFX.newTap(3,mx,my) end
love.mousepressed(mx,my,1)
love.mousereleased(mx,my,1)
end
else
if W and W.keypress then
W:keypress(key)
end
end
end
end
end
function love.keyreleased(i)
if WAIT.state or SCN.swapping then return end
if SCN.keyUp then SCN.keyUp(i) end
end
function love.textedited(texts)
EDITING=texts
end
function love.textinput(texts)
WIDGET.textinput(texts)
end
-- analog sticks: -1, 0, 1 for neg, neutral, pos
-- triggers: 0 for released, 1 for pressed
local jsAxisEventName={
leftx={'leftstick_left','leftstick_right'},
lefty={'leftstick_up','leftstick_down'},
rightx={'rightstick_left','rightstick_right'},
righty={'rightstick_up','rightstick_down'},
triggerleft='triggerleft',
triggerright='triggerright'
}
local gamePadKeys={'a','b','x','y','back','guide','start','leftstick','rightstick','leftshoulder','rightshoulder','dpup','dpdown','dpleft','dpright'}
local dPadToKey={
dpup='up',
dpdown='down',
dpleft='left',
dpright='right',
start='return',
back='escape',
}
function love.joystickadded(joystick)
table.insert(jsState,{
_id=joystick:getID(),
_jsObj=joystick,
leftx=0,lefty=0,
rightx=0,righty=0,
triggerleft=0,triggerright=0
})
MES.new('info',"Joystick added")
end
function love.joystickremoved(joystick)
for i=1,#jsState do
if jsState[i]._jsObj==joystick then
for j=1,#gamePadKeys do
if joystick:isGamepadDown(gamePadKeys[j]) then
love.gamepadreleased(joystick,gamePadKeys[j])
end
end
love.gamepadaxis(joystick,'leftx',0)
love.gamepadaxis(joystick,'lefty',0)
love.gamepadaxis(joystick,'rightx',0)
love.gamepadaxis(joystick,'righty',0)
love.gamepadaxis(joystick,'triggerleft',-1)
love.gamepadaxis(joystick,'triggerright',-1)
MES.new('info',"Joystick removed")
table.remove(jsState,i)
break
end
end
end
function love.gamepadaxis(joystick,axis,val)
if jsState[1] and joystick==jsState[1]._jsObj then
local js=jsState[1]
if axis=='leftx' or axis=='lefty' or axis=='rightx' or axis=='righty' then
local newVal=-- range: [0,1]
val>.4 and 1 or
val<-.4 and -1 or
0
if newVal~=js[axis] then
if js[axis]==-1 then
love.gamepadreleased(joystick,jsAxisEventName[axis][1])
elseif js[axis]~=0 then
love.gamepadreleased(joystick,jsAxisEventName[axis][2])
end
if newVal==-1 then
love.gamepadpressed(joystick,jsAxisEventName[axis][1])
elseif newVal==1 then
love.gamepadpressed(joystick,jsAxisEventName[axis][2])
end
js[axis]=newVal
end
elseif axis=='triggerleft' or axis=='triggerright' then
local newVal=val>.3 and 1 or 0-- range: [0,1]
if newVal~=js[axis] then
if newVal==1 then
love.gamepadpressed(joystick,jsAxisEventName[axis])
else
love.gamepadreleased(joystick,jsAxisEventName[axis])
end
js[axis]=newVal
end
end
end
end
function love.gamepadpressed(_,key)
mouseShow=false
if not SCN.swapping then
local cursorCtrl
if SCN.gamepadDown then
cursorCtrl=SCN.gamepadDown(key)
elseif SCN.keyDown then
cursorCtrl=SCN.keyDown(dPadToKey[key] or key)
else
cursorCtrl=true
end
if cursorCtrl then
key=dPadToKey[key] or key
mouseShow=true
local W=WIDGET.sel
if key=='back' then
SCN.back()
elseif key=='up' or key=='down' or key=='left' or key=='right' then
mouseShow=true
if W and W.arrowKey then W:arrowKey(key) end
elseif key=='return' then
mouseShow=true
if showClickFX then SYSFX.newTap(3,mx,my) end
love.mousepressed(mx,my,1)
love.mousereleased(mx,my,1)
else
if W and W.keypress then
W:keypress(key)
end
end
end
end
end
function love.gamepadreleased(_,i)
if WAIT.state or SCN.swapping then return end
if SCN.gamepadUp then SCN.gamepadUp(i) end
end
function love.filedropped(file)
if WAIT.state or SCN.swapping then return end
if SCN.fileDropped then SCN.fileDropped(file) end
end
function love.directorydropped(dir)
if WAIT.state or SCN.swapping then return end
if SCN.directoryDropped then SCN.directoryDropped(dir) end
end
local autoGCcount=0
function love.lowmemory()
collectgarbage()
if autoGCcount<3 then
autoGCcount=autoGCcount+1
MES.new('check',"[auto GC] low MEM 设备内存过低")
end
end
local onResize=NULL
function love.resize(w,h)
if SCR.w==w and SCR.h==h then return end
SCR.resize(w,h)
if BG.resize then BG.resize(w,h) end
if SCN.resize then SCN.resize(w,h) end
WIDGET.resize(w,h)
FONT.reset()
onResize(w,h)
end
local onFocus=NULL
function love.focus(f) onFocus(f) end
local yield=coroutine.yield
local function secondLoopThread()
local mainLoop=love.run()
repeat yield() until mainLoop()
end
function love.errorhandler(msg)
if type(msg)~='string' then
msg="Unknown error"
elseif msg:find("Invalid UTF-8") and text then
msg=text.tryAnotherBuild
end
-- Generate error message
local err={"Error:"..msg}
local c=2
for l in debug.traceback("",2):gmatch("(.-)\n") do
if c>2 then
if not l:find("boot") then
err[c]=l:gsub("^\t*","")
c=c+1
end
else
err[2]="Traceback"
c=3
end
end
print(table.concat(err,"\n",1,c-2))
-- Reset something
love.audio.stop()
gc.reset()
local sceneStack=SCN and table.concat(SCN.stack,"/") or "NULL"
if LOADED and #errData<3 then
BG.set('none')
table.insert(errData,{mes=err,scene=sceneStack})
-- Write messages to log file
love.filesystem.append('conf/error.log',
os.date("%Y/%m/%d %A %H:%M:%S\n")..
#errData.." crash(es) "..SYSTEM.."-"..VERSION.string.." scene: "..sceneStack.."\n"..
table.concat(err,"\n",1,c-2).."\n\n"
)
-- Get screencapture
gc.captureScreenshot(function(_) errData[#errData].shot=gc.newImage(_) end)
gc.present()
-- Create a new mainLoop thread to keep game alive
local status,resume=coroutine.status,coroutine.resume
local loopThread=coroutine.create(secondLoopThread)
local res,threadErr
repeat
res,threadErr=resume(loopThread)
until status(loopThread)=='dead'
if not res then
love.errorhandler(threadErr)
return
end
else
ms.setVisible(true)
local errorMsg
errorMsg=LOADED and
"Too many errors or fatal error occured.\nPlease restart the game." or
"An error has occurred during loading.\nError info has been created, and you can send it to the author."
while true do
love.event.pump()
for E,a,b in love.event.poll() do
if E=='quit' or a=='escape' then
return true
elseif E=='resize' then
SCR.resize(a,b)
end
end
gc_clear(.3,.5,.9)
gc_push('transform')
gc_replaceTransform(SCR.xOy)
FONT.set(100)gc_print(":(",100,0,0,1.2)
FONT.set(40)gc.printf(errorMsg,100,160,SCR.w0-100)
FONT.set(20)
gc_print(SYSTEM.."-"..VERSION.string.." scene:"..sceneStack,100,660)
gc.printf(err[1],100,360,1260-100)
gc_print("TRACEBACK",100,450)
for i=4,#err-2 do
gc_print(err[i],100,400+20*i)
end
gc_pop()
gc_present()
love.timer.sleep(.26)
end
end
end
love.threaderror=nil
love.draw,love.update=nil-- remove default draw/update
local debugColor={
COLOR.Z,
COLOR.lM,
COLOR.lG,
COLOR.lB,
}
local debugInfos={
{"Cache",gcinfo},
}
function love.run()
local love=love
local TEXT_update,TEXT_draw=TEXT.update,TEXT.draw
local MES_update,MES_draw=MES.update,MES.draw
local HTTP_update,WS_update=HTTP.update,WS.update
local TASK_update=TASK.update
local SYSFX_update,SYSFX_draw=SYSFX.update,SYSFX.draw
local WIDGET_update,WIDGET_draw=WIDGET.update,WIDGET.draw
local STEP,SLEEP=love.timer.step,love.timer.sleep
local FPS,MINI=love.timer.getFPS,love.window.isMinimized
local PUMP,POLL=love.event.pump,love.event.poll
local timer=love.timer.getTime
local frameTimeList={}
local lastFrame=timer()
local lastFreshPow=lastFrame
local FCT=0-- Framedraw counter, from 0~99
love.resize(gc.getWidth(),gc.getHeight())
-- Scene Launch
while #SCN.stack>0 do SCN.pop() end
if #errData>0 then
SCN.cur='error'
SCN.init('error')
else
SCN.init('load')
end
return function()
local _
local time=timer()
local dt=time-lastFrame
lastFrame=time
-- EVENT
PUMP()
for N,a,b,c,d,e in POLL() do
if love[N] then
love[N](a,b,c,d,e)
elseif N=='quit' then
if onBeforeQuit then
onBeforeQuit()
onBeforeQuit=false
else
onQuit()
return a or true
end
end
end
-- UPDATE
STEP()
if SYSTEM == 'Web' then
JS.retrieveData(dt)
CLIPBOARD._update(dt)
end
if mouseShow then mouse_update(dt) end
if next(jsState) then gp_update(jsState[1],dt) end
VOC.update()
BG.update(dt)
TEXT_update(dt)
WAIT.update(dt)
MES_update(dt)
HTTP_update(dt)
WS_update(dt)
TASK_update(dt)
SYSFX_update(dt)
if SCN.update then SCN.update(dt) end
if SCN.swapping then SCN.swapUpdate(dt) end
WIDGET_update(dt)
-- DRAW
if not MINI() then
FCT=FCT+frameMul
if FCT>=100 then
FCT=FCT-100
gc_replaceTransform(SCR.origin)
gc_setColor(1,1,1)
BG.draw()
gc_replaceTransform(SCR.xOy)
if SCN.draw then SCN.draw() end
WIDGET_draw()
SYSFX_draw()
TEXT_draw()
-- Draw cursor
if mouseShow then drawCursor(time,mx,my) end
gc_replaceTransform(SCR.xOy_ul)
if showPowerInfo then
gc.translate(0,27)
end
MES_draw()
gc_replaceTransform(SCR.origin)
-- Draw power info.
if showPowerInfo then
gc_setColor(1,1,1)
gc_draw(infoCanvas,SCR.safeX,0,0,SCR.k)
end
-- Draw scene swapping animation
if SCN.swapping then
gc_setColor(1,1,1)
_=SCN.state
_.draw(_.time)
end
gc_replaceTransform(SCR.xOy_d)
-- Draw Version string
gc_setColor(.9,.9,.9,.42)
FONT.set(20)
GC.mStr(versionText,0,-30)
gc_replaceTransform(SCR.xOy_dl)
local safeX=SCR.safeX/SCR.k
-- Draw FPS
FONT.set(15)
gc_setColor(1,1,1)
gc_print(FPS(),safeX+5,-20)
-- Debug info.
if debugMode then
-- Debug infos at left-down
gc_setColor(debugColor[debugMode])
-- Text infos
for i=1,#debugInfos do
gc_print(debugInfos[i][1],safeX+5,-20-20*i)
gc_print(debugInfos[i][2](),safeX+62.6,-20-20*i)
end
-- Update & draw frame time
table.insert(frameTimeList,1,dt)table.remove(frameTimeList,126)
gc_setColor(1,1,1,.3)
for i=1,#frameTimeList do
gc.rectangle('fill',150+2*i,-20,2,-frameTimeList[i]*4000)
end
-- Cursor pos disp
gc_replaceTransform(SCR.origin)
local x,y=SCR.xOy:transformPoint(mx,my)
gc_setLineWidth(1)
gc_line(x,0,x,SCR.h)
gc_line(0,y,SCR.w,y)
local t=math.floor(mx+.5)..","..math.floor(my+.5)
gc.setColor(COLOR.D)
gc_print(t,x+1,y)
gc_print(t,x+1,y-1)
gc_print(t,x+2,y-1)
gc_setColor(COLOR.Z)
gc_print(t,x+2,y)
gc_replaceTransform(SCR.xOy_dr)
-- Websocket status
local status=WS.status('game')
if status=='dead' then
gc_setColor(COLOR.R)
elseif status=='connecting' then
gc_setColor(1,1,1,.5+.3*math.sin(time*6.26))
elseif status=='running' then
gc_setColor(COLOR.lG)
end
gc.rectangle('fill',-16,-16,12,12)
local t1,t2,t3=WS.getTimers('game')
if t1>0 then gc_setColor(.9,.9,.9,t1)gc.rectangle('fill',-60,-2,-16,-16) end
if t2>0 then gc_setColor(.3,1,.3,t2)gc.rectangle('fill',-42,-2,-16,-16) end
if t3>0 then gc_setColor(1,.2,.2,t3)gc.rectangle('fill',-24,-2,-16,-16) end
end
gc_replaceTransform(SCR.origin)
WAIT.draw()
gc_present()
-- SPEED UPUPUP!
if discardCanvas then gc_discard() end
end
end
-- Fresh power info.
if time-lastFreshPow>2.6 then
if showPowerInfo then
updatePowerInfo()
lastFreshPow=time
end
if gc.getWidth()~=SCR.w or gc.getHeight()~=SCR.h then
love.resize(gc.getWidth(),gc.getHeight())
end
end
-- Slow debugmode
if debugMode then
if debugMode==3 then
SLEEP(.1)
elseif debugMode==4 then
SLEEP(.5)
end
end
_=timer()-lastFrame
if _<sleepInterval*.9626 then SLEEP(sleepInterval*.9626-_) end
while timer()-lastFrame<sleepInterval do end
end
end
local Z={}
function Z.getJsState() return jsState end
function Z.getErr(i)
if i=='#' then
return errData[#errData]
elseif i then
return errData[i]
else
return errData
end
end
function Z.setPowerInfo(bool) showPowerInfo=bool end
function Z.setCleanCanvas(bool) discardCanvas=bool end
function Z.setFrameMul(n) frameMul=n end
function Z.setMaxFPS(fps) sleepInterval=1/fps end
function Z.setClickFX(bool) showClickFX=bool end
--[Warning] Color and line width is uncertain value, set it in the function.
function Z.setCursor(func) drawCursor=func end
function Z.setVersionText(str) versionText=str end
function Z.setDebugInfo(list)
assert(type(list)=='table',"Z.setDebugInfo(list): list must be table")
for i=1,#list do
assert(type(list[i][1])=='string',"Z.setDebugInfo(list): list[i][1] must be string")
assert(type(list[i][2])=='function',"Z.setDebugInfo(list): list[i][2] must be function")
end
debugInfos=list
end
-- Change F1~F7 events of debugmode (F8 mode)
function Z.setOnFnKeys(list)
assert(type(list)=='table',"Z.setOnFnKeys(list): list must be table")
for i=1,7 do fnKey[i]=assert(type(list[i])=='function' and list[i]) end
end
function Z.setOnGlobalKey(key,func)
assert(type(key)=='string',"Z.setOnFnKeys(key,func): key must be string")
if not func then
globalKey[key]=nil
else
assert(type(func)=='function',"Z.setOnFnKeys(key,func): func must be function")
globalKey[key]=func
end
end
function Z.setOnFocus(func)
onFocus=assert(type(func)=='function' and func,"Z.setOnFocus(func): func must be function")
end
function Z.setOnResize(func)
onResize=assert(type(func)=='function' and func,"Z.setOnResize(func): func must be function")
end
function Z.setOnQuit(func)
onQuit=assert(type(func)=='function' and func,"Z.setOnQuit(func): func must be function")
end
function Z.setOnBeforeQuit(func)
onBeforeQuit=assert(type(func)=='function' and func,"Z.setOnBeforeQuit(func): func must be function")
end
return Z