代码规范:把所有的tab换成空格

This commit is contained in:
MrZ626
2021-08-25 04:28:52 +08:00
parent 8f910f95f4
commit 295e79984f
271 changed files with 35384 additions and 35379 deletions

View File

@@ -1,50 +1,50 @@
local gc_clear=love.graphics.clear
local BGs={
none={draw=function()gc_clear(.08,.08,.084)end}
none={draw=function()gc_clear(.08,.08,.084)end}
}
local BGlist={'none'}
local BG={
cur='none',
default='none',
init=false,
resize=false,
update=NULL,
draw=BGs.none.draw,
event=false,
discard=NULL,
cur='none',
default='none',
init=false,
resize=false,
update=NULL,
draw=BGs.none.draw,
event=false,
discard=NULL,
}
function BG.add(name,bg)
BGs[name]=bg
BGlist[#BGlist+1]=name
BGs[name]=bg
BGlist[#BGlist+1]=name
end
function BG.getList()
return BGlist
return BGlist
end
function BG.send(...)
if BG.event then
BG.event(...)
end
if BG.event then
BG.event(...)
end
end
function BG.setDefault(bg)
BG.default=bg
BG.default=bg
end
function BG.set(background)
if not background then background=BG.default end
if not BGs[background]or not SETTING.bg then return end
if background~=BG.cur then
BG.discard()
BG.cur=background
background=BGs[background]
if not background then background=BG.default end
if not BGs[background]or not SETTING.bg then return end
if background~=BG.cur then
BG.discard()
BG.cur=background
background=BGs[background]
BG.init= background.init or NULL
BG.resize= background.resize or NULL
BG.update= background.update or NULL
BG.draw= background.draw or NULL
BG.event= background.event or NULL
BG.discard= background.discard or NULL
BG.init()
end
return true
BG.init= background.init or NULL
BG.resize= background.resize or NULL
BG.update= background.update or NULL
BG.draw= background.draw or NULL
BG.event= background.event or NULL
BG.discard=background.discard or NULL
BG.init()
end
return true
end
return BG

View File

@@ -1,109 +1,109 @@
local BGM={
default=false,
getList=function()error("Cannot getList before initialize!")end,
getCount=function()return 0 end,
play=NULL,
freshVolume=NULL,
stop=NULL,
--nowPlay=[str:playing ID]
--playing=[src:playing SRC]
default=false,
getList=function()error("Cannot getList before initialize!")end,
getCount=function()return 0 end,
play=NULL,
freshVolume=NULL,
stop=NULL,
--nowPlay=[str:playing ID]
--playing=[src:playing SRC]
}
function BGM.setDefault(bgm)
BGM.default=bgm
BGM.default=bgm
end
function BGM.init(list)
BGM.init=nil
local Sources={}
BGM.init=nil
local Sources={}
local simpList={}
for _,v in next,list do
table.insert(simpList,v.name)
Sources[v.name]=v.path
end
table.sort(simpList)
function BGM.getList()return simpList end
local count=#simpList
function BGM.getCount()return count end
local simpList={}
for _,v in next,list do
table.insert(simpList,v.name)
Sources[v.name]=v.path
end
table.sort(simpList)
function BGM.getList()return simpList end
local count=#simpList
function BGM.getCount()return count end
local function _load(name)
if type(Sources[name])=='string'then
if love.filesystem.getInfo(Sources[name])then
Sources[name]=love.audio.newSource(Sources[name],'stream')
Sources[name]:setLooping(true)
Sources[name]:setVolume(0)
return true
else
MES.new('warn',"No BGM file: "..Sources[name],5)
end
elseif Sources[name]then
return true
elseif name then
MES.new('warn',"No BGM: "..name,5)
end
end
function BGM.loadAll()for name in next,Sources do _load(name)end end
local function task_fadeOut(src)
while true do
coroutine.yield()
local v=src:getVolume()-.025*SETTING.bgm
src:setVolume(v>0 and v or 0)
if v<=0 then
src:stop()
return true
end
end
end
local function task_fadeIn(src)
while true do
coroutine.yield()
local v=SETTING.bgm
v=math.min(v,src:getVolume()+.025*v)
src:setVolume(v)
if v>=SETTING.bgm then
return true
end
end
end
local function check_curFadeOut(task,code,src)
return task.code==code and task.args[1]==src
end
function BGM.play(name)
if not name then name=BGM.default end
if not _load(name)then return end
if SETTING.bgm==0 then
BGM.nowPlay=name
BGM.playing=Sources[name]
return true
end
if name and Sources[name]then
if BGM.nowPlay~=name then
if BGM.nowPlay then TASK.new(task_fadeOut,BGM.playing)end
TASK.removeTask_iterate(check_curFadeOut,task_fadeOut,Sources[name])
TASK.removeTask_code(task_fadeIn)
local function _load(name)
if type(Sources[name])=='string'then
if love.filesystem.getInfo(Sources[name])then
Sources[name]=love.audio.newSource(Sources[name],'stream')
Sources[name]:setLooping(true)
Sources[name]:setVolume(0)
return true
else
MES.new('warn',"No BGM file: "..Sources[name],5)
end
elseif Sources[name]then
return true
elseif name then
MES.new('warn',"No BGM: "..name,5)
end
end
function BGM.loadAll()for name in next,Sources do _load(name)end end
local function task_fadeOut(src)
while true do
coroutine.yield()
local v=src:getVolume()-.025*SETTING.bgm
src:setVolume(v>0 and v or 0)
if v<=0 then
src:stop()
return true
end
end
end
local function task_fadeIn(src)
while true do
coroutine.yield()
local v=SETTING.bgm
v=math.min(v,src:getVolume()+.025*v)
src:setVolume(v)
if v>=SETTING.bgm then
return true
end
end
end
local function check_curFadeOut(task,code,src)
return task.code==code and task.args[1]==src
end
function BGM.play(name)
if not name then name=BGM.default end
if not _load(name)then return end
if SETTING.bgm==0 then
BGM.nowPlay=name
BGM.playing=Sources[name]
return true
end
if name and Sources[name]then
if BGM.nowPlay~=name then
if BGM.nowPlay then TASK.new(task_fadeOut,BGM.playing)end
TASK.removeTask_iterate(check_curFadeOut,task_fadeOut,Sources[name])
TASK.removeTask_code(task_fadeIn)
TASK.new(task_fadeIn,Sources[name])
BGM.nowPlay=name
BGM.playing=Sources[name]
BGM.playing:play()
end
return true
end
end
function BGM.freshVolume()
if BGM.playing then
local v=SETTING.bgm
if v>0 then
BGM.playing:setVolume(v)
BGM.playing:play()
elseif BGM.nowPlay then
BGM.playing:pause()
end
end
end
function BGM.stop()
TASK.removeTask_code(task_fadeIn)
if BGM.nowPlay then TASK.new(task_fadeOut,BGM.playing)end
BGM.nowPlay,BGM.playing=nil
end
TASK.new(task_fadeIn,Sources[name])
BGM.nowPlay=name
BGM.playing=Sources[name]
BGM.playing:play()
end
return true
end
end
function BGM.freshVolume()
if BGM.playing then
local v=SETTING.bgm
if v>0 then
BGM.playing:setVolume(v)
BGM.playing:play()
elseif BGM.nowPlay then
BGM.playing:pause()
end
end
end
function BGM.stop()
TASK.removeTask_code(task_fadeIn)
if BGM.nowPlay then TASK.new(task_fadeOut,BGM.playing)end
BGM.nowPlay,BGM.playing=nil
end
end
return BGM

View File

@@ -1,126 +1,126 @@
local COLOR={
red= {.92, .12, .12},
fire= {.92, 0.4, .12},
orange= {.92, 0.6, .12},
yellow= {.92, .92, .12},
lime= {0.7, .92, .12},
jade= {0.5, .92, .12},
green= {.12, .92, .12},
aqua= {.12, .92, 0.6},
cyan= {.12, .92, .92},
navy= {.12, 0.7, .92},
sea= {.12, 0.4, .92},
blue= {0.2, 0.2, .92},
violet= {0.4, .12, .92},
purple= {0.7, .12, .92},
magenta= {.92, .12, .92},
wine= {.92, .12, 0.5},
red= {.92, .12, .12},
fire= {.92, 0.4, .12},
orange= {.92, 0.6, .12},
yellow= {.92, .92, .12},
lime= {0.7, .92, .12},
jade= {0.5, .92, .12},
green= {.12, .92, .12},
aqua= {.12, .92, 0.6},
cyan= {.12, .92, .92},
navy= {.12, 0.7, .92},
sea= {.12, 0.4, .92},
blue= {0.2, 0.2, .92},
violet= {0.4, .12, .92},
purple= {0.7, .12, .92},
magenta= {.92, .12, .92},
wine= {.92, .12, 0.5},
lRed= {.95, 0.5, 0.5},
lFire= {.95, 0.7, 0.5},
lOrange= {.95, 0.8, 0.3},
lYellow= {.95, .95, 0.5},
lLime= {0.8, .95, 0.4},
lJade= {0.6, .95, 0.4},
lGreen= {0.5, .95, 0.5},
lAqua= {0.4, .95, 0.7},
lCyan= {0.5, .95, .95},
lNavy= {0.4, .85, .95},
lSea= {0.5, 0.7, .95},
lBlue= {0.7, 0.7, .95},
lViolet= {0.7, 0.4, .95},
lPurple= {0.8, 0.4, .95},
lMagenta= {.95, 0.5, .95},
lWine= {.95, 0.4, 0.7},
lRed= {.95, 0.5, 0.5},
lFire= {.95, 0.7, 0.5},
lOrange= {.95, 0.8, 0.3},
lYellow= {.95, .95, 0.5},
lLime= {0.8, .95, 0.4},
lJade= {0.6, .95, 0.4},
lGreen= {0.5, .95, 0.5},
lAqua= {0.4, .95, 0.7},
lCyan= {0.5, .95, .95},
lNavy= {0.4, .85, .95},
lSea= {0.5, 0.7, .95},
lBlue= {0.7, 0.7, .95},
lViolet= {0.7, 0.4, .95},
lPurple= {0.8, 0.4, .95},
lMagenta={.95, 0.5, .95},
lWine= {.95, 0.4, 0.7},
dRed= {0.6, .08, .08},
dFire= {0.6, 0.3, .08},
dOrange= {0.6, 0.4, .08},
dYellow= {0.6, 0.6, .08},
dLime= {0.5, 0.6, .08},
dJade= {0.3, 0.6, .08},
dGreen= {.08, 0.6, .08},
dAqua= {.08, 0.6, 0.4},
dCyan= {.08, 0.6, 0.6},
dNavy= {.08, 0.4, 0.6},
dSea= {.08, 0.2, 0.6},
dBlue= {0.1, 0.1, 0.6},
dViolet= {0.2, .08, 0.6},
dPurple= {0.4, .08, 0.6},
dMagenta= {0.6, .08, 0.6},
dWine= {0.6, .08, 0.3},
dRed= {0.6, .08, .08},
dFire= {0.6, 0.3, .08},
dOrange= {0.6, 0.4, .08},
dYellow= {0.6, 0.6, .08},
dLime= {0.5, 0.6, .08},
dJade= {0.3, 0.6, .08},
dGreen= {.08, 0.6, .08},
dAqua= {.08, 0.6, 0.4},
dCyan= {.08, 0.6, 0.6},
dNavy= {.08, 0.4, 0.6},
dSea= {.08, 0.2, 0.6},
dBlue= {0.1, 0.1, 0.6},
dViolet= {0.2, .08, 0.6},
dPurple= {0.4, .08, 0.6},
dMagenta={0.6, .08, 0.6},
dWine= {0.6, .08, 0.3},
black= {.05, .05, .05},
dGray= {0.3, 0.3, 0.3},
gray= {0.6, 0.6, 0.6},
lGray= {0.8, 0.8, 0.8},
white= {.97, .97, .97},
black= {.05, .05, .05},
dGray= {0.3, 0.3, 0.3},
gray= {0.6, 0.6, 0.6},
lGray= {0.8, 0.8, 0.8},
white= {.97, .97, .97},
}
for k,v in next,{
R='red',F='fire',O='orange',Y='yellow',L='lime',J='jade',G='green',A='aqua',C='cyan',N='navy',S='sea',B='blue',V='violet',P='purple',M='magenta',W='wine',
lR='lRed',lF='lFire',lO='lOrange',lY='lYellow',lL='lLime',lJ='lJade',lG='lGreen',lA='lAqua',lC='lCyan',lN='lNavy',lS='lSea',lB='lBlue',lV='lViolet',lP='lPurple',lM='lMagenta',lW='lWine',
dR='dRed',dF='dFire',dO='dOrange',dY='dYellow',dL='dLime',dJ='dJade',dG='dGreen',dA='dAqua',dC='dCyan',dN='dNavy',dS='dSea',dB='dBlue',dV='dViolet',dP='dPurple',dM='dMagenta',dW='dWine',
D='black',dH='dGray',H='gray',lH='lGray',Z='white',
--Remain letter: EIKQTUX
R='red', F='fire', O='orange', Y='yellow', L='lime', J='jade', G='green', A='aqua', C='cyan', N='navy', S='sea', B='blue', V='violet', P='purple', M='magenta', W='wine',
lR='lRed',lF='lFire',lO='lOrange',lY='lYellow',lL='lLime',lJ='lJade',lG='lGreen',lA='lAqua',lC='lCyan',lN='lNavy',lS='lSea',lB='lBlue',lV='lViolet',lP='lPurple',lM='lMagenta',lW='lWine',
dR='dRed',dF='dFire',dO='dOrange',dY='dYellow',dL='dLime',dJ='dJade',dG='dGreen',dA='dAqua',dC='dCyan',dN='dNavy',dS='dSea',dB='dBlue',dV='dViolet',dP='dPurple',dM='dMagenta',dW='dWine',
D='black',dH='dGray',H='gray',lH='lGray',Z='white',
--Remain letter: EIKQTUX
}do
COLOR[k]=COLOR[v]
COLOR[k]=COLOR[v]
end
setmetatable(COLOR,{__index=function(_,k)
error("No color: "..tostring(k))
error("No color: "..tostring(k))
end})
do--Random generators
local rnd=math.random
local list_norm={'red','fire','orange','yellow','lime','jade','green','aqua','cyan','navy','sea','blue','violet','purple','magenta','wine'}
local len_list_norm=#list_norm
function COLOR.random_norm()
return COLOR[list_norm[rnd(len_list_norm)]]
end
local rnd=math.random
local list_norm={'red','fire','orange','yellow','lime','jade','green','aqua','cyan','navy','sea','blue','violet','purple','magenta','wine'}
local len_list_norm=#list_norm
function COLOR.random_norm()
return COLOR[list_norm[rnd(len_list_norm)]]
end
local list_bright={'lRed','lFire','lOrange','lYellow','lLime','lJade','lGreen','lAqua','lCyan','lNavy','lSea','lBlue','lViolet','lPurple','lMagenta','lWine'}
local len_list_bright=#list_bright
function COLOR.random_bright()
return COLOR[list_bright[rnd(len_list_bright)]]
end
local list_bright={'lRed','lFire','lOrange','lYellow','lLime','lJade','lGreen','lAqua','lCyan','lNavy','lSea','lBlue','lViolet','lPurple','lMagenta','lWine'}
local len_list_bright=#list_bright
function COLOR.random_bright()
return COLOR[list_bright[rnd(len_list_bright)]]
end
local list_dark={'dRed','dFire','dOrange','dYellow','dLime','dJade','dGreen','dAqua','dCyan','dNavy','dSea','dBlue','dViolet','dPurple','dMagenta','dWine'}
local len_list_dark=#list_dark
function COLOR.random_dark()
return COLOR[list_dark[rnd(len_list_dark)]]
end
local list_dark={'dRed','dFire','dOrange','dYellow','dLime','dJade','dGreen','dAqua','dCyan','dNavy','dSea','dBlue','dViolet','dPurple','dMagenta','dWine'}
local len_list_dark=#list_dark
function COLOR.random_dark()
return COLOR[list_dark[rnd(len_list_dark)]]
end
end
do--Rainbow generators
local sin=math.sin
function COLOR.rainbow(phase,a)
return
sin(phase)*.4+.6,
sin(phase+2.0944)*.4+.6,
sin(phase-2.0944)*.4+.6,
a
end
function COLOR.rainbow_light(phase,a)
return
sin(phase)*.2+.7,
sin(phase+2.0944)*.2+.7,
sin(phase-2.0944)*.2+.7,
a
end
function COLOR.rainbow_dark(phase,a)
return
sin(phase)*.2+.4,
sin(phase+2.0944)*.2+.4,
sin(phase-2.0944)*.2+.4,
a
end
function COLOR.rainbow_gray(phase,a)
return
sin(phase)*.16+.5,
sin(phase+2.0944)*.16+.5,
sin(phase-2.0944)*.16+.5,
a
end
local sin=math.sin
function COLOR.rainbow(phase,a)
return
sin(phase)*.4+.6,
sin(phase+2.0944)*.4+.6,
sin(phase-2.0944)*.4+.6,
a
end
function COLOR.rainbow_light(phase,a)
return
sin(phase)*.2+.7,
sin(phase+2.0944)*.2+.7,
sin(phase-2.0944)*.2+.7,
a
end
function COLOR.rainbow_dark(phase,a)
return
sin(phase)*.2+.4,
sin(phase+2.0944)*.2+.4,
sin(phase-2.0944)*.2+.4,
a
end
function COLOR.rainbow_gray(phase,a)
return
sin(phase)*.16+.5,
sin(phase+2.0944)*.16+.5,
sin(phase-2.0944)*.16+.5,
a
end
end
return COLOR

View File

@@ -1,90 +1,90 @@
local fs=love.filesystem
local FILE={}
function FILE.load(name)
if fs.getInfo(name)then
local F=fs.newFile(name)
if F:open'r'then
local s=F:read()
F:close()
if s:sub(1,6)=="return"then
s=loadstring(s)
if s then
setfenv(s,{})
return s()
end
elseif s:sub(1,1)=="["or s:sub(1,1)=="{"then
local res=JSON.decode(s)
if res then
return res
end
else
return s
end
end
MES.new('error',name.." "..text.loadError)
end
if fs.getInfo(name)then
local F=fs.newFile(name)
if F:open'r'then
local s=F:read()
F:close()
if s:sub(1,6)=="return"then
s=loadstring(s)
if s then
setfenv(s,{})
return s()
end
elseif s:sub(1,1)=="["or s:sub(1,1)=="{"then
local res=JSON.decode(s)
if res then
return res
end
else
return s
end
end
MES.new('error',name.." "..text.loadError)
end
end
function FILE.save(data,name,mode)
if not mode then mode=""end
if type(data)=='table'then
if mode:find'l'then
data=TABLE.dump(data)
if not data then
MES.new('error',name.." "..text.saveError.."dump error")
return
end
else
data=JSON.encode(data)
if not data then
MES.new('error',name.." "..text.saveError.."json error")
return
end
end
else
data=tostring(data)
end
if not mode then mode=""end
if type(data)=='table'then
if mode:find'l'then
data=TABLE.dump(data)
if not data then
MES.new('error',name.." "..text.saveError.."dump error")
return
end
else
data=JSON.encode(data)
if not data then
MES.new('error',name.." "..text.saveError.."json error")
return
end
end
else
data=tostring(data)
end
if mode:find'd'and fs.getInfo(name)then
MES.new('error',text.saveError_duplicate)
return
end
local F=fs.newFile(name)
F:open'w'
local success,mes=F:write(data)
F:flush()F:close()
if success then
return true
else
MES.new('error',text.saveError..(mes or"unknown error"))
MES.traceback()
end
if mode:find'd'and fs.getInfo(name)then
MES.new('error',text.saveError_duplicate)
return
end
local F=fs.newFile(name)
F:open'w'
local success,mes=F:write(data)
F:flush()F:close()
if success then
return true
else
MES.new('error',text.saveError..(mes or"unknown error"))
MES.traceback()
end
end
function FILE.clear(path)
if fs.getRealDirectory(path)~=SAVEDIR or fs.getInfo(path).type~='directory'then return end
for _,name in next,fs.getDirectoryItems(path)do
name=path..'/'..name
if fs.getRealDirectory(name)==SAVEDIR then
local t=fs.getInfo(name).type
if t=='file'then
fs.remove(name)
end
end
end
if fs.getRealDirectory(path)~=SAVEDIR or fs.getInfo(path).type~='directory'then return end
for _,name in next,fs.getDirectoryItems(path)do
name=path..'/'..name
if fs.getRealDirectory(name)==SAVEDIR then
local t=fs.getInfo(name).type
if t=='file'then
fs.remove(name)
end
end
end
end
function FILE.clear_s(path)
if path~=''and(fs.getRealDirectory(path)~=SAVEDIR or fs.getInfo(path).type~='directory')then return end
for _,name in next,fs.getDirectoryItems(path)do
name=path..'/'..name
if fs.getRealDirectory(name)==SAVEDIR then
local t=fs.getInfo(name).type
if t=='file'then
fs.remove(name)
elseif t=='directory'then
FILE.clear_s(name)
fs.remove(name)
end
end
end
fs.remove(path)
if path~=''and(fs.getRealDirectory(path)~=SAVEDIR or fs.getInfo(path).type~='directory')then return end
for _,name in next,fs.getDirectoryItems(path)do
name=path..'/'..name
if fs.getRealDirectory(name)==SAVEDIR then
local t=fs.getInfo(name).type
if t=='file'then
fs.remove(name)
elseif t=='directory'then
FILE.clear_s(name)
fs.remove(name)
end
end
end
fs.remove(path)
end
return FILE

View File

@@ -8,152 +8,152 @@ function GC.X(obj,x,y,a,k)draw(obj,x,y,a,k,nil,obj:getWidth()*.5,0)end
function GC.Y(obj,x,y,a,k)draw(obj,x,y,a,k,nil,0,obj:getHeight()*.5)end
function GC.draw(obj,x,y,a,k)draw(obj,x,y,a,k,nil,obj:getWidth()*.5,obj:getHeight()*.5)end
function GC.outDraw(obj,div,x,y,a,k)
local w,h=obj:getWidth()*.5,obj:getHeight()*.5
draw(obj,x-div,y-div,a,k,nil,w,h)
draw(obj,x-div,y+div,a,k,nil,w,h)
draw(obj,x+div,y-div,a,k,nil,w,h)
draw(obj,x+div,y+div,a,k,nil,w,h)
local w,h=obj:getWidth()*.5,obj:getHeight()*.5
draw(obj,x-div,y-div,a,k,nil,w,h)
draw(obj,x-div,y+div,a,k,nil,w,h)
draw(obj,x+div,y-div,a,k,nil,w,h)
draw(obj,x+div,y+div,a,k,nil,w,h)
end
function GC.shadedPrint(str,x,y,mode,d,clr1,clr2)
local w=1280
if mode=='center'then
x=x-w*.5
elseif mode=='right'then
x=x-w
end
if not d then d=1 end
setColor(clr1 or COLOR.D)
printf(str,x-d,y-d,w,mode)
printf(str,x-d,y+d,w,mode)
printf(str,x+d,y-d,w,mode)
printf(str,x+d,y+d,w,mode)
setColor(clr2 or COLOR.Z)
printf(str,x,y,w,mode)
local w=1280
if mode=='center'then
x=x-w*.5
elseif mode=='right'then
x=x-w
end
if not d then d=1 end
setColor(clr1 or COLOR.D)
printf(str,x-d,y-d,w,mode)
printf(str,x-d,y+d,w,mode)
printf(str,x+d,y-d,w,mode)
printf(str,x+d,y+d,w,mode)
setColor(clr2 or COLOR.Z)
printf(str,x,y,w,mode)
end
function GC.regularPolygon(mode,x,y,R,segments,r,phase)
local X,Y={},{}
local ang=phase or 0
local angStep=6.283185307179586/segments
for i=1,segments do
X[i]=x+R*math.cos(ang)
Y[i]=y+R*math.sin(ang)
ang=ang+angStep
end
X[segments+1]=x+R*math.cos(ang)
Y[segments+1]=y+R*math.sin(ang)
local halfAng=6.283185307179586/segments/2
local erasedLen=r*math.tan(halfAng)
if mode=='line'then
erasedLen=erasedLen+1--Fix 1px cover
for i=1,segments do
--Line
local x1,y1,x2,y2=X[i],Y[i],X[i+1],Y[i+1]
local dir=math.atan2(y2-y1,x2-x1)
gc.line(x1+erasedLen*math.cos(dir),y1+erasedLen*math.sin(dir),x2-erasedLen*math.cos(dir),y2-erasedLen*math.sin(dir))
local X,Y={},{}
local ang=phase or 0
local angStep=6.283185307179586/segments
for i=1,segments do
X[i]=x+R*math.cos(ang)
Y[i]=y+R*math.sin(ang)
ang=ang+angStep
end
X[segments+1]=x+R*math.cos(ang)
Y[segments+1]=y+R*math.sin(ang)
local halfAng=6.283185307179586/segments/2
local erasedLen=r*math.tan(halfAng)
if mode=='line'then
erasedLen=erasedLen+1--Fix 1px cover
for i=1,segments do
--Line
local x1,y1,x2,y2=X[i],Y[i],X[i+1],Y[i+1]
local dir=math.atan2(y2-y1,x2-x1)
gc.line(x1+erasedLen*math.cos(dir),y1+erasedLen*math.sin(dir),x2-erasedLen*math.cos(dir),y2-erasedLen*math.sin(dir))
--Arc
ang=ang+angStep
local R2=R-r/math.cos(halfAng)
local arcCX,arcCY=x+R2*math.cos(ang),y+R2*math.sin(ang)
gc.arc('line','open',arcCX,arcCY,r,ang-halfAng,ang+halfAng)
end
elseif mode=='fill'then
local L={}
for i=1,segments do
--Line
local x1,y1,x2,y2=X[i],Y[i],X[i+1],Y[i+1]
local dir=math.atan2(y2-y1,x2-x1)
table.insert(L,x1+erasedLen*math.cos(dir))
table.insert(L,y1+erasedLen*math.sin(dir))
table.insert(L,x2-erasedLen*math.cos(dir))
table.insert(L,y2-erasedLen*math.sin(dir))
--Arc
ang=ang+angStep
local R2=R-r/math.cos(halfAng)
local arcCX,arcCY=x+R2*math.cos(ang),y+R2*math.sin(ang)
gc.arc('line','open',arcCX,arcCY,r,ang-halfAng,ang+halfAng)
end
elseif mode=='fill'then
local L={}
for i=1,segments do
--Line
local x1,y1,x2,y2=X[i],Y[i],X[i+1],Y[i+1]
local dir=math.atan2(y2-y1,x2-x1)
table.insert(L,x1+erasedLen*math.cos(dir))
table.insert(L,y1+erasedLen*math.sin(dir))
table.insert(L,x2-erasedLen*math.cos(dir))
table.insert(L,y2-erasedLen*math.sin(dir))
--Arc
ang=ang+angStep
local R2=R-r/math.cos(halfAng)
local arcCX,arcCY=x+R2*math.cos(ang),y+R2*math.sin(ang)
gc.arc('fill','open',arcCX,arcCY,r,ang-halfAng,ang+halfAng)
end
gc.polygon('fill',L)
else
error("Draw mode should be 'line' or 'fill'")
end
--Arc
ang=ang+angStep
local R2=R-r/math.cos(halfAng)
local arcCX,arcCY=x+R2*math.cos(ang),y+R2*math.sin(ang)
gc.arc('fill','open',arcCX,arcCY,r,ang-halfAng,ang+halfAng)
end
gc.polygon('fill',L)
else
error("Draw mode should be 'line' or 'fill'")
end
end
do--function GC.DO(L)
local cmds={
origin="origin",
move="translate",
scale="scale",
rotate="rotate",
shear="shear",
clear="clear",
local cmds={
origin="origin",
move="translate",
scale="scale",
rotate="rotate",
shear="shear",
clear="clear",
setCL="setColor",
setCM="setColorMask",
setLW="setLineWidth",
setLS="setLineStyle",
setLJ="setLineJoin",
setCL="setColor",
setCM="setColorMask",
setLW="setLineWidth",
setLS="setLineStyle",
setLJ="setLineJoin",
print="print",
setFT=function(...)setFont(...)end,
mText=GC.str,
mDraw=GC.draw,
mOutDraw=GC.outDraw,
print="print",
setFT=function(...)setFont(...)end,
mText=GC.str,
mDraw=GC.draw,
mOutDraw=GC.outDraw,
draw="draw",
line="line",
fRect=function(...)gc.rectangle('fill',...)end,
dRect=function(...)gc.rectangle('line',...)end,
fCirc=function(...)gc.circle('fill',...)end,
dCirc=function(...)gc.circle('line',...)end,
fElps=function(...)gc.ellipse('fill',...)end,
dElps=function(...)gc.ellipse('line',...)end,
fPoly=function(...)gc.polygon('fill',...)end,
dPoly=function(...)gc.polygon('line',...)end,
draw="draw",
line="line",
fRect=function(...)gc.rectangle('fill',...)end,
dRect=function(...)gc.rectangle('line',...)end,
fCirc=function(...)gc.circle('fill',...)end,
dCirc=function(...)gc.circle('line',...)end,
fElps=function(...)gc.ellipse('fill',...)end,
dElps=function(...)gc.ellipse('line',...)end,
fPoly=function(...)gc.polygon('fill',...)end,
dPoly=function(...)gc.polygon('line',...)end,
dPie=function(...)gc.arc('line',...)end,
dArc=function(...)gc.arc('line','open',...)end,
dBow=function(...)gc.arc('line','closed',...)end,
fPie=function(...)gc.arc('fill',...)end,
fArc=function(...)gc.arc('fill','open',...)end,
fBow=function(...)gc.arc('fill','closed',...)end,
dPie=function(...)gc.arc('line',...)end,
dArc=function(...)gc.arc('line','open',...)end,
dBow=function(...)gc.arc('line','closed',...)end,
fPie=function(...)gc.arc('fill',...)end,
fArc=function(...)gc.arc('fill','open',...)end,
fBow=function(...)gc.arc('fill','closed',...)end,
fRPol=function(...)GC.regularPolygon('fill',...)end,
dRPol=function(...)GC.regularPolygon('line',...)end,
}
local sizeLimit=gc.getSystemLimits().texturesize
function GC.DO(L)
gc.push()
::REPEAT_tryAgain::
local success,canvas=pcall(gc.newCanvas,math.min(L[1],sizeLimit),math.min(L[2],sizeLimit))
if not success then
sizeLimit=math.floor(sizeLimit*.8)
goto REPEAT_tryAgain
end
gc.setCanvas(canvas)
gc.origin()
gc.clear(1,1,1,0)
gc.setColor(1,1,1)
gc.setLineWidth(1)
for i=3,#L do
local cmd=L[i][1]
if type(cmd)=='boolean'and cmd then
table.remove(L[i],1)
cmd=L[i][1]
end
if type(cmd)=='string'then
local func=cmds[cmd]
if type(func)=='string'then func=gc[func]end
if func then
func(unpack(L[i],2))
else
error("No gc command: "..cmd)
end
end
end
gc.setCanvas()
gc.pop()
return canvas
end
fRPol=function(...)GC.regularPolygon('fill',...)end,
dRPol=function(...)GC.regularPolygon('line',...)end,
}
local sizeLimit=gc.getSystemLimits().texturesize
function GC.DO(L)
gc.push()
::REPEAT_tryAgain::
local success,canvas=pcall(gc.newCanvas,math.min(L[1],sizeLimit),math.min(L[2],sizeLimit))
if not success then
sizeLimit=math.floor(sizeLimit*.8)
goto REPEAT_tryAgain
end
gc.setCanvas(canvas)
gc.origin()
gc.clear(1,1,1,0)
gc.setColor(1,1,1)
gc.setLineWidth(1)
for i=3,#L do
local cmd=L[i][1]
if type(cmd)=='boolean'and cmd then
table.remove(L[i],1)
cmd=L[i][1]
end
if type(cmd)=='string'then
local func=cmds[cmd]
if type(func)=='string'then func=gc[func]end
if func then
func(unpack(L[i],2))
else
error("No gc command: "..cmd)
end
end
end
gc.setCanvas()
gc.pop()
return canvas
end
end
return GC

View File

@@ -1,26 +1,26 @@
local IMG={}
function IMG.init(list)
IMG.init=nil
IMG.init=nil
local null=love.graphics.newCanvas(1,1)
setmetatable(IMG,{__index=function(self,name)
if type(list[name])=='table'then
self[name]={}
for i=1,#list[name]do
self[name][i]=love.graphics.newImage(list[name][i])
end
elseif type(list[name])=='string'then
self[name]=love.graphics.newImage(list[name])
else
MES.new('warn',"No IMG: "..name,5)
self[name]=null
end
return self[name]
end})
local null=love.graphics.newCanvas(1,1)
setmetatable(IMG,{__index=function(self,name)
if type(list[name])=='table'then
self[name]={}
for i=1,#list[name]do
self[name][i]=love.graphics.newImage(list[name][i])
end
elseif type(list[name])=='string'then
self[name]=love.graphics.newImage(list[name])
else
MES.new('warn',"No IMG: "..name,5)
self[name]=null
end
return self[name]
end})
function IMG.loadAll()
for k in next,list do local _=IMG[k]end
IMG.loadAll=nil
end
function IMG.loadAll()
for k in next,list do local _=IMG[k]end
IMG.loadAll=nil
end
end
return IMG

File diff suppressed because it is too large Load Diff

View File

@@ -32,86 +32,86 @@ local json = {}
local _encode
local escape_char_map = {
["\\"] = "\\",
["\""] = "\"",
["\b"] = "b",
["\f"] = "f",
["\n"] = "n",
["\r"] = "r",
["\t"] = "t"
["\\"] = "\\",
["\""] = "\"",
["\b"] = "b",
["\f"] = "f",
["\n"] = "n",
["\r"] = "r",
["\t"] = "t"
}
local escape_char_map_inv = {["/"] = "/"}
for k, v in pairs(escape_char_map) do escape_char_map_inv[v] = k end
local function escape_char(c)
return "\\" .. (escape_char_map[c] or string.format("u%04x", c:byte()))
return "\\" .. (escape_char_map[c] or string.format("u%04x", c:byte()))
end
local function encode_nil() return "null" end
local function encode_table(val, stack)
local res = {}
stack = stack or {}
local res = {}
stack = stack or {}
-- Circular reference?
if stack[val] then error("circular reference") end
-- Circular reference?
if stack[val] then error("circular reference") end
stack[val] = true
stack[val] = true
if rawget(val, 1) ~= nil or next(val) == nil then
-- Treat as array -- check keys are valid and it is not sparse
local n = 0
for k in pairs(val) do
if type(k) ~= 'number' then
error("invalid table: mixed or invalid key types")
end
n = n + 1
end
if n ~= #val then error("invalid table: sparse array") end
-- Encode
for _, v in ipairs(val) do ins(res, _encode(v, stack)) end
stack[val] = nil
return "[" .. table.concat(res, ",") .. "]"
if rawget(val, 1) ~= nil or next(val) == nil then
-- Treat as array -- check keys are valid and it is not sparse
local n = 0
for k in pairs(val) do
if type(k) ~= 'number' then
error("invalid table: mixed or invalid key types")
end
n = n + 1
end
if n ~= #val then error("invalid table: sparse array") end
-- Encode
for _, v in ipairs(val) do ins(res, _encode(v, stack)) end
stack[val] = nil
return "[" .. table.concat(res, ",") .. "]"
else
-- Treat as an object
for k, v in pairs(val) do
if type(k) ~= 'string' then
error("invalid table: mixed or invalid key types")
end
ins(res, _encode(k, stack) .. ":" .. _encode(v, stack))
end
stack[val] = nil
return "{" .. table.concat(res, ",") .. "}"
end
else
-- Treat as an object
for k, v in pairs(val) do
if type(k) ~= 'string' then
error("invalid table: mixed or invalid key types")
end
ins(res, _encode(k, stack) .. ":" .. _encode(v, stack))
end
stack[val] = nil
return "{" .. table.concat(res, ",") .. "}"
end
end
local function encode_string(val)
return '"' .. val:gsub('[%z\1-\31\\"]', escape_char) .. '"'
return '"' .. val:gsub('[%z\1-\31\\"]', escape_char) .. '"'
end
local function encode_number(val)
-- Check for NaN, -inf and inf
if val ~= val or val <= -math.huge or val >= math.huge then
error("unexpected number value '" .. tostring(val) .. "'")
end
return string.format("%.14g", val)
-- Check for NaN, -inf and inf
if val ~= val or val <= -math.huge or val >= math.huge then
error("unexpected number value '" .. tostring(val) .. "'")
end
return string.format("%.14g", val)
end
local type_func_map = {
['nil'] = encode_nil,
['table'] = encode_table,
['string'] = encode_string,
['number'] = encode_number,
['boolean'] = tostring
['nil'] = encode_nil,
['table'] = encode_table,
['string'] = encode_string,
['number'] = encode_number,
['boolean'] = tostring
}
_encode = function(val, stack)
local t = type(val)
local f = type_func_map[t]
if f then return f(val, stack) end
error("unexpected type '" .. t .. "'")
local t = type(val)
local f = type_func_map[t]
if f then return f(val, stack) end
error("unexpected type '" .. t .. "'")
end
json.encode=_encode
@@ -123,9 +123,9 @@ json.encode=_encode
local parse
local function create_set(...)
local res = {}
for i = 1, select("#", ...) do res[select(i, ...)] = true end
return res
local res = {}
for i = 1, select("#", ...) do res[select(i, ...)] = true end
return res
end
local space_chars = create_set(" ", "\t", "\r", "\n")
@@ -136,205 +136,205 @@ local literals = create_set("true", "false", "null")
local literal_map = {["true"] = true, ["false"] = false, ["null"] = nil}
local function next_char(str, idx, set, negate)
for i = idx, #str do if set[str:sub(i, i)] ~= negate then return i end end
return #str + 1
for i = idx, #str do if set[str:sub(i, i)] ~= negate then return i end end
return #str + 1
end
local function decode_error(str, idx, msg)
local line_count = 1
local col_count = 1
for i = 1, idx - 1 do
col_count = col_count + 1
if str:sub(i, i) == "\n" then
line_count = line_count + 1
col_count = 1
end
end
error(string.format("%s at line %d col %d", msg, line_count, col_count))
local line_count = 1
local col_count = 1
for i = 1, idx - 1 do
col_count = col_count + 1
if str:sub(i, i) == "\n" then
line_count = line_count + 1
col_count = 1
end
end
error(string.format("%s at line %d col %d", msg, line_count, col_count))
end
local function codepoint_to_utf8(n)
-- http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=iws-appendixa
local f = bit.rshift
if n <= 0x7f then
return char(n)
elseif n <= 0x7ff then
return char(f(n, 6) + 192, n % 64 + 128)
elseif n <= 0xffff then
return char(f(n, 12) + 224, f(n % 4096, 6) + 128, n % 64 + 128)
elseif n <= 0x10ffff then
return char(f(n, 18) + 240, f(n % 262144, 12) + 128, f(n % 4096, 6) + 128, n % 64 + 128)
end
error(string.format("invalid unicode codepoint '%x'", n))
-- http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=iws-appendixa
local f = bit.rshift
if n <= 0x7f then
return char(n)
elseif n <= 0x7ff then
return char(f(n, 6) + 192, n % 64 + 128)
elseif n <= 0xffff then
return char(f(n, 12) + 224, f(n % 4096, 6) + 128, n % 64 + 128)
elseif n <= 0x10ffff then
return char(f(n, 18) + 240, f(n % 262144, 12) + 128, f(n % 4096, 6) + 128, n % 64 + 128)
end
error(string.format("invalid unicode codepoint '%x'", n))
end
local function parse_unicode_escape(s)
local n1 = tonumber(s:sub(1, 4), 16)
local n2 = tonumber(s:sub(7, 10), 16)
-- Surrogate pair?
if n2 then
return
codepoint_to_utf8((n1 - 0xd800) * 0x400 + (n2 - 0xdc00) + 0x10000)
else
return codepoint_to_utf8(n1)
end
local n1 = tonumber(s:sub(1, 4), 16)
local n2 = tonumber(s:sub(7, 10), 16)
-- Surrogate pair?
if n2 then
return
codepoint_to_utf8((n1 - 0xd800) * 0x400 + (n2 - 0xdc00) + 0x10000)
else
return codepoint_to_utf8(n1)
end
end
local function parse_string(str, i)
local res = ""
local j = i + 1
local k = j
local res = ""
local j = i + 1
local k = j
while j <= #str do
local x = str:byte(j)
while j <= #str do
local x = str:byte(j)
if x < 32 then
decode_error(str, j, "control character in string")
if x < 32 then
decode_error(str, j, "control character in string")
elseif x == 92 then -- `\`: Escape
res = res .. str:sub(k, j - 1)
j = j + 1
local c = str:sub(j, j)
if c == "u" then
local hex = str:match("^[dD][89aAbB]%x%x\\u%x%x%x%x", j + 1) or
str:match("^%x%x%x%x", j + 1) or
decode_error(str, j - 1,
"invalid unicode escape in string")
res = res .. parse_unicode_escape(hex)
j = j + #hex
else
if not escape_chars[c] then
decode_error(str, j - 1,
"invalid escape char '" .. c .. "' in string")
end
res = res .. escape_char_map_inv[c]
end
k = j + 1
elseif x == 92 then -- `\`: Escape
res = res .. str:sub(k, j - 1)
j = j + 1
local c = str:sub(j, j)
if c == "u" then
local hex = str:match("^[dD][89aAbB]%x%x\\u%x%x%x%x", j + 1) or
str:match("^%x%x%x%x", j + 1) or
decode_error(str, j - 1,
"invalid unicode escape in string")
res = res .. parse_unicode_escape(hex)
j = j + #hex
else
if not escape_chars[c] then
decode_error(str, j - 1,
"invalid escape char '" .. c .. "' in string")
end
res = res .. escape_char_map_inv[c]
end
k = j + 1
elseif x == 34 then -- `"`: End of string
res = res .. str:sub(k, j - 1)
return res, j + 1
end
elseif x == 34 then -- `"`: End of string
res = res .. str:sub(k, j - 1)
return res, j + 1
end
j = j + 1
end
j = j + 1
end
decode_error(str, i, "expected closing quote for string")
decode_error(str, i, "expected closing quote for string")
end
local function parse_number(str, i)
local x = next_char(str, i, delim_chars)
local s = str:sub(i, x - 1)
local n = tonumber(s)
if not n then decode_error(str, i, "invalid number '" .. s .. "'") end
return n, x
local x = next_char(str, i, delim_chars)
local s = str:sub(i, x - 1)
local n = tonumber(s)
if not n then decode_error(str, i, "invalid number '" .. s .. "'") end
return n, x
end
local function parse_literal(str, i)
local x = next_char(str, i, delim_chars)
local word = str:sub(i, x - 1)
if not literals[word] then
decode_error(str, i, "invalid literal '" .. word .. "'")
end
return literal_map[word], x
local x = next_char(str, i, delim_chars)
local word = str:sub(i, x - 1)
if not literals[word] then
decode_error(str, i, "invalid literal '" .. word .. "'")
end
return literal_map[word], x
end
local function parse_array(str, i)
local res = {}
local n = 1
i = i + 1
while 1 do
local x
i = next_char(str, i, space_chars, true)
-- Empty / end of array?
if str:sub(i, i) == "]" then
i = i + 1
break
end
-- Read token
x, i = parse(str, i)
res[n] = x
n = n + 1
-- Next token
i = next_char(str, i, space_chars, true)
local chr = str:sub(i, i)
i = i + 1
if chr == "]" then break end
if chr ~= "," then decode_error(str, i, "expected ']' or ','") end
end
return res, i
local res = {}
local n = 1
i = i + 1
while 1 do
local x
i = next_char(str, i, space_chars, true)
-- Empty / end of array?
if str:sub(i, i) == "]" then
i = i + 1
break
end
-- Read token
x, i = parse(str, i)
res[n] = x
n = n + 1
-- Next token
i = next_char(str, i, space_chars, true)
local chr = str:sub(i, i)
i = i + 1
if chr == "]" then break end
if chr ~= "," then decode_error(str, i, "expected ']' or ','") end
end
return res, i
end
local function parse_object(str, i)
local res = {}
i = i + 1
while 1 do
local key, val
i = next_char(str, i, space_chars, true)
-- Empty / end of object?
if str:sub(i, i) == "}" then
i = i + 1
break
end
-- Read key
if str:sub(i, i) ~= '"' then
decode_error(str, i, "expected string for key")
end
key, i = parse(str, i)
-- Read ':' delimiter
i = next_char(str, i, space_chars, true)
if str:sub(i, i) ~= ":" then
decode_error(str, i, "expected ':' after key")
end
i = next_char(str, i + 1, space_chars, true)
-- Read value
val, i = parse(str, i)
-- Set
res[key] = val
-- Next token
i = next_char(str, i, space_chars, true)
local chr = str:sub(i, i)
i = i + 1
if chr == "}" then break end
if chr ~= "," then decode_error(str, i, "expected '}' or ','") end
end
return res, i
local res = {}
i = i + 1
while 1 do
local key, val
i = next_char(str, i, space_chars, true)
-- Empty / end of object?
if str:sub(i, i) == "}" then
i = i + 1
break
end
-- Read key
if str:sub(i, i) ~= '"' then
decode_error(str, i, "expected string for key")
end
key, i = parse(str, i)
-- Read ':' delimiter
i = next_char(str, i, space_chars, true)
if str:sub(i, i) ~= ":" then
decode_error(str, i, "expected ':' after key")
end
i = next_char(str, i + 1, space_chars, true)
-- Read value
val, i = parse(str, i)
-- Set
res[key] = val
-- Next token
i = next_char(str, i, space_chars, true)
local chr = str:sub(i, i)
i = i + 1
if chr == "}" then break end
if chr ~= "," then decode_error(str, i, "expected '}' or ','") end
end
return res, i
end
local char_func_map = {
['"'] = parse_string,
["0"] = parse_number,
["1"] = parse_number,
["2"] = parse_number,
["3"] = parse_number,
["4"] = parse_number,
["5"] = parse_number,
["6"] = parse_number,
["7"] = parse_number,
["8"] = parse_number,
["9"] = parse_number,
["-"] = parse_number,
["t"] = parse_literal,
["f"] = parse_literal,
["n"] = parse_literal,
["["] = parse_array,
["{"] = parse_object
['"'] = parse_string,
["0"] = parse_number,
["1"] = parse_number,
["2"] = parse_number,
["3"] = parse_number,
["4"] = parse_number,
["5"] = parse_number,
["6"] = parse_number,
["7"] = parse_number,
["8"] = parse_number,
["9"] = parse_number,
["-"] = parse_number,
["t"] = parse_literal,
["f"] = parse_literal,
["n"] = parse_literal,
["["] = parse_array,
["{"] = parse_object
}
function parse(str, idx)
local chr = str:sub(idx, idx)
local f = char_func_map[chr]
if f then return f(str, idx) end
decode_error(str, idx, "unexpected character '" .. chr .. "'")
local chr = str:sub(idx, idx)
local f = char_func_map[chr]
if f then return f(str, idx) end
decode_error(str, idx, "unexpected character '" .. chr .. "'")
end
function json.decode(str)
if type(str) ~= 'string' then
error("expected argument of type string, got " .. type(str))
end
local res, idx = parse(str, next_char(str, 1, space_chars, true))
idx = next_char(str, idx, space_chars, true)
if idx <= #str then decode_error(str, idx, "trailing garbage") end
return res
if type(str) ~= 'string' then
error("expected argument of type string, got " .. type(str))
end
local res, idx = parse(str, next_char(str, 1, space_chars, true))
idx = next_char(str, idx, space_chars, true)
if idx <= #str then decode_error(str, idx, "trailing garbage") end
return res
end
return json

View File

@@ -1,56 +1,56 @@
local LANG={}
function LANG.init(langList,publicText)--Attention, calling this will destory all initializing methods, create a LANG.set()!
local function _langFallback(T0,T)
for k,v in next,T0 do
if type(v)=='table'and not v.refuseCopy then--refuseCopy: just copy pointer, not contents
if not T[k]then T[k]={}end
if type(T[k])=='table'then _langFallback(v,T[k])end
elseif not T[k]then
T[k]=v
end
end
end
local tipMeta={__call=function(L)return L[math.random(#L)]end}
local function _langFallback(T0,T)
for k,v in next,T0 do
if type(v)=='table'and not v.refuseCopy then--refuseCopy: just copy pointer, not contents
if not T[k]then T[k]={}end
if type(T[k])=='table'then _langFallback(v,T[k])end
elseif not T[k]then
T[k]=v
end
end
end
local tipMeta={__call=function(L)return L[math.random(#L)]end}
for i=1,#langList do
local L=langList[i]
for i=1,#langList do
local L=langList[i]
--Set public text
for key,list in next,publicText do
L[key]=list
end
--Set public text
for key,list in next,publicText do
L[key]=list
end
--Fallback to other language, default zh
if i>1 then
_langFallback(langList[L.fallback or 1],L)
end
--Fallback to other language, default zh
if i>1 then
_langFallback(langList[L.fallback or 1],L)
end
--Metatable:__call for table:getTip
if type(rawget(L,'getTip'))=='table'then
setmetatable(L.getTip,tipMeta)
end
end
--Metatable:__call for table:getTip
if type(rawget(L,'getTip'))=='table'then
setmetatable(L.getTip,tipMeta)
end
end
LANG.init,LANG.setLangList,LANG.setPublicText=nil
LANG.init,LANG.setLangList,LANG.setPublicText=nil
function LANG.set(l)
if text~=langList[l]then
text=langList[l]
WIDGET.setLang(text.WidgetText)
for k,v in next,drawableText do
if text[k]then
v:set(text[k])
end
end
end
end
function LANG.set(l)
if text~=langList[l]then
text=langList[l]
WIDGET.setLang(text.WidgetText)
for k,v in next,drawableText do
if text[k]then
v:set(text[k])
end
end
end
end
function LANG.addScene(name)
for i=1,#langList do
if langList[i].WidgetText and not langList[i].WidgetText[name]then
langList[i].WidgetText[name]={back=langList[i].back}
end
end
end
function LANG.addScene(name)
for i=1,#langList do
if langList[i].WidgetText and not langList[i].WidgetText[name]then
langList[i].WidgetText[name]={back=langList[i].back}
end
end
end
end
return LANG

View File

@@ -10,77 +10,77 @@ local shadowMapShader=gc.newShader('Zframework/light/shadowMap.glsl')--Shader fo
local lightRenderShader=gc.newShader('Zframework/light/lightRender.glsl')--Shader for rendering blurred lights and shadows.
local Lights={}--Lightsource objects
local function move(L,x,y)
L.x,L.y=x,y
L.x,L.y=x,y
end
local function setPow(L,pow)
L.size=pow
L.size=pow
end
local function drawLight(L)
local s=L.size
local s=L.size
--Initialization
gc_setCanvas(L.blackCanvas)clear()
gc_setCanvas(L.shadowCanvas)clear()
gc_setCanvas(L.renderCanvas)clear()
lightRenderShader:send('xresolution',s)
shadowMapShader:send('yresolution',s)
--Initialization
gc_setCanvas(L.blackCanvas)clear()
gc_setCanvas(L.shadowCanvas)clear()
gc_setCanvas(L.renderCanvas)clear()
lightRenderShader:send('xresolution',s)
shadowMapShader:send('yresolution',s)
--Get up-left of light
local X=L.x-s*.5
local Y=L.y-s*.5
--Get up-left of light
local X=L.x-s*.5
local Y=L.y-s*.5
--Render solid
gc_translate(-X,-Y)
L.blackCanvas:renderTo(L.blackFn)
gc_translate(X,Y)
--Render solid
gc_translate(-X,-Y)
L.blackCanvas:renderTo(L.blackFn)
gc_translate(X,Y)
--Render shade canvas by solid
gc_setShader(shadowMapShader)
gc_setCanvas(L.shadowCanvas)
gc_draw(L.blackCanvas)
--Render shade canvas by solid
gc_setShader(shadowMapShader)
gc_setCanvas(L.shadowCanvas)
gc_draw(L.blackCanvas)
--Render light canvas by shade
gc_setShader(lightRenderShader)
gc_setCanvas(L.renderCanvas)
gc_draw(L.shadowCanvas,0,0,0,1,s)
--Render light canvas by shade
gc_setShader(lightRenderShader)
gc_setCanvas(L.renderCanvas)
gc_draw(L.shadowCanvas,0,0,0,1,s)
--Ready to final render
gc_setShader()gc_setCanvas()gc.setBlendMode('add')
--Ready to final render
gc_setShader()gc_setCanvas()gc.setBlendMode('add')
--Render to screen
gc_draw(L.renderCanvas,X,Y+s,0,1,-1)
--Render to screen
gc_draw(L.renderCanvas,X,Y+s,0,1,-1)
--Reset
gc.setBlendMode('alpha')
--Reset
gc.setBlendMode('alpha')
end
local LIGHT={}
function LIGHT.draw()
gc_setColor(1,1,1)
for i=1,#Lights do
drawLight(Lights[i])
end
gc_setColor(1,1,1)
for i=1,#Lights do
drawLight(Lights[i])
end
end
function LIGHT.clear()
for i=1,#Lights do
Lights[i].blackCanvas:release()
Lights[i].shadowCanvas:release()
Lights[i].renderCanvas:release()
Lights[i]=nil
end
for i=1,#Lights do
Lights[i].blackCanvas:release()
Lights[i].shadowCanvas:release()
Lights[i].renderCanvas:release()
Lights[i]=nil
end
end
function LIGHT.add(x,y,radius,solidFunc)
local id=#Lights+1
Lights[id]={
id=id,
x=x,y=y,size=radius,
blackCanvas=gc.newCanvas(radius,radius),--Solid canvas
shadowCanvas=gc.newCanvas(radius,1),--1D vis-depth canvas
renderCanvas=gc.newCanvas(radius,radius),--Light canvas
blackFn=solidFunc,--Solid draw function
local id=#Lights+1
Lights[id]={
id=id,
x=x,y=y,size=radius,
blackCanvas=gc.newCanvas(radius,radius),--Solid canvas
shadowCanvas=gc.newCanvas(radius,1),--1D vis-depth canvas
renderCanvas=gc.newCanvas(radius,radius),--Light canvas
blackFn=solidFunc,--Solid draw function
move=move,
setPow=setPow,
}
move=move,
setPow=setPow,
}
end
return LIGHT

View File

@@ -2,28 +2,28 @@
extern float xresolution;
// Sample from 1D vis-depth map
float samp(vec2 coord,float r,Image u_texture){
return step(r,Texel(u_texture,coord).r);
return step(r,Texel(u_texture,coord).r);
}
vec4 effect(vec4 color,Image tex,vec2 tex_coords,vec2 screen_coords){
// Cartesian to polar, y of 1D sample is always 0
vec2 norm=tex_coords.st*2.-1.;
vec2 tc=vec2((atan(norm.y,norm.x)+PI)/(2.*PI),0.);
float r=length(norm);
// Cartesian to polar, y of 1D sample is always 0
vec2 norm=tex_coords.st*2.-1.;
vec2 tc=vec2((atan(norm.y,norm.x)+PI)/(2.*PI),0.);
float r=length(norm);
// Enlarge blur parameter by distance, light scattering simulation
float blur=(1./xresolution)*smoothstep(0.3,1.,r);
// Enlarge blur parameter by distance, light scattering simulation
float blur=(1./xresolution)*smoothstep(0.3,1.,r);
// Simple Gaussian blur
float sum=// Brightness(0~1)
samp(vec2(tc.x-3.*blur,tc.y),r,tex)*0.1
+samp(vec2(tc.x-2.*blur,tc.y),r,tex)*0.13
+samp(vec2(tc.x-1.*blur,tc.y),r,tex)*0.17
// Simple Gaussian blur
float sum=// Brightness(0~1)
samp(vec2(tc.x-3.*blur,tc.y),r,tex)*0.1
+samp(vec2(tc.x-2.*blur,tc.y),r,tex)*0.13
+samp(vec2(tc.x-1.*blur,tc.y),r,tex)*0.17
+samp(tc,r,tex)*0.2// The center tex coord, which gives us hard shadows.
+samp(vec2(tc.x+1.*blur,tc.y),r,tex)*0.17
+samp(vec2(tc.x+2.*blur,tc.y),r,tex)*0.13
+samp(vec2(tc.x+3.*blur,tc.y),r,tex)*0.1;
+samp(tc,r,tex)*0.2// The center tex coord, which gives us hard shadows.
+samp(vec2(tc.x+1.*blur,tc.y),r,tex)*0.17
+samp(vec2(tc.x+2.*blur,tc.y),r,tex)*0.13
+samp(vec2(tc.x+3.*blur,tc.y),r,tex)*0.1;
// Multiply the distance to get a soft fading
return vec4(vec3(1.),sum*smoothstep(1.,0.,r));
// Multiply the distance to get a soft fading
return vec4(vec3(1.),sum*smoothstep(1.,0.,r));
}

View File

@@ -1,20 +1,20 @@
#define PI 3.14
extern float yresolution;
vec4 effect(vec4 color,Image tex,vec2 tex_coords,vec2 screen_coords){
// Iterate through the occluder map's y-axis.
for(float y=0.;y<yresolution;y++){
// Cartesian to polar
// y/yresolution=distance to light source(0~1)
vec2 norm=vec2(tex_coords.s,y/yresolution)*2.-1.;
float theta=PI*1.5+norm.x*PI;
float r=(1.+norm.y)*0.5;
// Iterate through the occluder map's y-axis.
for(float y=0.;y<yresolution;y++){
// Cartesian to polar
// y/yresolution=distance to light source(0~1)
vec2 norm=vec2(tex_coords.s,y/yresolution)*2.-1.;
float theta=PI*1.5+norm.x*PI;
float r=(1.+norm.y)*0.5;
//sample from solid
if(
Texel(tex,(
vec2(-r*sin(theta),-r*cos(theta))*0.5+0.5// Coord of solid sampling
)).a>0.1
)return vec4(vec3(y/yresolution),1.);// Collision check, alpha>0.1 means transparent
}
return vec4(1.);// Return max distance 1
//sample from solid
if(
Texel(tex,(
vec2(-r*sin(theta),-r*cos(theta))*0.5+0.5// Coord of solid sampling
)).a>0.1
)return vec4(vec3(y/yresolution),1.);// Collision check, alpha>0.1 means transparent
}
return vec4(1.);// Return max distance 1
}

View File

@@ -1,23 +1,23 @@
package.cpath=package.cpath..';'..SAVEDIR..'/lib/lib?.so;'..'?.dylib'
return function(libName)
if SYSTEM=='Android'then
local platform=(function()
local p=io.popen('uname -m')
local arch=p:read('*a'):lower()
p:close()
return
arch=='aarch64'or arch=='arm64'and'arm64-v8a'or
'armeabi-v7a'
end)()
love.filesystem.write(
'lib/libCCloader.so',
love.filesystem.read('data','libAndroid/'..platform..'/libCCloader.so')
)
end
local r1,r2,r3=pcall(require,libName)
if r1 and r2 then
return r2
else
MES.new('error',"Cannot load "..libName..": "..(r2 or r3))
end
if SYSTEM=='Android'then
local platform=(function()
local p=io.popen('uname -m')
local arch=p:read('*a'):lower()
p:close()
return
arch=='aarch64'or arch=='arm64'and'arm64-v8a'or
'armeabi-v7a'
end)()
love.filesystem.write(
'lib/libCCloader.so',
love.filesystem.read('data','libAndroid/'..platform..'/libCCloader.so')
)
end
local r1,r2,r3=pcall(require,libName)
if r1 and r2 then
return r2
else
MES.new('error',"Cannot load "..libName..": "..(r2 or r3))
end
end

View File

@@ -7,137 +7,137 @@ local max=math.max
local mesList={}
local mesIcon={
check=GC.DO{40,40,
{'setLW',10},
{'setCL',0,0,0},
{'line',4,19,15,30,36,9},
{'setLW',6},
{'setCL',.7,1,.6},
{'line',5,20,15,30,35,10},
},
info=GC.DO{40,40,
{'setCL',.2,.25,.85},
{'fCirc',20,20,15},
{'setCL',1,1,1},
{'setLW',2},
{'dCirc',20,20,15},
{'fRect',18,11,4,4},
{'fRect',18,17,4,12},
},
broadcast=GC.DO{40,40,
{'setCL',1,1,1},
{'fRect',2,4,36,26,3},
{'fPoly',2,27,2,37,14,25},
{'setCL',.5,.5,.5},
{'fRect',6,11,4,4},{'fRect',14,11,19,4},
{'fRect',6,19,4,4},{'fRect',14,19,19,4},
},
warn=GC.DO{40,40,
{'setCL',.95,.83,.4},
{'fPoly',20.5,1,0,38,40,38},
{'setCL',0,0,0},
{'dPoly',20.5,1,0,38,40,38},
{'fRect',17,10,7,18},
{'fRect',17,29,7,7},
{'setCL',1,1,1},
{'fRect',18,11,5,16},
{'fRect',18,30,5,5},
},
error=GC.DO{40,40,
{'setCL',.95,.3,.3},
{'fCirc',20,20,19},
{'setCL',0,0,0},
{'dCirc',20,20,19},
{'setLW',6},
{'line',10.2,10.2,29.8,29.8},
{'line',10.2,29.8,29.8,10.2},
{'setLW',4},
{'setCL',1,1,1},
{'line',11,11,29,29},
{'line',11,29,29,11},
},
check=GC.DO{40,40,
{'setLW',10},
{'setCL',0,0,0},
{'line',4,19,15,30,36,9},
{'setLW',6},
{'setCL',.7,1,.6},
{'line',5,20,15,30,35,10},
},
info=GC.DO{40,40,
{'setCL',.2,.25,.85},
{'fCirc',20,20,15},
{'setCL',1,1,1},
{'setLW',2},
{'dCirc',20,20,15},
{'fRect',18,11,4,4},
{'fRect',18,17,4,12},
},
broadcast=GC.DO{40,40,
{'setCL',1,1,1},
{'fRect',2,4,36,26,3},
{'fPoly',2,27,2,37,14,25},
{'setCL',.5,.5,.5},
{'fRect',6,11,4,4},{'fRect',14,11,19,4},
{'fRect',6,19,4,4},{'fRect',14,19,19,4},
},
warn=GC.DO{40,40,
{'setCL',.95,.83,.4},
{'fPoly',20.5,1,0,38,40,38},
{'setCL',0,0,0},
{'dPoly',20.5,1,0,38,40,38},
{'fRect',17,10,7,18},
{'fRect',17,29,7,7},
{'setCL',1,1,1},
{'fRect',18,11,5,16},
{'fRect',18,30,5,5},
},
error=GC.DO{40,40,
{'setCL',.95,.3,.3},
{'fCirc',20,20,19},
{'setCL',0,0,0},
{'dCirc',20,20,19},
{'setLW',6},
{'line',10.2,10.2,29.8,29.8},
{'line',10.2,29.8,29.8,10.2},
{'setLW',4},
{'setCL',1,1,1},
{'line',11,11,29,29},
{'line',11,29,29,11},
},
}
local MES={}
function MES.new(icon,str,time)
local backColor={.5,.5,.5,.7}
if type(icon)=='string'then
if icon=='check'then
backColor={.3,.6,.3,.7}
elseif icon=='broadcast'then
backColor={.3,.3,.6,.8}
elseif icon=='warn'then
backColor={.4,.4,.2,.9}
elseif icon=='error'then
backColor={.4,.2,.2,.9}
end
icon=mesIcon[icon]
end
local t=gc.newText(getFont(30),str)
local w=math.max(t:getWidth()+(icon and 45 or 5),200)+20
local h=math.max(t:getHeight(),46)+3
local L={w,h,
{'clear',backColor},
{'setCL',.7,.7,.7},
{'setLW',2},
{'dRect',1,1,w-2,h-2},
{'setCL',1,1,1},
}
if icon then
ins(L,{'draw',icon,4,4,nil,40/icon:getWidth(),40/icon:getHeight()})
end
ins(L,{'draw',t,icon and 50 or 10,2})
local backColor={.5,.5,.5,.7}
if type(icon)=='string'then
if icon=='check'then
backColor={.3,.6,.3,.7}
elseif icon=='broadcast'then
backColor={.3,.3,.6,.8}
elseif icon=='warn'then
backColor={.4,.4,.2,.9}
elseif icon=='error'then
backColor={.4,.2,.2,.9}
end
icon=mesIcon[icon]
end
local t=gc.newText(getFont(30),str)
local w=math.max(t:getWidth()+(icon and 45 or 5),200)+20
local h=math.max(t:getHeight(),46)+3
local L={w,h,
{'clear',backColor},
{'setCL',.7,.7,.7},
{'setLW',2},
{'dRect',1,1,w-2,h-2},
{'setCL',1,1,1},
}
if icon then
ins(L,{'draw',icon,4,4,nil,40/icon:getWidth(),40/icon:getHeight()})
end
ins(L,{'draw',t,icon and 50 or 10,2})
ins(mesList,{
startTime=.5,
endTime=.5,
time=time or 3,
canvas=GC.DO(L),
width=w,height=h,
scale=h>400 and 1/math.min(h/400,2.6)or 1
})
ins(mesList,{
startTime=.5,
endTime=.5,
time=time or 3,
canvas=GC.DO(L),
width=w,height=h,
scale=h>400 and 1/math.min(h/400,2.6)or 1
})
end
function MES.update(dt)
for i=#mesList,1,-1 do
local m=mesList[i]
if m.startTime>0 then
m.startTime=max(m.startTime-dt,0)
elseif m.time>0 then
m.time=max(m.time-dt,0)
elseif m.endTime>0 then
m.endTime=m.endTime-dt
else
rem(mesList,i)
end
end
for i=#mesList,1,-1 do
local m=mesList[i]
if m.startTime>0 then
m.startTime=max(m.startTime-dt,0)
elseif m.time>0 then
m.time=max(m.time-dt,0)
elseif m.endTime>0 then
m.endTime=m.endTime-dt
else
rem(mesList,i)
end
end
end
function MES.draw()
gc_push('transform')
if #mesList>0 then
gc_translate(SCR.safeX,30)
for i=1,#mesList do
local m=mesList[i]
gc_setColor(1,1,1,2*(m.endTime-m.startTime))
gc_draw(m.canvas,40-80*(m.endTime+m.startTime),0,nil,m.scale)
gc_translate(0,m.height*m.scale+4)
end
end
gc_pop()
gc_push('transform')
if #mesList>0 then
gc_translate(SCR.safeX,30)
for i=1,#mesList do
local m=mesList[i]
gc_setColor(1,1,1,2*(m.endTime-m.startTime))
gc_draw(m.canvas,40-80*(m.endTime+m.startTime),0,nil,m.scale)
gc_translate(0,m.height*m.scale+4)
end
end
gc_pop()
end
function MES.traceback()
local mes=
debug.traceback('',1)
:gsub(': in function',', in')
:gsub(':',' ')
:gsub('\t','')
MES.new('error',mes:sub(
mes:find("\n",2)+1,
mes:find("\n%[C%], in 'xpcall'")
),5)
local mes=
debug.traceback('',1)
:gsub(': in function',', in')
:gsub(':',' ')
:gsub('\t','')
MES.new('error',mes:sub(
mes:find("\n",2)+1,
mes:find("\n%[C%], in 'xpcall'")
),5)
end
return MES

View File

@@ -2,156 +2,156 @@ local clock=os.clock
local profile={}
local _labeled={} -- function labels
local _defined={} -- function definitions
local _tcalled={} -- time of last call
local _labeled={} -- function labels
local _defined={} -- function definitions
local _tcalled={} -- time of last call
local _telapsed={}-- total execution time
local _ncalls={} -- number of calls
local _ncalls={} -- number of calls
local _internal={}-- list of internal profiler functions
local getInfo=debug.getinfo
function profile.hooker(event,line,info)
info=info or getInfo(2,'fnS')
local f=info.func
if _internal[f]then return end-- ignore the profiler itself
if info.name then _labeled[f]=info.name end-- get the function name if available
-- find the line definition
if not _defined[f]then
_defined[f]=info.short_src..":"..info.linedefined
_ncalls[f]=0
_telapsed[f]=0
end
if _tcalled[f]then
local dt=clock()-_tcalled[f]
_telapsed[f]=_telapsed[f]+dt
_tcalled[f]=nil
end
if event=='tail call'then
local prev=getInfo(3,'fnS')
profile.hooker('return',line,prev)
profile.hooker('call',line,info)
elseif event=='call'then
_tcalled[f]=clock()
else
_ncalls[f]=_ncalls[f]+1
end
info=info or getInfo(2,'fnS')
local f=info.func
if _internal[f]then return end-- ignore the profiler itself
if info.name then _labeled[f]=info.name end-- get the function name if available
-- find the line definition
if not _defined[f]then
_defined[f]=info.short_src..":"..info.linedefined
_ncalls[f]=0
_telapsed[f]=0
end
if _tcalled[f]then
local dt=clock()-_tcalled[f]
_telapsed[f]=_telapsed[f]+dt
_tcalled[f]=nil
end
if event=='tail call'then
local prev=getInfo(3,'fnS')
profile.hooker('return',line,prev)
profile.hooker('call',line,info)
elseif event=='call'then
_tcalled[f]=clock()
else
_ncalls[f]=_ncalls[f]+1
end
end
--- Starts collecting data.
function profile.start()
if jit then
jit.off()
jit.flush()
end
debug.sethook(profile.hooker,'cr')
if jit then
jit.off()
jit.flush()
end
debug.sethook(profile.hooker,'cr')
end
--- Stops collecting data.
function profile.stop()
debug.sethook()
for f in next,_tcalled do
local dt=clock()-_tcalled[f]
_telapsed[f]=_telapsed[f]+dt
_tcalled[f]=nil
end
-- merge closures
local lookup={}
for f,d in next,_defined do
local id=(_labeled[f]or"?")..d
local f2=lookup[id]
if f2 then
_ncalls[f2]=_ncalls[f2]+(_ncalls[f]or 0)
_telapsed[f2]=_telapsed[f2]+(_telapsed[f]or 0)
_defined[f],_labeled[f]=nil,nil
_ncalls[f],_telapsed[f]=nil,nil
else
lookup[id]=f
end
end
collectgarbage()
debug.sethook()
for f in next,_tcalled do
local dt=clock()-_tcalled[f]
_telapsed[f]=_telapsed[f]+dt
_tcalled[f]=nil
end
-- merge closures
local lookup={}
for f,d in next,_defined do
local id=(_labeled[f]or"?")..d
local f2=lookup[id]
if f2 then
_ncalls[f2]=_ncalls[f2]+(_ncalls[f]or 0)
_telapsed[f2]=_telapsed[f2]+(_telapsed[f]or 0)
_defined[f],_labeled[f]=nil,nil
_ncalls[f],_telapsed[f]=nil,nil
else
lookup[id]=f
end
end
collectgarbage()
end
--- Resets all collected data.
function profile.reset()
for f in next,_ncalls do
_ncalls[f]=0
_telapsed[f]=0
_tcalled[f]=nil
end
collectgarbage()
for f in next,_ncalls do
_ncalls[f]=0
_telapsed[f]=0
_tcalled[f]=nil
end
collectgarbage()
end
local function _comp(a,b)
local dt=_telapsed[b]-_telapsed[a]
return dt==0 and _ncalls[b]<_ncalls[a]or dt<0
local dt=_telapsed[b]-_telapsed[a]
return dt==0 and _ncalls[b]<_ncalls[a]or dt<0
end
--- Iterates all functions that have been called since the profile was started.
function profile.query(limit)
local t={}
for f,n in next,_ncalls do
if n>0 then
t[#t+1]=f
end
end
table.sort(t,_comp)
local t={}
for f,n in next,_ncalls do
if n>0 then
t[#t+1]=f
end
end
table.sort(t,_comp)
if limit then while #t>limit do table.remove(t)end end
if limit then while #t>limit do table.remove(t)end end
for i,f in ipairs(t)do
local dt=0
if _tcalled[f]then
dt=clock()-_tcalled[f]
end
t[i]={i,_labeled[f]or"?",math.floor((_telapsed[f]+dt)*1e6)/1e6,_ncalls[f],_defined[f]}
end
return t
for i,f in ipairs(t)do
local dt=0
if _tcalled[f]then
dt=clock()-_tcalled[f]
end
t[i]={i,_labeled[f]or"?",math.floor((_telapsed[f]+dt)*1e6)/1e6,_ncalls[f],_defined[f]}
end
return t
end
local cols={3,20,8,6,32}
function profile.report(n)
local out={}
local report=profile.query(n)
for i,row in ipairs(report)do
for j=1,5 do
local s=tostring(row[j])
local l1,l2=#s,cols[j]
if l1<l2 then
s=s..(" "):rep(l2-l1)
elseif l1>l2 then
s=s:sub(l1-l2+1,l1)
end
row[j]=s
end
out[i]=table.concat(row," | ")
end
local out={}
local report=profile.query(n)
for i,row in ipairs(report)do
for j=1,5 do
local s=tostring(row[j])
local l1,l2=#s,cols[j]
if l1<l2 then
s=s..(" "):rep(l2-l1)
elseif l1>l2 then
s=s:sub(l1-l2+1,l1)
end
row[j]=s
end
out[i]=table.concat(row," | ")
end
local row=" +-----+----------------------+----------+--------+----------------------------------+ \n"
local col=" | # | Function | Time | Calls | Code | \n"
local sz=row..col..row
if #out>0 then
sz=sz.." | "..table.concat(out," | \n | ").." | \n"
end
return "\n"..sz..row
local row=" +-----+----------------------+----------+--------+----------------------------------+ \n"
local col=" | # | Function | Time | Calls | Code | \n"
local sz=row..col..row
if #out>0 then
sz=sz.." | "..table.concat(out," | \n | ").." | \n"
end
return "\n"..sz..row
end
local switch=false
function profile.switch()
switch=not switch
if not switch then
profile.stop()
love.system.setClipboardText(PROFILE.report())
PROFILE.reset()
return false
else
PROFILE.start()
return true
end
switch=not switch
if not switch then
profile.stop()
love.system.setClipboardText(PROFILE.report())
PROFILE.reset()
return false
else
PROFILE.start()
return true
end
end
-- store all internal profiler functions
for _,v in next,profile do
_internal[v]=type(v)=='function'
_internal[v]=type(v)=='function'
end
return profile

View File

@@ -4,173 +4,173 @@ local abs=math.abs
local scenes={}
local SCN={
cur='NULL',--Current scene name
swapping=false,--If Swapping
stat={
tar=false, --Swapping target
style=false,--Swapping style
changeTime=false, --Loading point
time=false, --Full swap time
draw=false, --Swap draw func
},
stack={},--Scene stack
cur='NULL', --Current scene name
swapping=false, --If Swapping
stat={
tar=false, --Swapping target
style=false, --Swapping style
changeTime=false,--Loading point
time=false, --Full swap time
draw=false, --Swap draw func
},
stack={},--Scene stack
scenes=scenes,
scenes=scenes,
--Events
update=false,
draw=false,
mouseClick=false,
touchClick=false,
mouseDown=false,
mouseMove=false,
mouseUp=false,
wheelMoved=false,
touchDown=false,
touchUp=false,
touchMove=false,
keyDown=false,
keyUp=false,
gamepadDown=false,
gamepadUp=false,
fileDropped=false,
directoryDropped=false,
resize=false,
socketRead=false,
--Events
update=false,
draw=false,
mouseClick=false,
touchClick=false,
mouseDown=false,
mouseMove=false,
mouseUp=false,
wheelMoved=false,
touchDown=false,
touchUp=false,
touchMove=false,
keyDown=false,
keyUp=false,
gamepadDown=false,
gamepadUp=false,
fileDropped=false,
directoryDropped=false,
resize=false,
socketRead=false,
}--Scene datas, returned
function SCN.add(name,scene)
scenes[name]=scene
if scene.widgetList then
setmetatable(scene.widgetList,WIDGET.indexMeta)
end
scenes[name]=scene
if scene.widgetList then
setmetatable(scene.widgetList,WIDGET.indexMeta)
end
end
function SCN.swapUpdate()
local S=SCN.stat
S.time=S.time-1
if S.time==S.changeTime then
--Scene swapped this moment
SCN.init(S.tar,SCN.cur)
end
if S.time==0 then
SCN.swapping=false
end
local S=SCN.stat
S.time=S.time-1
if S.time==S.changeTime then
--Scene swapped this moment
SCN.init(S.tar,SCN.cur)
end
if S.time==0 then
SCN.swapping=false
end
end
function SCN.init(s,org)
love.keyboard.setTextInput(false)
love.keyboard.setTextInput(false)
local S=scenes[s]
SCN.cur=s
local S=scenes[s]
SCN.cur=s
WIDGET.setScrollHeight(S.widgetScrollHeight)
WIDGET.setWidgetList(S.widgetList)
SCN.sceneInit=S.sceneInit
SCN.sceneBack=S.sceneBack
SCN.mouseDown=S.mouseDown
SCN.mouseMove=S.mouseMove
SCN.mouseUp=S.mouseUp
SCN.mouseClick=S.mouseClick
SCN.wheelMoved=S.wheelMoved
SCN.touchDown=S.touchDown
SCN.touchUp=S.touchUp
SCN.touchMove=S.touchMove
SCN.touchClick=S.touchClick
SCN.keyDown=S.keyDown
SCN.keyUp=S.keyUp
SCN.gamepadDown=S.gamepadDown
SCN.gamepadUp=S.gamepadUp
SCN.fileDropped=S.fileDropped
SCN.directoryDropped=S.directoryDropped
SCN.resize=S.resize
SCN.socketRead=S.socketRead
SCN.update=S.update
SCN.draw=S.draw
if S.sceneInit then S.sceneInit(org)end
WIDGET.setScrollHeight(S.widgetScrollHeight)
WIDGET.setWidgetList(S.widgetList)
SCN.sceneInit=S.sceneInit
SCN.sceneBack=S.sceneBack
SCN.mouseDown=S.mouseDown
SCN.mouseMove=S.mouseMove
SCN.mouseUp=S.mouseUp
SCN.mouseClick=S.mouseClick
SCN.wheelMoved=S.wheelMoved
SCN.touchDown=S.touchDown
SCN.touchUp=S.touchUp
SCN.touchMove=S.touchMove
SCN.touchClick=S.touchClick
SCN.keyDown=S.keyDown
SCN.keyUp=S.keyUp
SCN.gamepadDown=S.gamepadDown
SCN.gamepadUp=S.gamepadUp
SCN.fileDropped=S.fileDropped
SCN.directoryDropped=S.directoryDropped
SCN.resize=S.resize
SCN.socketRead=S.socketRead
SCN.update=S.update
SCN.draw=S.draw
if S.sceneInit then S.sceneInit(org)end
end
function SCN.push(tar,style)
if not SCN.swapping then
local m=#SCN.stack
SCN.stack[m+1]=tar or SCN.cur
SCN.stack[m+2]=style or'fade'
end
if not SCN.swapping then
local m=#SCN.stack
SCN.stack[m+1]=tar or SCN.cur
SCN.stack[m+2]=style or'fade'
end
end
function SCN.pop()
local s=SCN.stack
s[#s],s[#s-1]=nil
local s=SCN.stack
s[#s],s[#s-1]=nil
end
local swap={
none={duration=1,changeTime=0,draw=function()end},
flash={duration=8,changeTime=1,draw=function()gc.clear(1,1,1)end},
fade={duration=30,changeTime=15,draw=function(t)
t=t>15 and 2-t/15 or t/15
gc.setColor(0,0,0,t)
gc.rectangle('fill',0,0,SCR.w,SCR.h)
end},
fade_togame={duration=120,changeTime=20,draw=function(t)
t=t>20 and(120-t)/100 or t/20
gc.setColor(0,0,0,t)
gc.rectangle('fill',0,0,SCR.w,SCR.h)
end},
slowFade={duration=180,changeTime=90,draw=function(t)
t=t>90 and 2-t/90 or t/90
gc.setColor(0,0,0,t)
gc.rectangle('fill',0,0,SCR.w,SCR.h)
end},
swipeL={duration=30,changeTime=15,draw=function(t)
t=t/30
gc.setColor(.1,.1,.1,1-abs(t-.5))
t=t*t*(3-2*t)*2-1
gc.rectangle('fill',t*SCR.w,0,SCR.w,SCR.h)
end},
swipeR={duration=30,changeTime=15,draw=function(t)
t=t/30
gc.setColor(.1,.1,.1,1-abs(t-.5))
t=t*t*(2*t-3)*2+1
gc.rectangle('fill',t*SCR.w,0,SCR.w,SCR.h)
end},
swipeD={duration=30,changeTime=15,draw=function(t)
t=t/30
gc.setColor(.1,.1,.1,1-abs(t-.5))
t=t*t*(2*t-3)*2+1
gc.rectangle('fill',0,t*SCR.h,SCR.w,SCR.h)
end},
none={duration=1,changeTime=0,draw=function()end},
flash={duration=8,changeTime=1,draw=function()gc.clear(1,1,1)end},
fade={duration=30,changeTime=15,draw=function(t)
t=t>15 and 2-t/15 or t/15
gc.setColor(0,0,0,t)
gc.rectangle('fill',0,0,SCR.w,SCR.h)
end},
fade_togame={duration=120,changeTime=20,draw=function(t)
t=t>20 and(120-t)/100 or t/20
gc.setColor(0,0,0,t)
gc.rectangle('fill',0,0,SCR.w,SCR.h)
end},
slowFade={duration=180,changeTime=90,draw=function(t)
t=t>90 and 2-t/90 or t/90
gc.setColor(0,0,0,t)
gc.rectangle('fill',0,0,SCR.w,SCR.h)
end},
swipeL={duration=30,changeTime=15,draw=function(t)
t=t/30
gc.setColor(.1,.1,.1,1-abs(t-.5))
t=t*t*(3-2*t)*2-1
gc.rectangle('fill',t*SCR.w,0,SCR.w,SCR.h)
end},
swipeR={duration=30,changeTime=15,draw=function(t)
t=t/30
gc.setColor(.1,.1,.1,1-abs(t-.5))
t=t*t*(2*t-3)*2+1
gc.rectangle('fill',t*SCR.w,0,SCR.w,SCR.h)
end},
swipeD={duration=30,changeTime=15,draw=function(t)
t=t/30
gc.setColor(.1,.1,.1,1-abs(t-.5))
t=t*t*(2*t-3)*2+1
gc.rectangle('fill',0,t*SCR.h,SCR.w,SCR.h)
end},
}--Scene swapping animations
function SCN.swapTo(tar,style)--Parallel scene swapping, cannot back
if scenes[tar]then
if not SCN.swapping and tar~=SCN.cur then
if not style then style='fade'end
SCN.swapping=true
local S=SCN.stat
S.tar,S.style=tar,style
S.time=swap[style].duration
S.changeTime=swap[style].changeTime
S.draw=swap[style].draw
end
else
MES.new('warn',"No Scene: "..tar)
end
if scenes[tar]then
if not SCN.swapping and tar~=SCN.cur then
if not style then style='fade'end
SCN.swapping=true
local S=SCN.stat
S.tar,S.style=tar,style
S.time=swap[style].duration
S.changeTime=swap[style].changeTime
S.draw=swap[style].draw
end
else
MES.new('warn',"No Scene: "..tar)
end
end
function SCN.go(tar,style)--Normal scene swapping, can back
if scenes[tar]then
SCN.push()
SCN.swapTo(tar,style)
else
MES.new('warn',"No Scene: "..tar)
end
if scenes[tar]then
SCN.push()
SCN.swapTo(tar,style)
else
MES.new('warn',"No Scene: "..tar)
end
end
function SCN.back()
if SCN.swapping then return end
if SCN.swapping then return end
--Leave scene
if SCN.sceneBack then SCN.sceneBack()end
--Leave scene
if SCN.sceneBack then SCN.sceneBack()end
--Poll&Back to previous Scene
local m=#SCN.stack
if m>0 then
SCN.swapTo(SCN.stack[m-1],SCN.stack[m])
SCN.stack[m],SCN.stack[m-1]=nil
end
--Poll&Back to previous Scene
local m=#SCN.stack
if m>0 then
SCN.swapTo(SCN.stack[m-1],SCN.stack[m])
SCN.stack[m],SCN.stack[m-1]=nil
end
end
return SCN

View File

@@ -1,73 +1,73 @@
local SCR={
w0=1280,h0=720, --Default Screen Size
x=0,y=0, --Up-left Coord on screen
cx=0,cy=0, --Center Coord on screen (Center X/Y)
ex=0,ey=0, --Down-right Coord on screen (End X/Y)
w=0,h=0, --Fullscreen w/h for graphic functions
W=0,H=0, --Fullscreen w/h for shader
safeX=0,safeY=0,--Safe area
safeW=0,safeH=0,--Safe area
rad=0, --Radius
k=1, --Scale size
dpi=1, --DPI from gc.getDPIScale()
w0=1280,h0=720, --Default Screen Size
x=0,y=0, --Up-left Coord on screen
cx=0,cy=0, --Center Coord on screen (Center X/Y)
ex=0,ey=0, --Down-right Coord on screen (End X/Y)
w=0,h=0, --Fullscreen w/h for graphic functions
W=0,H=0, --Fullscreen w/h for shader
safeX=0,safeY=0,--Safe area
safeW=0,safeH=0,--Safe area
rad=0, --Radius
k=1, --Scale size
dpi=1, --DPI from gc.getDPIScale()
--Screen transformation objects
origin=love.math.newTransform(),
xOy=love.math.newTransform(),
xOy_m=love.math.newTransform(),
xOy_ul=love.math.newTransform(),
xOy_u=love.math.newTransform(),
xOy_ur=love.math.newTransform(),
xOy_l=love.math.newTransform(),
xOy_r=love.math.newTransform(),
xOy_dl=love.math.newTransform(),
xOy_d=love.math.newTransform(),
xOy_dr=love.math.newTransform(),
--Screen transformation objects
origin=love.math.newTransform(),
xOy=love.math.newTransform(),
xOy_m=love.math.newTransform(),
xOy_ul=love.math.newTransform(),
xOy_u=love.math.newTransform(),
xOy_ur=love.math.newTransform(),
xOy_l=love.math.newTransform(),
xOy_r=love.math.newTransform(),
xOy_dl=love.math.newTransform(),
xOy_d=love.math.newTransform(),
xOy_dr=love.math.newTransform(),
}
function SCR.setSize(w,h)
SCR.w0,SCR.h0=w,h
SCR.w0,SCR.h0=w,h
end
function SCR.resize(w,h)
SCR.w,SCR.h,SCR.dpi=w,h,love.graphics.getDPIScale()
SCR.W,SCR.H=SCR.w*SCR.dpi,SCR.h*SCR.dpi
SCR.r=h/w
SCR.rad=(w^2+h^2)^.5
SCR.w,SCR.h,SCR.dpi=w,h,love.graphics.getDPIScale()
SCR.W,SCR.H=SCR.w*SCR.dpi,SCR.h*SCR.dpi
SCR.r=h/w
SCR.rad=(w^2+h^2)^.5
SCR.x,SCR.y=0,0
if SCR.r>=SCR.h0/SCR.w0 then
SCR.k=w/SCR.w0
SCR.y=(h-SCR.h0*SCR.k)/2
else
SCR.k=h/SCR.h0
SCR.x=(w-SCR.w0*SCR.k)/2
end
SCR.cx,SCR.cy=SCR.w/2,SCR.h/2
SCR.ex,SCR.ey=SCR.w-SCR.x,SCR.h-SCR.y
SCR.safeX,SCR.safeY,SCR.safeW,SCR.safeH=love.window.getSafeArea()
SCR.x,SCR.y=0,0
if SCR.r>=SCR.h0/SCR.w0 then
SCR.k=w/SCR.w0
SCR.y=(h-SCR.h0*SCR.k)/2
else
SCR.k=h/SCR.h0
SCR.x=(w-SCR.w0*SCR.k)/2
end
SCR.cx,SCR.cy=SCR.w/2,SCR.h/2
SCR.ex,SCR.ey=SCR.w-SCR.x,SCR.h-SCR.y
SCR.safeX,SCR.safeY,SCR.safeW,SCR.safeH=love.window.getSafeArea()
SCR.origin:setTransformation(0,0)
SCR.xOy:setTransformation(SCR.x,SCR.y,0,SCR.k)
SCR.xOy_m:setTransformation(w/2,h/2,0,SCR.k)
SCR.xOy_ul:setTransformation(0,0,0,SCR.k)
SCR.xOy_u:setTransformation(w/2,0,0,SCR.k)
SCR.xOy_ur:setTransformation(w,0,0,SCR.k)
SCR.xOy_l:setTransformation(0,h/2,0,SCR.k)
SCR.xOy_r:setTransformation(w,h/2,0,SCR.k)
SCR.xOy_dl:setTransformation(0,h,0,SCR.k)
SCR.xOy_d:setTransformation(w/2,h,0,SCR.k)
SCR.xOy_dr:setTransformation(w,h,0,SCR.k)
SCR.origin:setTransformation(0,0)
SCR.xOy:setTransformation(SCR.x,SCR.y,0,SCR.k)
SCR.xOy_m:setTransformation(w/2,h/2,0,SCR.k)
SCR.xOy_ul:setTransformation(0,0,0,SCR.k)
SCR.xOy_u:setTransformation(w/2,0,0,SCR.k)
SCR.xOy_ur:setTransformation(w,0,0,SCR.k)
SCR.xOy_l:setTransformation(0,h/2,0,SCR.k)
SCR.xOy_r:setTransformation(w,h/2,0,SCR.k)
SCR.xOy_dl:setTransformation(0,h,0,SCR.k)
SCR.xOy_d:setTransformation(w/2,h,0,SCR.k)
SCR.xOy_dr:setTransformation(w,h,0,SCR.k)
end
function SCR.info()
return{
("w0,h0 : %d, %d"):format(SCR.w0,SCR.h0),
("x,y : %d, %d"):format(SCR.x,SCR.y),
("cx,cy : %d, %d"):format(SCR.cx,SCR.cy),
("ex,ey : %d, %d"):format(SCR.ex,SCR.ey),
("w,h : %d, %d"):format(SCR.w,SCR.h),
("W,H : %d, %d"):format(SCR.W,SCR.H),
("safeX,safeY : %d, %d"):format(SCR.safeX,SCR.safeY),
("safeW,safeH : %d, %d"):format(SCR.safeW,SCR.safeH),
("k,dpi,rad : %.2f, %d, %.2f"):format(SCR.k,SCR.dpi,SCR.rad),
}
return{
("w0,h0 : %d, %d"):format(SCR.w0,SCR.h0),
("x,y : %d, %d"):format(SCR.x,SCR.y),
("cx,cy : %d, %d"):format(SCR.cx,SCR.cy),
("ex,ey : %d, %d"):format(SCR.ex,SCR.ey),
("w,h : %d, %d"):format(SCR.w,SCR.h),
("W,H : %d, %d"):format(SCR.W,SCR.H),
("safeX,safeY : %d, %d"):format(SCR.safeX,SCR.safeY),
("safeW,safeH : %d, %d"):format(SCR.safeW,SCR.safeH),
("k,dpi,rad : %.2f, %d, %.2f"):format(SCR.k,SCR.dpi,SCR.rad),
}
end
return SCR

View File

@@ -3,36 +3,36 @@ local newFont=gc.setNewFont
local setNewFont=gc.setFont
local fontCache,currentFontSize={}
if love.filesystem.getInfo('font.ttf')then
local fontData=love.filesystem.newFile('font.ttf')
function setFont(s)
if s~=currentFontSize then
if not fontCache[s]then
fontCache[s]=newFont(fontData,s)
end
setNewFont(fontCache[s])
currentFontSize=s
end
end
function getFont(s)
if not fontCache[s]then
fontCache[s]=newFont(fontData,s)
end
return fontCache[s]
end
local fontData=love.filesystem.newFile('font.ttf')
function setFont(s)
if s~=currentFontSize then
if not fontCache[s]then
fontCache[s]=newFont(fontData,s)
end
setNewFont(fontCache[s])
currentFontSize=s
end
end
function getFont(s)
if not fontCache[s]then
fontCache[s]=newFont(fontData,s)
end
return fontCache[s]
end
else
function setFont(s)
if s~=currentFontSize then
if not fontCache[s]then
fontCache[s]=newFont(s)
end
setNewFont(fontCache[s])
currentFontSize=s
end
end
function getFont(s)
if not fontCache[s]then
fontCache[s]=newFont(s)
end
return fontCache[s]
end
function setFont(s)
if s~=currentFontSize then
if not fontCache[s]then
fontCache[s]=newFont(s)
end
setNewFont(fontCache[s])
currentFontSize=s
end
end
function getFont(s)
if not fontCache[s]then
fontCache[s]=newFont(s)
end
return fontCache[s]
end
end

View File

@@ -1,87 +1,87 @@
local SFX={
getCount=function()return 0 end,
loadAll=function()error("Cannot load before init!")end,
fieldPlay=NULL,
play=NULL,
fplay=NULL,
reset=NULL,
getCount=function()return 0 end,
loadAll=function()error("Cannot load before init!")end,
fieldPlay=NULL,
play=NULL,
fplay=NULL,
reset=NULL,
}
function SFX.init(list)
SFX.init=nil
local rem=table.remove
local Sources={}
SFX.init=nil
local rem=table.remove
local Sources={}
local count=#list function SFX.getCount()return count end
function SFX.loadAll()
for i=1,count do
local N='media/SFX/'..list[i]..'.ogg'
if love.filesystem.getInfo(N)then
Sources[list[i]]={love.audio.newSource(N,'static')}
else
MES.new('warn',"No SFX file: "..N,.1)
end
end
local count=#list function SFX.getCount()return count end
function SFX.loadAll()
for i=1,count do
local N='media/SFX/'..list[i]..'.ogg'
if love.filesystem.getInfo(N)then
Sources[list[i]]={love.audio.newSource(N,'static')}
else
MES.new('warn',"No SFX file: "..N,.1)
end
end
function SFX.play(s,vol,pos)
if SETTING.sfx==0 or vol==0 then return end
local S=Sources[s]--Source list
if not S then return end
local n=1
while S[n]:isPlaying()do
n=n+1
if not S[n]then
S[n]=S[1]:clone()
S[n]:seek(0)
break
end
end
S=S[n]--AU_SRC
if S:getChannelCount()==1 then
if pos then
pos=pos*SETTING.stereo
S:setPosition(pos,1-pos^2,0)
else
S:setPosition(0,0,0)
end
end
S:setVolume(((vol or 1)*SETTING.sfx)^1.626)
S:play()
end
function SFX.fplay(s,vol,pos)
local S=Sources[s]--Source list
if not S then return end
local n=1
while S[n]:isPlaying()do
n=n+1
if not S[n]then
S[n]=S[1]:clone()
S[n]:seek(0)
break
end
end
S=S[n]--AU_SRC
if S:getChannelCount()==1 then
if pos then
pos=pos*SETTING.stereo
S:setPosition(pos,1-pos^2,0)
else
S:setPosition(0,0,0)
end
end
S:setVolume(vol^1.626)
S:play()
end
function SFX.reset()
for _,L in next,Sources do
if type(L)=='table'then
for i=#L,1,-1 do
if not L[i]:isPlaying()then
rem(L,i)
end
end
end
end
end
end
function SFX.play(s,vol,pos)
if SETTING.sfx==0 or vol==0 then return end
local S=Sources[s]--Source list
if not S then return end
local n=1
while S[n]:isPlaying()do
n=n+1
if not S[n]then
S[n]=S[1]:clone()
S[n]:seek(0)
break
end
end
S=S[n]--AU_SRC
if S:getChannelCount()==1 then
if pos then
pos=pos*SETTING.stereo
S:setPosition(pos,1-pos^2,0)
else
S:setPosition(0,0,0)
end
end
S:setVolume(((vol or 1)*SETTING.sfx)^1.626)
S:play()
end
function SFX.fplay(s,vol,pos)
local S=Sources[s]--Source list
if not S then return end
local n=1
while S[n]:isPlaying()do
n=n+1
if not S[n]then
S[n]=S[1]:clone()
S[n]:seek(0)
break
end
end
S=S[n]--AU_SRC
if S:getChannelCount()==1 then
if pos then
pos=pos*SETTING.stereo
S:setPosition(pos,1-pos^2,0)
else
S:setPosition(0,0,0)
end
end
S:setVolume(vol^1.626)
S:play()
end
function SFX.reset()
for _,L in next,Sources do
if type(L)=='table'then
for i=#L,1,-1 do
if not L[i]:isPlaying()then
rem(L,i)
end
end
end
end
end
end
end
return SFX

View File

@@ -5,144 +5,144 @@ local find,sub,upper=string.find,string.sub,string.upper
local char,byte=string.char,string.byte
do--function STRING.shiftChar(c)
local shiftMap={
['1']='!',['2']='@',['3']='#',['4']='$',['5']='%',
['6']='^',['7']='&',['8']='*',['9']='(',['0']=')',
['`']='~',['-']='_',['=']='+',
['[']='{',[']']='}',['\\']='|',
[';']=':',['\'']='"',
[',']='<',['.']='>',['/']='?',
}
function STRING.shiftChar(c)
return shiftMap[c]or upper(c)
end
local shiftMap={
['1']='!',['2']='@',['3']='#',['4']='$',['5']='%',
['6']='^',['7']='&',['8']='*',['9']='(',['0']=')',
['`']='~',['-']='_',['=']='+',
['[']='{',[']']='}',['\\']='|',
[';']=':',['\'']='"',
[',']='<',['.']='>',['/']='?',
}
function STRING.shiftChar(c)
return shiftMap[c]or upper(c)
end
end
function STRING.trim(s)
if not s:find("%S")then return""end
s=s:sub((s:find("%S"))):reverse()
return s:sub((s:find("%S"))):reverse()
if not s:find("%S")then return""end
s=s:sub((s:find("%S"))):reverse()
return s:sub((s:find("%S"))):reverse()
end
function STRING.split(s,sep,regex)
local L={}
local p1,p2=1--start,target
if regex then
while p1<=#s do
p2=find(s,sep,p1)or #s+1
L[#L+1]=sub(s,p1,p2-1)
p1=p2+#sep
end
else
while p1<=#s do
p2=find(s,sep,p1,true)or #s+1
L[#L+1]=sub(s,p1,p2-1)
p1=p2+#sep
end
end
return L
local L={}
local p1,p2=1--start,target
if regex then
while p1<=#s do
p2=find(s,sep,p1)or #s+1
L[#L+1]=sub(s,p1,p2-1)
p1=p2+#sep
end
else
while p1<=#s do
p2=find(s,sep,p1,true)or #s+1
L[#L+1]=sub(s,p1,p2-1)
p1=p2+#sep
end
end
return L
end
function STRING.simpEmailCheck(e)
e=STRING.split(e,"@")
if #e~=2 then return false end
if e[1]:sub(-1)=="."or e[2]:sub(-1)=="."then return false end
local e1,e2=STRING.split(e[1],"."),STRING.split(e[2],".")
if #e1*#e2==0 then return false end
for _,v in next,e1 do if #v==0 then return false end end
for _,v in next,e2 do if #v==0 then return false end end
return true
e=STRING.split(e,"@")
if #e~=2 then return false end
if e[1]:sub(-1)=="."or e[2]:sub(-1)=="."then return false end
local e1,e2=STRING.split(e[1],"."),STRING.split(e[2],".")
if #e1*#e2==0 then return false end
for _,v in next,e1 do if #v==0 then return false end end
for _,v in next,e2 do if #v==0 then return false end end
return true
end
function STRING.time(s)
if s<60 then
return format("%.3f\"",s)
elseif s<3600 then
return format("%d'%05.2f\"",int(s/60),s%60)
else
local h=int(s/3600)
return format("%d:%.2d'%05.2f\"",h,int(s/60%60),s%60)
end
if s<60 then
return format("%.3f\"",s)
elseif s<3600 then
return format("%d'%05.2f\"",int(s/60),s%60)
else
local h=int(s/3600)
return format("%d:%.2d'%05.2f\"",h,int(s/60%60),s%60)
end
end
do--function STRING.urlEncode(s)
local rshift=bit.rshift
local b16={[0]='0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'}
function STRING.urlEncode(s)
local out=""
for i=1,#s do
if s:sub(i,i):match("[a-zA-Z0-9]")then
out=out..s:sub(i,i)
else
local b=s:byte(i)
out=out.."%"..b16[rshift(b,4)]..b16[b%16]
end
end
return out
end
local rshift=bit.rshift
local b16={[0]='0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'}
function STRING.urlEncode(s)
local out=""
for i=1,#s do
if s:sub(i,i):match("[a-zA-Z0-9]")then
out=out..s:sub(i,i)
else
local b=s:byte(i)
out=out.."%"..b16[rshift(b,4)]..b16[b%16]
end
end
return out
end
end
function STRING.vcsEncrypt(text,key)
local keyLen=#key
local result=""
local buffer=""
for i=0,#text-1 do
buffer=buffer..char((byte(text,i+1)-32+byte(key,i%keyLen+1))%95+32)
if #buffer==26 then
result=result..buffer
buffer=""
end
end
return result..buffer
local keyLen=#key
local result=""
local buffer=""
for i=0,#text-1 do
buffer=buffer..char((byte(text,i+1)-32+byte(key,i%keyLen+1))%95+32)
if #buffer==26 then
result=result..buffer
buffer=""
end
end
return result..buffer
end
function STRING.vcsDecrypt(text,key)
local keyLen=#key
local result=""
local buffer=""
for i=0,#text-1 do
buffer=buffer..char((byte(text,i+1)-32-byte(key,i%keyLen+1))%95+32)
if #buffer==26 then
result=result..buffer
buffer=""
end
end
return result..buffer
local keyLen=#key
local result=""
local buffer=""
for i=0,#text-1 do
buffer=buffer..char((byte(text,i+1)-32-byte(key,i%keyLen+1))%95+32)
if #buffer==26 then
result=result..buffer
buffer=""
end
end
return result..buffer
end
function STRING.readLine(str)
local p=str:find("\n")
if p then
return str:sub(1,p-1),str:sub(p+1)
else
return str,""
end
local p=str:find("\n")
if p then
return str:sub(1,p-1),str:sub(p+1)
else
return str,""
end
end
function STRING.packBin(s)
return data.encode('string','base64',data.compress('string','zlib',s))
return data.encode('string','base64',data.compress('string','zlib',s))
end
function STRING.unpackBin(str)
local res
res,str=pcall(data.decode,'string','base64',str)
if not res then return end
res,str=pcall(data.decompress,'string','zlib',str)
if res then return str end
local res
res,str=pcall(data.decode,'string','base64',str)
if not res then return end
res,str=pcall(data.decompress,'string','zlib',str)
if res then return str end
end
function STRING.packText(s)
return data.encode('string','base64',data.compress('string','gzip',s))
return data.encode('string','base64',data.compress('string','gzip',s))
end
function STRING.unpackText(str)
local res
res,str=pcall(data.decode,'string','base64',str)
if not res then return end
res,str=pcall(data.decompress,'string','gzip',str)
if res then return str end
local res
res,str=pcall(data.decode,'string','base64',str)
if not res then return end
res,str=pcall(data.decompress,'string','gzip',str)
if res then return str end
end
function STRING.packTable(t)
return STRING.packText(JSON.encode(t))
return STRING.packText(JSON.encode(t))
end
function STRING.unpackTable(t)
return JSON.decode(STRING.unpackText(t))
return JSON.decode(STRING.unpackText(t))
end
return STRING

View File

@@ -10,23 +10,23 @@ local ins,rem=table.insert,table.remove
local fx={}
local function _normUpdate(S,dt)
S.t=S.t+dt*S.rate
return S.t>1
S.t=S.t+dt*S.rate
return S.t>1
end
local FXupdate={}
function FXupdate.badge(S,dt)
S.t=S.t+dt
if S.t<.2 then
S.x,S.y=S.x1-14,S.y1-14
elseif S.t<.8 then
local t=((S.t-.2)*1.6667)
t=(3-2*t)*t*t
S.x,S.y=S.x1*(1-t)+S.x2*t-14,S.y1*(1-t)+S.y2*t-14
else
S.x,S.y=S.x2-14,S.y2-14
end
return S.t>=1
S.t=S.t+dt
if S.t<.2 then
S.x,S.y=S.x1-14,S.y1-14
elseif S.t<.8 then
local t=((S.t-.2)*1.6667)
t=(3-2*t)*t*t
S.x,S.y=S.x1*(1-t)+S.x2*t-14,S.y1*(1-t)+S.y2*t-14
else
S.x,S.y=S.x2-14,S.y2-14
end
return S.t>=1
end
FXupdate.attack=_normUpdate
FXupdate.tap=_normUpdate
@@ -34,172 +34,172 @@ FXupdate.ripple=_normUpdate
FXupdate.rectRipple=_normUpdate
FXupdate.shade=_normUpdate
function FXupdate.cell(S,dt)
if S.vx then
S.x=S.x+S.vx*S.rate
S.y=S.y+S.vy*S.rate
if S.ax then
S.vx=S.vx+S.ax*S.rate
S.vy=S.vy+S.ay*S.rate
end
end
S.t=S.t+dt*S.rate
return S.t>1
if S.vx then
S.x=S.x+S.vx*S.rate
S.y=S.y+S.vy*S.rate
if S.ax then
S.vx=S.vx+S.ax*S.rate
S.vy=S.vy+S.ay*S.rate
end
end
S.t=S.t+dt*S.rate
return S.t>1
end
FXupdate.line=_normUpdate
local FXdraw={}
function FXdraw.badge(S)
gc_setColor(1,1,1,S.t<.2 and S.t*.6 or S.t<.8 and 1 or(1-S.t)*.6)
gc_draw(IMG.badgeIcon,S.x,S.y)
gc_setColor(1,1,1,S.t<.2 and S.t*.6 or S.t<.8 and 1 or(1-S.t)*.6)
gc_draw(IMG.badgeIcon,S.x,S.y)
end
function FXdraw.attack(S)
gc_setColor(S.r*2,S.g*2,S.b*2,S.a*min(4-S.t*4,1))
gc_setColor(S.r*2,S.g*2,S.b*2,S.a*min(4-S.t*4,1))
gc_setLineWidth(S.wid)
local t1,t2=max(5*S.t-4,0),min(S.t*4,1)
gc_line(
S.x1*(1-t1)+S.x2*t1,
S.y1*(1-t1)+S.y2*t1,
S.x1*(1-t2)+S.x2*t2,
S.y1*(1-t2)+S.y2*t2
)
gc_setLineWidth(S.wid)
local t1,t2=max(5*S.t-4,0),min(S.t*4,1)
gc_line(
S.x1*(1-t1)+S.x2*t1,
S.y1*(1-t1)+S.y2*t1,
S.x1*(1-t2)+S.x2*t2,
S.y1*(1-t2)+S.y2*t2
)
gc_setLineWidth(S.wid*.6)
t1,t2=max(4*S.t-3,0),min(S.t*5,1)
gc_line(
S.x1*(1-t1)+S.x2*t1,
S.y1*(1-t1)+S.y2*t1,
S.x1*(1-t2)+S.x2*t2,
S.y1*(1-t2)+S.y2*t2
)
gc_setLineWidth(S.wid*.6)
t1,t2=max(4*S.t-3,0),min(S.t*5,1)
gc_line(
S.x1*(1-t1)+S.x2*t1,
S.y1*(1-t1)+S.y2*t1,
S.x1*(1-t2)+S.x2*t2,
S.y1*(1-t2)+S.y2*t2
)
end
function FXdraw.tap(S)
local t=S.t
gc_setColor(1,1,1,(1-t)*.4)
gc_circle('fill',S.x,S.y,30*(1-t)^.5)
local t=S.t
gc_setColor(1,1,1,(1-t)*.4)
gc_circle('fill',S.x,S.y,30*(1-t)^.5)
end
function FXdraw.ripple(S)
local t=S.t
gc_setLineWidth(2)
gc_setColor(1,1,1,1-t)
gc_circle('line',S.x,S.y,t*(2-t)*S.r)
local t=S.t
gc_setLineWidth(2)
gc_setColor(1,1,1,1-t)
gc_circle('line',S.x,S.y,t*(2-t)*S.r)
end
function FXdraw.rectRipple(S)
gc_setLineWidth(6)
gc_setColor(1,1,1,1-S.t)
local r=(10*S.t)^1.2
gc_rectangle('line',S.x-r,S.y-r,S.w+2*r,S.h+2*r)
gc_setLineWidth(6)
gc_setColor(1,1,1,1-S.t)
local r=(10*S.t)^1.2
gc_rectangle('line',S.x-r,S.y-r,S.w+2*r,S.h+2*r)
end
function FXdraw.shade(S)
gc_setColor(S.r,S.g,S.b,1-S.t)
gc_rectangle('fill',S.x,S.y,S.w,S.h,2)
gc_setColor(S.r,S.g,S.b,1-S.t)
gc_rectangle('fill',S.x,S.y,S.w,S.h,2)
end
function FXdraw.cell(S)
gc_setColor(1,1,1,1-S.t)
gc_draw(S.image,S.x,S.y,nil,S.size,nil,S.cx,S.cy)
gc_setColor(1,1,1,1-S.t)
gc_draw(S.image,S.x,S.y,nil,S.size,nil,S.cx,S.cy)
end
function FXdraw.line(S)
gc_setColor(1,1,1,S.a*(1-S.t))
gc_line(S.x1,S.y1,S.x2,S.y2)
gc_setColor(1,1,1,S.a*(1-S.t))
gc_line(S.x1,S.y1,S.x2,S.y2)
end
local SYSFX={}
function SYSFX.update(dt)
for i=#fx,1,-1 do
if fx[i]:update(dt)then
rem(fx,i)
end
end
for i=#fx,1,-1 do
if fx[i]:update(dt)then
rem(fx,i)
end
end
end
function SYSFX.draw()
for i=1,#fx do
fx[i]:draw()
end
for i=1,#fx do
fx[i]:draw()
end
end
function SYSFX.newBadge(x1,y1,x2,y2)
ins(fx,{
update=FXupdate.badge,
draw=FXdraw.badge,
t=0,
x=x1,y=y1,
x1=x1,y1=y1,
x2=x2,y2=y2,
})
ins(fx,{
update=FXupdate.badge,
draw=FXdraw.badge,
t=0,
x=x1,y=y1,
x1=x1,y1=y1,
x2=x2,y2=y2,
})
end
function SYSFX.newAttack(rate,x1,y1,x2,y2,wid,r,g,b,a)
ins(fx,{
update=FXupdate.attack,
draw=FXdraw.attack,
t=0,
rate=rate,
x1=x1,y1=y1,--Start pos
x2=x2,y2=y2,--End pos
wid=wid,--Line width
r=r,g=g,b=b,a=a,
})
ins(fx,{
update=FXupdate.attack,
draw=FXdraw.attack,
t=0,
rate=rate,
x1=x1,y1=y1,--Start pos
x2=x2,y2=y2,--End pos
wid=wid,--Line width
r=r,g=g,b=b,a=a,
})
end
function SYSFX.newTap(rate,x,y)
local T=
{
update=FXupdate.tap,
draw=FXdraw.tap,
t=0,
rate=rate,
x=x,y=y,
}
ins(fx,T)
local T=
{
update=FXupdate.tap,
draw=FXdraw.tap,
t=0,
rate=rate,
x=x,y=y,
}
ins(fx,T)
end
function SYSFX.newRipple(rate,x,y,r)
ins(fx,{
update=FXupdate.ripple,
draw=FXdraw.ripple,
t=0,
rate=rate,
x=x,y=y,r=r,
})
ins(fx,{
update=FXupdate.ripple,
draw=FXdraw.ripple,
t=0,
rate=rate,
x=x,y=y,r=r,
})
end
function SYSFX.newRectRipple(rate,x,y,w,h)
ins(fx,{
update=FXupdate.rectRipple,
draw=FXdraw.rectRipple,
t=0,
rate=rate,
x=x,y=y,w=w,h=h,
})
ins(fx,{
update=FXupdate.rectRipple,
draw=FXdraw.rectRipple,
t=0,
rate=rate,
x=x,y=y,w=w,h=h,
})
end
function SYSFX.newShade(rate,x,y,w,h,r,g,b)
ins(fx,{
update=FXupdate.shade,
draw=FXdraw.shade,
t=0,
rate=rate,
x=x,y=y,w=w,h=h,
r=r or 1,g=g or 1,b=b or 1,
})
ins(fx,{
update=FXupdate.shade,
draw=FXdraw.shade,
t=0,
rate=rate,
x=x,y=y,w=w,h=h,
r=r or 1,g=g or 1,b=b or 1,
})
end
function SYSFX.newCell(rate,image,size,x,y,vx,vy,ax,ay)
ins(fx,{
update=FXupdate.cell,
draw=FXdraw.cell,
t=0,
rate=rate*(.9+rnd()*.2),
image=image,size=size,
cx=image:getWidth()*.5,cy=image:getHeight()*.5,
x=x,y=y,
vx=vx,vy=vy,
ax=ax,ay=ay,
})
ins(fx,{
update=FXupdate.cell,
draw=FXdraw.cell,
t=0,
rate=rate*(.9+rnd()*.2),
image=image,size=size,
cx=image:getWidth()*.5,cy=image:getHeight()*.5,
x=x,y=y,
vx=vx,vy=vy,
ax=ax,ay=ay,
})
end
function SYSFX.newLine(rate,x1,y1,x2,y2,r,g,b,a)
ins(fx,{
update=FXupdate.line,
draw=FXdraw.line,
t=0,
rate=rate,
x1=x1 or 0,y1=y1 or 0,
x2=x2 or x1 or 1280,y2=y2 or y1 or 720,
r=r or 1,g=g or 1,b=b or 1,a=a or 1,
})
ins(fx,{
update=FXupdate.line,
draw=FXdraw.line,
t=0,
rate=rate,
x1=x1 or 0,y1=y1 or 0,
x2=x2 or x1 or 1280,y2=y2 or y1 or 720,
r=r or 1,g=g or 1,b=b or 1,a=a or 1,
})
end
return SYSFX

View File

@@ -4,195 +4,195 @@ local TABLE={}
--Get a new filled table
function TABLE.new(val,count)
local L={}
for i=1,count do
L[i]=val
end
return L
local L={}
for i=1,count do
L[i]=val
end
return L
end
--Get a copy of [1~#] elements
function TABLE.shift(org,depth)
if not depth then depth=1e99 end
local L={}
for i=1,#org do
if type(org[i])=='table'and depth>0 then
L[i]=TABLE.shift(org[i],depth-1)
else
L[i]=org[i]
end
end
return L
if not depth then depth=1e99 end
local L={}
for i=1,#org do
if type(org[i])=='table'and depth>0 then
L[i]=TABLE.shift(org[i],depth-1)
else
L[i]=org[i]
end
end
return L
end
--Get a full copy of a table, depth = how many layers will be recreate, default to inf
function TABLE.copy(org,depth)
if not depth then depth=1e99 end
local L={}
for k,v in next,org do
if type(v)=='table'and depth>0 then
L[k]=TABLE.copy(v,depth-1)
else
L[k]=v
end
end
return L
if not depth then depth=1e99 end
local L={}
for k,v in next,org do
if type(v)=='table'and depth>0 then
L[k]=TABLE.copy(v,depth-1)
else
L[k]=v
end
end
return L
end
--For all things in new, push to old
function TABLE.cover(new,old)
for k,v in next,new do
old[k]=v
end
for k,v in next,new do
old[k]=v
end
end
--For all things in new if same type in old, push to old
function TABLE.update(new,old)
for k,v in next,new do
if type(v)==type(old[k])then
if type(v)=='table'then
TABLE.update(v,old[k])
else
old[k]=v
end
end
end
for k,v in next,new do
if type(v)==type(old[k])then
if type(v)=='table'then
TABLE.update(v,old[k])
else
old[k]=v
end
end
end
end
--For all things in new if no val in old, push to old
function TABLE.complete(new,old)
for k,v in next,new do
if type(v)=='table'then
if old[k]==nil then old[k]={}end
TABLE.complete(v,old[k])
elseif old[k]==nil then
old[k]=v
end
end
for k,v in next,new do
if type(v)=='table'then
if old[k]==nil then old[k]={}end
TABLE.complete(v,old[k])
elseif old[k]==nil then
old[k]=v
end
end
end
--Remove positive integer index of table
function TABLE.cut(G)
for i=1,#G do
G[i]=nil
end
for i=1,#G do
G[i]=nil
end
end
--Clear table
function TABLE.clear(G)
for k in next,G do
G[k]=nil
end
for k in next,G do
G[k]=nil
end
end
--Find value in [1~#]
function TABLE.find(t,val)
for i=1,#t do if t[i]==val then return i end end
for i=1,#t do if t[i]==val then return i end end
end
--Find value in whole table
function TABLE.search(t,val)
for k,v in next,t do if v==val then return k end end
for k,v in next,t do if v==val then return k end end
end
--Re-index string value of a table
function TABLE.reIndex(org)
for k,v in next,org do
if type(v)=='string'then
org[k]=org[v]
end
end
for k,v in next,org do
if type(v)=='string'then
org[k]=org[v]
end
end
end
--Dump a simple lua table
do--function TABLE.dump(L,t)
local tabs={
[0]="",
"\t",
"\t\t",
"\t\t\t",
"\t\t\t\t",
"\t\t\t\t\t",
}
local function dump(L,t)
local s
if t then
s="{\n"
else
s="return{\n"
t=1
if type(L)~='table'then
return
end
end
local count=1
for k,v in next,L do
local T=type(k)
if T=='number'then
if k==count then
k=""
count=count+1
else
k="["..k.."]="
end
elseif T=='string'then
if find(k,"[^0-9a-zA-Z_]")then
k="[\""..k.."\"]="
else
k=k.."="
end
elseif T=='boolean'then k="["..k.."]="
else error("Error key type!")
end
T=type(v)
if T=='number'then v=tostring(v)
elseif T=='string'then v="\""..v.."\""
elseif T=='table'then v=dump(v,t+1)
elseif T=='boolean'then v=tostring(v)
else error("Error data type!")
end
s=s..tabs[t]..k..v..",\n"
end
return s..tabs[t-1].."}"
end
TABLE.dump=dump
local tabs={
[0]="",
"\t",
"\t\t",
"\t\t\t",
"\t\t\t\t",
"\t\t\t\t\t",
}
local function dump(L,t)
local s
if t then
s="{\n"
else
s="return{\n"
t=1
if type(L)~='table'then
return
end
end
local count=1
for k,v in next,L do
local T=type(k)
if T=='number'then
if k==count then
k=""
count=count+1
else
k="["..k.."]="
end
elseif T=='string'then
if find(k,"[^0-9a-zA-Z_]")then
k="[\""..k.."\"]="
else
k=k.."="
end
elseif T=='boolean'then k="["..k.."]="
else error("Error key type!")
end
T=type(v)
if T=='number'then v=tostring(v)
elseif T=='string'then v="\""..v.."\""
elseif T=='table'then v=dump(v,t+1)
elseif T=='boolean'then v=tostring(v)
else error("Error data type!")
end
s=s..tabs[t]..k..v..",\n"
end
return s..tabs[t-1].."}"
end
TABLE.dump=dump
end
--Dump a simple lua table (no whitespaces)
do--function TABLE.dumpDeflate(L,t)
local function dump(L)
local s="return{"
if type(L)~='table'then return end
local count=1
for k,v in next,L do
local T=type(k)
if T=='number'then
if k==count then
k=""
count=count+1
else
k="["..k.."]="
end
elseif T=='string'then
if find(k,"[^0-9a-zA-Z_]")then
k="[\""..k.."\"]="
else
k=k.."="
end
elseif T=='boolean'then k="["..k.."]="
else error("Error key type!")
end
T=type(v)
if T=='number'then v=tostring(v)
elseif T=='string'then v="\""..v.."\""
elseif T=='table'then v=dump(v)
elseif T=='boolean'then v=tostring(v)
else error("Error data type!")
end
end
return s.."}"
end
TABLE.dumpDeflate=dump
local function dump(L)
local s="return{"
if type(L)~='table'then return end
local count=1
for k,v in next,L do
local T=type(k)
if T=='number'then
if k==count then
k=""
count=count+1
else
k="["..k.."]="
end
elseif T=='string'then
if find(k,"[^0-9a-zA-Z_]")then
k="[\""..k.."\"]="
else
k=k.."="
end
elseif T=='boolean'then k="["..k.."]="
else error("Error key type!")
end
T=type(v)
if T=='number'then v=tostring(v)
elseif T=='string'then v="\""..v.."\""
elseif T=='table'then v=dump(v)
elseif T=='boolean'then v=tostring(v)
else error("Error data type!")
end
end
return s.."}"
end
TABLE.dumpDeflate=dump
end
return TABLE

View File

@@ -4,48 +4,48 @@ local tasks={}
local TASK={}
function TASK.getCount()
return #tasks
return #tasks
end
function TASK.update()
for i=#tasks,1,-1 do
local T=tasks[i]
if status(T.thread)=='dead'then
rem(tasks,i)
else
assert(resume(T.thread))
end
end
for i=#tasks,1,-1 do
local T=tasks[i]
if status(T.thread)=='dead'then
rem(tasks,i)
else
assert(resume(T.thread))
end
end
end
function TASK.new(code,...)
local thread=coroutine.create(code)
resume(thread,...)
if status(thread)~='dead'then
tasks[#tasks+1]={
thread=thread,
code=code,
args={...},
}
end
local thread=coroutine.create(code)
resume(thread,...)
if status(thread)~='dead'then
tasks[#tasks+1]={
thread=thread,
code=code,
args={...},
}
end
end
function TASK.removeTask_code(code)
for i=#tasks,1,-1 do
if tasks[i].code==code then
rem(tasks,i)
end
end
for i=#tasks,1,-1 do
if tasks[i].code==code then
rem(tasks,i)
end
end
end
function TASK.removeTask_iterate(func,...)
for i=#tasks,1,-1 do
if func(tasks[i],...)then
rem(tasks,i)
end
end
for i=#tasks,1,-1 do
if func(tasks[i],...)then
rem(tasks,i)
end
end
end
function TASK.clear()
local i=#tasks
while i>0 do
tasks[i]=nil
i=i-1
end
local i=#tasks
while i>0 do
tasks[i]=nil
i=i-1
end
end
return TASK

View File

@@ -10,120 +10,120 @@ local texts={}
local textFX={}
function textFX.appear(t)
mStr(t.text,t.x,t.y-t.font*.7)
mStr(t.text,t.x,t.y-t.font*.7)
end
function textFX.sudden(t)
gc_setColor(1,1,1,1-t.c)
mStr(t.text,t.x,t.y-t.font*.7)
gc_setColor(1,1,1,1-t.c)
mStr(t.text,t.x,t.y-t.font*.7)
end
function textFX.fly(t)
mStr(t.text,t.x+(t.c-.5)^3*300,t.y-t.font*.7)
mStr(t.text,t.x+(t.c-.5)^3*300,t.y-t.font*.7)
end
function textFX.stretch(t)
gc_push('transform')
gc_translate(t.x,t.y)
if t.c<.3 then gc_scale((.3-t.c)*1.6+1,1)end
mStr(t.text,0,-t.font*.7)
gc_pop()
gc_push('transform')
gc_translate(t.x,t.y)
if t.c<.3 then gc_scale((.3-t.c)*1.6+1,1)end
mStr(t.text,0,-t.font*.7)
gc_pop()
end
function textFX.drive(t)
gc_push('transform')
gc_translate(t.x,t.y)
if t.c<.3 then gc_shear((.3-t.c)*2,0)end
mStr(t.text,0,-t.font*.7)
gc_pop()
gc_push('transform')
gc_translate(t.x,t.y)
if t.c<.3 then gc_shear((.3-t.c)*2,0)end
mStr(t.text,0,-t.font*.7)
gc_pop()
end
function textFX.spin(t)
gc_push('transform')
gc_translate(t.x,t.y)
if t.c<.3 then
gc_rotate((.3-t.c)^2*4)
elseif t.c>.8 then
gc_rotate((t.c-.8)^2*-4)
end
mStr(t.text,0,-t.font*.7)
gc_pop()
gc_push('transform')
gc_translate(t.x,t.y)
if t.c<.3 then
gc_rotate((.3-t.c)^2*4)
elseif t.c>.8 then
gc_rotate((t.c-.8)^2*-4)
end
mStr(t.text,0,-t.font*.7)
gc_pop()
end
function textFX.flicker(t)
local _,_,_,T=gc_getColor()
gc_setColor(1,1,1,T*(rnd()+.5))
mStr(t.text,t.x,t.y-t.font*.7)
local _,_,_,T=gc_getColor()
gc_setColor(1,1,1,T*(rnd()+.5))
mStr(t.text,t.x,t.y-t.font*.7)
end
function textFX.zoomout(t)
gc_push('transform')
local k=t.c^.5*.1+1
gc_translate(t.x,t.y)
gc_scale(k,k)
mStr(t.text,0,-t.font*.7)
gc_pop()
gc_push('transform')
local k=t.c^.5*.1+1
gc_translate(t.x,t.y)
gc_scale(k,k)
mStr(t.text,0,-t.font*.7)
gc_pop()
end
function textFX.beat(t)
gc_push('transform')
gc_translate(t.x,t.y)
if t.c<.3 then
local k=1.3-t.c^2/.3
gc_scale(k,k)
end
mStr(t.text,0,-t.font*.7)
gc_pop()
gc_push('transform')
gc_translate(t.x,t.y)
if t.c<.3 then
local k=1.3-t.c^2/.3
gc_scale(k,k)
end
mStr(t.text,0,-t.font*.7)
gc_pop()
end
function textFX.score(t)
local _,_,_,T=gc_getColor()
gc_setColor(1,1,1,T*.5)
mStr(t.text,t.x,t.y-t.font*.7-t.c^.2*50)
local _,_,_,T=gc_getColor()
gc_setColor(1,1,1,T*.5)
mStr(t.text,t.x,t.y-t.font*.7-t.c^.2*50)
end
local TEXT={}
function TEXT.clear()
texts={}
texts={}
end
function TEXT.show(text,x,y,font,style,spd,stop)
ins(texts,{
c=0, --Timer
text=text, --String
x=x or 0, --X
y=y or 0, --Y
font=int(font/5)*5 or 40, --Font
spd=(spd or 1)/60, --Timing speed(1=last 1 sec)
stop=stop, --Stop time(sustained text)
draw=textFX[style or'appear']or error("unavailable type:"..style), --Draw method
})
ins(texts,{
c=0, --Timer
text=text, --String
x=x or 0, --X
y=y or 0, --Y
font=int(font/5)*5 or 40,--Font
spd=(spd or 1)/60, --Timing speed(1=last 1 sec)
stop=stop, --Stop time(sustained text)
draw=assert(textFX[style or'appear'],"no text type:"..style),--Draw method
})
end
function TEXT.getText(text,x,y,font,style,spd,stop)--Another version of TEXT.show(), but only return text object, need manual management
return{
c=0,
text=text,
x=x or 0,
y=y or 0,
font=int(font/5)*5 or 40,
spd=(spd or 1)/60,
stop=stop,
draw=textFX[style or'appear']or error("unavailable type:"..style),
}
return{
c=0,
text=text,
x=x or 0,
y=y or 0,
font=int(font/5)*5 or 40,
spd=(spd or 1)/60,
stop=stop,
draw=textFX[style or'appear']or error("unavailable type:"..style),
}
end
function TEXT.update(list)
if not list then list=texts end
for i=#list,1,-1 do
local t=list[i]
t.c=t.c+t.spd
if t.stop then
if t.c>t.stop then
t.c=t.stop
end
end
if t.c>1 then
rem(list,i)
end
end
if not list then list=texts end
for i=#list,1,-1 do
local t=list[i]
t.c=t.c+t.spd
if t.stop then
if t.c>t.stop then
t.c=t.stop
end
end
if t.c>1 then
rem(list,i)
end
end
end
function TEXT.draw(list)
if not list then list=texts end
for i=1,#list do
local t=list[i]
local p=t.c
gc_setColor(1,1,1,p<.2 and p*5 or p<.8 and 1 or 5-p*5)
setFont(t.font)
t:draw()
end
if not list then list=texts end
for i=1,#list do
local t=list[i]
local p=t.c
gc_setColor(1,1,1,p<.2 and p*5 or p<.8 and 1 or 5-p*5)
setFont(t.font)
t:draw()
end
end
return TEXT

View File

@@ -1,97 +1,97 @@
local THEME={
cur=false,--Current theme
cur=false,--Current theme
}
local themeColor={
xmas={COLOR.R,COLOR.Z,COLOR.G},
sprfes={COLOR.R,COLOR.O,COLOR.Y},
xmas={COLOR.R,COLOR.Z,COLOR.G},
sprfes={COLOR.R,COLOR.O,COLOR.Y},
}
function THEME.calculate(Y,M,D)
if not Y then Y,M,D=os.date('%Y'),os.date('%m'),os.date('%d')end
--Festival calculate within one statement
return
--Christmas
M=='12'and math.abs(D-25)<4 and
'xmas'or
if not Y then Y,M,D=os.date('%Y'),os.date('%m'),os.date('%d')end
--Festival calculate within one statement
return
--Christmas
M=='12'and math.abs(D-25)<4 and
'xmas'or
--Birthday
M=='06'and D=='06'and
'birth'or
--Birthday
M=='06'and D=='06'and
'birth'or
--Spring festival
M<'03'and math.abs((({
--Festival days. Jan 26=26, Feb 1=32, etc.
24,43,32,22,40,29,49,38,26,45,
34,23,41,31,50,39,28,47,36,25,
43,32,22,41,29,48,37,26,44,34,
23,42,31,50,39,28,46,35,24,43,
32,22,41,30,48,37,26,45,33,23,
42,32,50,39,28,46,35,24,43,33,
21,40,
})[Y-2000]or -26)-((M-1)*31+D))<6 and
'sprfes'or
--Spring festival
M<'03'and math.abs((({
--Festival days. Jan 26=26, Feb 1=32, etc.
24,43,32,22,40,29,49,38,26,45,
34,23,41,31,50,39,28,47,36,25,
43,32,22,41,29,48,37,26,44,34,
23,42,31,50,39,28,46,35,24,43,
32,22,41,30,48,37,26,45,33,23,
42,32,50,39,28,46,35,24,43,33,
21,40,
})[Y-2000]or -26)-((M-1)*31+D))<6 and
'sprfes'or
--April fool's day
M=='04'and D=='01'and
'fool'or
--April fool's day
M=='04'and D=='01'and
'fool'or
--Z day
D=='26'and(
(M=='01'or M=='02'or M=='03')and'zday1'or
(M=='04'or M=='05'or M=='06')and'zday2'or
(M=='07'or M=='08'or M=='09')and'zday3'or
(M=='10'or M=='11'or M=='12')and'zday4'
)or
--Z day
D=='26'and(
(M=='01'or M=='02'or M=='03')and'zday1'or
(M=='04'or M=='05'or M=='06')and'zday2'or
(M=='07'or M=='08'or M=='09')and'zday3'or
(M=='10'or M=='11'or M=='12')and'zday4'
)or
'classic'
'classic'
end
function THEME.set(theme)
if theme=='classic'then
BG.setDefault('space')
BGM.setDefault('nil')
elseif theme=='xmas'then
BG.setDefault('snow')
BGM.setDefault('xmas')
MES.new('info',"==Merry Christmas==")
elseif theme=='birth'then
BG.setDefault('firework')
BGM.setDefault('magicblock')
elseif theme=='sprfes'then
BG.setDefault('firework')
BGM.setDefault('spring festival')
MES.new('info',"★☆新年快乐☆★")
elseif theme=='zday1'then
BG.setDefault('lanterns')
BGM.setDefault('overzero')
elseif theme=='zday2'then
BG.setDefault('lanterns')
BGM.setDefault('vacuum')
elseif theme=='zday3'then
BG.setDefault('lanterns')
BGM.setDefault('empty')
elseif theme=='zday4'then
BG.setDefault('lanterns')
BGM.setDefault('space')
elseif theme=='fool'then
BG.setDefault('blockrain')
BGM.setDefault('how feeling')
else
return
end
THEME.cur=theme
BG.set()
BGM.play()
return true
if theme=='classic'then
BG.setDefault('space')
BGM.setDefault('nil')
elseif theme=='xmas'then
BG.setDefault('snow')
BGM.setDefault('xmas')
MES.new('info',"==Merry Christmas==")
elseif theme=='birth'then
BG.setDefault('firework')
BGM.setDefault('magicblock')
elseif theme=='sprfes'then
BG.setDefault('firework')
BGM.setDefault('spring festival')
MES.new('info',"★☆新年快乐☆★")
elseif theme=='zday1'then
BG.setDefault('lanterns')
BGM.setDefault('overzero')
elseif theme=='zday2'then
BG.setDefault('lanterns')
BGM.setDefault('vacuum')
elseif theme=='zday3'then
BG.setDefault('lanterns')
BGM.setDefault('empty')
elseif theme=='zday4'then
BG.setDefault('lanterns')
BGM.setDefault('space')
elseif theme=='fool'then
BG.setDefault('blockrain')
BGM.setDefault('how feeling')
else
return
end
THEME.cur=theme
BG.set()
BGM.play()
return true
end
function THEME.getThemeColor(theme)
if not theme then theme=THEME.cur end
return themeColor[theme]
if not theme then theme=THEME.cur end
return themeColor[theme]
end
function THEME.fresh()
THEME.set(THEME.calculate(os.date('%Y'),os.date('%m'),os.date('%d')))
THEME.set(THEME.calculate(os.date('%Y'),os.date('%m'),os.date('%d')))
end
return THEME

View File

@@ -1,8 +1,8 @@
local level={0,0,.01,.016,.023,.03,.04,.05,.06,.07,.08,.09,.12,.15}
local vib=love.system.vibrate
return function(t)
local L=SETTING.vib
if L>0 then
vib(level[L+t])
end
local L=SETTING.vib
if L>0 then
vib(level[L+t])
end
end

View File

@@ -1,118 +1,118 @@
local VOC={
getCount=function()return 0 end,
getQueueCount=function()return 0 end,
loadAll=function()error("Cannot load before init!")end,
getFreeChannel=NULL,
play=NULL,
update=NULL,
getCount=function()return 0 end,
getQueueCount=function()return 0 end,
loadAll=function()error("Cannot load before init!")end,
getFreeChannel=NULL,
play=NULL,
update=NULL,
}
function VOC.init(list)
VOC.init=nil
local rnd=math.random
local rem=table.remove
local voiceQueue={free=0}
local bank={}--{vocName1={SRC1s},vocName2={SRC2s},...}
local Source={}
VOC.init=nil
local rnd=math.random
local rem=table.remove
local voiceQueue={free=0}
local bank={}--{vocName1={SRC1s},vocName2={SRC2s},...}
local Source={}
local count=#list function VOC.getCount()return count end
local function _loadVoiceFile(N,vocName)
local fileName='media/VOICE/'..SETTING.cv..'/'..vocName..'.ogg'
if love.filesystem.getInfo(fileName)then
bank[vocName]={love.audio.newSource(fileName,'stream')}
table.insert(Source[N],vocName)
return true
end
end
local function _getVoice(str)
local L=bank[str]
local n=1
while L[n]:isPlaying()do
n=n+1
if not L[n]then
L[n]=L[1]:clone()
L[n]:seek(0)
break
end
end
return L[n]
--Load voice with string
end
function VOC.loadAll()
for i=1,count do
Source[list[i]]={}
local count=#list function VOC.getCount()return count end
local function _loadVoiceFile(N,vocName)
local fileName='media/VOICE/'..SETTING.cv..'/'..vocName..'.ogg'
if love.filesystem.getInfo(fileName)then
bank[vocName]={love.audio.newSource(fileName,'stream')}
table.insert(Source[N],vocName)
return true
end
end
local function _getVoice(str)
local L=bank[str]
local n=1
while L[n]:isPlaying()do
n=n+1
if not L[n]then
L[n]=L[1]:clone()
L[n]:seek(0)
break
end
end
return L[n]
--Load voice with string
end
function VOC.loadAll()
for i=1,count do
Source[list[i]]={}
local n=0
repeat n=n+1 until not _loadVoiceFile(list[i],list[i]..'_'..n)
local n=0
repeat n=n+1 until not _loadVoiceFile(list[i],list[i]..'_'..n)
if n==1 then
if not _loadVoiceFile(list[i],list[i])then
MES.new('warn',"No VOICE file: "..list[i],.1)
end
end
if not Source[list[i]][1]then Source[list[i]]=nil end
end
if n==1 then
if not _loadVoiceFile(list[i],list[i])then
MES.new('warn',"No VOICE file: "..list[i],.1)
end
end
if not Source[list[i]][1]then Source[list[i]]=nil end
end
function VOC.getQueueCount()
return #voiceQueue
end
function VOC.getFreeChannel()
local l=#voiceQueue
for i=1,l do
if #voiceQueue[i]==0 then return i end
end
voiceQueue[l+1]={s=0}
return l+1
end
function VOC.getQueueCount()
return #voiceQueue
end
function VOC.getFreeChannel()
local l=#voiceQueue
for i=1,l do
if #voiceQueue[i]==0 then return i end
end
voiceQueue[l+1]={s=0}
return l+1
end
function VOC.play(s,chn)
if SETTING.voc>0 then
local _=Source[s]
if not _ then return end
if chn then
local L=voiceQueue[chn]
L[#L+1]=_[rnd(#_)]
L.s=1
--Add to queue[chn]
else
voiceQueue[VOC.getFreeChannel()]={s=1,_[rnd(#_)]}
--Create new channel & play
end
end
end
function VOC.update()
for i=#voiceQueue,1,-1 do
local Q=voiceQueue[i]
if Q.s==0 then--Free channel, auto delete when >3
if i>3 then
rem(voiceQueue,i)
end
elseif Q.s==1 then--Waiting load source
Q[1]=_getVoice(Q[1])
Q[1]:setVolume(SETTING.voc)
Q[1]:play()
Q.s=Q[2]and 2 or 4
elseif Q.s==2 then--Playing 1,ready 2
if Q[1]:getDuration()-Q[1]:tell()<.08 then
Q[2]=_getVoice(Q[2])
Q[2]:setVolume(SETTING.voc)
Q[2]:play()
Q.s=3
end
elseif Q.s==3 then--Playing 12 same time
if not Q[1]:isPlaying()then
for j=1,#Q do
Q[j]=Q[j+1]
end
Q.s=Q[2]and 2 or 4
end
elseif Q.s==4 then--Playing last
if not Q[1].isPlaying(Q[1])then
Q[1]=nil
Q.s=0
end
end
end
end
end
function VOC.play(s,chn)
if SETTING.voc>0 then
local _=Source[s]
if not _ then return end
if chn then
local L=voiceQueue[chn]
L[#L+1]=_[rnd(#_)]
L.s=1
--Add to queue[chn]
else
voiceQueue[VOC.getFreeChannel()]={s=1,_[rnd(#_)]}
--Create new channel & play
end
end
end
function VOC.update()
for i=#voiceQueue,1,-1 do
local Q=voiceQueue[i]
if Q.s==0 then--Free channel, auto delete when >3
if i>3 then
rem(voiceQueue,i)
end
elseif Q.s==1 then--Waiting load source
Q[1]=_getVoice(Q[1])
Q[1]:setVolume(SETTING.voc)
Q[1]:play()
Q.s=Q[2]and 2 or 4
elseif Q.s==2 then--Playing 1,ready 2
if Q[1]:getDuration()-Q[1]:tell()<.08 then
Q[2]=_getVoice(Q[2])
Q[2]:setVolume(SETTING.voc)
Q[2]:play()
Q.s=3
end
elseif Q.s==3 then--Playing 12 same time
if not Q[1]:isPlaying()then
for j=1,#Q do
Q[j]=Q[j+1]
end
Q.s=Q[2]and 2 or 4
end
elseif Q.s==4 then--Playing last
if not Q[1].isPlaying(Q[1])then
Q[1]=nil
Q.s=0
end
end
end
end
end
end
return VOC

View File

@@ -1,7 +1,7 @@
local host=
-- '127.0.0.1'
-- '192.168.114.102'
'game.techmino.org'
-- '127.0.0.1'
-- '192.168.114.102'
'game.techmino.org'
local port='10026'
local path='/tech/socket/v1'
@@ -18,174 +18,174 @@ local TRD_isRunning=TRD.isRunning
local WS={}
local wsList=setmetatable({},{
__index=function(l,k)
local ws={
real=false,
status='dead',
lastPongTime=timer(),
sendTimer=0,
alertTimer=0,
pongTimer=0,
}
l[k]=ws
return ws
end
__index=function(l,k)
local ws={
real=false,
status='dead',
lastPongTime=timer(),
sendTimer=0,
alertTimer=0,
pongTimer=0,
}
l[k]=ws
return ws
end
})
function WS.switchHost(_1,_2,_3)
for k in next,wsList do
WS.close(k)
end
host=_1
port=_2 or port
path=_3 or path
for k in next,wsList do
WS.close(k)
end
host=_1
port=_2 or port
path=_3 or path
end
function WS.connect(name,subPath,body,timeout)
if wsList[name]and wsList[name].thread then
wsList[name].thread:release()
end
local ws={
real=true,
thread=love.thread.newThread('Zframework/websocket_thread.lua'),
triggerCHN=love.thread.newChannel(),
sendCHN=love.thread.newChannel(),
readCHN=love.thread.newChannel(),
lastPingTime=0,
lastPongTime=timer(),
pingInterval=6,
status='connecting',--'connecting', 'running', 'dead'
sendTimer=0,
alertTimer=0,
pongTimer=0,
}
wsList[name]=ws
ws.thread:start(ws.triggerCHN,ws.sendCHN,ws.readCHN)
CHN_push(ws.sendCHN,host)
CHN_push(ws.sendCHN,port)
CHN_push(ws.sendCHN,path..subPath)
CHN_push(ws.sendCHN,body or"")
CHN_push(ws.sendCHN,timeout or 2.6)
if wsList[name]and wsList[name].thread then
wsList[name].thread:release()
end
local ws={
real=true,
thread=love.thread.newThread('Zframework/websocket_thread.lua'),
triggerCHN=love.thread.newChannel(),
sendCHN=love.thread.newChannel(),
readCHN=love.thread.newChannel(),
lastPingTime=0,
lastPongTime=timer(),
pingInterval=6,
status='connecting',--'connecting', 'running', 'dead'
sendTimer=0,
alertTimer=0,
pongTimer=0,
}
wsList[name]=ws
ws.thread:start(ws.triggerCHN,ws.sendCHN,ws.readCHN)
CHN_push(ws.sendCHN,host)
CHN_push(ws.sendCHN,port)
CHN_push(ws.sendCHN,path..subPath)
CHN_push(ws.sendCHN,body or"")
CHN_push(ws.sendCHN,timeout or 2.6)
end
function WS.status(name)
local ws=wsList[name]
return ws.status or'dead'
local ws=wsList[name]
return ws.status or'dead'
end
function WS.getTimers(name)
local ws=wsList[name]
return ws.pongTimer,ws.sendTimer,ws.alertTimer
local ws=wsList[name]
return ws.pongTimer,ws.sendTimer,ws.alertTimer
end
function WS.setPingInterval(name,time)
local ws=wsList[name]
ws.pingInterval=math.max(time or 2.6,2.6)
local ws=wsList[name]
ws.pingInterval=math.max(time or 2.6,2.6)
end
function WS.alert(name)
local ws=wsList[name]
ws.alertTimer=2.6
local ws=wsList[name]
ws.alertTimer=2.6
end
local OPcode={
continue=0,
text=1,
binary=2,
close=8,
ping=9,
pong=10,
continue=0,
text=1,
binary=2,
close=8,
ping=9,
pong=10,
}
local OPname={
[0]='continue',
[1]='text',
[2]='binary',
[8]='close',
[9]='ping',
[10]='pong',
[0]='continue',
[1]='text',
[2]='binary',
[8]='close',
[9]='ping',
[10]='pong',
}
function WS.send(name,message,op)
if type(message)=='string'then
local ws=wsList[name]
if ws.real and ws.status=='running'then
CHN_push(ws.sendCHN,op and OPcode[op]or 2)--2=binary
CHN_push(ws.sendCHN,message)
ws.lastPingTime=timer()
ws.sendTimer=1
end
else
MES.new('error',"Attempt to send non-string value!")
MES.traceback()
end
if type(message)=='string'then
local ws=wsList[name]
if ws.real and ws.status=='running'then
CHN_push(ws.sendCHN,op and OPcode[op]or 2)--2=binary
CHN_push(ws.sendCHN,message)
ws.lastPingTime=timer()
ws.sendTimer=1
end
else
MES.new('error',"Attempt to send non-string value!")
MES.traceback()
end
end
function WS.read(name)
local ws=wsList[name]
if ws.real and ws.status~='connecting'and CHN_getCount(ws.readCHN)>=2 then
local op,message=CHN_pop(ws.readCHN),CHN_pop(ws.readCHN)
if op==8 then--8=close
ws.status='dead'
elseif op==9 then--9=ping
WS.send(name,message or"",'pong')
end
ws.lastPongTime=timer()
ws.pongTimer=1
return message,OPname[op]or op
end
local ws=wsList[name]
if ws.real and ws.status~='connecting'and CHN_getCount(ws.readCHN)>=2 then
local op,message=CHN_pop(ws.readCHN),CHN_pop(ws.readCHN)
if op==8 then--8=close
ws.status='dead'
elseif op==9 then--9=ping
WS.send(name,message or"",'pong')
end
ws.lastPongTime=timer()
ws.pongTimer=1
return message,OPname[op]or op
end
end
function WS.close(name)
local ws=wsList[name]
if ws.real then
CHN_push(ws.sendCHN,8)--close
CHN_push(ws.sendCHN,"")
ws.status='dead'
end
local ws=wsList[name]
if ws.real then
CHN_push(ws.sendCHN,8)--close
CHN_push(ws.sendCHN,"")
ws.status='dead'
end
end
function WS.update(dt)
local time=timer()
for name,ws in next,wsList do
if ws.real and ws.status~='dead'then
if TRD_isRunning(ws.thread)then
if CHN_getCount(ws.triggerCHN)==0 then
CHN_push(ws.triggerCHN,0)
end
if ws.status=='connecting'then
local mes=CHN_pop(ws.readCHN)
if mes then
if mes=='success'then
ws.status='running'
ws.lastPingTime=time
ws.lastPongTime=time
ws.pongTimer=1
else
ws.status='dead'
MES.new('warn',text.wsFailed..": "..(mes=="timeout"and text.netTimeout or mes))
end
end
elseif ws.status=='running'then
if time-ws.lastPingTime>ws.pingInterval then
WS.send(name,"",'pong')
end
if time-ws.lastPongTime>6+2*ws.pingInterval then
WS.close(name)
end
end
if ws.sendTimer>0 then ws.sendTimer=ws.sendTimer-dt end
if ws.pongTimer>0 then ws.pongTimer=ws.pongTimer-dt end
if ws.alertTimer>0 then ws.alertTimer=ws.alertTimer-dt end
else
ws.status='dead'
local err=ws.thread:getError()
if err then
err=err:sub((err:find(":",(err:find(":")or 0)+1)or 0)+1,(err:find("\n")or 0)-1)
MES.new('warn',text.wsClose..err)
WS.alert(name)
end
end
end
end
local time=timer()
for name,ws in next,wsList do
if ws.real and ws.status~='dead'then
if TRD_isRunning(ws.thread)then
if CHN_getCount(ws.triggerCHN)==0 then
CHN_push(ws.triggerCHN,0)
end
if ws.status=='connecting'then
local mes=CHN_pop(ws.readCHN)
if mes then
if mes=='success'then
ws.status='running'
ws.lastPingTime=time
ws.lastPongTime=time
ws.pongTimer=1
else
ws.status='dead'
MES.new('warn',text.wsFailed..": "..(mes=="timeout"and text.netTimeout or mes))
end
end
elseif ws.status=='running'then
if time-ws.lastPingTime>ws.pingInterval then
WS.send(name,"",'pong')
end
if time-ws.lastPongTime>6+2*ws.pingInterval then
WS.close(name)
end
end
if ws.sendTimer>0 then ws.sendTimer=ws.sendTimer-dt end
if ws.pongTimer>0 then ws.pongTimer=ws.pongTimer-dt end
if ws.alertTimer>0 then ws.alertTimer=ws.alertTimer-dt end
else
ws.status='dead'
local err=ws.thread:getError()
if err then
err=err:sub((err:find(":",(err:find(":")or 0)+1)or 0)+1,(err:find("\n")or 0)-1)
MES.new('warn',text.wsClose..err)
WS.alert(name)
end
end
end
end
end
return WS

View File

@@ -7,57 +7,57 @@ local SOCK=require'socket'.tcp()
local JSON=require'Zframework.json'
do--Connect
local host=CHN_demand(sendCHN)
local port=CHN_demand(sendCHN)
local path=CHN_demand(sendCHN)
local body=CHN_demand(sendCHN)
local timeout=CHN_demand(sendCHN)
local host=CHN_demand(sendCHN)
local port=CHN_demand(sendCHN)
local path=CHN_demand(sendCHN)
local body=CHN_demand(sendCHN)
local timeout=CHN_demand(sendCHN)
SOCK:settimeout(timeout)
local res,err=SOCK:connect(host,port)
assert(res,err)
SOCK:settimeout(timeout)
local res,err=SOCK:connect(host,port)
assert(res,err)
--WebSocket handshake
if not body then body=''end
SOCK:send(
'GET '..path..' HTTP/1.1\r\n'..
'Host: '..host..':'..port..'\r\n'..
'Connection: Upgrade\r\n'..
'Upgrade: websocket\r\n'..
'Content-Type: application/json\r\n'..
'Content-Length: '..#body..'\r\n'..
'Sec-WebSocket-Version: 13\r\n'..
'Sec-WebSocket-Key: osT3F7mvlojIvf3/8uIsJQ==\r\n\r\n'..--secKey
body
)
--WebSocket handshake
if not body then body=''end
SOCK:send(
'GET '..path..' HTTP/1.1\r\n'..
'Host: '..host..':'..port..'\r\n'..
'Connection: Upgrade\r\n'..
'Upgrade: websocket\r\n'..
'Content-Type: application/json\r\n'..
'Content-Length: '..#body..'\r\n'..
'Sec-WebSocket-Version: 13\r\n'..
'Sec-WebSocket-Key: osT3F7mvlojIvf3/8uIsJQ==\r\n\r\n'..--secKey
body
)
--First line of HTTP
res,err=SOCK:receive('*l')
assert(res,err)
local code,ctLen
code=res:find(' ')
code=res:sub(code+1,code+3)
--First line of HTTP
res,err=SOCK:receive('*l')
assert(res,err)
local code,ctLen
code=res:find(' ')
code=res:sub(code+1,code+3)
--Get body length from headers and remove headers
repeat
res,err=SOCK:receive('*l')
assert(res,err)
if not ctLen and res:find('length')then
ctLen=tonumber(res:match('%d+'))
end
until res==''
--Get body length from headers and remove headers
repeat
res,err=SOCK:receive('*l')
assert(res,err)
if not ctLen and res:find('length')then
ctLen=tonumber(res:match('%d+'))
end
until res==''
--Result
if ctLen then
if code=='101'then
CHN_push(readCHN,'success')
else
res,err=SOCK:receive(ctLen)
res=JSON.decode(assert(res,err))
error((code or"XXX")..":"..(res and res.reason or"Server Error"))
end
end
SOCK:settimeout(0)
--Result
if ctLen then
if code=='101'then
CHN_push(readCHN,'success')
else
res,err=SOCK:receive(ctLen)
res=JSON.decode(assert(res,err))
error((code or"XXX")..":"..(res and res.reason or"Server Error"))
end
end
SOCK:settimeout(0)
end
local YIELD=coroutine.yield
@@ -68,121 +68,121 @@ local shl,shr=bit.lshift,bit.rshift
local mask_key={1,14,5,14}
local mask_str=char(unpack(mask_key))
local function _send(op,message)
--Message type
SOCK:send(char(bor(op,0x80)))
--Message type
SOCK:send(char(bor(op,0x80)))
if message then
--Length
local length=#message
if length>65535 then
SOCK:send(char(bor(127,0x80),0,0,0,0,band(shr(length,24),0xff),band(shr(length,16),0xff),band(shr(length,8),0xff),band(length,0xff)))
elseif length>125 then
SOCK:send(char(bor(126,0x80),band(shr(length,8),0xff),band(length,0xff)))
else
SOCK:send(char(bor(length,0x80)))
end
local msgbyte={byte(message,1,length)}
for i=1,length do
msgbyte[i]=bxor(msgbyte[i],mask_key[(i-1)%4+1])
end
return SOCK:send(mask_str..char(unpack(msgbyte)))
else
SOCK:send('\128'..mask_str)
return 0
end
if message then
--Length
local length=#message
if length>65535 then
SOCK:send(char(bor(127,0x80),0,0,0,0,band(shr(length,24),0xff),band(shr(length,16),0xff),band(shr(length,8),0xff),band(length,0xff)))
elseif length>125 then
SOCK:send(char(bor(126,0x80),band(shr(length,8),0xff),band(length,0xff)))
else
SOCK:send(char(bor(length,0x80)))
end
local msgbyte={byte(message,1,length)}
for i=1,length do
msgbyte[i]=bxor(msgbyte[i],mask_key[(i-1)%4+1])
end
return SOCK:send(mask_str..char(unpack(msgbyte)))
else
SOCK:send('\128'..mask_str)
return 0
end
end
local sendThread=coroutine.wrap(function()
while true do
while CHN_getCount(sendCHN)>=2 do
_send(CHN_pop(sendCHN),CHN_pop(sendCHN))
end
YIELD()
end
while true do
while CHN_getCount(sendCHN)>=2 do
_send(CHN_pop(sendCHN),CHN_pop(sendCHN))
end
YIELD()
end
end)
local function _receive(sock,len)
local buffer=""
while true do
local r,e,p=sock:receive(len)
if r then
buffer=buffer..r
len=len-#r
elseif p then
buffer=buffer..p
len=len-#p
elseif e then
return nil,e
end
if len==0 then
return buffer
end
YIELD()
end
local buffer=""
while true do
local r,e,p=sock:receive(len)
if r then
buffer=buffer..r
len=len-#r
elseif p then
buffer=buffer..p
len=len-#p
elseif e then
return nil,e
end
if len==0 then
return buffer
end
YIELD()
end
end
local readThread=coroutine.wrap(function()
local res,err
local op,fin
local lBuffer=""--Long multi-pack buffer
while true do
--Byte 0-1
res,err=_receive(SOCK,2)
assert(res,err)
local res,err
local op,fin
local lBuffer=""--Long multi-pack buffer
while true do
--Byte 0-1
res,err=_receive(SOCK,2)
assert(res,err)
op=band(byte(res,1),0x0f)
fin=band(byte(res,1),0x80)==0x80
op=band(byte(res,1),0x0f)
fin=band(byte(res,1),0x80)==0x80
--Calculating data length
local length=band(byte(res,2),0x7f)
if length==126 then
res,err=_receive(SOCK,2)
assert(res,err)
length=shl(byte(res,1),8)+byte(res,2)
elseif length==127 then
local lenData
lenData,err=_receive(SOCK,8)
assert(res,err)
local _,_,_,_,_5,_6,_7,_8=byte(lenData,1,8)
length=shl(_5,24)+shl(_6,16)+shl(_7,8)+_8
end
res,err=_receive(SOCK,length)
assert(res,err)
--Calculating data length
local length=band(byte(res,2),0x7f)
if length==126 then
res,err=_receive(SOCK,2)
assert(res,err)
length=shl(byte(res,1),8)+byte(res,2)
elseif length==127 then
local lenData
lenData,err=_receive(SOCK,8)
assert(res,err)
local _,_,_,_,_5,_6,_7,_8=byte(lenData,1,8)
length=shl(_5,24)+shl(_6,16)+shl(_7,8)+_8
end
res,err=_receive(SOCK,length)
assert(res,err)
--React
if op==8 then--8=close
CHN_push(readCHN,8)--close
if type(res)=='string'then
CHN_push(readCHN,res:sub(3))--Warning: 2 bytes close code at start so :sub(3)
else
CHN_push(readCHN,"WS closed")
end
return
elseif op==0 then--0=continue
lBuffer=lBuffer..res
if fin then
CHN_push(readCHN,lBuffer)
lBuffer=""
end
else
CHN_push(readCHN,op)
if fin then
CHN_push(readCHN,res)
lBuffer=""
else
lBuffer=res
end
end
YIELD()
end
--React
if op==8 then--8=close
CHN_push(readCHN,8)--close
if type(res)=='string'then
CHN_push(readCHN,res:sub(3))--Warning: 2 bytes close code at start so :sub(3)
else
CHN_push(readCHN,"WS closed")
end
return
elseif op==0 then--0=continue
lBuffer=lBuffer..res
if fin then
CHN_push(readCHN,lBuffer)
lBuffer=""
end
else
CHN_push(readCHN,op)
if fin then
CHN_push(readCHN,res)
lBuffer=""
else
lBuffer=res
end
end
YIELD()
end
end)
local success,err
while true do--Running
CHN_demand(triggerCHN)
success,err=pcall(sendThread)
if not success or err then break end
success,err=pcall(readThread)
if not success or err then break end
CHN_demand(triggerCHN)
success,err=pcall(sendThread)
if not success or err then break end
success,err=pcall(readThread)
if not success or err then break end
end
SOCK:close()

View File

@@ -2,18 +2,18 @@ local love=love
local max,min=math.max,math.min
local float=0
return function(y,key1,key2)
if y>0 then
float=max(float,0)+y^1.2
elseif y<0 then
if float>0 then float=0 end
float=min(float,0)-(-y)^1.2
end
while float>=1 do
love.keypressed(key1 or"up")
float=float-1
end
while float<=-1 do
love.keypressed(key2 or"down")
float=float+1
end
if y>0 then
float=max(float,0)+y^1.2
elseif y<0 then
if float>0 then float=0 end
float=min(float,0)-(-y)^1.2
end
while float>=1 do
love.keypressed(key1 or"up")
float=float-1
end
while float<=-1 do
love.keypressed(key2 or"down")
float=float+1
end
end

File diff suppressed because it is too large Load Diff