移除Zframework,准备使用submodule
This commit is contained in:
@@ -1,56 +0,0 @@
|
|||||||
local gc_clear=love.graphics.clear
|
|
||||||
local BGs={
|
|
||||||
none={draw=function()gc_clear(.08,.08,.084)end}
|
|
||||||
}
|
|
||||||
local BGlist={'none'}
|
|
||||||
local BG={
|
|
||||||
default='none',
|
|
||||||
locked=false,
|
|
||||||
cur='none',
|
|
||||||
init=false,
|
|
||||||
resize=false,
|
|
||||||
update=NULL,
|
|
||||||
draw=BGs.none.draw,
|
|
||||||
event=false,
|
|
||||||
discard=NULL,
|
|
||||||
}
|
|
||||||
|
|
||||||
function BG.lock()BG.locked=true end
|
|
||||||
function BG.unlock()BG.locked=false end
|
|
||||||
function BG.add(name,bg)
|
|
||||||
BGs[name]=bg
|
|
||||||
BGlist[#BGlist+1]=name
|
|
||||||
end
|
|
||||||
function BG.getList()
|
|
||||||
return BGlist
|
|
||||||
end
|
|
||||||
function BG.remList(name)
|
|
||||||
table.remove(BGlist,TABLE.find(BGlist,name))
|
|
||||||
end
|
|
||||||
function BG.send(...)
|
|
||||||
if BG.event then
|
|
||||||
BG.event(...)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
function BG.setDefault(bg)
|
|
||||||
BG.default=bg
|
|
||||||
end
|
|
||||||
function BG.set(name)
|
|
||||||
name=name or BG.default
|
|
||||||
if not BGs[name]or BG.locked then return end
|
|
||||||
if name~=BG.cur then
|
|
||||||
BG.discard()
|
|
||||||
BG.cur=name
|
|
||||||
local bg=BGs[name]
|
|
||||||
|
|
||||||
BG.init= bg.init or NULL
|
|
||||||
BG.resize= bg.resize or NULL
|
|
||||||
BG.update= bg.update or NULL
|
|
||||||
BG.draw= bg.draw or NULL
|
|
||||||
BG.event= bg.event or NULL
|
|
||||||
BG.discard=bg.discard or NULL
|
|
||||||
BG.init()
|
|
||||||
end
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
return BG
|
|
||||||
@@ -1,182 +0,0 @@
|
|||||||
local lastLoaded={}
|
|
||||||
local maxLoadedCount=3
|
|
||||||
local nameList={}
|
|
||||||
local SourceObjList={}
|
|
||||||
local volume=1
|
|
||||||
|
|
||||||
local BGM={
|
|
||||||
default=false,
|
|
||||||
onChange=NULL,
|
|
||||||
--nowPlay=[str:playing ID]
|
|
||||||
--playing=[src:playing SRC]
|
|
||||||
--lastPlayed=[str:lastPlayed ID]
|
|
||||||
}
|
|
||||||
|
|
||||||
local function _tryReleaseSources()
|
|
||||||
local n=#lastLoaded
|
|
||||||
while #lastLoaded>maxLoadedCount do
|
|
||||||
local name=lastLoaded[n]
|
|
||||||
if SourceObjList[name].source:isPlaying()then
|
|
||||||
n=n-1
|
|
||||||
if n<=0 then return end
|
|
||||||
else
|
|
||||||
SourceObjList[name].source=SourceObjList[name].source:release()and nil
|
|
||||||
table.remove(lastLoaded,n)
|
|
||||||
return
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
local function _addFile(name,path)
|
|
||||||
if not SourceObjList[name]then
|
|
||||||
table.insert(nameList,name)
|
|
||||||
SourceObjList[name]={path=path,source=false}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function BGM.getList()return nameList end
|
|
||||||
function BGM.getCount()return #nameList end
|
|
||||||
function BGM.load(name,path)
|
|
||||||
if type(name)=='table'then
|
|
||||||
for k,v in next,name do
|
|
||||||
_addFile(k,v)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
_addFile(name,path)
|
|
||||||
end
|
|
||||||
table.sort(nameList)
|
|
||||||
LOG(BGM.getCount().." BGM files added")
|
|
||||||
end
|
|
||||||
|
|
||||||
function BGM.setDefault(bgm)
|
|
||||||
BGM.default=bgm
|
|
||||||
end
|
|
||||||
function BGM.setMaxSources(count)
|
|
||||||
maxLoadedCount=count
|
|
||||||
_tryReleaseSources()
|
|
||||||
end
|
|
||||||
function BGM.setChange(func)
|
|
||||||
BGM.onChange=func
|
|
||||||
end
|
|
||||||
function BGM.setVol(v)
|
|
||||||
assert(type(v)=='number'and v>=0 and v<=1,'Wrong volume')
|
|
||||||
volume=v
|
|
||||||
if BGM.playing then
|
|
||||||
if volume>0 then
|
|
||||||
BGM.playing:setVolume(volume)
|
|
||||||
BGM.playing:play()
|
|
||||||
elseif BGM.nowPlay then
|
|
||||||
BGM.playing:pause()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function task_fadeOut(src)
|
|
||||||
while true do
|
|
||||||
coroutine.yield()
|
|
||||||
local v=src:getVolume()-volume/40
|
|
||||||
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=volume
|
|
||||||
v=math.min(v,src:getVolume()+v/40)
|
|
||||||
src:setVolume(v)
|
|
||||||
if v>=volume then
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
local function check_curFadeOut(task,code,src)
|
|
||||||
return task.code==code and task.args[1]==src
|
|
||||||
end
|
|
||||||
local function _tryLoad(name)
|
|
||||||
if SourceObjList[name]then
|
|
||||||
if SourceObjList[name].source then
|
|
||||||
return true
|
|
||||||
elseif love.filesystem.getInfo(SourceObjList[name].path)then
|
|
||||||
SourceObjList[name].source=love.audio.newSource(SourceObjList[name].path,'stream')
|
|
||||||
SourceObjList[name].source:setVolume(0)
|
|
||||||
table.insert(lastLoaded,1,name)
|
|
||||||
_tryReleaseSources()
|
|
||||||
return true
|
|
||||||
else
|
|
||||||
LOG("No BGM: "..SourceObjList[name],5)
|
|
||||||
end
|
|
||||||
elseif name then
|
|
||||||
LOG("No BGM: "..name,5)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
function BGM.play(name,args)
|
|
||||||
name=name or BGM.default
|
|
||||||
args=args or""
|
|
||||||
if not _tryLoad(name)or args:sArg('-preLoad')then return end
|
|
||||||
if volume==0 then
|
|
||||||
BGM.nowPlay=name
|
|
||||||
BGM.playing=SourceObjList[name].source
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
if name and SourceObjList[name].source then
|
|
||||||
if BGM.nowPlay~=name then
|
|
||||||
if BGM.nowPlay then
|
|
||||||
if not args:sArg('-sdout')then
|
|
||||||
TASK.new(task_fadeOut,BGM.playing)
|
|
||||||
else
|
|
||||||
BGM.playing:pause()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
TASK.removeTask_iterate(check_curFadeOut,task_fadeOut,SourceObjList[name].source)
|
|
||||||
TASK.removeTask_code(task_fadeIn)
|
|
||||||
|
|
||||||
BGM.nowPlay=name
|
|
||||||
BGM.playing=SourceObjList[name].source
|
|
||||||
if not args:sArg('-sdin')then
|
|
||||||
BGM.playing:setVolume(0)
|
|
||||||
TASK.new(task_fadeIn,BGM.playing)
|
|
||||||
else
|
|
||||||
BGM.playing:setVolume(volume)
|
|
||||||
BGM.playing:play()
|
|
||||||
end
|
|
||||||
SourceObjList[name].source:setLooping(not args:sArg('-noloop'))
|
|
||||||
BGM.lastPlayed=BGM.nowPlay
|
|
||||||
BGM.playing:play()
|
|
||||||
BGM.onChange(name)
|
|
||||||
end
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
function BGM.seek(t)
|
|
||||||
if BGM.playing then
|
|
||||||
BGM.playing:seek(t)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
function BGM.isPlaying()
|
|
||||||
return BGM.playing and BGM.playing:isPlaying()
|
|
||||||
end
|
|
||||||
function BGM.continue()
|
|
||||||
if BGM.lastPlayed then
|
|
||||||
BGM.nowPlay,BGM.playing=BGM.lastPlayed,SourceObjList[BGM.lastPlayed].source
|
|
||||||
TASK.removeTask_iterate(check_curFadeOut,task_fadeOut,SourceObjList[BGM.nowPlay].source)
|
|
||||||
TASK.removeTask_code(task_fadeIn)
|
|
||||||
TASK.new(task_fadeIn,BGM.playing)
|
|
||||||
BGM.playing:play()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
function BGM.stop(args)
|
|
||||||
args=args or""
|
|
||||||
TASK.removeTask_code(task_fadeIn)
|
|
||||||
if not args:sArg('-s')then
|
|
||||||
if BGM.nowPlay then
|
|
||||||
TASK.new(task_fadeOut,BGM.playing)
|
|
||||||
end
|
|
||||||
elseif BGM.playing then
|
|
||||||
BGM.playing:pause()
|
|
||||||
end
|
|
||||||
BGM.nowPlay,BGM.playing=nil
|
|
||||||
end
|
|
||||||
return BGM
|
|
||||||
@@ -1,148 +0,0 @@
|
|||||||
local abs=math.abs
|
|
||||||
local function hsv(h,s,v,a)--Color type, Color amount, Light
|
|
||||||
if s<=0 then return v,v,v,a end
|
|
||||||
h=h*6
|
|
||||||
local c=v*s
|
|
||||||
local x=abs((h-1)%2-1)*c
|
|
||||||
if h<1 then return v,x+v-c,v-c,a
|
|
||||||
elseif h<2 then return x+v-c,v,v-c,a
|
|
||||||
elseif h<3 then return v-c,v,x+v-c,a
|
|
||||||
elseif h<4 then return v-c,x+v-c,v,a
|
|
||||||
elseif h<5 then return x+v-c,v-c,v,a
|
|
||||||
else return v,v-c,x+v-c,a
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local COLOR={
|
|
||||||
hsv=hsv,
|
|
||||||
|
|
||||||
red= {hsv(0.00, 0.89, 0.91)},
|
|
||||||
fire= {hsv(0.04, 0.93, 0.94)},
|
|
||||||
orange= {hsv(0.09, 0.99, 0.96)},
|
|
||||||
yellow= {hsv(0.15, 0.82, 0.90)},
|
|
||||||
lime= {hsv(0.20, 0.89, 0.88)},
|
|
||||||
jade= {hsv(0.25, 1.00, 0.82)},
|
|
||||||
green= {hsv(0.33, 1.00, 0.81)},
|
|
||||||
aqua= {hsv(0.47, 1.00, 0.76)},
|
|
||||||
cyan= {hsv(0.53, 1.00, 0.88)},
|
|
||||||
navy= {hsv(0.56, 1.00, 1.00)},
|
|
||||||
sea= {hsv(0.61, 1.00, 1.00)},
|
|
||||||
blue= {hsv(0.64, 1.00, 0.95)},
|
|
||||||
violet= {hsv(0.74, 1.00, 0.91)},
|
|
||||||
purple= {hsv(0.80, 1.00, 0.81)},
|
|
||||||
magenta= {hsv(0.86, 1.00, 0.78)},
|
|
||||||
wine= {hsv(0.92, 0.98, 0.91)},
|
|
||||||
|
|
||||||
lRed= {hsv(0.00, 0.38, 0.93)},
|
|
||||||
lFire= {hsv(0.04, 0.45, 0.91)},
|
|
||||||
lOrange= {hsv(0.10, 0.53, 0.92)},
|
|
||||||
lYellow= {hsv(0.14, 0.61, 0.95)},
|
|
||||||
lLime= {hsv(0.20, 0.66, 0.92)},
|
|
||||||
lJade= {hsv(0.26, 0.56, 0.90)},
|
|
||||||
lGreen= {hsv(0.34, 0.49, 0.89)},
|
|
||||||
lAqua= {hsv(0.47, 0.59, 0.86)},
|
|
||||||
lCyan= {hsv(0.51, 0.77, 0.88)},
|
|
||||||
lNavy= {hsv(0.54, 0.80, 0.95)},
|
|
||||||
lSea= {hsv(0.57, 0.72, 0.97)},
|
|
||||||
lBlue= {hsv(0.64, 0.44, 0.96)},
|
|
||||||
lViolet= {hsv(0.72, 0.47, 0.95)},
|
|
||||||
lPurple= {hsv(0.80, 0.62, 0.89)},
|
|
||||||
lMagenta= {hsv(0.86, 0.61, 0.89)},
|
|
||||||
lWine= {hsv(0.93, 0.57, 0.92)},
|
|
||||||
|
|
||||||
dRed= {hsv(0.00, 0.80, 0.48)},
|
|
||||||
dFire= {hsv(0.04, 0.80, 0.34)},
|
|
||||||
dOrange= {hsv(0.07, 0.80, 0.39)},
|
|
||||||
dYellow= {hsv(0.12, 0.80, 0.37)},
|
|
||||||
dLime= {hsv(0.20, 0.80, 0.26)},
|
|
||||||
dJade= {hsv(0.29, 0.80, 0.27)},
|
|
||||||
dGreen= {hsv(0.33, 0.80, 0.26)},
|
|
||||||
dAqua= {hsv(0.46, 0.80, 0.24)},
|
|
||||||
dCyan= {hsv(0.50, 0.80, 0.30)},
|
|
||||||
dNavy= {hsv(0.58, 0.80, 0.42)},
|
|
||||||
dSea= {hsv(0.64, 0.80, 0.40)},
|
|
||||||
dBlue= {hsv(0.67, 0.80, 0.34)},
|
|
||||||
dViolet= {hsv(0.71, 0.80, 0.35)},
|
|
||||||
dPurple= {hsv(0.76, 0.80, 0.32)},
|
|
||||||
dMagenta= {hsv(0.87, 0.80, 0.28)},
|
|
||||||
dWine= {hsv(0.92, 0.80, 0.28)},
|
|
||||||
|
|
||||||
black= {hsv(0.04, 0.04, 0.14)},
|
|
||||||
dGray= {hsv(0.02, 0.05, 0.44)},
|
|
||||||
gray= {hsv(0.02, 0.05, 0.65)},
|
|
||||||
lGray= {hsv(0.02, 0.06, 0.86)},
|
|
||||||
white= {hsv(0.01, 0.02, 0.99)},
|
|
||||||
|
|
||||||
xGray= {hsv(0.00, 0.00, 0.35,.8)},
|
|
||||||
lxGray= {hsv(0.00, 0.00, 0.62,.8)},
|
|
||||||
dxGray= {hsv(0.00, 0.00, 0.16,.8)},
|
|
||||||
}
|
|
||||||
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',
|
|
||||||
X='xGray',lX='lxGray',dX='dxGray',
|
|
||||||
--Remain letter: EIKQTUX
|
|
||||||
}do
|
|
||||||
COLOR[k]=COLOR[v]
|
|
||||||
end
|
|
||||||
setmetatable(COLOR,{__index=function(_,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 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
|
|
||||||
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
|
|
||||||
end
|
|
||||||
|
|
||||||
return COLOR
|
|
||||||
@@ -1,105 +0,0 @@
|
|||||||
local fs=love.filesystem
|
|
||||||
local FILE={}
|
|
||||||
function FILE.load(name,args)
|
|
||||||
if not args then args=''end
|
|
||||||
if fs.getInfo(name)then
|
|
||||||
local F=fs.newFile(name)
|
|
||||||
assert(F:open'r','open error')
|
|
||||||
local s=F:read()F:close()
|
|
||||||
local mode=
|
|
||||||
STRING.sArg(args,'-luaon')and'luaon'or
|
|
||||||
STRING.sArg(args,'-lua')and'lua'or
|
|
||||||
STRING.sArg(args,'-json')and'json'or
|
|
||||||
STRING.sArg(args,'-string')and'string'or
|
|
||||||
s:sub(1,6)=='return{'and'luaon'or
|
|
||||||
(s:sub(1,1)=='['and s:sub(-1)==']'or s:sub(1,1)=='{'and s:sub(-1)=='}')and'json'or
|
|
||||||
'string'
|
|
||||||
if mode=='luaon'then
|
|
||||||
local func,err_mes=loadstring(s)
|
|
||||||
if func then
|
|
||||||
setfenv(func,{})
|
|
||||||
local res=func()
|
|
||||||
return assert(res,'decode error')
|
|
||||||
else
|
|
||||||
error('decode error: '..err_mes)
|
|
||||||
end
|
|
||||||
elseif mode=='lua'then
|
|
||||||
local func,err_mes=loadstring(s)
|
|
||||||
if func then
|
|
||||||
local res=func()
|
|
||||||
return assert(res,'run error')
|
|
||||||
else
|
|
||||||
error('compile error: '..err_mes)
|
|
||||||
end
|
|
||||||
elseif mode=='json'then
|
|
||||||
local res=JSON.decode(s)
|
|
||||||
if res then
|
|
||||||
return res
|
|
||||||
end
|
|
||||||
error('decode error')
|
|
||||||
elseif mode=='string'then
|
|
||||||
return s
|
|
||||||
else
|
|
||||||
error('unknown mode')
|
|
||||||
end
|
|
||||||
else
|
|
||||||
error('no file')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
function FILE.save(data,name,args)
|
|
||||||
if not args then args=''end
|
|
||||||
if STRING.sArg(args,'-d')and fs.getInfo(name)then
|
|
||||||
error('duplicate')
|
|
||||||
end
|
|
||||||
|
|
||||||
if type(data)=='table'then
|
|
||||||
if STRING.sArg(args,'-luaon')then
|
|
||||||
data=TABLE.dump(data)
|
|
||||||
if not data then
|
|
||||||
error('encode error')
|
|
||||||
end
|
|
||||||
else
|
|
||||||
data=JSON.encode(data)
|
|
||||||
if not data then
|
|
||||||
error('encode error')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else
|
|
||||||
data=tostring(data)
|
|
||||||
end
|
|
||||||
|
|
||||||
local F=fs.newFile(name)
|
|
||||||
assert(F:open('w'),'open error')
|
|
||||||
F:write(data)F:flush()F:close()
|
|
||||||
end
|
|
||||||
function FILE.clear(path)
|
|
||||||
if fs.getRealDirectory(path)==SAVEDIR and fs.getInfo(path).type=='directory'then
|
|
||||||
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
|
|
||||||
end
|
|
||||||
function FILE.clear_s(path)
|
|
||||||
if path==''or(fs.getRealDirectory(path)==SAVEDIR and fs.getInfo(path).type=='directory')then
|
|
||||||
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
|
|
||||||
end
|
|
||||||
return FILE
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
local gc=love.graphics
|
|
||||||
local set=gc.setFont
|
|
||||||
local fontFiles,fontCache={},{}
|
|
||||||
local defaultFont,defaultFallBack
|
|
||||||
local curFont=false--Current using font object
|
|
||||||
|
|
||||||
local FONT={}
|
|
||||||
function FONT.setDefault(name)defaultFont=name end
|
|
||||||
function FONT.setFallback(name)defaultFallBack=name end
|
|
||||||
function FONT.rawget(s)
|
|
||||||
if not fontCache[s]then
|
|
||||||
fontCache[s]=gc.setNewFont(s,'light',gc.getDPIScale()*SCR.k*2)
|
|
||||||
end
|
|
||||||
return fontCache[s]
|
|
||||||
end
|
|
||||||
function FONT.rawset(s)
|
|
||||||
set(fontCache[s]or FONT.rawget(s))
|
|
||||||
end
|
|
||||||
function FONT.load(fonts)
|
|
||||||
for name,path in next,fonts do
|
|
||||||
assert(love.filesystem.getInfo(path),STRING.repD("Font file $1($2) not exist!",name,path))
|
|
||||||
fontFiles[name]=love.filesystem.newFile(path)
|
|
||||||
fontCache[name]={}
|
|
||||||
end
|
|
||||||
FONT.reset()
|
|
||||||
end
|
|
||||||
function FONT.get(size,name)
|
|
||||||
if not name then name=defaultFont end
|
|
||||||
local f=fontCache[name][size]
|
|
||||||
if not f then
|
|
||||||
f=gc.setNewFont(fontFiles[name],size,'light',gc.getDPIScale()*SCR.k*2)
|
|
||||||
if defaultFallBack and name~=defaultFallBack then
|
|
||||||
f:setFallbacks(FONT.get(size,defaultFallBack))
|
|
||||||
end
|
|
||||||
fontCache[name][size]=f
|
|
||||||
end
|
|
||||||
return f
|
|
||||||
end
|
|
||||||
function FONT.set(size,name)
|
|
||||||
if not name then name=defaultFont end
|
|
||||||
|
|
||||||
local f=fontCache[name][size]
|
|
||||||
if f~=curFont then
|
|
||||||
curFont=f or FONT.get(size,name)
|
|
||||||
set(curFont)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
function FONT.reset()
|
|
||||||
for name,cache in next,fontCache do
|
|
||||||
if type(cache)=='table'then
|
|
||||||
for size in next,cache do
|
|
||||||
cache[size]=FONT.get(size,name)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
fontCache[name]=FONT.rawget(name)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return FONT
|
|
||||||
@@ -1,164 +0,0 @@
|
|||||||
local gc=love.graphics
|
|
||||||
local setColor,printf,draw=gc.setColor,gc.printf,gc.draw
|
|
||||||
local GC={}
|
|
||||||
function GC.mStr(obj,x,y)printf(obj,x-626,y,1252,'center')end--Printf a string with 'center'
|
|
||||||
function GC.simpX(obj,x,y)draw(obj,x-obj:getWidth()*.5,y)end--Simply draw an obj with x=obj:getWidth()/2
|
|
||||||
function GC.simpY(obj,x,y)draw(obj,x,y-obj:getHeight()*.5)end--Simply draw an obj with y=obj:getWidth()/2
|
|
||||||
function GC.X(obj,x,y,a,k)draw(obj,x,y,a,k,nil,obj:getWidth()*.5,0)end--Draw an obj with x=obj:getWidth()/2
|
|
||||||
function GC.Y(obj,x,y,a,k)draw(obj,x,y,a,k,nil,0,obj:getHeight()*.5)end--Draw an obj with y=obj:getWidth()/2
|
|
||||||
function GC.draw(obj,x,y,a,k)draw(obj,x,y,a,k,nil,obj:getWidth()*.5,obj:getHeight()*.5)end--Draw an obj with both middle X & Y
|
|
||||||
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)
|
|
||||||
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)
|
|
||||||
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))
|
|
||||||
|
|
||||||
--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
|
|
||||||
end
|
|
||||||
do--function GC.DO(L)
|
|
||||||
local cmds={
|
|
||||||
origin="origin",
|
|
||||||
move="translate",
|
|
||||||
scale="scale",
|
|
||||||
rotate="rotate",
|
|
||||||
shear="shear",
|
|
||||||
clear="clear",
|
|
||||||
|
|
||||||
setCL="setColor",
|
|
||||||
setCM="setColorMask",
|
|
||||||
setLW="setLineWidth",
|
|
||||||
setLS="setLineStyle",
|
|
||||||
setLJ="setLineJoin",
|
|
||||||
|
|
||||||
print="print",
|
|
||||||
rawFT=function(...)FONT.rawset(...)end,
|
|
||||||
setFT=function(...)FONT.set(...)end,
|
|
||||||
mText=GC.mStr,
|
|
||||||
mDraw=GC.draw,
|
|
||||||
mDrawX=GC.X,
|
|
||||||
mDrawY=GC.Y,
|
|
||||||
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,
|
|
||||||
|
|
||||||
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
|
|
||||||
end
|
|
||||||
return GC
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
local IMG={}
|
|
||||||
function IMG.init(list)
|
|
||||||
IMG.init=nil
|
|
||||||
|
|
||||||
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
|
|
||||||
LOG("No IMG: "..name)
|
|
||||||
self[name]=PAPER
|
|
||||||
end
|
|
||||||
return self[name]
|
|
||||||
end})
|
|
||||||
|
|
||||||
function IMG.loadAll()
|
|
||||||
for k in next,list do local _=IMG[k]end
|
|
||||||
IMG.loadAll=nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return IMG
|
|
||||||
@@ -1,885 +0,0 @@
|
|||||||
NONE={}function NULL()end PAPER=love.graphics.newCanvas(1,1)
|
|
||||||
EDITING=""
|
|
||||||
LOADED=false
|
|
||||||
|
|
||||||
--Pure lua modules (basic)
|
|
||||||
MATH= require'Zframework.mathExtend'
|
|
||||||
COLOR= require'Zframework.color'
|
|
||||||
TABLE= require'Zframework.tableExtend'
|
|
||||||
STRING= require'Zframework.stringExtend'
|
|
||||||
PROFILE= require'Zframework.profile'
|
|
||||||
JSON= require'Zframework.json'
|
|
||||||
TEST= require'Zframework.test'
|
|
||||||
|
|
||||||
do--Add pcall & MES for JSON lib
|
|
||||||
local encode,decode=JSON.encode,JSON.decode
|
|
||||||
JSON.encode=function(val)
|
|
||||||
local a,b=pcall(encode,val)
|
|
||||||
if a then
|
|
||||||
return b
|
|
||||||
elseif MES then
|
|
||||||
MES.traceback()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
JSON.decode=function(str)
|
|
||||||
local a,b=pcall(decode,str)
|
|
||||||
if a then
|
|
||||||
return b
|
|
||||||
elseif MES then
|
|
||||||
MES.traceback()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--Pure lua modules (complex)
|
|
||||||
LOG= require'Zframework.log'
|
|
||||||
REQUIRE= require'Zframework.require'
|
|
||||||
TASK= require'Zframework.task'
|
|
||||||
WS= require'Zframework.websocket'
|
|
||||||
LANG= require'Zframework.languages'
|
|
||||||
|
|
||||||
--Love-based modules (basic)
|
|
||||||
FILE= require'Zframework.file'
|
|
||||||
WHEELMOV= require'Zframework.wheelScroll'
|
|
||||||
SCR= require'Zframework.screen'
|
|
||||||
SCN= require'Zframework.scene'
|
|
||||||
LIGHT= require'Zframework.light'
|
|
||||||
|
|
||||||
--Love-based modules (complex)
|
|
||||||
GC= require'Zframework.gcExtend'
|
|
||||||
FONT= require'Zframework.font'
|
|
||||||
TEXT= require'Zframework.text'
|
|
||||||
SYSFX= require'Zframework.sysFX'
|
|
||||||
MES= require'Zframework.message'
|
|
||||||
BG= require'Zframework.background'
|
|
||||||
WIDGET= require'Zframework.widget'
|
|
||||||
VIB= require'Zframework.vibrate'
|
|
||||||
SFX= require'Zframework.sfx'
|
|
||||||
IMG= require'Zframework.image'
|
|
||||||
BGM= require'Zframework.bgm'
|
|
||||||
VOC= require'Zframework.voice'
|
|
||||||
|
|
||||||
local ms,kb=love.mouse,love.keyboard
|
|
||||||
local KBisDown=kb.isDown
|
|
||||||
|
|
||||||
local gc=love.graphics
|
|
||||||
local gc_push,gc_pop,gc_clear,gc_discard=gc.push,gc.pop,gc.clear,gc.discard
|
|
||||||
local gc_replaceTransform,gc_present=gc.replaceTransform,gc.present
|
|
||||||
local gc_setColor,gc_setLineWidth=gc.setColor,gc.setLineWidth
|
|
||||||
local gc_draw,gc_line,gc_circle,gc_print=gc.draw,gc.line,gc.circle,gc.print
|
|
||||||
|
|
||||||
local WIDGET,SCR,SCN=WIDGET,SCR,SCN
|
|
||||||
local xOy=SCR.xOy
|
|
||||||
local ITP=xOy.inverseTransformPoint
|
|
||||||
|
|
||||||
local max,min=math.max,math.min
|
|
||||||
|
|
||||||
local devMode
|
|
||||||
local mx,my,mouseShow,cursorSpd=640,360,false,0
|
|
||||||
local jsState={}--map, joystickID->axisStates: {axisName->axisVal}
|
|
||||||
local errData={}--list, each error create {mes={errMes strings},scene=sceneNameStr}
|
|
||||||
|
|
||||||
local function drawCursor(_,x,y)
|
|
||||||
gc_setColor(1,1,1)
|
|
||||||
gc_setLineWidth(2)
|
|
||||||
gc_circle(ms.isDown(1)and'fill'or'line',x,y,6)
|
|
||||||
end
|
|
||||||
local showPowerInfo=true
|
|
||||||
local showClickFX=true
|
|
||||||
local discardCanvas=false
|
|
||||||
local frameMul=100
|
|
||||||
local sleepInterval=1/60
|
|
||||||
local onQuit=NULL
|
|
||||||
|
|
||||||
local batteryImg=GC.DO{31,20,
|
|
||||||
{'fRect',1,0,26,2},
|
|
||||||
{'fRect',1,18,26,2},
|
|
||||||
{'fRect',0,1,2,18},
|
|
||||||
{'fRect',26,1,2,18},
|
|
||||||
{'fRect',29,3,2,14},
|
|
||||||
}
|
|
||||||
local infoCanvas=gc.newCanvas(108,27)
|
|
||||||
local function updatePowerInfo()
|
|
||||||
local state,pow=love.system.getPowerInfo()
|
|
||||||
gc.setCanvas(infoCanvas)
|
|
||||||
gc_push('transform')
|
|
||||||
gc.origin()
|
|
||||||
gc_clear(0,0,0,.25)
|
|
||||||
if state~='unknown'then
|
|
||||||
gc_setLineWidth(4)
|
|
||||||
if state=='nobattery'then
|
|
||||||
gc_setColor(1,1,1)
|
|
||||||
gc_setLineWidth(2)
|
|
||||||
gc_line(74,5,100,22)
|
|
||||||
elseif pow then
|
|
||||||
if state=='charging'then gc_setColor(0,1,0)
|
|
||||||
elseif pow>50 then gc_setColor(1,1,1)
|
|
||||||
elseif pow>26 then gc_setColor(1,1,0)
|
|
||||||
elseif pow==26 then gc_setColor(.5,0,1)
|
|
||||||
else gc_setColor(1,0,0)
|
|
||||||
end
|
|
||||||
gc.rectangle('fill',76,6,pow*.22,14)
|
|
||||||
if pow<100 then
|
|
||||||
FONT.set(15)
|
|
||||||
gc.setColor(COLOR.D)
|
|
||||||
gc_print(pow,77,1)
|
|
||||||
gc_print(pow,77,3)
|
|
||||||
gc_print(pow,79,1)
|
|
||||||
gc_print(pow,79,3)
|
|
||||||
gc_setColor(COLOR.Z)
|
|
||||||
gc_print(pow,78,2)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
gc_draw(batteryImg,73,3)
|
|
||||||
end
|
|
||||||
FONT.set(25)
|
|
||||||
gc_print(os.date("%H:%M"),3,-5)
|
|
||||||
gc_pop()
|
|
||||||
gc.setCanvas()
|
|
||||||
end
|
|
||||||
-------------------------------------------------------------
|
|
||||||
local lastX,lastY=0,0--Last click pos
|
|
||||||
local function _updateMousePos(x,y,dx,dy)
|
|
||||||
if SCN.swapping then return end
|
|
||||||
dx,dy=dx/SCR.k,dy/SCR.k
|
|
||||||
if SCN.mouseMove then SCN.mouseMove(x,y,dx,dy)end
|
|
||||||
if ms.isDown(1)then
|
|
||||||
WIDGET.drag(x,y,dx,dy)
|
|
||||||
else
|
|
||||||
WIDGET.cursorMove(x,y)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
local function _triggerMouseDown(x,y,k)
|
|
||||||
if devMode==1 then
|
|
||||||
print(("(%d,%d)<-%d,%d ~~(%d,%d)<-%d,%d"):format(
|
|
||||||
x,y,
|
|
||||||
x-lastX,y-lastY,
|
|
||||||
math.floor(x/10)*10,math.floor(y/10)*10,
|
|
||||||
math.floor((x-lastX)/10)*10,math.floor((y-lastY)/10)*10
|
|
||||||
))
|
|
||||||
end
|
|
||||||
if SCN.swapping then return end
|
|
||||||
if SCN.mouseDown then SCN.mouseDown(x,y,k)end
|
|
||||||
WIDGET.press(x,y,k)
|
|
||||||
lastX,lastY=x,y
|
|
||||||
if showClickFX then SYSFX.newTap(3,x,y)end
|
|
||||||
end
|
|
||||||
local function mouse_update(dt)
|
|
||||||
if not KBisDown('lctrl','rctrl')and KBisDown('up','down','left','right')then
|
|
||||||
local dx,dy=0,0
|
|
||||||
if KBisDown('up')then dy=dy-cursorSpd end
|
|
||||||
if KBisDown('down')then dy=dy+cursorSpd end
|
|
||||||
if KBisDown('left')then dx=dx-cursorSpd end
|
|
||||||
if KBisDown('right')then dx=dx+cursorSpd end
|
|
||||||
mx=max(min(mx+dx,1280),0)
|
|
||||||
my=max(min(my+dy,720),0)
|
|
||||||
if my==0 or my==720 then
|
|
||||||
WIDGET.sel=false
|
|
||||||
WIDGET.drag(0,0,0,-dy)
|
|
||||||
end
|
|
||||||
_updateMousePos(mx,my,dx,dy)
|
|
||||||
cursorSpd=min(cursorSpd+dt*26,12.6)
|
|
||||||
else
|
|
||||||
cursorSpd=6
|
|
||||||
end
|
|
||||||
end
|
|
||||||
local function gp_update(js,dt)
|
|
||||||
local sx,sy=js._jsObj:getGamepadAxis('leftx'),js._jsObj:getGamepadAxis('lefty')
|
|
||||||
if math.abs(sx)>.1 or math.abs(sy)>.1 then
|
|
||||||
local dx,dy=0,0
|
|
||||||
if sy<-.1 then dy=dy+2*sy*cursorSpd end
|
|
||||||
if sy>.1 then dy=dy+2*sy*cursorSpd end
|
|
||||||
if sx<-.1 then dx=dx+2*sx*cursorSpd end
|
|
||||||
if sx>.1 then dx=dx+2*sx*cursorSpd end
|
|
||||||
mx=max(min(mx+dx,1280),0)
|
|
||||||
my=max(min(my+dy,720),0)
|
|
||||||
if my==0 or my==720 then
|
|
||||||
WIDGET.sel=false
|
|
||||||
WIDGET.drag(0,0,0,-dy)
|
|
||||||
end
|
|
||||||
_updateMousePos(mx,my,dx,dy)
|
|
||||||
cursorSpd=min(cursorSpd+dt*26,12.6)
|
|
||||||
else
|
|
||||||
cursorSpd=6
|
|
||||||
end
|
|
||||||
end
|
|
||||||
function love.mousepressed(x,y,k,touch)
|
|
||||||
if touch then return end
|
|
||||||
mouseShow=true
|
|
||||||
mx,my=ITP(xOy,x,y)
|
|
||||||
_triggerMouseDown(mx,my,k)
|
|
||||||
end
|
|
||||||
function love.mousemoved(x,y,dx,dy,touch)
|
|
||||||
if touch then return end
|
|
||||||
mouseShow=true
|
|
||||||
mx,my=ITP(xOy,x,y)
|
|
||||||
_updateMousePos(mx,my,dx,dy)
|
|
||||||
end
|
|
||||||
function love.mousereleased(x,y,k,touch)
|
|
||||||
if touch or SCN.swapping then return end
|
|
||||||
mx,my=ITP(xOy,x,y)
|
|
||||||
if SCN.mouseUp then SCN.mouseUp(mx,my,k)end
|
|
||||||
if WIDGET.sel then
|
|
||||||
WIDGET.release(mx,my)
|
|
||||||
else
|
|
||||||
if lastX and SCN.mouseClick and(mx-lastX)^2+(my-lastY)^2<62 then
|
|
||||||
SCN.mouseClick(mx,my,k)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
function love.wheelmoved(x,y)
|
|
||||||
if SCN.swapping then return end
|
|
||||||
if SCN.wheelMoved then
|
|
||||||
SCN.wheelMoved(x,y)
|
|
||||||
else
|
|
||||||
WIDGET.unFocus()
|
|
||||||
WIDGET.drag(0,0,0,100*y)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function love.touchpressed(id,x,y)
|
|
||||||
mouseShow=false
|
|
||||||
if SCN.swapping then return end
|
|
||||||
if not SCN.mainTouchID then
|
|
||||||
SCN.mainTouchID=id
|
|
||||||
WIDGET.unFocus(true)
|
|
||||||
love.touchmoved(id,x,y,0,0)
|
|
||||||
end
|
|
||||||
x,y=ITP(xOy,x,y)
|
|
||||||
lastX,lastY=x,y
|
|
||||||
WIDGET.cursorMove(x,y)
|
|
||||||
if SCN.touchDown then SCN.touchDown(x,y,id)end
|
|
||||||
if kb.hasTextInput()then kb.setTextInput(false)end
|
|
||||||
end
|
|
||||||
function love.touchmoved(id,x,y,dx,dy)
|
|
||||||
if SCN.swapping then return end
|
|
||||||
x,y=ITP(xOy,x,y)
|
|
||||||
if SCN.touchMove then SCN.touchMove(x,y,dx/SCR.k,dy/SCR.k,id)end
|
|
||||||
WIDGET.drag(x,y,dx/SCR.k,dy/SCR.k)
|
|
||||||
end
|
|
||||||
function love.touchreleased(id,x,y)
|
|
||||||
if SCN.swapping then return end
|
|
||||||
x,y=ITP(xOy,x,y)
|
|
||||||
if id==SCN.mainTouchID then
|
|
||||||
WIDGET.press(x,y,1)
|
|
||||||
WIDGET.release(x,y)
|
|
||||||
WIDGET.cursorMove(x,y)
|
|
||||||
WIDGET.unFocus()
|
|
||||||
SCN.mainTouchID=false
|
|
||||||
end
|
|
||||||
if SCN.touchUp then SCN.touchUp(x,y,id)end
|
|
||||||
if(x-lastX)^2+(y-lastY)^2<62 then
|
|
||||||
if SCN.touchClick then SCN.touchClick(x,y)end
|
|
||||||
if showClickFX then SYSFX.newTap(3,x,y)end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local fnKey={NULL,NULL,NULL,NULL,NULL,NULL,NULL}
|
|
||||||
local function noDevkeyPressed(key)
|
|
||||||
if key=='f1'then fnKey[1]()
|
|
||||||
elseif key=='f2'then fnKey[2]()
|
|
||||||
elseif key=='f3'then fnKey[3]()
|
|
||||||
elseif key=='f4'then fnKey[4]()
|
|
||||||
elseif key=='f5'then fnKey[5]()
|
|
||||||
elseif key=='f6'then fnKey[6]()
|
|
||||||
elseif key=='f7'then fnKey[7]()
|
|
||||||
elseif key=='f8'then devMode=nil MES.new('info',"DEBUG OFF",.2)
|
|
||||||
elseif key=='f9'then devMode=1 MES.new('info',"DEBUG 1")
|
|
||||||
elseif key=='f10'then devMode=2 MES.new('info',"DEBUG 2")
|
|
||||||
elseif key=='f11'then devMode=3 MES.new('info',"DEBUG 3")
|
|
||||||
elseif key=='f12'then devMode=4 MES.new('info',"DEBUG 4")
|
|
||||||
elseif devMode==2 then
|
|
||||||
local W=WIDGET.sel
|
|
||||||
if W then
|
|
||||||
if key=='left'then W.x=W.x-10
|
|
||||||
elseif key=='right'then W.x=W.x+10
|
|
||||||
elseif key=='up'then W.y=W.y-10
|
|
||||||
elseif key=='down'then W.y=W.y+10
|
|
||||||
elseif key==','then W.w=W.w-10
|
|
||||||
elseif key=='.'then W.w=W.w+10
|
|
||||||
elseif key=='/'then W.h=W.h-10
|
|
||||||
elseif key=='\''then W.h=W.h+10
|
|
||||||
elseif key=='['then W.font=W.font-5
|
|
||||||
elseif key==']'then W.font=W.font+5
|
|
||||||
else return true
|
|
||||||
end
|
|
||||||
else
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
else
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
function love.keypressed(key,_,isRep)
|
|
||||||
mouseShow=false
|
|
||||||
if devMode and not noDevkeyPressed(key)then
|
|
||||||
return
|
|
||||||
elseif key=='f8'then
|
|
||||||
devMode=1
|
|
||||||
MES.new('info',"DEBUG ON",.2)
|
|
||||||
elseif key=='f11'then
|
|
||||||
SETTING.fullscreen=not SETTING.fullscreen
|
|
||||||
applySettings()
|
|
||||||
saveSettings()
|
|
||||||
elseif not SCN.swapping then
|
|
||||||
if EDITING==""and(not SCN.keyDown or SCN.keyDown(key,isRep))then
|
|
||||||
local W=WIDGET.sel
|
|
||||||
if key=='escape'and not isRep then
|
|
||||||
SCN.back()
|
|
||||||
elseif key=='up'or key=='down'or key=='left'or key=='right'then
|
|
||||||
mouseShow=true
|
|
||||||
if KBisDown('lctrl','rctrl')then
|
|
||||||
if W and W.arrowKey then W:arrowKey(key)end
|
|
||||||
end
|
|
||||||
elseif key=='space'or key=='return'then
|
|
||||||
mouseShow=true
|
|
||||||
if not isRep then
|
|
||||||
if showClickFX then SYSFX.newTap(3,mx,my)end
|
|
||||||
_triggerMouseDown(mx,my,1)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
if W and W.keypress then
|
|
||||||
W:keypress(key)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
function love.keyreleased(i)
|
|
||||||
if SCN.swapping then return end
|
|
||||||
if SCN.keyUp then SCN.keyUp(i)end
|
|
||||||
end
|
|
||||||
|
|
||||||
function love.textedited(texts)
|
|
||||||
EDITING=texts
|
|
||||||
end
|
|
||||||
function love.textinput(texts)
|
|
||||||
WIDGET.textinput(texts)
|
|
||||||
end
|
|
||||||
|
|
||||||
--analog sticks: -1, 0, 1 for neg, neutral, pos
|
|
||||||
--triggers: 0 for released, 1 for pressed
|
|
||||||
local jsAxisEventName={
|
|
||||||
leftx={'leftstick_left','leftstick_right'},
|
|
||||||
lefty={'leftstick_up','leftstick_down'},
|
|
||||||
rightx={'rightstick_left','rightstick_right'},
|
|
||||||
righty={'rightstick_up','rightstick_down'},
|
|
||||||
triggerleft='triggerleft',
|
|
||||||
triggerright='triggerright'
|
|
||||||
}
|
|
||||||
local gamePadKeys={'a','b','x','y','back','guide','start','leftstick','rightstick','leftshoulder','rightshoulder','dpup','dpdown','dpleft','dpright'}
|
|
||||||
local dPadToKey={
|
|
||||||
dpup='up',
|
|
||||||
dpdown='down',
|
|
||||||
dpleft='left',
|
|
||||||
dpright='right',
|
|
||||||
start='return',
|
|
||||||
back='escape',
|
|
||||||
}
|
|
||||||
function love.joystickadded(JS)
|
|
||||||
table.insert(jsState,{
|
|
||||||
_id=JS:getID(),
|
|
||||||
_jsObj=JS,
|
|
||||||
leftx=0,lefty=0,
|
|
||||||
rightx=0,righty=0,
|
|
||||||
triggerleft=0,triggerright=0
|
|
||||||
})
|
|
||||||
MES.new('info',"Joystick added")
|
|
||||||
end
|
|
||||||
function love.joystickremoved(JS)
|
|
||||||
for i=1,#jsState do
|
|
||||||
if jsState[i]._jsObj==JS then
|
|
||||||
for j=1,#gamePadKeys do
|
|
||||||
if JS:isGamepadDown(gamePadKeys[j])then
|
|
||||||
love.gamepadreleased(JS,gamePadKeys[j])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
love.gamepadaxis(JS,'leftx',0)
|
|
||||||
love.gamepadaxis(JS,'lefty',0)
|
|
||||||
love.gamepadaxis(JS,'rightx',0)
|
|
||||||
love.gamepadaxis(JS,'righty',0)
|
|
||||||
love.gamepadaxis(JS,'triggerleft',-1)
|
|
||||||
love.gamepadaxis(JS,'triggerright',-1)
|
|
||||||
MES.new('info',"Joystick removed")
|
|
||||||
table.remove(jsState,i)
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
function love.gamepadaxis(JS,axis,val)
|
|
||||||
if jsState[1]and JS==jsState[1]._jsObj then
|
|
||||||
local js=jsState[1]
|
|
||||||
if axis=='leftx'or axis=='lefty'or axis=='rightx'or axis=='righty'then
|
|
||||||
local newVal=--range: [0,1]
|
|
||||||
val>.4 and 1 or
|
|
||||||
val<-.4 and -1 or
|
|
||||||
0
|
|
||||||
if newVal~=js[axis]then
|
|
||||||
if js[axis]==-1 then
|
|
||||||
love.gamepadreleased(JS,jsAxisEventName[axis][1])
|
|
||||||
elseif js[axis]~=0 then
|
|
||||||
love.gamepadreleased(JS,jsAxisEventName[axis][2])
|
|
||||||
end
|
|
||||||
if newVal==-1 then
|
|
||||||
love.gamepadpressed(JS,jsAxisEventName[axis][1])
|
|
||||||
elseif newVal==1 then
|
|
||||||
love.gamepadpressed(JS,jsAxisEventName[axis][2])
|
|
||||||
end
|
|
||||||
js[axis]=newVal
|
|
||||||
end
|
|
||||||
elseif axis=='triggerleft'or axis=='triggerright'then
|
|
||||||
local newVal=val>.3 and 1 or 0--range: [0,1]
|
|
||||||
if newVal~=js[axis]then
|
|
||||||
if newVal==1 then
|
|
||||||
love.gamepadpressed(JS,jsAxisEventName[axis])
|
|
||||||
else
|
|
||||||
love.gamepadreleased(JS,jsAxisEventName[axis])
|
|
||||||
end
|
|
||||||
js[axis]=newVal
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
function love.gamepadpressed(_,key)
|
|
||||||
mouseShow=false
|
|
||||||
if not SCN.swapping then
|
|
||||||
local cursorCtrl
|
|
||||||
if SCN.gamepadDown then
|
|
||||||
cursorCtrl=SCN.gamepadDown(key)
|
|
||||||
elseif SCN.keyDown then
|
|
||||||
cursorCtrl=SCN.keyDown(dPadToKey[key]or key)
|
|
||||||
else
|
|
||||||
cursorCtrl=true
|
|
||||||
end
|
|
||||||
if cursorCtrl then
|
|
||||||
key=dPadToKey[key]or key
|
|
||||||
mouseShow=true
|
|
||||||
local W=WIDGET.sel
|
|
||||||
if key=='back'then
|
|
||||||
SCN.back()
|
|
||||||
elseif key=='up'or key=='down'or key=='left'or key=='right'then
|
|
||||||
mouseShow=true
|
|
||||||
if W and W.arrowKey then W:arrowKey(key)end
|
|
||||||
elseif key=='return'then
|
|
||||||
mouseShow=true
|
|
||||||
if showClickFX then SYSFX.newTap(3,mx,my)end
|
|
||||||
_triggerMouseDown(mx,my,1)
|
|
||||||
else
|
|
||||||
if W and W.keypress then
|
|
||||||
W:keypress(key)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
function love.gamepadreleased(_,i)
|
|
||||||
if SCN.swapping then return end
|
|
||||||
if SCN.gamepadUp then SCN.gamepadUp(i)end
|
|
||||||
end
|
|
||||||
|
|
||||||
function love.filedropped(file)
|
|
||||||
if SCN.fileDropped then SCN.fileDropped(file)end
|
|
||||||
end
|
|
||||||
function love.directorydropped(dir)
|
|
||||||
if SCN.directoryDropped then SCN.directoryDropped(dir)end
|
|
||||||
end
|
|
||||||
local autoGCcount=0
|
|
||||||
function love.lowmemory()
|
|
||||||
collectgarbage()
|
|
||||||
if autoGCcount<3 then
|
|
||||||
autoGCcount=autoGCcount+1
|
|
||||||
MES.new('check',"[auto GC] low MEM 设备内存过低")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local onResize=NULL
|
|
||||||
function love.resize(w,h)
|
|
||||||
if SCR.w==w and SCR.h==h then return end
|
|
||||||
SCR.resize(w,h)
|
|
||||||
if BG.resize then BG.resize(w,h)end
|
|
||||||
if SCN.resize then SCN.resize(w,h)end
|
|
||||||
WIDGET.resize(w,h)
|
|
||||||
FONT.reset()
|
|
||||||
onResize(w,h)
|
|
||||||
end
|
|
||||||
|
|
||||||
local onFocus=NULL
|
|
||||||
function love.focus(f)onFocus(f)end
|
|
||||||
|
|
||||||
local yield=coroutine.yield
|
|
||||||
local function secondLoopThread()
|
|
||||||
local mainLoop=love.run()
|
|
||||||
repeat yield()until mainLoop()
|
|
||||||
end
|
|
||||||
function love.errorhandler(msg)
|
|
||||||
if type(msg)~='string'then
|
|
||||||
msg="Unknown error"
|
|
||||||
elseif msg:find("Invalid UTF-8")and text then
|
|
||||||
msg=text.tryAnotherBuild
|
|
||||||
end
|
|
||||||
|
|
||||||
--Generate error message
|
|
||||||
local err={"Error:"..msg}
|
|
||||||
local c=2
|
|
||||||
for l in debug.traceback("",2):gmatch("(.-)\n")do
|
|
||||||
if c>2 then
|
|
||||||
if not l:find("boot")then
|
|
||||||
err[c]=l:gsub("^\t*","")
|
|
||||||
c=c+1
|
|
||||||
end
|
|
||||||
else
|
|
||||||
err[2]="Traceback"
|
|
||||||
c=3
|
|
||||||
end
|
|
||||||
end
|
|
||||||
print(table.concat(err,"\n",1,c-2))
|
|
||||||
|
|
||||||
--Reset something
|
|
||||||
love.audio.stop()
|
|
||||||
gc.reset()
|
|
||||||
|
|
||||||
if LOADED and #errData<3 then
|
|
||||||
BG.set('none')
|
|
||||||
local scn=SCN and SCN.cur or"NULL"
|
|
||||||
table.insert(errData,{mes=err,scene=scn})
|
|
||||||
|
|
||||||
--Write messages to log file
|
|
||||||
love.filesystem.append('conf/error.log',
|
|
||||||
os.date("%Y/%m/%d %A %H:%M:%S\n")..
|
|
||||||
#errData.." crash(es) "..love.system.getOS().."-"..VERSION.string.." scene: "..scn.."\n"..
|
|
||||||
table.concat(err,"\n",1,c-2).."\n\n"
|
|
||||||
)
|
|
||||||
|
|
||||||
--Get screencapture
|
|
||||||
gc.captureScreenshot(function(_)errData[#errData].shot=gc.newImage(_)end)
|
|
||||||
gc.present()
|
|
||||||
|
|
||||||
--Create a new mainLoop thread to keep game alive
|
|
||||||
local status,resume=coroutine.status,coroutine.resume
|
|
||||||
local loopThread=coroutine.create(secondLoopThread)
|
|
||||||
local res,threadErr
|
|
||||||
repeat
|
|
||||||
res,threadErr=resume(loopThread)
|
|
||||||
until status(loopThread)=='dead'
|
|
||||||
if not res then
|
|
||||||
love.errorhandler(threadErr)
|
|
||||||
return
|
|
||||||
end
|
|
||||||
else
|
|
||||||
ms.setVisible(true)
|
|
||||||
|
|
||||||
local errorMsg
|
|
||||||
errorMsg=LOADED and
|
|
||||||
"Too many errors or fatal error occured.\nPlease restart the game."or
|
|
||||||
"An error has occurred during loading.\nError info has been created, and you can send it to the author."
|
|
||||||
while true do
|
|
||||||
love.event.pump()
|
|
||||||
for E,a,b in love.event.poll()do
|
|
||||||
if E=='quit'or a=='escape'then
|
|
||||||
return true
|
|
||||||
elseif E=='resize'then
|
|
||||||
SCR.resize(a,b)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
gc_clear(.3,.5,.9)
|
|
||||||
gc_push('transform')
|
|
||||||
gc_replaceTransform(SCR.xOy)
|
|
||||||
FONT.set(100)gc_print(":(",100,0,0,1.2)
|
|
||||||
FONT.set(40)gc.printf(errorMsg,100,160,SCR.w0-100)
|
|
||||||
FONT.set(20)
|
|
||||||
gc_print(love.system.getOS().."-"..VERSION.string.." scene:"..(SCN and SCN.cur or"NULL"),100,660)
|
|
||||||
gc.printf(err[1],100,360,1260-100)
|
|
||||||
gc_print("TRACEBACK",100,450)
|
|
||||||
for i=4,#err-2 do
|
|
||||||
gc_print(err[i],100,400+20*i)
|
|
||||||
end
|
|
||||||
gc_pop()
|
|
||||||
gc_present()
|
|
||||||
love.timer.sleep(.26)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
love.threaderror=nil
|
|
||||||
|
|
||||||
love.draw,love.update=nil--remove default draw/update
|
|
||||||
|
|
||||||
local devColor={
|
|
||||||
COLOR.Z,
|
|
||||||
COLOR.lM,
|
|
||||||
COLOR.lG,
|
|
||||||
COLOR.lB,
|
|
||||||
}
|
|
||||||
local WS=WS
|
|
||||||
local WSnames={'app','user','play','stream','chat','manage'}
|
|
||||||
local wsImg={}do
|
|
||||||
local L={78,18,
|
|
||||||
{'clear',1,1,1,0},
|
|
||||||
{'setCL',1,1,1,.3},
|
|
||||||
{'fRect',60,0,18,18},
|
|
||||||
}
|
|
||||||
for i=0,59 do
|
|
||||||
table.insert(L,{'setCL',1,1,1,i*.005})
|
|
||||||
table.insert(L,{'fRect',i,0,1,18})
|
|
||||||
end
|
|
||||||
wsImg.bottom=GC.DO(L)
|
|
||||||
wsImg.dead=GC.DO{20,20,
|
|
||||||
{'rawFT',20},
|
|
||||||
{'setCL',1,.3,.3},
|
|
||||||
{'mText',"X",11,-1},
|
|
||||||
}
|
|
||||||
wsImg.connecting=GC.DO{20,20,
|
|
||||||
{'rawFT',20},
|
|
||||||
{'setLW',3},
|
|
||||||
{'mText',"C",11,-1},
|
|
||||||
}
|
|
||||||
wsImg.running=GC.DO{20,20,
|
|
||||||
{'rawFT',20},
|
|
||||||
{'setCL',.5,1,0},
|
|
||||||
{'mText',"R",11,-1},
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
local debugInfos={
|
|
||||||
{"Cache",gcinfo},
|
|
||||||
}
|
|
||||||
function love.run()
|
|
||||||
local love=love
|
|
||||||
|
|
||||||
local BG=BG
|
|
||||||
local TEXT_update,TEXT_draw=TEXT.update,TEXT.draw
|
|
||||||
local MES_update,MES_draw=MES.update,MES.draw
|
|
||||||
local WS_update=WS.update
|
|
||||||
local TASK_update=TASK.update
|
|
||||||
local SYSFX_update,SYSFX_draw=SYSFX.update,SYSFX.draw
|
|
||||||
local WIDGET_update,WIDGET_draw=WIDGET.update,WIDGET.draw
|
|
||||||
local STEP,WAIT=love.timer.step,love.timer.sleep
|
|
||||||
local FPS,MINI=love.timer.getFPS,love.window.isMinimized
|
|
||||||
local PUMP,POLL=love.event.pump,love.event.poll
|
|
||||||
|
|
||||||
local timer,VERSION=love.timer.getTime,VERSION
|
|
||||||
|
|
||||||
local frameTimeList={}
|
|
||||||
local lastFrame=timer()
|
|
||||||
local lastFreshPow=lastFrame
|
|
||||||
local FCT=0--Framedraw counter, from 0~99
|
|
||||||
|
|
||||||
love.resize(gc.getWidth(),gc.getHeight())
|
|
||||||
|
|
||||||
--Scene Launch
|
|
||||||
while #SCN.stack>0 do SCN.pop()end
|
|
||||||
SCN.push('quit','slowFade')
|
|
||||||
SCN.init(#errData==0 and'load'or'error')
|
|
||||||
|
|
||||||
return function()
|
|
||||||
local _
|
|
||||||
|
|
||||||
local time=timer()
|
|
||||||
local dt=time-lastFrame
|
|
||||||
lastFrame=time
|
|
||||||
|
|
||||||
--EVENT
|
|
||||||
PUMP()
|
|
||||||
for N,a,b,c,d,e in POLL()do
|
|
||||||
if love[N]then
|
|
||||||
love[N](a,b,c,d,e)
|
|
||||||
elseif N=='quit'then
|
|
||||||
onQuit()
|
|
||||||
return a or true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--UPDATE
|
|
||||||
STEP()
|
|
||||||
if mouseShow then mouse_update(dt)end
|
|
||||||
if next(jsState)then gp_update(jsState[1],dt)end
|
|
||||||
VOC.update()
|
|
||||||
BG.update(dt)
|
|
||||||
TEXT_update(dt)
|
|
||||||
MES_update(dt)
|
|
||||||
WS_update(dt)
|
|
||||||
TASK_update(dt)
|
|
||||||
SYSFX_update(dt)
|
|
||||||
if SCN.update then SCN.update(dt)end
|
|
||||||
if SCN.swapping then SCN.swapUpdate(dt)end
|
|
||||||
WIDGET_update(dt)
|
|
||||||
|
|
||||||
--DRAW
|
|
||||||
if not MINI()then
|
|
||||||
FCT=FCT+frameMul
|
|
||||||
if FCT>=100 then
|
|
||||||
FCT=FCT-100
|
|
||||||
|
|
||||||
gc_replaceTransform(SCR.origin)
|
|
||||||
gc_setColor(1,1,1)
|
|
||||||
BG.draw()
|
|
||||||
gc_replaceTransform(SCR.xOy)
|
|
||||||
if SCN.draw then SCN.draw()end
|
|
||||||
WIDGET_draw()
|
|
||||||
SYSFX_draw()
|
|
||||||
TEXT_draw()
|
|
||||||
|
|
||||||
--Draw cursor
|
|
||||||
if mouseShow then drawCursor(time,mx,my)end
|
|
||||||
gc_replaceTransform(SCR.xOy_ul)
|
|
||||||
MES_draw()
|
|
||||||
gc_replaceTransform(SCR.origin)
|
|
||||||
--Draw power info.
|
|
||||||
if showPowerInfo then
|
|
||||||
gc_setColor(1,1,1)
|
|
||||||
gc_draw(infoCanvas,SCR.safeX,0,0,SCR.k)
|
|
||||||
end
|
|
||||||
|
|
||||||
--Draw scene swapping animation
|
|
||||||
if SCN.swapping then
|
|
||||||
gc_setColor(1,1,1)
|
|
||||||
_=SCN.stat
|
|
||||||
_.draw(_.time)
|
|
||||||
end
|
|
||||||
gc_replaceTransform(SCR.xOy_d)
|
|
||||||
--Draw Version string
|
|
||||||
gc_setColor(.9,.9,.9,.42)
|
|
||||||
FONT.set(20)
|
|
||||||
mStr(VERSION.string,0,-30)
|
|
||||||
gc_replaceTransform(SCR.xOy_dl)
|
|
||||||
local safeX=SCR.safeX/SCR.k
|
|
||||||
|
|
||||||
--Draw FPS
|
|
||||||
FONT.set(15)
|
|
||||||
gc_setColor(1,1,1)
|
|
||||||
gc_print(FPS(),safeX+5,-20)
|
|
||||||
|
|
||||||
--Debug info.
|
|
||||||
if devMode then
|
|
||||||
--Debug infos at left-down
|
|
||||||
gc_setColor(devColor[devMode])
|
|
||||||
|
|
||||||
--Text infos
|
|
||||||
for i=1,#debugInfos do
|
|
||||||
gc_print(debugInfos[i][1],safeX+5,-20-20*i)
|
|
||||||
gc_print(debugInfos[i][2](),safeX+62.6,-20-20*i)
|
|
||||||
end
|
|
||||||
|
|
||||||
--Update & draw frame time
|
|
||||||
table.insert(frameTimeList,1,dt)table.remove(frameTimeList,126)
|
|
||||||
gc_setColor(1,1,1,.3)
|
|
||||||
for i=1,#frameTimeList do
|
|
||||||
gc.rectangle('fill',150+2*i,-20,2,-frameTimeList[i]*4000)
|
|
||||||
end
|
|
||||||
|
|
||||||
--Cursor pos disp
|
|
||||||
gc_replaceTransform(SCR.origin)
|
|
||||||
local x,y=SCR.xOy:transformPoint(mx,my)
|
|
||||||
gc_setLineWidth(1)
|
|
||||||
gc_line(x,0,x,SCR.h)
|
|
||||||
gc_line(0,y,SCR.w,y)
|
|
||||||
local t=math.floor(mx+.5)..","..math.floor(my+.5)
|
|
||||||
gc.setColor(COLOR.D)
|
|
||||||
gc_print(t,x+1,y)
|
|
||||||
gc_print(t,x+1,y-1)
|
|
||||||
gc_print(t,x+2,y-1)
|
|
||||||
gc_setColor(COLOR.Z)
|
|
||||||
gc_print(t,x+2,y)
|
|
||||||
|
|
||||||
gc_replaceTransform(SCR.xOy_dr)
|
|
||||||
--Websocket status
|
|
||||||
for i=1,6 do
|
|
||||||
local status=WS.status(WSnames[i])
|
|
||||||
gc_setColor(1,1,1)
|
|
||||||
gc.draw(wsImg.bottom,-79,20*i-139)
|
|
||||||
if status=='dead'then
|
|
||||||
gc_draw(wsImg.dead,-20,20*i-140)
|
|
||||||
elseif status=='connecting'then
|
|
||||||
gc_setColor(1,1,1,.5+.3*math.sin(time*6.26))
|
|
||||||
gc_draw(wsImg.connecting,-20,20*i-140)
|
|
||||||
elseif status=='running'then
|
|
||||||
gc_draw(wsImg.running,-20,20*i-140)
|
|
||||||
end
|
|
||||||
local t1,t2,t3=WS.getTimers(WSnames[i])
|
|
||||||
gc_setColor(.9,.9,.9,t1)gc.rectangle('fill',-60,20*i-122,-16,-16)
|
|
||||||
gc_setColor(.3,1,.3,t2)gc.rectangle('fill',-42,20*i-122,-16,-16)
|
|
||||||
gc_setColor(1,.2,.2,t3)gc.rectangle('fill',-24,20*i-122,-16,-16)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
gc_present()
|
|
||||||
|
|
||||||
--SPEED UPUPUP!
|
|
||||||
if discardCanvas then gc_discard()end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--Fresh power info.
|
|
||||||
if time-lastFreshPow>2.6 then
|
|
||||||
if showPowerInfo then
|
|
||||||
updatePowerInfo()
|
|
||||||
lastFreshPow=time
|
|
||||||
end
|
|
||||||
if gc.getWidth()~=SCR.w or gc.getHeight()~=SCR.h then
|
|
||||||
love.resize(gc.getWidth(),gc.getHeight())
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--Slow devmode
|
|
||||||
if devMode then
|
|
||||||
if devMode==3 then
|
|
||||||
WAIT(.1)
|
|
||||||
elseif devMode==4 then
|
|
||||||
WAIT(.5)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
_=timer()-lastFrame
|
|
||||||
if _<sleepInterval*.9626 then WAIT(sleepInterval*.9626-_)end
|
|
||||||
while timer()-lastFrame<sleepInterval do end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local Z={}
|
|
||||||
|
|
||||||
function Z.getJsState()return jsState end
|
|
||||||
function Z.getErr(i)
|
|
||||||
if i=='#'then
|
|
||||||
return errData[#errData]
|
|
||||||
elseif i then
|
|
||||||
return errData[i]
|
|
||||||
else
|
|
||||||
return errData
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function Z.setPowerInfo(bool)showPowerInfo=bool end
|
|
||||||
function Z.setCleanCanvas(bool)discardCanvas=bool end
|
|
||||||
function Z.setFrameMul(n)frameMul=n end
|
|
||||||
function Z.setMaxFPS(fps)sleepInterval=1/fps end
|
|
||||||
function Z.setClickFX(bool)showClickFX=bool end
|
|
||||||
|
|
||||||
--[Warning] Color and line width is uncertain value, set it in the function.
|
|
||||||
function Z.setCursor(func)drawCursor=func end
|
|
||||||
|
|
||||||
--Change F1~F7 events of devmode (F8 mode)
|
|
||||||
function Z.setOnFnKeys(list)
|
|
||||||
assert(type(list)=='table',"Z.setOnFnKeys(list): list must be a table")
|
|
||||||
for i=1,7 do fnKey[i]=assert(type(list[i])=='function'and list[i])end
|
|
||||||
end
|
|
||||||
|
|
||||||
function Z.setDebugInfo(list)
|
|
||||||
assert(type(list)=='table',"Z.setDebugInfo(list): list must be a table")
|
|
||||||
for i=1,#list do
|
|
||||||
assert(type(list[i][1])=='string',"Z.setDebugInfo(list): list[i][1] must be a string")
|
|
||||||
assert(type(list[i][2])=='function',"Z.setDebugInfo(list): list[i][2] must be a function")
|
|
||||||
end
|
|
||||||
debugInfos=list
|
|
||||||
end
|
|
||||||
|
|
||||||
function Z.setOnFocus(func)
|
|
||||||
onFocus=assert(type(func)=='function'and func,"Z.setOnFocus(func): func must be a function")
|
|
||||||
end
|
|
||||||
|
|
||||||
function Z.setOnResize(func)
|
|
||||||
onResize=assert(type(func)=='function'and func,"Z.setOnResize(func): func must be a function")
|
|
||||||
end
|
|
||||||
|
|
||||||
function Z.setOnQuit(func)
|
|
||||||
onQuit=assert(type(func)=='function'and func,"Z.setOnQuit(func): func must be a function")
|
|
||||||
end
|
|
||||||
|
|
||||||
return Z
|
|
||||||
@@ -1,340 +0,0 @@
|
|||||||
-- json.lua
|
|
||||||
|
|
||||||
-- Copyright (c) 2020 rxi
|
|
||||||
|
|
||||||
-- Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
||||||
-- this software and associated documentation files (the "Software"), to deal in
|
|
||||||
-- the Software without restriction, including without limitation the rights to
|
|
||||||
-- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
||||||
-- of the Software, and to permit persons to whom the Software is furnished to do
|
|
||||||
-- so, subject to the following conditions:
|
|
||||||
|
|
||||||
-- The above copyright notice and this permission notice shall be included in all
|
|
||||||
-- copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
-- SOFTWARE.
|
|
||||||
|
|
||||||
-- Editted by MrZ
|
|
||||||
|
|
||||||
local ins,char=table.insert,string.char
|
|
||||||
local json = {}
|
|
||||||
|
|
||||||
-------------------------------------------------------------------------------
|
|
||||||
-- Encode
|
|
||||||
-------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
local _encode
|
|
||||||
|
|
||||||
local escape_char_map = {
|
|
||||||
["\\"] = "\\",
|
|
||||||
["\""] = "\"",
|
|
||||||
["\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()))
|
|
||||||
end
|
|
||||||
|
|
||||||
local function encode_nil() return "null" end
|
|
||||||
|
|
||||||
local function encode_table(val, stack)
|
|
||||||
local res = {}
|
|
||||||
stack = stack or {}
|
|
||||||
|
|
||||||
-- Circular reference?
|
|
||||||
if stack[val] then error("circular reference") end
|
|
||||||
|
|
||||||
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, ",") .. "]"
|
|
||||||
|
|
||||||
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) .. '"'
|
|
||||||
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)
|
|
||||||
end
|
|
||||||
|
|
||||||
local type_func_map = {
|
|
||||||
['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 .. "'")
|
|
||||||
end
|
|
||||||
|
|
||||||
json.encode=_encode
|
|
||||||
|
|
||||||
-------------------------------------------------------------------------------
|
|
||||||
-- Decode
|
|
||||||
-------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
local parse
|
|
||||||
|
|
||||||
local function create_set(...)
|
|
||||||
local res = {}
|
|
||||||
for i = 1, select("#", ...) do res[select(i, ...)] = true end
|
|
||||||
return res
|
|
||||||
end
|
|
||||||
|
|
||||||
local space_chars = create_set(" ", "\t", "\r", "\n")
|
|
||||||
local delim_chars = create_set(" ", "\t", "\r", "\n", "]", "}", ",")
|
|
||||||
local escape_chars = create_set("\\", "/", '"', "b", "f", "n", "r", "t", "u")
|
|
||||||
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
|
|
||||||
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))
|
|
||||||
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))
|
|
||||||
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
|
|
||||||
end
|
|
||||||
|
|
||||||
local function parse_string(str, i)
|
|
||||||
local res = ""
|
|
||||||
local j = i + 1
|
|
||||||
local k = j
|
|
||||||
|
|
||||||
while j <= #str do
|
|
||||||
local x = str:byte(j)
|
|
||||||
|
|
||||||
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 == 34 then -- `"`: End of string
|
|
||||||
res = res .. str:sub(k, j - 1)
|
|
||||||
return res, j + 1
|
|
||||||
end
|
|
||||||
|
|
||||||
j = j + 1
|
|
||||||
end
|
|
||||||
|
|
||||||
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
|
|
||||||
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
|
|
||||||
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
|
|
||||||
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
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
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 .. "'")
|
|
||||||
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
|
|
||||||
end
|
|
||||||
return json
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
local LANG={}
|
|
||||||
--ONLY FIRST CALL MAKE SENSE
|
|
||||||
--Create LANG.get() and LANG.addScene()
|
|
||||||
function LANG.init(defaultLang,langList,publicText,pretreatFunc)
|
|
||||||
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
|
|
||||||
|
|
||||||
--Set public text
|
|
||||||
if publicText then
|
|
||||||
for _,L in next,langList do
|
|
||||||
for key,list in next,publicText do L[key]=list end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--Fallback to default language
|
|
||||||
for name,L in next,langList do
|
|
||||||
if name~=defaultLang then
|
|
||||||
_langFallback(langList[L.fallback or defaultLang],L)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--Custom pretreatment for each language
|
|
||||||
if pretreatFunc then
|
|
||||||
for _,L in next,langList do
|
|
||||||
pretreatFunc(L)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function LANG.get(l)
|
|
||||||
if not langList[l]then
|
|
||||||
LOG("Wrong language: "..tostring(l))
|
|
||||||
l=defaultLang
|
|
||||||
end
|
|
||||||
return langList[l]
|
|
||||||
end
|
|
||||||
|
|
||||||
function LANG.addScene(name)
|
|
||||||
for _,L in next,langList do
|
|
||||||
if L.WidgetText and not L.WidgetText[name]then
|
|
||||||
L.WidgetText[name]={}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function LANG.init()end
|
|
||||||
end
|
|
||||||
return LANG
|
|
||||||
@@ -1,86 +0,0 @@
|
|||||||
--LIGHT MODULE (Optimized by MrZ, Original on github/LÖVE community/simple-love-lights)
|
|
||||||
--Heavily based on mattdesl's libGDX implementation:
|
|
||||||
--https://github.com/mattdesl/lwjgl-basics/wiki/2D-Pixel-Perfect-Shadows
|
|
||||||
local gc=love.graphics
|
|
||||||
local clear,gc_translate=gc.clear,gc.translate
|
|
||||||
local gc_setCanvas,gc_setShader=gc.setCanvas,gc.setShader
|
|
||||||
local gc_setColor,gc_draw=gc.setColor,gc.draw
|
|
||||||
|
|
||||||
local shadowMapShader=gc.newShader('Zframework/light/shadowMap.glsl')--Shader for caculating the 1D shadow map.
|
|
||||||
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
|
|
||||||
end
|
|
||||||
local function setPow(L,pow)
|
|
||||||
L.size=pow
|
|
||||||
end
|
|
||||||
local function drawLight(L)
|
|
||||||
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)
|
|
||||||
|
|
||||||
--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 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)
|
|
||||||
|
|
||||||
--Ready to final render
|
|
||||||
gc_setShader()gc_setCanvas()gc.setBlendMode('add')
|
|
||||||
|
|
||||||
--Render to screen
|
|
||||||
gc_draw(L.renderCanvas,X,Y+s,0,1,-1)
|
|
||||||
|
|
||||||
--Reset
|
|
||||||
gc.setBlendMode('alpha')
|
|
||||||
end
|
|
||||||
|
|
||||||
local LIGHT={}
|
|
||||||
function LIGHT.draw()
|
|
||||||
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
|
|
||||||
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
|
|
||||||
|
|
||||||
move=move,
|
|
||||||
setPow=setPow,
|
|
||||||
}
|
|
||||||
end
|
|
||||||
return LIGHT
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
#define PI 3.14159
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
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);
|
|
||||||
|
|
||||||
// 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
|
|
||||||
|
|
||||||
+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));
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
#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;
|
|
||||||
|
|
||||||
//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
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
local ins=table.insert
|
|
||||||
|
|
||||||
local logs={os.date("Techmino logs %Y/%m/%d %A")}
|
|
||||||
|
|
||||||
local function log(message)
|
|
||||||
ins(logs,os.date("[%H:%M:%S] ")..message)
|
|
||||||
end
|
|
||||||
|
|
||||||
local LOG=setmetatable({logs=logs},{
|
|
||||||
__call=function(_,message)
|
|
||||||
print(message)
|
|
||||||
log(message)
|
|
||||||
end
|
|
||||||
})
|
|
||||||
|
|
||||||
function LOG.read()
|
|
||||||
return table.concat(logs,"\n")
|
|
||||||
end
|
|
||||||
|
|
||||||
return LOG
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
local MATH={}for k,v in next,math do MATH[k]=v end
|
|
||||||
|
|
||||||
local int,ceil=math.floor,math.ceil
|
|
||||||
local rnd=math.random
|
|
||||||
|
|
||||||
MATH.tau=2*math.pi
|
|
||||||
|
|
||||||
function MATH.sign(a)
|
|
||||||
return a>0 and 1 or a<0 and -1 or 0
|
|
||||||
end
|
|
||||||
|
|
||||||
function MATH.roll(chance)
|
|
||||||
return rnd()<(chance or .5)
|
|
||||||
end
|
|
||||||
|
|
||||||
function MATH.coin(a,b)
|
|
||||||
if rnd()<.5 then
|
|
||||||
return a
|
|
||||||
else
|
|
||||||
return b
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function MATH.interval(v,low,high)
|
|
||||||
if v<=low then
|
|
||||||
return low
|
|
||||||
elseif v>=high then
|
|
||||||
return high
|
|
||||||
else
|
|
||||||
return v
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function MATH.lerp(s,e,t)
|
|
||||||
return s+(e-s)*t
|
|
||||||
end
|
|
||||||
|
|
||||||
do--function MATH.listLerp(list,t)
|
|
||||||
local interval,lerp=MATH.interval,MATH.lerp
|
|
||||||
function MATH.listLerp(list,t)
|
|
||||||
local t2=(#list-1)*interval(t,0,1)+1
|
|
||||||
return lerp(list[int(t2)],list[ceil(t2)],t2%1)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function MATH.expApproach(a,b,k)
|
|
||||||
return b+(a-b)*2.718281828459045^-k
|
|
||||||
end
|
|
||||||
|
|
||||||
return MATH
|
|
||||||
@@ -1,148 +0,0 @@
|
|||||||
local gc=love.graphics
|
|
||||||
local gc_push,gc_pop=gc.push,gc.pop
|
|
||||||
local gc_translate,gc_setColor,gc_draw=gc.translate,gc.setColor,gc.draw
|
|
||||||
|
|
||||||
local ins,rem=table.insert,table.remove
|
|
||||||
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,1},{'fRect',14,11,19,4,1},
|
|
||||||
{'fRect',6,19,4,4,1},{'fRect',14,19,19,4,1},
|
|
||||||
},
|
|
||||||
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,2},
|
|
||||||
{'fRect',17,29,7,7,2},
|
|
||||||
{'setCL',1,1,1},
|
|
||||||
{'fRect',18,11,5,16,2},
|
|
||||||
{'fRect',18,30,5,5,2},
|
|
||||||
},
|
|
||||||
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},
|
|
||||||
},
|
|
||||||
music=GC.DO{40,40,
|
|
||||||
{'setLW',2},
|
|
||||||
{'dRect',1,3,38,34,3},
|
|
||||||
{'setLW',4},
|
|
||||||
{'line',21,26,21,10,28,10},
|
|
||||||
{'fElps',17,26,6,5},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
local MES={}
|
|
||||||
local backColors={
|
|
||||||
check={.3,.6,.3,.7},
|
|
||||||
broadcast={.3,.3,.6,.8},
|
|
||||||
warn={.4,.4,.2,.9},
|
|
||||||
error={.4,.2,.2,.9},
|
|
||||||
music={.2,.4,.4,.9},
|
|
||||||
}
|
|
||||||
function MES.new(icon,str,time)
|
|
||||||
local backColor={.5,.5,.5,.7}
|
|
||||||
if type(icon)=='string'then
|
|
||||||
backColor=backColors[icon]or backColor
|
|
||||||
icon=mesIcon[icon]
|
|
||||||
end
|
|
||||||
local t=gc.newText(FONT.get(30),str)
|
|
||||||
local w=math.max(t:getWidth()+(icon and 45 or 5),200)+15
|
|
||||||
local h=math.max(t:getHeight(),46)+2
|
|
||||||
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,{'mDrawY',t,icon and 50 or 10,h/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
|
|
||||||
})
|
|
||||||
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
|
|
||||||
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+2)
|
|
||||||
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)
|
|
||||||
end
|
|
||||||
|
|
||||||
return MES
|
|
||||||
@@ -1,157 +0,0 @@
|
|||||||
local clock=os.clock
|
|
||||||
|
|
||||||
local profile={}
|
|
||||||
|
|
||||||
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 _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
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Starts collecting data.
|
|
||||||
function profile.start()
|
|
||||||
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()
|
|
||||||
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()
|
|
||||||
end
|
|
||||||
|
|
||||||
local function _comp(a,b)
|
|
||||||
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)
|
|
||||||
|
|
||||||
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
|
|
||||||
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 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
|
|
||||||
end
|
|
||||||
|
|
||||||
-- store all internal profiler functions
|
|
||||||
for _,v in next,profile do
|
|
||||||
_internal[v]=type(v)=='function'
|
|
||||||
end
|
|
||||||
|
|
||||||
return profile
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
package.cpath=package.cpath..';'..SAVEDIR..'/lib/lib?.so;'..'?.dylib'
|
|
||||||
local loaded={}
|
|
||||||
return function(libName)
|
|
||||||
local require=require
|
|
||||||
if love.system.getOS()=='OS X'then
|
|
||||||
require=package.loadlib(libName..'.dylib','luaopen_'..libName)
|
|
||||||
libname=nil
|
|
||||||
elseif love.system.getOS()=='Android'then
|
|
||||||
if not loaded[libName]then
|
|
||||||
local platform=(function()
|
|
||||||
local p=io.popen('uname -m')
|
|
||||||
local arch=p:read('*a'):lower()
|
|
||||||
p:close()
|
|
||||||
if arch:find('v8')or arch:find('64')then
|
|
||||||
return'arm64-v8a'
|
|
||||||
else
|
|
||||||
return'armeabi-v7a'
|
|
||||||
end
|
|
||||||
end)()
|
|
||||||
love.filesystem.write(
|
|
||||||
'lib/libCCloader.so',
|
|
||||||
love.filesystem.read('data','libAndroid/'..platform..'/libCCloader.so')
|
|
||||||
)
|
|
||||||
loaded[libName]=true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
local success,res=pcall(require,libName)
|
|
||||||
if success and res then
|
|
||||||
return res
|
|
||||||
else
|
|
||||||
MES.new('error',"Cannot load "..libName..": "..res)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@@ -1,210 +0,0 @@
|
|||||||
local gc=love.graphics
|
|
||||||
local abs=math.abs
|
|
||||||
|
|
||||||
local scenes={}
|
|
||||||
|
|
||||||
local SCN={
|
|
||||||
mainTouchID=nil, --First touching ID(userdata)
|
|
||||||
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
|
|
||||||
prev=false,
|
|
||||||
args={},--Arguments from previous scene
|
|
||||||
|
|
||||||
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,
|
|
||||||
}--Scene datas, returned
|
|
||||||
|
|
||||||
function SCN.add(name,scene)
|
|
||||||
scenes[name]=scene
|
|
||||||
if scene.widgetList then
|
|
||||||
setmetatable(scene.widgetList,WIDGET.indexMeta)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function SCN.swapUpdate(dt)
|
|
||||||
local S=SCN.stat
|
|
||||||
S.time=S.time-dt
|
|
||||||
if S.time<S.changeTime and S.time+dt>=S.changeTime then
|
|
||||||
--Scene swapped this frame
|
|
||||||
SCN.prev=SCN.cur
|
|
||||||
SCN.init(S.tar)
|
|
||||||
SCN.mainTouchID=nil
|
|
||||||
end
|
|
||||||
if S.time<0 then
|
|
||||||
SCN.swapping=false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
function SCN.init(s)
|
|
||||||
love.keyboard.setTextInput(false)
|
|
||||||
|
|
||||||
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()
|
|
||||||
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
|
|
||||||
end
|
|
||||||
function SCN.pop()
|
|
||||||
local s=SCN.stack
|
|
||||||
s[#s],s[#s-1]=nil
|
|
||||||
end
|
|
||||||
|
|
||||||
local swap={
|
|
||||||
none={
|
|
||||||
duration=0,changeTime=0,
|
|
||||||
draw=function()end
|
|
||||||
},
|
|
||||||
flash={
|
|
||||||
duration=.16,changeTime=.08,
|
|
||||||
draw=function()gc.clear(1,1,1)end
|
|
||||||
},
|
|
||||||
fade={
|
|
||||||
duration=.5,changeTime=.25,
|
|
||||||
draw=function(t)
|
|
||||||
t=t>.25 and 2-t*4 or t*4
|
|
||||||
gc.setColor(0,0,0,t)
|
|
||||||
gc.rectangle('fill',0,0,SCR.w,SCR.h)
|
|
||||||
end
|
|
||||||
},
|
|
||||||
fade_togame={
|
|
||||||
duration=2,changeTime=.5,
|
|
||||||
draw=function(t)
|
|
||||||
t=t>.5 and(2-t)/1.5 or t*.5
|
|
||||||
gc.setColor(0,0,0,t)
|
|
||||||
gc.rectangle('fill',0,0,SCR.w,SCR.h)
|
|
||||||
end
|
|
||||||
},
|
|
||||||
slowFade={
|
|
||||||
duration=3,changeTime=1.5,
|
|
||||||
draw=function(t)
|
|
||||||
t=t>1.5 and (3-t)/1.5 or t/1.5
|
|
||||||
gc.setColor(0,0,0,t)
|
|
||||||
gc.rectangle('fill',0,0,SCR.w,SCR.h)
|
|
||||||
end
|
|
||||||
},
|
|
||||||
swipeL={
|
|
||||||
duration=.5,changeTime=.25,
|
|
||||||
draw=function(t)
|
|
||||||
t=t*2
|
|
||||||
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=.5,changeTime=.25,
|
|
||||||
draw=function(t)
|
|
||||||
t=t*2
|
|
||||||
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=.5,changeTime=.25,
|
|
||||||
draw=function(t)
|
|
||||||
t=t*2
|
|
||||||
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
|
|
||||||
style=style or'fade'
|
|
||||||
SCN.swapping=true
|
|
||||||
SCN.args={...}
|
|
||||||
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
|
|
||||||
end
|
|
||||||
function SCN.back(...)
|
|
||||||
if SCN.swapping then return 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
|
|
||||||
end
|
|
||||||
return SCN
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
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()
|
|
||||||
|
|
||||||
--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
|
|
||||||
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.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)
|
|
||||||
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),
|
|
||||||
}
|
|
||||||
end
|
|
||||||
return SCR
|
|
||||||
@@ -1,170 +0,0 @@
|
|||||||
local type,rem=type,table.remove
|
|
||||||
local int,rnd=math.floor,math.random
|
|
||||||
local interval=MATH.interval
|
|
||||||
|
|
||||||
local sfxList={}
|
|
||||||
local packSetting={}
|
|
||||||
local Sources={}
|
|
||||||
local volume=1
|
|
||||||
local stereo=1
|
|
||||||
|
|
||||||
local noteVal={
|
|
||||||
C=1,c=1,
|
|
||||||
D=3,d=3,
|
|
||||||
E=5,e=5,
|
|
||||||
F=6,f=6,
|
|
||||||
G=8,g=8,
|
|
||||||
A=10,a=10,
|
|
||||||
B=12,b=12,
|
|
||||||
}
|
|
||||||
local noteName={'C','C#','D','D#','E','F','F#','G','G#','A','A#','B'}
|
|
||||||
local function _getTuneHeight(tune)
|
|
||||||
local octave=tonumber(tune:sub(-1,-1))
|
|
||||||
if octave then
|
|
||||||
local tuneHeight=noteVal[tune:sub(1,1)]
|
|
||||||
if tuneHeight then
|
|
||||||
tuneHeight=tuneHeight+(octave-1)*12
|
|
||||||
local s=tune:sub(2,2)
|
|
||||||
if s=='s'or s=='#'then
|
|
||||||
tuneHeight=tuneHeight+1
|
|
||||||
elseif s=='f'or s=='b'then
|
|
||||||
tuneHeight=tuneHeight-1
|
|
||||||
end
|
|
||||||
return tuneHeight
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local SFX={}
|
|
||||||
|
|
||||||
function SFX.init(list)
|
|
||||||
assert(type(list)=='table',"Initialize SFX lib with a list of filenames!")
|
|
||||||
for i=1,#list do table.insert(sfxList,list[i])end
|
|
||||||
end
|
|
||||||
function SFX.load(path)
|
|
||||||
local c=0
|
|
||||||
local missing=0
|
|
||||||
for i=1,#sfxList do
|
|
||||||
local fullPath=path..sfxList[i]..'.ogg'
|
|
||||||
if love.filesystem.getInfo(fullPath)then
|
|
||||||
if Sources[sfxList[i]]then
|
|
||||||
for j=1,#Sources[sfxList[i]]do
|
|
||||||
Sources[sfxList[i]][j]:release()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
Sources[sfxList[i]]={love.audio.newSource(fullPath,'static')}
|
|
||||||
c=c+1
|
|
||||||
else
|
|
||||||
LOG("No SFX: "..sfxList[i]..'.ogg',.1)
|
|
||||||
missing=missing+1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
LOG(c.."/"..#sfxList.." SFX files loaded")
|
|
||||||
LOG(missing.." SFX files missing")
|
|
||||||
if missing>0 then
|
|
||||||
MES.new('info',missing.." SFX files missing")
|
|
||||||
end
|
|
||||||
collectgarbage()
|
|
||||||
end
|
|
||||||
function SFX.loadSample(pack)
|
|
||||||
assert(type(pack)=='table',"Usage: SFX.loadsample([table])")
|
|
||||||
assert(pack.name,"No field: name")
|
|
||||||
assert(pack.path,"No field: path")
|
|
||||||
local num=1
|
|
||||||
while love.filesystem.getInfo(pack.path..'/'..num..'.ogg')do
|
|
||||||
Sources[pack.name..num]={love.audio.newSource(pack.path..'/'..num..'.ogg','static')}
|
|
||||||
num=num+1
|
|
||||||
end
|
|
||||||
local base=(_getTuneHeight(pack.base)or 37)-1
|
|
||||||
local top=base+num-1
|
|
||||||
packSetting[pack.name]={base=base,top=top}
|
|
||||||
LOG((num-1).." "..pack.name.." samples loaded")
|
|
||||||
end
|
|
||||||
|
|
||||||
function SFX.getCount()
|
|
||||||
return #sfxList
|
|
||||||
end
|
|
||||||
function SFX.setVol(v)
|
|
||||||
assert(type(v)=='number'and v>=0 and v<=1,'Wrong volume')
|
|
||||||
volume=v
|
|
||||||
end
|
|
||||||
function SFX.setStereo(v)
|
|
||||||
assert(type(v)=='number'and v>=0 and v<=1,'Wrong stereo')
|
|
||||||
stereo=v
|
|
||||||
end
|
|
||||||
|
|
||||||
function SFX.getNoteName(note)
|
|
||||||
if note<1 then
|
|
||||||
return'---'
|
|
||||||
else
|
|
||||||
note=note-1
|
|
||||||
local octave=int(note/12)+1
|
|
||||||
return noteName[note%12+1]..octave
|
|
||||||
end
|
|
||||||
end
|
|
||||||
function SFX.playSample(pack,...)--vol-1, sampSet1, vol-2, sampSet2
|
|
||||||
if ... then
|
|
||||||
local arg={...}
|
|
||||||
local vol
|
|
||||||
for i=1,#arg do
|
|
||||||
local a=arg[i]
|
|
||||||
if type(a)=='number'and a<=1 then
|
|
||||||
vol=a
|
|
||||||
else
|
|
||||||
local base=packSetting[pack].base
|
|
||||||
local top=packSetting[pack].top
|
|
||||||
local tune=type(a)=='string'and _getTuneHeight(a)or a--Absolute tune in number
|
|
||||||
local playTune=tune+rnd(-2,2)
|
|
||||||
if playTune<=base then--Too low notes
|
|
||||||
playTune=base+1
|
|
||||||
elseif playTune>top then--Too high notes
|
|
||||||
playTune=top
|
|
||||||
end
|
|
||||||
SFX.play(pack..playTune-base,vol,nil,tune-playTune)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
local function _play(name,vol,pos,pitch)
|
|
||||||
if volume==0 or vol==0 then return end
|
|
||||||
local S=Sources[name]--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=interval(pos,-1,1)*stereo
|
|
||||||
S:setPosition(pos,1-pos^2,0)
|
|
||||||
else
|
|
||||||
S:setPosition(0,0,0)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
S:setVolume(vol^1.626)
|
|
||||||
S:setPitch(pitch and 1.0594630943592953^pitch or 1)
|
|
||||||
S:play()
|
|
||||||
end
|
|
||||||
SFX.fplay=_play--Play sounds without apply module's volume setting
|
|
||||||
function SFX.play(name,vol,pos,pitch)
|
|
||||||
_play(name,(vol or 1)*volume,pos,pitch)
|
|
||||||
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
|
|
||||||
|
|
||||||
return SFX
|
|
||||||
@@ -1,272 +0,0 @@
|
|||||||
local data=love.data
|
|
||||||
local STRING={}
|
|
||||||
local assert,tostring,tonumber=assert,tostring,tonumber
|
|
||||||
local int,format=math.floor,string.format
|
|
||||||
local find,sub,gsub=string.find,string.sub,string.gsub
|
|
||||||
local rep,upper=string.rep,string.upper
|
|
||||||
local char,byte=string.char,string.byte
|
|
||||||
|
|
||||||
--"Replace dollars", replace all $n with ...
|
|
||||||
function STRING.repD(str,...)
|
|
||||||
local l={...}
|
|
||||||
for i=#l,1,-1 do
|
|
||||||
str=gsub(str,'$'..i,l[i])
|
|
||||||
end
|
|
||||||
return str
|
|
||||||
end
|
|
||||||
|
|
||||||
--"Scan arg", scan if str has the arg (format of str is like "-json -q", arg is like "-q")
|
|
||||||
function STRING.sArg(str,switch)
|
|
||||||
if find(str.." ",switch.." ")then
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
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
|
|
||||||
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()
|
|
||||||
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
|
|
||||||
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
|
|
||||||
end
|
|
||||||
|
|
||||||
function STRING.time_simp(t)
|
|
||||||
return format("%02d:%02d",int(t/60),int(t%60))
|
|
||||||
end
|
|
||||||
|
|
||||||
function STRING.time(t)
|
|
||||||
if t<60 then
|
|
||||||
return format("%.3f″",t)
|
|
||||||
elseif t<3600 then
|
|
||||||
return format("%d′%05.2f″",int(t/60),int(t%60*100)/100)
|
|
||||||
else
|
|
||||||
return format("%d:%.2d′%05.2f″",int(t/3600),int(t/60%60),int(t%60*100)/100)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function STRING.UTF8(n)--Simple utf8 coding
|
|
||||||
assert(type(n)=='number',"Wrong type ("..type(n)..")")
|
|
||||||
assert(n>=0 and n<2^31,"Out of range ("..n..")")
|
|
||||||
if n<2^7 then return char(n)
|
|
||||||
elseif n<2^11 then return char(192+int(n/2^06),128+n%2^6)
|
|
||||||
elseif n<2^16 then return char(224+int(n/2^12),128+int(n/2^06)%2^6,128+n%2^6)
|
|
||||||
elseif n<2^21 then return char(240+int(n/2^18),128+int(n/2^12)%2^6,128+int(n/2^06)%2^6,128+n%2^6)
|
|
||||||
elseif n<2^26 then return char(248+int(n/2^24),128+int(n/2^18)%2^6,128+int(n/2^12)%2^6,128+int(n/2^06)%2^6,128+n%2^6)
|
|
||||||
elseif n<2^31 then return char(252+int(n/2^30),128+int(n/2^24)%2^6,128+int(n/2^18)%2^6,128+int(n/2^12)%2^6,128+int(n/2^06)%2^6,128+n%2^6)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
do--function STRING.bigInt(t)
|
|
||||||
local lg=math.log10
|
|
||||||
local units={"","K","M","B","T","Qa","Qt","Sx","Sp","Oc","No"}
|
|
||||||
local preUnits={"","U","D","T","Qa","Qt","Sx","Sp","O","N"}
|
|
||||||
local secUnits={"Dc","Vg","Tg","Qd","Qi","Se","St","Og","Nn","Ce"}--Ce is next-level unit, but DcCe is not used so used here
|
|
||||||
for _,preU in next,preUnits do for _,secU in next,secUnits do table.insert(units,preU..secU)end end
|
|
||||||
function STRING.bigInt(t)
|
|
||||||
if t<1000 then
|
|
||||||
return tostring(t)
|
|
||||||
elseif t~=1e999 then
|
|
||||||
local e=int(lg(t)/3)
|
|
||||||
return(t/10^(e*3))..units[e+1]
|
|
||||||
else
|
|
||||||
return"INF"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
do--function STRING.toBin, STRING.toOct, STRING.toHex(n,len)
|
|
||||||
function STRING.toBin(n,len)
|
|
||||||
local s=""
|
|
||||||
while n>0 do
|
|
||||||
s=(n%2)..s
|
|
||||||
n=int(n/2)
|
|
||||||
end
|
|
||||||
if len then
|
|
||||||
return rep("0",len-#s)..s
|
|
||||||
else
|
|
||||||
return s
|
|
||||||
end
|
|
||||||
end
|
|
||||||
function STRING.toOct(n,len)
|
|
||||||
local s=""
|
|
||||||
while n>0 do
|
|
||||||
s=(n%8)..s
|
|
||||||
n=int(n/8)
|
|
||||||
end
|
|
||||||
if len then
|
|
||||||
return rep("0",len-#s)..s
|
|
||||||
else
|
|
||||||
return s
|
|
||||||
end
|
|
||||||
end
|
|
||||||
local b16={[0]='0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}
|
|
||||||
function STRING.toHex(n,len)
|
|
||||||
local s=""
|
|
||||||
while n>0 do
|
|
||||||
s=b16[n%16]..s
|
|
||||||
n=int(n/16)
|
|
||||||
end
|
|
||||||
if len then
|
|
||||||
return rep("0",len-#s)..s
|
|
||||||
else
|
|
||||||
return s
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function STRING.hexColor(str)--[LOW PERFORMENCE]
|
|
||||||
assert(type(str)=='string')
|
|
||||||
if str:sub(1,1)=="#"then str=str:sub(2)end
|
|
||||||
assert(#str<=8)
|
|
||||||
local r=(tonumber(str:sub(1,2),16)or 0)/255
|
|
||||||
local g=(tonumber(str:sub(3,4),16)or 0)/255
|
|
||||||
local b=(tonumber(str:sub(5,6),16)or 0)/255
|
|
||||||
local a=(tonumber(str:sub(7,8),16)or 255)/255
|
|
||||||
return r,g,b,a
|
|
||||||
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
|
|
||||||
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
|
|
||||||
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
|
|
||||||
end
|
|
||||||
function STRING.digezt(text)--Not powerful hash, just protect the original text
|
|
||||||
local out={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
|
|
||||||
local seed=26
|
|
||||||
for i=1,#text do
|
|
||||||
local c=byte(text,i)
|
|
||||||
seed=(seed+c)%26
|
|
||||||
c=c+seed
|
|
||||||
local pos=c*i%16
|
|
||||||
local step=(c+i)%4+1
|
|
||||||
local times=2+(c%6)
|
|
||||||
for _=1,times do
|
|
||||||
out[pos+1]=(out[pos+1]+c)%256
|
|
||||||
pos=(pos+step)%16
|
|
||||||
end
|
|
||||||
end
|
|
||||||
local result=""
|
|
||||||
for i=1,16 do result=result..char(out[i])end
|
|
||||||
return result
|
|
||||||
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
|
|
||||||
end
|
|
||||||
function STRING.readChars(str,n)
|
|
||||||
return sub(str,1,n),sub(str,n+1)
|
|
||||||
end
|
|
||||||
|
|
||||||
function STRING.packBin(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
|
|
||||||
end
|
|
||||||
function STRING.packText(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
|
|
||||||
end
|
|
||||||
function STRING.packTable(t)
|
|
||||||
return STRING.packText(JSON.encode(t))
|
|
||||||
end
|
|
||||||
function STRING.unpackTable(t)
|
|
||||||
return JSON.decode(STRING.unpackText(t))
|
|
||||||
end
|
|
||||||
|
|
||||||
return STRING
|
|
||||||
@@ -1,205 +0,0 @@
|
|||||||
local gc=love.graphics
|
|
||||||
local gc_setColor,gc_setLineWidth=gc.setColor,gc.setLineWidth
|
|
||||||
local gc_draw,gc_line=gc.draw,gc.line
|
|
||||||
local gc_rectangle,gc_circle=gc.rectangle,gc.circle
|
|
||||||
|
|
||||||
local max,min=math.max,math.min
|
|
||||||
local rnd=math.random
|
|
||||||
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
|
|
||||||
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
|
|
||||||
end
|
|
||||||
FXupdate.attack=_normUpdate
|
|
||||||
FXupdate.tap=_normUpdate
|
|
||||||
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
|
|
||||||
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)
|
|
||||||
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_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
|
|
||||||
)
|
|
||||||
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)
|
|
||||||
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)
|
|
||||||
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)
|
|
||||||
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)
|
|
||||||
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)
|
|
||||||
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)
|
|
||||||
end
|
|
||||||
|
|
||||||
local SYSFX={}
|
|
||||||
function SYSFX.update(dt)
|
|
||||||
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
|
|
||||||
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,
|
|
||||||
})
|
|
||||||
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,
|
|
||||||
})
|
|
||||||
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)
|
|
||||||
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,
|
|
||||||
})
|
|
||||||
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,
|
|
||||||
})
|
|
||||||
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,
|
|
||||||
})
|
|
||||||
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,
|
|
||||||
})
|
|
||||||
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,
|
|
||||||
})
|
|
||||||
end
|
|
||||||
return SYSFX
|
|
||||||
@@ -1,271 +0,0 @@
|
|||||||
local rnd=math.random
|
|
||||||
local find=string.find
|
|
||||||
local rem=table.remove
|
|
||||||
local next,type=next,type
|
|
||||||
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
|
|
||||||
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
|
|
||||||
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
|
|
||||||
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
|
|
||||||
end
|
|
||||||
|
|
||||||
--For all things in new, push to old
|
|
||||||
function TABLE.coverR(new,old)
|
|
||||||
for k,v in next,new do
|
|
||||||
if type(v)=='table'and type(old[k])=='table'then
|
|
||||||
TABLE.coverR(v,old[k])
|
|
||||||
else
|
|
||||||
old[k]=v
|
|
||||||
end
|
|
||||||
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
|
|
||||||
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
|
|
||||||
end
|
|
||||||
|
|
||||||
--------------------------
|
|
||||||
|
|
||||||
--Pop & return random [1~#] of table
|
|
||||||
function TABLE.popRandom(t)
|
|
||||||
local l=#t
|
|
||||||
if l>0 then
|
|
||||||
local r=rnd(l)
|
|
||||||
r,t[r]=t[r],t[l]
|
|
||||||
t[l]=nil
|
|
||||||
return r
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--Remove [1~#] of table
|
|
||||||
function TABLE.cut(G)
|
|
||||||
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
|
|
||||||
end
|
|
||||||
|
|
||||||
--------------------------
|
|
||||||
|
|
||||||
--Remove duplicated value of [1~#]
|
|
||||||
function TABLE.trimDuplicate(org)
|
|
||||||
local cache={}
|
|
||||||
for i=1,#org,-1 do
|
|
||||||
if cache[org[i]]then
|
|
||||||
rem(org,i)
|
|
||||||
else
|
|
||||||
cache[org[i]]=true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--Discard duplicated value
|
|
||||||
function TABLE.remDuplicate(org)
|
|
||||||
local cache={}
|
|
||||||
for k,v in next,org do
|
|
||||||
if cache[v]then
|
|
||||||
org[k]=nil
|
|
||||||
else
|
|
||||||
cache[v]=true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--------------------------
|
|
||||||
|
|
||||||
--Reverse [1~#]
|
|
||||||
function TABLE.reverse(org)
|
|
||||||
local l=#org
|
|
||||||
for i=1,math.floor(l/2)do
|
|
||||||
org[i],org[l+1-i]=org[l+1-i],org[i]
|
|
||||||
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
|
|
||||||
end
|
|
||||||
|
|
||||||
--Return next value of [1~#] (by value)
|
|
||||||
function TABLE.next(t,val)
|
|
||||||
for i=1,#t do if t[i]==val then return t[i%#t+1]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
|
|
||||||
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
|
|
||||||
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
|
|
||||||
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
|
|
||||||
end
|
|
||||||
|
|
||||||
return TABLE
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
local rem=table.remove
|
|
||||||
local assert,resume,status=assert,coroutine.resume,coroutine.status
|
|
||||||
local tasks={}
|
|
||||||
|
|
||||||
local TASK={}
|
|
||||||
function TASK.getCount()
|
|
||||||
return #tasks
|
|
||||||
end
|
|
||||||
local trigFrame=0
|
|
||||||
function TASK.update(dt)
|
|
||||||
trigFrame=trigFrame+dt*60
|
|
||||||
while trigFrame>=1 do
|
|
||||||
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
|
|
||||||
trigFrame=trigFrame-1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
function TASK.new(code,...)
|
|
||||||
local thread=coroutine.create(code)
|
|
||||||
assert(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
|
|
||||||
end
|
|
||||||
function TASK.removeTask_iterate(func,...)
|
|
||||||
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
|
|
||||||
end
|
|
||||||
return TASK
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
local TEST={}
|
|
||||||
|
|
||||||
--Wait for the scene swapping animation to finish
|
|
||||||
function TEST.yieldUntilNextScene()
|
|
||||||
while SCN.swapping do YIELD()end
|
|
||||||
end
|
|
||||||
|
|
||||||
function TEST.yieldN(frames)
|
|
||||||
for _=1,frames do YIELD()end
|
|
||||||
end
|
|
||||||
|
|
||||||
return TEST
|
|
||||||
@@ -1,153 +0,0 @@
|
|||||||
local gc=love.graphics
|
|
||||||
local getColor,setColor=gc.getColor,gc.setColor
|
|
||||||
|
|
||||||
local int,rnd=math.floor,math.random
|
|
||||||
local ins,rem=table.insert,table.remove
|
|
||||||
local draw=gc.draw
|
|
||||||
|
|
||||||
local texts={}
|
|
||||||
|
|
||||||
local textFX={}
|
|
||||||
function textFX.appear(t)
|
|
||||||
draw(
|
|
||||||
t.text,t.x,t.y,
|
|
||||||
nil,
|
|
||||||
nil,nil,
|
|
||||||
t.text:getWidth()*.5,t.text:getHeight()*.5
|
|
||||||
)
|
|
||||||
end
|
|
||||||
function textFX.sudden(t)
|
|
||||||
setColor(1,1,1,1-t.c)
|
|
||||||
draw(
|
|
||||||
t.text,t.x,t.y,
|
|
||||||
nil,
|
|
||||||
nil,nil,
|
|
||||||
t.text:getWidth()*.5,t.text:getHeight()*.5
|
|
||||||
)
|
|
||||||
end
|
|
||||||
function textFX.fly(t)
|
|
||||||
draw(
|
|
||||||
t.text,t.x+(t.c-.5)^3*300,t.y,
|
|
||||||
nil,
|
|
||||||
nil,nil,
|
|
||||||
t.text:getWidth()*.5,t.text:getHeight()*.5
|
|
||||||
)
|
|
||||||
end
|
|
||||||
function textFX.stretch(t)
|
|
||||||
draw(
|
|
||||||
t.text,t.x,t.y,
|
|
||||||
nil,
|
|
||||||
t.c<.3 and(.3-t.c)*1.6+1 or 1,1,
|
|
||||||
t.text:getWidth()*.5,t.text:getHeight()*.5
|
|
||||||
)
|
|
||||||
end
|
|
||||||
function textFX.drive(t)
|
|
||||||
draw(
|
|
||||||
t.text,t.x,t.y,
|
|
||||||
nil,
|
|
||||||
nil,nil,
|
|
||||||
t.text:getWidth()*.5,t.text:getHeight()*.5,
|
|
||||||
t.c<.3 and(.3-t.c)*2 or 0,0
|
|
||||||
)
|
|
||||||
end
|
|
||||||
function textFX.spin(t)
|
|
||||||
draw(
|
|
||||||
t.text,t.x,t.y,
|
|
||||||
t.c<.3 and(.3-t.c)^2*4 or t.c<.8 and 0 or(t.c-.8)^2*-4,
|
|
||||||
nil,nil,
|
|
||||||
t.text:getWidth()*.5,t.text:getHeight()*.5
|
|
||||||
)
|
|
||||||
end
|
|
||||||
function textFX.flicker(t)
|
|
||||||
local _,_,_,T=getColor()
|
|
||||||
setColor(1,1,1,T*(rnd()+.5))
|
|
||||||
draw(
|
|
||||||
t.text,t.x,t.y,
|
|
||||||
nil,
|
|
||||||
nil,nil,
|
|
||||||
t.text:getWidth()*.5,t.text:getHeight()*.5
|
|
||||||
)
|
|
||||||
end
|
|
||||||
function textFX.zoomout(t)
|
|
||||||
draw(
|
|
||||||
t.text,t.x,t.y,
|
|
||||||
nil,
|
|
||||||
t.c^.5*.1+1,nil,
|
|
||||||
t.text:getWidth()*.5,t.text:getHeight()*.5
|
|
||||||
)
|
|
||||||
end
|
|
||||||
function textFX.beat(t)
|
|
||||||
local k=t.c<.3 and 1.3-t.c^2/.3 or 1
|
|
||||||
draw(
|
|
||||||
t.text,t.x,t.y,
|
|
||||||
nil,
|
|
||||||
k,k,
|
|
||||||
t.text:getWidth()*.5,t.text:getHeight()*.5
|
|
||||||
)
|
|
||||||
end
|
|
||||||
function textFX.score(t)
|
|
||||||
local _,_,_,T=getColor()
|
|
||||||
setColor(1,1,1,T*.5)
|
|
||||||
draw(
|
|
||||||
t.text,t.x,t.y-0-t.c^.2*50,
|
|
||||||
nil,
|
|
||||||
nil,nil,
|
|
||||||
t.text:getWidth()*.5,t.text:getHeight()*.5
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
local TEXT={}
|
|
||||||
function TEXT.clear()
|
|
||||||
texts={}
|
|
||||||
end
|
|
||||||
function TEXT.show(text,x,y,font,style,spd,stop)
|
|
||||||
ins(texts,{
|
|
||||||
c=0, --Timer
|
|
||||||
text=gc.newText(FONT.get(int(font/5)*5 or 40),text), --String
|
|
||||||
x=x or 0, --X
|
|
||||||
y=y or 0, --Y
|
|
||||||
spd=(spd or 1), --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=gc.newText(FONT.get(int(font/5)*5 or 40),text),
|
|
||||||
x=x or 0,
|
|
||||||
y=y or 0,
|
|
||||||
spd=(spd or 1),
|
|
||||||
stop=stop,
|
|
||||||
draw=textFX[style or'appear']or error("unavailable type:"..style),
|
|
||||||
}
|
|
||||||
end
|
|
||||||
function TEXT.update(dt,list)
|
|
||||||
if not list then
|
|
||||||
list=texts
|
|
||||||
end
|
|
||||||
for i=#list,1,-1 do
|
|
||||||
local t=list[i]
|
|
||||||
t.c=t.c+t.spd*dt
|
|
||||||
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
|
|
||||||
setColor(1,1,1,p<.2 and p*5 or p<.8 and 1 or 5-p*5)
|
|
||||||
t:draw()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return TEXT
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
local level={0,0,.01,.016,.023,.03,.04,.05,.06,.07,.08,.09,.12,.15}
|
|
||||||
local vib=love.system.vibrate
|
|
||||||
return love.system.getOS()=='iOS'and
|
|
||||||
function(t)
|
|
||||||
t=level[t]
|
|
||||||
if t then vib(t<=.03 and 1 or t<=.09 and 2 or 3)end
|
|
||||||
end
|
|
||||||
or
|
|
||||||
function(t)
|
|
||||||
t=level[t]
|
|
||||||
if t then vib(t)end
|
|
||||||
end
|
|
||||||
@@ -1,132 +0,0 @@
|
|||||||
local rnd=math.random
|
|
||||||
local volume=1
|
|
||||||
local diversion=0
|
|
||||||
local VOC={
|
|
||||||
getCount=function()return 0 end,
|
|
||||||
getQueueCount=function()return 0 end,
|
|
||||||
load=function()error("Cannot load before init!")end,
|
|
||||||
getFreeChannel=NULL,
|
|
||||||
play=NULL,
|
|
||||||
update=NULL,
|
|
||||||
}
|
|
||||||
function VOC.setDiversion(n)
|
|
||||||
assert(type(n)=='number'and n>0 and n<12,'Wrong div')
|
|
||||||
diversion=n
|
|
||||||
end
|
|
||||||
function VOC.setVol(v)
|
|
||||||
assert(type(v)=='number'and v>=0 and v<=1,'Wrong volume')
|
|
||||||
volume=v
|
|
||||||
end
|
|
||||||
function VOC.init(list)
|
|
||||||
VOC.init=nil
|
|
||||||
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(path,N,vocName)
|
|
||||||
local fullPath=path..vocName..'.ogg'
|
|
||||||
if love.filesystem.getInfo(fullPath)then
|
|
||||||
bank[vocName]={love.audio.newSource(fullPath,'stream')}
|
|
||||||
table.insert(Source[N],vocName)
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
--Load voice with string
|
|
||||||
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]
|
|
||||||
end
|
|
||||||
function VOC.load(path)
|
|
||||||
for i=1,count do
|
|
||||||
Source[list[i]]={}
|
|
||||||
|
|
||||||
local n=0
|
|
||||||
repeat n=n+1 until not _loadVoiceFile(path,list[i],list[i]..'_'..n)
|
|
||||||
|
|
||||||
if n==1 then
|
|
||||||
if not _loadVoiceFile(path,list[i],list[i])then
|
|
||||||
LOG("No VOC: "..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.play(s,chn)
|
|
||||||
if volume>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(volume)
|
|
||||||
Q[1]:setPitch(1.0594630943592953^(diversion*(rnd()*2-1)))
|
|
||||||
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(volume)
|
|
||||||
Q[1]:setPitch(1.0594630943592953^(diversion*(rnd()*2-1)))
|
|
||||||
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
|
|
||||||
@@ -1,191 +0,0 @@
|
|||||||
local host=
|
|
||||||
-- '127.0.0.1'
|
|
||||||
-- '192.168.114.102'
|
|
||||||
'game.techmino.org'
|
|
||||||
local port='10026'
|
|
||||||
local path='/tech/socket/v1'
|
|
||||||
|
|
||||||
-- lua + LÖVE threading websocket client
|
|
||||||
-- Original pure lua ver. by flaribbit and Particle_G
|
|
||||||
-- Threading version by MrZ
|
|
||||||
|
|
||||||
local type=type
|
|
||||||
local timer=love.timer.getTime
|
|
||||||
local CHN=love.thread.newChannel()
|
|
||||||
local CHN_getCount,CHN_push,CHN_pop=CHN.getCount,CHN.push,CHN.pop
|
|
||||||
local TRD=love.thread.newThread("\n")
|
|
||||||
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
|
|
||||||
})
|
|
||||||
|
|
||||||
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
|
|
||||||
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)
|
|
||||||
end
|
|
||||||
|
|
||||||
function WS.status(name)
|
|
||||||
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
|
|
||||||
end
|
|
||||||
|
|
||||||
function WS.setPingInterval(name,time)
|
|
||||||
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
|
|
||||||
end
|
|
||||||
|
|
||||||
local OPcode={
|
|
||||||
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',
|
|
||||||
}
|
|
||||||
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
|
|
||||||
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
|
|
||||||
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
|
|
||||||
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
|
|
||||||
end
|
|
||||||
|
|
||||||
return WS
|
|
||||||
@@ -1,191 +0,0 @@
|
|||||||
local triggerCHN,sendCHN,readCHN=...
|
|
||||||
|
|
||||||
local CHN_demand,CHN_getCount=triggerCHN.demand,triggerCHN.getCount
|
|
||||||
local CHN_push,CHN_pop=triggerCHN.push,triggerCHN.pop
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
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
|
|
||||||
)
|
|
||||||
|
|
||||||
--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==''
|
|
||||||
|
|
||||||
--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
|
|
||||||
local byte,char=string.byte,string.char
|
|
||||||
local band,bor,bxor=bit.band,bit.bor,bit.bxor
|
|
||||||
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)))
|
|
||||||
|
|
||||||
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
|
|
||||||
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
|
|
||||||
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)
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
--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
|
|
||||||
end
|
|
||||||
|
|
||||||
SOCK:close()
|
|
||||||
CHN_push(readCHN,8)--close
|
|
||||||
CHN_push(readCHN,err or"Disconnected")
|
|
||||||
error()
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
local love=love
|
|
||||||
local max,min=math.max,math.min
|
|
||||||
local trigDist=0
|
|
||||||
return function(y,key1,key2)
|
|
||||||
if y>0 then
|
|
||||||
trigDist=max(trigDist,0)+y^1.2
|
|
||||||
elseif y<0 then
|
|
||||||
if trigDist>0 then trigDist=0 end
|
|
||||||
trigDist=min(trigDist,0)-(-y)^1.2
|
|
||||||
end
|
|
||||||
while trigDist>=1 do
|
|
||||||
love.keypressed(key1 or'up')
|
|
||||||
trigDist=trigDist-1
|
|
||||||
end
|
|
||||||
while trigDist<=-1 do
|
|
||||||
love.keypressed(key2 or'down')
|
|
||||||
trigDist=trigDist+1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user