From ad7feed5bf992cfa9bb3bf8374160dc9f64d81ff Mon Sep 17 00:00:00 2001 From: MrZ626 <1046101471@qq.com> Date: Sun, 28 Mar 2021 03:42:00 +0800 Subject: [PATCH 01/83] =?UTF-8?q?=E5=B0=9D=E8=AF=95=E5=90=AF=E7=94=A8ws-pl?= =?UTF-8?q?ay?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main.lua | 1 - parts/gametoolfunc.lua | 13 +++++----- parts/scenes/net_rooms.lua | 52 ++++++++++++++++++++------------------ 3 files changed, 34 insertions(+), 32 deletions(-) diff --git a/main.lua b/main.lua index 1f74bb39..d0b3add4 100644 --- a/main.lua +++ b/main.lua @@ -27,7 +27,6 @@ LOGIN=false EDITING="" NET={ allow_online=false, - try_enter_netmenu=false, } ERRDATA={} diff --git a/parts/gametoolfunc.lua b/parts/gametoolfunc.lua index 814ac235..b6985574 100644 --- a/parts/gametoolfunc.lua +++ b/parts/gametoolfunc.lua @@ -1168,7 +1168,6 @@ do 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") @@ -1184,10 +1183,10 @@ do 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 + WS.connect("play","/play",JSON.encode{ + id=USER.id, + accessToken=USER.accessToken, + }) elseif res.action==1 then USER.name=res.username USER.motto=res.motto @@ -1239,7 +1238,9 @@ do return else local res=JSON.decode(message) - --TODO + if res.message=="Connected"then + SCN.go("net_menu") + end end end end diff --git a/parts/scenes/net_rooms.lua b/parts/scenes/net_rooms.lua index 2d7e86a7..3226ff21 100644 --- a/parts/scenes/net_rooms.lua +++ b/parts/scenes/net_rooms.lua @@ -6,26 +6,27 @@ local scrollPos,selected local lastfreshTime 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, - }) - ]] + WS.send("play","/play",JSON.encode{ + action=0, + data={ + type=nil, + begin=0, + count=10, + } + }) +end +local function enterRoom(roomID,password) + WS.send("play","/play",JSON.encode{ + action=2, + data={ + rid=roomID, + conf=dumpBasicConfig(), + password=password, + } + }) end local scene={} @@ -47,14 +48,15 @@ function scene.keyDown(k) 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, - }) - ]] + WS.send("play",JSON.encode{ + action=1, + data={ + type=nil, + name=(USER.name or"???").."'s room", + password=nil, + conf=dumpBasicConfig(), + } + }) lastCreateRoomTime=TIME() else LOG.print(text.createRoomTooFast,"warn") From 2aeb8b5deacfa1f1b2c98c91204154bfefb2923a Mon Sep 17 00:00:00 2001 From: MrZ626 <1046101471@qq.com> Date: Sun, 28 Mar 2021 11:32:00 +0800 Subject: [PATCH 02/83] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dws=E5=BA=93=E8=BF=94?= =?UTF-8?q?=E5=9B=9E=E7=9A=84op=E7=B1=BB=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Zframework/websocket.lua | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Zframework/websocket.lua b/Zframework/websocket.lua index 8ac28640..660f0223 100644 --- a/Zframework/websocket.lua +++ b/Zframework/websocket.lua @@ -188,6 +188,14 @@ 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 @@ -202,7 +210,7 @@ function WS.read(name) local message=ws.readCHN:pop() if op==8 then ws.status="dead"end ws.lastPongTime=timer() - return message,op + return message,OPname[op]or op end end From 014ae849832bcd0f3773d3282b6959eecf6284df Mon Sep 17 00:00:00 2001 From: MrZ626 <1046101471@qq.com> Date: Sun, 28 Mar 2021 15:16:47 +0800 Subject: [PATCH 03/83] =?UTF-8?q?=E4=B8=8D=E5=86=8D=E9=94=99=E8=AF=AF?= =?UTF-8?q?=E5=A4=84=E7=90=86pong=E6=B6=88=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- parts/gametoolfunc.lua | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/parts/gametoolfunc.lua b/parts/gametoolfunc.lua index b6985574..87adc867 100644 --- a/parts/gametoolfunc.lua +++ b/parts/gametoolfunc.lua @@ -1121,6 +1121,7 @@ do if message then if op=="ping"then WS.send("app",message,"pong") + elseif op=="pong"then elseif op=="close"then message=JSON.decode(message) if message then @@ -1155,6 +1156,7 @@ do if message then if op=="ping"then WS.send("user",message,"pong") + elseif op=="pong"then elseif op=="close"then message=JSON.decode(message) if message then @@ -1207,6 +1209,7 @@ do if message then if op=="ping"then WS.send("chat",message,"pong") + elseif op=="pong"then elseif op=="close"then message=JSON.decode(message) if message then @@ -1230,6 +1233,7 @@ do if message then if op=="ping"then WS.send("play",message,"pong") + elseif op=="pong"then elseif op=="close"then message=JSON.decode(message) if message then @@ -1255,6 +1259,7 @@ do if message then if op=="ping"then WS.send("stream",message,"pong") + elseif op=="pong"then elseif op=="close"then message=JSON.decode(message) if message then From d0b797d6bd67cc51ef953f612934b11ef9647bb9 Mon Sep 17 00:00:00 2001 From: MrZ626 <1046101471@qq.com> Date: Sun, 28 Mar 2021 15:44:44 +0800 Subject: [PATCH 04/83] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=B8=BB=E8=8F=9C?= =?UTF-8?q?=E5=8D=95=E8=A7=92=E8=90=BD=E4=B8=89=E4=B8=AA=E6=8C=89=E9=92=AE?= =?UTF-8?q?=E6=8C=89=E4=B8=8D=E4=BA=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- parts/scenes/main.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/parts/scenes/main.lua b/parts/scenes/main.lua index 6ea1db7a..fd117de0 100644 --- a/parts/scenes/main.lua +++ b/parts/scenes/main.lua @@ -183,9 +183,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}, } From e6becff209a33244fa7a2a067665c807811aa94e Mon Sep 17 00:00:00 2001 From: MrZ626 <1046101471@qq.com> Date: Sun, 28 Mar 2021 16:08:25 +0800 Subject: [PATCH 05/83] =?UTF-8?q?ws-user=E8=BF=87=E6=BB=A4=E9=9D=9Ejson?= =?UTF-8?q?=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- parts/gametoolfunc.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/parts/gametoolfunc.lua b/parts/gametoolfunc.lua index 87adc867..8830b474 100644 --- a/parts/gametoolfunc.lua +++ b/parts/gametoolfunc.lua @@ -1165,6 +1165,7 @@ do return else local res=JSON.decode(message) + if not res then return end if res.message=="Connected"then LOGIN=true if res.id then From 35ac6eacbcc9a0fb589796b6df4cd632638ebb09 Mon Sep 17 00:00:00 2001 From: MrZ626 <1046101471@qq.com> Date: Sun, 28 Mar 2021 20:15:36 +0800 Subject: [PATCH 06/83] =?UTF-8?q?LOGIN=E5=8F=98=E9=87=8F=E7=A7=BB=E8=87=B3?= =?UTF-8?q?NET=E5=86=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main.lua | 2 +- parts/gametoolfunc.lua | 4 ++-- parts/scenes/main.lua | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/main.lua b/main.lua index d0b3add4..f8722495 100644 --- a/main.lua +++ b/main.lua @@ -23,9 +23,9 @@ SAVEDIR=fs.getSaveDirectory() --Global Vars & Settings LOADED=false DAILYLAUNCH=false -LOGIN=false EDITING="" NET={ + login=false, allow_online=false, } ERRDATA={} diff --git a/parts/gametoolfunc.lua b/parts/gametoolfunc.lua index 8830b474..7306cd6f 100644 --- a/parts/gametoolfunc.lua +++ b/parts/gametoolfunc.lua @@ -1068,7 +1068,7 @@ do --[[ register: if response.message=="OK"then - LOGIN=true + NET.login=true USER.name=res.name USER.id=res.id USER.motto=res.motto @@ -1167,7 +1167,7 @@ do local res=JSON.decode(message) if not res then return end if res.message=="Connected"then - LOGIN=true + NET.login=true if res.id then USER.id=res.id USER.authToken=res.authToken diff --git a/parts/scenes/main.lua b/parts/scenes/main.lua index fd117de0..0f074243 100644 --- a/parts/scenes/main.lua +++ b/parts/scenes/main.lua @@ -77,7 +77,7 @@ 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") From 4222fff2e3a3c9cd6acbb6adae0f69d6d117e880 Mon Sep 17 00:00:00 2001 From: MrZ626 <1046101471@qq.com> Date: Sun, 28 Mar 2021 21:08:15 +0800 Subject: [PATCH 07/83] =?UTF-8?q?=E6=8A=8A=E6=89=80=E6=9C=89=E7=BD=91?= =?UTF-8?q?=E7=BB=9C=E6=93=8D=E4=BD=9C=E6=8A=BD=E8=B1=A1=E5=88=B0NET?= =?UTF-8?q?=E4=B8=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main.lua | 5 +-- parts/gametoolfunc.lua | 24 ++++------- parts/net.lua | 84 ++++++++++++++++++++++++++++++++++++++ parts/player/player.lua | 2 +- parts/scenes/main.lua | 2 +- parts/scenes/net_chat.lua | 14 ++----- parts/scenes/net_game.lua | 16 ++------ parts/scenes/net_rooms.lua | 31 ++------------ 8 files changed, 105 insertions(+), 73 deletions(-) create mode 100644 parts/net.lua diff --git a/main.lua b/main.lua index f8722495..b512c1f7 100644 --- a/main.lua +++ b/main.lua @@ -24,10 +24,6 @@ SAVEDIR=fs.getSaveDirectory() LOADED=false DAILYLAUNCH=false EDITING="" -NET={ - login=false, - allow_online=false, -} ERRDATA={} --System setting @@ -80,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" diff --git a/parts/gametoolfunc.lua b/parts/gametoolfunc.lua index 7306cd6f..2b2cf3f6 100644 --- a/parts/gametoolfunc.lua +++ b/parts/gametoolfunc.lua @@ -1120,7 +1120,7 @@ do local message,op=WS.read("app") if message then if op=="ping"then - WS.send("app",message,"pong") + NET.pong("app",message) elseif op=="pong"then elseif op=="close"then message=JSON.decode(message) @@ -1155,7 +1155,7 @@ do local message,op=WS.read("user") if message then if op=="ping"then - WS.send("user",message,"pong") + NET.pong("user",message) elseif op=="pong"then elseif op=="close"then message=JSON.decode(message) @@ -1171,25 +1171,17 @@ do if res.id then USER.id=res.id USER.authToken=res.authToken - WS.send("user",JSON.encode{action=0}) + NET.getAccessToken() 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, - }, - }) + NET.getSelfInfo() elseif res.action==0 then USER.accessToken=res.accessToken LOG.print(text.accessSuccessed) - WS.connect("play","/play",JSON.encode{ - id=USER.id, - accessToken=USER.accessToken, - }) + NET.wsConnectPlay() elseif res.action==1 then USER.name=res.username USER.motto=res.motto @@ -1209,7 +1201,7 @@ do local message,op=WS.read("chat") if message then if op=="ping"then - WS.send("chat",message,"pong") + NET.pong("chat",message) elseif op=="pong"then elseif op=="close"then message=JSON.decode(message) @@ -1233,7 +1225,7 @@ do local message,op=WS.read("play") if message then if op=="ping"then - WS.send("play",message,"pong") + NET.pong("play",message) elseif op=="pong"then elseif op=="close"then message=JSON.decode(message) @@ -1259,7 +1251,7 @@ do local message,op=WS.read("stream") if message then if op=="ping"then - WS.send("stream",message,"pong") + NET.pong("stream",message) elseif op=="pong"then elseif op=="close"then message=JSON.decode(message) diff --git a/parts/net.lua b/parts/net.lua new file mode 100644 index 00000000..05e05c95 --- /dev/null +++ b/parts/net.lua @@ -0,0 +1,84 @@ +local data=love.data +local NET={ + login=false, + allow_online=false, +} + +--Account +function NET.pong(wsName,message) + WS.send(wsName,message,"pong") +end +function NET.getAccessToken() + WS.send("user",JSON.encode{action=0}) +end +function NET.getSelfInfo() + WS.send("user",JSON.encode{ + action=1, + data={ + id=USER.id, + }, + }) +end + +--Play +function NET.wsConnectPlay() + WS.connect("play","/play",JSON.encode{ + id=USER.id, + accessToken=USER.accessToken, + }) +end +function NET.signal_ready() + WS.send("play","R") +end +function NET.uploadRecStream(stream) + WS.send("stream",data.encode("string","base64",stream)) +end +function NET.signal_die() + WS.send("play","D") +end +function NET.signal_quit() + WS.send("play","Q") +end + +--Room +function NET.freshRoom() + WS.send("play","/play",JSON.encode{ + action=0, + data={ + type=nil, + begin=0, + count=10, + } + }) +end +function NET.createRoom() + WS.send("play",JSON.encode{ + action=1, + data={ + type=nil, + name=(USER.name or"???").."'s room", + password=nil, + conf=dumpBasicConfig(), + } + }) +end +function NET.enterRoom(roomID,password) + WS.send("play","/play",JSON.encode{ + action=2, + data={ + rid=roomID, + conf=dumpBasicConfig(), + password=password, + } + }) +end + +--Chat +function NET.sendChatMes(mes) + WS.send("chat","T"..data.encode("string","base64",mes)) +end +function NET.quitChat() + WS.send("chat","Q") +end + +return NET \ No newline at end of file diff --git a/parts/player/player.lua b/parts/player/player.lua index 44fcc9d6..1e822aca 100644 --- a/parts/player/player.lua +++ b/parts/player/player.lua @@ -1813,7 +1813,7 @@ function Player.lose(P,force) gameOver() P:newTask(#PLAYERS>1 and tick_lose or tick_finish) if GAME.net then - WS.send("play","D") + NET.signal_die() else TASK.new(tick_autoPause) end diff --git a/parts/scenes/main.lua b/parts/scenes/main.lua index 0f074243..209f5375 100644 --- a/parts/scenes/main.lua +++ b/parts/scenes/main.lua @@ -82,7 +82,7 @@ function scene.keyDown(key) 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") diff --git a/parts/scenes/net_chat.lua b/parts/scenes/net_chat.lua index 9c2242e2..fb8696dc 100644 --- a/parts/scenes/net_chat.lua +++ b/parts/scenes/net_chat.lua @@ -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,7 +29,7 @@ function scene.sceneInit() BG.set("none") end function scene.sceneBack() - WS.send("chat","Q") + NET.quitChat() LOG.print(text.wsDisconnected,"warn") end @@ -80,13 +79,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) diff --git a/parts/scenes/net_game.lua b/parts/scenes/net_game.lua index f1d46441..7ea561f9 100644 --- a/parts/scenes/net_game.lua +++ b/parts/scenes/net_game.lua @@ -20,7 +20,6 @@ end local playerInitialized local playing -local heartBeatTimer local lastUpstreamTime local upstreamProgress local lastBackTime=0 @@ -30,7 +29,7 @@ local touchMoveLastFrame=false local scene={} function scene.sceneBack() - WS.send("play","Q") + NET.signal_quit() LOG.print(text.wsDisconnected,"warn") love.keyboard.setKeyRepeat(true) end @@ -107,7 +106,7 @@ function scene.keyDown(key) end elseif key=="space"then if not PLAYERS[1].ready then - WS.send("play","R") + NET.signal_ready() end end end @@ -262,14 +261,7 @@ function scene.update(dt) 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 not playing then return end touchMoveLastFrame=false updateVirtualkey() @@ -289,7 +281,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) diff --git a/parts/scenes/net_rooms.lua b/parts/scenes/net_rooms.lua index 3226ff21..2037bd59 100644 --- a/parts/scenes/net_rooms.lua +++ b/parts/scenes/net_rooms.lua @@ -9,24 +9,7 @@ local lastCreateRoomTime=0 local function fresh() lastfreshTime=TIME() rooms=nil - WS.send("play","/play",JSON.encode{ - action=0, - data={ - type=nil, - begin=0, - count=10, - } - }) -end -local function enterRoom(roomID,password) - WS.send("play","/play",JSON.encode{ - action=2, - data={ - rid=roomID, - conf=dumpBasicConfig(), - password=password, - } - }) + NET.freshRoom() end local scene={} @@ -48,15 +31,7 @@ function scene.keyDown(k) end elseif k=="n"then if TIME()-lastCreateRoomTime>26 then - WS.send("play",JSON.encode{ - action=1, - data={ - type=nil, - name=(USER.name or"???").."'s room", - password=nil, - conf=dumpBasicConfig(), - } - }) + NET.createRoom() lastCreateRoomTime=TIME() else LOG.print(text.createRoomTooFast,"warn") @@ -83,7 +58,7 @@ function scene.keyDown(k) LOG.print("Can't enter private room now") return end - enterRoom(rooms[selected].id) + NET.enterRoom(rooms[selected].id)--,password end end end From f25c4e1423ca8ee7558172c86999121f2cc520e9 Mon Sep 17 00:00:00 2001 From: MrZ626 <1046101471@qq.com> Date: Sun, 28 Mar 2021 22:13:23 +0800 Subject: [PATCH 08/83] =?UTF-8?q?ws=E5=BA=93=E6=94=AF=E6=8C=81continue?= =?UTF-8?q?=E7=9A=84opcode?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: flaribbit <1149761294@qq.com> --- Zframework/websocket.lua | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/Zframework/websocket.lua b/Zframework/websocket.lua index 660f0223..6144ba2f 100644 --- a/Zframework/websocket.lua +++ b/Zframework/websocket.lua @@ -97,7 +97,7 @@ do--Connect end - +local buffer while true do--Running triggerCHN:demand() while sendCHN:getCount()>=2 do @@ -112,6 +112,7 @@ while true do--Running if not res then break end local op=band(byte(res,1),0x0f) + local fin=band(byte(res,1),0x80)==0x80 --Calculating data length local length=band(byte(res,2),0x7f) @@ -128,8 +129,8 @@ while true do--Running res=SOCK:receive(length) --React - readCHN:push(op) - if op==8 then--close + if op==8 then--8=close + readCHN:push(op) SOCK:close() if type(res)=="string"then local reason=JSON.decode(res) @@ -137,8 +138,19 @@ while true do--Running else readCHN:push("Server Error") end + elseif op==0 then + buffer=buffer..res + if fin then + readCHN:push(buffer) + buffer="" + end else - readCHN:push(res) + readCHN:push(op) + if fin then + readCHN:push(res) + else + buffer=res + end end end end @@ -208,7 +220,7 @@ function WS.read(name) if 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,OPname[op]or op end From 5d456dda67020eb5dd98750bcae222e27b85f5d2 Mon Sep 17 00:00:00 2001 From: MrZ626 <1046101471@qq.com> Date: Mon, 29 Mar 2021 00:37:59 +0800 Subject: [PATCH 09/83] =?UTF-8?q?=E4=BF=AE=E5=A4=8DTASK=E6=A8=A1=E5=9D=97?= =?UTF-8?q?=E5=9C=A8=E5=8D=8F=E7=A8=8B=E6=8A=A5=E9=94=99=E5=90=8E=E8=B7=B3?= =?UTF-8?q?=E8=BF=87=E5=88=A0=E9=99=A4task=E4=BB=A3=E7=A0=81=E5=AF=BC?= =?UTF-8?q?=E8=87=B4=E5=9C=A8=E9=94=99=E8=AF=AF=E7=95=8C=E9=9D=A2=E8=BF=9E?= =?UTF-8?q?=E7=BB=AD=E7=88=86=E7=82=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Zframework/task.lua | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/Zframework/task.lua b/Zframework/task.lua index f2685c7c..3fa19084 100644 --- a/Zframework/task.lua +++ b/Zframework/task.lua @@ -1,6 +1,6 @@ local rem=table.remove -local ct=coroutine local assert=assert +local resume,status=coroutine.resume,coroutine.status local tasks={} local TASK={} @@ -10,16 +10,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, From ccbe7646da5942bdf3261cb7ddf83d479e38c791 Mon Sep 17 00:00:00 2001 From: MrZ626 <1046101471@qq.com> Date: Mon, 29 Mar 2021 01:04:09 +0800 Subject: [PATCH 10/83] =?UTF-8?q?ws=E6=A8=A1=E5=9D=97=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E4=B8=A4=E4=B8=AA=E8=AE=A1=E6=97=B6=E5=99=A8=E7=94=A8=E6=9D=A5?= =?UTF-8?q?=E6=98=BE=E7=A4=BA=E7=8A=B6=E6=80=81=EF=BC=8C=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?alert=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Zframework/init.lua | 9 ++-- Zframework/websocket.lua | 95 +++++++++++++++++++++++++++------------- 2 files changed, 68 insertions(+), 36 deletions(-) diff --git a/Zframework/init.lua b/Zframework/init.lua index e89ff481..e29e9e40 100644 --- a/Zframework/init.lua +++ b/Zframework/init.lua @@ -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 @@ -598,11 +598,8 @@ function love.run() gc_setColor(.8,.8,.8) 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 + gc_setColor(1,1,1,WS.getPongTimer(WSnames[i]))gc_rectangle("fill",0,20*i,-20,-20) + gc_setColor(1,0,0,WS.getPongTimer(WSnames[i]))gc_rectangle("fill",-4,20*i-4,-12,-12) end gc_pop() diff --git a/Zframework/websocket.lua b/Zframework/websocket.lua index 6144ba2f..e32b6b14 100644 --- a/Zframework/websocket.lua +++ b/Zframework/websocket.lua @@ -158,10 +158,23 @@ 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(), + pongTimer=0, + alertTimer=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(), @@ -170,6 +183,8 @@ function WS.connect(name,subPath,body) lastPongTime=timer(), pingInterval=26, status="connecting",--connecting, running, dead + pongTimer=0, + alertTimer=0, } wsList[name]=ws ws.thread:start(ws.triggerCHN,ws.sendCHN,ws.readCHN) @@ -180,11 +195,16 @@ 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.getPongTimer(name) + return wsList[name].pongTimer +end + +function WS.getAlertTimer(name) + return wsList[name].alertTimer end function WS.setPingInterval(name,time) @@ -192,6 +212,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=1 +end + local OPcode={ continue=0, text=1, @@ -210,52 +235,62 @@ local OPname={ } 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() + 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--8=close ws.lastPongTime=timer() + 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" - ws.lastPingTime=time - ws.lastPongTime=time - else - ws.status="dead" - LOG.print(text.wsFailed.." "..mes,"warn") + 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,"warn") + end end + elseif time-ws.lastPingTime>ws.pingInterval then + ws.sendCHN:push(9) + ws.sendCHN:push("")--ping + ws.lastPingTime=time 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 time-ws.lastPongTime>10+3*ws.pingInterval then + WS.close(name) + 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 From 0233adc184379b91079655a6afa4b8f4295d4f58 Mon Sep 17 00:00:00 2001 From: MrZ626 <1046101471@qq.com> Date: Mon, 29 Mar 2021 01:07:00 +0800 Subject: [PATCH 11/83] =?UTF-8?q?=E6=8B=89=E5=8F=96ws=E6=B6=88=E6=81=AF?= =?UTF-8?q?=E6=9B=B4=E4=B8=8D=E5=AE=B9=E6=98=93=E7=88=86=E7=82=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- parts/gametoolfunc.lua | 76 +++++++++++++++++++++++++----------------- 1 file changed, 45 insertions(+), 31 deletions(-) diff --git a/parts/gametoolfunc.lua b/parts/gametoolfunc.lua index 2b2cf3f6..efb7ee33 100644 --- a/parts/gametoolfunc.lua +++ b/parts/gametoolfunc.lua @@ -1130,13 +1130,17 @@ do return else local res=JSON.decode(message) - if VERSION_CODE>=res.lowest then - NET.allow_online=true + if res then + if VERSION_CODE>=res.lowest then + NET.allow_online=true + end + if VERSION_CODE Date: Mon, 29 Mar 2021 01:15:17 +0800 Subject: [PATCH 12/83] =?UTF-8?q?=E7=8E=A9=E5=AE=B6=E7=B1=BB=E6=89=80?= =?UTF-8?q?=E6=9C=89=E6=96=B9=E6=B3=95=E6=94=B9=E7=94=A8=E5=86=92=E5=8F=B7?= =?UTF-8?q?=E5=92=8Cself?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- parts/player/player.lua | 1519 +++++++++++++++++++-------------------- 1 file changed, 759 insertions(+), 760 deletions(-) diff --git a/parts/player/player.lua b/parts/player/player.lua index 1e822aca..1cd56cf6 100644 --- a/parts/player/player.lua +++ b/parts/player/player.lua @@ -1,7 +1,6 @@ ------------------------------------------------------- ---Notice: anything in this file or in any other file, ---local var P stands for Player object. Don't forget it. ------------------------------------------------------- +------------------------------------------------- +--Var P in other files represent Player object!-- +------------------------------------------------- local Player={}--Player class local int,ceil,rnd=math.floor,math.ceil,math.random @@ -12,96 +11,96 @@ local resume,yield=coroutine.resume,coroutine.yield local kickList=require"parts.kickList" ---------------------------------------------------- -function Player.showText(P,text,dx,dy,font,style,spd,stop) - if P.gameEnv.text then - ins(P.bonus,TEXT.getText(text,150+dx,300+dy,font*P.size,style,spd,stop)) +function Player:showText(text,dx,dy,font,style,spd,stop) + if self.gameEnv.text then + ins(self.bonus,TEXT.getText(text,150+dx,300+dy,font*self.size,style,spd,stop)) end end -function Player.showTextF(P,text,dx,dy,font,style,spd,stop) - ins(P.bonus,TEXT.getText(text,150+dx,300+dy,font*P.size,style,spd,stop)) +function Player:showTextF(text,dx,dy,font,style,spd,stop) + ins(self.bonus,TEXT.getText(text,150+dx,300+dy,font*self.size,style,spd,stop)) end -function Player.createLockFX(P) - local CB=P.cur.bk - local t=12-P.gameEnv.lockFX*2 +function Player:createLockFX() + local CB=self.cur.bk + local t=12-self.gameEnv.lockFX*2 for i=1,#CB do - local y=P.curY+i-1 - local L=P.clearedRow + local y=self.curY+i-1 + local L=self.clearedRow for j=1,#L do if L[j]==y then goto CONTINUE_skip end end y=-30*y for j=1,#CB[1]do if CB[i][j]then - ins(P.lockFX,{30*(P.curX+j-2),y,0,t}) + ins(self.lockFX,{30*(self.curX+j-2),y,0,t}) end end ::CONTINUE_skip:: end end -function Player.createDropFX(P,x,y,w,h) - ins(P.dropFX,{x,y,w,h,0,13-2*P.gameEnv.dropFX}) +function Player:createDropFX(x,y,w,h) + ins(self.dropFX,{x,y,w,h,0,13-2*self.gameEnv.dropFX}) end -function Player.createMoveFX(P,dir) - local T=10-1.5*P.gameEnv.moveFX - local C=P.cur.color - local CB=P.cur.bk - local x=P.curX-1 - local y=P.gameEnv.smooth and P.curY+P.dropDelay/P.gameEnv.drop-2 or P.curY-1 +function Player:createMoveFX(dir) + local T=10-1.5*self.gameEnv.moveFX + local C=self.cur.color + local CB=self.cur.bk + local x=self.curX-1 + local y=self.gameEnv.smooth and self.curY+self.dropDelay/self.gameEnv.drop-2 or self.curY-1 if dir=="left"then for i=1,#CB do for j=#CB[1],1,-1 do - if P.cur.bk[i][j]then - ins(P.moveFX,{C,x+j,y+i,0,T}) + if self.cur.bk[i][j]then + ins(self.moveFX,{C,x+j,y+i,0,T}) break end end end elseif dir=="right"then for i=1,#CB do for j=1,#CB[1]do - if P.cur.bk[i][j]then - ins(P.moveFX,{C,x+j,y+i,0,T}) + if self.cur.bk[i][j]then + ins(self.moveFX,{C,x+j,y+i,0,T}) break end end end elseif dir=="down"then for j=1,#CB[1]do for i=#CB,1,-1 do - if P.cur.bk[i][j]then - ins(P.moveFX,{C,x+j,y+i,0,T}) + if self.cur.bk[i][j]then + ins(self.moveFX,{C,x+j,y+i,0,T}) break end end end else for i=1,#CB do for j=1,#CB[1]do - if P.cur.bk[i][j]then - ins(P.moveFX,{C,x+j,y+i,0,T}) + if self.cur.bk[i][j]then + ins(self.moveFX,{C,x+j,y+i,0,T}) end end end end end -function Player.createSplashFX(P,h) - local L=P.field[h] - local size=P.size - local y=P.fieldY+size*(P.fieldOff.y+P.fieldBeneath+P.fieldUp+615) +function Player:createSplashFX(h) + local L=self.field[h] + local size=self.size + local y=self.fieldY+size*(self.fieldOff.y+self.fieldBeneath+self.fieldUp+615) for x=1,10 do local c=L[x] if c>0 then SYSFX.newCell( - 2.5-P.gameEnv.splashFX*.4, + 2.5-self.gameEnv.splashFX*.4, SKIN.curText[c], size, - P.fieldX+(30*x-15)*size,y-30*h*size, + self.fieldX+(30*x-15)*size,y-30*h*size, rnd()*5-2.5,rnd()*-1, 0,.6 ) end end end -function Player.createClearingFX(P,y,spd) - ins(P.clearFX,{y,0,spd}) +function Player:createClearingFX(y,spd) + ins(self.clearFX,{y,0,spd}) end -function Player.createBeam(P,R,send,color) +function Player:createBeam(R,send,color) local x1,y1,x2,y2 - if P.mini then x1,y1=P.centerX,P.centerY - else x1,y1=P.x+(30*(P.curX+P.cur.sc[2])-30+15+150)*P.size,P.y+(600-30*(P.curY+P.cur.sc[1])+15)*P.size + if self.mini then x1,y1=self.centerX,self.centerY + else x1,y1=self.x+(30*(self.curX+self.cur.sc[2])-30+15+150)*self.size,self.y+(600-30*(self.curY+self.cur.sc[1])+15)*self.size end if R.small then x2,y2=R.centerX,R.centerY else x2,y2=R.x+308*R.size,R.y+450*R.size @@ -110,21 +109,21 @@ function Player.createBeam(P,R,send,color) local r,g,b=unpack(minoColor[color]) r,g,b=r*2,g*2,b*2 - local a=GAME.modeEnv.royaleMode and not(P.type=="human"or R.type=="human")and .2 or 1 + local a=GAME.modeEnv.royaleMode and not(self.type=="human"or R.type=="human")and .2 or 1 SYSFX.newAttack(1-SETTING.atkFX*.1,x1,y1,x2,y2,int(send^.7*(4+SETTING.atkFX)),r,g,b,a*(SETTING.atkFX+2)*.0626) end ---------------------------------------------------- ---------------------------------------------------- -function Player.RND(P,a,b) - local R=P.randGen +function Player:RND(a,b) + local R=self.randGen return R:random(a,b) end -function Player.newTask(P,code,...) +function Player:newTask(code,...) local thread=coroutine.create(code) - coroutine.resume(thread,P,...) + coroutine.resume(thread,self,...) if coroutine.status(thread)~="dead"then - P.tasks[#P.tasks+1]={ + self.tasks[#self.tasks+1]={ thread=thread, code=code, args={...}, @@ -132,164 +131,164 @@ function Player.newTask(P,code,...) end end -function Player.setPosition(P,x,y,size) +function Player:setPosition(x,y,size) size=size or 1 - P.x,P.y,P.size=x,y,size - if P.mini or P.demo then - P.fieldX,P.fieldY=x,y - P.centerX,P.centerY=x+300*size,y+600*size + self.x,self.y,self.size=x,y,size + if self.mini or self.demo then + self.fieldX,self.fieldY=x,y + self.centerX,self.centerY=x+300*size,y+600*size else - P.fieldX,P.fieldY=x+150*size,y - P.centerX,P.centerY=x+300*size,y+370*size - P.absFieldX,P.absFieldY=x+150*size,y-10*size + self.fieldX,self.fieldY=x+150*size,y + self.centerX,self.centerY=x+300*size,y+370*size + self.absFieldX,self.absFieldY=x+150*size,y-10*size end end -local function task_movePosition(P,x,y,size) - local x1,y1,size1=P.x,P.y,P.size +local function task_movePosition(self,x,y,size) + local x1,y1,size1=self.x,self.y,self.size while true do yield() if (x1-x)^2+(y1-y)^2<1 then - P:setPosition(x,y,size) + self:setPosition(x,y,size) return true else x1=x1+(x-x1)*.126 y1=y1+(y-y1)*.126 size1=size1+(size-size1)*.126 - P:setPosition(x1,y1,size1) + self:setPosition(x1,y1,size1) end end end local function checkPlayer(obj,Ptar) return obj.args[1]==Ptar end -function Player.movePosition(P,x,y,size) - TASK.removeTask_iterate(checkPlayer,P) - TASK.new(task_movePosition,P,x,y,size or P.size) +function Player:movePosition(x,y,size) + TASK.removeTask_iterate(checkPlayer,self) + TASK.new(task_movePosition,self,x,y,size or self.size) end -function Player.switchKey(P,id,on) - P.keyAvailable[id]=on +function Player:switchKey(id,on) + self.keyAvailable[id]=on if not on then - P:releaseKey(id) + self:releaseKey(id) end - if P.type=="human"then + if self.type=="human"then virtualkey[id].ava=on end end -function Player.set20G(P,if20g) - P._20G=if20g - P:switchKey(7,not if20g) - if if20g and P.AI_mode=="CC"then CC.switch20G(P)end +function Player:set20G(if20g) + self._20G=if20g + self:switchKey(7,not if20g) + if if20g and self.AI_mode=="CC"then CC.switch20G(self)end end -function Player.setHold(P,count)--Set hold count (false/true as 0/1) +function Player:setHold(count)--Set hold count (false/true as 0/1) if not count then count=0 elseif count==true then count=1 end - P.gameEnv.holdCount=count - P.holdTime=count - while P.holdQueue[count+1]do rem(P.holdQueue)end + self.gameEnv.holdCount=count + self.holdTime=count + while self.holdQueue[count+1]do rem(self.holdQueue)end end -function Player.setNext(P,next,hidden)--Set next count (use hidden=true if set env.nextStartPos>1) - P.gameEnv.nextCount=next +function Player:setNext(next,hidden)--Set next count (use hidden=true if set env.nextStartPos>1) + self.gameEnv.nextCount=next if next==0 then - P.drawNext=NULL + self.drawNext=NULL elseif not hidden then - P.drawNext=PLY.draw.drawNext_norm + self.drawNext=PLY.draw.drawNext_norm else - P.drawNext=PLY.draw.drawNext_hidden + self.drawNext=PLY.draw.drawNext_hidden end end -function Player.setInvisible(P,time)--Time in frames +function Player:setInvisible(time)--Time in frames if time<0 then - P.keepVisible=true - P.showTime=1e99 + self.keepVisible=true + self.showTime=1e99 else - P.keepVisible=false - P.showTime=time + self.keepVisible=false + self.showTime=time end end -function Player.setRS(P,RSname) - P.RS=kickList[RSname] +function Player:setRS(RSname) + self.RS=kickList[RSname] end -function Player.setConf(P,confStr) +function Player:setConf(confStr) local _,conf=pcall(love.data.decode,"string","base64",confStr) if _ then for k,v in next,conf do if not GAME.modeEnv[k]then - P.gameEnv[k]=v + self.gameEnv[k]=v end end else - LOG.print("Bad conf from "..P.userName.."#"..P.userID) + LOG.print("Bad conf from "..self.userName.."#"..self.userID) end end -function Player.getHolePos(P)--Get a good garbage-line hole position - if P.garbageBeneath==0 then - return generateLine(P:RND(10)) +function Player:getHolePos()--Get a good garbage-line hole position + if self.garbageBeneath==0 then + return generateLine(self:RND(10)) else - local p=P:RND(10) - if P.field[1][p]<=0 then - return generateLine(P:RND(10)) + local p=self:RND(10) + if self.field[1][p]<=0 then + return generateLine(self:RND(10)) end return generateLine(p) end end -function Player.garbageRelease(P)--Check garbage buffer and try to release them +function Player:garbageRelease()--Check garbage buffer and try to release them local n,flag=1 while true do - local A=P.atkBuffer[n] + local A=self.atkBuffer[n] if A and A.countdown<=0 and not A.sent then - P:garbageRise(19+A.lv,A.amount,A.line) - P.atkBuffer.sum=P.atkBuffer.sum-A.amount + self:garbageRise(19+A.lv,A.amount,A.line) + self.atkBuffer.sum=self.atkBuffer.sum-A.amount A.sent,A.time=true,0 - P.stat.pend=P.stat.pend+A.amount + self.stat.pend=self.stat.pend+A.amount n=n+1 flag=true else break end end - if flag and P.AI_mode=="CC"and P.AI_bot then CC.updateField(P)end + if flag and self.AI_mode=="CC"and self.AI_bot then CC.updateField(self)end end -function Player.garbageRise(P,color,amount,line)--Release n-lines garbage to field +function Player:garbageRise(color,amount,line)--Release n-lines garbage to field local _ - local t=P.showTime*2 + local t=self.showTime*2 for _=1,amount do - ins(P.field,1,FREEROW.get(0,true)) - ins(P.visTime,1,FREEROW.get(t)) + ins(self.field,1,FREEROW.get(0,true)) + ins(self.visTime,1,FREEROW.get(t)) for i=1,10 do - P.field[1][i]=bit.rshift(line,i-1)%2==1 and color or 0 + self.field[1][i]=bit.rshift(line,i-1)%2==1 and color or 0 end end - P.fieldBeneath=P.fieldBeneath+amount*30 - if P.cur then - P.curY=P.curY+amount - P.ghoY=P.ghoY+amount + self.fieldBeneath=self.fieldBeneath+amount*30 + if self.cur then + self.curY=self.curY+amount + self.ghoY=self.ghoY+amount end - P.garbageBeneath=P.garbageBeneath+amount - for i=1,#P.clearingRow do - P.clearingRow[i]=P.clearingRow[i]+amount + self.garbageBeneath=self.garbageBeneath+amount + for i=1,#self.clearingRow do + self.clearingRow[i]=self.clearingRow[i]+amount end - P:freshBlock("push") - for i=1,#P.lockFX do - _=P.lockFX[i] + self:freshBlock("push") + for i=1,#self.lockFX do + _=self.lockFX[i] _[2]=_[2]-30*amount--Shift 30px per line cleared end - for i=1,#P.dropFX do - _=P.dropFX[i] + for i=1,#self.dropFX do + _=self.dropFX[i] _[3],_[5]=_[3]+amount,_[5]+amount end - if #P.field>42 then P:lose()end + if #self.field>42 then self:lose()end end local invList={2,1,4,3,5,6,7} -function Player.pushLineList(P,L,mir)--Push some lines to field +function Player:pushLineList(L,mir)--Push some lines to field local l=#L - local S=P.gameEnv.skin + local S=self.gameEnv.skin for i=1,l do local r=FREEROW.get(0) if not mir then @@ -301,44 +300,44 @@ function Player.pushLineList(P,L,mir)--Push some lines to field r[j]=S[invList[L[i][11-j]]]or 0 end end - ins(P.field,1,r) - ins(P.visTime,1,FREEROW.get(20)) + ins(self.field,1,r) + ins(self.visTime,1,FREEROW.get(20)) end - P.fieldBeneath=P.fieldBeneath+30*l - P.curY=P.curY+l - P.ghoY=P.ghoY+l - P:freshBlock("push") + self.fieldBeneath=self.fieldBeneath+30*l + self.curY=self.curY+l + self.ghoY=self.ghoY+l + self:freshBlock("push") end -function Player.pushNextList(P,L,mir)--Push some nexts to nextQueue +function Player:pushNextList(L,mir)--Push some nexts to nextQueue for i=1,#L do - P:getNext(mir and invList[L[i]]or L[i]) + self:getNext(mir and invList[L[i]]or L[i]) end end -function Player.getCenterX(P) - return P.curX+P.cur.sc[2]-5.5 +function Player:getCenterX() + return self.curX+self.cur.sc[2]-5.5 end -function Player.solid(P,x,y) +function Player:solid(x,y) if x<1 or x>10 or y<1 then return true end - if y>#P.field then return false end - return P.field[y] + if y>#self.field then return false end + return self.field[y] [x]>0--to catch bug (nil[*]) end -function Player.ifoverlap(P,bk,x,y) +function Player:ifoverlap(bk,x,y) local C=#bk[1] if x<1 or x+C>11 or y<1 then return true end - if y>#P.field then return end + if y>#self.field then return end for i=1,#bk do - if P.field[y+i-1]then + if self.field[y+i-1]then for j=1,C do - if bk[i][j]and P.field[y+i-1][x+j-1]>0 then return true end + if bk[i][j]and self.field[y+i-1][x+j-1]>0 then return true end end end end end -function Player.attack(P,R,send,time,line,fromStream) +function Player:attack(R,send,time,line,fromStream) if GAME.net then - if P.type=="human"then--Local player attack others + if self.type=="human"then--Local player attack others ins(GAME.rep,GAME.frame) ins(GAME.rep, R.subID+ @@ -351,21 +350,21 @@ function Player.attack(P,R,send,time,line,fromStream) if fromStream and R.type=="human"then--Local player receiving lines ins(GAME.rep,GAME.frame) ins(GAME.rep, - P.subID+ + self.subID+ send*0x100+ time*0x10000+ line*0x100000000+ 0x1000000000000 ) - R:receive(P,send,time,line) + R:receive(self,send,time,line) end else - R:receive(P,send,time,line) + R:receive(self,send,time,line) end end -function Player.receive(P,A,send,time,line) - P.lastRecv=A - local B=P.atkBuffer +function Player:receive(A,send,time,line) + self.lastRecv=A + local B=self.atkBuffer if B.sum<26 then if send>26-B.sum then send=26-B.sum end local m,k=#B,1 @@ -383,91 +382,91 @@ function Player.receive(P,A,send,time,line) lv=min(int(send^.69),5), }--Sorted insert(by time) B.sum=B.sum+send - P.stat.recv=P.stat.recv+send - if P.sound then + self.stat.recv=self.stat.recv+send + if self.sound then SFX.play(send<4 and"blip_1"or"blip_2",min(send+1,5)*.1) end end end -function Player.freshTarget(P) - if P.atkMode==1 then - if not P.atking or not P.atking.alive or rnd()<.1 then - P:changeAtk(randomTarget(P)) +function Player:freshTarget() + if self.atkMode==1 then + if not self.atking or not self.atking.alive or rnd()<.1 then + self:changeAtk(randomTarget(self)) end - elseif P.atkMode==2 then - P:changeAtk(P~=GAME.mostBadge and GAME.mostBadge or GAME.secBadge or randomTarget(P)) - elseif P.atkMode==3 then - P:changeAtk(P~=GAME.mostDangerous and GAME.mostDangerous or GAME.secDangerous or randomTarget(P)) - elseif P.atkMode==4 then - for i=1,#P.atker do - if not P.atker[i].alive then - rem(P.atker,i) + elseif self.atkMode==2 then + self:changeAtk(self~=GAME.mostBadge and GAME.mostBadge or GAME.secBadge or randomTarget(self)) + elseif self.atkMode==3 then + self:changeAtk(self~=GAME.mostDangerous and GAME.mostDangerous or GAME.secDangerous or randomTarget(self)) + elseif self.atkMode==4 then + for i=1,#self.atker do + if not self.atker[i].alive then + rem(self.atker,i) return end end end end -function Player.changeAtkMode(P,m) - if P.atkMode==m then return end - P.atkMode=m +function Player:changeAtkMode(m) + if self.atkMode==m then return end + self.atkMode=m if m==1 then - P:changeAtk(randomTarget(P)) + self:changeAtk(randomTarget(self)) elseif m==2 or m==3 then - P:freshTarget() + self:freshTarget() elseif m==4 then - P:changeAtk() + self:changeAtk() end end -function Player.changeAtk(P,R) - -- if P.type~="human"then R=PLAYERS[1]end--1vALL mode? - if P.atking then - local K=P.atking.atker +function Player:changeAtk(R) + -- if self.type~="human"then R=PLAYERS[1]end--1vALL mode? + if self.atking then + local K=self.atking.atker for i=1,#K do - if K[i]==P then + if K[i]==self then rem(K,i) break end end end if R then - P.atking=R - ins(R.atker,P) + self.atking=R + ins(R.atker,self) else - P.atking=false + self.atking=false end end -function Player.freshBlock(P,mode)--string mode: push/move/fresh/newBlock - local ENV=P.gameEnv +function Player:freshBlock(mode)--string mode: push/move/fresh/newBlock + local ENV=self.gameEnv --Fresh ghost - if(mode=="move"or mode=="newBlock"or mode=="push")and P.cur then - local CB=P.cur.bk - P.ghoY=min(#P.field+1,P.curY) - if P._20G or ENV.sdarr==0 and P.keyPressing[7]and P.downing>ENV.sddas then - local _=P.ghoY + if(mode=="move"or mode=="newBlock"or mode=="push")and self.cur then + local CB=self.cur.bk + self.ghoY=min(#self.field+1,self.curY) + if self._20G or ENV.sdarr==0 and self.keyPressing[7]and self.downing>ENV.sddas then + local _=self.ghoY --Move ghost to bottom - while not P:ifoverlap(CB,P.curX,P.ghoY-1)do - P.ghoY=P.ghoY-1 + while not self:ifoverlap(CB,self.curX,self.ghoY-1)do + self.ghoY=self.ghoY-1 end --Cancel spinLast - if _~=P.ghoY then - P.spinLast=false + if _~=self.ghoY then + self.spinLast=false end --Create FX if dropped - if P.curY>P.ghoY then - if ENV.dropFX and ENV.block and P.curY-P.ghoY-#CB>-1 then - P:createDropFX(P.curX,P.curY-1,#CB[1],P.curY-P.ghoY-#CB+1) + if self.curY>self.ghoY then + if ENV.dropFX and ENV.block and self.curY-self.ghoY-#CB>-1 then + self:createDropFX(self.curX,self.curY-1,#CB[1],self.curY-self.ghoY-#CB+1) end if ENV.shakeFX then - P.fieldOff.vy=ENV.shakeFX*.5 + self.fieldOff.vy=ENV.shakeFX*.5 end - P.curY=P.ghoY + self.curY=self.ghoY end else - while not P:ifoverlap(CB,P.curX,P.ghoY-1)do - P.ghoY=P.ghoY-1 + while not self:ifoverlap(CB,self.curX,self.ghoY-1)do + self.ghoY=self.ghoY-1 end end end @@ -476,43 +475,43 @@ function Player.freshBlock(P,mode)--string mode: push/move/fresh/newBlock if mode=="move"or mode=="newBlock"or mode=="fresh"then local d0,l0=ENV.drop,ENV.lock if ENV.easyFresh then - if P.lockDelay0 then + if self.lockDelay0 then if mode~="newBlock"then - P.freshTime=P.freshTime-1 + self.freshTime=self.freshTime-1 end - P.lockDelay=l0 - P.dropDelay=d0 + self.lockDelay=l0 + self.dropDelay=d0 end - if P.curY+P.cur.sc[1]0 then - P.freshTime=P.freshTime-1 - P.dropDelay=d0 - P.lockDelay=l0 + if self.curY+self.cur.sc[1]0 then + self.freshTime=self.freshTime-1 + self.dropDelay=d0 + self.lockDelay=l0 end end end end end -function Player.lock(P) - local dest=P.AI_dest +function Player:lock() + local dest=self.AI_dest local has_dest=dest~=nil - local CB=P.cur.bk + local CB=self.cur.bk for i=1,#CB do - local y=P.curY+i-1 - if not P.field[y]then P.field[y],P.visTime[y]=FREEROW.get(0),FREEROW.get(0)end + local y=self.curY+i-1 + if not self.field[y]then self.field[y],self.visTime[y]=FREEROW.get(0),FREEROW.get(0)end for j=1,#CB[1]do if CB[i][j]then - P.field[y][P.curX+j-1]=P.cur.color - P.visTime[y][P.curX+j-1]=P.showTime + self.field[y][self.curX+j-1]=self.cur.color + self.visTime[y][self.curX+j-1]=self.showTime if dest then - local x=P.curX+j-1 + local x=self.curX+j-1 for k=1,#dest,2 do if x==dest[k]+1 and y==dest[k+1]+1 then rem(dest,k)rem(dest,k) @@ -525,142 +524,142 @@ function Player.lock(P) end end end - if has_dest and not dest and P.AI_mode=="CC"and P.AI_bot then - CC.updateField(P) + if has_dest and not dest and self.AI_mode=="CC"and self.AI_bot then + CC.updateField(self) end end local spawnSFX_name={}for i=1,7 do spawnSFX_name[i]="spawn_"..i end -function Player.resetBlock(P)--Reset Block's position and execute I*S - local B=P.cur.bk - P.curX=int(6-#B[1]*.5) - local y=int(P.gameEnv.fieldH+1-modf(P.cur.sc[1]))+ceil(P.fieldBeneath/30) - P.curY=y - P.minY=y+P.cur.sc[1] +function Player:resetBlock()--Reset Block's position and execute I*S + local B=self.cur.bk + self.curX=int(6-#B[1]*.5) + local y=int(self.gameEnv.fieldH+1-modf(self.cur.sc[1]))+ceil(self.fieldBeneath/30) + self.curY=y + self.minY=y+self.cur.sc[1] - local _=P.keyPressing + local _=self.keyPressing --IMS - if P.gameEnv.ims and(_[1]and P.movDir==-1 or _[2]and P.movDir==1)and P.moving>=P.gameEnv.das then - local x=P.curX+P.movDir - if not P:ifoverlap(B,x,y)then - P.curX=x + if self.gameEnv.ims and(_[1]and self.movDir==-1 or _[2]and self.movDir==1)and self.moving>=self.gameEnv.das then + local x=self.curX+self.movDir + if not self:ifoverlap(B,x,y)then + self.curX=x end end --IRS - if P.gameEnv.irs then + if self.gameEnv.irs then if _[5]then - P:spin(2,true) + self:spin(2,true) else if _[3]then if _[4]then - P:spin(2,true) + self:spin(2,true) else - P:spin(1,true) + self:spin(1,true) end elseif _[4]then - P:spin(3,true) + self:spin(3,true) end end end --DAS cut - if P.gameEnv.dascut>0 then - P.moving=P.moving-(P.moving>0 and 1 or -1)*P.gameEnv.dascut + if self.gameEnv.dascut>0 then + self.moving=self.moving-(self.moving>0 and 1 or -1)*self.gameEnv.dascut end --Spawn SFX - if P.sound and P.cur.id<8 then - SFX.fplay(spawnSFX_name[P.cur.id],SETTING.sfx_spawn) + if self.sound and self.cur.id<8 then + SFX.fplay(spawnSFX_name[self.cur.id],SETTING.sfx_spawn) end end -function Player.spin(P,d,ifpre) - local kickData=P.RS[P.cur.id] +function Player:spin(d,ifpre) + local kickData=self.RS[self.cur.id] if type(kickData)=="table"then - local idir=(P.cur.dir+d)%4 - kickData=kickData[P.cur.dir*10+idir] + local idir=(self.cur.dir+d)%4 + kickData=kickData[self.cur.dir*10+idir] if not kickData then - P:freshBlock("move") - SFX.play(ifpre and"prerotate"or"rotate",nil,P:getCenterX()*.15) + self:freshBlock("move") + SFX.play(ifpre and"prerotate"or"rotate",nil,self:getCenterX()*.15) return end - local icb=BLOCKS[P.cur.id][idir] - local isc=SCS[P.cur.id][idir] - local ix,iy=P.curX+P.cur.sc[2]-isc[2],P.curY+P.cur.sc[1]-isc[1] + local icb=BLOCKS[self.cur.id][idir] + local isc=SCS[self.cur.id][idir] + local ix,iy=self.curX+self.cur.sc[2]-isc[2],self.curY+self.cur.sc[1]-isc[1] for test=1,#kickData do local x,y=ix+kickData[test][1],iy+kickData[test][2] - if not P:ifoverlap(icb,x,y)and(P.freshTime>=0 or kickData[test][2]<0)then + if not self:ifoverlap(icb,x,y)and(self.freshTime>=0 or kickData[test][2]<0)then ix,iy=x,y - if P.gameEnv.moveFX and P.gameEnv.block then - P:createMoveFX() + if self.gameEnv.moveFX and self.gameEnv.block then + self:createMoveFX() end - P.curX,P.curY,P.cur.dir=ix,iy,idir - P.cur.sc,P.cur.bk=isc,icb - P.spinLast=test==2 and 0 or 1 + self.curX,self.curY,self.cur.dir=ix,iy,idir + self.cur.sc,self.cur.bk=isc,icb + self.spinLast=test==2 and 0 or 1 - local t=P.freshTime + local t=self.freshTime if not ifpre then - P:freshBlock("move") + self:freshBlock("move") end - if kickData[test][2]>0 and P.freshTime~=t and P.curY~=P.imgY then - P.freshTime=P.freshTime-1 + if kickData[test][2]>0 and self.freshTime~=t and self.curY~=self.imgY then + self.freshTime=self.freshTime-1 end - if P.sound then + if self.sound then local sfx if ifpre then sfx="prerotate" - elseif P:ifoverlap(icb,ix,iy+1)and P:ifoverlap(icb,ix-1,iy)and P:ifoverlap(icb,ix+1,iy)then + elseif self:ifoverlap(icb,ix,iy+1)and self:ifoverlap(icb,ix-1,iy)and self:ifoverlap(icb,ix+1,iy)then sfx="rotatekick" - if P.gameEnv.shakeFX then + if self.gameEnv.shakeFX then if d==1 or d==3 then - P.fieldOff.va=P.fieldOff.va+(2-d)*P.gameEnv.shakeFX*6e-3 + self.fieldOff.va=self.fieldOff.va+(2-d)*self.gameEnv.shakeFX*6e-3 else - P.fieldOff.va=P.fieldOff.va+P:getCenterX()*P.gameEnv.shakeFX*3e-3 + self.fieldOff.va=self.fieldOff.va+self:getCenterX()*self.gameEnv.shakeFX*3e-3 end end else sfx="rotate" end - SFX.play(sfx,nil,P:getCenterX()*.15) + SFX.play(sfx,nil,self:getCenterX()*.15) end - P.stat.rotate=P.stat.rotate+1 + self.stat.rotate=self.stat.rotate+1 return end end elseif kickData then - kickData(P,d) + kickData(self,d) else - P:freshBlock("move") - SFX.play(ifpre and"prerotate"or"rotate",nil,P:getCenterX()*.15) + self:freshBlock("move") + SFX.play(ifpre and"prerotate"or"rotate",nil,self:getCenterX()*.15) end end local phyHoldKickX={ [true]={0,-1,1},--X==?.0 tests [false]={-.5,.5},--X==?.5 tests } -function Player.hold(P,ifpre) - local ENV=P.gameEnv - if P.holdTime>0 and(ifpre or P.waiting==-1)then - if #P.holdQueue0 and(ifpre or self.waiting==-1)then + if #self.holdQueue ::BREAK_success:: - P.spinLast=false - P.spinSeq=0 - local hb=P:getBlock(C.id) + self.spinLast=false + self.spinSeq=0 + local hb=self:getBlock(C.id) hb.name=C.name hb.color=C.color - ins(P.holdQueue,hb) - P.cur=rem(P.holdQueue,1) - P.curX,P.curY=x,y + ins(self.holdQueue,hb) + self.cur=rem(self.holdQueue,1) + self.curX,self.curY=x,y else--Normal hold - P.spinLast=false - P.spinSeq=0 + self.spinLast=false + self.spinSeq=0 if C then - local hb=P:getBlock(C.id) + local hb=self:getBlock(C.id) hb.color=C.color hb.name=C.name - ins(P.holdQueue,hb) + ins(self.holdQueue,hb) end - P.cur=rem(P.holdQueue,1) + self.cur=rem(self.holdQueue,1) - P:resetBlock() + self:resetBlock() end - P:freshBlock("move") - P.dropDelay=ENV.drop - P.lockDelay=ENV.lock - if P:ifoverlap(P.cur.bk,P.curX,P.curY)then - P:lock() - P:lose() + self:freshBlock("move") + self.dropDelay=ENV.drop + self.lockDelay=ENV.lock + if self:ifoverlap(self.cur.bk,self.curX,self.curY)then + self:lock() + self:lose() end end - P.freshTime=int(min(P.freshTime+ENV.freshLimit*.25,ENV.freshLimit*((P.holdTime+1)/ENV.holdCount))) + self.freshTime=int(min(self.freshTime+ENV.freshLimit*.25,ENV.freshLimit*((self.holdTime+1)/ENV.holdCount))) if not ENV.infHold then - P.holdTime=P.holdTime-1 + self.holdTime=self.holdTime-1 end - if P.sound then + if self.sound then SFX.play(ifpre and"prehold"or"hold") end - if P.AI_mode=="CC"then - local next=P.nextQueue[P.AIdata.nextCount] + if self.AI_mode=="CC"then + local next=self.nextQueue[self.AIdata.nextCount] if next then - CC.addNext(P.AI_bot,next.id) + CC.addNext(self.AI_bot,next.id) end end - P.stat.hold=P.stat.hold+1 + self.stat.hold=self.stat.hold+1 end end -function Player.getBlock(P,n)--Get a block(id=n) object - local E=P.gameEnv +function Player:getBlock(n)--Get a block(id=n) object + local E=self.gameEnv local dir=E.face[n] return{ id=n, @@ -743,10 +742,10 @@ function Player.getBlock(P,n)--Get a block(id=n) object color=E.bone and 17 or E.skin[n], } end -function Player.getNext(P,n)--Push a block(id=n) to nextQueue - local E=P.gameEnv +function Player:getNext(n)--Push a block(id=n) to nextQueue + local E=self.gameEnv local dir=E.face[n] - ins(P.nextQueue,{ + ins(self.nextQueue,{ id=n, bk=BLOCKS[n][dir], sc=SCS[n][dir], @@ -755,60 +754,60 @@ function Player.getNext(P,n)--Push a block(id=n) to nextQueue color=E.bone and 17 or E.skin[n], }) end -function Player.popNext(P,ifhold)--Pop nextQueue to hand +function Player:popNext(ifhold)--Pop nextQueue to hand if not ifhold then - P.holdTime=min(P.holdTime+1,P.gameEnv.holdCount) + self.holdTime=min(self.holdTime+1,self.gameEnv.holdCount) end - P.spinLast=false - P.spinSeq=0 - P.ctrlCount=0 + self.spinLast=false + self.spinSeq=0 + self.ctrlCount=0 - P.cur=rem(P.nextQueue,1) - assert(resume(P.newNext)) - if P.cur then - P.pieceCount=P.pieceCount+1 - if P.AI_mode=="CC"then - local next=P.nextQueue[P.AIdata.next] + self.cur=rem(self.nextQueue,1) + assert(resume(self.newNext)) + if self.cur then + self.pieceCount=self.pieceCount+1 + if self.AI_mode=="CC"then + local next=self.nextQueue[self.AIdata.next] if next then - CC.addNext(P.AI_bot,next.id) + CC.addNext(self.AI_bot,next.id) end end - local _=P.keyPressing + local _=self.keyPressing --IHS - if not ifhold and _[8]and P.gameEnv.ihs then - P:hold(true) + if not ifhold and _[8]and self.gameEnv.ihs then + self:hold(true) _[8]=false else - P:resetBlock() + self:resetBlock() end - P.dropDelay=P.gameEnv.drop - P.lockDelay=P.gameEnv.lock - P.freshTime=P.gameEnv.freshLimit + self.dropDelay=self.gameEnv.drop + self.lockDelay=self.gameEnv.lock + self.freshTime=self.gameEnv.freshLimit - if P.cur then - if P:ifoverlap(P.cur.bk,P.curX,P.curY)then - P:lock() - P:lose() + if self.cur then + if self:ifoverlap(self.cur.bk,self.curX,self.curY)then + self:lock() + self:lose() end - P:freshBlock("newBlock") + self:freshBlock("newBlock") end --IHdS if _[6]and not ifhold then - P.act_hardDrop(P) + self.act_hardDrop(self) _[6]=false end else - P:hold() + self:hold() end end -function Player.cancel(P,N)--Cancel Garbage +function Player:cancel(N)--Cancel Garbage local off=0--Lines offseted - local bf=P.atkBuffer + local bf=self.atkBuffer for i=1,#bf do if bf.sum==0 or N==0 then break end local A=bf[i] @@ -826,7 +825,7 @@ function Player.cancel(P,N)--Cancel Garbage end return off end -do--Player.drop(P)--Place piece +do--Player.drop(self)--Place piece local clearSCR={80,200,400}--Techrash:1K; B2Bmul:1.3/1.8 local spinSCR={ {200,750,1300,2000},--Z @@ -879,7 +878,7 @@ do--Player.drop(P)--Place piece 1,2 },--Z5 8,--S5 - 3,--P + 3,--self 3,--Q { {1,2,1,0,1,2,2,1}, @@ -950,17 +949,17 @@ do--Player.drop(P)--Place piece end end - function Player.drop(P) + function Player:drop() local _ local CHN=VOC.getFreeChannel() - P.dropTime[11]=ins(P.dropTime,1,GAME.frame)--Update speed dial - local ENV=P.gameEnv - local STAT=P.stat - local piece=P.lastPiece + self.dropTime[11]=ins(self.dropTime,1,GAME.frame)--Update speed dial + local ENV=self.gameEnv + local STAT=self.stat + local piece=self.lastPiece local finish - local cmb=P.combo - local C,CB,CX,CY=P.cur,P.cur.bk,P.curX,P.curY + local cmb=self.combo + local C,CB,CX,CY=self.cur,self.cur.bk,self.curX,self.curY local clear--If clear with no line fall local cc,gbcc=0,0--Row/garbage-row cleared,full-part local atk,exblock=0,0--Attack & extra defense @@ -969,44 +968,44 @@ do--Player.drop(P)--Place piece local dospin,mini=0 piece.id,piece.name=C.id,C.name - P.waiting=ENV.wait + self.waiting=ENV.wait --Tri-corner spin check - if P.spinLast then + if self.spinLast then if C.id<6 then - local x,y=CX+P.cur.sc[2],CY+P.cur.sc[1] + local x,y=CX+self.cur.sc[2],CY+self.cur.sc[1] local c=0 - if P:solid(x-1,y+1)then c=c+1 end - if P:solid(x+1,y+1)then c=c+1 end + if self:solid(x-1,y+1)then c=c+1 end + if self:solid(x+1,y+1)then c=c+1 end if c~=0 then - if P:solid(x-1,y-1)then c=c+1 end - if P:solid(x+1,y-1)then c=c+1 end + if self:solid(x-1,y-1)then c=c+1 end + if self:solid(x+1,y-1)then c=c+1 end if c>2 then dospin=dospin+2 end end end end --Immovable spin check - if P:ifoverlap(CB,CX,CY+1)and P:ifoverlap(CB,CX-1,CY)and P:ifoverlap(CB,CX+1,CY)then + if self:ifoverlap(CB,CX,CY+1)and self:ifoverlap(CB,CX-1,CY)and self:ifoverlap(CB,CX+1,CY)then dospin=dospin+2 end --Lock block to field - P:lock() + self:lock() --Clear list of cleared-rows - if P.clearedRow[1]then P.clearedRow={}end + if self.clearedRow[1]then self.clearedRow={}end --Check line clear for i=1,#CB do local h=CY+i-2 --Bomb trigger - if h>0 and P.field[h]and P.clearedRow[cc]~=h then + if h>0 and self.field[h]and self.clearedRow[cc]~=h then for x=1,#CB[1]do - if CB[i][x]and P.field[h][CX+x-1]==19 then + if CB[i][x]and self.field[h][CX+x-1]==19 then cc=cc+1 - P.clearingRow[cc]=h-cc+1 - P.clearedRow[cc]=h + self.clearingRow[cc]=h-cc+1 + self.clearedRow[cc]=h break end end @@ -1015,13 +1014,13 @@ do--Player.drop(P)--Place piece h=h+1 --Row filled for x=1,10 do - if P.field[h][x]<=0 then + if self.field[h][x]<=0 then goto CONTINUE_notFull end end cc=cc+1 - P.clearingRow[cc]=h-cc+1 - P.clearedRow[cc]=h + self.clearingRow[cc]=h-cc+1 + self.clearedRow[cc]=h ::CONTINUE_notFull:: end @@ -1029,10 +1028,10 @@ do--Player.drop(P)--Place piece if cc>0 and ENV.clearFX then local t=7-ENV.clearFX*1 for i=1,cc do - local y=P.clearedRow[i] - P:createClearingFX(y,t) + local y=self.clearedRow[i] + self:createClearingFX(y,t) if ENV.splashFX then - P:createSplashFX(y) + self:createSplashFX(y) end end end @@ -1040,12 +1039,12 @@ do--Player.drop(P)--Place piece --Create locking FX if ENV.lockFX then if cc==0 then - P:createLockFX() + self:createLockFX() else - _=#P.lockFX + _=#self.lockFX if _>0 then for _=1,_ do - rem(P.lockFX) + rem(self.lockFX) end end end @@ -1054,7 +1053,7 @@ do--Player.drop(P)--Place piece --Final spin check if dospin>0 then if cc>0 then - dospin=dospin+(P.spinLast or 0) + dospin=dospin+(self.spinLast or 0) if dospin<3 then mini=C.id<6 and cc<#CB end @@ -1077,8 +1076,8 @@ do--Player.drop(P)--Place piece local testX=CX+x-1--Optimize --Test the whole column of field to find roof - for testY=CY+y,#P.field do - if P:solid(testX,testY)then + for testY=CY+y,#self.field do + if self:solid(testX,testY)then finesse=true goto BERAK_roofFound end @@ -1090,24 +1089,24 @@ do--Player.drop(P)--Place piece --Remove rows need to be cleared if cc>0 then for i=cc,1,-1 do - _=P.clearedRow[i] - if P.field[_].garbage then - P.garbageBeneath=P.garbageBeneath-1 + _=self.clearedRow[i] + if self.field[_].garbage then + self.garbageBeneath=self.garbageBeneath-1 gbcc=gbcc+1 end - FREEROW.discard(rem(P.field,_)) - FREEROW.discard(rem(P.visTime,_)) + FREEROW.discard(rem(self.field,_)) + FREEROW.discard(rem(self.visTime,_)) end end --Cancel no-sense clearing FX - _=#P.clearingRow - while _>0 and P.clearingRow[_]>#P.field do - P.clearingRow[_]=nil + _=#self.clearingRow + while _>0 and self.clearingRow[_]>#self.field do + self.clearingRow[_]=nil _=_-1 end - if P.clearingRow[1]then - P.falling=ENV.fall + if self.clearingRow[1]then + self.falling=ENV.fall elseif cc>=#C.bk then clear=true end @@ -1115,9 +1114,9 @@ do--Player.drop(P)--Place piece --Finesse check (control) local finePts if not finesse then - if dospin then P.ctrlCount=P.ctrlCount-2 end--Allow 2 more step for roof-less spin + if dospin then self.ctrlCount=self.ctrlCount-2 end--Allow 2 more step for roof-less spin local id=C.id - local d=P.ctrlCount-finesseList[id][P.cur.dir+1][CX] + local d=self.ctrlCount-finesseList[id][self.cur.dir+1][CX] finePts=d<=0 and 5 or max(3-d,0) else finePts=5 @@ -1130,25 +1129,25 @@ do--Player.drop(P)--Place piece if ENV.fineKill then finish=true end - if P.sound then + if self.sound then if ENV.fineKill then SFX.play("finesseError_long",.6) elseif ENV.fine then SFX.play("finesseError",.8) else - SFX.play("lock",nil,P:getCenterX()*.15) + SFX.play("lock",nil,self:getCenterX()*.15) end end - elseif P.sound then - SFX.play("lock",nil,P:getCenterX()*.15) + elseif self.sound then + SFX.play("lock",nil,self:getCenterX()*.15) end if finePts<=1 then - P.finesseCombo=0 + self.finesseCombo=0 else - P.finesseCombo=P.finesseCombo+1 - if P.finesseCombo>2 then - P.finesseComboTime=12 + self.finesseCombo=self.finesseCombo+1 + if self.finesseCombo>2 then + self.finesseComboTime=12 end end @@ -1159,88 +1158,88 @@ do--Player.drop(P)--Place piece cmb=cmb+1 if dospin then cscore=(spinSCR[C.name]or spinSCR[8])[cc] - if P.b2b>800 then - P:showText(text.b3b..text.block[C.name]..text.spin.." "..text.clear[cc],0,-30,35,"stretch") + if self.b2b>800 then + self:showText(text.b3b..text.block[C.name]..text.spin.." "..text.clear[cc],0,-30,35,"stretch") atk=b2bATK[cc]+cc*.5 exblock=exblock+1 cscore=cscore*2 STAT.b3b=STAT.b3b+1 - if P.sound then + if self.sound then VOC.play("b3b",CHN) end - elseif P.b2b>=50 then - P:showText(text.b2b..text.block[C.name]..text.spin.." "..text.clear[cc],0,-30,35,"spin") + elseif self.b2b>=50 then + self:showText(text.b2b..text.block[C.name]..text.spin.." "..text.clear[cc],0,-30,35,"spin") atk=b2bATK[cc] cscore=cscore*1.2 STAT.b2b=STAT.b2b+1 - if P.sound then + if self.sound then VOC.play("b2b",CHN) end else - P:showText(text.block[C.name]..text.spin.." "..text.clear[cc],0,-30,45,"spin") + self:showText(text.block[C.name]..text.spin.." "..text.clear[cc],0,-30,45,"spin") atk=2*cc end sendTime=20+atk*20 if mini then - P:showText(text.mini,0,-80,35,"appear") + self:showText(text.mini,0,-80,35,"appear") atk=atk*.25 sendTime=sendTime+60 cscore=cscore*.5 - P.b2b=P.b2b+b2bPoint[cc]*.5 - if P.sound then + self.b2b=self.b2b+b2bPoint[cc]*.5 + if self.sound then VOC.play("mini",CHN) end else - P.b2b=P.b2b+b2bPoint[cc] + self.b2b=self.b2b+b2bPoint[cc] end piece.mini=mini piece.special=true - if P.sound then + if self.sound then SFX.play(spinSFX[cc]or"spin_3") VOC.play(spinVoice[C.name],CHN) end elseif cc>=4 then cscore=cc==4 and 1000 or cc==5 and 1500 or 2000 - if P.b2b>800 then - P:showText(text.b3b..text.clear[cc],0,-30,50,"fly") + if self.b2b>800 then + self:showText(text.b3b..text.clear[cc],0,-30,50,"fly") atk=4*cc-10 sendTime=100 exblock=exblock+1 cscore=cscore*1.8 STAT.b3b=STAT.b3b+1 - if P.sound then + if self.sound then VOC.play("b3b",CHN) end - elseif P.b2b>=50 then - P:showText(text.b2b..text.clear[cc],0,-30,50,"drive") + elseif self.b2b>=50 then + self:showText(text.b2b..text.clear[cc],0,-30,50,"drive") sendTime=80 atk=3*cc-7 cscore=cscore*1.3 STAT.b2b=STAT.b2b+1 - if P.sound then + if self.sound then VOC.play("b2b",CHN) end else - P:showText(text.clear[cc],0,-30,70,"stretch") + self:showText(text.clear[cc],0,-30,70,"stretch") sendTime=60 atk=2*cc-4 end - P.b2b=P.b2b+cc*100-300 + self.b2b=self.b2b+cc*100-300 piece.special=true else piece.special=false end - if P.sound then + if self.sound then VOC.play(clearVoice[cc],CHN) end --Normal clear,reduce B2B point if not piece.special then - P.b2b=max(P.b2b-250,0) - if P.b2b<50 and ENV.b2bKill then + self.b2b=max(self.b2b-250,0) + if self.b2b<50 and ENV.b2bKill then finish=true end - P:showText(text.clear[cc],0,-30,35,"appear",(8-cc)*.3) + self:showText(text.clear[cc],0,-30,35,"appear",(8-cc)*.3) atk=cc-.5 sendTime=20+int(atk*20) cscore=cscore+clearSCR[cc] @@ -1253,37 +1252,37 @@ do--Player.drop(P)--Place piece if cmb>=3 then atk=atk+1 end - P:showText(text.cmb[min(cmb,21)],0,25,15+min(cmb,15)*5,cmb<10 and"appear"or"flicker") + self:showText(text.cmb[min(cmb,21)],0,25,15+min(cmb,15)*5,cmb<10 and"appear"or"flicker") cscore=cscore+min(50*cmb,500)*(2*cc-1) end --PC/HPC - if clear and #P.field==0 then - P:showText(text.PC,0,-80,50,"flicker") + if clear and #self.field==0 then + self:showText(text.PC,0,-80,50,"flicker") atk=max(atk,min(8+STAT.pc*2,16)) exblock=exblock+2 sendTime=sendTime+120 if STAT.row+cc>4 then - P.b2b=1000 + self.b2b=1000 cscore=cscore+300*min(6+STAT.pc,10) else cscore=cscore+626 end STAT.pc=STAT.pc+1 - if P.sound then + if self.sound then SFX.play("clear") VOC.play("perfect_clear",CHN) end piece.pc=true piece.special=true - elseif clear and(cc>1 or #P.field==P.garbageBeneath)then - P:showText(text.HPC,0,-80,50,"fly") + elseif clear and(cc>1 or #self.field==self.garbageBeneath)then + self:showText(text.HPC,0,-80,50,"fly") atk=atk+2 exblock=exblock+2 sendTime=sendTime+60 cscore=cscore+626 STAT.hpc=STAT.hpc+1 - if P.sound then + if self.sound then SFX.play("clear") VOC.play("half_clear",CHN) end @@ -1291,11 +1290,11 @@ do--Player.drop(P)--Place piece piece.special=true end - if P.b2b>1000 then P.b2b=1000 end + if self.b2b>1000 then self.b2b=1000 end --Bonus atk/def when focused if GAME.modeEnv.royaleMode then - local i=min(#P.atker,9) + local i=min(#self.atker,9) if i>1 then atk=atk+reAtk[i] exblock=exblock+reDef[i] @@ -1303,52 +1302,52 @@ do--Player.drop(P)--Place piece end --Send Lines - atk=int(atk*(1+P.strength*.25))--Badge Buff + atk=int(atk*(1+self.strength*.25))--Badge Buff send=atk if exblock>0 then - exblock=int(exblock*(1+P.strength*.25))--Badge Buff - P:showText("+"..exblock,0,53,20,"fly") - off=off+P:cancel(exblock) + exblock=int(exblock*(1+self.strength*.25))--Badge Buff + self:showText("+"..exblock,0,53,20,"fly") + off=off+self:cancel(exblock) end if send>=1 then - P:showText(send,0,80,35,"zoomout") - _=P:cancel(send) + self:showText(send,0,80,35,"zoomout") + _=self:cancel(send) send=send-_ off=off+_ if send>0 then local T if GAME.modeEnv.royaleMode then - if P.atkMode==4 then - local M=#P.atker + if self.atkMode==4 then + local M=#self.atker if M>0 then for i=1,M do - P:attack(P.atker[i],send,sendTime,generateLine(P:RND(10))) + self:attack(self.atker[i],send,sendTime,generateLine(self:RND(10))) if SETTING.atkFX>0 then - P:createBeam(P.atker[i],send,C.color) + self:createBeam(self.atker[i],send,C.color) end end else - T=randomTarget(P) + T=randomTarget(self) end else - T=P.atking - P:freshTarget() + T=self.atking + self:freshTarget() end elseif #PLAYERS.alive>1 then - T=randomTarget(P) + T=randomTarget(self) end if T then - P:attack(T,send,sendTime,generateLine(P:RND(10))) + self:attack(T,send,sendTime,generateLine(self:RND(10))) if SETTING.atkFX>0 then - P:createBeam(T,send,C.color) + self:createBeam(T,send,C.color) end end end - if P.sound and send>3 then SFX.play("emit",min(send,7)*.1)end + if self.sound and send>3 then SFX.play("emit",min(send,7)*.1)end end --SFX & Vibrate - if P.sound then + if self.sound then SFX.play(clearSFX[cc]or"clear_4") SFX.play(renSFX[min(cmb,11)]) if cmb>14 then SFX.play("ren_mega",(cmb-10)*.1)end @@ -1359,25 +1358,25 @@ do--Player.drop(P)--Place piece --Spin bonus if dospin then - P:showText(text.block[C.name]..text.spin,0,-30,45,"appear") - P.b2b=P.b2b+20 - if P.sound then + self:showText(text.block[C.name]..text.spin,0,-30,45,"appear") + self.b2b=self.b2b+20 + if self.sound then SFX.play("spin_0") VOC.play(spinVoice[C.name],CHN) end cscore=30 end - if P.b2b>800 then - P.b2b=max(P.b2b-40,800) + if self.b2b>800 then + self.b2b=max(self.b2b-40,800) end - P:garbageRelease() + self:garbageRelease() end - P.combo=cmb + self.combo=cmb --DropSpeed bonus - if P._20G then + if self._20G then cscore=cscore*2 elseif ENV.drop<1 then cscore=cscore*1.5 @@ -1386,13 +1385,13 @@ do--Player.drop(P)--Place piece end --Speed bonus - if P.dropSpeed>60 then - cscore=cscore*(.9+P.dropSpeed/600) + if self.dropSpeed>60 then + cscore=cscore*(.9+self.dropSpeed/600) end cscore=int(cscore) if ENV.score then - P:showText(cscore,(P.curX+P.cur.sc[2]-5.5)*30,(10-P.curY-P.cur.sc[1])*30+P.fieldBeneath+P.fieldUp,40-600/(cscore+20),"score",2) + self:showText(cscore,(self.curX+self.cur.sc[2]-5.5)*30,(10-self.curY-self.cur.sc[1])*30+self.fieldBeneath+self.fieldUp,40-600/(cscore+20),"score",2) end piece.row,piece.dig=cc,gbcc @@ -1401,8 +1400,8 @@ do--Player.drop(P)--Place piece piece.off,piece.send=off,send --Check clearing task - if cc>0 and P.curMission then - local t=ENV.mission[P.curMission] + if cc>0 and self.curMission then + local t=ENV.mission[self.curMission] local success if t<5 then if piece.row==t and not piece.spin then @@ -1422,14 +1421,14 @@ do--Player.drop(P)--Place piece end end if success then - P.curMission=P.curMission+1 + self.curMission=self.curMission+1 SFX.play("reach") - if P.curMission>#ENV.mission then - P.curMission=false + if self.curMission>#ENV.mission then + self.curMission=false if not finish then finish="finish"end end elseif ENV.missionKill then - P:showText(text.missionFailed,0,140,40,"flicker",.5) + self:showText(text.missionFailed,0,140,40,"flicker",.5) SFX.play("finesseError_long",.6) finish=true end @@ -1439,8 +1438,8 @@ do--Player.drop(P)--Place piece STAT.score=STAT.score+cscore STAT.piece=STAT.piece+1 STAT.row=STAT.row+cc - STAT.maxFinesseCombo=max(STAT.maxFinesseCombo,P.finesseCombo) - STAT.maxCombo=max(STAT.maxCombo,P.combo) + STAT.maxFinesseCombo=max(STAT.maxFinesseCombo,self.finesseCombo) + STAT.maxCombo=max(STAT.maxCombo,self.combo) if atk>0 then STAT.atk=STAT.atk+atk if send>0 then @@ -1466,55 +1465,55 @@ do--Player.drop(P)--Place piece end if finish then - if finish==true then P:lose()end - _=ENV.dropPiece if _ then _(P)end - if finish then P:win(finish)end + if finish==true then self:lose()end + _=ENV.dropPiece if _ then _(self)end + if finish then self:win(finish)end else - _=ENV.dropPiece if _ then _(P)end + _=ENV.dropPiece if _ then _(self)end end end end -function Player.loadAI(P,data)--Load AI params +function Player:loadAI(data)--Load AI params if not CC then data.type="9S" data.delta=int(data.delta*.3) end - P.AI_mode=data.type - P.AI_keys={} - P.AI_delay=min(int(P.gameEnv.drop*.8),data.delta*rnd()*4) - P.AI_delay0=data.delta - P.AIdata={ + self.AI_mode=data.type + self.AI_keys={} + self.AI_delay=min(int(self.gameEnv.drop*.8),data.delta*rnd()*4) + self.AI_delay0=data.delta + self.AIdata={ type=data.type, delay=data.delay, delta=data.delta, next=data.next, hold=data.hold, - _20G=P._20G, + _20G=self._20G, bag=data.bag, node=data.node, } - if P.AI_mode=="CC"then - P:setRS("SRS") + if self.AI_mode=="CC"then + self:setRS("SRS") local opt,wei=CC.getConf() CC.fastWeights(wei) - CC.setHold(opt,P.AIdata.hold) - CC.set20G(opt,P.AIdata._20G) - CC.setBag(opt,P.AIdata.bag=="bag") - CC.setNode(opt,P.AIdata.node) - P.AI_bot=CC.new(opt,wei) + CC.setHold(opt,self.AIdata.hold) + CC.set20G(opt,self.AIdata._20G) + CC.setBag(opt,self.AIdata.bag=="bag") + CC.setNode(opt,self.AIdata.node) + self.AI_bot=CC.new(opt,wei) CC.free(opt)CC.free(wei) - for i=1,P.AIdata.next do - CC.addNext(P.AI_bot,P.nextQueue[i].id) + for i=1,self.AIdata.next do + CC.addNext(self.AI_bot,self.nextQueue[i].id) end - if P.gameEnv.holdCount and P.gameEnv.holdCount>1 then - P:setHold(1) + if self.gameEnv.holdCount and self.gameEnv.holdCount>1 then + self:setHold(1) end else - P:setRS("TRS") + self:setRS("TRS") end - P.AI_thread=coroutine.create(AIFUNC[data.type]) - coroutine.resume(P.AI_thread,P,P.AI_keys) + self.AI_thread=coroutine.create(AIFUNC[data.type]) + coroutine.resume(self.AI_thread,self,self.AI_keys) end ---------------------------------------------------- @@ -1547,49 +1546,49 @@ local function tick_throwBadge(ifAI,sender,time) if time<=0 then return end end end -local function tick_finish(P) +local function tick_finish(self) while true do yield() - P.endCounter=P.endCounter+1 - if P.endCounter<40 then + self.endCounter=self.endCounter+1 + if self.endCounter<40 then --Make field visible - for j=1,#P.field do for i=1,10 do - if P.visTime[j][i]<20 then P.visTime[j][i]=P.visTime[j][i]+.5 end + for j=1,#self.field do for i=1,10 do + if self.visTime[j][i]<20 then self.visTime[j][i]=self.visTime[j][i]+.5 end end end - elseif P.endCounter==60 then + elseif self.endCounter==60 then return end end end -local function tick_lose(P) +local function tick_lose(self) while true do yield() - P.endCounter=P.endCounter+1 - if P.endCounter<40 then + self.endCounter=self.endCounter+1 + if self.endCounter<40 then --Make field visible - for j=1,#P.field do for i=1,10 do - if P.visTime[j][i]<20 then P.visTime[j][i]=P.visTime[j][i]+.5 end + for j=1,#self.field do for i=1,10 do + if self.visTime[j][i]<20 then self.visTime[j][i]=self.visTime[j][i]+.5 end end end - elseif P.endCounter>80 then - for i=1,#P.field do + elseif self.endCounter>80 then + for i=1,#self.field do for j=1,10 do - if P.visTime[i][j]>0 then - P.visTime[i][j]=P.visTime[i][j]-1 + if self.visTime[i][j]>0 then + self.visTime[i][j]=self.visTime[i][j]-1 end end end - if P.endCounter==120 then - for _=#P.field,1,-1 do - FREEROW.discard(P.field[_]) - FREEROW.discard(P.visTime[_]) - P.field[_],P.visTime[_]=nil + if self.endCounter==120 then + for _=#self.field,1,-1 do + FREEROW.discard(self.field[_]) + FREEROW.discard(self.visTime[_]) + self.field[_],self.visTime[_]=nil end return end end if not GAME.modeEnv.royaleMode and #PLAYERS>1 then - P.y=P.y+P.endCounter*.26 - P.absFieldY=P.absFieldY+P.endCounter*.26 + self.y=self.y+self.endCounter*.26 + self.absFieldY=self.absFieldY+self.endCounter*.26 end end end @@ -1667,33 +1666,33 @@ local function gameOver()--Save record end end -function Player.die(P)--Called both when win/lose! - P.alive=false - P.timing=false - P.control=false - P.update=PLY.update.dead - P.waiting=1e99 - P.b2b=0 - P.tasks={} - for i=1,#P.atkBuffer do - P.atkBuffer[i].sent=true - P.atkBuffer[i].time=0 +function Player:die()--Called both when win/lose! + self.alive=false + self.timing=false + self.control=false + self.update=PLY.update.dead + self.waiting=1e99 + self.b2b=0 + self.tasks={} + for i=1,#self.atkBuffer do + self.atkBuffer[i].sent=true + self.atkBuffer[i].time=0 end - for i=1,#P.field do + for i=1,#self.field do for j=1,10 do - P.visTime[i][j]=min(P.visTime[i][j],20) + self.visTime[i][j]=min(self.visTime[i][j],20) end end end -function Player.win(P,result) - if P.result then return end - P:die() - P.result="WIN" +function Player:win(result) + if self.result then return end + self:die() + self.result="WIN" if GAME.modeEnv.royaleMode then - P.modeData.place=1 - P:changeAtk() + self.modeData.place=1 + self:changeAtk() end - if P.type=="human"then + if self.type=="human"then GAME.result=result or"win" SFX.play("win") VOC.play("win") @@ -1702,92 +1701,92 @@ function Player.win(P,result) end end if GAME.curMode.id=="custom_puzzle"then - P:showTextF(text.win,0,0,90,"beat",.4) + self:showTextF(text.win,0,0,90,"beat",.4) else - P:showTextF(text.win,0,0,90,"beat",.5,.2) + self:showTextF(text.win,0,0,90,"beat",.5,.2) end - if P.type=="human"then + if self.type=="human"then gameOver() TASK.new(tick_autoPause) end - P:newTask(tick_finish) + self:newTask(tick_finish) end -function Player.lose(P,force) - if P.result then return end - if P.life>0 and not force then - P.waiting=62 - local h=#P.field +function Player:lose(force) + if self.result then return end + if self.life>0 and not force then + self.waiting=62 + local h=#self.field for _=h,1,-1 do - FREEROW.discard(P.field[_]) - FREEROW.discard(P.visTime[_]) - P.field[_],P.visTime[_]=nil + FREEROW.discard(self.field[_]) + FREEROW.discard(self.visTime[_]) + self.field[_],self.visTime[_]=nil end - P.garbageBeneath=0 + self.garbageBeneath=0 - if P.AI_mode=="CC"then - CC.destroy(P.AI_bot) - while P.holdQueue[1]do rem(P.holdQueue)end - P:loadAI(P.AIdata) + if self.AI_mode=="CC"then + CC.destroy(self.AI_bot) + while self.holdQueue[1]do rem(self.holdQueue)end + self:loadAI(self.AIdata) end - P.life=P.life-1 - P.fieldBeneath=0 - P.b2b=0 - for i=1,#P.atkBuffer do - local A=P.atkBuffer[i] + self.life=self.life-1 + self.fieldBeneath=0 + self.b2b=0 + for i=1,#self.atkBuffer do + local A=self.atkBuffer[i] if not A.sent then A.sent=true A.time=0 end end - P.atkBuffer.sum=0 + self.atkBuffer.sum=0 for i=1,h do - P:createClearingFX(i,1.5) + self:createClearingFX(i,1.5) end - SYSFX.newShade(1.4,P.fieldX,P.fieldY,300*P.size,610*P.size) - SYSFX.newRectRipple(2,P.fieldX,P.fieldY,300*P.size,610*P.size) - SYSFX.newRipple(2,P.x+(475+25*(P.life<3 and P.life or 0)+12)*P.size,P.y+(665+12)*P.size,20) + SYSFX.newShade(1.4,self.fieldX,self.fieldY,300*self.size,610*self.size) + SYSFX.newRectRipple(2,self.fieldX,self.fieldY,300*self.size,610*self.size) + SYSFX.newRipple(2,self.x+(475+25*(self.life<3 and self.life or 0)+12)*self.size,self.y+(665+12)*self.size,20) SFX.play("clear_3") SFX.play("emit") return end - P:die() + self:die() for i=1,#PLAYERS.alive do - if PLAYERS.alive[i]==P then + if PLAYERS.alive[i]==self then rem(PLAYERS.alive,i) break end end - P.result="K.O." + self.result="K.O." if GAME.modeEnv.royaleMode then - P:changeAtk() - P.modeData.place=#PLAYERS.alive+1 - P.strength=0 - if P.lastRecv then - local A,i=P,0 + self:changeAtk() + self.modeData.place=#PLAYERS.alive+1 + self.strength=0 + if self.lastRecv then + local A,i=self,0 repeat A,i=A.lastRecv,i+1 - until not A or A.alive or A==P or i==3 + until not A or A.alive or A==self or i==3 if A and A.alive then - if P.id==1 or A.id==1 then - P.killMark=A.id==1 + if self.id==1 or A.id==1 then + self.killMark=A.id==1 end - A.modeData.ko,A.badge=A.modeData.ko+1,A.badge+P.badge+1 + A.modeData.ko,A.badge=A.modeData.ko+1,A.badge+self.badge+1 for j=A.strength+1,4 do if A.badge>=royaleData.powerUp[j]then A.strength=j A.frameColor=A.strength end end - P.lastRecv=A - if P.id==1 or A.id==1 then - TASK.new(tick_throwBadge,not A.type=="human",P,max(3,P.badge)*4) + self.lastRecv=A + if self.id==1 or A.id==1 then + TASK.new(tick_throwBadge,not A.type=="human",self,max(3,self.badge)*4) end end else - P.badge=-1 + self.badge=-1 end freshMostBadge() @@ -1795,30 +1794,30 @@ function Player.lose(P,force) if #PLAYERS.alive==royaleData.stage[GAME.stage]then royaleLevelup() end - P:showTextF(P.modeData.place,0,120,60,"appear",.26,.9) + self:showTextF(self.modeData.place,0,120,60,"appear",.26,.9) end - P.gameEnv.keepVisible=P.gameEnv.visible~="show" - P:showTextF(text.gameover,0,0,60,"appear",.26,.9) - if P.type=="human"then + self.gameEnv.keepVisible=self.gameEnv.visible~="show" + self:showTextF(text.gameover,0,0,60,"appear",.26,.9) + if self.type=="human"then GAME.result="gameover" SFX.play("fail") VOC.play("lose") if GAME.modeEnv.royaleMode then - if P.modeData.place==2 then + if self.modeData.place==2 then BGM.play("hay what kind of feeling") else BGM.play("end") end end gameOver() - P:newTask(#PLAYERS>1 and tick_lose or tick_finish) + self:newTask(#PLAYERS>1 and tick_lose or tick_finish) if GAME.net then NET.signal_die() else TASK.new(tick_autoPause) end else - P:newTask(tick_lose) + self:newTask(tick_lose) end if #PLAYERS.alive==1 then PLAYERS.alive[1]:win() @@ -1827,269 +1826,269 @@ end --------------------------<\Events>-------------------------- ---------------------------------------------------- -function Player.act_moveLeft(P,auto) +function Player:act_moveLeft(auto) if not auto then - P.ctrlCount=P.ctrlCount+1 + self.ctrlCount=self.ctrlCount+1 end - P.movDir=-1 - if P.keyPressing[9]then - if P.gameEnv.swap then - P:changeAtkMode(1) - P.keyPressing[1]=false + self.movDir=-1 + if self.keyPressing[9]then + if self.gameEnv.swap then + self:changeAtkMode(1) + self.keyPressing[1]=false end - elseif P.control and P.waiting==-1 then - if P.cur and not P:ifoverlap(P.cur.bk,P.curX-1,P.curY)then - if P.gameEnv.moveFX and P.gameEnv.block then - P:createMoveFX("left") + elseif self.control and self.waiting==-1 then + if self.cur and not self:ifoverlap(self.cur.bk,self.curX-1,self.curY)then + if self.gameEnv.moveFX and self.gameEnv.block then + self:createMoveFX("left") end - P.curX=P.curX-1 - P:freshBlock("move") - if P.sound and P.curY==P.ghoY then SFX.play("move")end - if not auto then P.moving=0 end - P.spinLast=false + self.curX=self.curX-1 + self:freshBlock("move") + if self.sound and self.curY==self.ghoY then SFX.play("move")end + if not auto then self.moving=0 end + self.spinLast=false else - P.moving=P.gameEnv.das + self.moving=self.gameEnv.das end else - P.moving=0 + self.moving=0 end end -function Player.act_moveRight(P,auto) +function Player:act_moveRight(auto) if not auto then - P.ctrlCount=P.ctrlCount+1 + self.ctrlCount=self.ctrlCount+1 end - P.movDir=1 - if P.keyPressing[9]then - if P.gameEnv.swap then - P:changeAtkMode(2) - P.keyPressing[2]=false + self.movDir=1 + if self.keyPressing[9]then + if self.gameEnv.swap then + self:changeAtkMode(2) + self.keyPressing[2]=false end - elseif P.control and P.waiting==-1 then - if P.cur and not P:ifoverlap(P.cur.bk,P.curX+1,P.curY)then - if P.gameEnv.moveFX and P.gameEnv.block then - P:createMoveFX("right") + elseif self.control and self.waiting==-1 then + if self.cur and not self:ifoverlap(self.cur.bk,self.curX+1,self.curY)then + if self.gameEnv.moveFX and self.gameEnv.block then + self:createMoveFX("right") end - P.curX=P.curX+1 - P:freshBlock("move") - if P.sound and P.curY==P.ghoY then SFX.play("move")end - if not auto then P.moving=0 end - P.spinLast=false + self.curX=self.curX+1 + self:freshBlock("move") + if self.sound and self.curY==self.ghoY then SFX.play("move")end + if not auto then self.moving=0 end + self.spinLast=false else - P.moving=P.gameEnv.das + self.moving=self.gameEnv.das end else - P.moving=0 + self.moving=0 end end -function Player.act_rotRight(P) - if P.control and P.waiting==-1 and P.cur then - P.ctrlCount=P.ctrlCount+1 - P:spin(1) - P.keyPressing[3]=false +function Player:act_rotRight() + if self.control and self.waiting==-1 and self.cur then + self.ctrlCount=self.ctrlCount+1 + self:spin(1) + self.keyPressing[3]=false end end -function Player.act_rotLeft(P) - if P.control and P.waiting==-1 and P.cur then - P.ctrlCount=P.ctrlCount+1 - P:spin(3) - P.keyPressing[4]=false +function Player:act_rotLeft() + if self.control and self.waiting==-1 and self.cur then + self.ctrlCount=self.ctrlCount+1 + self:spin(3) + self.keyPressing[4]=false end end -function Player.act_rot180(P) - if P.control and P.waiting==-1 and P.cur then - P.ctrlCount=P.ctrlCount+2 - P:spin(2) - P.keyPressing[5]=false +function Player:act_rot180() + if self.control and self.waiting==-1 and self.cur then + self.ctrlCount=self.ctrlCount+2 + self:spin(2) + self.keyPressing[5]=false end end -function Player.act_hardDrop(P) - if P.keyPressing[9]then - if P.gameEnv.swap then - P:changeAtkMode(3) +function Player:act_hardDrop() + if self.keyPressing[9]then + if self.gameEnv.swap then + self:changeAtkMode(3) end - P.keyPressing[6]=false - elseif P.control and P.waiting==-1 and P.cur then - if P.curY>P.ghoY then - local CB=P.cur.bk - if P.gameEnv.dropFX and P.gameEnv.block and P.curY-P.ghoY-#CB>-1 then - P:createDropFX(P.curX,P.curY-1,#CB[1],P.curY-P.ghoY-#CB+1) + self.keyPressing[6]=false + elseif self.control and self.waiting==-1 and self.cur then + if self.curY>self.ghoY then + local CB=self.cur.bk + if self.gameEnv.dropFX and self.gameEnv.block and self.curY-self.ghoY-#CB>-1 then + self:createDropFX(self.curX,self.curY-1,#CB[1],self.curY-self.ghoY-#CB+1) end - P.curY=P.ghoY - P.spinLast=false - if P.sound then - SFX.play("drop",nil,P:getCenterX()*.15) + self.curY=self.ghoY + self.spinLast=false + if self.sound then + SFX.play("drop",nil,self:getCenterX()*.15) VIB(1) end end - if P.gameEnv.shakeFX then - P.fieldOff.vy=P.gameEnv.shakeFX*.6 - P.fieldOff.va=P.fieldOff.va+P:getCenterX()*P.gameEnv.shakeFX*6e-4 + if self.gameEnv.shakeFX then + self.fieldOff.vy=self.gameEnv.shakeFX*.6 + self.fieldOff.va=self.fieldOff.va+self:getCenterX()*self.gameEnv.shakeFX*6e-4 end - P.lockDelay=-1 - P:drop() - P.keyPressing[6]=false + self.lockDelay=-1 + self:drop() + self.keyPressing[6]=false end end -function Player.act_softDrop(P) - local ENV=P.gameEnv - if P.keyPressing[9]then +function Player:act_softDrop() + local ENV=self.gameEnv + if self.keyPressing[9]then if ENV.swap then - P:changeAtkMode(4) + self:changeAtkMode(4) end else - P.downing=1 - if P.control and P.waiting==-1 and P.cur then - if P.curY>P.ghoY then - P.curY=P.curY-1 - P:freshBlock("fresh") - P.spinLast=false + self.downing=1 + if self.control and self.waiting==-1 and self.cur then + if self.curY>self.ghoY then + self.curY=self.curY-1 + self:freshBlock("fresh") + self.spinLast=false elseif ENV.deepDrop then - local CB=P.cur.bk - local y=P.curY-1 - while P:ifoverlap(CB,P.curX,y)and y>0 do + local CB=self.cur.bk + local y=self.curY-1 + while self:ifoverlap(CB,self.curX,y)and y>0 do y=y-1 end if y>0 then - if ENV.dropFX and ENV.block and P.curY-y-#CB>-1 then - P:createDropFX(P.curX,P.curY-1,#CB[1],P.curY-y-#CB+1) + if ENV.dropFX and ENV.block and self.curY-y-#CB>-1 then + self:createDropFX(self.curX,self.curY-1,#CB[1],self.curY-y-#CB+1) end - P.curY=y - P:freshBlock("move") + self.curY=y + self:freshBlock("move") SFX.play("swipe") end end end end end -function Player.act_hold(P) - if P.control and P.waiting==-1 then - P:hold() +function Player:act_hold() + if self.control and self.waiting==-1 then + self:hold() end end -function Player.act_func1(P) - P.gameEnv.fkey1(P) +function Player:act_func1() + self.gameEnv.fkey1(self) end -function Player.act_func2(P) - P.gameEnv.fkey2(P) +function Player:act_func2() + self.gameEnv.fkey2(self) end -function Player.act_insLeft(P,auto) - if not P.cur then return end - local x0=P.curX - while not P:ifoverlap(P.cur.bk,P.curX-1,P.curY)do - if P.gameEnv.moveFX and P.gameEnv.block then - P:createMoveFX("left") +function Player:act_insLeft(auto) + if not self.cur then return end + local x0=self.curX + while not self:ifoverlap(self.cur.bk,self.curX-1,self.curY)do + if self.gameEnv.moveFX and self.gameEnv.block then + self:createMoveFX("left") end - P.curX=P.curX-1 - P:freshBlock("move") + self.curX=self.curX-1 + self:freshBlock("move") end - if P.curX~=x0 then - P.spinLast=false + if self.curX~=x0 then + self.spinLast=false end - if P.gameEnv.shakeFX then - P.fieldOff.vx=-P.gameEnv.shakeFX*.5 + if self.gameEnv.shakeFX then + self.fieldOff.vx=-self.gameEnv.shakeFX*.5 end if auto then - if P.ctrlCount==0 then P.ctrlCount=1 end + if self.ctrlCount==0 then self.ctrlCount=1 end else - P.ctrlCount=P.ctrlCount+1 + self.ctrlCount=self.ctrlCount+1 end end -function Player.act_insRight(P,auto) - if not P.cur then return end - local x0=P.curX - while not P:ifoverlap(P.cur.bk,P.curX+1,P.curY)do - if P.gameEnv.moveFX and P.gameEnv.block then - P:createMoveFX("right") +function Player:act_insRight(auto) + if not self.cur then return end + local x0=self.curX + while not self:ifoverlap(self.cur.bk,self.curX+1,self.curY)do + if self.gameEnv.moveFX and self.gameEnv.block then + self:createMoveFX("right") end - P.curX=P.curX+1 - P:freshBlock("move") + self.curX=self.curX+1 + self:freshBlock("move") end - if P.curX~=x0 then - P.spinLast=false + if self.curX~=x0 then + self.spinLast=false end - if P.gameEnv.shakeFX then - P.fieldOff.vx=P.gameEnv.shakeFX*.5 + if self.gameEnv.shakeFX then + self.fieldOff.vx=self.gameEnv.shakeFX*.5 end if auto then - if P.ctrlCount==0 then P.ctrlCount=1 end + if self.ctrlCount==0 then self.ctrlCount=1 end else - P.ctrlCount=P.ctrlCount+1 + self.ctrlCount=self.ctrlCount+1 end end -function Player.act_insDown(P) - if P.cur and P.curY>P.ghoY then - local ENV=P.gameEnv - local CB=P.cur.bk - if ENV.dropFX and ENV.block and P.curY-P.ghoY-#CB>-1 then - P:createDropFX(P.curX,P.curY-1,#CB[1],P.curY-P.ghoY-#CB+1) +function Player:act_insDown() + if self.cur and self.curY>self.ghoY then + local ENV=self.gameEnv + local CB=self.cur.bk + if ENV.dropFX and ENV.block and self.curY-self.ghoY-#CB>-1 then + self:createDropFX(self.curX,self.curY-1,#CB[1],self.curY-self.ghoY-#CB+1) end if ENV.shakeFX then - P.fieldOff.vy=ENV.shakeFX*.5 + self.fieldOff.vy=ENV.shakeFX*.5 end - P.curY=P.ghoY - P.lockDelay=ENV.lock - P.spinLast=false - P:freshBlock("fresh") + self.curY=self.ghoY + self.lockDelay=ENV.lock + self.spinLast=false + self:freshBlock("fresh") end end -function Player.act_down1(P) - if P.cur and P.curY>P.ghoY then - if P.gameEnv.moveFX and P.gameEnv.block then - P:createMoveFX("down") +function Player:act_down1() + if self.cur and self.curY>self.ghoY then + if self.gameEnv.moveFX and self.gameEnv.block then + self:createMoveFX("down") end - P.curY=P.curY-1 - P:freshBlock("fresh") - P.spinLast=false + self.curY=self.curY-1 + self:freshBlock("fresh") + self.spinLast=false end end -function Player.act_down4(P) - if P.cur and P.curY>P.ghoY then - local y=max(P.curY-4,P.ghoY) - local CB=P.cur.bk - if P.gameEnv.dropFX and P.gameEnv.block and P.curY-y-#CB>-1 then - P:createDropFX(P.curX,P.curY-1,#CB[1],P.curY-y-#CB+1) +function Player:act_down4() + if self.cur and self.curY>self.ghoY then + local y=max(self.curY-4,self.ghoY) + local CB=self.cur.bk + if self.gameEnv.dropFX and self.gameEnv.block and self.curY-y-#CB>-1 then + self:createDropFX(self.curX,self.curY-1,#CB[1],self.curY-y-#CB+1) end - P.curY=y - P:freshBlock("fresh") - P.spinLast=false + self.curY=y + self:freshBlock("fresh") + self.spinLast=false end end -function Player.act_down10(P) - if P.cur and P.curY>P.ghoY then - local y=max(P.curY-10,P.ghoY) - local CB=P.cur.bk - if P.gameEnv.dropFX and P.gameEnv.block and P.curY-y-#CB>-1 then - P:createDropFX(P.curX,P.curY-1,#CB[1],P.curY-y-#CB+1) +function Player:act_down10() + if self.cur and self.curY>self.ghoY then + local y=max(self.curY-10,self.ghoY) + local CB=self.cur.bk + if self.gameEnv.dropFX and self.gameEnv.block and self.curY-y-#CB>-1 then + self:createDropFX(self.curX,self.curY-1,#CB[1],self.curY-y-#CB+1) end - P.curY=y - P:freshBlock("fresh") - P.spinLast=false + self.curY=y + self:freshBlock("fresh") + self.spinLast=false end end -function Player.act_dropLeft(P) - if not P.cur then return end - P:act_insLeft() - P:act_hardDrop() +function Player:act_dropLeft() + if not self.cur then return end + self:act_insLeft() + self:act_hardDrop() end -function Player.act_dropRight(P) - if not P.cur then return end - P:act_insRight() - P:act_hardDrop() +function Player:act_dropRight() + if not self.cur then return end + self:act_insRight() + self:act_hardDrop() end -function Player.act_zangiLeft(P) - if not P.cur then return end - P:act_insLeft() - P:act_insDown() - P:act_insRight() - P:act_hardDrop() +function Player:act_zangiLeft() + if not self.cur then return end + self:act_insLeft() + self:act_insDown() + self:act_insRight() + self:act_hardDrop() end -function Player.act_zangiRight(P) - if not P.cur then return end - P:act_insRight() - P:act_insDown() - P:act_insLeft() - P:act_hardDrop() +function Player:act_zangiRight() + if not self.cur then return end + self:act_insRight() + self:act_insDown() + self:act_insLeft() + self:act_hardDrop() end Player.actList={ Player.act_moveLeft, --1 From 4dad8500bc60873f7ecbb9cc88ce4efb3362658e Mon Sep 17 00:00:00 2001 From: MrZ626 <1046101471@qq.com> Date: Mon, 29 Mar 2021 11:11:45 +0800 Subject: [PATCH 13/83] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dws=E7=8A=B6=E6=80=81?= =?UTF-8?q?=E6=98=BE=E7=A4=BA=E7=9A=84alertTimer=E6=89=93=E9=94=99?= =?UTF-8?q?=E6=96=B9=E6=B3=95=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Zframework/init.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Zframework/init.lua b/Zframework/init.lua index e29e9e40..8058fe6b 100644 --- a/Zframework/init.lua +++ b/Zframework/init.lua @@ -599,7 +599,7 @@ function love.run() gc_draw(TEXTURE.ws_running,-20,20*i-20) end gc_setColor(1,1,1,WS.getPongTimer(WSnames[i]))gc_rectangle("fill",0,20*i,-20,-20) - gc_setColor(1,0,0,WS.getPongTimer(WSnames[i]))gc_rectangle("fill",-4,20*i-4,-12,-12) + gc_setColor(1,0,0,WS.getAlertTimer(WSnames[i]))gc_rectangle("fill",-4,20*i-4,-12,-12) end gc_pop() From 209038adb2d6cd622f6574bc7cb448eb08b762d9 Mon Sep 17 00:00:00 2001 From: MrZ626 <1046101471@qq.com> Date: Mon, 29 Mar 2021 11:12:13 +0800 Subject: [PATCH 14/83] =?UTF-8?q?=E4=B8=BB=E8=8F=9C=E5=8D=95=E4=B8=8D?= =?UTF-8?q?=E5=86=8D=E7=A6=81=E6=AD=A2=E8=87=AA=E5=8A=A8=E8=87=AA=E5=8A=A8?= =?UTF-8?q?=E9=87=8D=E5=A4=8D=E6=8C=89=E9=94=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- parts/scenes/main.lua | 4 ---- 1 file changed, 4 deletions(-) diff --git a/parts/scenes/main.lua b/parts/scenes/main.lua index 209f5375..9dcbdafb 100644 --- a/parts/scenes/main.lua +++ b/parts/scenes/main.lua @@ -43,10 +43,6 @@ 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) From fa8493fd3e8559f1f50b8e2fca392532f42ffb81 Mon Sep 17 00:00:00 2001 From: MrZ626 <1046101471@qq.com> Date: Mon, 29 Mar 2021 11:12:35 +0800 Subject: [PATCH 15/83] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dload=E5=AE=8C=E5=BF=98?= =?UTF-8?q?=E4=BA=86=E5=90=AF=E5=8A=A8ws-play=E7=9A=84task?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- parts/scenes/load.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/parts/scenes/load.lua b/parts/scenes/load.lua index 94e5634e..eb94a22c 100644 --- a/parts/scenes/load.lua +++ b/parts/scenes/load.lua @@ -180,6 +180,7 @@ local loadingThread=coroutine.create(function() --Connect to server TASK.new(TICK_WS_app) TASK.new(TICK_WS_user) + TASK.new(TICK_WS_play) WS.connect("app","/app") if USER.authToken then WS.connect("user","/user",JSON.encode{ From c0736132b17afc9e7242c1e93d09b4662cd41962 Mon Sep 17 00:00:00 2001 From: MrZ626 <1046101471@qq.com> Date: Mon, 29 Mar 2021 11:21:16 +0800 Subject: [PATCH 16/83] =?UTF-8?q?=E6=95=B4=E7=90=86=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- parts/gametoolfunc.lua | 41 ++++++++++++------------ parts/scenes/customGame.lua | 12 +++---- parts/scenes/custom_advance.lua | 34 ++++++++++---------- parts/scenes/custom_mission.lua | 2 +- parts/scenes/custom_sequence.lua | 4 +-- parts/scenes/music.lua | 2 +- parts/scenes/setting_control.lua | 16 +++++----- parts/scenes/setting_game.lua | 14 ++++---- parts/scenes/setting_sound.lua | 14 ++++---- parts/scenes/setting_touchSwitch.lua | 12 +++---- parts/scenes/setting_trackSetting.lua | 6 ++-- parts/scenes/setting_video.lua | 46 +++++++++++++-------------- parts/scenes/sound.lua | 4 +-- 13 files changed, 104 insertions(+), 103 deletions(-) diff --git a/parts/gametoolfunc.lua b/parts/gametoolfunc.lua index efb7ee33..3bc0fd2a 100644 --- a/parts/gametoolfunc.lua +++ b/parts/gametoolfunc.lua @@ -982,25 +982,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,14 +1052,14 @@ 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 + 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 diff --git a/parts/scenes/customGame.lua b/parts/scenes/customGame.lua index 998bf10a..d3988082 100644 --- a/parts/scenes/customGame.lua +++ b/parts/scenes/customGame.lua @@ -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"}, diff --git a/parts/scenes/custom_advance.lua b/parts/scenes/custom_advance.lua index 4ef4beba..b7176219 100644 --- a/parts/scenes/custom_advance.lua +++ b/parts/scenes/custom_advance.lua @@ -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}, } diff --git a/parts/scenes/custom_mission.lua b/parts/scenes/custom_mission.lua index c9855c4b..b5688b98 100644 --- a/parts/scenes/custom_mission.lua +++ b/parts/scenes/custom_mission.lua @@ -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}, } diff --git a/parts/scenes/custom_sequence.lua b/parts/scenes/custom_sequence.lua index ca999163..17deb1b6 100644 --- a/parts/scenes/custom_sequence.lua +++ b/parts/scenes/custom_sequence.lua @@ -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)}, diff --git a/parts/scenes/music.lua b/parts/scenes/music.lua index 796a88fa..0289e344 100644 --- a/parts/scenes/music.lua +++ b/parts/scenes/music.lua @@ -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}, diff --git a/parts/scenes/setting_control.lua b/parts/scenes/setting_control.lua index 8ebb151a..4bb3f3a0 100644 --- a/parts/scenes/setting_control.lua +++ b/parts/scenes/setting_control.lua @@ -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 diff --git a/parts/scenes/setting_game.lua b/parts/scenes/setting_game.lua index 05a25023..2c0347af 100644 --- a/parts/scenes/setting_game.lua +++ b/parts/scenes/setting_game.lua @@ -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 diff --git a/parts/scenes/setting_sound.lua b/parts/scenes/setting_sound.lua index effea2a4..03652c69 100644 --- a/parts/scenes/setting_sound.lua +++ b/parts/scenes/setting_sound.lua @@ -61,13 +61,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}, diff --git a/parts/scenes/setting_touchSwitch.lua b/parts/scenes/setting_touchSwitch.lua index af5a6079..b8ec6bfb 100644 --- a/parts/scenes/setting_touchSwitch.lua +++ b/parts/scenes/setting_touchSwitch.lua @@ -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}, } diff --git a/parts/scenes/setting_trackSetting.lua b/parts/scenes/setting_trackSetting.lua index 85531473..f507c92b 100644 --- a/parts/scenes/setting_trackSetting.lua +++ b/parts/scenes/setting_trackSetting.lua @@ -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}, } diff --git a/parts/scenes/setting_video.lua b/parts/scenes/setting_video.lua index d63c3e8f..9311435e 100644 --- a/parts/scenes/setting_video.lua +++ b/parts/scenes/setting_video.lua @@ -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}, } diff --git a/parts/scenes/sound.lua b/parts/scenes/sound.lua index 3b8765ee..666a5e97 100644 --- a/parts/scenes/sound.lua +++ b/parts/scenes/sound.lua @@ -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}, From ee02013fa5b2348688ffbbf2239cf009baf2e319 Mon Sep 17 00:00:00 2001 From: MrZ626 <1046101471@qq.com> Date: Mon, 29 Mar 2021 11:40:36 +0800 Subject: [PATCH 17/83] =?UTF-8?q?PLAYERS.alive=E6=8B=BF=E5=87=BA=E6=9D=A5?= =?UTF-8?q?=E4=BD=9C=E4=B8=BA=E5=8D=95=E7=8B=AC=E5=8F=98=E9=87=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Zframework/init.lua | 2 +- parts/gametoolfunc.lua | 48 ++++++++++++++++++------------------ parts/globalTables.lua | 3 ++- parts/modes/custom_clear.lua | 2 +- parts/modes/round_e.lua | 2 +- parts/modes/round_h.lua | 2 +- parts/modes/round_l.lua | 2 +- parts/modes/round_n.lua | 2 +- parts/modes/round_u.lua | 2 +- parts/modes/techmino49_e.lua | 2 +- parts/modes/techmino49_h.lua | 2 +- parts/modes/techmino49_u.lua | 2 +- parts/modes/techmino99_e.lua | 2 +- parts/modes/techmino99_h.lua | 2 +- parts/modes/techmino99_u.lua | 2 +- parts/player/init.lua | 2 +- parts/player/player.lua | 16 ++++++------ parts/player/update.lua | 4 +-- parts/scenes/net_game.lua | 8 +++--- 19 files changed, 54 insertions(+), 53 deletions(-) diff --git a/Zframework/init.lua b/Zframework/init.lua index 8058fe6b..faf26cfe 100644 --- a/Zframework/init.lua +++ b/Zframework/init.lua @@ -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() diff --git a/parts/gametoolfunc.lua b/parts/gametoolfunc.lua index 3bc0fd2a..aa461149 100644 --- a/parts/gametoolfunc.lua +++ b/parts/gametoolfunc.lua @@ -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,8 +537,8 @@ 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 + for i=#PLY_ALIVE,1,-1 do + PLY_ALIVE[i]=nil end collectgarbage() end @@ -611,7 +611,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) diff --git a/parts/globalTables.lua b/parts/globalTables.lua index 93439ce4..3aae2007 100644 --- a/parts/globalTables.lua +++ b/parts/globalTables.lua @@ -142,7 +142,8 @@ for i=1,#MODOPT do end --Game tables -PLAYERS={alive={}}--Players data +PLAYERS={}--Players data +PLY_ALIVE={} FIELD={}--Field(s) for custom game BAG={}--Sequence for custom game MISSION={}--Clearing mission for custom game diff --git a/parts/modes/custom_clear.lua b/parts/modes/custom_clear.lua index 5809db7b..4dbbb590 100644 --- a/parts/modes/custom_clear.lua +++ b/parts/modes/custom_clear.lua @@ -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, diff --git a/parts/modes/round_e.lua b/parts/modes/round_e.lua index 2b3ef740..d565c152 100644 --- a/parts/modes/round_e.lua +++ b/parts/modes/round_e.lua @@ -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 diff --git a/parts/modes/round_h.lua b/parts/modes/round_h.lua index 54d17ae3..3ccce225 100644 --- a/parts/modes/round_h.lua +++ b/parts/modes/round_h.lua @@ -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 diff --git a/parts/modes/round_l.lua b/parts/modes/round_l.lua index a9ab94d7..69a21cd4 100644 --- a/parts/modes/round_l.lua +++ b/parts/modes/round_l.lua @@ -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 diff --git a/parts/modes/round_n.lua b/parts/modes/round_n.lua index b790fa84..6619e14e 100644 --- a/parts/modes/round_n.lua +++ b/parts/modes/round_n.lua @@ -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 diff --git a/parts/modes/round_u.lua b/parts/modes/round_u.lua index d8675c26..15ddef4d 100644 --- a/parts/modes/round_u.lua +++ b/parts/modes/round_u.lua @@ -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 diff --git a/parts/modes/techmino49_e.lua b/parts/modes/techmino49_e.lua index e1083665..05caf981 100644 --- a/parts/modes/techmino49_e.lua +++ b/parts/modes/techmino49_e.lua @@ -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) diff --git a/parts/modes/techmino49_h.lua b/parts/modes/techmino49_h.lua index 9643673f..8f2efa53 100644 --- a/parts/modes/techmino49_h.lua +++ b/parts/modes/techmino49_h.lua @@ -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) diff --git a/parts/modes/techmino49_u.lua b/parts/modes/techmino49_u.lua index d10655b9..fdc11d4a 100644 --- a/parts/modes/techmino49_u.lua +++ b/parts/modes/techmino49_u.lua @@ -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) diff --git a/parts/modes/techmino99_e.lua b/parts/modes/techmino99_e.lua index c35700ac..9ef69fe9 100644 --- a/parts/modes/techmino99_e.lua +++ b/parts/modes/techmino99_e.lua @@ -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) diff --git a/parts/modes/techmino99_h.lua b/parts/modes/techmino99_h.lua index 713030b3..6479e695 100644 --- a/parts/modes/techmino99_h.lua +++ b/parts/modes/techmino99_h.lua @@ -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) diff --git a/parts/modes/techmino99_u.lua b/parts/modes/techmino99_u.lua index 3ca05a56..a6440694 100644 --- a/parts/modes/techmino99_u.lua +++ b/parts/modes/techmino99_u.lua @@ -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) diff --git a/parts/player/init.lua b/parts/player/init.lua index ede6222e..04fcf48d 100644 --- a/parts/player/init.lua +++ b/parts/player/init.lua @@ -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 diff --git a/parts/player/player.lua b/parts/player/player.lua index 1cd56cf6..ebc30661 100644 --- a/parts/player/player.lua +++ b/parts/player/player.lua @@ -1333,7 +1333,7 @@ do--Player.drop(self)--Place piece T=self.atking self:freshTarget() end - elseif #PLAYERS.alive>1 then + elseif #PLY_ALIVE>1 then T=randomTarget(self) end if T then @@ -1753,16 +1753,16 @@ function Player:lose(force) return end self:die() - for i=1,#PLAYERS.alive do - if PLAYERS.alive[i]==self then - rem(PLAYERS.alive,i) + for i=1,#PLY_ALIVE do + if PLY_ALIVE[i]==self then + rem(PLY_ALIVE,i) break end end self.result="K.O." if GAME.modeEnv.royaleMode then self:changeAtk() - self.modeData.place=#PLAYERS.alive+1 + self.modeData.place=#PLY_ALIVE+1 self.strength=0 if self.lastRecv then local A,i=self,0 @@ -1791,7 +1791,7 @@ function Player:lose(force) freshMostBadge() freshMostDangerous() - if #PLAYERS.alive==royaleData.stage[GAME.stage]then + if #PLY_ALIVE==royaleData.stage[GAME.stage]then royaleLevelup() end self:showTextF(self.modeData.place,0,120,60,"appear",.26,.9) @@ -1819,8 +1819,8 @@ function Player:lose(force) else self:newTask(tick_lose) end - if #PLAYERS.alive==1 then - PLAYERS.alive[1]:win() + if #PLY_ALIVE==1 then + PLY_ALIVE[1]:win() end end --------------------------<\Events>-------------------------- diff --git a/parts/player/update.lua b/parts/player/update.lua index 9b99af5d..d04ef910 100644 --- a/parts/player/update.lua +++ b/parts/player/update.lua @@ -398,7 +398,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 +409,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 diff --git a/parts/scenes/net_game.lua b/parts/scenes/net_game.lua index 7ea561f9..de4f162c 100644 --- a/parts/scenes/net_game.lua +++ b/parts/scenes/net_game.lua @@ -185,9 +185,9 @@ function scene.socketRead(mes) break end end - for i=1,#PLAYERS.alive do - if PLAYERS.alive[i].userID==args[2]then - rem(PLAYERS.alive,i) + for i=1,#PLY_ALIVE do + if PLY_ALIVE[i].userID==args[2]then + rem(PLY_ALIVE,i) break end end @@ -225,7 +225,7 @@ function scene.socketRead(mes) end end elseif cmd=="R"then - local L=PLAYERS.alive + local L=PLY_ALIVE for i=1,#L do if L[i].subID==args[1]then L[i].ready=true From aad6dcb26968290d8163d31fc126543b11b76c46 Mon Sep 17 00:00:00 2001 From: MrZ626 <1046101471@qq.com> Date: Mon, 29 Mar 2021 12:29:52 +0800 Subject: [PATCH 18/83] =?UTF-8?q?ws=E7=B1=BB=E5=8A=A0=E5=85=A5=E5=8F=91?= =?UTF-8?q?=E9=80=81timer=E5=B9=B6=E4=BF=AE=E6=94=B9=E8=AF=BB=E5=8F=96?= =?UTF-8?q?=E6=96=B9=E6=B3=95=EF=BC=8C=E6=9B=B4=E6=B8=85=E6=99=B0=E7=9A=84?= =?UTF-8?q?ws=E7=8A=B6=E6=80=81=E5=B1=95=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Zframework/init.lua | 26 ++++++++++++++------------ Zframework/websocket.lua | 17 +++++++++-------- parts/texture.lua | 4 ++-- 3 files changed, 25 insertions(+), 22 deletions(-) diff --git a/Zframework/init.lua b/Zframework/init.lua index faf26cfe..28a333b9 100644 --- a/Zframework/init.lua +++ b/Zframework/init.lua @@ -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, @@ -587,19 +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 - gc_setColor(1,1,1,WS.getPongTimer(WSnames[i]))gc_rectangle("fill",0,20*i,-20,-20) - gc_setColor(1,0,0,WS.getAlertTimer(WSnames[i]))gc_rectangle("fill",-4,20*i-4,-12,-12) + 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() diff --git a/Zframework/websocket.lua b/Zframework/websocket.lua index e32b6b14..49389bfa 100644 --- a/Zframework/websocket.lua +++ b/Zframework/websocket.lua @@ -164,8 +164,9 @@ local wsList=setmetatable({},{ real=false, status="dead", lastPongTime=timer(), - pongTimer=0, + sendTimer=0, alertTimer=0, + pongTimer=0, } l[k]=ws return ws @@ -183,8 +184,9 @@ function WS.connect(name,subPath,body) lastPongTime=timer(), pingInterval=26, status="connecting",--connecting, running, dead - pongTimer=0, + sendTimer=0, alertTimer=0, + pongTimer=0, } wsList[name]=ws ws.thread:start(ws.triggerCHN,ws.sendCHN,ws.readCHN) @@ -199,12 +201,9 @@ function WS.status(name) return ws.status or"dead" end -function WS.getPongTimer(name) - return wsList[name].pongTimer -end - -function WS.getAlertTimer(name) - return wsList[name].alertTimer +function WS.getTimers(name) + local ws=wsList[name] + return ws.pongTimer,ws.sendTimer,ws.alertTimer end function WS.setPingInterval(name,time) @@ -239,6 +238,7 @@ function WS.send(name,message,op) ws.sendCHN:push(op and OPcode[op]or 2)--2=binary ws.sendCHN:push(message) ws.lastPingTime=timer() + ws.sendTimer=1 end end @@ -289,6 +289,7 @@ function WS.update(dt) if time-ws.lastPongTime>10+3*ws.pingInterval then WS.close(name) end + if ws.sendTimer>0 then ws.sendTimer=ws.sendTimer-dt end if ws.pongTimer>0 then ws.pongTimer=ws.pongTimer-dt end if ws.alertTimer>0 then ws.alertTimer=ws.alertTimer-dt end end diff --git a/parts/texture.lua b/parts/texture.lua index 4a2cb28f..f8631006 100644 --- a/parts/texture.lua +++ b/parts/texture.lua @@ -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) From 3001a60ee079e9b4d87f9dd8269f193b1939cef9 Mon Sep 17 00:00:00 2001 From: MrZ626 <1046101471@qq.com> Date: Mon, 29 Mar 2021 13:58:33 +0800 Subject: [PATCH 19/83] =?UTF-8?q?SCN.back=E4=BC=9A=E5=85=88=E6=A3=80?= =?UTF-8?q?=E6=B5=8B=E6=98=AF=E5=90=A6=E6=AD=A3=E5=9C=A8=E5=88=87=E6=8D=A2?= =?UTF-8?q?=E5=9C=BA=E6=99=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Zframework/scene.lua | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Zframework/scene.lua b/Zframework/scene.lua index 8a2bb951..c87ec688 100644 --- a/Zframework/scene.lua +++ b/Zframework/scene.lua @@ -152,6 +152,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 From 1ad3acb5a5ed26f461d556e39c72a8689e69b94a Mon Sep 17 00:00:00 2001 From: MrZ626 <1046101471@qq.com> Date: Mon, 29 Mar 2021 14:00:31 +0800 Subject: [PATCH 20/83] =?UTF-8?q?=E6=88=BF=E9=97=B4=E5=88=97=E8=A1=A8?= =?UTF-8?q?=E5=9C=BA=E6=99=AF=E7=9A=84rooms=E5=8F=98=E9=87=8F=E7=A7=BB?= =?UTF-8?q?=E5=85=A5NET=EF=BC=8C=E6=94=B9=E5=90=8DroomList=EF=BC=88?= =?UTF-8?q?=E7=94=A8=E4=BA=8E=E5=85=A8=E5=B1=80=E8=AF=BB=E5=86=99=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- parts/net.lua | 1 + parts/scenes/net_rooms.lua | 36 ++++++++++++++++++------------------ 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/parts/net.lua b/parts/net.lua index 05e05c95..bd51566e 100644 --- a/parts/net.lua +++ b/parts/net.lua @@ -2,6 +2,7 @@ local data=love.data local NET={ login=false, allow_online=false, + roomList=false, } --Account diff --git a/parts/scenes/net_rooms.lua b/parts/scenes/net_rooms.lua index 2037bd59..899a684f 100644 --- a/parts/scenes/net_rooms.lua +++ b/parts/scenes/net_rooms.lua @@ -1,14 +1,14 @@ local gc=love.graphics local min=math.min -local rooms +local NET=NET local scrollPos,selected local lastfreshTime local lastCreateRoomTime=0 -local function fresh() +local function freshRoomList() + NET.roomList=nil lastfreshTime=TIME() - rooms=nil NET.freshRoom() end @@ -18,7 +18,7 @@ function scene.sceneInit() BG.set("bg1") scrollPos=0 selected=1 - fresh() + freshRoomList() end function scene.wheelMoved(_,y) @@ -27,7 +27,7 @@ end function scene.keyDown(k) if k=="r"then if TIME()-lastfreshTime>1 then - fresh() + freshRoomList() end elseif k=="n"then if TIME()-lastCreateRoomTime>26 then @@ -38,9 +38,9 @@ function scene.keyDown(k) end elseif k=="escape"then SCN.back() - elseif rooms and #rooms>0 then + elseif NET.roomList and #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 @@ -54,34 +54,34 @@ function scene.keyDown(k) end end elseif k=="return"then - if rooms[selected].private then + if NET.roomList[selected].private then LOG.print("Can't enter private room now") return end - NET.enterRoom(rooms[selected].id)--,password + NET.enterRoom(NET.roomList[selected].id)--,password end end end function scene.update() if TIME()-lastfreshTime>5 then - fresh() + freshRoomList() end end function scene.draw() gc.setColor(1,1,1,.26) gc.arc("fill","pie",240,620,60,-1.5708,-1.5708+1.2566*(TIME()-lastfreshTime)) - if rooms then + if NET.roomList then gc.setColor(1,1,1) - if #rooms>0 then + if #NET.roomList>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] + 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.draw(IMG.lock,64,75+40*i) @@ -102,11 +102,11 @@ function scene.draw() 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.newKey{name="fresh", x=240,y=620,w=140,h=140,font=40,code=freshRoomList,hide=function()return TIME()-lastfreshTime<1.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 not NET.roomList end}, + WIDGET.newKey{name="up", x=840,y=585,w=140,h=70,font=40,code=pressKey"up",hide=function()return not NET.roomList end}, + WIDGET.newKey{name="down", x=840,y=655,w=140,h=70,font=40,code=pressKey"down",hide=function()return not NET.roomList end}, WIDGET.newButton{name="back", x=1140,y=640,w=170,h=80,font=40,code=backScene}, } From a439d55bf8aca5fa310ddfb2fdd7f6f7e566b7af Mon Sep 17 00:00:00 2001 From: MrZ626 <1046101471@qq.com> Date: Mon, 29 Mar 2021 14:07:37 +0800 Subject: [PATCH 21/83] =?UTF-8?q?=E6=95=B4=E7=90=86=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Zframework/init.lua | 2 +- parts/scenes/net_game.lua | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Zframework/init.lua b/Zframework/init.lua index 28a333b9..78213706 100644 --- a/Zframework/init.lua +++ b/Zframework/init.lua @@ -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 diff --git a/parts/scenes/net_game.lua b/parts/scenes/net_game.lua index de4f162c..65b9de34 100644 --- a/parts/scenes/net_game.lua +++ b/parts/scenes/net_game.lua @@ -260,7 +260,7 @@ function scene.update(dt) local _ local GAME=GAME - if WS.status("play")~="running"and not SCN.swapping then SCN.back()end + if WS.status("play")~="running"then SCN.back()end if not playing then return end touchMoveLastFrame=false From d1e074c1ca0a190fdd6fb11dbb25920e320b0ecb Mon Sep 17 00:00:00 2001 From: MrZ626 <1046101471@qq.com> Date: Mon, 29 Mar 2021 14:11:34 +0800 Subject: [PATCH 22/83] =?UTF-8?q?=E6=95=B4=E7=90=86=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=EF=BC=8C=E5=AE=9E=E7=8E=B0ws-app=E9=83=A8=E5=88=86=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=EF=BC=8C=E5=A2=9E=E5=BC=BAws-user?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- parts/gametoolfunc.lua | 151 +++++++++++++++++++---------------------- 1 file changed, 69 insertions(+), 82 deletions(-) diff --git a/parts/gametoolfunc.lua b/parts/gametoolfunc.lua index aa461149..51046fb6 100644 --- a/parts/gametoolfunc.lua +++ b/parts/gametoolfunc.lua @@ -1087,29 +1087,6 @@ do 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() @@ -1183,15 +1160,19 @@ do --Get self infos NET.getSelfInfo() - elseif res.action==0 then + elseif res.action==0 then--Get accessToken USER.accessToken=res.accessToken LOG.print(text.accessSuccessed) NET.wsConnectPlay() - elseif res.action==1 then - USER.name=res.username - USER.motto=res.motto - USER.avatar=res.avatar - FILE.save(USER,"conf/user") + elseif res.action==1 then--Get userInfo + if res.id==USER.id then--Own + USER.name=res.username + USER.motto=res.motto + USER.avatar=res.avatar + FILE.save(USER,"conf/user") + else--Others + LOG.print("Get user info: "..USER.id) + end end else WS.alert("user") @@ -1201,6 +1182,65 @@ do 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 + NET.pong("play",message) + elseif op=="pong"then + 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 then + if res.message=="Connected"then + SCN.go("net_menu") + elseif res.action==0 then--Fetch rooms + NET.roomList=res.roomList + elseif res.action==2 then--Join room + loadGame("netBattle",true,true) + elseif res.action==3 then--Leave room + SCN.back() + end + else + WS.alert("play") + end + 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 + NET.pong("stream",message) + elseif op=="pong"then + elseif op=="close"then + message=JSON.decode(message) + if message then + LOG.print(text.wsClose..message.message,"warn") + end + return + else + --TODO + end + end + end + end + end function TICK_WS_chat() while true do YIELD() @@ -1229,57 +1269,4 @@ do 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 - NET.pong("play",message) - elseif op=="pong"then - 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 then - if res.message=="Connected"then - SCN.go("net_menu") - end - else - WS.alert("play") - end - 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 - NET.pong("stream",message) - elseif op=="pong"then - elseif op=="close"then - message=JSON.decode(message) - if message then - LOG.print(text.wsClose..message.message,"warn") - end - return - else - --TODO - end - end - end - end - end end \ No newline at end of file From d37802185b4828e0e2f7b7e9f89b15bba221dfac Mon Sep 17 00:00:00 2001 From: MrZ626 <1046101471@qq.com> Date: Mon, 29 Mar 2021 15:16:23 +0800 Subject: [PATCH 23/83] =?UTF-8?q?NET=E6=B7=BB=E5=8A=A0=E6=93=8D=E4=BD=9C?= =?UTF-8?q?=E9=94=81=E4=BF=9D=E8=AF=81=E4=BB=BB=E5=8A=A1=E5=94=AF=E4=B8=80?= =?UTF-8?q?=EF=BC=8C=E5=BA=94=E7=94=A8=E7=BB=99=E9=83=A8=E5=88=86=E6=93=8D?= =?UTF-8?q?=E4=BD=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- parts/gametoolfunc.lua | 6 ++++ parts/net.lua | 62 ++++++++++++++++++++++++++++-------------- 2 files changed, 48 insertions(+), 20 deletions(-) diff --git a/parts/gametoolfunc.lua b/parts/gametoolfunc.lua index 51046fb6..e4475c93 100644 --- a/parts/gametoolfunc.lua +++ b/parts/gametoolfunc.lua @@ -1154,6 +1154,8 @@ do USER.id=res.id USER.authToken=res.authToken NET.getAccessToken() + else + SCN.back() end FILE.save(USER,"conf/user","q") LOG.print(text.loginSuccessed) @@ -1164,12 +1166,14 @@ do USER.accessToken=res.accessToken LOG.print(text.accessSuccessed) NET.wsConnectPlay() + NET.unlock("accessToken") elseif res.action==1 then--Get userInfo if res.id==USER.id then--Own USER.name=res.username USER.motto=res.motto USER.avatar=res.avatar FILE.save(USER,"conf/user") + NET.unlock("getSelfInfo") else--Others LOG.print("Get user info: "..USER.id) end @@ -1202,11 +1206,13 @@ do local res=JSON.decode(message) if res then if res.message=="Connected"then + NET.unlock("connectPlay") SCN.go("net_menu") elseif res.action==0 then--Fetch rooms NET.roomList=res.roomList elseif res.action==2 then--Join room loadGame("netBattle",true,true) + NET.unlock("enterRoom") elseif res.action==3 then--Leave room SCN.back() end diff --git a/parts/net.lua b/parts/net.lua index bd51566e..3883b3c3 100644 --- a/parts/net.lua +++ b/parts/net.lua @@ -5,28 +5,48 @@ local NET={ roomList=false, } +--Lock & Unlock submodule +local locks={} +function NET.lock(name,T) + if locks[name]and TIME() Date: Mon, 29 Mar 2021 15:29:42 +0800 Subject: [PATCH 24/83] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E7=99=BB=E5=BD=95?= =?UTF-8?q?=E6=B5=81=E7=A8=8B=E7=9A=84=E4=B8=80=E4=B8=AA=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- parts/gametoolfunc.lua | 2 -- 1 file changed, 2 deletions(-) diff --git a/parts/gametoolfunc.lua b/parts/gametoolfunc.lua index e4475c93..eeb15fab 100644 --- a/parts/gametoolfunc.lua +++ b/parts/gametoolfunc.lua @@ -1153,8 +1153,6 @@ do if res.id then USER.id=res.id USER.authToken=res.authToken - NET.getAccessToken() - else SCN.back() end FILE.save(USER,"conf/user","q") From 6b0f60d859f3a8107df230959f41b9f6fffffa8e Mon Sep 17 00:00:00 2001 From: MrZ626 <1046101471@qq.com> Date: Mon, 29 Mar 2021 17:54:27 +0800 Subject: [PATCH 25/83] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=9C=BA=E5=9C=B0?= =?UTF-8?q?=E7=BB=98=E5=88=B6=E4=BA=A4=E4=BA=92?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- parts/scenes/custom_field.lua | 160 +++++++++++++++++----------------- 1 file changed, 79 insertions(+), 81 deletions(-) diff --git a/parts/scenes/custom_field.lua b/parts/scenes/custom_field.lua index 4a059bcc..9ef1d67b 100644 --- a/parts/scenes/custom_field.lua +++ b/parts/scenes/custom_field.lua @@ -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 @@ -102,95 +104,89 @@ 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 + if y<0 then + penColor=penColor+1 + if penColor==25 then penColor=1 end + else + penColor=penColor-1 + if penColor==0 then penColor=24 end + end + 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 +256,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 +301,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 +323,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,1,1) 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,600-30*SPlist[i][2]) end end end @@ -347,16 +345,16 @@ function scene.draw() gc.rectangle("fill",50,600,100,6) --Draw pen color - if pen>0 then + if penColor>0 then gc.setLineWidth(13) - gc.setColor(minoColor[pen]) + gc.setColor(minoColor[penColor]) gc.rectangle("line",565,495,70,70) - elseif pen==-1 then + elseif penColor==-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 + elseif penColor==-2 then gc.setLineWidth(13) gc.setColor(COLOR.rainbow(TIME()*6.2)) gc.rectangle("line",565,495,70,70) @@ -382,7 +380,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"}, From d601aad274e9c2ab3ddb743e02e0227ed5033ae0 Mon Sep 17 00:00:00 2001 From: MrZ626 <1046101471@qq.com> Date: Tue, 30 Mar 2021 01:03:58 +0800 Subject: [PATCH 26/83] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dws=E5=BA=93=E4=B8=80?= =?UTF-8?q?=E4=B8=AA=E9=95=BF=E6=B6=88=E6=81=AF=E8=A7=A3=E7=A0=81=E9=94=99?= =?UTF-8?q?=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Zframework/websocket.lua | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Zframework/websocket.lua b/Zframework/websocket.lua index 49389bfa..84ec954b 100644 --- a/Zframework/websocket.lua +++ b/Zframework/websocket.lua @@ -120,9 +120,8 @@ while true do--Running 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] + local b={byte(SOCK:receive(8),1,8)} + length=shl(b[5],24)+shl(b[6],16)+shl(b[7],8)+b[8] end --Receive data From 306b627ef820cdb57b879e7d3c29593819a4d6e1 Mon Sep 17 00:00:00 2001 From: MrZ626 <1046101471@qq.com> Date: Tue, 30 Mar 2021 01:06:53 +0800 Subject: [PATCH 27/83] =?UTF-8?q?ws=E5=85=B3=E9=97=AD=E6=B6=88=E6=81=AF?= =?UTF-8?q?=E7=9A=84=E8=A7=A3=E6=9E=90=E4=BB=A3=E7=A0=81=E5=8D=87=E7=BA=A7?= =?UTF-8?q?=E5=B9=B6=E5=BD=92=E5=85=A5NET?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- parts/gametoolfunc.lua | 25 +++++-------------------- parts/net.lua | 10 ++++++++++ 2 files changed, 15 insertions(+), 20 deletions(-) diff --git a/parts/gametoolfunc.lua b/parts/gametoolfunc.lua index eeb15fab..d1034d4d 100644 --- a/parts/gametoolfunc.lua +++ b/parts/gametoolfunc.lua @@ -1101,10 +1101,7 @@ do NET.pong("app",message) elseif op=="pong"then elseif op=="close"then - message=JSON.decode(message) - if message then - LOG.print(text.wsClose..message.message,"warn") - end + NET.wsCloseMessage(message) return else local res=JSON.decode(message) @@ -1140,10 +1137,7 @@ do NET.pong("user",message) elseif op=="pong"then elseif op=="close"then - message=JSON.decode(message) - if message then - LOG.print(text.wsClose..message.message,"warn") - end + NET.wsCloseMessage(message) return else local res=JSON.decode(message) @@ -1195,10 +1189,7 @@ do NET.pong("play",message) elseif op=="pong"then elseif op=="close"then - message=JSON.decode(message) - if message then - LOG.print(text.wsClose..message.message,"warn") - end + NET.wsCloseMessage(message) return else local res=JSON.decode(message) @@ -1233,10 +1224,7 @@ do NET.pong("stream",message) elseif op=="pong"then elseif op=="close"then - message=JSON.decode(message) - if message then - LOG.print(text.wsClose..message.message,"warn") - end + NET.wsCloseMessage(message) return else --TODO @@ -1256,10 +1244,7 @@ do NET.pong("chat",message) elseif op=="pong"then elseif op=="close"then - message=JSON.decode(message) - if message then - LOG.print(text.wsClose..message.message,"warn") - end + NET.wsCloseMessage(message) return else local res=JSON.decode(message) diff --git a/parts/net.lua b/parts/net.lua index 3883b3c3..00d520c1 100644 --- a/parts/net.lua +++ b/parts/net.lua @@ -19,6 +19,16 @@ function NET.unlock(name) locks[name]=false end +--wsEvent +function NET.wsCloseMessage(message) + if message:sub(1,1)=="{"then + local mes=JSON.decode(message) + LOG.print(text.wsClose..mes.message,"warn") + else + LOG.print(text.wsClose..message,"warn") + end +end + --Account function NET.pong(wsName,message) WS.send(wsName,message,"pong") From 101636a60a0d8619379eef6e7b6674e050bfb0ed Mon Sep 17 00:00:00 2001 From: MrZ626 <1046101471@qq.com> Date: Tue, 30 Mar 2021 01:16:28 +0800 Subject: [PATCH 28/83] =?UTF-8?q?ws=E5=BA=93=E5=86=8D=E5=8D=87=E7=BA=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Zframework/websocket.lua | 65 +++++++++++++++++++++++++++------------- 1 file changed, 44 insertions(+), 21 deletions(-) diff --git a/Zframework/websocket.lua b/Zframework/websocket.lua index 84ec954b..ea0b52ea 100644 --- a/Zframework/websocket.lua +++ b/Zframework/websocket.lua @@ -93,7 +93,7 @@ do--Connect else readCHN:push(err) end - SOCK:settimeout(0) + SOCK:settimeout(6.26) end @@ -125,31 +125,54 @@ while true do--Running end --Receive data - res=SOCK:receive(length) + res="" + while length>0 do + local t=SOCK:receive(length) + if t then + res=res..t + length=length-#t + else--Time out! + res=false + break + end + end --React - if op==8 then--8=close - readCHN:push(op) - SOCK:close() - if type(res)=="string"then - local reason=JSON.decode(res) - readCHN:push(reason and reason.message or"Server Error") + if res then + if op==8 then--8=close + readCHN:push(op) + 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") + end + elseif op==0 then--0=continue + buffer=buffer..res + if fin then + -- print("FIN=1 (c") + readCHN:push(buffer) + buffer="" + else + -- print("FIN=0 (c") + end else - readCHN:push("Server Error") - end - elseif op==0 then - buffer=buffer..res - if fin then - readCHN:push(buffer) - buffer="" + readCHN:push(op) + if fin then + -- print("OP: "..op.."\tFIN=1") + readCHN:push(res) + else + -- print("OP: "..op.."\tFIN=0") + buffer=res + -- print("START pack: "..res) + end end else - readCHN:push(op) - if fin then - readCHN:push(res) - else - buffer=res - end + --TIMEOUT + SOCK:close() + readCHN:push(8) + readCHN:push("WS time out") end end end From 0efdb7dc338d279b8d26fc057151a6db02892126 Mon Sep 17 00:00:00 2001 From: MrZ626 <1046101471@qq.com> Date: Tue, 30 Mar 2021 10:46:23 +0800 Subject: [PATCH 29/83] =?UTF-8?q?=E8=B0=83=E6=95=B4=E8=BF=9B=E6=88=BF?= =?UTF-8?q?=E9=97=B4=E4=BB=BB=E5=8A=A1=E9=94=81=E6=9C=BA=E5=88=B6=EF=BC=8C?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=B8=80=E4=B8=AA=E8=AF=B7=E6=B1=82=E5=8F=82?= =?UTF-8?q?=E6=95=B0=E5=90=8D=E5=86=99=E9=94=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- parts/gametoolfunc.lua | 2 +- parts/net.lua | 22 ++++++++++++---------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/parts/gametoolfunc.lua b/parts/gametoolfunc.lua index d1034d4d..68747e1a 100644 --- a/parts/gametoolfunc.lua +++ b/parts/gametoolfunc.lua @@ -1199,7 +1199,7 @@ do SCN.go("net_menu") elseif res.action==0 then--Fetch rooms NET.roomList=res.roomList - elseif res.action==2 then--Join room + elseif res.action==2 then--Join(create) room loadGame("netBattle",true,true) NET.unlock("enterRoom") elseif res.action==3 then--Leave room diff --git a/parts/net.lua b/parts/net.lua index 00d520c1..6ef0bdc2 100644 --- a/parts/net.lua +++ b/parts/net.lua @@ -83,15 +83,17 @@ function NET.freshRoom() }) end function NET.createRoom() - WS.send("play",JSON.encode{ - action=1, - data={ - type="classic", - name=(USER.name or"???").."'s room", - password=nil, - conf=dumpBasicConfig(), - } - }) + if NET.lock("enterRoom")then + WS.send("play",JSON.encode{ + action=1, + data={ + type="classic", + name=(USER.name or"???").."'s room", + password=nil, + config=dumpBasicConfig(), + } + }) + end end function NET.enterRoom(roomID,password) if NET.lock("enterRoom")then @@ -99,7 +101,7 @@ function NET.enterRoom(roomID,password) action=2, data={ rid=roomID, - conf=dumpBasicConfig(), + config=dumpBasicConfig(), password=password, } }) From ec63618bead1547652fa01c6aa5408890d139969 Mon Sep 17 00:00:00 2001 From: MrZ626 <1046101471@qq.com> Date: Tue, 30 Mar 2021 12:02:51 +0800 Subject: [PATCH 30/83] =?UTF-8?q?=E6=95=B4=E7=90=86=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=EF=BC=8C=E9=80=82=E9=85=8D=E6=96=B0=E7=9A=84=E7=8E=A9=E5=AE=B6?= =?UTF-8?q?=E4=BF=A1=E6=81=AF=E6=8B=89=E5=8F=96=E6=9C=BA=E5=88=B6=EF=BC=8C?= =?UTF-8?q?=E4=BF=AE=E6=94=B9=E7=8E=A9=E5=AE=B6=E6=95=B0=E6=8D=AE=E4=BF=9D?= =?UTF-8?q?=E5=AD=98=E6=96=B9=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- parts/gametoolfunc.lua | 198 ----------------------------------------- parts/globalTables.lua | 3 +- parts/net.lua | 193 +++++++++++++++++++++++++++++++++++++-- parts/scenes/load.lua | 6 +- 4 files changed, 189 insertions(+), 211 deletions(-) diff --git a/parts/gametoolfunc.lua b/parts/gametoolfunc.lua index 68747e1a..33c83b19 100644 --- a/parts/gametoolfunc.lua +++ b/parts/gametoolfunc.lua @@ -1060,202 +1060,4 @@ do--CUS/SETXXX(k) 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 - - - ---Network funcs -do - --[[ - register: - if response.message=="OK"then - NET.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 - ]] - - 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 - NET.pong("app",message) - elseif op=="pong"then - elseif op=="close"then - NET.wsCloseMessage(message) - return - else - local res=JSON.decode(message) - if res then - if VERSION_CODE>=res.lowest then - NET.allow_online=true - end - if VERSION_CODE=res.lowest then + NET.allow_online=true + end + if VERSION_CODE Date: Tue, 30 Mar 2021 12:03:00 +0800 Subject: [PATCH 31/83] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E4=B8=80=E4=BA=9Btip?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- parts/language/lang_zh.lua | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/parts/language/lang_zh.lua b/parts/language/lang_zh.lua index 331f6ae9..9ab032d9 100644 --- a/parts/language/lang_zh.lua +++ b/parts/language/lang_zh.lua @@ -763,11 +763,13 @@ return{ }, getTip={refuseCopy=true, "...,合群了就会消失,不合群世界毁灭(指game over", - "...,合群了就会消失,但消失并非没有意义", + "...,合群了就会消失,但消失不代表没有意义", "(a+b)³=a³+3a²b+3ab²+b³", "(RUR'U')R'FR2U'R'U'(RUR'F')", + "《多练的力量》", + "《天赋的力量》", "《知识的力量》", - "\"TechOS\"", + "\"TechminOS\"", "↑↑↓↓←→←→BA", "$include", "0next 0hold.", @@ -824,6 +826,7 @@ return{ "方块不能吃", "方块教会我们,合群了就会消失,...", "方块默认出现的方向都是重心在下哦", + "方块能吃吗", "服务器随时爆炸", "感觉自己明明按键了但是没反应?你真的按到了吗?", "感觉自己速度到上限了?试着把das调低一点", From 1af58efad5da0392c412903628e01a58c7537023 Mon Sep 17 00:00:00 2001 From: MrZ626 <1046101471@qq.com> Date: Tue, 30 Mar 2021 12:12:09 +0800 Subject: [PATCH 32/83] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=87=A0=E4=B8=AAunpac?= =?UTF-8?q?k=E8=B0=83=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Zframework/scene.lua | 3 ++- Zframework/widget.lua | 6 ++++-- parts/player/player.lua | 4 ++-- parts/scenes/app_ten.lua | 3 ++- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/Zframework/scene.lua b/Zframework/scene.lua index c87ec688..022f8886 100644 --- a/Zframework/scene.lua +++ b/Zframework/scene.lua @@ -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") diff --git a/Zframework/widget.lua b/Zframework/widget.lua index da7fb784..2a8e379f 100644 --- a/Zframework/widget.lua +++ b/Zframework/widget.lua @@ -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) diff --git a/parts/player/player.lua b/parts/player/player.lua index ebc30661..2a294017 100644 --- a/parts/player/player.lua +++ b/parts/player/player.lua @@ -106,8 +106,8 @@ function Player:createBeam(R,send,color) else x2,y2=R.x+308*R.size,R.y+450*R.size end - local r,g,b=unpack(minoColor[color]) - r,g,b=r*2,g*2,b*2 + local c=minoColor[color] + local r,g,b=c[1]*2,c[2]*2,c[3]*2 local a=GAME.modeEnv.royaleMode and not(self.type=="human"or R.type=="human")and .2 or 1 SYSFX.newAttack(1-SETTING.atkFX*.1,x1,y1,x2,y2,int(send^.7*(4+SETTING.atkFX)),r,g,b,a*(SETTING.atkFX+2)*.0626) diff --git a/parts/scenes/app_ten.lua b/parts/scenes/app_ten.lua index c4c47881..46e3ebfa 100644 --- a/parts/scenes/app_ten.lua +++ b/parts/scenes/app_ten.lua @@ -76,7 +76,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) From ef64e0f6ef5b21d865556ba0ec0a609eb43ca66b Mon Sep 17 00:00:00 2001 From: MrZ626 <1046101471@qq.com> Date: Tue, 30 Mar 2021 12:46:58 +0800 Subject: [PATCH 33/83] =?UTF-8?q?=E6=95=B4=E7=90=86=E7=BD=91=E7=BB=9C?= =?UTF-8?q?=E5=92=8C=E7=94=A8=E6=88=B7=E7=9B=B8=E5=85=B3=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- parts/globalTables.lua | 2 -- parts/net.lua | 24 ++++++++++++++++-------- parts/scenes/login.lua | 1 - 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/parts/globalTables.lua b/parts/globalTables.lua index 229a87d7..d26a094a 100644 --- a/parts/globalTables.lua +++ b/parts/globalTables.lua @@ -223,9 +223,7 @@ USER=FILE.load("conf/user")or{--User infomation --Network infos name=false, id=false, - email=false, authToken=false, - accessToken=false, --Local data xp=0,lv=1, diff --git a/parts/net.lua b/parts/net.lua index 90c5f17e..55570983 100644 --- a/parts/net.lua +++ b/parts/net.lua @@ -3,6 +3,7 @@ local NET={ login=false, allow_online=false, roomList=false, + accessToken=false, } --Lock & Unlock submodule @@ -48,17 +49,25 @@ function NET.getUserInfo(id,ifDetail) }) end function NET.storeUserInfo(res) - local user - if not USERS[res.id]then + local user=USERS[res.id] + if not user then user={} user.email=res.email user.name=res.username USERS[res.id]=user else - user=USERS[res.id] + 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.id==USER.id then + USER.name=res.name + FILE.save(USER,"conf/user") + end + -- FILE.save(USERS,"conf/users") end @@ -67,7 +76,7 @@ function NET.wsConnectPlay() if NET.lock("connectPlay")then WS.connect("play","/play",JSON.encode{ id=USER.id, - accessToken=USER.accessToken, + accessToken=NET.accessToken, }) end end @@ -188,21 +197,20 @@ function NET.TICK_WS_user() if res.id then USER.id=res.id USER.authToken=res.authToken + FILE.save(USER,"conf/user","q") SCN.back() end - FILE.save(USER,"conf/user","q") LOG.print(text.loginSuccessed) --Get self infos - NET.getUserInfo() + NET.getUserInfo(USER.id) elseif res.action==0 then--Get accessToken - USER.accessToken=res.accessToken + NET.accessToken=res.accessToken LOG.print(text.accessSuccessed) NET.wsConnectPlay() NET.unlock("accessToken") elseif res.action==1 then--Get userInfo NET.storeUserInfo(res) - FILE.save(USER,"conf/user") end else WS.alert("user") diff --git a/parts/scenes/login.lua b/parts/scenes/login.lua index 4885f58b..d6517847 100644 --- a/parts/scenes/login.lua +++ b/parts/scenes/login.lua @@ -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, From 0e4f04d091a18c4d14831c36d6da4ecc53f1429b Mon Sep 17 00:00:00 2001 From: MrZ626 <1046101471@qq.com> Date: Tue, 30 Mar 2021 13:48:40 +0800 Subject: [PATCH 34/83] =?UTF-8?q?=E5=A2=9E=E5=8A=A0ws=E7=8A=B6=E6=80=81?= =?UTF-8?q?=E6=98=BE=E7=A4=BAalert=E7=9A=84=E6=97=B6=E9=97=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Zframework/websocket.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Zframework/websocket.lua b/Zframework/websocket.lua index ea0b52ea..58f1fb99 100644 --- a/Zframework/websocket.lua +++ b/Zframework/websocket.lua @@ -235,7 +235,7 @@ end function WS.alert(name) local ws=wsList[name] - ws.alertTimer=1 + ws.alertTimer=2 end local OPcode={ From 38a91ce351fea52979d8afd159570c921204f131 Mon Sep 17 00:00:00 2001 From: MrZ626 <1046101471@qq.com> Date: Tue, 30 Mar 2021 13:49:36 +0800 Subject: [PATCH 35/83] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=B8=A4=E5=A4=84WS.se?= =?UTF-8?q?nd=E4=BD=BF=E7=94=A8=E9=94=99=E8=AF=AF=EF=BC=8C=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0NET.parse=E5=87=BD=E6=95=B0=E7=94=A8=E4=BA=8E=E7=BB=9F?= =?UTF-8?q?=E4=B8=80=E8=BF=87=E6=BB=A4=E5=B9=B6=E6=89=93=E5=8D=B0=E9=94=99?= =?UTF-8?q?=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- parts/net.lua | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/parts/net.lua b/parts/net.lua index 55570983..c3fff6d3 100644 --- a/parts/net.lua +++ b/parts/net.lua @@ -20,6 +20,18 @@ function NET.unlock(name) locks[name]=false end +--messageParse +function NET.parse(res) + res=JSON.decode(res) + if res then + if res.message=="OK"or res.message=="Connected"then + return res + else + LOG.print(res.message and res.message..": "..(res.reason or"[NO reason]")or"[NO Message]","warning") + end + end +end + --wsEvent function NET.wsCloseMessage(message) if message:sub(1,1)=="{"then @@ -95,7 +107,7 @@ end --Room function NET.freshRoom() - WS.send("play","/play",JSON.encode{ + WS.send("play",JSON.encode{ action=0, data={ type=nil, @@ -119,7 +131,7 @@ function NET.createRoom() end function NET.enterRoom(roomID,password) if NET.lock("enterRoom")then - WS.send("play","/play",JSON.encode{ + WS.send("play",JSON.encode{ action=2, data={ rid=roomID, @@ -154,7 +166,7 @@ function NET.TICK_WS_app() NET.wsCloseMessage(message) return else - local res=JSON.decode(message) + local res=NET.parse(message) if res then if VERSION_CODE>=res.lowest then NET.allow_online=true @@ -190,7 +202,7 @@ function NET.TICK_WS_user() NET.wsCloseMessage(message) return else - local res=JSON.decode(message) + local res=NET.parse(message) if res then if res.message=="Connected"then NET.login=true @@ -234,7 +246,7 @@ function NET.TICK_WS_play() NET.wsCloseMessage(message) return else - local res=JSON.decode(message) + local res=NET.parse(message) if res then if res.message=="Connected"then NET.unlock("connectPlay") @@ -242,7 +254,7 @@ function NET.TICK_WS_play() elseif res.action==0 then--Fetch rooms NET.roomList=res.roomList elseif res.action==2 then--Join(create) room - loadGame("netBattle",true,true) + -- loadGame("netBattle",true,true) NET.unlock("enterRoom") elseif res.action==3 then--Leave room SCN.back() @@ -289,7 +301,7 @@ function NET.TICK_WS_chat() NET.wsCloseMessage(message) return else - local res=JSON.decode(message) + local res=NET.parse(message) if res then --TODO else From a1c44bab40912960543174287635ab3d1a2baec1 Mon Sep 17 00:00:00 2001 From: MrZ626 <1046101471@qq.com> Date: Tue, 30 Mar 2021 14:20:07 +0800 Subject: [PATCH 36/83] =?UTF-8?q?NET=E9=87=8C=E7=9A=84=E4=B8=8A=E4=B8=8B?= =?UTF-8?q?=E9=94=81=E5=92=8Cparse=E6=94=B9=E4=B8=BA=E5=86=85=E9=83=A8?= =?UTF-8?q?=E5=87=BD=E6=95=B0=EF=BC=8Cparse=E8=83=BD=E6=8E=A5=E5=8F=97?= =?UTF-8?q?=E6=9C=8D=E5=8A=A1=E5=99=A8=E6=9B=B4=E5=A4=9A=E7=B1=BB=E5=9E=8B?= =?UTF-8?q?=E7=9A=84=E6=B6=88=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- parts/net.lua | 47 ++++++++++++++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/parts/net.lua b/parts/net.lua index c3fff6d3..3976d506 100644 --- a/parts/net.lua +++ b/parts/net.lua @@ -6,9 +6,16 @@ local NET={ accessToken=false, } +local mesType={ + OK=true, + Connected=true, + Server=true, + Broadcast=true, +} + --Lock & Unlock submodule local locks={} -function NET.lock(name,T) +local function _lock(name,T) if locks[name]and TIME()=res.lowest then NET.allow_online=true @@ -202,7 +215,7 @@ function NET.TICK_WS_user() NET.wsCloseMessage(message) return else - local res=NET.parse(message) + local res=_parse(message) if res then if res.message=="Connected"then NET.login=true @@ -220,7 +233,7 @@ function NET.TICK_WS_user() NET.accessToken=res.accessToken LOG.print(text.accessSuccessed) NET.wsConnectPlay() - NET.unlock("accessToken") + _unlock("accessToken") elseif res.action==1 then--Get userInfo NET.storeUserInfo(res) end @@ -246,16 +259,16 @@ function NET.TICK_WS_play() NET.wsCloseMessage(message) return else - local res=NET.parse(message) + local res=_parse(message) if res then if res.message=="Connected"then - NET.unlock("connectPlay") + _unlock("connectPlay") SCN.go("net_menu") elseif res.action==0 then--Fetch rooms NET.roomList=res.roomList elseif res.action==2 then--Join(create) room -- loadGame("netBattle",true,true) - NET.unlock("enterRoom") + _unlock("enterRoom") elseif res.action==3 then--Leave room SCN.back() end @@ -301,7 +314,7 @@ function NET.TICK_WS_chat() NET.wsCloseMessage(message) return else - local res=NET.parse(message) + local res=_parse(message) if res then --TODO else From 20f031fcb47c8df3fa019ee321a3c8ab96ff0b51 Mon Sep 17 00:00:00 2001 From: MrZ626 <1046101471@qq.com> Date: Tue, 30 Mar 2021 14:51:28 +0800 Subject: [PATCH 37/83] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dws=E6=A8=A1=E5=9D=97?= =?UTF-8?q?=E6=9C=89=E4=B8=80=E4=B8=AA=E6=8F=A1=E6=89=8B=E9=94=99=E8=AF=AF?= =?UTF-8?q?=E4=BC=9A=E5=AF=BC=E8=87=B4=E6=8A=A5=E9=94=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Zframework/websocket.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Zframework/websocket.lua b/Zframework/websocket.lua index 58f1fb99..7e26ef64 100644 --- a/Zframework/websocket.lua +++ b/Zframework/websocket.lua @@ -88,7 +88,7 @@ do--Connect readCHN:push("success") else local reason=JSON.decode(SOCK:receive(ctLen)) - readCHN:push(code..":"..(reason and reason.message or"Server Error")) + readCHN:push((code or"???")..":"..(reason and reason.message or"Server Error")) end else readCHN:push(err) From 23c0c63c6ad74656721fa03376d0b2cd3f4316ca Mon Sep 17 00:00:00 2001 From: MrZ626 <1046101471@qq.com> Date: Tue, 30 Mar 2021 14:55:46 +0800 Subject: [PATCH 38/83] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=88=B7=E6=96=B0?= =?UTF-8?q?=E6=88=BF=E9=97=B4=E7=9B=B8=E5=85=B3=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- parts/language/lang_en.lua | 2 +- parts/language/lang_fr.lua | 2 +- parts/language/lang_pt.lua | 2 +- parts/language/lang_sp.lua | 2 +- parts/language/lang_zh.lua | 2 +- parts/net.lua | 26 +++++++----- parts/scenes/net_rooms.lua | 84 +++++++++++++++++++------------------- 7 files changed, 64 insertions(+), 56 deletions(-) diff --git a/parts/language/lang_en.lua b/parts/language/lang_en.lua index 160ded7a..1da1c1d5 100644 --- a/parts/language/lang_en.lua +++ b/parts/language/lang_en.lua @@ -252,7 +252,7 @@ return{ chat="Chat", }, net_rooms={ - fresh="Reresh", + refresh="Refresh", new="New Room", join="Join", up="↑", diff --git a/parts/language/lang_fr.lua b/parts/language/lang_fr.lua index b6388b74..f62c004b 100644 --- a/parts/language/lang_fr.lua +++ b/parts/language/lang_fr.lua @@ -225,7 +225,7 @@ return{ chat="Chat", }, net_rooms={ - fresh="Fresh", + -- refresh="Refresh", new="Nouveau salon", join="Rejoindre", up="↑", diff --git a/parts/language/lang_pt.lua b/parts/language/lang_pt.lua index 37005e29..ed69e24d 100644 --- a/parts/language/lang_pt.lua +++ b/parts/language/lang_pt.lua @@ -252,7 +252,7 @@ return{ chat="Chat", }, net_rooms={ - fresh="Fresh", + -- refresh="Refresh", -- new="New room", -- join="Join", up="↑", diff --git a/parts/language/lang_sp.lua b/parts/language/lang_sp.lua index 5eaf9e87..09ada05e 100644 --- a/parts/language/lang_sp.lua +++ b/parts/language/lang_sp.lua @@ -231,7 +231,7 @@ return{ -- chat="Chat", }, net_rooms={ - -- fresh="Fresh", + -- refresh="Refresh", -- new="New room", -- join="Join", up="↑", diff --git a/parts/language/lang_zh.lua b/parts/language/lang_zh.lua index 9ab032d9..851a7130 100644 --- a/parts/language/lang_zh.lua +++ b/parts/language/lang_zh.lua @@ -252,7 +252,7 @@ return{ chat="聊天室", }, net_rooms={ - fresh="刷新", + refresh="刷新", new="创建房间", join="加入", up="↑", diff --git a/parts/net.lua b/parts/net.lua index 3976d506..61421dc0 100644 --- a/parts/net.lua +++ b/parts/net.lua @@ -2,7 +2,7 @@ local data=love.data local NET={ login=false, allow_online=false, - roomList=false, + roomList={}, accessToken=false, } @@ -26,6 +26,9 @@ end local function _unlock(name) locks[name]=false end +function NET.getLock(name) + return locks[name] +end --Parse json message local function _parse(res) @@ -119,15 +122,17 @@ function NET.signal_quit() end --Room -function NET.freshRoom() - WS.send("play",JSON.encode{ - action=0, - data={ - type=nil, - begin=0, - count=10, - } - }) +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 @@ -266,6 +271,7 @@ function NET.TICK_WS_play() SCN.go("net_menu") elseif res.action==0 then--Fetch rooms NET.roomList=res.roomList + _unlock("fetchRoom") elseif res.action==2 then--Join(create) room -- loadGame("netBattle",true,true) _unlock("enterRoom") diff --git a/parts/scenes/net_rooms.lua b/parts/scenes/net_rooms.lua index 899a684f..2fb0ae17 100644 --- a/parts/scenes/net_rooms.lua +++ b/parts/scenes/net_rooms.lua @@ -3,13 +3,12 @@ local min=math.min local NET=NET local scrollPos,selected -local lastfreshTime +local lastFetchTime local lastCreateRoomTime=0 -local function freshRoomList() - NET.roomList=nil - lastfreshTime=TIME() - NET.freshRoom() +local function fetchRoom() + lastFetchTime=TIME() + NET.fetchRoom() end local scene={} @@ -18,7 +17,7 @@ function scene.sceneInit() BG.set("bg1") scrollPos=0 selected=1 - freshRoomList() + fetchRoom() end function scene.wheelMoved(_,y) @@ -26,8 +25,8 @@ function scene.wheelMoved(_,y) end function scene.keyDown(k) if k=="r"then - if TIME()-lastfreshTime>1 then - freshRoomList() + if TIME()-lastFetchTime>1 then + fetchRoom() end elseif k=="n"then if TIME()-lastCreateRoomTime>26 then @@ -38,7 +37,7 @@ function scene.keyDown(k) end elseif k=="escape"then SCN.back() - elseif NET.roomList and #NET.roomList>0 then + elseif #NET.roomList>0 then if k=="down"then if selected<#NET.roomList then selected=selected+1 @@ -54,6 +53,7 @@ function scene.keyDown(k) end end elseif k=="return"then + if NET.getLock("fetchRoom")then return end if NET.roomList[selected].private then LOG.print("Can't enter private room now") return @@ -64,49 +64,51 @@ function scene.keyDown(k) end function scene.update() - if TIME()-lastfreshTime>5 then - freshRoomList() + if TIME()-lastFetchTime>5 then + fetchRoom() 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 NET.roomList then - gc.setColor(1,1,1) - if #NET.roomList>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,#NET.roomList-scrollPos)do - local R=NET.roomList[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.setColor(1,1,1) - gc.printf(R.type,500,66+40*i,500,"right") - gc.print(R.count.."/"..R.capacity,1050,66+40*i) - end - else - setFont(60) - mStr(text.noRooms,640,315) + gc.arc("fill","pie",240,620,60,-1.5708,-1.5708+1.2566*(TIME()-lastFetchTime)) + + --Room list + gc.setColor(1,1,1) + 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,#NET.roomList-scrollPos)do + local R=NET.roomList[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.setColor(1,1,1) + gc.printf(R.type,500,66+40*i,500,"right") + gc.print(R.count.."/"..R.capacity,1050,66+40*i) + end + + --No room message + if #NET.roomList==0 then + setFont(60) + mStr(text.noRooms,640,315) end end scene.widgetList={ - WIDGET.newKey{name="fresh", x=240,y=620,w=140,h=140,font=40,code=freshRoomList,hide=function()return TIME()-lastfreshTime<1.26 end}, + WIDGET.newKey{name="refresh", x=240,y=620,w=140,h=140,font=40,code=fetchRoom, hide=function()return TIME()-lastFetchTime<1.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 NET.roomList end}, - WIDGET.newKey{name="up", x=840,y=585,w=140,h=70,font=40,code=pressKey"up",hide=function()return not NET.roomList end}, - WIDGET.newKey{name="down", x=840,y=655,w=140,h=70,font=40,code=pressKey"down",hide=function()return not NET.roomList 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}, } From 4a9066b1cb83c3d4ce0678deab9445743df77cab Mon Sep 17 00:00:00 2001 From: MrZ626 <1046101471@qq.com> Date: Tue, 30 Mar 2021 15:22:50 +0800 Subject: [PATCH 39/83] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=88=B7=E6=96=B0?= =?UTF-8?q?=E6=88=BF=E9=97=B4=E7=9A=84=E5=8A=A8=E7=94=BB=E6=8F=90=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- parts/language/lang_en.lua | 3 ++- parts/language/lang_fr.lua | 4 ++-- parts/language/lang_pt.lua | 3 ++- parts/language/lang_sp.lua | 3 ++- parts/language/lang_zh.lua | 3 ++- parts/scenes/net_rooms.lua | 27 +++++++++++++-------------- 6 files changed, 23 insertions(+), 20 deletions(-) diff --git a/parts/language/lang_en.lua b/parts/language/lang_en.lua index 1da1c1d5..e655a523 100644 --- a/parts/language/lang_en.lua +++ b/parts/language/lang_en.lua @@ -106,7 +106,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,6 +251,8 @@ return{ chat="Chat", }, net_rooms={ + refreshing="Refreshing Rooms", + noRooms="Such emptiness much void, come back later?", refresh="Refresh", new="New Room", join="Join", diff --git a/parts/language/lang_fr.lua b/parts/language/lang_fr.lua index f62c004b..1cee3d4b 100644 --- a/parts/language/lang_fr.lua +++ b/parts/language/lang_fr.lua @@ -107,7 +107,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", @@ -225,8 +224,9 @@ return{ chat="Chat", }, net_rooms={ + -- refreshing="Refreshing Rooms", + noRooms="Aucun salon actuellement", -- refresh="Refresh", - new="Nouveau salon", join="Rejoindre", up="↑", down="↓", diff --git a/parts/language/lang_pt.lua b/parts/language/lang_pt.lua index ed69e24d..b3e6d8a6 100644 --- a/parts/language/lang_pt.lua +++ b/parts/language/lang_pt.lua @@ -106,7 +106,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,6 +251,8 @@ return{ chat="Chat", }, net_rooms={ + -- refreshing="Refreshing Rooms", + noRooms="Nenhuma sala agora", -- refresh="Refresh", -- new="New room", -- join="Join", diff --git a/parts/language/lang_sp.lua b/parts/language/lang_sp.lua index 09ada05e..8fd51e56 100644 --- a/parts/language/lang_sp.lua +++ b/parts/language/lang_sp.lua @@ -108,7 +108,6 @@ return{ -- chatStart="------Beginning of log------", -- chatHistory="------New messages below------", - -- noRooms="No Rooms Now", -- roomsCreateFailed="Failed to create room", -- roomsFetchFailed="Failed to fetch rooms", @@ -231,6 +230,8 @@ return{ -- chat="Chat", }, net_rooms={ + -- refreshing="Refreshing Rooms", + -- noRooms="No Rooms Now", -- refresh="Refresh", -- new="New room", -- join="Join", diff --git a/parts/language/lang_zh.lua b/parts/language/lang_zh.lua index 851a7130..7545f36e 100644 --- a/parts/language/lang_zh.lua +++ b/parts/language/lang_zh.lua @@ -106,7 +106,6 @@ return{ chatStart="------消息的开头------", chatHistory="------以上是历史消息------", - noRooms="一个房间都没有哎...", roomsCreateFailed="创建房间失败", roomsFetchFailed="拉取房间列表失败", @@ -252,6 +251,8 @@ return{ chat="聊天室", }, net_rooms={ + refreshing="刷新房间列表中", + noRooms="一个房间都没有哎...", refresh="刷新", new="创建房间", join="加入", diff --git a/parts/scenes/net_rooms.lua b/parts/scenes/net_rooms.lua index 2fb0ae17..18f182b4 100644 --- a/parts/scenes/net_rooms.lua +++ b/parts/scenes/net_rooms.lua @@ -3,11 +3,11 @@ local min=math.min local NET=NET local scrollPos,selected -local lastFetchTime +local fetchTimer local lastCreateRoomTime=0 local function fetchRoom() - lastFetchTime=TIME() + fetchTimer=5 NET.fetchRoom() end @@ -25,7 +25,7 @@ function scene.wheelMoved(_,y) end function scene.keyDown(k) if k=="r"then - if TIME()-lastFetchTime>1 then + if fetchTimer<=0 then fetchRoom() end elseif k=="n"then @@ -63,16 +63,19 @@ function scene.keyDown(k) end end -function scene.update() - if TIME()-lastFetchTime>5 then - fetchRoom() +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()-lastFetchTime)) + gc.arc("fill","pie",240,620,60,-1.5708,-1.5708-1.2566*fetchTimer) --Room list gc.setColor(1,1,1) @@ -95,16 +98,12 @@ function scene.draw() gc.printf(R.type,500,66+40*i,500,"right") gc.print(R.count.."/"..R.capacity,1050,66+40*i) end - - --No room message - if #NET.roomList==0 then - setFont(60) - mStr(text.noRooms,640,315) - end end scene.widgetList={ - WIDGET.newKey{name="refresh", x=240,y=620,w=140,h=140,font=40,code=fetchRoom, hide=function()return TIME()-lastFetchTime<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=65,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 #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}, From 53607f6fe7b3701fd9dcbd2ecec3a12b5257a6a4 Mon Sep 17 00:00:00 2001 From: MrZ626 <1046101471@qq.com> Date: Wed, 31 Mar 2021 21:38:09 +0800 Subject: [PATCH 40/83] =?UTF-8?q?=E5=AE=8C=E5=96=84TABLE=E6=89=A9=E5=B1=95?= =?UTF-8?q?=E6=A8=A1=E5=9D=97=E7=9A=84=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Zframework/tableExtend.lua | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/Zframework/tableExtend.lua b/Zframework/tableExtend.lua index 120241fd..bbd8c8e7 100644 --- a/Zframework/tableExtend.lua +++ b/Zframework/tableExtend.lua @@ -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,7 +26,9 @@ 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.add(G,base) for k,v in next,G do if type(v)==type(base[k])then if type(v)=="table"then @@ -33,7 +39,9 @@ function TABLE.add(G,base)--For all things in G if same type in base, push to ba 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,8 @@ function TABLE.complete(G,base)--For all things in G if no val in base, push to end end end + +--Re-index string value of a table function TABLE.reIndex(org) for k,v in next,org do if type(v)=="string"then From 027e16f67628856173f2138034f201d62649113a Mon Sep 17 00:00:00 2001 From: MrZ626 <1046101471@qq.com> Date: Wed, 31 Mar 2021 22:48:15 +0800 Subject: [PATCH 41/83] =?UTF-8?q?=E8=AF=8D=E5=85=B8=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E6=BB=9A=E8=BD=AE=E5=92=8Cpgup/pgdown=E5=BF=AB=E9=80=9F?= =?UTF-8?q?=E7=BF=BB=E9=A1=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- parts/scenes/dict.lua | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/parts/scenes/dict.lua b/parts/scenes/dict.lua index 2d8b088f..9ae92356 100644 --- a/parts/scenes/dict.lua +++ b/parts/scenes/dict.lua @@ -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 From a7133e92d828557564752dbcfe5a157090bd2341 Mon Sep 17 00:00:00 2001 From: MrZ626 <1046101471@qq.com> Date: Thu, 1 Apr 2021 02:42:51 +0800 Subject: [PATCH 42/83] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=88=BF=E9=97=B4?= =?UTF-8?q?=E5=88=97=E8=A1=A8R=E9=94=AE=E5=88=B7=E6=96=B0=E9=97=AE?= =?UTF-8?q?=E9=A2=98=E5=92=8CnoRoom=E6=96=87=E6=9C=AC=E4=B8=8D=E5=AF=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- parts/language/lang_en.lua | 2 +- parts/language/lang_fr.lua | 2 +- parts/language/lang_pt.lua | 2 +- parts/language/lang_sp.lua | 2 +- parts/language/lang_zh.lua | 2 +- parts/scenes/net_rooms.lua | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/parts/language/lang_en.lua b/parts/language/lang_en.lua index e655a523..1dfcf38f 100644 --- a/parts/language/lang_en.lua +++ b/parts/language/lang_en.lua @@ -252,7 +252,7 @@ return{ }, net_rooms={ refreshing="Refreshing Rooms", - noRooms="Such emptiness much void, come back later?", + noRoom="Such emptiness much void, come back later?", refresh="Refresh", new="New Room", join="Join", diff --git a/parts/language/lang_fr.lua b/parts/language/lang_fr.lua index 1cee3d4b..5cecb95c 100644 --- a/parts/language/lang_fr.lua +++ b/parts/language/lang_fr.lua @@ -225,7 +225,7 @@ return{ }, net_rooms={ -- refreshing="Refreshing Rooms", - noRooms="Aucun salon actuellement", + noRoom="Aucun salon actuellement", -- refresh="Refresh", join="Rejoindre", up="↑", diff --git a/parts/language/lang_pt.lua b/parts/language/lang_pt.lua index b3e6d8a6..7fb3f716 100644 --- a/parts/language/lang_pt.lua +++ b/parts/language/lang_pt.lua @@ -252,7 +252,7 @@ return{ }, net_rooms={ -- refreshing="Refreshing Rooms", - noRooms="Nenhuma sala agora", + noRoom="Nenhuma sala agora", -- refresh="Refresh", -- new="New room", -- join="Join", diff --git a/parts/language/lang_sp.lua b/parts/language/lang_sp.lua index 8fd51e56..6854aef4 100644 --- a/parts/language/lang_sp.lua +++ b/parts/language/lang_sp.lua @@ -231,7 +231,7 @@ return{ }, net_rooms={ -- refreshing="Refreshing Rooms", - -- noRooms="No Rooms Now", + -- noRoom="No Rooms Now", -- refresh="Refresh", -- new="New room", -- join="Join", diff --git a/parts/language/lang_zh.lua b/parts/language/lang_zh.lua index 7545f36e..fe42e453 100644 --- a/parts/language/lang_zh.lua +++ b/parts/language/lang_zh.lua @@ -252,7 +252,7 @@ return{ }, net_rooms={ refreshing="刷新房间列表中", - noRooms="一个房间都没有哎...", + noRoom="一个房间都没有哎...", refresh="刷新", new="创建房间", join="加入", diff --git a/parts/scenes/net_rooms.lua b/parts/scenes/net_rooms.lua index 18f182b4..a999ce64 100644 --- a/parts/scenes/net_rooms.lua +++ b/parts/scenes/net_rooms.lua @@ -25,7 +25,7 @@ function scene.wheelMoved(_,y) end function scene.keyDown(k) if k=="r"then - if fetchTimer<=0 then + if fetchTimer<=3.26 then fetchRoom() end elseif k=="n"then From 5e0d640c2f2e6a1c0f91fce64786dc98b5f6daa4 Mon Sep 17 00:00:00 2001 From: MrZ626 <1046101471@qq.com> Date: Thu, 1 Apr 2021 02:53:11 +0800 Subject: [PATCH 43/83] =?UTF-8?q?=E5=A4=A7=E6=94=B9websocket=E6=A8=A1?= =?UTF-8?q?=E5=9D=97=E7=9A=84=E7=BA=BF=E7=A8=8B=E9=83=A8=E5=88=86=EF=BC=8C?= =?UTF-8?q?=E4=BC=98=E5=8C=96=E9=80=BB=E8=BE=91=E5=92=8C=E6=93=8D=E4=BD=9C?= =?UTF-8?q?=E5=AE=89=E5=85=A8=E3=80=82=E6=94=AF=E6=8C=81=E5=A4=9A=E5=B8=A7?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=EF=BC=88=E9=9C=80=E8=A6=81=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Zframework/websocket.lua | 197 ++++++++++++++++++++++----------------- 1 file changed, 110 insertions(+), 87 deletions(-) diff --git a/Zframework/websocket.lua b/Zframework/websocket.lua index 7e26ef64..f567aa18 100644 --- a/Zframework/websocket.lua +++ b/Zframework/websocket.lua @@ -6,17 +6,17 @@ local path="/tech/socket/v1" 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 RESUME,YIELD=coroutine.resume,coroutine.yield local SOCK=require"socket".tcp() local JSON=require"Zframework.json" @@ -47,8 +47,6 @@ local function _send(opcode,message) return SOCK:send(char(unpack(msgbyte))) end - - do--Connect local host=sendCHN:demand() local port=sendCHN:demand() @@ -57,48 +55,58 @@ 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 not res 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 or"???")..":"..(reason and reason.message or"Server Error")) + res,err=SOCK:receive(ctLen) + if not res then readCHN:push(err)return end + local reason=JSON.decode(res) + readCHN:push((code or"XXX")..":"..(reason and reason.message or"Server Error")) end - else - readCHN:push(err) end - SOCK:settimeout(6.26) + SOCK:settimeout(0) end - -local buffer +local length +local lBuffer=""--Multi-data buffer +local unfinishedFrame--Multi-frame buffer +local sBuffer="" while true do--Running + --Send triggerCHN:demand() while sendCHN:getCount()>=2 do local op=sendCHN:pop() @@ -106,54 +114,72 @@ 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) - local fin=band(byte(res,1),0x80)==0x80 - - --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 - local b={byte(SOCK:receive(8),1,8)} - length=shl(b[5],24)+shl(b[6],16)+shl(b[7],8)+b[8] - end - - --Receive data - res="" - while length>0 do - local t=SOCK:receive(length) - if t then - res=res..t - length=length-#t - else--Time out! - res=false - break + --Read + while true do + if unfinishedFrame then--UNF process + local s,e,p=SOCK:receive(length) + if s then + sBuffer=sBuffer..s + elseif p then + sBuffer=sBuffer..p + length=length-#p end - end + unfinishedFrame=s or length==0 + else + --Byte 0-1 + local res,err=SOCK:receive(2) + if err then break end - --React - if res then + 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,e,p=SOCK:receive(length) + if s then + print(("%s[%d]:%s"):format(threadName,length,s)) + res=s + elseif p then--UNF head + print(("%s[%d/%d]:%s"):format(threadName,#p,length,p)) + unfinishedFrame=true + sBuffer=sBuffer..p + length=length-#p + break + end + -- elseif e then + -- readCHN:push(8) + -- readCHN:push(e) + -- return + else + res="" + end + + --React if op==8 then--8=close readCHN:push(op) SOCK:close() if type(res)=="string"then local reason=JSON.decode(res) - readCHN:push(reason and reason.message or"Server Error") + readCHN:push(reason and reason.message or"WS Error") else - readCHN:push("Server Error") + readCHN:push("WS Error") end elseif op==0 then--0=continue - buffer=buffer..res + lBuffer=lBuffer..res if fin then -- print("FIN=1 (c") - readCHN:push(buffer) - buffer="" + readCHN:push(lBuffer) + lBuffer="" else -- print("FIN=0 (c") end @@ -164,15 +190,10 @@ while true do--Running readCHN:push(res) else -- print("OP: "..op.."\tFIN=0") - buffer=res + sBuffer=res -- print("START pack: "..res) end end - else - --TIMEOUT - SOCK:close() - readCHN:push(8) - readCHN:push("WS time out") end end end @@ -211,7 +232,7 @@ function WS.connect(name,subPath,body) 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) @@ -303,13 +324,15 @@ function WS.update(dt) LOG.print(text.wsFailed.." "..mes,"warn") 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) + elseif ws.status=="running"then + if 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) + end end if ws.sendTimer>0 then ws.sendTimer=ws.sendTimer-dt end if ws.pongTimer>0 then ws.pongTimer=ws.pongTimer-dt end From dfae6a686c0baab56bb67cf376180714dc9a02fd Mon Sep 17 00:00:00 2001 From: MrZ626 <1046101471@qq.com> Date: Thu, 1 Apr 2021 12:17:12 +0800 Subject: [PATCH 44/83] =?UTF-8?q?=E6=95=B4=E7=90=86=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Zframework/websocket.lua | 90 +++++++++++++++++++++------------------- 1 file changed, 47 insertions(+), 43 deletions(-) diff --git a/Zframework/websocket.lua b/Zframework/websocket.lua index f567aa18..f7bc1a6c 100644 --- a/Zframework/websocket.lua +++ b/Zframework/websocket.lua @@ -12,41 +12,9 @@ local wsThread=[[ 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 RESUME,YIELD=coroutine.resume,coroutine.yield 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() @@ -101,10 +69,47 @@ do--Connect 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} + 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 +end local length -local lBuffer=""--Multi-data buffer -local unfinishedFrame--Multi-frame buffer -local sBuffer="" +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() @@ -116,15 +121,18 @@ while true do--Running --Read while true do - if unfinishedFrame then--UNF process + 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 - unfinishedFrame=s or length==0 else --Byte 0-1 local res,err=SOCK:receive(2) @@ -145,21 +153,17 @@ while true do--Running if length>0 then --Receive data - local s,e,p=SOCK:receive(length) + local s,_,p=SOCK:receive(length) if s then print(("%s[%d]:%s"):format(threadName,length,s)) res=s elseif p then--UNF head print(("%s[%d/%d]:%s"):format(threadName,#p,length,p)) - unfinishedFrame=true + UFF=true sBuffer=sBuffer..p length=length-#p break end - -- elseif e then - -- readCHN:push(8) - -- readCHN:push(e) - -- return else res="" end From 881769b433f0e23408afc77ba10306363adf5729 Mon Sep 17 00:00:00 2001 From: MrZ626 <1046101471@qq.com> Date: Thu, 1 Apr 2021 12:31:45 +0800 Subject: [PATCH 45/83] =?UTF-8?q?=E6=B7=BB=E5=8A=A0naki=E7=AB=8B=E7=BB=98?= =?UTF-8?q?=EF=BC=8C=E6=95=B4=E7=90=86=E4=BA=BA=E7=89=A9=E7=9B=B8=E5=85=B3?= =?UTF-8?q?=E7=9A=84=E5=9B=BE=E7=89=87=E6=96=87=E4=BB=B6=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main.lua | 16 +++++------ media/image/{mess => characters}/electric.png | Bin media/image/{mess => characters}/hbm.png | Bin .../{miya/ch.png => characters/miya.png} | Bin .../{miya/f1.png => characters/miya_f1.png} | Bin .../{miya/f2.png => characters/miya_f2.png} | Bin .../{miya/f3.png => characters/miya_f3.png} | Bin .../{miya/f4.png => characters/miya_f4.png} | Bin media/image/characters/naki.png | Bin 0 -> 123696 bytes parts/scenes/setting_sound.lua | 27 +++++++++--------- 10 files changed, 21 insertions(+), 22 deletions(-) rename media/image/{mess => characters}/electric.png (100%) rename media/image/{mess => characters}/hbm.png (100%) rename media/image/{miya/ch.png => characters/miya.png} (100%) rename media/image/{miya/f1.png => characters/miya_f1.png} (100%) rename media/image/{miya/f2.png => characters/miya_f2.png} (100%) rename media/image/{miya/f3.png => characters/miya_f3.png} (100%) rename media/image/{miya/f4.png => characters/miya_f4.png} (100%) create mode 100644 media/image/characters/naki.png diff --git a/main.lua b/main.lua index b512c1f7..71fd62dd 100644 --- a/main.lua +++ b/main.lua @@ -109,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", diff --git a/media/image/mess/electric.png b/media/image/characters/electric.png similarity index 100% rename from media/image/mess/electric.png rename to media/image/characters/electric.png diff --git a/media/image/mess/hbm.png b/media/image/characters/hbm.png similarity index 100% rename from media/image/mess/hbm.png rename to media/image/characters/hbm.png diff --git a/media/image/miya/ch.png b/media/image/characters/miya.png similarity index 100% rename from media/image/miya/ch.png rename to media/image/characters/miya.png diff --git a/media/image/miya/f1.png b/media/image/characters/miya_f1.png similarity index 100% rename from media/image/miya/f1.png rename to media/image/characters/miya_f1.png diff --git a/media/image/miya/f2.png b/media/image/characters/miya_f2.png similarity index 100% rename from media/image/miya/f2.png rename to media/image/characters/miya_f2.png diff --git a/media/image/miya/f3.png b/media/image/characters/miya_f3.png similarity index 100% rename from media/image/miya/f3.png rename to media/image/characters/miya_f3.png diff --git a/media/image/miya/f4.png b/media/image/characters/miya_f4.png similarity index 100% rename from media/image/miya/f4.png rename to media/image/characters/miya_f4.png diff --git a/media/image/characters/naki.png b/media/image/characters/naki.png new file mode 100644 index 0000000000000000000000000000000000000000..05c71f3bfbbcdc3e3bc746d48b8dae8b08be6c9e GIT binary patch literal 123696 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⋙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 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 From 5d728573cdc1557ee0c5735051b572f60e5068c2 Mon Sep 17 00:00:00 2001 From: MrZ626 <1046101471@qq.com> Date: Thu, 1 Apr 2021 12:42:28 +0800 Subject: [PATCH 46/83] =?UTF-8?q?=E5=87=8F=E5=B0=91=E8=BF=9E=E7=BB=AD?= =?UTF-8?q?=E6=8A=A5=E9=94=99=E9=99=90=E5=88=B6=E6=AC=A1=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Zframework/init.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Zframework/init.lua b/Zframework/init.lua index 78213706..e66c0fd7 100644 --- a/Zframework/init.lua +++ b/Zframework/init.lua @@ -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} From 78b7dfcc36b263df590fc6156bc4692ca75f1666 Mon Sep 17 00:00:00 2001 From: MrZ626 <1046101471@qq.com> Date: Thu, 1 Apr 2021 14:47:54 +0800 Subject: [PATCH 47/83] =?UTF-8?q?=E6=95=B4=E7=90=86=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=EF=BC=8C=E9=83=A8=E5=88=86=E5=8D=8F=E7=A8=8B=E5=88=9B=E5=BB=BA?= =?UTF-8?q?/=E6=89=A7=E8=A1=8C=E6=94=B9=E7=94=A8wrap=E6=9B=B4=E5=8A=A0?= =?UTF-8?q?=E7=AE=80=E6=B4=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Zframework/task.lua | 3 +-- parts/ai.lua | 4 ++-- parts/player/init.lua | 6 +++--- parts/player/player.lua | 12 ++++++------ parts/player/update.lua | 24 ++++++++++-------------- parts/scenes/load.lua | 9 ++++----- parts/scenes/main.lua | 20 +++++++++----------- 7 files changed, 35 insertions(+), 43 deletions(-) diff --git a/Zframework/task.lua b/Zframework/task.lua index 3fa19084..a7a7c976 100644 --- a/Zframework/task.lua +++ b/Zframework/task.lua @@ -1,6 +1,5 @@ local rem=table.remove -local assert=assert -local resume,status=coroutine.resume,coroutine.status +local assert,resume,status=assert,coroutine.resume,coroutine.status local tasks={} local TASK={} diff --git a/parts/ai.lua b/parts/ai.lua index ae6506e0..0d4122df 100644 --- a/parts/ai.lua +++ b/parts/ai.lua @@ -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, @@ -79,7 +79,7 @@ if type(_CC)=="table"then 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) diff --git a/parts/player/init.lua b/parts/player/init.lua index 04fcf48d..ac2f380d 100644 --- a/parts/player/init.lua +++ b/parts/player/init.lua @@ -178,7 +178,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 +312,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 diff --git a/parts/player/player.lua b/parts/player/player.lua index 2a294017..d523b5e4 100644 --- a/parts/player/player.lua +++ b/parts/player/player.lua @@ -6,7 +6,7 @@ local Player={}--Player class local int,ceil,rnd=math.floor,math.ceil,math.random local max,min,modf=math.max,math.min,math.modf local ins,rem=table.insert,table.remove -local resume,yield=coroutine.resume,coroutine.yield +local resume,yield,status=coroutine.resume,coroutine.yield,coroutine.status local kickList=require"parts.kickList" @@ -121,8 +121,8 @@ function Player:RND(a,b) end function Player:newTask(code,...) local thread=coroutine.create(code) - coroutine.resume(thread,self,...) - if coroutine.status(thread)~="dead"then + resume(thread,self,...) + if status(thread)~="dead"then self.tasks[#self.tasks+1]={ thread=thread, code=code, @@ -763,7 +763,7 @@ function Player:popNext(ifhold)--Pop nextQueue to hand self.ctrlCount=0 self.cur=rem(self.nextQueue,1) - assert(resume(self.newNext)) + self.newNext() if self.cur then self.pieceCount=self.pieceCount+1 if self.AI_mode=="CC"then @@ -1512,8 +1512,8 @@ function Player:loadAI(data)--Load AI params else self:setRS("TRS") end - self.AI_thread=coroutine.create(AIFUNC[data.type]) - coroutine.resume(self.AI_thread,self,self.AI_keys) + self.AI_thread=coroutine.wrap(AIFUNC[data.type]) + self.AI_thread(self,self.AI_keys) end ---------------------------------------------------- diff --git a/parts/player/update.lua b/parts/player/update.lua index d04ef910..ecb0c39c 100644 --- a/parts/player/update.lua +++ b/parts/player/update.lua @@ -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 @@ -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]) diff --git a/parts/scenes/load.lua b/parts/scenes/load.lua index 45e9299b..0386a0c8 100644 --- a/parts/scenes/load.lua +++ b/parts/scenes/load.lua @@ -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,7 +175,6 @@ local loadingThread=coroutine.create(function() logoColor2={COLOR.rainbow_light(r)} end STAT.run=STAT.run+1 - LOADED=true --Connect to server TASK.new(NET.TICK_WS_app) @@ -194,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() @@ -256,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 diff --git a/parts/scenes/main.lua b/parts/scenes/main.lua index 9dcbdafb..08b66486 100644 --- a/parts/scenes/main.lua +++ b/parts/scenes/main.lua @@ -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] @@ -47,7 +45,7 @@ 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" @@ -121,7 +119,7 @@ function scene.keyDown(key) SCN.back() end else - coroutine.resume(cmdEntryThread,key) + cmdEntryThread(key) end end From 81a0dd4a5caaed5d569b73cd8246e91dd0fd0f46 Mon Sep 17 00:00:00 2001 From: MrZ626 <1046101471@qq.com> Date: Thu, 1 Apr 2021 15:54:58 +0800 Subject: [PATCH 48/83] =?UTF-8?q?=E6=96=B0=E8=83=8C=E6=99=AF=EF=BC=9Ablock?= =?UTF-8?q?rain?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- parts/backgrounds/blockrain.lua | 56 +++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 parts/backgrounds/blockrain.lua diff --git a/parts/backgrounds/blockrain.lua b/parts/backgrounds/blockrain.lua new file mode 100644 index 00000000..1cb9cbb3 --- /dev/null +++ b/parts/backgrounds/blockrain.lua @@ -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 \ No newline at end of file From 0bd6006d70eccd84d67d841ae41d1e3254eb7856 Mon Sep 17 00:00:00 2001 From: MrZ626 <1046101471@qq.com> Date: Thu, 1 Apr 2021 15:55:08 +0800 Subject: [PATCH 49/83] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=84=9A=E4=BA=BA?= =?UTF-8?q?=E8=8A=82=E4=B8=BB=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Zframework/theme.lua | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Zframework/theme.lua b/Zframework/theme.lua index 4de2df1e..c79c85c5 100644 --- a/Zframework/theme.lua +++ b/Zframework/theme.lua @@ -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 From 81fa2579155da752d8442d14f6e1ea638e727461 Mon Sep 17 00:00:00 2001 From: MrZ626 <1046101471@qq.com> Date: Thu, 1 Apr 2021 15:57:58 +0800 Subject: [PATCH 50/83] =?UTF-8?q?=E6=B7=B7=E6=88=98=E6=A8=A1=E5=BC=8F?= =?UTF-8?q?=E7=AC=AC=E4=BA=8C=E5=90=8D=E7=89=B9=E6=AE=8ABGM=E5=8F=96?= =?UTF-8?q?=E6=B6=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- parts/player/player.lua | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/parts/player/player.lua b/parts/player/player.lua index d523b5e4..2844b383 100644 --- a/parts/player/player.lua +++ b/parts/player/player.lua @@ -1803,11 +1803,7 @@ function Player:lose(force) SFX.play("fail") VOC.play("lose") if GAME.modeEnv.royaleMode then - if self.modeData.place==2 then - BGM.play("hay what kind of feeling") - else - BGM.play("end") - end + BGM.play("end") end gameOver() self:newTask(#PLAYERS>1 and tick_lose or tick_finish) From ed66e69e7cde5c1031a38aaa396c802e9f508fa3 Mon Sep 17 00:00:00 2001 From: MrZ626 <1046101471@qq.com> Date: Thu, 1 Apr 2021 20:11:59 +0800 Subject: [PATCH 51/83] =?UTF-8?q?=E6=94=B9=E5=9B=9E=E9=83=A8=E5=88=86?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E4=BB=A3=E7=A0=81=EF=BC=8C=E5=8F=AF=E4=BB=A5?= =?UTF-8?q?=E8=BF=9B=E6=88=BF=E9=97=B4=EF=BC=8C=E5=87=86=E5=A4=87=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=E6=88=BF=E9=97=B4=E5=86=85=E5=91=BD=E4=BB=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- parts/net.lua | 2 +- parts/scenes/net_rooms.lua | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/parts/net.lua b/parts/net.lua index 61421dc0..59021d52 100644 --- a/parts/net.lua +++ b/parts/net.lua @@ -273,7 +273,7 @@ function NET.TICK_WS_play() NET.roomList=res.roomList _unlock("fetchRoom") elseif res.action==2 then--Join(create) room - -- loadGame("netBattle",true,true) + loadGame("netBattle",true,true) _unlock("enterRoom") elseif res.action==3 then--Leave room SCN.back() diff --git a/parts/scenes/net_rooms.lua b/parts/scenes/net_rooms.lua index a999ce64..5f404426 100644 --- a/parts/scenes/net_rooms.lua +++ b/parts/scenes/net_rooms.lua @@ -58,7 +58,7 @@ function scene.keyDown(k) LOG.print("Can't enter private room now") return end - NET.enterRoom(NET.roomList[selected].id)--,password + NET.enterRoom(NET.roomList[selected].rid)--,password end end end From ad477974674ef6ca6d252bffe67f1bddf4b78e7f Mon Sep 17 00:00:00 2001 From: MrZ626 <1046101471@qq.com> Date: Fri, 2 Apr 2021 23:37:30 +0800 Subject: [PATCH 52/83] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=B0=8F=E7=A8=8B?= =?UTF-8?q?=E5=BA=8Ften=E4=BB=A5fast=E6=A8=A1=E5=BC=8F=E7=BB=93=E6=9D=9F?= =?UTF-8?q?=E5=90=8E=E6=96=B0=E5=BC=80=E4=B8=80=E5=B1=80=E6=AD=BB=E4=BA=A1?= =?UTF-8?q?=E4=BD=8D=E7=BD=AE=E7=82=B9=E4=B8=8D=E4=BA=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- parts/scenes/app_ten.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/parts/scenes/app_ten.lua b/parts/scenes/app_ten.lua index 46e3ebfa..e176f909 100644 --- a/parts/scenes/app_ten.lua +++ b/parts/scenes/app_ten.lua @@ -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") From 2f2e4f389fcf075a6706f82c3bb19e6148076df3 Mon Sep 17 00:00:00 2001 From: MrZ626 <1046101471@qq.com> Date: Sat, 3 Apr 2021 00:18:01 +0800 Subject: [PATCH 53/83] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=A9=AC=E6=8B=89?= =?UTF-8?q?=E6=9D=BE=E7=9B=AE=E6=A0=87=E8=A1=8C=E6=95=B0=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- parts/modes/marathon_h.lua | 6 ++---- parts/modes/marathon_n.lua | 15 ++++++++------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/parts/modes/marathon_h.lua b/parts/modes/marathon_h.lua index 5fd2eb63..9223011f 100644 --- a/parts/modes/marathon_h.lua +++ b/parts/modes/marathon_h.lua @@ -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 diff --git a/parts/modes/marathon_n.lua b/parts/modes/marathon_n.lua index 41f41367..ea691ac5 100644 --- a/parts/modes/marathon_n.lua +++ b/parts/modes/marathon_n.lua @@ -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, From 7286d4ffe0aff688ca93fd410cc12b6c72083456 Mon Sep 17 00:00:00 2001 From: MrZ626 <1046101471@qq.com> Date: Sat, 3 Apr 2021 00:47:23 +0800 Subject: [PATCH 54/83] =?UTF-8?q?net=5Fgame=E5=9C=BA=E6=99=AF=E7=9A=84play?= =?UTF-8?q?erData=E5=8F=98=E9=87=8F=E6=94=B9=E4=B8=BA=E5=85=A8=E5=B1=80PLY?= =?UTF-8?q?=5FNET?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- parts/gametoolfunc.lua | 4 ++-- parts/globalTables.lua | 1 + parts/modes/netBattle.lua | 10 +++++----- parts/scenes/net_game.lua | 37 +++++++++++++++++++------------------ 4 files changed, 27 insertions(+), 25 deletions(-) diff --git a/parts/gametoolfunc.lua b/parts/gametoolfunc.lua index 33c83b19..38e16886 100644 --- a/parts/gametoolfunc.lua +++ b/parts/gametoolfunc.lua @@ -715,7 +715,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 +744,7 @@ do--function resetGameData(args) end destroyPlayers() - GAME.curMode.load(playerData) + GAME.curMode.load() initPlayerPosition(args:find("q")) restoreVirtualkey() if GAME.modeEnv.task then diff --git a/parts/globalTables.lua b/parts/globalTables.lua index d26a094a..9a8e96b9 100644 --- a/parts/globalTables.lua +++ b/parts/globalTables.lua @@ -144,6 +144,7 @@ end --Game tables PLAYERS={}--Players data PLY_ALIVE={} +PLY_NET={} FIELD={}--Field(s) for custom game BAG={}--Sequence for custom game MISSION={}--Clearing mission for custom game diff --git a/parts/modes/netBattle.lua b/parts/modes/netBattle.lua index aaadc2e8..c290f52e 100644 --- a/parts/modes/netBattle.lua +++ b/parts/modes/netBattle.lua @@ -5,14 +5,14 @@ return{ freshLimit=15, noMod=true, }, - 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].id==tostring(USER.id)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 diff --git a/parts/scenes/net_game.lua b/parts/scenes/net_game.lua index 65b9de34..35114f30 100644 --- a/parts/scenes/net_game.lua +++ b/parts/scenes/net_game.lua @@ -2,7 +2,6 @@ local data=love.data local gc=love.graphics local tc=love.touch -local playerData local ins,rem=table.insert,table.remove local SCR=SCR @@ -11,6 +10,8 @@ local onVirtualkey=onVirtualkey local pressVirtualkey=pressVirtualkey local updateVirtualkey=updateVirtualkey +local PLY_NET=PLY_NET + local hideChatBox local textBox=WIDGET.newTextBox{name="texts",x=340,y=80,w=600,h=550,hide=function()return hideChatBox end} local function switchChat() @@ -39,8 +40,8 @@ function scene.sceneInit() playerInitialized=false textBox:clear() - playerData={} - resetGameData("n",playerData) + while #PLY_NET>0 do rem(PLY_NET)end + resetGameData("n") noTouch=not SETTING.VKSwitch playing=false lastUpstreamTime=0 @@ -160,12 +161,12 @@ function scene.socketRead(mes) 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"}) + ins(PLY_NET,{name=L[1],id=L[2],sid=L[3],conf=L[4],ready=L[5]=="1"}) end playerInitialized=true SFX.play("click") if not playing then - resetGameData("qn",playerData) + resetGameData("qn") end elseif cmd=="L"then textBox:push{ @@ -173,9 +174,9 @@ function scene.socketRead(mes) COLOR.dY,"#"..args[2].." ", COLOR.Y,text.leaveRoom, } - for i=1,#playerData do - if playerData[i].id==args[2]then - rem(playerData,i) + for i=1,#PLY_NET do + if PLY_NET[i].id==args[2]then + rem(PLY_NET,i) break end end @@ -202,14 +203,14 @@ function scene.socketRead(mes) } 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]) + for i=1,#PLY_NET do + if PLY_NET[i].id==args[2]then + PLY_NET[i].conf=args[4] + PLY_NET[i].p:setConf(args[4]) return end end - resetGameData("qn",playerData) + resetGameData("qn") end elseif cmd=="S"then if playing and args[1]~=PLAYERS[1].subID then @@ -238,16 +239,16 @@ function scene.socketRead(mes) playing=true lastUpstreamTime=0 upstreamProgress=1 - resetGameData("n",playerData,tonumber(args[1])) + resetGameData("n",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) + resetGameData("n") + for i=1,#PLY_NET do + if PLY_NET[i].sid==args[1]then + TEXT.show(text.champion:gsub("$1",PLY_NET[i].name.."#"..PLY_NET[i].id),640,260,80,"zoomout",.26) break end end From 1f8895257d3a491917f37682a9a90d202efacb97 Mon Sep 17 00:00:00 2001 From: MrZ626 <1046101471@qq.com> Date: Sat, 3 Apr 2021 00:49:22 +0800 Subject: [PATCH 55/83] =?UTF-8?q?=E6=95=B4=E7=90=86=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- parts/scenes/net_game.lua | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/parts/scenes/net_game.lua b/parts/scenes/net_game.lua index 35114f30..220ebd04 100644 --- a/parts/scenes/net_game.lua +++ b/parts/scenes/net_game.lua @@ -14,10 +14,6 @@ local PLY_NET=PLY_NET 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 @@ -96,7 +92,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] @@ -315,7 +311,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"}, } From 4170965c64af9fead973849d2f12235af55d2950 Mon Sep 17 00:00:00 2001 From: MrZ626 <1046101471@qq.com> Date: Sat, 3 Apr 2021 00:54:29 +0800 Subject: [PATCH 56/83] =?UTF-8?q?=E5=A2=9E=E5=8A=A0mesType=EF=BC=8C?= =?UTF-8?q?=E6=96=B0=E7=9A=84=E5=AF=B9=E6=88=98=E7=94=A8=E6=B6=88=E6=81=AF?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F=EF=BC=88=E6=9C=AA=E5=AE=8C=E6=88=90=EF=BC=8C?= =?UTF-8?q?=E5=BE=85=E6=B5=8B=E8=AF=95=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- parts/net.lua | 93 +++++++++++++++++++++++++++------------ parts/scenes/net_game.lua | 24 +++++----- 2 files changed, 76 insertions(+), 41 deletions(-) diff --git a/parts/net.lua b/parts/net.lua index 59021d52..44fa993d 100644 --- a/parts/net.lua +++ b/parts/net.lua @@ -7,10 +7,11 @@ local NET={ } local mesType={ - OK=true, Connected=true, - Server=true, + Self=true, Broadcast=true, + Private=true, + Server=true, } --Lock & Unlock submodule @@ -34,15 +35,17 @@ end local function _parse(res) res=JSON.decode(res) if res then - if mesType[res.message]then + if mesType[res.type]then return res else LOG.print( - res.message and( - res.reason and res.message..": "..res.reason or - res.message - )or - "[NO Message]", + "WS error:"..( + res.type and( + res.reason and res.type..": "..res.reason or + res.type + )or + "[NO Message]" + ), "warning") end end @@ -52,9 +55,9 @@ end function NET.wsCloseMessage(message) if message:sub(1,1)=="{"then local mes=JSON.decode(message) - LOG.print(text.wsClose..mes.message,"warn") + LOG.print(text.wsClose..mes.type,"warn") else - LOG.print(text.wsClose..message,"warn") + LOG.print(text.wsClose..type,"warn") end end @@ -109,16 +112,19 @@ function NET.wsConnectPlay() end end function NET.signal_ready() - WS.send("play","R") -end -function NET.uploadRecStream(stream) - WS.send("stream",data.encode("string","base64",stream)) -end -function NET.signal_die() - WS.send("play","D") + if _lock("ready")then + WS.send("play",'{"action":6,"data":{"ready":true}}') + end end function NET.signal_quit() - WS.send("play","Q") + WS.send("play",'{"action":3}') +end +function NET.uploadRecStream(stream) + stream=data.encode("string","base64",stream) + WS.send("stream",'{"action":2,"data":{"stream":"'..stream..'"}}') +end +function NET.signal_die() + WS.send("stream",'{"action":3,"data":{"score":0,"survivalTime":0}}') end --Room @@ -222,7 +228,7 @@ function NET.TICK_WS_user() else local res=_parse(message) if res then - if res.message=="Connected"then + if res.type=="Connected"then NET.login=true if res.id then USER.id=res.id @@ -266,17 +272,31 @@ function NET.TICK_WS_play() else local res=_parse(message) if res then - if res.message=="Connected"then - _unlock("connectPlay") + if res.type=="Connected"then SCN.go("net_menu") + _unlock("connectPlay") elseif res.action==0 then--Fetch rooms NET.roomList=res.roomList _unlock("fetchRoom") - elseif res.action==2 then--Join(create) room - loadGame("netBattle",true,true) - _unlock("enterRoom") - elseif res.action==3 then--Leave room - SCN.back() + -- elseif res.action==1 then + elseif res.action==2 then--Player join + if res.type=="Self"then + --Create room + loadGame("netBattle",true,true) + _unlock("enterRoom") + else + --Others join room + SCN.socketRead("Join",res.data) + end + elseif res.action==3 then--Player leave + 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") end else WS.alert("play") @@ -300,7 +320,26 @@ function NET.TICK_WS_stream() NET.wsCloseMessage(message) return else - --TODO + local res=_parse(message) + if res then + if res.type=="Connected"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 + SCN.socketRead("J",res.data) + elseif res.action==3 then--Player leave + SCN.socketRead("L",res.data) + elseif res.action==4 then--Player died + SCN.socketRead("Die",res.data) + elseif res.action==5 then--Receive stream + SCN.socketRead("S",res.data) + end + else + WS.alert("stream") + end end end end diff --git a/parts/scenes/net_game.lua b/parts/scenes/net_game.lua index 220ebd04..a6b46949 100644 --- a/parts/scenes/net_game.lua +++ b/parts/scenes/net_game.lua @@ -102,7 +102,7 @@ function scene.keyDown(key) VK[k].pressTime=10 end elseif key=="space"then - if not PLAYERS[1].ready then + if not NET.getLock("ready")then NET.signal_ready() end end @@ -143,10 +143,8 @@ 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 +function scene.socketRead(cmd,args) + if cmd=="Join"then if playerInitialized then local L=SPLITSTR(args[1],",") textBox:push{ @@ -164,7 +162,7 @@ function scene.socketRead(mes) if not playing then resetGameData("qn") end - elseif cmd=="L"then + elseif cmd=="Leave"then textBox:push{ COLOR.lR,args[1], COLOR.dY,"#"..args[2].." ", @@ -189,7 +187,7 @@ function scene.socketRead(mes) end end initPlayerPosition(true) - elseif cmd=="T"then + elseif cmd=="Talk"then local _,text=pcall(data.decode,"string","base64",args[3]) if not _ then text=args[3]end textBox:push{ @@ -197,7 +195,7 @@ function scene.socketRead(mes) COLOR.dY,"#"..args[2].." ", COLOR.sky,text } - elseif cmd=="C"then + elseif cmd=="Config"then if tostring(USER.id)~=args[2]then for i=1,#PLY_NET do if PLY_NET[i].id==args[2]then @@ -208,7 +206,7 @@ function scene.socketRead(mes) end resetGameData("qn") end - elseif cmd=="S"then + elseif cmd=="Stream"then if playing and args[1]~=PLAYERS[1].subID then for _,P in next,PLAYERS do if P.subID==args[1]then @@ -221,7 +219,7 @@ function scene.socketRead(mes) end end end - elseif cmd=="R"then + elseif cmd=="Ready"then local L=PLY_ALIVE for i=1,#L do if L[i].subID==args[1]then @@ -230,7 +228,7 @@ function scene.socketRead(mes) break end end - elseif cmd=="B"then + elseif cmd=="Begin"then if not playing then playing=true lastUpstreamTime=0 @@ -239,7 +237,7 @@ function scene.socketRead(mes) else LOG.print("Redundant signal: B(begin)",30,COLOR.green) end - elseif cmd=="F"then + elseif cmd=="Finish"then playing=false resetGameData("n") for i=1,#PLY_NET do @@ -248,8 +246,6 @@ function scene.socketRead(mes) break end end - else - LOG.print("Illegal message: ["..mes.."]",30,COLOR.green) end end From c1dbc494ae8309d0e13e7a8a80dfa4878a852dcf Mon Sep 17 00:00:00 2001 From: MrZ626 <1046101471@qq.com> Date: Sat, 3 Apr 2021 15:18:03 +0800 Subject: [PATCH 57/83] =?UTF-8?q?=E6=95=B4=E7=90=86=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Zframework/websocket.lua | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/Zframework/websocket.lua b/Zframework/websocket.lua index f7bc1a6c..3bec44b6 100644 --- a/Zframework/websocket.lua +++ b/Zframework/websocket.lua @@ -80,30 +80,32 @@ local _send do 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 not message then - SOCK:send(char(0x80,unpack(mask_key))) + 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 - - --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 end local length From 5fc3dff2d5f1e538fcb5354c4fddc6497a1dba52 Mon Sep 17 00:00:00 2001 From: MrZ626 <1046101471@qq.com> Date: Sat, 3 Apr 2021 16:25:21 +0800 Subject: [PATCH 58/83] =?UTF-8?q?=E8=B0=83=E6=95=B4=E8=87=AA=E5=AE=9A?= =?UTF-8?q?=E4=B9=89=E5=9C=BA=E5=9C=B0=E7=9A=84ui=EF=BC=8C=E5=8F=AF?= =?UTF-8?q?=E4=BB=A5=E7=9C=8B=E5=88=B0=E9=BC=A0=E6=A0=87=E4=B8=8D=E5=90=8C?= =?UTF-8?q?=E6=8C=89=E9=94=AE=E5=AF=B9=E5=BA=94=E7=94=BB=E7=AC=94=E9=A2=9C?= =?UTF-8?q?=E8=89=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- parts/scenes/custom_field.lua | 62 +++++++++++++++++++++-------------- 1 file changed, 37 insertions(+), 25 deletions(-) diff --git a/parts/scenes/custom_field.lua b/parts/scenes/custom_field.lua index 9ef1d67b..968c5f85 100644 --- a/parts/scenes/custom_field.lua +++ b/parts/scenes/custom_field.lua @@ -63,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() @@ -100,6 +99,7 @@ local function SPdraw() end end SPlist={} + SPmode=0 end function scene.sceneInit() @@ -152,13 +152,7 @@ end function scene.wheelMoved(_,y) if penColor>0 then - if y<0 then - penColor=penColor+1 - if penColor==25 then penColor=1 end - else - penColor=penColor-1 - if penColor==0 then penColor=24 end - end + penColor=(penColor+(y<0 and 1 or -1)-1)%24+1 end end function scene.touchDown(x,y)scene.mouseDown(x,y,1)end @@ -329,9 +323,9 @@ function scene.draw() gc.rectangle("line",30*SPlist[i][1]-30+2,600-30*SPlist[i][2]+2,30-4,30-4,3) end else - gc.setColor(1,1,1) + gc.setColor(1,0,0) for i=1,#SPlist do - gc.draw(cross,30*SPlist[i][1]-30,600-30*SPlist[i][2]) + gc.draw(cross,30*SPlist[i][1]-30+math.random(-1,1),600-30*SPlist[i][2]+math.random(-1,1)) end end end @@ -345,20 +339,38 @@ function scene.draw() gc.rectangle("fill",50,600,100,6) --Draw pen color - if penColor>0 then - gc.setLineWidth(13) - gc.setColor(minoColor[penColor]) - gc.rectangle("line",565,495,70,70) - elseif penColor==-1 then - gc.setLineWidth(5) - gc.setColor(.9,.9,.9) - gc.line(575,505,625,555) - gc.line(575,555,625,505) - elseif penColor==-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 From 7d325bd0db9e70d032b628b4fc9f31fe9615a1e8 Mon Sep 17 00:00:00 2001 From: MrZ626 <1046101471@qq.com> Date: Sat, 3 Apr 2021 23:00:08 +0800 Subject: [PATCH 59/83] =?UTF-8?q?=E8=B0=83=E6=95=B4ws=E9=94=99=E8=AF=AF?= =?UTF-8?q?=E6=B6=88=E6=81=AF=E6=98=BE=E7=A4=BA=EF=BC=8C=E6=95=B4=E7=90=86?= =?UTF-8?q?=E7=BF=BB=E8=AF=91=E6=96=87=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Zframework/websocket.lua | 4 ++-- parts/language/lang_en.lua | 4 +--- parts/language/lang_fr.lua | 6 ++---- parts/language/lang_pt.lua | 4 +--- parts/language/lang_sp.lua | 4 +--- parts/language/lang_zh.lua | 4 +--- parts/net.lua | 8 ++++---- parts/scenes/net_chat.lua | 1 - parts/scenes/net_game.lua | 1 - 9 files changed, 12 insertions(+), 24 deletions(-) diff --git a/Zframework/websocket.lua b/Zframework/websocket.lua index 3bec44b6..114c92ba 100644 --- a/Zframework/websocket.lua +++ b/Zframework/websocket.lua @@ -23,7 +23,7 @@ do--Connect SOCK:settimeout(2.6) local res,err=SOCK:connect(host,port) - if not res then readCHN:push(err)return end + if err then readCHN:push(err)return end --WebSocket handshake if not body then body=""end @@ -327,7 +327,7 @@ function WS.update(dt) ws.pongTimer=1 else ws.status="dead" - LOG.print(text.wsFailed.." "..mes,"warn") + LOG.print(text.wsFailed..": "..(mes=="timeout"and text.netTimeout or mes),"warn") end end elseif ws.status=="running"then diff --git a/parts/language/lang_en.lua b/parts/language/lang_en.lua index 1dfcf38f..dfae6dd6 100644 --- a/parts/language/lang_en.lua +++ b/parts/language/lang_en.lua @@ -90,10 +90,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!", diff --git a/parts/language/lang_fr.lua b/parts/language/lang_fr.lua index 5cecb95c..0a215ca7 100644 --- a/parts/language/lang_fr.lua +++ b/parts/language/lang_fr.lua @@ -91,10 +91,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 !", diff --git a/parts/language/lang_pt.lua b/parts/language/lang_pt.lua index 7fb3f716..c27c224a 100644 --- a/parts/language/lang_pt.lua +++ b/parts/language/lang_pt.lua @@ -90,10 +90,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!", diff --git a/parts/language/lang_sp.lua b/parts/language/lang_sp.lua index 6854aef4..4f6d34dc 100644 --- a/parts/language/lang_sp.lua +++ b/parts/language/lang_sp.lua @@ -92,10 +92,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!", diff --git a/parts/language/lang_zh.lua b/parts/language/lang_zh.lua index fe42e453..d02c5eaa 100644 --- a/parts/language/lang_zh.lua +++ b/parts/language/lang_zh.lua @@ -90,10 +90,8 @@ return{ accessFailed="身份验证失败", wsSuccessed="WS连接成功", wsFailed="WS连接失败", - wsDisconnected="WS连接断开", - wsNoConn="WS未连接", wsClose="WS被断开: ", - waitNetTask="正在连接,请稍候", + netTimeout="网络连接超时", createRoomTooFast="创建房间太快啦,等等吧", createRoomSuccessed="创建房间成功!", diff --git a/parts/net.lua b/parts/net.lua index 44fa993d..f8593e3e 100644 --- a/parts/net.lua +++ b/parts/net.lua @@ -53,11 +53,11 @@ end --wsEvent function NET.wsCloseMessage(message) - if message:sub(1,1)=="{"then - local mes=JSON.decode(message) - LOG.print(text.wsClose..mes.type,"warn") + 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..type,"warn") + LOG.print(text.wsClose.."","warn") end end diff --git a/parts/scenes/net_chat.lua b/parts/scenes/net_chat.lua index fb8696dc..f3d45d45 100644 --- a/parts/scenes/net_chat.lua +++ b/parts/scenes/net_chat.lua @@ -30,7 +30,6 @@ function scene.sceneInit() end function scene.sceneBack() NET.quitChat() - LOG.print(text.wsDisconnected,"warn") end function scene.wheelMoved(_,y) diff --git a/parts/scenes/net_game.lua b/parts/scenes/net_game.lua index a6b46949..eb3d40b7 100644 --- a/parts/scenes/net_game.lua +++ b/parts/scenes/net_game.lua @@ -27,7 +27,6 @@ local scene={} function scene.sceneBack() NET.signal_quit() - LOG.print(text.wsDisconnected,"warn") love.keyboard.setKeyRepeat(true) end function scene.sceneInit() From 5268ad041f6656774ff4e51a90f48b0f200cb386 Mon Sep 17 00:00:00 2001 From: MrZ626 <1046101471@qq.com> Date: Sun, 4 Apr 2021 01:36:43 +0800 Subject: [PATCH 60/83] =?UTF-8?q?=E6=95=B4=E7=90=86=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=EF=BC=8C=E9=85=8D=E5=90=88=E4=BF=AE=E6=94=B9=E4=B8=80=E4=B8=AA?= =?UTF-8?q?=E8=81=94=E7=BD=91=E5=91=BD=E4=BB=A4=E7=B1=BB=E5=9E=8B=EF=BC=8C?= =?UTF-8?q?=E4=BF=AE=E6=94=B9=E8=81=94=E7=BD=91=E7=9B=B8=E5=85=B3=E5=9C=BA?= =?UTF-8?q?=E6=99=AF=E8=83=8C=E6=99=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- parts/modes/netBattle.lua | 1 + parts/net.lua | 18 +++++++++--------- parts/scenes/load.lua | 6 +++--- parts/scenes/net_menu.lua | 6 +++--- parts/scenes/net_rooms.lua | 2 +- 5 files changed, 17 insertions(+), 16 deletions(-) diff --git a/parts/modes/netBattle.lua b/parts/modes/netBattle.lua index c290f52e..45f8cbf4 100644 --- a/parts/modes/netBattle.lua +++ b/parts/modes/netBattle.lua @@ -4,6 +4,7 @@ return{ drop=30, freshLimit=15, noMod=true, + bg="space", }, load=function() PLY.newPlayer(1) diff --git a/parts/net.lua b/parts/net.lua index f8593e3e..64fb5fc1 100644 --- a/parts/net.lua +++ b/parts/net.lua @@ -7,7 +7,7 @@ local NET={ } local mesType={ - Connected=true, + Connect=true, Self=true, Broadcast=true, Private=true, @@ -175,7 +175,7 @@ function NET.quitChat() end --WS tick funcs -function NET.TICK_WS_app() +function NET.updateWS_app() local retryTime=5 while true do YIELD() @@ -212,7 +212,7 @@ function NET.TICK_WS_app() end end end -function NET.TICK_WS_user() +function NET.updateWS_user() while true do YIELD() local status=WS.status("user") @@ -228,7 +228,7 @@ function NET.TICK_WS_user() else local res=_parse(message) if res then - if res.type=="Connected"then + if res.type=="Connect"then NET.login=true if res.id then USER.id=res.id @@ -256,7 +256,7 @@ function NET.TICK_WS_user() end end end -function NET.TICK_WS_play() +function NET.updateWS_play() while true do YIELD() local status=WS.status("play") @@ -272,7 +272,7 @@ function NET.TICK_WS_play() else local res=_parse(message) if res then - if res.type=="Connected"then + if res.type=="Connect"then SCN.go("net_menu") _unlock("connectPlay") elseif res.action==0 then--Fetch rooms @@ -306,7 +306,7 @@ function NET.TICK_WS_play() end end end -function NET.TICK_WS_stream() +function NET.updateWS_stream() while true do YIELD() local status=WS.status("stream") @@ -322,7 +322,7 @@ function NET.TICK_WS_stream() else local res=_parse(message) if res then - if res.type=="Connected"then + if res.type=="Connect"then --? elseif res.action==0 then--Game start SCN.socketRead("Begin",res.data) @@ -345,7 +345,7 @@ function NET.TICK_WS_stream() end end end -function NET.TICK_WS_chat() +function NET.updateWS_chat() while true do YIELD() local status=WS.status("chat") diff --git a/parts/scenes/load.lua b/parts/scenes/load.lua index 0386a0c8..baacbed4 100644 --- a/parts/scenes/load.lua +++ b/parts/scenes/load.lua @@ -177,9 +177,9 @@ local loadingThread=coroutine.wrap(function() STAT.run=STAT.run+1 --Connect to server - TASK.new(NET.TICK_WS_app) - TASK.new(NET.TICK_WS_user) - TASK.new(NET.TICK_WS_play) + 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{ diff --git a/parts/scenes/net_menu.lua b/parts/scenes/net_menu.lua index 8f1597fb..4246cec5 100644 --- a/parts/scenes/net_menu.lua +++ b/parts/scenes/net_menu.lua @@ -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}, } diff --git a/parts/scenes/net_rooms.lua b/parts/scenes/net_rooms.lua index 5f404426..18539b03 100644 --- a/parts/scenes/net_rooms.lua +++ b/parts/scenes/net_rooms.lua @@ -14,7 +14,7 @@ end local scene={} function scene.sceneInit() - BG.set("bg1") + BG.set("space") scrollPos=0 selected=1 fetchRoom() From 7e65a81d31c12fbdb432430c33594dcf6c89ee37 Mon Sep 17 00:00:00 2001 From: MrZ626 <1046101471@qq.com> Date: Sun, 4 Apr 2021 01:45:10 +0800 Subject: [PATCH 61/83] =?UTF-8?q?=E5=BE=AE=E8=B0=83=E8=AF=AD=E8=A8=80?= =?UTF-8?q?=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- parts/language/lang_en.lua | 1 - parts/language/lang_fr.lua | 3 +-- parts/language/lang_pt.lua | 1 - parts/language/lang_sp.lua | 4 +--- parts/language/lang_symbol.lua | 11 ++++++----- parts/language/lang_zh.lua | 5 ++--- 6 files changed, 10 insertions(+), 15 deletions(-) diff --git a/parts/language/lang_en.lua b/parts/language/lang_en.lua index dfae6dd6..a4f0280c 100644 --- a/parts/language/lang_en.lua +++ b/parts/language/lang_en.lua @@ -75,7 +75,6 @@ return{ needUpdate="Newer version required!", notFinished="Coming soon!", - httpCode="HTTP status code", jsonError="JSON error", noUsername="Please specify a username.", diff --git a/parts/language/lang_fr.lua b/parts/language/lang_fr.lua index 0a215ca7..a14243b7 100644 --- a/parts/language/lang_fr.lua +++ b/parts/language/lang_fr.lua @@ -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", @@ -183,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", diff --git a/parts/language/lang_pt.lua b/parts/language/lang_pt.lua index c27c224a..0086f5f9 100644 --- a/parts/language/lang_pt.lua +++ b/parts/language/lang_pt.lua @@ -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", diff --git a/parts/language/lang_sp.lua b/parts/language/lang_sp.lua index 4f6d34dc..dc555312 100644 --- a/parts/language/lang_sp.lua +++ b/parts/language/lang_sp.lua @@ -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", @@ -185,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", diff --git a/parts/language/lang_symbol.lua b/parts/language/lang_symbol.lua index 69cbea11..fd93f92d 100644 --- a/parts/language/lang_symbol.lua +++ b/parts/language/lang_symbol.lua @@ -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={ diff --git a/parts/language/lang_zh.lua b/parts/language/lang_zh.lua index d02c5eaa..a9f22174 100644 --- a/parts/language/lang_zh.lua +++ b/parts/language/lang_zh.lua @@ -75,7 +75,6 @@ return{ needUpdate="此功能需要更新游戏!", notFinished="暂未完成,敬请期待!", - httpCode="Http码", jsonError="json错误", noUsername="请填写用户名", @@ -174,7 +173,7 @@ return{ "", "使用LOVE2D引擎", "错误或者建议请附带截图发送到内测群或者作者邮箱~", - "仅通过内测群1127702001进行免费下载/更新", + "仅通过内测qq群/discord群进行免费下载/更新", "其他渠道获得游戏皆有被修改/加广告/植入病毒的风险,程序只申请了振动&联网权限!", "若由于被修改的本游戏产生的各种损失作者不负责(我怎么负责啊跟我有啥关系)", "请从正规途径获得最新版,游戏现为免费,不过有打赏当然感谢啦~", @@ -206,7 +205,7 @@ return{ simple-love-lights [dylhunn] ]], support="支持作者", - group="官方QQ群(如果没有被暗改的话就是这个):913154753", + group="官方QQ群:913154753", WidgetText={ main={ offline="单机游戏", From 68366bf9a3f1d03eb6369e42b2c9e0e716428bf7 Mon Sep 17 00:00:00 2001 From: MrZ626 <1046101471@qq.com> Date: Mon, 5 Apr 2021 00:50:14 +0800 Subject: [PATCH 62/83] =?UTF-8?q?=E5=BE=AE=E8=B0=83=E6=88=BF=E9=97=B4?= =?UTF-8?q?=E5=88=97=E8=A1=A8ui?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- parts/scenes/net_rooms.lua | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/parts/scenes/net_rooms.lua b/parts/scenes/net_rooms.lua index 18539b03..09577710 100644 --- a/parts/scenes/net_rooms.lua +++ b/parts/scenes/net_rooms.lua @@ -80,29 +80,31 @@ function scene.draw() --Room list gc.setColor(1,1,1) 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,#NET.roomList-scrollPos)do - local R=NET.roomList[scrollPos+i] - if R.private then + 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.draw(IMG.lock,59,75+40*i) + end + 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.draw(IMG.lock,64,75+40*i) + gc.printf(R.type,550,66+40*i,500,"right") + gc.print(R.count.."/"..R.capacity,1100,66+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.setColor(1,1,1) - gc.printf(R.type,500,66+40*i,500,"right") - gc.print(R.count.."/"..R.capacity,1050,66+40*i) end end scene.widgetList={ 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=65,hide=function()return #NET.roomList>0 or 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 #NET.roomList==0 end}, From 14302d0106e6e6a17ce390c5311ce0b4efbf70ea Mon Sep 17 00:00:00 2001 From: MrZ626 <1046101471@qq.com> Date: Mon, 5 Apr 2021 01:50:15 +0800 Subject: [PATCH 63/83] =?UTF-8?q?=E7=BB=A7=E7=BB=AD=E8=B7=9F=E8=BF=9B?= =?UTF-8?q?=E8=81=94=E7=BD=91=E9=83=A8=E5=88=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- parts/net.lua | 72 ++++++++++++++++++++++----------------- parts/scenes/net_game.lua | 2 ++ 2 files changed, 42 insertions(+), 32 deletions(-) diff --git a/parts/net.lua b/parts/net.lua index 64fb5fc1..904dc6b1 100644 --- a/parts/net.lua +++ b/parts/net.lua @@ -4,6 +4,7 @@ local NET={ allow_online=false, roomList={}, accessToken=false, + rid=false, } local mesType={ @@ -102,31 +103,6 @@ function NET.storeUserInfo(res) -- FILE.save(USERS,"conf/users") end ---Play -function NET.wsConnectPlay() - if _lock("connectPlay")then - WS.connect("play","/play",JSON.encode{ - id=USER.id, - 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.uploadRecStream(stream) - stream=data.encode("string","base64",stream) - WS.send("stream",'{"action":2,"data":{"stream":"'..stream..'"}}') -end -function NET.signal_die() - WS.send("stream",'{"action":3,"data":{"score":0,"survivalTime":0}}') -end - --Room function NET.fetchRoom() if _lock("fetchRoom")then @@ -155,6 +131,7 @@ function NET.createRoom() end function NET.enterRoom(roomID,password) if _lock("enterRoom")then + NET.rid=roomID WS.send("play",JSON.encode{ action=2, data={ @@ -166,6 +143,39 @@ function NET.enterRoom(roomID,password) end end +--Play +function NET.wsConnectPlay() + if _lock("connectPlay")then + WS.connect("play","/play",JSON.encode{ + id=USER.id, + 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{ + id=USER.id, + accessToken=NET.accessToken, + rid=NET.rid, + }) + 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)) @@ -297,6 +307,8 @@ function NET.updateWS_play() elseif res.action==6 then--Player ready SCN.socketRead("Ready",res.data) _unlock("ready") + elseif res.action==7 then--All ready + SCN.socketRead("Set",res.data) end else WS.alert("play") @@ -328,14 +340,10 @@ function NET.updateWS_stream() SCN.socketRead("Begin",res.data) elseif res.action==1 then--Game finished SCN.socketRead("Finish",res.data) - elseif res.action==2 then--Player join - SCN.socketRead("J",res.data) - elseif res.action==3 then--Player leave - SCN.socketRead("L",res.data) - elseif res.action==4 then--Player died + elseif res.action==2 then--Player died SCN.socketRead("Die",res.data) - elseif res.action==5 then--Receive stream - SCN.socketRead("S",res.data) + elseif res.action==3 then--Receive stream + SCN.socketRead("Stream",res.data) end else WS.alert("stream") diff --git a/parts/scenes/net_game.lua b/parts/scenes/net_game.lua index eb3d40b7..eee3a317 100644 --- a/parts/scenes/net_game.lua +++ b/parts/scenes/net_game.lua @@ -227,6 +227,8 @@ function scene.socketRead(cmd,args) break end end + elseif cmd=="Set"then + NET.wsConnectStream() elseif cmd=="Begin"then if not playing then playing=true From 046a41177f787f52526dc0ddaa1036999fa439a0 Mon Sep 17 00:00:00 2001 From: MrZ626 <1046101471@qq.com> Date: Mon, 5 Apr 2021 20:49:17 +0800 Subject: [PATCH 64/83] =?UTF-8?q?=E7=BB=A7=E7=BB=AD=E6=8E=A8=E8=BF=9B?= =?UTF-8?q?=E8=81=94=E7=BD=91=EF=BC=8C=E5=AE=9E=E7=8E=B0=E6=8E=A5=E5=85=A5?= =?UTF-8?q?stream=E5=92=8C=E8=80=81=E4=BB=A3=E7=A0=81=E7=9A=84=E6=9B=B4?= =?UTF-8?q?=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Zframework/websocket.lua | 8 ++-- parts/net.lua | 16 +++++--- parts/scenes/net_game.lua | 82 +++++++++++++++++++-------------------- 3 files changed, 56 insertions(+), 50 deletions(-) diff --git a/Zframework/websocket.lua b/Zframework/websocket.lua index 114c92ba..a0f30002 100644 --- a/Zframework/websocket.lua +++ b/Zframework/websocket.lua @@ -62,8 +62,8 @@ do--Connect else res,err=SOCK:receive(ctLen) if not res then readCHN:push(err)return end - local reason=JSON.decode(res) - readCHN:push((code or"XXX")..":"..(reason and reason.message or"Server Error")) + res=JSON.decode(res) + readCHN:push((code or"XXX")..":"..(res and res.reason or"Server Error")) end end SOCK:settimeout(0) @@ -175,8 +175,8 @@ while true do--Running readCHN:push(op) SOCK:close() if type(res)=="string"then - local reason=JSON.decode(res) - readCHN:push(reason and reason.message or"WS Error") + res=JSON.decode(res) + readCHN:push(res and res.reason or"WS Error") else readCHN:push("WS Error") end diff --git a/parts/net.lua b/parts/net.lua index 904dc6b1..c4086d41 100644 --- a/parts/net.lua +++ b/parts/net.lua @@ -5,6 +5,7 @@ local NET={ roomList={}, accessToken=false, rid=false, + rsid=false, } local mesType={ @@ -163,9 +164,9 @@ end function NET.wsConnectStream() if _lock("connectStream")then WS.connect("stream","/stream",JSON.encode{ - id=USER.id, + uid=USER.id, accessToken=NET.accessToken, - rid=NET.rid, + rid=NET.rsid, }) end end @@ -288,7 +289,7 @@ function NET.updateWS_play() elseif res.action==0 then--Fetch rooms NET.roomList=res.roomList _unlock("fetchRoom") - -- elseif res.action==1 then + elseif res.action==1 then--Create room (not used) elseif res.action==2 then--Player join if res.type=="Self"then --Create room @@ -308,6 +309,7 @@ function NET.updateWS_play() 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 @@ -340,9 +342,13 @@ function NET.updateWS_stream() SCN.socketRead("Begin",res.data) elseif res.action==1 then--Game finished SCN.socketRead("Finish",res.data) - elseif res.action==2 then--Player died + 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==3 then--Receive stream + elseif res.action==5 then--Receive stream SCN.socketRead("Stream",res.data) end else diff --git a/parts/scenes/net_game.lua b/parts/scenes/net_game.lua index eee3a317..4a0690d1 100644 --- a/parts/scenes/net_game.lua +++ b/parts/scenes/net_game.lua @@ -1,4 +1,3 @@ -local data=love.data local gc=love.graphics local tc=love.touch @@ -142,19 +141,24 @@ function scene.gamepadUp(key) end end -function scene.socketRead(cmd,args) +function scene.socketRead(cmd,data) if cmd=="Join"then if playerInitialized then - local L=SPLITSTR(args[1],",") textBox:push{ - COLOR.lR,L[1], - COLOR.dY,"#"..L[2].." ", + COLOR.lR,data.username, + COLOR.dY,"#"..data.uid.." ", COLOR.Y,text.joinRoom, } end - for i=1,#args do - local L=SPLITSTR(args[i],",") - ins(PLY_NET,{name=L[1],id=L[2],sid=L[3],conf=L[4],ready=L[5]=="1"}) + local L=data.players + for i=1,#L do + ins(PLY_NET,{ + sid=L[i].sid, + uid=L[i].uid, + username=L[i].username, + conf=L[i].config, + ready=L[i].ready, + }) end playerInitialized=true SFX.play("click") @@ -163,88 +167,84 @@ function scene.socketRead(cmd,args) end 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,#PLY_NET do - if PLY_NET[i].id==args[2]then + if PLY_NET[i].id==data.uid then rem(PLY_NET,i) break end end for i=1,#PLAYERS do - if PLAYERS[i].userID==args[2]then + if PLAYERS[i].userID==data.uid then rem(PLAYERS,i) break end end for i=1,#PLY_ALIVE do - if PLY_ALIVE[i].userID==args[2]then + if PLY_ALIVE[i].userID==data.uid then rem(PLY_ALIVE,i) break end end initPlayerPosition(true) elseif cmd=="Talk"then - local _,text=pcall(data.decode,"string","base64",args[3]) - if not _ then text=args[3]end 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=="Config"then - if tostring(USER.id)~=args[2]then + if tostring(USER.id)~=data.uid then for i=1,#PLY_NET do - if PLY_NET[i].id==args[2]then - PLY_NET[i].conf=args[4] - PLY_NET[i].p:setConf(args[4]) + if PLY_NET[i].id==data.uid then + PLY_NET[i].conf=data.config + PLY_NET[i].p:setConf(data.config) return end end resetGameData("qn") end - elseif cmd=="Stream"then - if playing and args[1]~=PLAYERS[1].subID then - for _,P in next,PLAYERS do - if P.subID==args[1]then - local _,stream=pcall(data.decode,"string","base64",args[2]) - if _ then - pumpRecording(stream,P.stream) - else - LOG.print("Bad stream from "..P.userName.."#"..P.userID) - end - end - end - end elseif cmd=="Ready"then local L=PLY_ALIVE for i=1,#L do - if L[i].subID==args[1]then + if L[i].subID==data.uid then L[i].ready=true SFX.play("reach",.6) break end end elseif cmd=="Set"then + NET.rsid=data.rid NET.wsConnectStream() elseif cmd=="Begin"then if not playing then playing=true lastUpstreamTime=0 upstreamProgress=1 - resetGameData("n",tonumber(args[1])) + resetGameData("n",data.seed) else LOG.print("Redundant signal: B(begin)",30,COLOR.green) end elseif cmd=="Finish"then playing=false resetGameData("n") - for i=1,#PLY_NET do - if PLY_NET[i].sid==args[1]then - TEXT.show(text.champion:gsub("$1",PLY_NET[i].name.."#"..PLY_NET[i].id),640,260,80,"zoomout",.26) - break + 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 playing and data.uid~=PLAYERS[1].subID then + for _,P in next,PLAYERS do + if P.subID==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) + end + end end end end From 56bbd269c9592692fcc5c25d1e16b98880ea139c Mon Sep 17 00:00:00 2001 From: MrZ626 <1046101471@qq.com> Date: Mon, 5 Apr 2021 21:41:59 +0800 Subject: [PATCH 65/83] =?UTF-8?q?=E6=8D=A2=E6=96=B0=E5=87=86=E5=A4=87?= =?UTF-8?q?=E5=92=8C=E5=BD=95=E5=83=8F=E6=B5=81=E4=BC=A0=E8=BE=93=E7=9A=84?= =?UTF-8?q?=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- parts/scenes/net_game.lua | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/parts/scenes/net_game.lua b/parts/scenes/net_game.lua index 4a0690d1..3e53b3ab 100644 --- a/parts/scenes/net_game.lua +++ b/parts/scenes/net_game.lua @@ -208,17 +208,22 @@ function scene.socketRead(cmd,data) resetGameData("qn") end elseif cmd=="Ready"then - local L=PLY_ALIVE - for i=1,#L do - if L[i].subID==data.uid then - L[i].ready=true - SFX.play("reach",.6) - break + if data.uid==USER.id 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 @@ -235,9 +240,13 @@ function scene.socketRead(cmd,data) elseif cmd=="Die"then LOG.print("One player failed",COLOR.sky) elseif cmd=="Stream"then - if playing and data.uid~=PLAYERS[1].subID then + if data.uid==USER.id then + LOG.print("SELF STREAM") + return + end + if playing then for _,P in next,PLAYERS do - if P.subID==data.uid 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) From 27075d159633b28e4c58c3e192260bb1145d2090 Mon Sep 17 00:00:00 2001 From: MrZ626 <1046101471@qq.com> Date: Mon, 5 Apr 2021 21:42:11 +0800 Subject: [PATCH 66/83] =?UTF-8?q?=E6=B3=A8=E9=87=8A=E6=8E=89=E4=B8=80?= =?UTF-8?q?=E4=BA=9B=E6=B5=8B=E8=AF=95=E7=94=A8=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Zframework/websocket.lua | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Zframework/websocket.lua b/Zframework/websocket.lua index a0f30002..78d5200d 100644 --- a/Zframework/websocket.lua +++ b/Zframework/websocket.lua @@ -157,10 +157,10 @@ while true do--Running --Receive data local s,_,p=SOCK:receive(length) if s then - print(("%s[%d]:%s"):format(threadName,length,s)) + -- print(("%s[%d]:%s"):format(threadName,length,s)) res=s elseif p then--UNF head - print(("%s[%d/%d]:%s"):format(threadName,#p,length,p)) + -- print(("%s[%d/%d]:%s"):format(threadName,#p,length,p)) UFF=true sBuffer=sBuffer..p length=length-#p @@ -183,21 +183,21 @@ while true do--Running elseif op==0 then--0=continue lBuffer=lBuffer..res if fin then - -- print("FIN=1 (c") + -- print("FIN=1 (c") readCHN:push(lBuffer) lBuffer="" else - -- print("FIN=0 (c") + -- print("FIN=0 (c") end else readCHN:push(op) if fin then - -- print("OP: "..op.."\tFIN=1") + -- print("OP: "..op.."\tFIN=1") readCHN:push(res) else - -- print("OP: "..op.."\tFIN=0") + -- print("OP: "..op.."\tFIN=0") sBuffer=res - -- print("START pack: "..res) + -- print("START pack: "..res) end end end From d4a29db0514bcd2b5846297e66e18fea069d927b Mon Sep 17 00:00:00 2001 From: MrZ626 <1046101471@qq.com> Date: Mon, 5 Apr 2021 23:28:54 +0800 Subject: [PATCH 67/83] =?UTF-8?q?table=E6=89=A9=E5=B1=95=E6=A8=A1=E5=9D=97?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0clear=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Zframework/tableExtend.lua | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Zframework/tableExtend.lua b/Zframework/tableExtend.lua index bbd8c8e7..b3f9537e 100644 --- a/Zframework/tableExtend.lua +++ b/Zframework/tableExtend.lua @@ -40,6 +40,13 @@ function TABLE.add(G,base) end end +--Clear the table +function TABLE.clear(G) + for k in next,G do + G[k]=nil + end +end + --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 From e9fd74ef5d077f5596491104177db93ca5783bd5 Mon Sep 17 00:00:00 2001 From: MrZ626 <1046101471@qq.com> Date: Mon, 5 Apr 2021 23:31:39 +0800 Subject: [PATCH 68/83] =?UTF-8?q?=E7=BB=A7=E7=BB=AD=E5=AE=8C=E5=96=84?= =?UTF-8?q?=E8=81=94=E7=BD=91=EF=BC=8C=E8=B0=83=E6=95=B4=E7=8E=A9=E5=AE=B6?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=88=9D=E5=A7=8B=E5=8C=96=E8=BF=87=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- parts/net.lua | 11 ++++++++++- parts/player/init.lua | 6 ++++++ parts/scenes/net_game.lua | 23 ++++++++++++++++------- 3 files changed, 32 insertions(+), 8 deletions(-) diff --git a/parts/net.lua b/parts/net.lua index c4086d41..392c14f5 100644 --- a/parts/net.lua +++ b/parts/net.lua @@ -97,7 +97,7 @@ function NET.storeUserInfo(res) --Get own name if res.id==USER.id then - USER.name=res.name + USER.name=res.username FILE.save(USER,"conf/user") end @@ -293,6 +293,15 @@ function NET.updateWS_play() elseif res.action==2 then--Player join if res.type=="Self"then --Create room + TABLE.clear(PLY_NET) + local d=res.data + table.insert(PLY_NET,{ + conf=dumpBasicConfig(), + username=USER.name, + uid=USER.id, + sid=d.sid, + ready=d.ready, + }) loadGame("netBattle",true,true) _unlock("enterRoom") else diff --git a/parts/player/init.lua b/parts/player/init.lua index ac2f380d..88a5010c 100644 --- a/parts/player/init.lua +++ b/parts/player/init.lua @@ -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 @@ -405,6 +408,9 @@ function PLY.newPlayer(id,mini) P.type="human" P.sound=true + P.userID=USER.id + P.subID=-1 + loadGameEnv(P) applyGameEnv(P) end diff --git a/parts/scenes/net_game.lua b/parts/scenes/net_game.lua index 3e53b3ab..bfe4b1a3 100644 --- a/parts/scenes/net_game.lua +++ b/parts/scenes/net_game.lua @@ -150,14 +150,23 @@ function scene.socketRead(cmd,data) COLOR.Y,text.joinRoom, } end - local L=data.players - for i=1,#L do + if data.players then + for _,p in next,data.players do + ins(PLY_NET,{ + sid=p.sid, + uid=p.uid, + username=p.username, + conf=p.config, + ready=p.ready, + }) + end + else ins(PLY_NET,{ - sid=L[i].sid, - uid=L[i].uid, - username=L[i].username, - conf=L[i].config, - ready=L[i].ready, + sid=data.sid, + uid=data.uid, + username=data.username, + conf=data.config, + ready=data.ready, }) end playerInitialized=true From eb15bec707fbff4c3c62c2111f276cb523e30346 Mon Sep 17 00:00:00 2001 From: MrZ626 <1046101471@qq.com> Date: Tue, 6 Apr 2021 00:22:26 +0800 Subject: [PATCH 69/83] =?UTF-8?q?=E8=81=94=E7=BD=91=E6=8E=A8=E8=BF=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- parts/net.lua | 2 +- parts/scenes/net_game.lua | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/parts/net.lua b/parts/net.lua index 392c14f5..3a6546d7 100644 --- a/parts/net.lua +++ b/parts/net.lua @@ -297,7 +297,7 @@ function NET.updateWS_play() local d=res.data table.insert(PLY_NET,{ conf=dumpBasicConfig(), - username=USER.name, + name=USER.name, uid=USER.id, sid=d.sid, ready=d.ready, diff --git a/parts/scenes/net_game.lua b/parts/scenes/net_game.lua index bfe4b1a3..65fb034e 100644 --- a/parts/scenes/net_game.lua +++ b/parts/scenes/net_game.lua @@ -155,7 +155,7 @@ function scene.socketRead(cmd,data) ins(PLY_NET,{ sid=p.sid, uid=p.uid, - username=p.username, + name=p.username, conf=p.config, ready=p.ready, }) @@ -164,7 +164,7 @@ function scene.socketRead(cmd,data) ins(PLY_NET,{ sid=data.sid, uid=data.uid, - username=data.username, + name=data.username, conf=data.config, ready=data.ready, }) From 3b5d21fcd4023dff2a0c41cf2b7852dcdd7f3b6f Mon Sep 17 00:00:00 2001 From: MrZ626 <1046101471@qq.com> Date: Tue, 6 Apr 2021 00:43:10 +0800 Subject: [PATCH 70/83] =?UTF-8?q?=E6=95=B4=E7=90=86=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- parts/ai.lua | 2 +- parts/gametoolfunc.lua | 4 +--- parts/player/player.lua | 2 +- parts/scenes/dict.lua | 2 +- parts/scenes/net_game.lua | 4 ---- 5 files changed, 4 insertions(+), 10 deletions(-) diff --git a/parts/ai.lua b/parts/ai.lua index 0d4122df..6f2c0d93 100644 --- a/parts/ai.lua +++ b/parts/ai.lua @@ -73,7 +73,7 @@ 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) diff --git a/parts/gametoolfunc.lua b/parts/gametoolfunc.lua index 38e16886..161b5f45 100644 --- a/parts/gametoolfunc.lua +++ b/parts/gametoolfunc.lua @@ -537,9 +537,7 @@ function destroyPlayers()--Destroy all player objects, restore freerows and free end PLAYERS[i]=nil end - for i=#PLY_ALIVE,1,-1 do - PLY_ALIVE[i]=nil - end + TABLE.clear(PLY_ALIVE) collectgarbage() end function restoreVirtualkey() diff --git a/parts/player/player.lua b/parts/player/player.lua index 2844b383..195add8a 100644 --- a/parts/player/player.lua +++ b/parts/player/player.lua @@ -1725,7 +1725,7 @@ function Player:lose(force) if self.AI_mode=="CC"then CC.destroy(self.AI_bot) - while self.holdQueue[1]do rem(self.holdQueue)end + TABLE.clear(self.holdQueue) self:loadAI(self.AIdata) end diff --git a/parts/scenes/dict.lua b/parts/scenes/dict.lua index 9ae92356..5f394ad6 100644 --- a/parts/scenes/dict.lua +++ b/parts/scenes/dict.lua @@ -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 diff --git a/parts/scenes/net_game.lua b/parts/scenes/net_game.lua index 65fb034e..5bd9c6e3 100644 --- a/parts/scenes/net_game.lua +++ b/parts/scenes/net_game.lua @@ -14,7 +14,6 @@ local PLY_NET=PLY_NET local hideChatBox local textBox=WIDGET.newTextBox{name="texts",x=340,y=80,w=600,h=550,hide=function()return hideChatBox end} -local playerInitialized local playing local lastUpstreamTime local upstreamProgress @@ -31,16 +30,13 @@ end function scene.sceneInit() love.keyboard.setKeyRepeat(false) hideChatBox=true - playerInitialized=false textBox:clear() - while #PLY_NET>0 do rem(PLY_NET)end resetGameData("n") noTouch=not SETTING.VKSwitch playing=false lastUpstreamTime=0 upstreamProgress=1 - heartBeatTimer=0 end function scene.touchDown(x,y) From 9c120489649c46d9619178a9be24bb71b1d14143 Mon Sep 17 00:00:00 2001 From: MrZ626 <1046101471@qq.com> Date: Tue, 6 Apr 2021 01:06:32 +0800 Subject: [PATCH 71/83] =?UTF-8?q?=E8=81=94=E7=BD=91=E6=8E=A8=E8=BF=9B?= =?UTF-8?q?=EF=BC=88=E4=BF=AE=E6=94=B9=E5=A2=9E=E5=87=8F=E7=8E=A9=E5=AE=B6?= =?UTF-8?q?=E7=9B=B8=E5=85=B3=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- parts/net.lua | 47 +++++++++++++++++++++++++------- parts/scenes/net_game.lua | 56 ++++++--------------------------------- 2 files changed, 46 insertions(+), 57 deletions(-) diff --git a/parts/net.lua b/parts/net.lua index 3a6546d7..2f2ca350 100644 --- a/parts/net.lua +++ b/parts/net.lua @@ -1,4 +1,5 @@ local data=love.data +local ins,rem=table.insert,table.remove local NET={ login=false, allow_online=false, @@ -294,21 +295,49 @@ function NET.updateWS_play() if res.type=="Self"then --Create room TABLE.clear(PLY_NET) - local d=res.data - table.insert(PLY_NET,{ - conf=dumpBasicConfig(), - name=USER.name, - uid=USER.id, - sid=d.sid, - ready=d.ready, - }) + if data.players then + for _,p in next,data.players do + ins(PLY_NET,{ + sid=p.sid, + uid=p.uid, + name=p.username, + conf=p.config, + ready=p.ready, + }) + end + end loadGame("netBattle",true,true) _unlock("enterRoom") else - --Others join room + --Load other players + ins(PLY_NET,{ + sid=data.sid, + uid=data.uid, + name=data.username, + conf=data.config, + ready=data.ready, + }) SCN.socketRead("Join",res.data) end elseif res.action==3 then--Player leave + for i=1,#PLY_NET do + if PLY_NET[i].id==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) diff --git a/parts/scenes/net_game.lua b/parts/scenes/net_game.lua index 5bd9c6e3..d7158b5b 100644 --- a/parts/scenes/net_game.lua +++ b/parts/scenes/net_game.lua @@ -1,7 +1,7 @@ local gc=love.graphics local tc=love.touch -local ins,rem=table.insert,table.remove +local ins=table.insert local SCR=SCR local VK=virtualkey @@ -9,8 +9,6 @@ local onVirtualkey=onVirtualkey local pressVirtualkey=pressVirtualkey local updateVirtualkey=updateVirtualkey -local PLY_NET=PLY_NET - local hideChatBox local textBox=WIDGET.newTextBox{name="texts",x=340,y=80,w=600,h=550,hide=function()return hideChatBox end} @@ -139,33 +137,11 @@ end function scene.socketRead(cmd,data) if cmd=="Join"then - if playerInitialized then - textBox:push{ - COLOR.lR,data.username, - COLOR.dY,"#"..data.uid.." ", - COLOR.Y,text.joinRoom, - } - end - if data.players then - for _,p in next,data.players do - ins(PLY_NET,{ - sid=p.sid, - uid=p.uid, - name=p.username, - conf=p.config, - ready=p.ready, - }) - end - else - ins(PLY_NET,{ - sid=data.sid, - uid=data.uid, - name=data.username, - conf=data.config, - ready=data.ready, - }) - end - playerInitialized=true + textBox:push{ + COLOR.lR,data.username, + COLOR.dY,"#"..data.uid.." ", + COLOR.Y,text.joinRoom, + } SFX.play("click") if not playing then resetGameData("qn") @@ -176,25 +152,9 @@ function scene.socketRead(cmd,data) COLOR.dY,"#"..data.uid.." ", COLOR.Y,text.leaveRoom, } - for i=1,#PLY_NET do - if PLY_NET[i].id==data.uid then - rem(PLY_NET,i) - break - end + if not playing then + initPlayerPosition(true) 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 - initPlayerPosition(true) elseif cmd=="Talk"then textBox:push{ COLOR.W,data.username, From 5405244e4baa0dd597c35bcc61322d385a6f5bf6 Mon Sep 17 00:00:00 2001 From: MrZ626 <1046101471@qq.com> Date: Tue, 6 Apr 2021 01:15:14 +0800 Subject: [PATCH 72/83] =?UTF-8?q?ws=E5=BA=93=E5=A2=9E=E5=8A=A0debug?= =?UTF-8?q?=E6=A8=A1=E5=BC=8F=E5=8F=98=E9=87=8F=EF=BC=88=E4=B8=8D=E5=BD=B1?= =?UTF-8?q?=E5=93=8D=E6=80=A7=E8=83=BD=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Zframework/websocket.lua | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/Zframework/websocket.lua b/Zframework/websocket.lua index 78d5200d..13988ffb 100644 --- a/Zframework/websocket.lua +++ b/Zframework/websocket.lua @@ -4,6 +4,8 @@ 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 @@ -157,10 +159,10 @@ while true do--Running --Receive data local s,_,p=SOCK:receive(length) if s then - -- print(("%s[%d]:%s"):format(threadName,length,s)) + ]]..(debug==1 and""or"--")..[[print(("%s[%d]:%s"):format(threadName,length,s)) res=s elseif p then--UNF head - -- print(("%s[%d/%d]:%s"):format(threadName,#p,length,p)) + ]]..(debug==1 and""or"--")..[[print(("%s[%d/%d]:%s"):format(threadName,#p,length,p)) UFF=true sBuffer=sBuffer..p length=length-#p @@ -183,21 +185,21 @@ while true do--Running elseif op==0 then--0=continue lBuffer=lBuffer..res if fin then - -- print("FIN=1 (c") + ]]..(debug==2 and""or"--")..[[print("FIN=1 (c") readCHN:push(lBuffer) lBuffer="" else - -- print("FIN=0 (c") + ]]..(debug==2 and""or"--")..[[print("FIN=0 (c") end else readCHN:push(op) if fin then - -- print("OP: "..op.."\tFIN=1") + ]]..(debug==2 and""or"--")..[[print("OP: "..op.."\tFIN=1") readCHN:push(res) else - -- print("OP: "..op.."\tFIN=0") + ]]..(debug==2 and""or"--")..[[print("OP: "..op.."\tFIN=0") sBuffer=res - -- print("START pack: "..res) + ]]..(debug==2 and""or"--")..[[print("START pack: "..res) end end end From 708de3360324dab911beb151668e75d49eb94ffe Mon Sep 17 00:00:00 2001 From: MrZ626 <1046101471@qq.com> Date: Tue, 6 Apr 2021 12:59:10 +0800 Subject: [PATCH 73/83] =?UTF-8?q?=E5=A2=9E=E5=BC=BA=E7=82=B9=E5=87=BB?= =?UTF-8?q?=E7=89=B9=E6=95=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Zframework/sysFX.lua | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/Zframework/sysFX.lua b/Zframework/sysFX.lua index e0d458b0..3f2204bb 100644 --- a/Zframework/sysFX.lua +++ b/Zframework/sysFX.lua @@ -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]={ From 677456456d5335a018eec69d55638fec9b71cd81 Mon Sep 17 00:00:00 2001 From: MrZ626 <1046101471@qq.com> Date: Tue, 6 Apr 2021 13:05:51 +0800 Subject: [PATCH 74/83] =?UTF-8?q?=E6=94=B9=E6=AD=A3=E4=B8=80=E5=A4=84?= =?UTF-8?q?=E4=B8=B4=E6=97=B6=E5=8F=98=E9=87=8F=E6=B2=A1=E6=9C=89local?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- parts/player/update.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parts/player/update.lua b/parts/player/update.lua index ecb0c39c..2e7048fc 100644 --- a/parts/player/update.lua +++ b/parts/player/update.lua @@ -131,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 From 24e97e10c839d0d0761297b41eb1ff0d23abad5b Mon Sep 17 00:00:00 2001 From: MrZ626 <1046101471@qq.com> Date: Tue, 6 Apr 2021 14:47:29 +0800 Subject: [PATCH 75/83] =?UTF-8?q?=E8=81=94=E7=BD=91=E6=8E=A8=E8=BF=9B?= =?UTF-8?q?=EF=BC=88=E4=BF=AE=E6=94=B9=E6=88=BF=E9=97=B4=E5=86=85=E7=94=A8?= =?UTF-8?q?=E6=88=B7=E4=BF=A1=E6=81=AF=E7=9B=B8=E5=85=B3=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- parts/modes/netBattle.lua | 2 +- parts/net.lua | 9 ++++++++- parts/player/init.lua | 14 +++++++------- parts/scenes/net_game.lua | 2 +- 4 files changed, 17 insertions(+), 10 deletions(-) diff --git a/parts/modes/netBattle.lua b/parts/modes/netBattle.lua index 45f8cbf4..db8c1a92 100644 --- a/parts/modes/netBattle.lua +++ b/parts/modes/netBattle.lua @@ -10,7 +10,7 @@ return{ PLY.newPlayer(1) local N=2 for i=1,#PLY_NET do - if PLY_NET[i].id==tostring(USER.id)then + if PLY_NET[i].uid==USER.id then PLAYERS[1].subID=PLY_NET[1].sid else PLY.newRemotePlayer(N,false,PLY_NET[i]) diff --git a/parts/net.lua b/parts/net.lua index 2f2ca350..c08fb8a6 100644 --- a/parts/net.lua +++ b/parts/net.lua @@ -295,6 +295,13 @@ function NET.updateWS_play() if res.type=="Self"then --Create room TABLE.clear(PLY_NET) + ins(PLY_NET,{ + uid=USER.id, + name=USER.name, + conf=dumpBasicConfig(), + sid=data.sid, + ready=data.ready, + }) if data.players then for _,p in next,data.players do ins(PLY_NET,{ @@ -321,7 +328,7 @@ function NET.updateWS_play() end elseif res.action==3 then--Player leave for i=1,#PLY_NET do - if PLY_NET[i].id==data.uid then + if PLY_NET[i].uid==data.uid then rem(PLY_NET,i) break end diff --git a/parts/player/init.lua b/parts/player/init.lua index 88a5010c..1a6d4804 100644 --- a/parts/player/init.lua +++ b/parts/player/init.lua @@ -372,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 @@ -382,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.userName=data.name + P.userID=data.uid + P.subID=data.sid + P.ready=data.ready - loadRemoteEnv(P,playerData.conf) + loadRemoteEnv(P,data.conf) applyGameEnv(P) end diff --git a/parts/scenes/net_game.lua b/parts/scenes/net_game.lua index d7158b5b..9c0e8edd 100644 --- a/parts/scenes/net_game.lua +++ b/parts/scenes/net_game.lua @@ -164,7 +164,7 @@ function scene.socketRead(cmd,data) elseif cmd=="Config"then if tostring(USER.id)~=data.uid then for i=1,#PLY_NET do - if PLY_NET[i].id==data.uid then + if PLY_NET[i].uid==data.uid then PLY_NET[i].conf=data.config PLY_NET[i].p:setConf(data.config) return From 202559211c52bae67181c23221d2671b841739c3 Mon Sep 17 00:00:00 2001 From: MrZ626 <1046101471@qq.com> Date: Tue, 6 Apr 2021 14:53:52 +0800 Subject: [PATCH 76/83] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=85=A8=E5=B1=80?= =?UTF-8?q?=E7=BB=93=E6=9E=84=E4=BD=93=E5=8F=98=E9=87=8FUSER=E7=9A=84?= =?UTF-8?q?=E6=88=90=E5=91=98=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- parts/gametoolfunc.lua | 2 +- parts/globalTables.lua | 4 ++-- parts/modes/netBattle.lua | 2 +- parts/net.lua | 20 ++++++++++---------- parts/player/init.lua | 2 +- parts/scenes/load.lua | 2 +- parts/scenes/net_game.lua | 6 +++--- 7 files changed, 19 insertions(+), 19 deletions(-) diff --git a/parts/gametoolfunc.lua b/parts/gametoolfunc.lua index 161b5f45..1d6440d0 100644 --- a/parts/gametoolfunc.lua +++ b/parts/gametoolfunc.lua @@ -956,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".. diff --git a/parts/globalTables.lua b/parts/globalTables.lua index 9a8e96b9..ece00317 100644 --- a/parts/globalTables.lua +++ b/parts/globalTables.lua @@ -222,8 +222,8 @@ 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, + username=false, + uid=false, authToken=false, --Local data diff --git a/parts/modes/netBattle.lua b/parts/modes/netBattle.lua index db8c1a92..41925c8b 100644 --- a/parts/modes/netBattle.lua +++ b/parts/modes/netBattle.lua @@ -10,7 +10,7 @@ return{ PLY.newPlayer(1) local N=2 for i=1,#PLY_NET do - if PLY_NET[i].uid==USER.id then + if PLY_NET[i].uid==USER.uid then PLAYERS[1].subID=PLY_NET[1].sid else PLY.newRemotePlayer(N,false,PLY_NET[i]) diff --git a/parts/net.lua b/parts/net.lua index c08fb8a6..c6e26756 100644 --- a/parts/net.lua +++ b/parts/net.lua @@ -77,7 +77,7 @@ function NET.getUserInfo(id,ifDetail) WS.send("user",JSON.encode{ action=1, data={ - id=id or USER.id, + id=id or USER.uid, detailed=ifDetail or false, }, }) @@ -97,8 +97,8 @@ function NET.storeUserInfo(res) end --Get own name - if res.id==USER.id then - USER.name=res.username + if res.id==USER.uid then + USER.username=res.username FILE.save(USER,"conf/user") end @@ -124,7 +124,7 @@ function NET.createRoom() action=1, data={ type="classic", - name=(USER.name or"???").."'s room", + name=(USER.username or"???").."'s room", password=nil, config=dumpBasicConfig(), } @@ -149,7 +149,7 @@ end function NET.wsConnectPlay() if _lock("connectPlay")then WS.connect("play","/play",JSON.encode{ - id=USER.id, + id=USER.uid, accessToken=NET.accessToken, }) end @@ -165,7 +165,7 @@ end function NET.wsConnectStream() if _lock("connectStream")then WS.connect("stream","/stream",JSON.encode{ - uid=USER.id, + uid=USER.uid, accessToken=NET.accessToken, rid=NET.rsid, }) @@ -243,7 +243,7 @@ function NET.updateWS_user() if res.type=="Connect"then NET.login=true if res.id then - USER.id=res.id + USER.uid=res.id USER.authToken=res.authToken FILE.save(USER,"conf/user","q") SCN.back() @@ -251,7 +251,7 @@ function NET.updateWS_user() LOG.print(text.loginSuccessed) --Get self infos - NET.getUserInfo(USER.id) + NET.getUserInfo(USER.uid) elseif res.action==0 then--Get accessToken NET.accessToken=res.accessToken LOG.print(text.accessSuccessed) @@ -296,8 +296,8 @@ function NET.updateWS_play() --Create room TABLE.clear(PLY_NET) ins(PLY_NET,{ - uid=USER.id, - name=USER.name, + uid=USER.uid, + name=USER.username, conf=dumpBasicConfig(), sid=data.sid, ready=data.ready, diff --git a/parts/player/init.lua b/parts/player/init.lua index 1a6d4804..72691a4a 100644 --- a/parts/player/init.lua +++ b/parts/player/init.lua @@ -408,7 +408,7 @@ function PLY.newPlayer(id,mini) P.type="human" P.sound=true - P.userID=USER.id + P.userID=USER.uid P.subID=-1 loadGameEnv(P) diff --git a/parts/scenes/load.lua b/parts/scenes/load.lua index baacbed4..3609fa84 100644 --- a/parts/scenes/load.lua +++ b/parts/scenes/load.lua @@ -183,7 +183,7 @@ local loadingThread=coroutine.wrap(function() WS.connect("app","/app") if USER.authToken then WS.connect("user","/user",JSON.encode{ - id=USER.id, + id=USER.uid, authToken=USER.authToken, }) end diff --git a/parts/scenes/net_game.lua b/parts/scenes/net_game.lua index 9c0e8edd..52bbcd61 100644 --- a/parts/scenes/net_game.lua +++ b/parts/scenes/net_game.lua @@ -162,7 +162,7 @@ function scene.socketRead(cmd,data) COLOR.sky,data.message or"[_]", } elseif cmd=="Config"then - if tostring(USER.id)~=data.uid 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 @@ -173,7 +173,7 @@ function scene.socketRead(cmd,data) resetGameData("qn") end elseif cmd=="Ready"then - if data.uid==USER.id then + if data.uid==USER.uid then PLAYERS[1].ready=true SFX.play("reach",.6) else @@ -205,7 +205,7 @@ function scene.socketRead(cmd,data) elseif cmd=="Die"then LOG.print("One player failed",COLOR.sky) elseif cmd=="Stream"then - if data.uid==USER.id then + if data.uid==USER.uid then LOG.print("SELF STREAM") return end From c2cfb709bb8fe66e25d5185246f35063f7f3ed72 Mon Sep 17 00:00:00 2001 From: MrZ626 <1046101471@qq.com> Date: Tue, 6 Apr 2021 15:02:52 +0800 Subject: [PATCH 77/83] =?UTF-8?q?=E8=81=94=E7=BD=91=E6=8E=A8=E8=BF=9B?= =?UTF-8?q?=EF=BC=88=E6=95=B4=E7=90=86=E4=BB=A3=E7=A0=81=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- parts/net.lua | 16 ++++++++-------- parts/player/init.lua | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/parts/net.lua b/parts/net.lua index c6e26756..7485fda8 100644 --- a/parts/net.lua +++ b/parts/net.lua @@ -297,19 +297,19 @@ function NET.updateWS_play() TABLE.clear(PLY_NET) ins(PLY_NET,{ uid=USER.uid, - name=USER.username, - conf=dumpBasicConfig(), + username=USER.username, sid=data.sid, ready=data.ready, + conf=dumpBasicConfig(), }) if data.players then for _,p in next,data.players do ins(PLY_NET,{ - sid=p.sid, uid=p.uid, - name=p.username, - conf=p.config, + username=p.username, + sid=p.sid, ready=p.ready, + conf=p.config, }) end end @@ -318,11 +318,11 @@ function NET.updateWS_play() else --Load other players ins(PLY_NET,{ - sid=data.sid, uid=data.uid, - name=data.username, - conf=data.config, + username=data.username, + sid=data.sid, ready=data.ready, + conf=data.config, }) SCN.socketRead("Join",res.data) end diff --git a/parts/player/init.lua b/parts/player/init.lua index 72691a4a..6c39c9be 100644 --- a/parts/player/init.lua +++ b/parts/player/init.lua @@ -383,12 +383,12 @@ function PLY.newRemotePlayer(id,mini,data) P.streamProgress=1 data.p=P - P.userName=data.name P.userID=data.uid + P.userName=data.username P.subID=data.sid P.ready=data.ready - loadRemoteEnv(P,data.conf) + applyGameEnv(P) end From 65faa84351b07dea77aa4052ba5f71ef76e72af5 Mon Sep 17 00:00:00 2001 From: MrZ626 <1046101471@qq.com> Date: Tue, 6 Apr 2021 15:20:02 +0800 Subject: [PATCH 78/83] =?UTF-8?q?=E6=95=B4=E7=90=86table=E6=89=A9=E5=B1=95?= =?UTF-8?q?=E6=A8=A1=E5=9D=97=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Zframework/tableExtend.lua | 25 ++++++++++++++++--------- parts/globalTables.lua | 2 +- parts/scenes/savedata.lua | 8 ++++---- 3 files changed, 21 insertions(+), 14 deletions(-) diff --git a/Zframework/tableExtend.lua b/Zframework/tableExtend.lua index b3f9537e..fea18fea 100644 --- a/Zframework/tableExtend.lua +++ b/Zframework/tableExtend.lua @@ -28,11 +28,11 @@ function TABLE.copy(org) end --For all things in G if same type in base, push to base -function TABLE.add(G,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 @@ -40,13 +40,6 @@ function TABLE.add(G,base) end end ---Clear the table -function TABLE.clear(G) - for k in next,G do - G[k]=nil - end -end - --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 @@ -58,6 +51,20 @@ function TABLE.complete(G,base) 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 diff --git a/parts/globalTables.lua b/parts/globalTables.lua index ece00317..501ee680 100644 --- a/parts/globalTables.lua +++ b/parts/globalTables.lua @@ -299,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 diff --git a/parts/scenes/savedata.lua b/parts/scenes/savedata.lua index e5b8eacb..8050e8aa 100644 --- a/parts/scenes/savedata.lua +++ b/parts/scenes/savedata.lua @@ -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 From 9fdb50d12aff808bd1b531746113fa145120b7de Mon Sep 17 00:00:00 2001 From: MrZ626 <1046101471@qq.com> Date: Tue, 6 Apr 2021 15:23:45 +0800 Subject: [PATCH 79/83] =?UTF-8?q?=E8=81=94=E7=BD=91=E6=8E=A8=E8=BF=9B?= =?UTF-8?q?=EF=BC=88=E7=94=A8=E6=88=B7=E5=90=8D=E7=9B=B8=E5=85=B3=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- parts/net.lua | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/parts/net.lua b/parts/net.lua index 7485fda8..41884e26 100644 --- a/parts/net.lua +++ b/parts/net.lua @@ -83,12 +83,12 @@ function NET.getUserInfo(id,ifDetail) }) end function NET.storeUserInfo(res) - local user=USERS[res.id] + local user=USERS[res.uid] if not user then user={} user.email=res.email user.name=res.username - USERS[res.id]=user + USERS[res.uid]=user else user.email=res.email user.name=res.username @@ -97,7 +97,7 @@ function NET.storeUserInfo(res) end --Get own name - if res.id==USER.uid then + if res.uid==USER.uid then USER.username=res.username FILE.save(USER,"conf/user") end @@ -242,8 +242,8 @@ function NET.updateWS_user() if res then if res.type=="Connect"then NET.login=true - if res.id then - USER.uid=res.id + if res.uid then + USER.uid=res.uid USER.authToken=res.authToken FILE.save(USER,"conf/user","q") SCN.back() From c6db6834e9ca9fcff4022e467c5817235ad2299f Mon Sep 17 00:00:00 2001 From: MrZ626 <1046101471@qq.com> Date: Tue, 6 Apr 2021 15:26:59 +0800 Subject: [PATCH 80/83] =?UTF-8?q?=E8=81=94=E7=BD=91=E6=8E=A8=E8=BF=9B?= =?UTF-8?q?=EF=BC=88=E7=94=A8=E6=88=B7=E5=90=8D=E7=9B=B8=E5=85=B3*2?= =?UTF-8?q?=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- parts/net.lua | 2 +- parts/scenes/load.lua | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/parts/net.lua b/parts/net.lua index 41884e26..991a07a4 100644 --- a/parts/net.lua +++ b/parts/net.lua @@ -149,7 +149,7 @@ end function NET.wsConnectPlay() if _lock("connectPlay")then WS.connect("play","/play",JSON.encode{ - id=USER.uid, + uid=USER.uid, accessToken=NET.accessToken, }) end diff --git a/parts/scenes/load.lua b/parts/scenes/load.lua index 3609fa84..9685dfa1 100644 --- a/parts/scenes/load.lua +++ b/parts/scenes/load.lua @@ -183,7 +183,7 @@ local loadingThread=coroutine.wrap(function() WS.connect("app","/app") if USER.authToken then WS.connect("user","/user",JSON.encode{ - id=USER.uid, + uid=USER.uid, authToken=USER.authToken, }) end From c245c076f9711e58ca3233b0f52c19239d0dc75b Mon Sep 17 00:00:00 2001 From: MrZ626 <1046101471@qq.com> Date: Tue, 6 Apr 2021 15:41:37 +0800 Subject: [PATCH 81/83] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=94=99=E8=A7=A3?= =?UTF-8?q?=E6=9E=90=E6=9C=8D=E5=8A=A1=E5=99=A8=E5=8F=91=E9=80=81=E7=9A=84?= =?UTF-8?q?=E7=8E=A9=E5=AE=B6=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- parts/net.lua | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/parts/net.lua b/parts/net.lua index 991a07a4..0a35a405 100644 --- a/parts/net.lua +++ b/parts/net.lua @@ -292,18 +292,19 @@ function NET.updateWS_play() _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=data.sid, - ready=data.ready, + sid=d.sid, + ready=d.ready, conf=dumpBasicConfig(), }) - if data.players then - for _,p in next,data.players do + if d.players then + for _,p in next,d.players do ins(PLY_NET,{ uid=p.uid, username=p.username, @@ -318,11 +319,11 @@ function NET.updateWS_play() else --Load other players ins(PLY_NET,{ - uid=data.uid, - username=data.username, - sid=data.sid, - ready=data.ready, - conf=data.config, + uid=d.uid, + username=d.username, + sid=d.sid, + ready=d.ready, + conf=d.config, }) SCN.socketRead("Join",res.data) end From ae8e8825b706c81f5d6d13cb45cd87a877c59854 Mon Sep 17 00:00:00 2001 From: MrZ626 <1046101471@qq.com> Date: Wed, 7 Apr 2021 09:22:44 +0800 Subject: [PATCH 82/83] =?UTF-8?q?=E7=89=88=E6=9C=AC=E5=8F=B7=E6=94=B9?= =?UTF-8?q?=E4=B8=BA0.14.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- conf.lua | 4 ++-- main.lua | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/conf.lua b/conf.lua index abcb88f0..df78d08c 100644 --- a/conf.lua +++ b/conf.lua @@ -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" diff --git a/main.lua b/main.lua index 71fd62dd..f34549a9 100644 --- a/main.lua +++ b/main.lua @@ -255,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 @@ -270,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 From e42a0102c2c93f7eb5dd59123b958eef6b361bbd Mon Sep 17 00:00:00 2001 From: MrZ626 <1046101471@qq.com> Date: Wed, 7 Apr 2021 09:34:42 +0800 Subject: [PATCH 83/83] =?UTF-8?q?0.14.0=E7=9A=84=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=E6=97=A5=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- parts/updateLog.lua | 88 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 67 insertions(+), 21 deletions(-) diff --git a/parts/updateLog.lua b/parts/updateLog.lua index 281659a7..2ba70aef 100644 --- a/parts/updateLog.lua +++ b/parts/updateLog.lua @@ -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功能(暂时只在自定义开放)