Merge branch 'wstest_3_28' into main

This commit is contained in:
MrZ626
2021-04-07 09:39:21 +08:00
72 changed files with 2179 additions and 1772 deletions

View File

@@ -165,7 +165,7 @@ function love.touchpressed(id,x,y)
if SCN.touchDown then SCN.touchDown(x,y)end
if kb.hasTextInput()then kb.setTextInput(false)end
end
function love.touchmoved(id,x,y,dx,dy)
function love.touchmoved(_,x,y,dx,dy)
if SCN.swapping then return end
x,y=xOy:inverseTransformPoint(x,y)
if SCN.touchMove then SCN.touchMove(x,y,dx/SCR.k,dy/SCR.k)end
@@ -205,7 +205,7 @@ local function noDevkeyPressed(key)
LOG.print(string.format("System:%s[%s]\nluaVer:%s\njitVer:%s\njitVerNum:%s",SYSTEM,jit.arch,_VERSION,jit.version,jit.version_num))
elseif key=="f3"then
for _=1,8 do
local P=PLAYERS.alive[rnd(#PLAYERS.alive)]
local P=PLY_ALIVE[rnd(#PLY_ALIVE)]
if P~=PLAYERS[1]then
P.lastRecv=PLAYERS[1]
P:lose()
@@ -382,7 +382,7 @@ function love.errorhandler(msg)
love.audio.stop()
gc.reset()
if LOADED and #ERRDATA<5 then
if LOADED and #ERRDATA<3 then
BG.set("none")
local scn=SCN and SCN.cur or"NULL"
ERRDATA[#ERRDATA+1]={mes=err,scene=scn}
@@ -444,13 +444,13 @@ function love.errorhandler(msg)
end
end
end
local WSnames={"app","user","chat","play","stream"}
local WSnames={"app","user","play","stream","chat"}
local WScolor={
{1,0,0,.26},
{1,.7,0,.26},
{0,.7,1,.26},
{0,1,0,.26},
{1,1,0,.26}
{1,.5,.5,.7},
{1,.8,.3,.7},
{1,1,.4,.7},
{.4,1,.7,.7},
{.5,.8,1,.7},
}
local devColor={
COLOR.white,
@@ -511,7 +511,7 @@ function love.run()
if SCN.swapping then SCN.swapUpdate()end--Scene swapping animation
WIDGET.update()--Widgets animation
LOG.update()
WS.update()
WS.update(dt)
--DRAW
if not MINI()then
@@ -587,22 +587,21 @@ function love.run()
for i=1,5 do
local status=WS.status(WSnames[i])
gc_setColor(WScolor[i])
gc_rectangle("fill",0,20*i,-20,-20)
gc_rectangle("fill",0,20*i,-80,-20)
if status=="dead"then
gc_setColor(.8,.8,.8)
gc_setColor(1,1,1)
gc_draw(TEXTURE.ws_dead,-20,20*i-20)
elseif status=="connecting"then
gc_setColor(.8,.8,.8,.5+.3*sin(t*6.26))
gc_setColor(1,1,1,.5+.3*sin(t*6.26))
gc_draw(TEXTURE.ws_connecting,-20,20*i-20)
elseif status=="running"then
gc_setColor(.8,.8,.8)
gc_setColor(1,1,1)
gc_draw(TEXTURE.ws_running,-20,20*i-20)
end
local lastPongTime=WS.lastPongTime(WSnames[i])
if lastPongTime<1 then
gc_setColor(1,1,1,1-lastPongTime)
gc_rectangle("fill",0,20*i,-20,-20)
end
local t1,t2,t3=WS.getTimers(WSnames[i])
gc_setColor(1,1,1,t1)gc_rectangle("fill",-60,20*i,-20,-20)
gc_setColor(0,1,0,t2)gc_rectangle("fill",-40,20*i,-20,-20)
gc_setColor(1,0,0,t3)gc_rectangle("fill",-20,20*i,-20,-20)
end
gc_pop()

View File

@@ -137,7 +137,8 @@ function SCN.swapTo(tar,style)--Parallel scene swapping, cannot back
SCN.swapping=true
local S=SCN.stat
S.tar,S.style=tar,style
S.time,S.mid,S.draw=unpack(swap[style])
local s=swap[style]
S.time,S.mid,S.draw=s[1],s[2],s[3]
end
else
LOG.print("No Scene: "..tar,"warn")
@@ -152,6 +153,8 @@ function SCN.go(tar,style)--Normal scene swapping, can back
end
end
function SCN.back()
if SCN.swapping then return end
--Leave scene
if SCN.sceneBack then SCN.sceneBack()end

View File

@@ -1,5 +1,6 @@
local gc=love.graphics
local setColor,setWidth=gc.setColor,gc.setLineWidth
local sin,cos=math.sin,math.cos
local max,min=math.max,math.min
local rnd=math.random
local rem=table.remove
@@ -77,8 +78,13 @@ function FXdraw.tap(S)
gc.circle("line",S.x,S.y,t*(2-t)*30)
setColor(1,1,1,(1-t)*.5)
gc.circle("fill",S.x,S.y,t*30)
setColor(1,1,1,(1-t)*.2)
gc.circle("fill",S.x,S.y,(t*(1-t)*2)*30)
setColor(1,1,1,1-t)
for i=1,10 do
local p=S.ptc[i]
local T=t^.5
gc.rectangle("fill",p[1]*(1-T)+p[3]*T-5,p[2]*(1-T)+p[4]*T-5,11,11)
end
end
function FXdraw.ripple(S)
local t=S.t
@@ -142,13 +148,21 @@ function SYSFX.newAttack(rate,x1,y1,x2,y2,wid,r,g,b,a)
}
end
function SYSFX.newTap(rate,x,y)
fx[#fx+1]={
local T=
{
update=FXupdate.tap,
draw=FXdraw.tap,
t=0,
rate=rate,
x=x,y=y,
ptc={},
}
for i=1,10 do
local d=40+50*rnd()
local ang=rnd()*6.2832
T.ptc[i]={x,y,x+d*cos(ang),y+d*sin(ang)}
end
fx[#fx+1]=T
end
function SYSFX.newRipple(rate,x,y,r)
fx[#fx+1]={

View File

@@ -1,5 +1,7 @@
local next,type=next,type
local TABLE={}
--Copy [1~#] elements
function TABLE.shift(org)
local L={}
for i=1,#org do
@@ -11,6 +13,8 @@ function TABLE.shift(org)
end
return L
end
--Copy all elements
function TABLE.copy(org)
local L={}
for k,v in next,org do
@@ -22,18 +26,22 @@ function TABLE.copy(org)
end
return L
end
function TABLE.add(G,base)--For all things in G if same type in base, push to base
--For all things in G if same type in base, push to base
function TABLE.update(G,base)
for k,v in next,G do
if type(v)==type(base[k])then
if type(v)=="table"then
TABLE.add(v,base[k])
TABLE.update(v,base[k])
else
base[k]=v
end
end
end
end
function TABLE.complete(G,base)--For all things in G if no val in base, push to base
--For all things in G if no val in base, push to base
function TABLE.complete(G,base)
for k,v in next,G do
if base[k]==nil then
base[k]=v
@@ -42,6 +50,22 @@ function TABLE.complete(G,base)--For all things in G if no val in base, push to
end
end
end
--Remove positive integer index of table
function TABLE.cut(G)
for i=#G,1,-1 do
G[i]=nil
end
end
--Clear table
function TABLE.clear(G)
for k in next,G do
G[k]=nil
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

View File

@@ -1,6 +1,5 @@
local rem=table.remove
local ct=coroutine
local assert=assert
local assert,resume,status=assert,coroutine.resume,coroutine.status
local tasks={}
local TASK={}
@@ -10,16 +9,17 @@ end
function TASK.update()
for i=#tasks,1,-1 do
local T=tasks[i]
assert(ct.resume(T.thread))
if ct.status(T.thread)=="dead"then
rem(tasks,i)
if status(T.thread)=="dead"then
rem(tasks,i)
else
assert(resume(T.thread))
end
end
end
function TASK.new(code,...)
local thread=ct.create(code)
ct.resume(thread,...)
if ct.status(thread)~="dead"then
local thread=coroutine.create(code)
resume(thread,...)
if status(thread)~="dead"then
tasks[#tasks+1]={
thread=thread,
code=code,

View File

@@ -27,6 +27,10 @@ function THEME.calculate(Y,M,D)
})[Y-2000]or -26)-((M-1)*31+D))<6 and
"sprfes"or
--April fool's day
M=="04"and D=="01"and
"fool"or
--Z day (Feb./Mar./Apr./May./June 26)
math.abs(M-4)<=2 and D+0==26 and
"zday"or
@@ -53,6 +57,9 @@ function THEME.set(theme)
elseif theme=="zday"then
BG.setDefault("lanterns")
BGM.setDefault("overzero")
elseif theme=="fool"then
BG.setDefault("blockrain")
BGM.setDefault("how feeling")
else
return
end

View File

@@ -4,51 +4,19 @@ local host="hdustea.3322.org"
local port="10026"
local path="/tech/socket/v1"
local debug=false
local wsThread=[[
-- lua + love2d threading websocket client
-- Original pure lua ver. by flaribbit and Particle_G and MrZ
-- Original pure lua ver. by flaribbit and Particle_G
-- Threading version by MrZ
local triggerCHN,sendCHN,readCHN=...
local triggerCHN,sendCHN,readCHN,threadName=...
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 SOCK=require"socket".tcp()
local JSON=require"Zframework.json"
local mask_key={1,14,5,14}
local function _send(opcode,message)
--Message type
SOCK:send(char(bor(0x80,opcode)))
if not message then
SOCK:send(char(0x80,unpack(mask_key)))
return 0
end
--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
SOCK:send(char(unpack(mask_key)))
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(char(unpack(msgbyte)))
end
do--Connect
local host=sendCHN:demand()
local port=sendCHN:demand()
@@ -57,48 +25,97 @@ do--Connect
SOCK:settimeout(2.6)
local res,err=SOCK:connect(host,port)
if res then
--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
)
if err then readCHN:push(err)return end
--First line of HTTP
local l=SOCK:receive("*l")
local code,ctLen
if l then
code=l:find(" "); code=l:sub(code+1,code+3)
repeat
l=SOCK:receive("*l")
if not ctLen and l:find"length"then
ctLen=tonumber(l:match"%d+")
end
until l==""
--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")
if not res then readCHN:push(err)return end
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")
if not res then readCHN:push(err)return end
if not ctLen and res:find"length"then
ctLen=tonumber(res:match"%d+")
end
until res==""
--Result
if ctLen then
if code=="101"then
readCHN:push("success")
else
local reason=JSON.decode(SOCK:receive(ctLen))
readCHN:push(code..":"..(reason and reason.message or"Server Error"))
res,err=SOCK:receive(ctLen)
if not res then readCHN:push(err)return end
res=JSON.decode(res)
readCHN:push((code or"XXX")..":"..(res and res.reason or"Server Error"))
end
else
readCHN:push(err)
end
SOCK:settimeout(0)
end
local byte=string.byte
local band,shl=bit.band,bit.lshift
local _send do
local char=string.char
local bor,bxor=bit.bor,bit.bxor
local shr=bit.rshift
local mask_key={1,14,5,14}
local mask_str=char(unpack(mask_key))
function _send(opcode,message)
--Message type
SOCK:send(char(bor(0x80,opcode)))
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
SOCK:send(mask_str)
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(char(unpack(msgbyte)))
else
SOCK:send("\128"..mask_str)
return 0
end
end
end
local length
local lBuffer=""--Long multi-data buffer
local UFF--Un-finished-frame mode
local sBuffer=""--Short multi-frame buffer
while true do--Running
--Send
triggerCHN:demand()
while sendCHN:getCount()>=2 do
local op=sendCHN:pop()
@@ -106,39 +123,85 @@ while true do--Running
_send(op,message)
end
while true do--Read
--Byte 0-1
local res,err=SOCK:receive(2)
if not res then break end
local op=band(byte(res,1),0x0f)
--Calculating data length
local length=band(byte(res,2),0x7f)
if length==126 then
res=SOCK:receive(2)
length=shl(byte(res,1),8)+byte(res,2)
elseif length==127 then
res=SOCK:receive(8)
local b={byte(res,1,8)}
length=shl(b[5],32)+shl(b[6],24)+shl(b[7],8)+b[8]
end
--Receive data
res=SOCK:receive(length)
--React
readCHN:push(op)
if op==8 then--close
SOCK:close()
if type(res)=="string"then
local reason=JSON.decode(res)
readCHN:push(reason and reason.message or"Server Error")
else
readCHN:push("Server Error")
--Read
while true do
if UFF then--UNF process
local s,e,p=SOCK:receive(length)
if s then
sBuffer=sBuffer..s
UFF=false
elseif p then
sBuffer=sBuffer..p
length=length-#p
if length==0 then
UFF=false
end
end
else
readCHN:push(res)
--Byte 0-1
local res,err=SOCK:receive(2)
if err then break end
local op=band(byte(res,1),0x0f)
local fin=band(byte(res,1),0x80)==0x80
--Calculating data length
length=band(byte(res,2),0x7f)
if length==126 then
res=SOCK:receive(2)
length=shl(byte(res,1),8)+byte(res,2)
elseif length==127 then
local b={byte(SOCK:receive(8),1,8)}
length=shl(b[5],24)+shl(b[6],16)+shl(b[7],8)+b[8]
end
if length>0 then
--Receive data
local s,_,p=SOCK:receive(length)
if s then
]]..(debug==1 and""or"--")..[[print(("%s[%d]:%s"):format(threadName,length,s))
res=s
elseif p then--UNF head
]]..(debug==1 and""or"--")..[[print(("%s[%d/%d]:%s"):format(threadName,#p,length,p))
UFF=true
sBuffer=sBuffer..p
length=length-#p
break
end
else
res=""
end
--React
if op==8 then--8=close
readCHN:push(op)
SOCK:close()
if type(res)=="string"then
res=JSON.decode(res)
readCHN:push(res and res.reason or"WS Error")
else
readCHN:push("WS Error")
end
elseif op==0 then--0=continue
lBuffer=lBuffer..res
if fin then
]]..(debug==2 and""or"--")..[[print("FIN=1 (c")
readCHN:push(lBuffer)
lBuffer=""
else
]]..(debug==2 and""or"--")..[[print("FIN=0 (c")
end
else
readCHN:push(op)
if fin then
]]..(debug==2 and""or"--")..[[print("OP: "..op.."\tFIN=1")
readCHN:push(res)
else
]]..(debug==2 and""or"--")..[[print("OP: "..op.."\tFIN=0")
sBuffer=res
]]..(debug==2 and""or"--")..[[print("START pack: "..res)
end
end
end
end
end
@@ -146,10 +209,24 @@ end
local timer=love.timer.getTime
local WS={}
local wsList={}
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.connect(name,subPath,body)
local ws={
real=true,
thread=love.thread.newThread(wsThread),
triggerCHN=love.thread.newChannel(),
sendCHN=love.thread.newChannel(),
@@ -158,9 +235,12 @@ function WS.connect(name,subPath,body)
lastPongTime=timer(),
pingInterval=26,
status="connecting",--connecting, running, dead
sendTimer=0,
alertTimer=0,
pongTimer=0,
}
wsList[name]=ws
ws.thread:start(ws.triggerCHN,ws.sendCHN,ws.readCHN)
ws.thread:start(ws.triggerCHN,ws.sendCHN,ws.readCHN,name)
ws.sendCHN:push(host)
ws.sendCHN:push(port)
ws.sendCHN:push(path..subPath)
@@ -168,11 +248,13 @@ function WS.connect(name,subPath,body)
end
function WS.status(name)
return wsList[name]and wsList[name].status or"dead"
local ws=wsList[name]
return ws.status or"dead"
end
function WS.lastPongTime(name)
return wsList[name]and timer()-wsList[name].lastPongTime or 999
function WS.getTimers(name)
local ws=wsList[name]
return ws.pongTimer,ws.sendTimer,ws.alertTimer
end
function WS.setPingInterval(name,time)
@@ -180,6 +262,11 @@ function WS.setPingInterval(name,time)
ws.pingInterval=math.max(time or 1,2.6)
end
function WS.alert(name)
local ws=wsList[name]
ws.alertTimer=2
end
local OPcode={
continue=0,
text=1,
@@ -188,54 +275,76 @@ local OPcode={
ping=9,
pong=10,
}
local OPname={
[0]="continue",
[1]="text",
[2]="binary",
[8]="close",
[9]="ping",
[10]="pong",
}
function WS.send(name,message,op)
local ws=wsList[name]
ws.sendCHN:push(op and OPcode[op]or 2)--2=binary
ws.sendCHN:push(message)
ws.lastPingTime=timer()
if ws.real then
ws.sendCHN:push(op and OPcode[op]or 2)--2=binary
ws.sendCHN:push(message)
ws.lastPingTime=timer()
ws.sendTimer=1
end
end
function WS.read(name)
local ws=wsList[name]
if ws.readCHN:getCount()>=2 then
if ws.real and ws.readCHN:getCount()>=2 then
local op=ws.readCHN:pop()
local message=ws.readCHN:pop()
if op==8 then ws.status="dead"end
if op==8 then ws.status="dead"end--8=close
ws.lastPongTime=timer()
return message,op
ws.pongTimer=1
return message,OPname[op]or op
end
end
function WS.close(name)
local ws=wsList[name]
ws.sendCHN:push(8)--close
ws.sendCHN:push("")
ws.status="dead"
if ws.real then
ws.sendCHN:push(8)--close
ws.sendCHN:push("")
ws.status="dead"
end
end
function WS.update()
function WS.update(dt)
local time=timer()
for name,ws in next,wsList do
ws.triggerCHN:push(0)
if ws.status=="connecting"then
local mes=ws.readCHN:pop()
if mes then
if mes=="success"then
ws.status="running"
if ws.real then
ws.triggerCHN:push(0)
if ws.status=="connecting"then
local mes=ws.readCHN:pop()
if mes then
if mes=="success"then
ws.status="running"
ws.lastPingTime=time
ws.lastPongTime=time
ws.pongTimer=1
else
ws.status="dead"
LOG.print(text.wsFailed..": "..(mes=="timeout"and text.netTimeout or mes),"warn")
end
end
elseif ws.status=="running"then
if time-ws.lastPingTime>ws.pingInterval then
ws.sendCHN:push(9)
ws.sendCHN:push("")--ping
ws.lastPingTime=time
ws.lastPongTime=time
else
ws.status="dead"
LOG.print(text.wsFailed.." "..mes,"warn")
end
if time-ws.lastPongTime>10+3*ws.pingInterval then
WS.close(name)
end
end
elseif time-ws.lastPingTime>ws.pingInterval then
ws.sendCHN:push(9)
ws.sendCHN:push("")--ping
ws.lastPingTime=time
end
if time-ws.lastPongTime>10+3*ws.pingInterval then
WS.close(name)
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
end
end
end

View File

@@ -141,7 +141,8 @@ end
function button:draw()
local x,y,w,h=self.x,self.y,self.w,self.h
local ATV=self.ATV
local r,g,b=unpack(self.color)
local c=self.color
local r,g,b=c[1],c[2],c[3]
gc.setColor(.2+r*.8,.2+g*.8,.2+b*.8,.7)
gc.rectangle("fill",x-ATV,y-ATV,w+2*ATV,h+2*ATV)
if ATV>0 then
@@ -233,7 +234,8 @@ end
function key:draw()
local x,y,w,h=self.x,self.y,self.w,self.h
local ATV=self.ATV
local r,g,b=unpack(self.color)
local c=self.color
local r,g,b=c[1],c[2],c[3]
gc.setColor(1,1,1,ATV*.125)
gc.rectangle("fill",x,y,w,h)

View File

@@ -1,5 +1,5 @@
VERSION_CODE=1303
VERSION_NAME="Alpha V0.13.3"
VERSION_CODE=1400
VERSION_NAME="Alpha V0.14.0"
function love.conf(t)
t.identity="Techmino"--Saving folder
t.version="11.1"

View File

@@ -23,12 +23,7 @@ SAVEDIR=fs.getSaveDirectory()
--Global Vars & Settings
LOADED=false
DAILYLAUNCH=false
LOGIN=false
EDITING=""
NET={
allow_online=false,
try_enter_netmenu=false,
}
ERRDATA={}
--System setting
@@ -81,6 +76,7 @@ require"parts.gametoolfunc"
SCR.setSize(1280,720)--Initialize Screen size
FIELD[1]=newBoard()--Initialize field[1]
NET= require"parts.net"
AIBUILDER= require"parts.AITemplate"
FREEROW= require"parts.freeRow"
@@ -113,14 +109,14 @@ IMG.init{
pay1="mess/pay1.png",
pay2="mess/pay2.png",
miyaCH="miya/ch.png",
miyaF1="miya/f1.png",
miyaF2="miya/f2.png",
miyaF3="miya/f3.png",
miyaF4="miya/f4.png",
electric="mess/electric.png",
hbm="mess/hbm.png",
nakiCH="characters/naki.png",
miyaCH="characters/miya.png",
miyaF1="characters/miya_f1.png",
miyaF2="characters/miya_f2.png",
miyaF3="characters/miya_f3.png",
miyaF4="characters/miya_f4.png",
electric="characters/electric.png",
hbm="characters/hbm.png",
lanterns={
"lanterns/1.png",
@@ -259,14 +255,12 @@ do
if type(STAT.version)~="number"then
STAT.version=0
end
if STAT.version<1204 then
if STAT.version<1300 then
STAT.frame=math.floor(STAT.time*60)
STAT.lastPlay="sprint_10l"
RANKS.sprintFix=nil
RANKS.sprintLock=nil
needSave=true
end
if STAT.version<1300 then
for _,name in next,fs.getDirectoryItems("replay")do
fs.remove("replay/"..name)
end
@@ -274,13 +268,15 @@ do
if STAT.version<1302 then
if RANKS.pctrain_n then RANKS.pctrain_n=0 end
if RANKS.pctrain_l then RANKS.pctrain_l=0 end
fs.remove("conf/user")
fs.remove("conf/settings")
needSave=true
autoRestart=true
end
if STAT.version<1303 then
if STAT.version<1400 then
fs.remove("conf/user")
SETTING.appLock=false
needSave=true
autoRestart=true
end
for _,v in next,VK_org do

View File

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

Before

Width:  |  Height:  |  Size: 74 KiB

After

Width:  |  Height:  |  Size: 74 KiB

View File

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

View File

@@ -1,6 +1,6 @@
local int,ceil,min,abs,rnd,modf=math.floor,math.ceil,math.min,math.abs,math.random,math.modf
local ins,rem=table.insert,table.remove
local resume,yield=coroutine.resume,coroutine.yield
local yield=coroutine.yield
-- controlname:
-- 1~5:mL,mR,rR,rL,rF,
-- 6~10:hD,sD,H,A,R,
@@ -73,13 +73,13 @@ if type(_CC)=="table"then
end
CC.updateField(P)
while P.holdQueue[1]do rem(P.holdQueue)end
TABLE.clear(P.holdQueue)
P.holdTime=P.gameEnv.holdCount
P.cur=rem(P.nextQueue,1)
P.curX,P.curY=blockPos[P.cur.id],int(P.gameEnv.fieldH+1-modf(P.cur.sc[1]))+ceil(P.fieldBeneath/30)
assert(resume(P.newNext))
P.newNext()
local id=CCblockID[P.nextQueue[P.AIdata.next].id]
if id then
CC.addNext(P.AI_bot,id)

View File

@@ -0,0 +1,56 @@
--Block rain
local gc=love.graphics
local rnd=math.random
local ins,rem=table.insert,table.remove
local back={}
local t
local cell
function back.init()
t=0
cell={}
end
function back.update()
t=t+1
if t%10==0 then
ins(cell,{
bid=rnd(29),
x=SCR.w*rnd(),
y=-25,
a=rnd()*6.2832,
vy=.5+rnd()*.4,
vx=rnd()*.4-.2,
va=rnd()*.04-.02,
})
end
for i=#cell,1,-1 do
local P=cell[i]
P.y=P.y+P.vy
if P.y>SCR.h+25 then
rem(cell,i)
else
P.x=P.x+P.vx
P.a=P.a+P.va
P.vx=P.vx-.01+rnd()*.02
end
end
end
function back.draw()
gc.clear(.15,.15,.15)
gc.push("transform")
gc.origin()
local texture=TEXTURE.miniBlock
local minoColor=minoColor
for i=1,#cell do
local C=cell[i]
local tex=texture[C.bid]
local c=minoColor[SETTING.skin[C.bid]]
gc.setColor(c[1],c[2],c[3],.5)
gc.draw(tex,C.x,C.y,C.a,10,10,tex:getWidth()/2,tex:getHeight()/2)
end
gc.pop()
end
function back.discard()
cell=nil
end
return back

View File

@@ -271,10 +271,10 @@ end
--Royale mode
function randomTarget(P)--Return a random opponent for P
if #PLAYERS.alive>1 then
if #PLY_ALIVE>1 then
local R
repeat
R=PLAYERS.alive[rnd(#PLAYERS.alive)]
R=PLY_ALIVE[rnd(#PLY_ALIVE)]
until R~=P
return R
end
@@ -282,28 +282,28 @@ end
function freshMostDangerous()
GAME.mostDangerous,GAME.secDangerous=false,false
local m,m2=0,0
for i=1,#PLAYERS.alive do
local h=#PLAYERS.alive[i].field
for i=1,#PLY_ALIVE do
local h=#PLY_ALIVE[i].field
if h>=m then
GAME.mostDangerous,GAME.secDangerous=PLAYERS.alive[i],GAME.mostDangerous
GAME.mostDangerous,GAME.secDangerous=PLY_ALIVE[i],GAME.mostDangerous
m,m2=h,m
elseif h>=m2 then
GAME.secDangerous=PLAYERS.alive[i]
GAME.secDangerous=PLY_ALIVE[i]
m2=h
end
end
for i=1,#PLAYERS.alive do
if PLAYERS.alive[i].atkMode==3 then
PLAYERS.alive[i]:freshTarget()
for i=1,#PLY_ALIVE do
if PLY_ALIVE[i].atkMode==3 then
PLY_ALIVE[i]:freshTarget()
end
end
end
function freshMostBadge()
GAME.mostBadge,GAME.secBadge=false,false
local m,m2=0,0
for i=1,#PLAYERS.alive do
local P=PLAYERS.alive[i]
for i=1,#PLY_ALIVE do
local P=PLY_ALIVE[i]
local b=P.badge
if b>=m then
GAME.mostBadge,GAME.secBadge=P,GAME.mostBadge
@@ -314,44 +314,44 @@ function freshMostBadge()
end
end
for i=1,#PLAYERS.alive do
if PLAYERS.alive[i].atkMode==4 then
PLAYERS.alive[i]:freshTarget()
for i=1,#PLY_ALIVE do
if PLY_ALIVE[i].atkMode==4 then
PLY_ALIVE[i]:freshTarget()
end
end
end
function royaleLevelup()
GAME.stage=GAME.stage+1
local spd
TEXT.show(text.royale_remain:gsub("$1",#PLAYERS.alive),640,200,40,"beat",.3)
TEXT.show(text.royale_remain:gsub("$1",#PLY_ALIVE),640,200,40,"beat",.3)
if GAME.stage==2 then
spd=30
elseif GAME.stage==3 then
spd=15
for _,P in next,PLAYERS.alive do
for _,P in next,PLY_ALIVE do
P.gameEnv.garbageSpeed=.6
end
if PLAYERS[1].alive then BGM.play("cruelty")end
elseif GAME.stage==4 then
spd=10
for _,P in next,PLAYERS.alive do
for _,P in next,PLY_ALIVE do
P.gameEnv.pushSpeed=3
end
elseif GAME.stage==5 then
spd=5
for _,P in next,PLAYERS.alive do
for _,P in next,PLY_ALIVE do
P.gameEnv.garbageSpeed=1
end
elseif GAME.stage==6 then
spd=3
if PLAYERS[1].alive then BGM.play("final")end
end
for _,P in next,PLAYERS.alive do
for _,P in next,PLY_ALIVE do
P.gameEnv.drop=spd
end
if GAME.curMode.name:find("_u")then
for i=1,#PLAYERS.alive do
local P=PLAYERS.alive[i]
for i=1,#PLY_ALIVE do
local P=PLY_ALIVE[i]
P.gameEnv.drop=int(P.gameEnv.drop*.3)
if P.gameEnv.drop==0 then
P.curY=P.ghoY
@@ -537,9 +537,7 @@ function destroyPlayers()--Destroy all player objects, restore freerows and free
end
PLAYERS[i]=nil
end
for i=#PLAYERS.alive,1,-1 do
PLAYERS.alive[i]=nil
end
TABLE.clear(PLY_ALIVE)
collectgarbage()
end
function restoreVirtualkey()
@@ -611,7 +609,7 @@ function loadGame(M,ifQuickPlay,ifNet)--Load a mode and go to game scene
end
end
function initPlayerPosition(sudden)--Set initial position for every player
local L=PLAYERS.alive
local L=PLY_ALIVE
if not sudden then
for i=1,#L do
L[i]:setPosition(640,#L<=5 and 360 or -62,0)
@@ -715,7 +713,7 @@ do--function resetGameData(args)
end
return S
end
function resetGameData(args,playerData,seed)
function resetGameData(args,seed)
if not args then args=""end
if PLAYERS[1]and not GAME.replaying and(GAME.frame>400 or GAME.result)then
mergeStat(STAT,PLAYERS[1].stat)
@@ -744,7 +742,7 @@ do--function resetGameData(args)
end
destroyPlayers()
GAME.curMode.load(playerData)
GAME.curMode.load()
initPlayerPosition(args:find("q"))
restoreVirtualkey()
if GAME.modeEnv.task then
@@ -958,7 +956,7 @@ do--function saveRecording()
os.date("%Y/%m/%d %A %H:%M:%S\n")..
GAME.curModeName.."\n"..
VERSION_NAME.."\n"..
(USER.name or"Player")
(USER.username or"Player")
local fileBody=
GAME.seed.."\n"..
JSON.encode(GAME.setting).."\n"..
@@ -982,25 +980,26 @@ end
--Game draw
do--function drawFWM()
local m={
"\230\184\184\230\136\143\228\189\156\232\128\133\58\77\114\90\95\50\54\10\228\187\187\228\189\149\232\167\134\233\162\145\47\231\155\180\230\146\173\228\184\141\229\190\151\229\135\186\231\142\176\230\173\164\230\176\180\229\141\176\10\228\187\187\228\189\149\232\189\172\232\191\176\229\163\176\230\152\142\230\151\160\230\149\136",
"\230\184\184\230\136\143\228\189\156\232\128\133\58\77\114\90\95\50\54\10\228\187\187\228\189\149\232\167\134\233\162\145\47\231\155\180\230\146\173\228\184\141\229\190\151\229\135\186\231\142\176\230\173\164\230\176\180\229\141\176\10\228\187\187\228\189\149\232\189\172\232\191\176\229\163\176\230\152\142\230\151\160\230\149\136",
"\230\184\184\230\136\143\228\189\156\232\128\133\58\77\114\90\95\50\54\10\228\187\187\228\189\149\232\167\134\233\162\145\47\231\155\180\230\146\173\228\184\141\229\190\151\229\135\186\231\142\176\230\173\164\230\176\180\229\141\176\10\228\187\187\228\189\149\232\189\172\232\191\176\229\163\176\230\152\142\230\151\160\230\149\136",
"\65\117\116\104\111\114\58\32\77\114\90\95\50\54\n\82\101\99\111\114\100\105\110\103\115\32\99\111\110\116\97\105\110\105\110\103\32\116\104\105\115\n\119\97\116\101\114\109\97\114\107\32\97\114\101\32\117\110\97\117\116\104\111\114\105\122\101\100",
"\67\114\195\169\97\116\101\117\114\32\100\117\32\106\101\117\58\32\77\114\90\95\50\54\10\69\110\114\101\103\105\115\116\114\101\109\101\110\116\32\110\111\110\32\97\117\116\111\114\105\115\195\169\10\99\111\110\116\101\110\97\110\116\32\99\101\32\102\105\108\105\103\114\97\110\101",
"\65\117\116\111\114\58\32\77\114\90\95\50\54\10\71\114\97\98\97\99\105\195\179\110\32\110\111\32\97\117\116\111\114\105\122\97\100\97\32\113\117\101\10\99\111\110\116\105\101\110\101\32\101\115\116\97\32\109\97\114\99\97\32\100\101\32\97\103\117\97",
"\65\117\116\111\114\32\100\111\32\106\111\103\111\58\32\77\114\90\95\50\54\10\71\114\97\118\97\195\167\195\181\101\115\32\99\111\110\116\101\110\100\111\32\101\115\116\97\32\77\97\114\99\97\10\100\101\32\195\161\103\117\97\32\110\195\163\111\32\115\195\163\111\32\97\117\116\111\114\105\122\97\100\97\115",
"\65\117\116\104\111\114\58\32\77\114\90\95\50\54\10\82\101\99\111\114\100\105\110\103\115\32\99\111\110\116\97\105\110\105\110\103\32\116\104\105\115\10\119\97\116\101\114\109\97\114\107\32\97\114\101\32\117\110\97\117\116\104\111\114\105\122\101\100",
string.char(230,184,184,230,136,143,228,189,156,232,128,133,58,77,114,90,95,50,54,10,228,187,187,228,189,149,232,167,134,233,162,145,47,231,155,180,230,146,173,228,184,141,229,190,151,229,135,186,231,142,176,230,173,164,230,176,180,229,141,176,10,228,187,187,228,189,149,232,189,172,232,191,176,229,163,176,230,152,142,230,151,160,230,149,136),
string.char(230,184,184,230,136,143,228,189,156,232,128,133,58,77,114,90,95,50,54,10,228,187,187,228,189,149,232,167,134,233,162,145,47,231,155,180,230,146,173,228,184,141,229,190,151,229,135,186,231,142,176,230,173,164,230,176,180,229,141,176,10,228,187,187,228,189,149,232,189,172,232,191,176,229,163,176,230,152,142,230,151,160,230,149,136),
string.char(230,184,184,230,136,143,228,189,156,232,128,133,58,77,114,90,95,50,54,10,228,187,187,228,189,149,232,167,134,233,162,145,47,231,155,180,230,146,173,228,184,141,229,190,151,229,135,186,231,142,176,230,173,164,230,176,180,229,141,176,10,228,187,187,228,189,149,232,189,172,232,191,176,229,163,176,230,152,142,230,151,160,230,149,136),
string.char(65,117,116,104,111,114,58,32,77,114,90,95,50,54,10,82,101,99,111,114,100,105,110,103,115,32,99,111,110,116,97,105,110,105,110,103,32,116,104,105,115,10,119,97,116,101,114,109,97,114,107,32,97,114,101,32,117,110,97,117,116,104,111,114,105,122,101,100),
string.char(67,114,195,169,97,116,101,117,114,32,100,117,32,106,101,117,58,32,77,114,90,95,50,54,10,69,110,114,101,103,105,115,116,114,101,109,101,110,116,32,110,111,110,32,97,117,116,111,114,105,115,195,169,10,99,111,110,116,101,110,97,110,116,32,99,101,32,102,105,108,105,103,114,97,110,101),
string.char(65,117,116,111,114,58,32,77,114,90,95,50,54,10,71,114,97,98,97,99,105,195,179,110,32,110,111,32,97,117,116,111,114,105,122,97,100,97,32,113,117,101,10,99,111,110,116,105,101,110,101,32,101,115,116,97,32,109,97,114,99,97,32,100,101,32,97,103,117,97),
string.char(65,117,116,111,114,32,100,111,32,106,111,103,111,58,32,77,114,90,95,50,54,10,71,114,97,118,97,195,167,195,181,101,115,32,99,111,110,116,101,110,100,111,32,101,115,116,97,32,77,97,114,99,97,10,100,101,32,195,161,103,117,97,32,110,195,163,111,32,115,195,163,111,32,97,117,116,111,114,105,122,97,100,97,115),
string.char(65,117,116,104,111,114,58,32,77,114,90,95,50,54,10,82,101,99,111,114,100,105,110,103,115,32,99,111,110,116,97,105,110,105,110,103,32,116,104,105,115,10,119,97,116,101,114,109,97,114,107,32,97,114,101,32,117,110,97,117,116,104,111,114,105,122,101,100),
}
--你竟然找到了这里!那么在动手之前读读下面这些吧。
--千万不要为了在网络公共场合发视 频或者直播需要而擅自删除这部分代码!
--录制视 频上传到公共场合(包括但不限于任何视 频平台/论坛/几十个人以上的社区群等)很可能会对Techmino未来的发展有负面影响
--【魔幻躲关键字搜索警告,看得懂就行】
--千万不要为了在网络公共场合发视屏或者直播需要而擅自删除这部分代码!
--录制视屏上传到公共场合(包括但不限于任何视屏平台/论坛/几十个人以上的社区群等)很可能会对Techmino未来的发展有负面影响
--如果被TTC发现TTC随时可以用DMCA从法律层面强迫停止开发到时候谁都没得玩。这是真的已经有几个方块这么死了…
--印限制还可以减少低质量视泛滥,也能减轻过多不是真的感兴趣路人玩家入坑可能带来的压力
--想发视的话请先向作者申请,描述录制的大致内容,同意了才可以去关闭
--印限制还可以减少低质量视泛滥,也能减轻过多不是真的感兴趣路人玩家入坑可能带来的压力
--想发视的话请先向作者申请,描述录制的大致内容,同意了才可以去关闭
--等Techmino发展到一定程度之后会解除这个限制
--最后,别把藏在这里的东西截图/复制出去哦~
--感谢您对Techmino的支持
local setFont=setFont
local setFont,TIME,mStr=setFont,TIME,mStr
function drawFWM()
local t=TIME()
setFont(25)
@@ -1051,221 +1050,12 @@ do--function pressKey(k)
return cache[k]
end
end
do--lnk_CUS/SETXXX(k)
do--CUS/SETXXX(k)
local c,s=CUSTOMENV,SETTING
function lnk_CUSval(k)return function()return c[k] end end
function lnk_SETval(k)return function()return s[k] end end
function lnk_CUSrev(k)return function()c[k]=not c[k]end end
function lnk_SETrev(k)return function()s[k]=not s[k]end end
function lnk_CUSsto(k)return function(i)c[k]=i end end
function lnk_SETsto(k)return function(i)s[k]=i end end
end
--Network funcs
do
--[[
register:
if response.message=="OK"then
LOGIN=true
USER.name=res.name
USER.id=res.id
USER.motto=res.motto
USER.avatar=res.avatar
FILE.save(USER,"conf/user","q")
LOG.print(text.registerSuccessed..": "..res.message)
else
LOG.print(text.httpCode..response.code..": "..res.message,"warn")
end
goChatRoom:
if res.message=="OK"then
SCN.go("net_chat")
LOG.print(text.wsSuccessed,"warn")
else
LOG.print(text.wsFailed..": "..connErr,"warn")
end
fetchRooms:
if res.message=="OK"then
rooms=res.room_list
else
LOG.print(text.httpCode..response.code..": "..res.message,"warn")
end
createRoom:
if res.message=="OK"then
LOG.print(text.createRoomSuccessed)
enterRoom(res.room.id)
else
LOG.print(text.httpCode..res.code..": "..res.message,"warn")
end
enterRoom:
if res.message=="OK"then
loadGame("netBattle",true,true)
LOG.print(text.wsSuccessed,"warn")
else
LOG.print(text.wsFailed..": "..connErr,"warn")
end
]]
function TICK_WS_app()
local retryTime=5
while true do
YIELD()
local status=WS.status("app")
if status=="running"then
local message,op=WS.read("app")
if message then
if op=="ping"then
WS.send("app",message,"pong")
elseif op=="close"then
message=JSON.decode(message)
if message then
LOG.print(text.wsClose..message.message,"warn")
end
return
else
local res=JSON.decode(message)
if VERSION_CODE>=res.lowest then
NET.allow_online=true
end
if VERSION_CODE<res.newestCode then
LOG.print(text.oldVersion:gsub("$1",res.newestName),180,COLOR.sky)
end
LOG.print(res.notice,300,COLOR.sky)
end
end
elseif status=="dead"then
retryTime=retryTime-1
if retryTime==0 then return end
for _=1,120 do YIELD()end
WS.connect("app","/app")
end
end
end
function TICK_WS_user()
while true do
YIELD()
local status=WS.status("user")
if status=="running"then
local message,op=WS.read("user")
if message then
if op=="ping"then
WS.send("user",message,"pong")
elseif op=="close"then
message=JSON.decode(message)
if message then
LOG.print(text.wsClose..message.message,"warn")
end
return
else
local res=JSON.decode(message)
if res.message=="Connected"then
LOGIN=true
if res.id then
USER.id=res.id
USER.authToken=res.authToken
NET.try_enter_netmenu=true
WS.send("user",JSON.encode{action=0})
end
FILE.save(USER,"conf/user","q")
LOG.print(text.loginSuccessed)
--Get self infos
WS.send("user",JSON.encode{
action=1,
data={
id=USER.id,
},
})
elseif res.action==0 then
USER.accessToken=res.accessToken
LOG.print(text.accessSuccessed)
if NET.try_enter_netmenu then
NET.try_enter_netmenu=false
SCN.go("net_menu")
end
elseif res.action==1 then
USER.name=res.username
USER.motto=res.motto
USER.avatar=res.avatar
FILE.save(USER,"conf/user")
end
end
end
end
end
end
function TICK_WS_chat()
while true do
YIELD()
local status=WS.status("chat")
if status=="running"then
local message,op=WS.read("chat")
if message then
if op=="ping"then
WS.send("chat",message,"pong")
elseif op=="close"then
message=JSON.decode(message)
if message then
LOG.print(text.wsClose..message.message,"warn")
end
return
else
local res=JSON.decode(message)
--TODO
end
end
end
end
end
function TICK_WS_play()
while true do
YIELD()
local status=WS.status("play")
if status=="running"then
local message,op=WS.read("play")
if message then
if op=="ping"then
WS.send("play",message,"pong")
elseif op=="close"then
message=JSON.decode(message)
if message then
LOG.print(text.wsClose..message.message,"warn")
end
return
else
local res=JSON.decode(message)
--TODO
end
end
end
end
end
function TICK_WS_stream()
while true do
YIELD()
local status=WS.status("stream")
if status=="running"then
local message,op=WS.read("stream")
if message then
if op=="ping"then
WS.send("stream",message,"pong")
elseif op=="close"then
message=JSON.decode(message)
if message then
LOG.print(text.wsClose..message.message,"warn")
end
return
else
local res=JSON.decode(message)
--TODO
end
end
end
end
end
function CUSval(k)return function()return c[k]end end
function SETval(k)return function()return s[k]end end
function CUSrev(k)return function()c[k]=not c[k]end end
function SETrev(k)return function()s[k]=not s[k]end end
function CUSsto(k)return function(i)c[k]=i end end
function SETsto(k)return function(i)s[k]=i end end
end

View File

@@ -142,7 +142,9 @@ for i=1,#MODOPT do
end
--Game tables
PLAYERS={alive={}}--Players data
PLAYERS={}--Players data
PLY_ALIVE={}
PLY_NET={}
FIELD={}--Field(s) for custom game
BAG={}--Sequence for custom game
MISSION={}--Clearing mission for custom game
@@ -220,17 +222,14 @@ GAME={--Global game data
RANKS=FILE.load("conf/unlock")or{sprint_10l=0}--Ranks of modes
USER=FILE.load("conf/user")or{--User infomation
--Network infos
name=false,
id=false,
email=false,
motto=false,
avatar=false,
username=false,
uid=false,
authToken=false,
accessToken=false,
--Local data
xp=0,lv=1,
}
USERS=FILE.load("conf/users")or{}
SETTING={--Settings
--Tuning
das=10,arr=2,dascut=0,
@@ -300,7 +299,7 @@ SETTING={--Settings
VKAlpha=.3,
}
local S=FILE.load("conf/settings")
if S then TABLE.add(S,SETTING)end
if S then TABLE.update(S,SETTING)end
S=FILE.load("conf/data")
if S then--Statistics
STAT=S

View File

@@ -75,7 +75,6 @@ return{
needUpdate="Newer version required!",
notFinished="Coming soon!",
httpCode="HTTP status code",
jsonError="JSON error",
noUsername="Please specify a username.",
@@ -90,10 +89,8 @@ return{
accessFailed="Access Denied.",
wsSuccessed="WebSocket: Connected.",
wsFailed="WebSocket: Connection Failed.",
wsDisconnected="WebSocket: Disconnected.",
wsNoConn="WebSocket: Not Connected.",
wsClose="WebSocket Closed: ",
waitNetTask="Connecting. Please wait...",
netTimeout="Network connection timeout",
createRoomTooFast="Hold on there! We can't handle this fast!",
createRoomSuccessed="Room successfully created!",
@@ -106,7 +103,6 @@ return{
chatStart="------Beginning of log------",
chatHistory="------New messages below------",
noRooms="Such emptiness much void, come back later?",
roomsCreateFailed="Failed to create room.",
roomsFetchFailed="Failed to fetch room list.",
@@ -252,7 +248,9 @@ return{
chat="Chat",
},
net_rooms={
fresh="Reresh",
refreshing="Refreshing Rooms",
noRoom="Such emptiness much void, come back later?",
refresh="Refresh",
new="New Room",
join="Join",
up="",

View File

@@ -76,7 +76,6 @@ return{
-- needUpdate="Newer version required!",
-- notFinished="Coming soon!",
httpCode="Code de statut Http",
jsonError="Erreur json",
noUsername="Entrez votre nom d'utilisateur",
@@ -91,10 +90,8 @@ return{
accessFailed="Autorisation échouée",
wsSuccessed="WebSocket: connecté",
wsFailed="WebSocket: connection échouée",
wsDisconnected="WebSocket: déconnecté",
wsNoConn="WebSocket: vous n'êtes pas connecté",
wsError="Erreur WebSocket : ",
waitNetTask="Connexion, veuillez patienter",
-- wsClose="WebSocket Closed: ",
-- netTimeout="Network connection timeout",
createRoomTooFast="Vous avez créé un salon trop rapidement !",
createRoomSuccessed="Salon créé avec succès !",
@@ -107,7 +104,6 @@ return{
chatStart="--------Début des logs--------",
chatHistory="-Nouveaux messages en dessous-",
noRooms="Aucun salon actuellement",
roomsCreateFailed="Echec de la création du salon",
roomsFetchFailed="Echec de la récupération des salons",
@@ -186,7 +182,7 @@ return{
simple-love-lights [dylhunn]
]],
support="Aider le créateur",
group="Groupe QQ officiel (si non piraté) : 913154753",
group="Groupe QQ officiel : 913154753",
WidgetText={
main={
-- offline="Solo",
@@ -225,8 +221,9 @@ return{
chat="Chat",
},
net_rooms={
fresh="Fresh",
new="Nouveau salon",
-- refreshing="Refreshing Rooms",
noRoom="Aucun salon actuellement",
-- refresh="Refresh",
join="Rejoindre",
up="",
down="",

View File

@@ -75,7 +75,6 @@ return{
-- needUpdate="Newer version required!",
-- notFinished="Coming soon!",
-- httpCode="Http status code",
jsonError="Json error",
noUsername="Insira seu nome de usuário",
@@ -90,10 +89,8 @@ return{
accessFailed="Falha na autorização",
wsSuccessed="WebSocket: conectado",
wsFailed="WebSocket: falha na conexão",
wsDisconnected="WebSocket: desconectado",
wsNoConn="WebSocket: você não está conectado",
wsClose="WebSocket closed: ",
waitNetTask="Conectando, aguarde",
-- netTimeout="Network connection timeout",
-- createRoomTooFast="Create room too fast!",
-- createRoomSuccessed="Room successfully created!",
@@ -106,7 +103,6 @@ return{
chatStart="------Começo do log------",
chatHistory="------Novas mensagens abaixo------",
noRooms="Nenhuma sala agora",
-- roomsCreateFailed="Failed to create room",
roomsFetchFailed="Falha ao buscar salas",
@@ -252,7 +248,9 @@ return{
chat="Chat",
},
net_rooms={
fresh="Fresh",
-- refreshing="Refreshing Rooms",
noRoom="Nenhuma sala agora",
-- refresh="Refresh",
-- new="New room",
-- join="Join",
up="",

View File

@@ -76,11 +76,9 @@ return{
-- needUpdate="Newer version required!",
-- notFinished="Coming soon!",
-- httpCode="Http status code",
-- jsonError="Json error",
noUsername="Por favor ingresa un nombre de usuario",
-- wrongEmail="Wrong email address",
noPassword="Por favor ingresa una contraseña",
diffPassword="Las contraseñas no coinciden",
@@ -92,10 +90,8 @@ return{
-- accessFailed="Authorization failed",
-- wsSuccessed="WebSocket: connected",
-- wsFailed="WebSocket: connection failed",
-- wsDisconnected="WebSocket: disconnected",
-- wsNoConn="WebSocket: you are not connected",
-- wsClose="WebSocket closed: ",
-- waitNetTask="Connecting, please wait",
-- netTimeout="Network connection timeout",
-- createRoomTooFast="Create room too fast!",
-- createRoomSuccessed="Room successfully created!",
@@ -108,7 +104,6 @@ return{
-- chatStart="------Beginning of log------",
-- chatHistory="------New messages below------",
-- noRooms="No Rooms Now",
-- roomsCreateFailed="Failed to create room",
-- roomsFetchFailed="Failed to fetch rooms",
@@ -188,7 +183,7 @@ return{
simple-love-lights [dylhunn]
]],
support="Apoyen al Autor",
group="Grupo Oficial de QQ (si no lo hackean) : 913154753",
group="Grupo Oficial de QQ : 913154753",
WidgetText={
main={
-- offline="Single",
@@ -231,7 +226,9 @@ return{
-- chat="Chat",
},
net_rooms={
-- fresh="Fresh",
-- refreshing="Refreshing Rooms",
-- noRoom="No Rooms Now",
-- refresh="Refresh",
-- new="New room",
-- join="Join",
up="",

View File

@@ -83,11 +83,12 @@ return{
"□!!~~~,□□□□X",
"□!!==*/*/*/*~",
"",
"bug reports/suggestions, sent to the author's testing group or email ~",
"This is a free download available only through discord.gg/f9pUvkh",
"The game downloaded from other sources may contain viruses,",
"and only vibration & networking permissions are needed for mobile versions!",
"The author is not responsible for any losses from modifying the game.",
"Powered by LÖVE/love2d",
"Any suggestions or bug reports are appreciated!",
"Make sure to only obtain the game from official sources;",
"We can't make sure you're safe if you got it elsewhere.",
"The author is not responsible for any modified binaries.",
"While the game is free, donations are appreciated."
},
WidgetText={
main={

View File

@@ -75,7 +75,6 @@ return{
needUpdate="此功能需要更新游戏!",
notFinished="暂未完成,敬请期待!",
httpCode="Http码",
jsonError="json错误",
noUsername="请填写用户名",
@@ -90,10 +89,8 @@ return{
accessFailed="身份验证失败",
wsSuccessed="WS连接成功",
wsFailed="WS连接失败",
wsDisconnected="WS连接断开",
wsNoConn="WS未连接",
wsClose="WS被断开: ",
waitNetTask="正在连接,请稍候",
netTimeout="网络连接超时",
createRoomTooFast="创建房间太快啦,等等吧",
createRoomSuccessed="创建房间成功!",
@@ -106,7 +103,6 @@ return{
chatStart="------消息的开头------",
chatHistory="------以上是历史消息------",
noRooms="一个房间都没有哎...",
roomsCreateFailed="创建房间失败",
roomsFetchFailed="拉取房间列表失败",
@@ -177,7 +173,7 @@ return{
"",
"使用LOVE2D引擎",
"错误或者建议请附带截图发送到内测群或者作者邮箱~",
"仅通过内测群1127702001进行免费下载/更新",
"仅通过内测qq群/discord群进行免费下载/更新",
"其他渠道获得游戏皆有被修改/加广告/植入病毒的风险,程序只申请了振动&联网权限!",
"若由于被修改的本游戏产生的各种损失作者不负责(我怎么负责啊跟我有啥关系)",
"请从正规途径获得最新版,游戏现为免费,不过有打赏当然感谢啦~",
@@ -209,7 +205,7 @@ return{
simple-love-lights [dylhunn]
]],
support="支持作者",
group="官方QQ群(如果没有被暗改的话就是这个):913154753",
group="官方QQ群:913154753",
WidgetText={
main={
offline="单机游戏",
@@ -252,7 +248,9 @@ return{
chat="聊天室",
},
net_rooms={
fresh="刷新",
refreshing="刷新房间列表中",
noRoom="一个房间都没有哎...",
refresh="刷新",
new="创建房间",
join="加入",
up="",

View File

@@ -71,7 +71,7 @@ return{
PLY.newAIPlayer(2,AIBUILDER("CC",2*AIlevel-1,math.floor(AIlevel*.5+1),true,20000+5000*AIlevel))
end
for _,P in next,PLAYERS.alive do
for _,P in next,PLY_ALIVE do
setField(P,1)
end
end,

View File

@@ -9,17 +9,15 @@ return{
task=function(P)P.modeData.target=50 end,
dropPiece=function(P)
if P.stat.row>=P.modeData.target then
local T=P.modeData.target
if T==50 then
if P.modeData.target==50 then
P.gameEnv.drop=.25
P.modeData.target=100
SFX.play("reach")
elseif T==100 then
elseif P.modeData.target==100 then
P:set20G(true)
P.modeData.target=200
SFX.play("reach")
else
P.stat.row=200
P:win("finish")
end
end

View File

@@ -8,14 +8,15 @@ return{
drop=60,wait=8,fall=20,
task=function(P)P.modeData.target=10 end,
dropPiece=function(P)
local T=P.modeData.target
if P.stat.row>=T then
if T==200 then
if P.stat.row<180 then
P.stat.row=180
end
if P.stat.row>=P.modeData.target then
if P.modeData.target==200 then
P:win("finish")
else
T=T+10
P.gameEnv.drop=dropSpeed[T/10]
P.modeData.target=T
P.gameEnv.drop=dropSpeed[P.modeData.target/10]
P.modeData.target=P.modeData.target+10
SFX.play("reach")
end
end
@@ -31,7 +32,7 @@ return{
mesDisp=function(P)
setFont(45)
mStr(P.stat.row,69,320)
mStr(P.modeData.target+10,69,370)
mStr(P.modeData.target,69,370)
gc.rectangle("fill",25,375,90,4)
end,
score=function(P)return{math.min(P.stat.row,200),P.stat.time}end,

View File

@@ -4,15 +4,16 @@ return{
drop=30,
freshLimit=15,
noMod=true,
bg="space",
},
load=function(playerData)
load=function()
PLY.newPlayer(1)
local N=2
for i=1,#playerData do
if playerData[i].id==tostring(USER.id)then
PLAYERS[1].subID=playerData[1].sid
for i=1,#PLY_NET do
if PLY_NET[i].uid==USER.uid then
PLAYERS[1].subID=PLY_NET[1].sid
else
PLY.newRemotePlayer(N,false,playerData[i])
PLY.newRemotePlayer(N,false,PLY_NET[i])
N=N+1
end
end

View File

@@ -1,5 +1,5 @@
local function update_round(P)
if #PLAYERS.alive>1 then
if #PLY_ALIVE>1 then
P.control=false
local ID=P.id
repeat

View File

@@ -1,5 +1,5 @@
local function update_round(P)
if #PLAYERS.alive>1 then
if #PLY_ALIVE>1 then
P.control=false
local ID=P.id
repeat

View File

@@ -1,5 +1,5 @@
local function update_round(P)
if #PLAYERS.alive>1 then
if #PLY_ALIVE>1 then
P.control=false
local ID=P.id
repeat

View File

@@ -1,5 +1,5 @@
local function update_round(P)
if #PLAYERS.alive>1 then
if #PLY_ALIVE>1 then
P.control=false
local ID=P.id
repeat

View File

@@ -1,5 +1,5 @@
local function update_round(P)
if #PLAYERS.alive>1 then
if #PLY_ALIVE>1 then
P.control=false
local ID=P.id
repeat

View File

@@ -59,7 +59,7 @@ return{
end,
mesDisp=function(P)
setFont(35)
mStr(#PLAYERS.alive.."/49",69,175)
mStr(#PLY_ALIVE.."/49",69,175)
mStr(P.modeData.ko,80,215)
gc.draw(drawableText.ko,60-drawableText.ko:getWidth(),222)
setFont(20)

View File

@@ -59,7 +59,7 @@ return{
end,
mesDisp=function(P)
setFont(35)
mStr(#PLAYERS.alive.."/49",69,175)
mStr(#PLY_ALIVE.."/49",69,175)
mStr(P.modeData.ko,80,215)
gc.draw(drawableText.ko,60-drawableText.ko:getWidth(),222)
setFont(20)

View File

@@ -59,7 +59,7 @@ return{
end,
mesDisp=function(P)
setFont(35)
mStr(#PLAYERS.alive.."/49",69,175)
mStr(#PLY_ALIVE.."/49",69,175)
mStr(P.modeData.ko,80,215)
gc.draw(drawableText.ko,60-drawableText.ko:getWidth(),222)
setFont(20)

View File

@@ -59,7 +59,7 @@ return{
end,
mesDisp=function(P)
setFont(35)
mStr(#PLAYERS.alive.."/99",69,175)
mStr(#PLY_ALIVE.."/99",69,175)
mStr(P.modeData.ko,80,215)
gc.draw(drawableText.ko,60-drawableText.ko:getWidth(),222)
setFont(20)

View File

@@ -59,7 +59,7 @@ return{
end,
mesDisp=function(P)
setFont(35)
mStr(#PLAYERS.alive.."/99",69,175)
mStr(#PLY_ALIVE.."/99",69,175)
mStr(P.modeData.ko,80,215)
gc.draw(drawableText.ko,60-drawableText.ko:getWidth(),222)
setFont(20)

View File

@@ -59,7 +59,7 @@ return{
end,
mesDisp=function(P)
setFont(35)
mStr(#PLAYERS.alive.."/99",69,175)
mStr(#PLY_ALIVE.."/99",69,175)
mStr(P.modeData.ko,80,215)
gc.draw(drawableText.ko,60-drawableText.ko:getWidth(),222)
setFont(20)

434
parts/net.lua Normal file
View File

@@ -0,0 +1,434 @@
local data=love.data
local ins,rem=table.insert,table.remove
local NET={
login=false,
allow_online=false,
roomList={},
accessToken=false,
rid=false,
rsid=false,
}
local mesType={
Connect=true,
Self=true,
Broadcast=true,
Private=true,
Server=true,
}
--Lock & Unlock submodule
local locks={}
local function _lock(name,T)
if locks[name]and TIME()<locks[name]then
return false
else
locks[name]=TIME()+(T or 1e99)
return true
end
end
local function _unlock(name)
locks[name]=false
end
function NET.getLock(name)
return locks[name]
end
--Parse json message
local function _parse(res)
res=JSON.decode(res)
if res then
if mesType[res.type]then
return res
else
LOG.print(
"WS error:"..(
res.type and(
res.reason and res.type..": "..res.reason or
res.type
)or
"[NO Message]"
),
"warning")
end
end
end
--wsEvent
function NET.wsCloseMessage(message)
local mes=JSON.decode(message)
if mes then
LOG.print(("%s [%s] %s"):format(text.wsClose,mes.type or"unknown type",mes.reason or""),"warn")
else
LOG.print(text.wsClose.."","warn")
end
end
--Account
function NET.pong(wsName,message)
WS.send(wsName,message,"pong")
end
function NET.getAccessToken()
if _lock("accessToken")then
WS.send("user",JSON.encode{action=0})
end
end
function NET.getUserInfo(id,ifDetail)
WS.send("user",JSON.encode{
action=1,
data={
id=id or USER.uid,
detailed=ifDetail or false,
},
})
end
function NET.storeUserInfo(res)
local user=USERS[res.uid]
if not user then
user={}
user.email=res.email
user.name=res.username
USERS[res.uid]=user
else
user.email=res.email
user.name=res.username
if not user.motto then user.motto=res.motto end
if not user.avatar then user.avatar=res.avatar end
end
--Get own name
if res.uid==USER.uid then
USER.username=res.username
FILE.save(USER,"conf/user")
end
-- FILE.save(USERS,"conf/users")
end
--Room
function NET.fetchRoom()
if _lock("fetchRoom")then
WS.send("play",JSON.encode{
action=0,
data={
type=nil,
begin=0,
count=10,
}
})
end
end
function NET.createRoom()
if _lock("enterRoom")then
WS.send("play",JSON.encode{
action=1,
data={
type="classic",
name=(USER.username or"???").."'s room",
password=nil,
config=dumpBasicConfig(),
}
})
end
end
function NET.enterRoom(roomID,password)
if _lock("enterRoom")then
NET.rid=roomID
WS.send("play",JSON.encode{
action=2,
data={
rid=roomID,
config=dumpBasicConfig(),
password=password,
}
})
end
end
--Play
function NET.wsConnectPlay()
if _lock("connectPlay")then
WS.connect("play","/play",JSON.encode{
uid=USER.uid,
accessToken=NET.accessToken,
})
end
end
function NET.signal_ready()
if _lock("ready")then
WS.send("play",'{"action":6,"data":{"ready":true}}')
end
end
function NET.signal_quit()
WS.send("play",'{"action":3}')
end
function NET.wsConnectStream()
if _lock("connectStream")then
WS.connect("stream","/stream",JSON.encode{
uid=USER.uid,
accessToken=NET.accessToken,
rid=NET.rsid,
})
end
end
function NET.uploadRecStream(stream)
WS.send("stream",'{"action":2,"data":{"stream":"'..data.encode("string","base64",stream)..'"}}')
end
function NET.signal_die()
WS.send("stream",'{"action":3,"data":{"score":0,"survivalTime":0}}')
end
--Chat
function NET.sendChatMes(mes)
WS.send("chat","T"..data.encode("string","base64",mes))
end
function NET.quitChat()
WS.send("chat","Q")
end
--WS tick funcs
function NET.updateWS_app()
local retryTime=5
while true do
YIELD()
local status=WS.status("app")
if status=="running"then
local message,op=WS.read("app")
if message then
if op=="ping"then
NET.pong("app",message)
elseif op=="pong"then
elseif op=="close"then
NET.wsCloseMessage(message)
return
else
local res=_parse(message)
if res then
if VERSION_CODE>=res.lowest then
NET.allow_online=true
end
if VERSION_CODE<res.newestCode then
LOG.print(text.oldVersion:gsub("$1",res.newestName),180,COLOR.sky)
end
LOG.print(res.notice,300,COLOR.sky)
else
WS.alert("app")
end
end
end
elseif status=="dead"then
retryTime=retryTime-1
if retryTime==0 then return end
for _=1,120 do YIELD()end
WS.connect("app","/app")
end
end
end
function NET.updateWS_user()
while true do
YIELD()
local status=WS.status("user")
if status=="running"then
local message,op=WS.read("user")
if message then
if op=="ping"then
NET.pong("user",message)
elseif op=="pong"then
elseif op=="close"then
NET.wsCloseMessage(message)
return
else
local res=_parse(message)
if res then
if res.type=="Connect"then
NET.login=true
if res.uid then
USER.uid=res.uid
USER.authToken=res.authToken
FILE.save(USER,"conf/user","q")
SCN.back()
end
LOG.print(text.loginSuccessed)
--Get self infos
NET.getUserInfo(USER.uid)
elseif res.action==0 then--Get accessToken
NET.accessToken=res.accessToken
LOG.print(text.accessSuccessed)
NET.wsConnectPlay()
_unlock("accessToken")
elseif res.action==1 then--Get userInfo
NET.storeUserInfo(res)
end
else
WS.alert("user")
end
end
end
end
end
end
function NET.updateWS_play()
while true do
YIELD()
local status=WS.status("play")
if status=="running"then
local message,op=WS.read("play")
if message then
if op=="ping"then
NET.pong("play",message)
elseif op=="pong"then
elseif op=="close"then
NET.wsCloseMessage(message)
return
else
local res=_parse(message)
if res then
if res.type=="Connect"then
SCN.go("net_menu")
_unlock("connectPlay")
elseif res.action==0 then--Fetch rooms
NET.roomList=res.roomList
_unlock("fetchRoom")
elseif res.action==1 then--Create room (not used)
elseif res.action==2 then--Player join
local d=res.data
if res.type=="Self"then
--Create room
TABLE.clear(PLY_NET)
ins(PLY_NET,{
uid=USER.uid,
username=USER.username,
sid=d.sid,
ready=d.ready,
conf=dumpBasicConfig(),
})
if d.players then
for _,p in next,d.players do
ins(PLY_NET,{
uid=p.uid,
username=p.username,
sid=p.sid,
ready=p.ready,
conf=p.config,
})
end
end
loadGame("netBattle",true,true)
_unlock("enterRoom")
else
--Load other players
ins(PLY_NET,{
uid=d.uid,
username=d.username,
sid=d.sid,
ready=d.ready,
conf=d.config,
})
SCN.socketRead("Join",res.data)
end
elseif res.action==3 then--Player leave
for i=1,#PLY_NET do
if PLY_NET[i].uid==data.uid then
rem(PLY_NET,i)
break
end
end
for i=1,#PLAYERS do
if PLAYERS[i].userID==data.uid then
rem(PLAYERS,i)
break
end
end
for i=1,#PLY_ALIVE do
if PLY_ALIVE[i].userID==data.uid then
rem(PLY_ALIVE,i)
break
end
end
SCN.socketRead("Leave",res.data)
elseif res.action==4 then--Player talk
SCN.socketRead("Talk",res.data)
elseif res.action==5 then--Player change settings
SCN.socketRead("Config",res.data)
elseif res.action==6 then--Player ready
SCN.socketRead("Ready",res.data)
_unlock("ready")
elseif res.action==7 then--All ready
elseif res.action==8 then--Sure ready
SCN.socketRead("Set",res.data)
end
else
WS.alert("play")
end
end
end
end
end
end
function NET.updateWS_stream()
while true do
YIELD()
local status=WS.status("stream")
if status=="running"then
local message,op=WS.read("stream")
if message then
if op=="ping"then
NET.pong("stream",message)
elseif op=="pong"then
elseif op=="close"then
NET.wsCloseMessage(message)
return
else
local res=_parse(message)
if res then
if res.type=="Connect"then
--?
elseif res.action==0 then--Game start
SCN.socketRead("Begin",res.data)
elseif res.action==1 then--Game finished
SCN.socketRead("Finish",res.data)
elseif res.action==2 then--Player join
--?
elseif res.action==3 then--Player leave
--?
elseif res.action==4 then--Player died
SCN.socketRead("Die",res.data)
elseif res.action==5 then--Receive stream
SCN.socketRead("Stream",res.data)
end
else
WS.alert("stream")
end
end
end
end
end
end
function NET.updateWS_chat()
while true do
YIELD()
local status=WS.status("chat")
if status=="running"then
local message,op=WS.read("chat")
if message then
if op=="ping"then
NET.pong("chat",message)
elseif op=="pong"then
elseif op=="close"then
NET.wsCloseMessage(message)
return
else
local res=_parse(message)
if res then
--TODO
else
WS.alert("chat")
end
end
end
end
end
end
return NET

View File

@@ -75,7 +75,7 @@ end
local function newEmptyPlayer(id,mini)
local P={id=id}
PLAYERS[id]=P
PLAYERS.alive[id]=P
PLY_ALIVE[id]=P
--Inherit functions of Player class
for k,v in next,Player do P[k]=v end
@@ -134,6 +134,9 @@ local function newEmptyPlayer(id,mini)
P.atker,P.atking,P.lastRecv={}
--Network-related
P.userName="_"
P.userID=-1
P.subID=-1
P.ready=false
P.dropDelay,P.lockDelay=0,0
@@ -178,7 +181,7 @@ local function newEmptyPlayer(id,mini)
P.type="none"
P.sound=false
-- P.newNext=false--Coroutine to get new next, loaded in applyGameEnv()
-- P.newNext=false--Warped coroutine to get new next, loaded in applyGameEnv()
P.keyPressing={}for i=1,12 do P.keyPressing[i]=false end
P.movDir,P.moving,P.downing=0,0,0--Last move key,DAS charging,downDAS charging
@@ -312,8 +315,8 @@ local function applyGameEnv(P)--Finish gameEnv processing
if ENV.nextCount==0 then ENV.nextPos=false end
P.newNext=coroutine.create(getSeqGen(P))
assert(coroutine.resume(P.newNext,P,P.gameEnv.seqData))
P.newNext=coroutine.wrap(getSeqGen(P))
P.newNext(P,P.gameEnv.seqData)
if P.mini then
ENV.lockFX=false
@@ -369,7 +372,7 @@ function PLY.newDemoPlayer(id)
}
P:popNext()
end
function PLY.newRemotePlayer(id,mini,playerData)
function PLY.newRemotePlayer(id,mini,data)
local P=newEmptyPlayer(id,mini)
P.type="remote"
P.update=PLY.update.remote_alive
@@ -379,13 +382,13 @@ function PLY.newRemotePlayer(id,mini,playerData)
P.stream={}
P.streamProgress=1
playerData.p=P
P.userName=playerData.name
P.userID=playerData.id
P.subID=playerData.sid
P.ready=playerData.ready
data.p=P
P.userID=data.uid
P.userName=data.username
P.subID=data.sid
P.ready=data.ready
loadRemoteEnv(P,data.conf)
loadRemoteEnv(P,playerData.conf)
applyGameEnv(P)
end
@@ -405,6 +408,9 @@ function PLY.newPlayer(id,mini)
P.type="human"
P.sound=true
P.userID=USER.uid
P.subID=-1
loadGameEnv(P)
applyGameEnv(P)
end

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +1,7 @@
local max,min=math.max,math.min
local int,abs,rnd=math.floor,math.abs,math.random
local rem=table.remove
local resume=coroutine.resume
local status=coroutine.status
local assert,resume,status=assert,coroutine.resume,coroutine.status
local function updateLine(P)--Attacks, line pushing, cam moving
local bf=P.atkBuffer
@@ -100,16 +99,13 @@ local function updateFXs(P,dt)
TEXT.update(P.bonus)
end
end
local updateTasks do--updateTasks(P)
local assert=assert
function updateTasks(P)
local L=P.tasks
for i=#L,1,-1 do
local tr=L[i].thread
assert(resume(tr))
if status(tr)=="dead"then
rem(L,i)
end
local function updateTasks(P)
local L=P.tasks
for i=#L,1,-1 do
local tr=L[i].thread
assert(resume(tr))
if status(tr)=="dead"then
rem(L,i)
end
end
end
@@ -135,7 +131,7 @@ function update.alive(P,dt)
end
if GAME.modeEnv.royaleMode then
v=P.swappingAtkMode
local v=P.swappingAtkMode
if P.keyPressing[9]then
P.swappingAtkMode=min(v+2,30)
else
@@ -150,8 +146,8 @@ function update.alive(P,dt)
local C=P.AI_keys
P.AI_delay=P.AI_delay-1
if not C[1]then
if status(P.AI_thread)=="suspended"then
resume(P.AI_thread)
if P.AI_thread and not pcall(P.AI_thread)then
P.AI_thread=false
end
elseif P.AI_delay<=0 then
P:pressKey(C[1])P:releaseKey(C[1])
@@ -398,7 +394,7 @@ function update.remote_alive(P,dt)
local amount=int(event/0x100)%0x100
local time=int(event/0x10000)%0x10000
local line=int(event/0x100000000)%0x10000
local L=PLAYERS.alive
local L=PLY_ALIVE
for i=1,#L do
if L[i].subID==sid then
P:attack(L[i],amount,time,line,true)
@@ -409,7 +405,7 @@ function update.remote_alive(P,dt)
end
end
elseif event>0x1000000000000 then--Receiving lines
local L=PLAYERS.alive
local L=PLY_ALIVE
local sid=tostring(event%0x100)
for i=1,#L do
if L[i].subID==sid then

View File

@@ -52,6 +52,7 @@ local function reset()
end end
board[rnd(5)][rnd(5)]=2
fallingTimer=false
failPos=false
end
function scene.sceneInit()
BG.set("rainbow2")
@@ -76,7 +77,8 @@ local function merge()
local connected={{cy,cx}}
local count=1
repeat
local y,x=unpack(rem(connected))
local c=rem(connected)
local y,x=c[1],c[2]
if board[y][x]~=0 then
board[y][x]=0
SYSFX.newShade(2,320+x*128-128,40+y*128-128,128,128)

View File

@@ -149,14 +149,14 @@ scene.widgetList={
WIDGET.newText{name="noMsn", x=610, y=550,align="L",color="grey",hide=function()return MISSION[1]end},
--Basic
WIDGET.newSelector{name="drop", x=170, y=150,w=220,color="orange", list={0,.125,.25,.5,1,2,3,4,5,6,7,8,9,10,12,14,16,18,20,25,30,40,60,180,1e99},disp=lnk_CUSval("drop"),code=lnk_CUSsto("drop")},
WIDGET.newSelector{name="lock", x=170, y=230,w=220,color="red", list={0,1,2,3,4,5,6,7,8,9,10,12,14,16,18,20,25,30,40,60,180,1e99}, disp=lnk_CUSval("lock"),code=lnk_CUSsto("lock")},
WIDGET.newSelector{name="wait", x=410, y=150,w=220,color="green", list={0,1,2,3,4,5,6,7,8,10,15,20,30,60}, disp=lnk_CUSval("wait"),code=lnk_CUSsto("wait")},
WIDGET.newSelector{name="fall", x=410, y=230,w=220,color="yellow", list={0,1,2,3,4,5,6,7,8,10,15,20,30,60}, disp=lnk_CUSval("fall"),code=lnk_CUSsto("fall")},
WIDGET.newSelector{name="drop", x=170, y=150,w=220,color="orange", list={0,.125,.25,.5,1,2,3,4,5,6,7,8,9,10,12,14,16,18,20,25,30,40,60,180,1e99},disp=CUSval("drop"),code=CUSsto("drop")},
WIDGET.newSelector{name="lock", x=170, y=230,w=220,color="red", list={0,1,2,3,4,5,6,7,8,9,10,12,14,16,18,20,25,30,40,60,180,1e99}, disp=CUSval("lock"),code=CUSsto("lock")},
WIDGET.newSelector{name="wait", x=410, y=150,w=220,color="green", list={0,1,2,3,4,5,6,7,8,10,15,20,30,60}, disp=CUSval("wait"),code=CUSsto("wait")},
WIDGET.newSelector{name="fall", x=410, y=230,w=220,color="yellow", list={0,1,2,3,4,5,6,7,8,10,15,20,30,60}, disp=CUSval("fall"),code=CUSsto("fall")},
--Else
WIDGET.newSelector{name="bg", x=1070, y=150,w=250,color="yellow",list=BG.getList(),disp=lnk_CUSval("bg"), code=function(i)CUSTOMENV.bg=i BG.set(i)end},
WIDGET.newSelector{name="bgm", x=1070, y=230,w=250,color="yellow", list=BGM.getList(), disp=lnk_CUSval("bgm"), code=function(i)CUSTOMENV.bgm=i BGM.play(i)end},
WIDGET.newSelector{name="bg", x=1070, y=150,w=250,color="yellow",list=BG.getList(),disp=CUSval("bg"), code=function(i)CUSTOMENV.bg=i BG.set(i)end},
WIDGET.newSelector{name="bgm", x=1070, y=230,w=250,color="yellow", list=BGM.getList(), disp=CUSval("bgm"), code=function(i)CUSTOMENV.bgm=i BGM.play(i)end},
--Copy/Paste/Start
WIDGET.newButton{name="copy", x=1070, y=310,w=310,h=70,color="lRed", font=25,code=pressKey"cC"},

View File

@@ -15,26 +15,26 @@ scene.widgetList={
WIDGET.newText{name="subTitle", x=530,y=50,font=35,align="L",color="grey"},
--Control
WIDGET.newSlider{name="nextCount", x=200, y=150, w=200,unit=6,disp=lnk_CUSval("nextCount"),code=lnk_CUSsto("nextCount")},
WIDGET.newSlider{name="holdCount", x=200, y=240, w=200,unit=6,disp=lnk_CUSval("holdCount"),code=lnk_CUSsto("holdCount")},
WIDGET.newSwitch{name="infHold", x=350, y=340, disp=lnk_CUSval("infHold"), code=lnk_CUSrev("infHold"),hide=function()return CUSTOMENV.holdCount==0 end},
WIDGET.newSwitch{name="phyHold", x=350, y=430, disp=lnk_CUSval("phyHold"), code=lnk_CUSrev("phyHold"),hide=function()return CUSTOMENV.holdCount==0 end},
WIDGET.newSlider{name="nextCount", x=200, y=150, w=200,unit=6,disp=CUSval("nextCount"),code=CUSsto("nextCount")},
WIDGET.newSlider{name="holdCount", x=200, y=240, w=200,unit=6,disp=CUSval("holdCount"),code=CUSsto("holdCount")},
WIDGET.newSwitch{name="infHold", x=350, y=340, disp=CUSval("infHold"), code=CUSrev("infHold"),hide=function()return CUSTOMENV.holdCount==0 end},
WIDGET.newSwitch{name="phyHold", x=350, y=430, disp=CUSval("phyHold"), code=CUSrev("phyHold"),hide=function()return CUSTOMENV.holdCount==0 end},
--Rule
WIDGET.newSelector{name="fieldH", x=270, y=520, w=260,color="sky", list=sList.fieldH, disp=lnk_CUSval("fieldH"),code=lnk_CUSsto("fieldH")},
WIDGET.newSelector{name="visible", x=840, y=60, w=260,color="lBlue",list=sList.visible, disp=lnk_CUSval("visible"),code=lnk_CUSsto("visible")},
WIDGET.newSelector{name="target", x=840, y=160, w=260,color="green",list=sList.target, disp=lnk_CUSval("target"),code=lnk_CUSsto("target")},
WIDGET.newSelector{name="freshLimit",x=840, y=260, w=260,color="purple",list=sList.freshLimit, disp=lnk_CUSval("freshLimit"),code=lnk_CUSsto("freshLimit")},
WIDGET.newSelector{name="opponent", x=1120, y=60, w=260,color="red", list=sList.opponent, disp=lnk_CUSval("opponent"),code=lnk_CUSsto("opponent")},
WIDGET.newSelector{name="life", x=1120, y=160, w=260,color="red", list=sList.life, disp=lnk_CUSval("life"),code=lnk_CUSsto("life")},
WIDGET.newSelector{name="pushSpeed",x=1120, y=260, w=260,color="red", list=sList.pushSpeed, disp=lnk_CUSval("pushSpeed"),code=lnk_CUSsto("pushSpeed")},
WIDGET.newSelector{name="fieldH", x=270, y=520, w=260,color="sky", list=sList.fieldH, disp=CUSval("fieldH"),code=CUSsto("fieldH")},
WIDGET.newSelector{name="visible", x=840, y=60, w=260,color="lBlue",list=sList.visible, disp=CUSval("visible"),code=CUSsto("visible")},
WIDGET.newSelector{name="target", x=840, y=160, w=260,color="green",list=sList.target, disp=CUSval("target"),code=CUSsto("target")},
WIDGET.newSelector{name="freshLimit",x=840, y=260, w=260,color="purple",list=sList.freshLimit, disp=CUSval("freshLimit"),code=CUSsto("freshLimit")},
WIDGET.newSelector{name="opponent", x=1120, y=60, w=260,color="red", list=sList.opponent, disp=CUSval("opponent"),code=CUSsto("opponent")},
WIDGET.newSelector{name="life", x=1120, y=160, w=260,color="red", list=sList.life, disp=CUSval("life"),code=CUSsto("life")},
WIDGET.newSelector{name="pushSpeed",x=1120, y=260, w=260,color="red", list=sList.pushSpeed, disp=CUSval("pushSpeed"),code=CUSsto("pushSpeed")},
WIDGET.newSwitch{name="ospin", x=870, y=350, font=30,disp=lnk_CUSval("ospin"), code=lnk_CUSrev("ospin")},
WIDGET.newSwitch{name="fineKill", x=870, y=530, font=20,disp=lnk_CUSval("fineKill"),code=lnk_CUSrev("fineKill")},
WIDGET.newSwitch{name="b2bKill", x=870, y=620, font=20,disp=lnk_CUSval("b2bKill"), code=lnk_CUSrev("b2bKill")},
WIDGET.newSwitch{name="easyFresh", x=1160, y=350, font=20,disp=lnk_CUSval("easyFresh"),code=lnk_CUSrev("easyFresh")},
WIDGET.newSwitch{name="deepDrop", x=1160, y=440, font=30,disp=lnk_CUSval("deepDrop"),code=lnk_CUSrev("deepDrop")},
WIDGET.newSwitch{name="bone", x=1160, y=530, disp=lnk_CUSval("bone"), code=lnk_CUSrev("bone")},
WIDGET.newSwitch{name="ospin", x=870, y=350, font=30,disp=CUSval("ospin"), code=CUSrev("ospin")},
WIDGET.newSwitch{name="fineKill", x=870, y=530, font=20,disp=CUSval("fineKill"),code=CUSrev("fineKill")},
WIDGET.newSwitch{name="b2bKill", x=870, y=620, font=20,disp=CUSval("b2bKill"), code=CUSrev("b2bKill")},
WIDGET.newSwitch{name="easyFresh", x=1160, y=350, font=20,disp=CUSval("easyFresh"),code=CUSrev("easyFresh")},
WIDGET.newSwitch{name="deepDrop", x=1160, y=440, font=30,disp=CUSval("deepDrop"),code=CUSrev("deepDrop")},
WIDGET.newSwitch{name="bone", x=1160, y=530, disp=CUSval("bone"), code=CUSrev("bone")},
WIDGET.newButton{name="back", x=1140, y=640, w=170,h=80, font=40,code=backScene},
}

View File

@@ -1,5 +1,5 @@
local gc,sys=love.graphics,love.system
local ms,kb=love.mouse,love.keyboard
local kb=love.keyboard
local max,min,int=math.max,math.min,math.floor
local ins,rem=table.insert,table.remove
@@ -9,7 +9,8 @@ local FIELD=FIELD
local scene={}
local sure
local pen--Pen type
local penColor--Pen color
local penMode--Pen mode (false=unavailable, else=mouse button)
local penX,penY--Pen position
local demo--If show x
local page
@@ -54,6 +55,7 @@ local minoPosCode={
local SPmode
local SPlist={}--Smart pen path list
local function SPpath(x,y)
if not penMode then return end
for i=1,#SPlist do
if x==SPlist[i][1]and y==SPlist[i][2]then
return
@@ -61,8 +63,7 @@ local function SPpath(x,y)
end
ins(SPlist,{x,y})
if #SPlist==1 then
local start=FIELD[page][y][x]
SPmode=start==0 and 0 or 1
SPmode=FIELD[page][y][x]==0 and 0 or 1
end
end
local function SPdraw()
@@ -98,99 +99,88 @@ local function SPdraw()
end
end
SPlist={}
SPmode=0
end
function scene.sceneInit()
sure=0
pen=1
penColor=1
penMode=false
penX,penY=1,1
demo=false
page=1
love.keyboard.setKeyRepeat(false)
end
function scene.sceneBack()
love.keyboard.setKeyRepeat(true)
end
function scene.mouseMove(x,y)
local sx,sy=int((x-200)/30)+1,20-int((y-60)/30)
if sx<1 or sx>10 then sx=nil end
if sy<1 or sy>20 then sy=nil end
penX,penY=sx,sy
if ms.isDown(1,2,3)then
if sx and sy then
if pen==-2 then
if ms.isDown(1)then
SPpath(sx,sy)
else
FIELD[page][sy][sx]=-1
end
if sx>=1 and sx<=10 and sy>=1 and sy<=20 then
penX,penY=sx,sy
if penMode then
if penColor==-2 and penMode==1 then
SPpath(sx,sy)
else
FIELD[page][sy][sx]=
ms.isDown(1)and pen or
ms.isDown(2)and -1
or 0
penMode==1 and penColor or
penMode==2 and -1 or
-- penMode==3 and 0
0
end
end
else
penX,penY=nil
end
end
function scene.mouseDown(x,y,k)
if k==2 and pen==-2 then
SPlist={}
else
scene.mouseMove(x,y)
if not penMode then
penMode=k
elseif penMode~=k then
penMode=false
if penColor==-2 then
SPlist={}
end
end
end
function scene.mouseUp()
if pen==-2 then SPdraw()end
end
function scene.wheelMoved(_,y)
if y<0 then
pen=pen+1
if pen==25 then pen=1 end
else
pen=pen-1
if pen==0 then pen=24 end
end
end
function scene.touchDown(x,y)
scene.mouseMove(x,y)
end
function scene.touchMove(x,y)
local sx,sy=int((x-200)/30)+1,20-int((y-60)/30)
if sx<1 or sx>10 then sx=nil end
if sy<1 or sy>20 then sy=nil end
penX,penY=sx,sy
if sx and sy then
if pen==-2 then
SPpath(sx,sy)
else
FIELD[page][sy][sx]=pen
function scene.mouseUp(_,_,k)
if penMode==k then
penMode=false
if penColor==-2 then
SPdraw()
end
end
end
scene.touchUp=scene.mouseUp
function scene.wheelMoved(_,y)
if penColor>0 then
penColor=(penColor+(y<0 and 1 or -1)-1)%24+1
end
end
function scene.touchDown(x,y)scene.mouseDown(x,y,1)end
function scene.touchMove(x,y)scene.mouseMove(x,y)end
function scene.touchUp(x,y)scene.mouseUp(x,y,1)end
function scene.keyDown(key)
local sx,sy=penX,penY
if key=="up"or key=="down"or key=="left"or key=="right"then
if not sx then sx=1 end
if not sy then sy=1 end
if key=="up"and sy<20 then sy=sy+1
elseif key=="down"and sy>1 then sy=sy-1
elseif key=="left"and sx>1 then sx=sx-1
elseif key=="right"and sx<10 then sx=sx+1
if not penX or not penY then penX,penY=1,1 end
if key=="up"then
if penY<20 then penY=penY+1 end
elseif key=="down"then
if penY>1 then penY=penY-1 end
elseif key=="left"then
if penX>1 then penX=penX-1 end
elseif key=="right"then
if penX<10 then penX=penX+1 end
end
if kb.isDown("space")then
scene.keyDown("space")
end
elseif key=="space"then
if sx and sy then
if pen==-2 then
SPpath(sx,sy)
if penX and penY then
penMode=1
if penColor==-2 then
SPpath(penX,penY)
else
FIELD[page][sy][sx]=pen
FIELD[page][penY][penX]=penColor
end
end
elseif key=="delete"then
@@ -260,13 +250,15 @@ function scene.keyDown(key)
elseif key=="escape"then
SCN.back()
else
pen=penKey[key]or pen
penColor=penKey[key]or penColor
end
penX,penY,pen=sx,sy,pen
end
function scene.keyUp(key)
if key=="space"and pen==-2 then
SPdraw()
if key=="space"then
if penColor==-2 then
SPdraw()
end
penMode=false
end
end
@@ -303,20 +295,19 @@ function scene.draw()
--Draw pen
if penX and penY then
local x,y=30*penX,600-30*penY
if kb.isDown("space")or ms.isDown(1)then
if penMode==1 or penMode==2 then
gc.setLineWidth(5)
gc.rectangle("line",x-30,y,30,30,4)
elseif ms.isDown(3)then
elseif penMode==3 then
gc.setLineWidth(3)
gc.line(x-15,y,x-30,y+15)
gc.line(x,y,x-30,y+30)
gc.line(x,y+15,x-15,y+30)
else
gc.setLineWidth(2)
gc.rectangle("line",x-30,y,30,30,3)
gc.setColor(1,1,1,.2)
gc.rectangle("fill",x-30,y,30,30,3)
end
gc.setLineWidth(2)
gc.rectangle("line",x-30,y,30,30,3)
gc.setColor(1,1,1,.2)
gc.rectangle("fill",x-30,y,30,30,3)
end
--Draw smart pen path
@@ -326,14 +317,15 @@ function scene.draw()
if #SPlist<=5 then
gc.setColor(COLOR.rainbow_light(TIME()*6.2))
else
gc.setColor(COLOR.grey)
gc.setColor(.9,.9,.9,.7+.2*math.sin(TIME()*12.6))
end
for i=1,#SPlist do
gc.rectangle("line",30*SPlist[i][1]-30+2,600-30*SPlist[i][2]+2,30-4,30-4,3)
end
elseif SPmode==1 then
else
gc.setColor(1,0,0)
for i=1,#SPlist do
gc.rectangle("line",30*SPlist[i][1]-30+2,600-30*SPlist[i][2]+2,30-4,30-4,3)
gc.draw(cross,30*SPlist[i][1]-30+math.random(-1,1),600-30*SPlist[i][2]+math.random(-1,1))
end
end
end
@@ -347,20 +339,38 @@ function scene.draw()
gc.rectangle("fill",50,600,100,6)
--Draw pen color
if pen>0 then
gc.setLineWidth(13)
gc.setColor(minoColor[pen])
gc.rectangle("line",565,495,70,70)
elseif pen==-1 then
gc.setLineWidth(5)
gc.setColor(.9,.9,.9)
gc.line(575,505,625,555)
gc.line(575,555,625,505)
elseif pen==-2 then
gc.setLineWidth(13)
gc.setColor(COLOR.rainbow(TIME()*6.2))
gc.rectangle("line",565,495,70,70)
end
gc.translate(560,475)
--Right mouse button
gc.setLineWidth(3)
gc.setColor(1,1,1,.9)
gc.line(52,5,75,35)
gc.line(75,5,52,35)
--Left mouse button
if penColor>0 then
gc.setColor(minoColor[penColor])
gc.rectangle("fill",5,5,23,30)
elseif penColor==-1 then
gc.line(5,5,28,35)
gc.line(28,5,5,35)
elseif penColor==-2 then
if SPmode==1 then
gc.setColor(1,0,0)
gc.line(5,5,28,35)
gc.line(28,5,5,35)
else
gc.setLineWidth(13)
gc.setColor(COLOR.rainbow(TIME()*12.6))
gc.rectangle("fill",5,5,23,30)
end
end
--Draw mouse
gc.setLineWidth(2)
gc.setColor(1,1,1)
gc.rectangle("line",0,0,80,110,5)
gc.line(0,40,80,40)
gc.line(33,0,33,40)
gc.line(47,0,47,40)
gc.translate(-560,-475)
--Confirm reset
if sure>0 then
@@ -382,7 +392,7 @@ function scene.draw()
end
end
local function setPen(i)return function()pen=i end end
local function setPen(i)return function()penColor=i end end
scene.widgetList={
WIDGET.newText{name="title", x=1020,y=5,font=70,align="R"},
WIDGET.newText{name="subTitle", x=1030,y=50,font=35,align="L",color="grey"},

View File

@@ -231,7 +231,7 @@ scene.widgetList={
WIDGET.newKey{name="reset", x=1000, y=640, w=90, color="lYellow",font=50,code=pressKey"delete"},
WIDGET.newButton{name="copy", x=1140, y=440, w=170,h=80, color="lRed", font=40,code=pressKey"cC",hide=function()return #MISSION==0 end},
WIDGET.newButton{name="paste", x=1140, y=540, w=170,h=80, color="lBlue", font=40,code=pressKey"cV"},
WIDGET.newSwitch{name="mission",x=1150, y=350, disp=lnk_CUSval("missionKill"),code=lnk_CUSrev("missionKill")},
WIDGET.newSwitch{name="mission",x=1150, y=350, disp=CUSval("missionKill"),code=CUSrev("missionKill")},
WIDGET.newButton{name="back", x=1140, y=640, w=170,h=80, font=40,code=backScene},
}

View File

@@ -191,8 +191,8 @@ scene.widgetList={
WIDGET.newSelector{name="sequence",
x=1080,y=60,w=200,color="yellow",
list={"bag","his4","c2","rnd","mess","reverb","loop","fixed"},
disp=lnk_CUSval("sequence"),
code=lnk_CUSsto("sequence")
disp=CUSval("sequence"),
code=CUSsto("sequence")
},
WIDGET.newKey{name="Z", x=120,y=460,w=80,font=50,code=pressKey(1)},

View File

@@ -36,7 +36,7 @@ function scene.sceneInit()
end
local function clearResult()
for _=1,#result do rem(result)end
TABLE.clear(result)
selected,scrollPos=1,0
waiting,lastSearch=0,false
end
@@ -60,6 +60,9 @@ local function search()
lastSearch=input
end
function scene.wheelMoved(_,y)
WHEELMOV(y)
end
function scene.keyDown(key)
if key=="up"then
if selected and selected>1 then
@@ -75,6 +78,10 @@ function scene.keyDown(key)
scrollPos=selected-15
end
end
elseif key=="pageup"then
for _=1,12 do scene.keyDown("up")end
elseif key=="pagedown"then
for _=1,12 do scene.keyDown("down")end
elseif key=="link"then
love.system.openURL(url)
elseif key=="delete"then

View File

@@ -36,7 +36,7 @@ local function upFloor()
SFX.play("click",.3)
end
end
local loadingThread=coroutine.create(function()
local loadingThread=coroutine.wrap(function()
for i=1,SFX.getCount()do
SFX.loadOne()
if i%3==0 then YIELD()end
@@ -175,15 +175,15 @@ local loadingThread=coroutine.create(function()
logoColor2={COLOR.rainbow_light(r)}
end
STAT.run=STAT.run+1
LOADED=true
--Connect to server
TASK.new(TICK_WS_app)
TASK.new(TICK_WS_user)
TASK.new(NET.updateWS_app)
TASK.new(NET.updateWS_user)
TASK.new(NET.updateWS_play)
WS.connect("app","/app")
if USER.authToken then
WS.connect("user","/user",JSON.encode{
id=USER.id,
uid=USER.uid,
authToken=USER.authToken,
})
end
@@ -193,10 +193,10 @@ local loadingThread=coroutine.create(function()
upFloor()
end
if progress==25 then
loadingThread=false
SFX.play("welcome_sfx")
VOC.play("welcome_voc")
THEME.fresh()
LOADED=true
return
end
YIELD()
@@ -255,8 +255,8 @@ function scene.update(dt)
if progress<25 then
local p=progress
repeat
assert(coroutine.resume(loadingThread))
until not loadingThread or skip<=0 or progress~=p
loadingThread()
until LOADED or skip<=0 or progress~=p
if skip>0 then skip=skip-1 end
else
openTime=openTime+dt

View File

@@ -6,7 +6,6 @@ local function login()
elseif #password==0 then
LOG.print(text.noPassword)return
end
USER.email=email
WS.connect("user","/user",JSON.encode{
email=email,
password=password,

View File

@@ -12,15 +12,13 @@ local widgetX0={
1290,1290,1290,1290,
}
local cmdEntryThread=coroutine.create(function()
local cmdEntryThread=coroutine.wrap(function()
while true do
while true do
if YIELD()~="c"then break end
SFX.play("ren_6")
if YIELD()~="m"then break end
SFX.play("ren_9")
if YIELD()~="d"then break end
SFX.play("ren_11")
if
YIELD()=="c"and(SFX.play("ren_6")or 1)and
YIELD()=="m"and(SFX.play("ren_9")or 1)and
YIELD()=="d"and(SFX.play("ren_11")or 1)
then
SCN.go("app_cmd")
end
end
@@ -30,7 +28,7 @@ function scene.sceneInit()
scrollX=tipLength
BG.set()
coroutine.resume(cmdEntryThread)
cmdEntryThread()
--Set quick-play-button text
scene.widgetList[2].text=text.WidgetText.main.qplay..": "..text.modes[STAT.lastPlay][1]
@@ -43,15 +41,11 @@ function scene.sceneInit()
GAME.seed=math.random(2e6)
PLY.newDemoPlayer(1)
PLAYERS[1]:setPosition(520,140,.8)
love.keyboard.setKeyRepeat(false)
end
function scene.sceneBack()
love.keyboard.setKeyRepeat(true)
end
function scene.mouseDown(x,y)
if x>=520 and x<=760 and y>=140 and y<=620 then
coroutine.resume(cmdEntryThread,
cmdEntryThread(
x<520+80 and y>620-80 and"c"or
x>760-80 and y>620-80 and"m"or
x<520+80 and y<140+80 and"d"
@@ -77,12 +71,12 @@ function scene.keyDown(key)
end
elseif key=="a"then
if testButton(3)then
if LOGIN then
if NET.login then
if not NET.allow_online then
TEXT.show(text.needUpdate,640,450,60,"flicker")
SFX.play("finesseError")
else
WS.send("user",JSON.encode{action=0})
NET.getAccessToken()
end
else
SCN.go("login")
@@ -125,7 +119,7 @@ function scene.keyDown(key)
SCN.back()
end
else
coroutine.resume(cmdEntryThread,key)
cmdEntryThread(key)
end
end
@@ -183,9 +177,9 @@ scene.widgetList={
WIDGET.newButton{name="dict", x=2480,y=450,w=800,h=100, color="lGreen", font=40,align="L",edge=30, code=pressKey"l"},
WIDGET.newButton{name="manual", x=2480,y=570,w=800,h=100, color="lC", font=40,align="L",edge=30, code=pressKey","},
WIDGET.newButton{name="music", x=160,y=80,w=200,h=90, color="lOrange",font=35, code=pressKey"f2"},
WIDGET.newButton{name="lang", x=1120,y=80,w=200,h=90, color="lY", font=40, code=pressKey"f3"},
WIDGET.newButton{name="about", x=-110,y=670,w=600,h=70, color="lB", font=35,align="R",edge=30, code=pressKey"f1"},
WIDGET.newButton{name="music", x=160,y=80,w=200,h=90, color="lOrange",font=35, code=pressKey"2"},
WIDGET.newButton{name="lang", x=1120,y=80,w=200,h=90, color="lY", font=40, code=pressKey"0"},
WIDGET.newButton{name="about", x=-110,y=670,w=600,h=70, color="lB", font=35,align="R",edge=30, code=pressKey"x"},
WIDGET.newButton{name="quit", x=1390,y=670,w=600,h=70, color="lR", font=40,align="L",edge=30, code=function()VOC.play("bye")SCN.swapTo("quit","slowFade")end},
}

View File

@@ -88,7 +88,7 @@ scene.widgetList={
WIDGET.newText{name="title", x=30, y=30,font=80,align="L"},
WIDGET.newText{name="arrow", x=270, y=360,font=45,align="L"},
WIDGET.newText{name="now", x=700, y=500,font=50,align="R",hide=function()return not BGM.nowPlay end},
WIDGET.newSlider{name="bgm", x=760, y=80,w=400, font=35,disp=lnk_SETval("bgm"),code=function(v)SETTING.bgm=v BGM.freshVolume()end},
WIDGET.newSlider{name="bgm", x=760, y=80,w=400, font=35,disp=SETval("bgm"),code=function(v)SETTING.bgm=v BGM.freshVolume()end},
WIDGET.newButton{name="up", x=200, y=250,w=120, font=55,code=pressKey"up",hide=function()return selected==1 end},
WIDGET.newButton{name="play", x=200, y=390,w=120, font=35,code=pressKey"space"},
WIDGET.newButton{name="down", x=200, y=530,w=120, font=55,code=pressKey"down",hide=function()return selected==#bgmList end},

View File

@@ -3,12 +3,12 @@ local data=love.data
local textBox=WIDGET.newTextBox{name="texts",x=40,y=50,w=1200,h=430}
local remain--People in chat room
local heartBeatTimer
local escapeTimer=0
local function sendMessage()
local W=WIDGET.active.input
if #W.value>0 and WS.send("chat","T"..data.encode("string","base64",W.value))then
if #W.value>0 then
NET.sendChatMes(W.value)
W.value=""
end
end
@@ -16,7 +16,6 @@ end
local scene={}
function scene.sceneInit()
heartBeatTimer=0
remain=false
local texts=textBox.texts
@@ -30,8 +29,7 @@ function scene.sceneInit()
BG.set("none")
end
function scene.sceneBack()
WS.send("chat","Q")
LOG.print(text.wsDisconnected,"warn")
NET.quitChat()
end
function scene.wheelMoved(_,y)
@@ -80,13 +78,6 @@ function scene.socketRead(mes)
end
end
function scene.update(dt)
heartBeatTimer=heartBeatTimer+dt
if heartBeatTimer>42 then
heartBeatTimer=0
WS.send("chat","P")
end
end
function scene.draw()
setFont(25)
gc.setColor(1,1,1)

View File

@@ -1,9 +1,7 @@
local data=love.data
local gc=love.graphics
local tc=love.touch
local playerData
local ins,rem=table.insert,table.remove
local ins=table.insert
local SCR=SCR
local VK=virtualkey
@@ -13,14 +11,8 @@ local updateVirtualkey=updateVirtualkey
local hideChatBox
local textBox=WIDGET.newTextBox{name="texts",x=340,y=80,w=600,h=550,hide=function()return hideChatBox end}
local function switchChat()
hideChatBox=not hideChatBox
end
local playerInitialized
local playing
local heartBeatTimer
local lastUpstreamTime
local upstreamProgress
local lastBackTime=0
@@ -30,23 +22,19 @@ local touchMoveLastFrame=false
local scene={}
function scene.sceneBack()
WS.send("play","Q")
LOG.print(text.wsDisconnected,"warn")
NET.signal_quit()
love.keyboard.setKeyRepeat(true)
end
function scene.sceneInit()
love.keyboard.setKeyRepeat(false)
hideChatBox=true
playerInitialized=false
textBox:clear()
playerData={}
resetGameData("n",playerData)
resetGameData("n")
noTouch=not SETTING.VKSwitch
playing=false
lastUpstreamTime=0
upstreamProgress=1
heartBeatTimer=0
end
function scene.touchDown(x,y)
@@ -96,7 +84,7 @@ function scene.keyDown(key)
LOG.print(text.sureQuit,COLOR.orange)
end
elseif key=="\\"then
switchChat()
hideChatBox=not hideChatBox
elseif playing then
if noKey then return end
local k=keyMap.keyboard[key]
@@ -106,8 +94,8 @@ function scene.keyDown(key)
VK[k].pressTime=10
end
elseif key=="space"then
if not PLAYERS[1].ready then
WS.send("play","R")
if not NET.getLock("ready")then
NET.signal_ready()
end
end
end
@@ -147,77 +135,85 @@ function scene.gamepadUp(key)
end
end
function scene.socketRead(mes)
local cmd=mes:sub(1,1)
local args=SPLITSTR(mes:sub(2),";")
if cmd=="J"then
if playerInitialized then
local L=SPLITSTR(args[1],",")
textBox:push{
COLOR.lR,L[1],
COLOR.dY,"#"..L[2].." ",
COLOR.Y,text.joinRoom,
}
end
for i=1,#args do
local L=SPLITSTR(args[i],",")
ins(playerData,{name=L[1],id=L[2],sid=L[3],conf=L[4],ready=L[5]=="1"})
end
playerInitialized=true
function scene.socketRead(cmd,data)
if cmd=="Join"then
textBox:push{
COLOR.lR,data.username,
COLOR.dY,"#"..data.uid.." ",
COLOR.Y,text.joinRoom,
}
SFX.play("click")
if not playing then
resetGameData("qn",playerData)
resetGameData("qn")
end
elseif cmd=="L"then
elseif cmd=="Leave"then
textBox:push{
COLOR.lR,args[1],
COLOR.dY,"#"..args[2].." ",
COLOR.lR,data.username,
COLOR.dY,"#"..data.uid.." ",
COLOR.Y,text.leaveRoom,
}
for i=1,#playerData do
if playerData[i].id==args[2]then
rem(playerData,i)
break
end
if not playing then
initPlayerPosition(true)
end
for i=1,#PLAYERS do
if PLAYERS[i].userID==args[2]then
rem(PLAYERS,i)
break
end
end
for i=1,#PLAYERS.alive do
if PLAYERS.alive[i].userID==args[2]then
rem(PLAYERS.alive,i)
break
end
end
initPlayerPosition(true)
elseif cmd=="T"then
local _,text=pcall(data.decode,"string","base64",args[3])
if not _ then text=args[3]end
elseif cmd=="Talk"then
textBox:push{
COLOR.W,args[1],
COLOR.dY,"#"..args[2].." ",
COLOR.sky,text
COLOR.W,data.username,
COLOR.dY,"#"..data.uid.." ",
COLOR.sky,data.message or"[_]",
}
elseif cmd=="C"then
if tostring(USER.id)~=args[2]then
for i=1,#playerData do
if playerData[i].id==args[2]then
playerData[i].conf=args[4]
playerData[i].p:setConf(args[4])
elseif cmd=="Config"then
if tostring(USER.uid)~=data.uid then
for i=1,#PLY_NET do
if PLY_NET[i].uid==data.uid then
PLY_NET[i].conf=data.config
PLY_NET[i].p:setConf(data.config)
return
end
end
resetGameData("qn",playerData)
resetGameData("qn")
end
elseif cmd=="S"then
if playing and args[1]~=PLAYERS[1].subID then
elseif cmd=="Ready"then
if data.uid==USER.uid then
PLAYERS[1].ready=true
SFX.play("reach",.6)
else
for i=1,#PLAYERS do
if PLAYERS[i].userID==data.uid then
PLAYERS[i].ready=true
SFX.play("reach",.6)
break
end
end
end
elseif cmd=="Set"then
NET.rsid=data.rid
NET.wsConnectStream()
TASK.new(NET.updateWS_stream)
elseif cmd=="Begin"then
if not playing then
playing=true
lastUpstreamTime=0
upstreamProgress=1
resetGameData("n",data.seed)
else
LOG.print("Redundant signal: B(begin)",30,COLOR.green)
end
elseif cmd=="Finish"then
playing=false
resetGameData("n")
TEXT.show(text.champion:gsub("$1","SOMEBODY"),640,260,80,"zoomout",.26)
elseif cmd=="Die"then
LOG.print("One player failed",COLOR.sky)
elseif cmd=="Stream"then
if data.uid==USER.uid then
LOG.print("SELF STREAM")
return
end
if playing then
for _,P in next,PLAYERS do
if P.subID==args[1]then
local _,stream=pcall(data.decode,"string","base64",args[2])
if _ then
if P.userID==data.uid then
local res,stream=pcall(love.data.decode,"string","base64",data.stream)
if res then
pumpRecording(stream,P.stream)
else
LOG.print("Bad stream from "..P.userName.."#"..P.userID)
@@ -225,35 +221,6 @@ function scene.socketRead(mes)
end
end
end
elseif cmd=="R"then
local L=PLAYERS.alive
for i=1,#L do
if L[i].subID==args[1]then
L[i].ready=true
SFX.play("reach",.6)
break
end
end
elseif cmd=="B"then
if not playing then
playing=true
lastUpstreamTime=0
upstreamProgress=1
resetGameData("n",playerData,tonumber(args[1]))
else
LOG.print("Redundant signal: B(begin)",30,COLOR.green)
end
elseif cmd=="F"then
playing=false
resetGameData("n",playerData)
for i=1,#playerData do
if playerData[i].sid==args[1]then
TEXT.show(text.champion:gsub("$1",playerData[i].name.."#"..playerData[i].id),640,260,80,"zoomout",.26)
break
end
end
else
LOG.print("Illegal message: ["..mes.."]",30,COLOR.green)
end
end
@@ -261,15 +228,8 @@ function scene.update(dt)
local _
local GAME=GAME
if WS.status("play")~="running"and not SCN.swapping then SCN.back()end
if not playing then
heartBeatTimer=heartBeatTimer+dt
if heartBeatTimer>42 then
heartBeatTimer=0
WS.send("play","P")
end
return
end
if WS.status("play")~="running"then SCN.back()end
if not playing then return end
touchMoveLastFrame=false
updateVirtualkey()
@@ -289,7 +249,7 @@ function scene.update(dt)
local stream
stream,upstreamProgress=dumpRecording(GAME.rep,upstreamProgress)
if #stream>0 then
WS.send("stream",data.encode("string","base64",stream))
NET.uploadRecStream(stream)
else
ins(GAME.rep,GAME.frame)
ins(GAME.rep,0)
@@ -322,7 +282,7 @@ end
scene.widgetList={
textBox,
WIDGET.newKey{name="ready",x=640,y=440,w=200,h=80,color="yellow",font=40,code=pressKey"space",hide=function()return playing or not hideChatBox or PLAYERS[1].ready end},
WIDGET.newKey{name="hideChat",fText="...",x=380,y=35,w=60,font=35,code=switchChat},
WIDGET.newKey{name="hideChat",fText="...",x=380,y=35,w=60,font=35,code=pressKey"\\"},
WIDGET.newKey{name="quit",fText="X",x=900,y=35,w=60,font=40,code=pressKey"escape"},
}

View File

@@ -1,13 +1,13 @@
local scene={}
function scene.sceneInit()
BG.set("matrix")
BG.set("space")
end
scene.widgetList={
WIDGET.newButton{name="ffa", x=640, y=200,w=350,h=120,font=40,code=NULL},
-- WIDGET.newButton{name="ffa", x=640, y=200,w=350,h=120,font=40,code=NULL},
WIDGET.newButton{name="rooms", x=640, y=360,w=350,h=120,font=40,code=goScene"net_rooms"},
WIDGET.newButton{name="chat", x=640, y=540,w=350,h=120,font=40,code=goScene"net_chat",hide=function()return WS.status("chat")~="running"end},
-- WIDGET.newButton{name="chat", x=640, y=540,w=350,h=120,font=40,code=goScene"net_chat"},
WIDGET.newButton{name="back", x=1140, y=640,w=170,h=80,font=40,code=backScene},
}

View File

@@ -1,40 +1,23 @@
local gc=love.graphics
local min=math.min
local rooms
local NET=NET
local scrollPos,selected
local lastfreshTime
local fetchTimer
local lastCreateRoomTime=0
local function enterRoom(roomID)
--[[TODO
WS.connect("play","/play",JSON.encode{
email=USER.email,
token=USER.accessToken,
id=roomID,
conf=dumpBasicConfig(),
-- password=password,
})
]]
end
local function fresh()
lastfreshTime=TIME()
rooms=nil
--[[TODO
WS.connect("play","/play",JSON.encode{
email=USER.email,
accessToken=USER.accessToken,
})
]]
local function fetchRoom()
fetchTimer=5
NET.fetchRoom()
end
local scene={}
function scene.sceneInit()
BG.set("bg1")
BG.set("space")
scrollPos=0
selected=1
fresh()
fetchRoom()
end
function scene.wheelMoved(_,y)
@@ -42,28 +25,21 @@ function scene.wheelMoved(_,y)
end
function scene.keyDown(k)
if k=="r"then
if TIME()-lastfreshTime>1 then
fresh()
if fetchTimer<=3.26 then
fetchRoom()
end
elseif k=="n"then
if TIME()-lastCreateRoomTime>26 then
--[[TODO
WS.send("room",JSON.encode{
email=USER.email,
accessToken=USER.accessToken,
room_name=(USER.name or"???").."'s room",
room_password=nil,
})
]]
NET.createRoom()
lastCreateRoomTime=TIME()
else
LOG.print(text.createRoomTooFast,"warn")
end
elseif k=="escape"then
SCN.back()
elseif rooms and #rooms>0 then
elseif #NET.roomList>0 then
if k=="down"then
if selected<#rooms then
if selected<#NET.roomList then
selected=selected+1
if selected>scrollPos+10 then
scrollPos=scrollPos+1
@@ -77,59 +53,63 @@ function scene.keyDown(k)
end
end
elseif k=="return"then
if rooms[selected].private then
if NET.getLock("fetchRoom")then return end
if NET.roomList[selected].private then
LOG.print("Can't enter private room now")
return
end
enterRoom(rooms[selected].id)
NET.enterRoom(NET.roomList[selected].rid)--,password
end
end
end
function scene.update()
if TIME()-lastfreshTime>5 then
fresh()
function scene.update(dt)
if not NET.getLock("fetchRoom")then
fetchTimer=fetchTimer-dt
if fetchTimer<=0 then
fetchRoom()
end
end
end
function scene.draw()
--Fetching timer
gc.setColor(1,1,1,.26)
gc.arc("fill","pie",240,620,60,-1.5708,-1.5708+1.2566*(TIME()-lastfreshTime))
if rooms then
gc.setColor(1,1,1)
if #rooms>0 then
gc.setLineWidth(2)
gc.rectangle("line",55,110,1100,400)
gc.setColor(1,1,1,.3)
gc.rectangle("fill",55,40*(1+selected-scrollPos)+30,1100,40)
setFont(35)
for i=1,min(10,#rooms-scrollPos)do
local R=rooms[scrollPos+i]
if R.private then
gc.setColor(1,1,1)
gc.draw(IMG.lock,64,75+40*i)
end
gc.setColor(.9,.9,1)
gc.print(scrollPos+i,100,66+40*i)
gc.setColor(1,1,.7)
gc.print(R.name,200,66+40*i)
gc.arc("fill","pie",240,620,60,-1.5708,-1.5708-1.2566*fetchTimer)
--Room list
gc.setColor(1,1,1)
gc.setLineWidth(2)
gc.rectangle("line",50,110,1180,400)
if #NET.roomList>0 then
gc.setColor(1,1,1,.3)
gc.rectangle("fill",50,40*(1+selected-scrollPos)+30,1180,40)
setFont(35)
for i=1,min(10,#NET.roomList-scrollPos)do
local R=NET.roomList[scrollPos+i]
if R.private then
gc.setColor(1,1,1)
gc.printf(R.type,500,66+40*i,500,"right")
gc.print(R.count.."/"..R.capacity,1050,66+40*i)
gc.draw(IMG.lock,59,75+40*i)
end
else
setFont(60)
mStr(text.noRooms,640,315)
gc.setColor(.9,.9,1)
gc.print(scrollPos+i,95,66+40*i)
gc.setColor(1,1,.7)
gc.print(R.name,250,66+40*i)
gc.setColor(1,1,1)
gc.printf(R.type,550,66+40*i,500,"right")
gc.print(R.count.."/"..R.capacity,1100,66+40*i)
end
end
end
scene.widgetList={
WIDGET.newKey{name="fresh", x=240,y=620,w=140,h=140,font=40,code=fresh,hide=function()return TIME()-lastfreshTime<1.26 end},
WIDGET.newText{name="refreshing",x=640,y=260,font=65,hide=function()return not NET.getLock("fetchRoom")end},
WIDGET.newText{name="noRoom", x=640,y=260,font=40,hide=function()return #NET.roomList>0 or NET.getLock("fetchRoom")end},
WIDGET.newKey{name="refresh", x=240,y=620,w=140,h=140,font=40,code=fetchRoom, hide=function()return fetchTimer>3.26 end},
WIDGET.newKey{name="new", x=440,y=620,w=140,h=140,font=25,code=pressKey"n"},
WIDGET.newKey{name="join", x=640,y=620,w=140,h=140,font=40,code=pressKey"return",hide=function()return not rooms end},
WIDGET.newKey{name="up", x=840,y=585,w=140,h=70,font=40,code=pressKey"up",hide=function()return not rooms end},
WIDGET.newKey{name="down", x=840,y=655,w=140,h=70,font=40,code=pressKey"down",hide=function()return not rooms end},
WIDGET.newKey{name="join", x=640,y=620,w=140,h=140,font=40,code=pressKey"return", hide=function()return #NET.roomList==0 end},
WIDGET.newKey{name="up", x=840,y=585,w=140,h=70,font=40,code=pressKey"up", hide=function()return #NET.roomList==0 end},
WIDGET.newKey{name="down", x=840,y=655,w=140,h=70,font=40,code=pressKey"down", hide=function()return #NET.roomList==0 end},
WIDGET.newButton{name="back", x=1140,y=640,w=170,h=80,font=40,code=backScene},
}

View File

@@ -49,7 +49,7 @@ scene.widgetList={
WIDGET.newButton{name="importUnlock", x=190,y=300,w=280,h=100,color="lBlue",font=25,code=function()
local D=parseCB()
if D then
TABLE.add(D,RANKS)
TABLE.update(D,RANKS)
FILE.save(RANKS,"conf/unlock")
LOG.print(text.importSuccess,"message")
else
@@ -59,7 +59,7 @@ scene.widgetList={
WIDGET.newButton{name="importData", x=490,y=300,w=280,h=100,color="lBlue",font=25,code=function()
local D=parseCB()
if D and D.version==STAT.version then
TABLE.add(D,STAT)
TABLE.update(D,STAT)
FILE.save(STAT,"conf/data")
LOG.print(text.importSuccess,"message")
else
@@ -69,7 +69,7 @@ scene.widgetList={
WIDGET.newButton{name="importSetting", x=790,y=300,w=280,h=100,color="lBlue",font=25,code=function()
local D=parseCB()
if D then
TABLE.add(D,SETTING)
TABLE.update(D,SETTING)
FILE.save(SETTING,"conf/settings")
LOG.print(text.importSuccess,"message")
else
@@ -79,7 +79,7 @@ scene.widgetList={
WIDGET.newButton{name="importVK", x=1090,y=300,w=280,h=100,color="lBlue",font=25,code=function()
local D=parseCB()
if D then
TABLE.add(D,VK_org)
TABLE.update(D,VK_org)
FILE.save(VK_org,"conf/virtualkey")
LOG.print(text.importSuccess,"message")
else

View File

@@ -81,14 +81,14 @@ scene.widgetList={
WIDGET.newText{name="title", x=80, y=50,font=70,align="L"},
WIDGET.newText{name="preview", x=520, y=540,font=40,align="R"},
WIDGET.newSlider{name="das", x=250, y=190,w=600,unit=20,disp=lnk_SETval("das"), show=sliderShow,code=lnk_SETsto("das")},
WIDGET.newSlider{name="arr", x=250, y=260,w=525,unit=15,disp=lnk_SETval("arr"), show=sliderShow,code=lnk_SETsto("arr")},
WIDGET.newSlider{name="sddas", x=250, y=330,w=350,unit=10,disp=lnk_SETval("sddas"),show=sliderShow,code=lnk_SETsto("sddas")},
WIDGET.newSlider{name="sdarr", x=250, y=400,w=140,unit=4, disp=lnk_SETval("sdarr"),show=sliderShow,code=lnk_SETsto("sdarr")},
WIDGET.newSlider{name="dascut", x=250, y=470,w=600,unit=20,disp=lnk_SETval("dascut"),show=sliderShow,code=lnk_SETsto("dascut")},
WIDGET.newSwitch{name="ihs", x=1100, y=260, disp=lnk_SETval("ihs"), code=lnk_SETrev("ihs")},
WIDGET.newSwitch{name="irs", x=1100, y=330, disp=lnk_SETval("irs"), code=lnk_SETrev("irs")},
WIDGET.newSwitch{name="ims", x=1100, y=400, disp=lnk_SETval("ims"), code=lnk_SETrev("ims")},
WIDGET.newSlider{name="das", x=250, y=190,w=600,unit=20,disp=SETval("das"), show=sliderShow,code=SETsto("das")},
WIDGET.newSlider{name="arr", x=250, y=260,w=525,unit=15,disp=SETval("arr"), show=sliderShow,code=SETsto("arr")},
WIDGET.newSlider{name="sddas", x=250, y=330,w=350,unit=10,disp=SETval("sddas"),show=sliderShow,code=SETsto("sddas")},
WIDGET.newSlider{name="sdarr", x=250, y=400,w=140,unit=4, disp=SETval("sdarr"),show=sliderShow,code=SETsto("sdarr")},
WIDGET.newSlider{name="dascut", x=250, y=470,w=600,unit=20,disp=SETval("dascut"),show=sliderShow,code=SETsto("dascut")},
WIDGET.newSwitch{name="ihs", x=1100, y=260, disp=SETval("ihs"), code=SETrev("ihs")},
WIDGET.newSwitch{name="irs", x=1100, y=330, disp=SETval("irs"), code=SETrev("irs")},
WIDGET.newSwitch{name="ims", x=1100, y=400, disp=SETval("ims"), code=SETrev("ims")},
WIDGET.newButton{name="reset", x=160, y=580,w=200,h=100,color="lRed",font=40,
code=function()
local _=SETTING

View File

@@ -27,14 +27,14 @@ scene.widgetList={
WIDGET.newButton{name="ctrl", x=290, y=220, w=320,h=80, color="lYellow",font=35,code=goScene"setting_control"},
WIDGET.newButton{name="key", x=640, y=220, w=320,h=80, color="lGreen", font=35,code=goScene"setting_key"},
WIDGET.newButton{name="touch", x=990, y=220, w=320,h=80, color="lBlue", font=35,code=goScene"setting_touch"},
WIDGET.newSlider{name="reTime", x=350, y=340, w=300,unit=10,disp=lnk_SETval("reTime"),code=lnk_SETsto("reTime"),show=function(S)return(.5+S.disp()*.25).."s"end},
WIDGET.newSelector{name="RS", x=500, y=420, w=300,color="sea",list={"TRS","SRS","C2","C2sym","Classic","None"},disp=lnk_SETval("RS"),code=lnk_SETsto("RS")},
WIDGET.newSlider{name="reTime", x=350, y=340, w=300,unit=10,disp=SETval("reTime"),code=SETsto("reTime"),show=function(S)return(.5+S.disp()*.25).."s"end},
WIDGET.newSelector{name="RS", x=500, y=420, w=300,color="sea",list={"TRS","SRS","C2","C2sym","Classic","None"},disp=SETval("RS"),code=SETsto("RS")},
WIDGET.newButton{name="layout", x=550, y=540, w=200,h=70, font=35,code=goScene"setting_skin"},
WIDGET.newSwitch{name="autoPause", x=1060, y=310, font=20,disp=lnk_SETval("autoPause"),code=lnk_SETrev("autoPause")},
WIDGET.newSwitch{name="swap", x=1060, y=370, font=20,disp=lnk_SETval("swap"), code=lnk_SETrev("swap")},
WIDGET.newSwitch{name="fine", x=1060, y=430, font=20,disp=lnk_SETval("fine"), code=function()SETTING.fine=not SETTING.fine if SETTING.fine then SFX.play("finesseError",.6) end end},
WIDGET.newSwitch{name="appLock", x=1060, y=490, font=20,disp=lnk_SETval("appLock"), code=lnk_SETrev("appLock")},
WIDGET.newSwitch{name="simpMode", x=1060, y=550, font=25,disp=lnk_SETval("simpMode"),code=function()
WIDGET.newSwitch{name="autoPause", x=1060, y=310, font=20,disp=SETval("autoPause"),code=SETrev("autoPause")},
WIDGET.newSwitch{name="swap", x=1060, y=370, font=20,disp=SETval("swap"), code=SETrev("swap")},
WIDGET.newSwitch{name="fine", x=1060, y=430, font=20,disp=SETval("fine"), code=function()SETTING.fine=not SETTING.fine if SETTING.fine then SFX.play("finesseError",.6) end end},
WIDGET.newSwitch{name="appLock", x=1060, y=490, font=20,disp=SETval("appLock"), code=SETrev("appLock")},
WIDGET.newSwitch{name="simpMode", x=1060, y=550, font=25,disp=SETval("simpMode"),code=function()
SETTING.simpMode=not SETTING.simpMode
for i=1,#SCN.stack,2 do
if SCN.stack[i]=="main"or SCN.stack[i]=="main_simple"then

View File

@@ -10,8 +10,7 @@ local jump--Animation timer(10 to 0)
local cv=SETTING.cv
function scene.sceneInit()
last=0
jump=0
last,jump=0,0
cv=SETTING.cv
BG.set()
end
@@ -34,24 +33,24 @@ function scene.touchDown(x,y)
end
function scene.update()
local t=jump
if t>0 then
jump=t-1
end
if jump>0 then jump=jump-1 end
end
function scene.draw()
gc.setColor(1,1,1)
local t=TIME()
local _=jump
local x,y=800,340+10*sin(t*.5)+(_-10)*_*.3
local x,y=800,340+10*sin(t*.5)+(jump-10)*jump*.3
gc.translate(x,y)
gc.draw(IMG.miyaCH,0,0)
gc.setColor(1,1,1,.7)
gc.draw(IMG.miyaF1,4,47+4*sin(t*.9))
gc.draw(IMG.miyaF2,42,107+5*sin(t))
gc.draw(IMG.miyaF3,93,126+3*sin(t*.7))
gc.draw(IMG.miyaF4,129,98+3*sin(t*.7))
if cv=="miya"then
gc.draw(IMG.miyaCH)
gc.setColor(1,1,1,.7)
gc.draw(IMG.miyaF1,4,47+4*sin(t*.9))
gc.draw(IMG.miyaF2,42,107+5*sin(t))
gc.draw(IMG.miyaF3,93,126+3*sin(t*.7))
gc.draw(IMG.miyaF4,129,98+3*sin(t*.5))
elseif cv=="naki"then
gc.draw(IMG.nakiCH)
end
gc.translate(-x,-y)
end
@@ -61,13 +60,13 @@ scene.widgetList={
WIDGET.newButton{name="game", x=200, y=80,w=240,h=80,color="lCyan",font=35,code=swapScene"setting_game","swipeR"},
WIDGET.newButton{name="graphic",x=1080, y=80,w=240,h=80,color="lCyan",font=35,code=swapScene"setting_video","swipeL"},
WIDGET.newSlider{name="sfx", x=180, y=200,w=400, font=35,change=function()SFX.play("blip_1")end, disp=lnk_SETval("sfx"),code=lnk_SETsto("sfx")},
WIDGET.newSlider{name="spawn", x=180, y=300,w=400, font=30,change=function()SFX.fplay("spawn_"..math.random(7),SETTING.sfx_spawn)end,disp=lnk_SETval("sfx_spawn"),code=lnk_SETsto("sfx_spawn")},
WIDGET.newSlider{name="warn", x=180, y=400,w=400, font=30,change=function()SFX.fplay("warning",SETTING.sfx_warn)end,disp=lnk_SETval("sfx_warn"),code=lnk_SETsto("sfx_warn")},
WIDGET.newSlider{name="bgm", x=180, y=500,w=400, font=35, disp=lnk_SETval("bgm"),code=function(v)SETTING.bgm=v BGM.freshVolume()end},
WIDGET.newSlider{name="stereo", x=180, y=600,w=400, font=35,change=function()SFX.play("move",1,-1)SFX.play("lock",1,1)end,disp=lnk_SETval("stereo"),code=lnk_SETsto("stereo"),hide=function()return SETTING.sx==0 end},
WIDGET.newSlider{name="vib", x=750, y=200,w=400,unit=5, font=25,change=function()VIB(2)end, disp=lnk_SETval("vib"),code=lnk_SETsto("vib")},
WIDGET.newSlider{name="voc", x=750, y=300,w=400, font=35,change=function()VOC.play("test")end, disp=lnk_SETval("voc"),code=lnk_SETsto("voc")},
WIDGET.newSlider{name="sfx", x=180, y=200,w=400, font=35,change=function()SFX.play("blip_1")end, disp=SETval("sfx"),code=SETsto("sfx")},
WIDGET.newSlider{name="spawn", x=180, y=300,w=400, font=30,change=function()SFX.fplay("spawn_"..math.random(7),SETTING.sfx_spawn)end,disp=SETval("sfx_spawn"),code=SETsto("sfx_spawn")},
WIDGET.newSlider{name="warn", x=180, y=400,w=400, font=30,change=function()SFX.fplay("warning",SETTING.sfx_warn)end,disp=SETval("sfx_warn"),code=SETsto("sfx_warn")},
WIDGET.newSlider{name="bgm", x=180, y=500,w=400, font=35, disp=SETval("bgm"),code=function(v)SETTING.bgm=v BGM.freshVolume()end},
WIDGET.newSlider{name="stereo", x=180, y=600,w=400, font=35,change=function()SFX.play("move",1,-1)SFX.play("lock",1,1)end,disp=SETval("stereo"),code=SETsto("stereo"),hide=function()return SETTING.sx==0 end},
WIDGET.newSlider{name="vib", x=750, y=200,w=400,unit=5, font=25,change=function()VIB(2)end, disp=SETval("vib"),code=SETsto("vib")},
WIDGET.newSlider{name="voc", x=750, y=300,w=400, font=35,change=function()VOC.play("test")end, disp=SETval("voc"),code=SETsto("voc")},
WIDGET.newSelector{name="cv", x=1100, y=380,w=200, list={"miya","naki"}, disp=function()return cv end,code=function(i)cv=i end},
WIDGET.newButton{name="apply", x=1100, y=460,w=180,h=80, code=function()SETTING.cv=cv VOC.loadAll()end,hide=function()return SETTING.cv==cv end},
WIDGET.newButton{name="back", x=1140, y=640,w=170,h=80, font=40,code=backScene},

View File

@@ -30,11 +30,11 @@ scene.widgetList={
WIDGET.newSwitch{name="b20", x=580, y=620, font=35,disp=VKAdisp(20),code=VKAcode(20)},
WIDGET.newButton{name="norm", x=840, y=100, w=240,h=80, font=35,code=function()for i=1,20 do VK_org[i].ava=i<11 end end},
WIDGET.newButton{name="pro", x=1120, y=100, w=240,h=80, font=35,code=function()for i=1,20 do VK_org[i].ava=true end end},
WIDGET.newSwitch{name="hide", x=1170, y=200, font=40,disp=lnk_SETval("VKSwitch"),code=lnk_SETrev("VKSwitch")},
WIDGET.newSwitch{name="track", x=1170, y=300, font=35,disp=lnk_SETval("VKTrack"),code=lnk_SETrev("VKTrack")},
WIDGET.newSlider{name="sfx", x=800, y=380, w=180, font=35,change=function()SFX.play("virtualKey",SETTING.VKSFX)end,disp=lnk_SETval("VKSFX"),code=lnk_SETsto("VKSFX")},
WIDGET.newSlider{name="vib", x=800, y=460, w=180,unit=2, font=35,change=function()VIB(SETTING.VKVIB)end,disp=lnk_SETval("VKVIB"),code=lnk_SETsto("VKVIB")},
WIDGET.newSwitch{name="icon", x=850, y=300, font=40,disp=lnk_SETval("VKIcon"),code=lnk_SETrev("VKIcon")},
WIDGET.newSwitch{name="hide", x=1170, y=200, font=40,disp=SETval("VKSwitch"),code=SETrev("VKSwitch")},
WIDGET.newSwitch{name="track", x=1170, y=300, font=35,disp=SETval("VKTrack"),code=SETrev("VKTrack")},
WIDGET.newSlider{name="sfx", x=800, y=380, w=180, font=35,change=function()SFX.play("virtualKey",SETTING.VKSFX)end,disp=SETval("VKSFX"),code=SETsto("VKSFX")},
WIDGET.newSlider{name="vib", x=800, y=460, w=180,unit=2, font=35,change=function()VIB(SETTING.VKVIB)end,disp=SETval("VKVIB"),code=SETsto("VKVIB")},
WIDGET.newSwitch{name="icon", x=850, y=300, font=40,disp=SETval("VKIcon"),code=SETrev("VKIcon")},
WIDGET.newButton{name="tkset", x=1120, y=420, w=240,h=80,
code=function()
SCN.go("setting_trackSetting")
@@ -42,7 +42,7 @@ scene.widgetList={
hide=function()
return not SETTING.VKTrack
end},
WIDGET.newSlider{name="alpha", x=840, y=540, w=400,font=40,disp=lnk_SETval("VKAlpha"),code=lnk_SETsto("VKAlpha")},
WIDGET.newSlider{name="alpha", x=840, y=540, w=400,font=40,disp=SETval("VKAlpha"),code=SETsto("VKAlpha")},
WIDGET.newButton{name="back", x=1140, y=640, w=170,h=80,font=40,code=backScene},
}

View File

@@ -11,9 +11,9 @@ function scene.draw()
end
scene.widgetList={
WIDGET.newSwitch{name="VKDodge",x=400, y=530, font=35,disp=lnk_SETval("VKDodge"),code=lnk_SETrev("VKDodge")},
WIDGET.newSlider{name="VKTchW", x=140, y=320,w=1000, font=35,disp=lnk_SETval("VKTchW"),code=function(i)SETTING.VKTchW=i SETTING.VKCurW=math.max(SETTING.VKCurW,i)end},
WIDGET.newSlider{name="VKCurW", x=140, y=390,w=1000, font=35,disp=lnk_SETval("VKCurW"),code=function(i)SETTING.VKCurW=i SETTING.VKTchW=math.min(SETTING.VKTchW,i)end},
WIDGET.newSwitch{name="VKDodge",x=400, y=530, font=35,disp=SETval("VKDodge"),code=SETrev("VKDodge")},
WIDGET.newSlider{name="VKTchW", x=140, y=320,w=1000, font=35,disp=SETval("VKTchW"),code=function(i)SETTING.VKTchW=i SETTING.VKCurW=math.max(SETTING.VKCurW,i)end},
WIDGET.newSlider{name="VKCurW", x=140, y=390,w=1000, font=35,disp=SETval("VKCurW"),code=function(i)SETTING.VKCurW=i SETTING.VKTchW=math.min(SETTING.VKTchW,i)end},
WIDGET.newButton{name="back", x=1140, y=640,w=170,h=80,font=40,code=backScene},
}

View File

@@ -13,22 +13,22 @@ scene.widgetList={
WIDGET.newButton{name="sound", x=200, y=80,w=240,h=80,color="lCyan",font=35,code=swapScene"setting_sound","swipeR"},
WIDGET.newButton{name="game", x=1080, y=80,w=240,h=80,color="lCyan",font=35,code=swapScene"setting_game","swipeL"},
WIDGET.newSwitch{name="block", x=340, y=150, disp=lnk_SETval("block"), code=lnk_SETrev("block")},
WIDGET.newSwitch{name="smooth", x=340, y=210, disp=lnk_SETval("smooth"), code=lnk_SETrev("smooth")},
WIDGET.newSwitch{name="upEdge", x=340, y=270, disp=lnk_SETval("upEdge"), code=lnk_SETrev("upEdge")},
WIDGET.newSwitch{name="bagLine", x=340, y=330, disp=lnk_SETval("bagLine"), code=lnk_SETrev("bagLine")},
WIDGET.newSwitch{name="block", x=340, y=150, disp=SETval("block"), code=SETrev("block")},
WIDGET.newSwitch{name="smooth", x=340, y=210, disp=SETval("smooth"), code=SETrev("smooth")},
WIDGET.newSwitch{name="upEdge", x=340, y=270, disp=SETval("upEdge"), code=SETrev("upEdge")},
WIDGET.newSwitch{name="bagLine", x=340, y=330, disp=SETval("bagLine"), code=SETrev("bagLine")},
WIDGET.newSlider{name="ghost", x=630, y=180,w=200,unit=.6,disp=lnk_SETval("ghost"),show="percent",code=lnk_SETsto("ghost")},
WIDGET.newSlider{name="grid", x=630, y=240,w=200,unit=.4,disp=lnk_SETval("grid"),show="percent", code=lnk_SETsto("grid")},
WIDGET.newSlider{name="center", x=630, y=300,w=200,unit=1, disp=lnk_SETval("center"), code=lnk_SETsto("center")},
WIDGET.newSlider{name="ghost", x=630, y=180,w=200,unit=.6,disp=SETval("ghost"),show="percent",code=SETsto("ghost")},
WIDGET.newSlider{name="grid", x=630, y=240,w=200,unit=.4,disp=SETval("grid"),show="percent", code=SETsto("grid")},
WIDGET.newSlider{name="center", x=630, y=300,w=200,unit=1, disp=SETval("center"), code=SETsto("center")},
WIDGET.newSlider{name="lockFX", x=350, y=375,w=373,unit=5, disp=lnk_SETval("lockFX"), code=lnk_SETsto("lockFX")},
WIDGET.newSlider{name="dropFX", x=350, y=420,w=373,unit=5, disp=lnk_SETval("dropFX"), code=lnk_SETsto("dropFX")},
WIDGET.newSlider{name="moveFX", x=350, y=465,w=373,unit=5, disp=lnk_SETval("moveFX"), code=lnk_SETsto("moveFX")},
WIDGET.newSlider{name="clearFX", x=350, y=510,w=373,unit=5, disp=lnk_SETval("clearFX"), code=lnk_SETsto("clearFX")},
WIDGET.newSlider{name="splashFX", x=350, y=555,w=373,unit=5, disp=lnk_SETval("splashFX"),code=lnk_SETsto("splashFX")},
WIDGET.newSlider{name="shakeFX", x=350, y=600,w=373,unit=5, disp=lnk_SETval("shakeFX"), code=lnk_SETsto("shakeFX")},
WIDGET.newSlider{name="atkFX", x=350, y=645,w=373,unit=5, disp=lnk_SETval("atkFX"), code=lnk_SETsto("atkFX")},
WIDGET.newSlider{name="lockFX", x=350, y=375,w=373,unit=5, disp=SETval("lockFX"), code=SETsto("lockFX")},
WIDGET.newSlider{name="dropFX", x=350, y=420,w=373,unit=5, disp=SETval("dropFX"), code=SETsto("dropFX")},
WIDGET.newSlider{name="moveFX", x=350, y=465,w=373,unit=5, disp=SETval("moveFX"), code=SETsto("moveFX")},
WIDGET.newSlider{name="clearFX", x=350, y=510,w=373,unit=5, disp=SETval("clearFX"), code=SETsto("clearFX")},
WIDGET.newSlider{name="splashFX", x=350, y=555,w=373,unit=5, disp=SETval("splashFX"),code=SETsto("splashFX")},
WIDGET.newSlider{name="shakeFX", x=350, y=600,w=373,unit=5, disp=SETval("shakeFX"), code=SETsto("shakeFX")},
WIDGET.newSlider{name="atkFX", x=350, y=645,w=373,unit=5, disp=SETval("atkFX"), code=SETsto("atkFX")},
WIDGET.newSlider{name="frame", x=350, y=690,w=373,unit=10,
disp=function()
return SETTING.frameMul>35 and SETTING.frameMul/10 or SETTING.frameMul/5-4
@@ -37,20 +37,20 @@ scene.widgetList={
SETTING.frameMul=i<5 and 5*i+20 or 10*i
end},
WIDGET.newSwitch{name="text", x=1100, y=180,font=35,disp=lnk_SETval("text"), code=lnk_SETrev("text")},
WIDGET.newSwitch{name="score", x=1100, y=240,font=35,disp=lnk_SETval("score"), code=lnk_SETrev("score")},
WIDGET.newSwitch{name="warn", x=1100, y=300,font=35,disp=lnk_SETval("warn"), code=lnk_SETrev("warn")},
WIDGET.newSwitch{name="highCam", x=1100, y=360,font=35,disp=lnk_SETval("highCam"),code=lnk_SETrev("highCam")},
WIDGET.newSwitch{name="nextPos", x=1100, y=420,font=35,disp=lnk_SETval("nextPos"),code=lnk_SETrev("nextPos")},
WIDGET.newSwitch{name="fullscreen",x=1100, y=480,disp=lnk_SETval("fullscreen"), code=switchFullscreen},
WIDGET.newSwitch{name="bg", x=1100, y=540,font=35,disp=lnk_SETval("bg"),
WIDGET.newSwitch{name="text", x=1100, y=180,font=35,disp=SETval("text"), code=SETrev("text")},
WIDGET.newSwitch{name="score", x=1100, y=240,font=35,disp=SETval("score"), code=SETrev("score")},
WIDGET.newSwitch{name="warn", x=1100, y=300,font=35,disp=SETval("warn"), code=SETrev("warn")},
WIDGET.newSwitch{name="highCam", x=1100, y=360,font=35,disp=SETval("highCam"),code=SETrev("highCam")},
WIDGET.newSwitch{name="nextPos", x=1100, y=420,font=35,disp=SETval("nextPos"),code=SETrev("nextPos")},
WIDGET.newSwitch{name="fullscreen",x=1100, y=480,disp=SETval("fullscreen"), code=switchFullscreen},
WIDGET.newSwitch{name="bg", x=1100, y=540,font=35,disp=SETval("bg"),
code=function()
BG.set("none")
SETTING.bg=not SETTING.bg
BG.set()
end},
WIDGET.newSwitch{name="power", x=990, y=610,font=35,disp=lnk_SETval("powerInfo"),code=lnk_SETrev("powerInfo")},
WIDGET.newSwitch{name="clean", x=990, y=670,font=35,disp=lnk_SETval("cleanCanvas"),code=lnk_SETrev("cleanCanvas")},
WIDGET.newSwitch{name="power", x=990, y=610,font=35,disp=SETval("powerInfo"),code=SETrev("powerInfo")},
WIDGET.newSwitch{name="clean", x=990, y=670,font=35,disp=SETval("cleanCanvas"),code=SETrev("cleanCanvas")},
WIDGET.newButton{name="back", x=1140, y=640,w=170,h=80,font=40,code=backScene},
}

View File

@@ -39,8 +39,8 @@ end
scene.widgetList={
WIDGET.newText{name="title", x=30, y=15,font=70,align="L"},
WIDGET.newSlider{name="sfx", x=510, y=60,w=330,font=35,change=function()SFX.play("blip_1")end,disp=lnk_SETval("sfx"),code=lnk_SETsto("sfx")},
WIDGET.newSlider{name="voc", x=510, y=120,w=330,font=35,change=function()VOC.play("test")end,disp=lnk_SETval("voc"),code=lnk_SETsto("voc")},
WIDGET.newSlider{name="sfx", x=510, y=60,w=330,font=35,change=function()SFX.play("blip_1")end,disp=SETval("sfx"),code=SETsto("sfx")},
WIDGET.newSlider{name="voc", x=510, y=120,w=330,font=35,change=function()VOC.play("test")end,disp=SETval("voc"),code=SETsto("voc")},
WIDGET.newKey{name="move", x=110, y=140,w=160,h=50,font=20,code=function()SFX.play("move")end},
WIDGET.newKey{name="lock", x=110, y=205,w=160,h=50,font=20,code=function()SFX.play("lock")end},

View File

@@ -144,14 +144,14 @@ end
--WS icons
setFont(20)
TEXTURE.ws_dead=NSC(20,20)
gc.setColor(1,.4,.3)
gc.setColor(1,.3,.3)
gc.print("X",3,-4)
TEXTURE.ws_connecting=NSC(20,20)
gc.setLineWidth(3)
gc.setColor(1,1,1)
gc.arc("line","open",11.5,10,6.26,1,5.28)
TEXTURE.ws_running=NSC(20,20)
gc.setColor(0,.9,0)
gc.setColor(.5,1,0)
gc.print("R",3,-4)

View File

@@ -1,24 +1,70 @@
return SPLITSTR([=[
未来计划:
新模式:
无尽PC挑战; 简单极简练习; 任务生存; 对称; 跑酷; 教学; 术语问答; 无摩擦
极简教程/考试; 连击练习; 自攻自受; 大爆炸; 音游模式; 拼方形; 养成玩法
OSD; 强制Misdrop; 涂色模式(模仿喷喷, designed by teatube)
其他:
小游戏:
速算(前缀后缀表达式,二八十六进制); 动态视力测试(记数字)
Tetro-1010(四/五连块, 2C2N, 若干回合改变重力方向)
求合体; 坦克大战; 扫雷; 接水管; 各种NS计算器小游戏移植
多方块; XRS; 移动n格+硬降复合操作键; 更好的手柄支持; 手势操作
区分各种消除(隔断/架空/混合/彩色/穿墙)
更复杂的垃圾行(数量/等待时间/抵消倍率/洞数/连接/炸弹)
可调场地宽度; DAS系统更细节的折返选项; 特殊控件(虚拟摇杆等)
主菜单和选关UI重做; 适应任意屏幕尺寸的UI
可更换的全局主题系统; 成就系统; 3D背景
可选虚拟按键颜色; 工程编译到字节码; task-Z(新AI)
录像回放菜单; 跳帧开关; 超60帧; 热更新
未来模式:
无尽PC挑战; 简单极简练习; 任务生存; 对称; 无摩擦; 连击练习; 拼方形
极简教程/考试; 大爆炸; 音游模式; 跑酷; 术语问答; 养成玩法
OSD; 强制Misdrop; 涂色模式(模仿喷喷, designed by teatube)
未来大游戏:
puyo; 花仙子方块; 2048; 泡泡龙
未来Mod:
修改颜色配置; 只显示场地边框线/顶线
未来小游戏:
Tetro-1010(四/五连块, 2C2N, 若干回合改变重力方向)
Tetra-link; 速算(前缀后缀表达式,二八十六进制)
连连看; 求合体; 坦克大战; 扫雷; 接水管
其他未来内容:
XRS; 移动n格+硬降复合操作键; 更好的手柄支持
自适应UI; 重做模式选择UI和MOD的UI; 高级自定义序列
区分各种消除(隔断/架空/混合/彩色/穿墙)
更复杂的垃圾行(数量/等待时间/抵消倍率/洞数/连接/炸弹)
可调场地宽度; 手势操作; 特殊控件(虚拟摇杆等); 切换高低镜头的按键
DAS系统和Deepdrop系统更细节的选项; spike计数器; 攻击总缓冲显示
成就系统; 更强的主题系统; 多方块; 3D背景
可选虚拟按键颜色; 工程编译到字节码; task-Z(新AI)
录像回放菜单; 跳帧开关; 教学关; 超60帧; 热更新
0.13.3: 科技飞跃
0.14.0: 地平线 The Horizon
新增:
重新开放联网游戏测试
主菜单UI更新,改变几个场景间的关系
场地晃动加入旋转分量
加入c2和mess序列模式,可以在自定义或mod中开启
新模式:Backfire(四个难度)
新背景:BlackHole(用于Backfire)
新增BGM:echo(用于Backfire), hang out(用于两个小程序)
调整自定义场地的ui可以看到鼠标不同按键对应画笔颜色
小程序DTW增加双押功能
新增绘制优化设置(手机开启可能加速,花屏可能关闭解决)
改动:
错误处理机制大升级,更不容易闪退(CC爆炸除外)
赞助名单移至staff场景并添加动画(已经在榜上的可以来定制颜色!)
修改GM模式的名称和段位名以及修改连带内容,加高成绩上限,修复一个旧版本存档转换错误
封面NOGAME改为启动时弹窗提示重启
鼠标按下时光标显示会变化
优化场地绘制交互,添加一个鼠标功能指示器
微调生存模式下落速度
修改时间字符串格式
词典不再大小写敏感
调整徽章图标
添加naki立绘
报错时会把traceback信息保存到日志文件便于debug
cmd添加一些测试用命令和一些文件管理命令,可以用于自行修复存档
cmd添加复制粘贴剪切和tab补全,不再需要切焦点
ws状态展示样式升级,只在debug模式下显示
代码:
序列生成器改用协程实现
THEME做成独立模块
玩家属性modeData地位提升
不再每次启动时强制删除存档目录内所有非文件夹内容
绘制玩家场地用的scissor换成stencil(支持旋转和变形)
优化/大规模整理代码,网络相关全面升级
修复:
物理hold可能会卡死和踢墙测试位置不正确
词典中c2序列生成器的说明错误
刚安装就用简洁模式玩会报错(修改成绩比较逻辑)
报错提示的场景显示不正确
智能画笔问题
0.13.3: 科技飞跃 Technological Advancements
新增:
地图UI升级,增加模式图标
自定义场地新增智能画笔
@@ -45,7 +91,7 @@ return SPLITSTR([=[
一个老存档转换问题
重开后虚拟按键失效
0.13.2+: 工作室搬迁
0.13.2+: 工作室搬迁 Moving the Studio
新增:
全新加载动画与资源加载机制
显示ai计算的下一块位置
@@ -59,7 +105,7 @@ return SPLITSTR([=[
修复:
CC闪退(可能修复)
0.13.2: 节奏模式
0.13.2: 节奏模式 Rhythm Mode
新增:
新增节奏模式(三个难度)
加入deepDrop功能(暂时只在自定义开放)