Compare commits

..

10 Commits

Author SHA1 Message Date
MrZ626
6105f32cfa 修改房间版本号,不再允许快照版本进0.17.0的房间 2022-01-05 12:29:02 +08:00
MrZ626
4927d56c1e 修改自定义背景注释文本 2022-01-04 16:48:31 +08:00
MrZ626
0ef1103931 框架跟进 2022-01-04 16:48:21 +08:00
MrZ626
07d5a4c4d2 整理中文tip 2022-01-03 15:58:53 +08:00
MrZ626
c0cc759c72 Zframework使用子模块 2022-01-03 14:37:50 +08:00
MrZ626
94e06fab4a 移除Zframework,准备使用submodule 2022-01-03 14:35:10 +08:00
C₂₉H₂₅N₃O₅
8fa2e055d5 新增/调整字符 (#575)
* 修改日语文件的小错误

* 新增麻将字符 and more

* 字体新增麻将字符
* 字体加入自动hint
* 微调几个表情包
2022-01-03 01:36:56 +08:00
MrZ626
2d5642a99c 数学扩展模块新增listLerp函数 2022-01-03 00:14:10 +08:00
MrZ626
98050f99be 数学扩展模块新增lerp函数 2022-01-02 20:14:26 +08:00
MrZ626
27d9cf8a9b 字符串扩展模块新增几个进制转换函数 2022-01-02 13:57:42 +08:00
40 changed files with 189 additions and 6052 deletions

3
.gitmodules vendored Normal file
View File

@@ -0,0 +1,3 @@
[submodule "Zframework"]
path = Zframework
url = git@github.com:26F-Studio/Zframework.git

1
Zframework Submodule

Submodule Zframework added at f687fb9c1a

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View 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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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));
}

View File

@@ -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
}

View File

@@ -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

View File

@@ -1,37 +0,0 @@
local MATH={}for k,v in next,math do MATH[k]=v end
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.expApproach(a,b,k)
return b+(a-b)*2.718281828459045^-k
end
return MATH

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -1,231 +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,upper=string.find,string.sub,string.gsub,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
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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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()

View File

@@ -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

View File

@@ -1,4 +1,4 @@
--Secret custom background
--Custom background
local gc_clear,gc_setColor=love.graphics.clear,love.graphics.setColor
local back={}

View File

@@ -172,7 +172,7 @@ local L={
macPgdnAlt= 0xF0125,
iecPower= 0xF0126,
},
controller={--F0100~F017F
controller={--F0180~F01FF
xbox= 0xF0180,
lt= 0xF0181,
rt= 0xF0182,
@@ -211,7 +211,93 @@ local L={
psMute= 0xF01A3,
psCreate= 0xF01A4,
psOption= 0xF01A5,
},
mahjong={--F0200~F027F
wan1= 0xF0200,
wan2= 0xF0201,
wan3= 0xF0202,
wan4= 0xF0203,
wan5= 0xF0204,
wan6= 0xF0205,
wan7= 0xF0206,
wan8= 0xF0207,
wan9= 0xF0208,
tiao1= 0xF0209,
tiao2= 0xF020A,
tiao3= 0xF020B,
tiao4= 0xF020C,
tiao5= 0xF020D,
tiao6= 0xF020E,
tiao7= 0xF020F,
tiao8= 0xF0210,
tiao9= 0xF0211,
tong1= 0xF0212,
tong2= 0xF0213,
tong3= 0xF0214,
tong4= 0xF0215,
tong5= 0xF0216,
tong6= 0xF0217,
tong7= 0xF0218,
tong8= 0xF0219,
tong9= 0xF021A,
east= 0xF021B,
south= 0xF021C,
west= 0xF021D,
north= 0xF021E,
center= 0xF021F,
fortune= 0xF0220,
soap= 0xF0221,
fortuneAlt= 0xF0222,
soapAlt= 0xF0223,
spring= 0xF0224,
summer= 0xF0225,
autumn= 0xF0226,
winter= 0xF0227,
plum= 0xF0228,
orchid= 0xF0229,
chry= 0xF022A,
bamboo= 0xF022B,
wan5Red= 0xF022C,
tiao5Red= 0xF022D,
tong5Red= 0xF022E,
wan1Base= 0xF022F,
wan2Base= 0xF0230,
wan3Base= 0xF0231,
wan4Base= 0xF0232,
wan5Base= 0xF0233,
wan6Base= 0xF0234,
wan7Base= 0xF0235,
wan8Base= 0xF0236,
wan9Base= 0xF0237,
wanComb= 0xF0238,
tiao1Base= 0xF0239,
tiao1Comb= 0xF023A,
tiao5Base= 0xF023B,
tiao5Comb= 0xF023C,
tiao7Base= 0xF023D,
tiao7Comb= 0xF023E,
tiao9Base= 0xF023F,
tiao9Comb= 0xF0240,
tong2Base= 0xF0241,
tong2Comb= 0xF0242,
tong3Base= 0xF0243,
tong3Comb1= 0xF0244,
tong3Comb2= 0xF0245,
tong4Base= 0xF0246,
tong4Comb= 0xF0247,
tong5Base= 0xF0248,
tong5Comb1= 0xF0249,
tong5Comb2= 0xF024A,
tong6Base= 0xF024B,
tong6Comb= 0xF024C,
tong7Base= 0xF024D,
tong7Comb= 0xF024E,
tong9Base= 0xF024F,
tong9Comb1= 0xF0250,
tong9Comb2= 0xF0251,
frameComb= 0xF0252,
}
}
for _,pack in next,L do

Binary file not shown.

View File

@@ -854,13 +854,11 @@ return{
['custom_puzzle']= {"自定义", "拼图"},
},
getTip={refuseCopy=true,
"“Techmino.app”将对您的电脑造成伤害。您应该将它移到废纸篓。",
"(RUR'U')R'FR2U'R'U'(RUR'F')",
"《按钮风格进化史》",
"《加载动画进化史》",
"《主题曲进化史》",
"↑↑↓↓←→←→BA",
"$include<studio.h>",
"0next 0hold.",
"11renPC",
"1next 0hold",
@@ -877,24 +875,17 @@ return{
"本游戏还在测试中,出各种问题都是有可能的哦",
"本游戏使用精简版字体,可能有些特殊字符不能正确显示",
"别催了,在做了!",
"不要大力拍打或滑动哦",
"不要卖弱不要卖弱不要卖弱",
"不知道有多少人玩游戏的时候会关心游戏是谁做的",
"部分手机系统开启震动会导致严重卡顿",
"彩色消除即将到来!",
"草(日本语)",
"车万方块是一家(暴论",
"吃键?真的吗?建议回放看看到底按没按到,按了多久",
"凑数tip什么时候能站起来",
"打块多是一件美事啊",
"打铁.mp4",
"大概还是有人会看tip的",
"大家认为的俄罗斯方块很可能不是你以为的俄罗斯方块,场合合适的时候可以适当提醒一下哦",
"大满贯10连击消四全清",
"戴上耳机以获得最佳体验",
"单手也能玩!",
"点击添加标题",
"对编程有真·兴趣推荐Lua安装无脑 语法简单 执行速度快 远离枯燥学校编程(雾",
"多年小游戏玩家表示痛恨故意拖时间的假加载",
"多hold现代块又回来了",
"俄罗斯方块完全可以作为电竞游戏",
@@ -903,23 +894,17 @@ return{
"方块能吃吗",
"感觉明明按键了但是没反应?你真的按到了吗?",
"感谢群友帮忙想tip",
"感谢Orzmic为这个tip框提供修改意见",
"感谢Phigros提供(确信)部分tip模板",
"隔壁不在乎玩家意见但是我们在乎,没人提过的合理建议一定会回应",
"隔断消除即将到来!",
"还能写些什么tip呢",
"好像还没人能用脚打块打到一定水平",
"很有精神!",
"欢迎来帮忙制作音乐或音效!",
"欢迎提供更多游戏创意!",
"混合消除即将到来!",
"架空消除即将到来!",
"建议使用双手游玩",
"绝大多数按钮上的图标是调用Unicode私用区里的自制字符实现的",
"科技骨牌 你的创新式块堆栈业务技术管理器",
"块东V共荣",
"快去打一把100%极简看看会怎样",
"锟斤拷锟斤拷锟斤拷",
"来学编程,好玩的",
"老牌益智游戏了",
"论如何正确使用Unicode私用区定制字体",
@@ -928,42 +913,29 @@ return{
"免费吃鸡方块",
"喵!",
"魔方也是方块(确信",
"你的双手是为了你的一生服务的而不是Techmino",
"你今天的人品值是(满分100):"..math.random(100),
"你们考虑过Z酱的感受吗没有你们只考虑你自己。",
"你有一个好",
"你这块是金子做的还是垃圾行是金子做的",
"你准备好了吗?",
"配乐是有考虑到模式氛围的哦",
"请谨慎向没有方块经验的玩家推荐,会对本游戏的生存环境造成影响,感谢配合。",
"请勿大力敲打设备敲坏了就没有Techmino玩了",
"请勿使用三只手游玩",
"全球目前应该没人能全X评价(大爆炸不算)",
"如何O-spin: 一秒转626圈(误",
"三岁通关困难马拉松",
"少女祈祷中",
"深降了解一下",
"试试用跳舞毯打块",
"适度游戏益脑,沉迷游戏伤身,合理安排时间,享受健康生活",
"烫烫烫烫烫烫",
"天哪我竟然是一条凑数tip",
"挖掘能力在对战里非常非常非常重要!!!!",
"玩到一半弹出消息框?快去设置禁止弹窗",
"玩得开心的话游戏作者也会很开心哦",
"我曾经在极度愤怒的时候15秒消了40行",
"我们联合!",
"我们是不是第一个在方块游戏做tip的",
"我是一条凑数tip",
"我也是一条凑数tip",
"我一个滑铲就挖了个11renPC",
"我永远喜……",
"无法打开“Techmino.app”因为无法验证开发者。",
"物理hold了解一下",
"希望极简率没事",
"希望你们都能喜欢Z……哦不是喜欢Techmino",
"享受Tech的特色旋转系统",
"写不出那种很酷的音乐(哭",
"要盯着bug不放",
"音乐风格是什么,能吃吗",
"音乐使用beepbox制作",
"音游方块是一家(暴论",
@@ -972,15 +944,12 @@ return{
"有建议的话可以反馈给作者~",
"有两个模式是以东方Project里的角色为主题的",
"这不是休闲游戏……别怪关卡要求太高,多练吧",
"震惊我只是一条凑数tip吗",
"中文方块百科全书tetris.huijiwiki.com",
"众所周知俄罗斯方块是经典编程练手游戏(",
"众所周知mac不能拿来玩游戏",
"作业没做完别玩手机",
"作者40行sub26了",
"作者电脑上装了11个方块",
"作者浏览器收藏夹里有6个方块",
"做,做碌鸠啊做,打块先啦!",
"ALLSPIN!",
"Am G F G",
"B2B2B",
@@ -989,40 +958,105 @@ return{
"c4w人竟是我自己",
"c4w人竟在我身边",
"fin neo iso 是满足tspin条件的特殊t2的名字",
"git commit",
"git push -f",
"hello world",
"if a==true",
"iOS设备使用键盘控制可能会有问题还是先只用触屏吧",
"l-=-1",
"Let-The-Bass-Kick",
"MrZ是谁啊",
"pps-0.01",
"shutdown -h now",
"sofunhowtoget",
"STSD必死",
"sudo rm -rf /*",
"Techmino /'tɛkmɪnoʊ/ n.铁壳米诺(游戏名)",
"Techmino = Technique + Tetromino",
"Techmino 好玩!",
"Techmino 濂界帺锛",
"Techmino console了解一下",
"Techmino: App意外退出。",
"Techmino.exe 已停止工作",
"Techmino安卓下载",
"Techmino没有氪金没有逼肝良不良心~",
"Techmino在哪里下载",
"Techmino怎么念啊",
"techminohaowan",
"techminoisfun",
"TechminOS coming s∞n",
"viod main[]",
"while(false)",
"Z酱竟是我自己",
"Z酱累了Z酱不想更新",
"Z酱是谁",
"Z酱只是个写代码的懂什么方块",
"Z块等身抱枕来一个(x",
--凑数
"凑数tip什么时候能站起来",
"天哪我竟然是一条凑数tip",
"我是一条凑数tip",
"我也是一条凑数tip",
"震惊我只是一条凑数tip吗",
--计算机技术梗
"点击添加标题",
"对编程有真·兴趣推荐Lua安装无脑 语法简单 执行速度快 远离枯燥学校编程(雾",
"绝大多数按钮上的图标是调用Unicode私用区里的自制字符实现的",
"科技骨牌 你的创新式块堆栈业务技术管理器",
"锟斤拷锟斤拷锟斤拷",
"“Techmino.app”将对您的电脑造成伤害。您应该将它移到废纸篓。",
"$include<studio.h>",
"无法打开“Techmino.app”因为无法验证开发者。",
"众所周知俄罗斯方块是经典编程练手游戏(",
"git commit",
"git push -f",
"hello world",
"if a==true",
"l-=-1",
"shutdown -h now",
"sudo rm -rf /*",
"Techmino 濂界帺锛",
"Techmino console了解一下",
"Techmino: App意外退出。",
"Techmino.exe 已停止工作",
"TechminOS coming s∞n",
"viod main[]",
"while(false)",
--其他游戏梗
"不要大力拍打或滑动哦",
"车万方块是一家(暴论",
"单手也能玩!",
"感谢Orzmic为这个tip框提供修改意见",
"感谢Phigros提供(确信)部分tip模板",
"你的双手是为了你的一生服务的而不是Techmino",
"你有一个好",
"你准备好了吗?",
"请勿大力敲打设备敲坏了就没有Techmino玩了",
"少女祈祷中",
"要盯着bug不放",
{C.Z,"12",C.C,"",C.Z,""},
{C.C,"<PURE ",C.P,"MEMORY>"},
{C.H,"暂定段位:9"},
{C.lY,"COOL"},
{C.H,"REGRET!!"},
{C.Y,"<φ> 10000"},
{C.Y,"10000 φ"},
{C.Y,"暂定段位:GM"},
{C.Y,"暂定段位:M"},
{C.Y,"暂定段位:MK"},
{C.Y,"暂定段位:MM"},
{C.Y,"暂定段位:MO"},
{C.Y,"暂定段位:MV"},
{C.Y,"O-spin"},
{C.lY,"Xspin",C.Z,"是啥"},
{C.Z,"堆叠药水",C.H," 堆叠提升 (3:00)"},
{C.Z,"挖掘药水",C.H," 挖掘提升 (8:00)"},
{C.Z,"效率药水",C.H," 效率提升 (3:00)"},
{C.Z,"协调药水",C.H," MD减少 II(1:30)"},
{C.P,"T-spin!"},
{C.R,"DD",C.Z,"炮=",C.P,"TS",C.R,"D",C.Z,"+",C.P,"TS",C.R,"D",C.Z,""},
{C.R,"DT",C.Z,"炮=",C.P,"TS",C.R,"D",C.Z,"+",C.P,"TS",C.R,"T",C.Z,""},
{C.R,"LrL ",C.G,"RlR ",C.B,"LLr ",C.O,"RRl ",C.P,"RRR LLL ",C.C,"FFF ",C.Y,"RfR RRf rFF"},
--网络梗
"我们联合!",
"你这块是金子做的还是垃圾行是金子做的",
"做,做碌鸠啊做,打块先啦!",
"啊哈哈哈哈哈T块来咯",
"这打块,多是一件美事",
"不轻不黏,手感真是好极了",
"他奶奶的,为什么转不进去",
--时间碎片
"时间碎片[000] 2021/11/21加入这个版块",
"时间碎片[001] V0.0.091726加入TRS旋转系统",
"时间碎片[002] V0.7.9加入O-spin",
@@ -1043,6 +1077,8 @@ return{
"时间碎片[017] V0.16.0加入BIRS",
"时间碎片[018] V0.16.2加入打击垫样式的音效室",
"时间碎片[019] V0.17.0加入手柄的摇杆和扳机支持",
--豆知识
"豆知识[001]总共有400多条tip哦",
"豆知识[002]背景影响游玩?可以去设置关闭",
"豆知识[003]方块默认出现的方向都是重心在下哦(如果你没乱动设置",
@@ -1148,6 +1184,8 @@ return{
"豆知识[103]请在有一定基础之后再学Tspin不然副作用非常大",
"豆知识[104]新人请千万记住,打好基础,不要太早学那些花里胡哨的。",
"豆知识[105]长时间游戏状态会越来越差!玩久了记得放松一下~",
--健康小贴士
"健康小贴士[01]玩游戏多眨眼,不然会干眼病",
"健康小贴士[02]少玩点游戏,多注意眨眼和休息",
"健康小贴士[03]戴耳机(尤其是半入耳式)时音量千万别拉满,不然真的会影响听力(虽然很慢)",
@@ -1156,6 +1194,8 @@ return{
"群友名言[001]“玩了Techmino之后发现打字速度变快了”",
"群友名言[002]“我要陪伴着tech一步步成长然后就可以疯狂的享受他”",
"群友名言[003]“太super啦不愧是guideline”",
--Frt评
"Frt评[01]“成天被夸赞‘好玩’的”",
"Frt评[02]“可以形成方块圈子小中心话题,同作者一起衍生一些概念与梗的”",
"Frt评[03]“论方块的软工意义(就算这么小个范围内,各种取舍蒙混翻车现象都总会以很易懂的方式出现(”",
@@ -1168,6 +1208,8 @@ return{
"Frt评[10]“是民间UI动效艺术作品”",
"Frt评[11]“是一滩散乱的代码组成的蜜汁结构”",
"Frt评[12]“它是现在的techmino已发布版本”",
--今日数学
"今日数学[01](a+b)³=a³+3a²b+3ab²+b³",
"今日数学[02]∫u dv=uv-∫v du",
"今日数学[03]cos(α+β)=CαCβ-SβSα",
@@ -1183,6 +1225,8 @@ return{
"今日数学[13]sin²α-cos²β=-C(α+β)C(α-β)",
"今日数学[14]sin²α-sin²β=S(α+β)S(α-β)",
"今日数学[15]sin2α=2SαCα",
--Z
"Z哲[01]方块教会我们,合群了就会消失,……",
"Z哲[02]假如生活欺骗了你,不要悲伤,不要心急,还有块陪着你",
"Z哲[03]……合群了就会消失不合群世界毁灭指game over",
@@ -1223,41 +1267,21 @@ return{
"Z推[14]魔方好玩!",
"Z推[15]15puzzle好玩",
"Z推[16]扫雷好玩!",
{C.C,"<PURE ",C.P,"MEMORY>"},
{C.H,"暂定段位:9"},
{C.H,"REGRET!!"},
{C.lC,"Xspin",C.Z,"是啥"},
--可爱!
{C.lP,"口〇口",C.Z," 可爱!"},
{C.lP,"秘密数字:626"},
{C.lR,"Z ",C.lG,"S ",C.lS,"J ",C.lO,"L ",C.lP,"T ",C.lY,"O ",C.lC,"I"},
{C.Y,"Miya",C.Z," 可爱!"},
{C.lS,"茶娘",C.Z," 可爱!"},
{C.lY,"COOL"},
{C.lP,"秘密数字:626"},
{C.N,"Lua",C.Z,"天下第一"},
{C.P,"T-spin!"},
{C.lR,"Z ",C.lG,"S ",C.lS,"J ",C.lO,"L ",C.lP,"T ",C.lY,"O ",C.lC,"I"},
{C.R,"《滥用DMCA》"},
{C.R,"《知识产权法》"},
{C.R,"本游戏难度上限很高,做好心理准备。"},
{C.R,"上班时间不许摸鱼打块!"},
{C.R,"上课时间不许摸鱼打块!"},
{C.R,"DD",C.Z,"炮=",C.P,"TS",C.R,"D",C.Z,"+",C.P,"TS",C.R,"D",C.Z,""},
{C.R,"DT",C.Z,"炮=",C.P,"TS",C.R,"D",C.Z,"+",C.P,"TS",C.R,"T",C.Z,""},
{C.R,"LrL ",C.G,"RlR ",C.B,"LLr ",C.O,"RRl ",C.P,"RRR LLL ",C.C,"FFF ",C.Y,"RfR RRf rFF"},
{C.W,"uid:225238922"},
{C.Y,"<φ> 10000"},
{C.Y,"10000 φ"},
{C.Y,"暂定段位:GM"},
{C.Y,"暂定段位:M"},
{C.Y,"暂定段位:MK"},
{C.Y,"暂定段位:MM"},
{C.Y,"暂定段位:MO"},
{C.Y,"暂定段位:MV"},
{C.Y,"Miya",C.Z," 可爱!"},
{C.Y,"O-spin"},
{C.Z,"12",C.C,"",C.Z,""},
{C.Z,"堆叠药水",C.H," 堆叠提升 (3:00)"},
{C.Z,"挖掘药水",C.H," 挖掘提升 (8:00)"},
{C.Z,"效率药水",C.H," 效率提升 (3:00)"},
{C.Z,"协调药水",C.H," MD减少 II(1:30)"},
-- "Z酱 可爱!",
}
}

View File

@@ -1,7 +1,7 @@
return{
["apkCode"]=424,
["apkCode"]=425,
["code"]=1701,
["string"]="V0.17.1",
["room"]="ver A-2",
["room"]="ver A-3",
["name"]="苏醒 Wake Up",
}