Merge pull request #904 from 26F-Studio/ci-web-test

Ci web test
This commit is contained in:
Particle_G
2023-06-15 10:56:52 +08:00
committed by GitHub
18 changed files with 274 additions and 213 deletions

View File

@@ -143,7 +143,8 @@ jobs:
build-android: build-android:
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: [get-info, build-core, auto-test] needs: [get-info, build-core, auto-test]
if: github.event_name != 'pull_request' # if: github.event_name != 'pull_request'
if: ${{ !always() }}
env: env:
OUTPUT_FOLDER: ./build OUTPUT_FOLDER: ./build
RELEASE_FOLDER: ./release RELEASE_FOLDER: ./release
@@ -216,7 +217,8 @@ jobs:
build-ios: build-ios:
runs-on: macos-latest runs-on: macos-latest
needs: [get-info, build-core, auto-test] needs: [get-info, build-core, auto-test]
if: github.event_name != 'pull_request' # if: github.event_name != 'pull_request'
if: ${{ !always() }}
env: env:
OUTPUT_FOLDER: ./build OUTPUT_FOLDER: ./build
RELEASE_FOLDER: ./release RELEASE_FOLDER: ./release
@@ -297,6 +299,7 @@ jobs:
build-linux: build-linux:
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: [get-info, build-core, auto-test] needs: [get-info, build-core, auto-test]
if: ${{ !always() }}
env: env:
OUTPUT_FOLDER: ./build OUTPUT_FOLDER: ./build
RELEASE_FOLDER: ./release RELEASE_FOLDER: ./release
@@ -380,7 +383,8 @@ jobs:
build-macos-appstore: build-macos-appstore:
runs-on: macos-latest runs-on: macos-latest
needs: [get-info, build-core, auto-test] needs: [get-info, build-core, auto-test]
if: github.event_name != 'pull_request' # if: github.event_name != 'pull_request'
if: ${{ !always() }}
env: env:
OUTPUT_FOLDER: ./build OUTPUT_FOLDER: ./build
RELEASE_FOLDER: ./release RELEASE_FOLDER: ./release
@@ -464,7 +468,8 @@ jobs:
build-macos-portable: build-macos-portable:
runs-on: macos-latest runs-on: macos-latest
needs: [get-info, build-core, auto-test] needs: [get-info, build-core, auto-test]
if: github.event_name != 'pull_request' # if: github.event_name != 'pull_request'
if: ${{ !always() }}
env: env:
OUTPUT_FOLDER: ./build OUTPUT_FOLDER: ./build
RELEASE_FOLDER: ./release RELEASE_FOLDER: ./release
@@ -560,6 +565,7 @@ jobs:
build-windows: build-windows:
runs-on: windows-latest runs-on: windows-latest
needs: [get-info, build-core, auto-test] needs: [get-info, build-core, auto-test]
if: ${{ !always() }}
env: env:
OUTPUT_FOLDER: ./build OUTPUT_FOLDER: ./build
RELEASE_FOLDER: ./release RELEASE_FOLDER: ./release

View File

@@ -2,6 +2,15 @@ SYSTEM=love._os if SYSTEM=='OS X' then SYSTEM='macOS' end
MOBILE=SYSTEM=='Android' or SYSTEM=='iOS' MOBILE=SYSTEM=='Android' or SYSTEM=='iOS'
FNNS=SYSTEM:find'\79\83'-- What does FNSF stand for? IDK so don't ask me lol FNNS=SYSTEM:find'\79\83'-- What does FNSF stand for? IDK so don't ask me lol
if SYSTEM=='Web' then
local oldRead=love.filesystem.read
function love.filesystem.read(name,size)
if love.filesystem.getInfo(name) then
return oldRead(name,size)
end
end
end
function love.conf(t) function love.conf(t)
local identity='Techmino' local identity='Techmino'
local msaa=0 local msaa=0

View File

@@ -10,8 +10,7 @@
Instructions: Instructions:
1. I made a framework called Zframework, *most* code in Zframework are not directly relevant to game; 1. I made a framework called Zframework, *most* code in Zframework are not directly relevant to game;
2. "xxx" are texts for reading by player, 'xxx' are string values just used in program; 2. "xxx" are texts for reading by player, 'xxx' are string values just used in program;
3. Some goto statement are used for better performance. All goto-labes have detailed names so don't be afraid; 3. Except "gcinfo" function of lua itself, other "gc" are short for "graphics";
4. Except "gcinfo" function of lua itself, other "gc" are short for "graphics";
]]-- ]]--
@@ -560,16 +559,15 @@ applySettings()
-- Load replays -- Load replays
for _,fileName in next,fs.getDirectoryItems('replay') do for _,fileName in next,fs.getDirectoryItems('replay') do
if fileName:sub(12,12):match("[a-zA-Z]") then if fileName:sub(12,12):match("[a-zA-Z]") then repeat
local date,mode,version,player,seed,setting,mod local date,mode,version,player,seed,setting,mod
local fileData=fs.read('replay/'..fileName) local success,fileData=true,fs.read('replay/'..fileName)
date, fileData=STRING.readLine(fileData)date=date:gsub("[a-zA-Z]","") date, fileData=STRING.readLine(fileData)date=date:gsub("[a-zA-Z]","")
mode, fileData=STRING.readLine(fileData)mode=MODE_UPDATE_MAP[mode] or mode mode, fileData=STRING.readLine(fileData)mode=MODE_UPDATE_MAP[mode] or mode
version,fileData=STRING.readLine(fileData) version,fileData=STRING.readLine(fileData)
player, fileData=STRING.readLine(fileData) if player=="Local Player" then player="Stacker" end player, fileData=STRING.readLine(fileData) if player=="Local Player" then player="Stacker" end
local success
success,fileData=pcall(love.data.decompress,'string','zlib',fileData) success,fileData=pcall(love.data.decompress,'string','zlib',fileData)
if not success then goto BREAK_cannotParse end if not success then break end
seed, fileData=STRING.readLine(fileData) seed, fileData=STRING.readLine(fileData)
setting,fileData=STRING.readLine(fileData)setting=JSON.decode(setting) setting,fileData=STRING.readLine(fileData)setting=JSON.decode(setting)
mod, fileData=STRING.readLine(fileData)mod=JSON.decode(mod) mod, fileData=STRING.readLine(fileData)mod=JSON.decode(mod)
@@ -578,7 +576,7 @@ for _,fileName in next,fs.getDirectoryItems('replay') do
not mod or not mod or
not mode or not mode or
#mode==0 #mode==0
then goto BREAK_cannotParse end then break end
fs.remove('replay/'..fileName) fs.remove('replay/'..fileName)
local newName=fileName:sub(1,10)..fileName:sub(15) local newName=fileName:sub(1,10)..fileName:sub(15)
@@ -597,8 +595,7 @@ for _,fileName in next,fs.getDirectoryItems('replay') do
) )
) )
fileName=newName fileName=newName
end until true end
::BREAK_cannotParse::
local rep=DATA.parseReplay('replay/'..fileName) local rep=DATA.parseReplay('replay/'..fileName)
table.insert(REPLAY,rep) table.insert(REPLAY,rep)
end end

View File

@@ -65,14 +65,19 @@ local function _getScore(field,cb,cy)
local hole=0 local hole=0
for i=cy+#cb-1,cy,-1 do for i=cy+#cb-1,cy,-1 do
local full=true
for j=1,10 do for j=1,10 do
if field[i][j]==0 then if field[i][j]==0 then
goto CONTINUE_notFull -- goto CONTINUE_notFull
full=false
break
end end
end end
discardRow(rem(field,i)) if full then
clear=clear+1 -- ::CONTINUE_notFull::
::CONTINUE_notFull:: discardRow(rem(field,i))
clear=clear+1
end
end end
if #field==0 then-- PC if #field==0 then-- PC
return 1e99 return 1e99

View File

@@ -376,22 +376,26 @@ function DATA.parseReplay(fileName,ifFull)
return DATA.parseReplayData(fileName,fileData,ifFull) return DATA.parseReplayData(fileName,fileData,ifFull)
end end
function DATA.parseReplayData(fileName,fileData,ifFull) function DATA.parseReplayData(fileName,fileData,ifFull)
local success,metaData,rep local success,metaData
local rep={-- unavailable replay object
fileName=fileName,
available=false,
}
if not (fileData and #fileData>0) then goto BREAK_cannotParse end if not (fileData and #fileData>0) then return rep end-- goto BREAK_cannotParse
-- Decompress file -- Decompress file
success,fileData=pcall(love.data.decompress,'string','zlib',fileData) success,fileData=pcall(love.data.decompress,'string','zlib',fileData)
if not success then goto BREAK_cannotParse end if not success then return rep end-- goto BREAK_cannotParse
-- Load metadata -- Load metadata
metaData,fileData=STRING.readLine(fileData) metaData,fileData=STRING.readLine(fileData)
metaData=JSON.decode(metaData) metaData=JSON.decode(metaData)
if not metaData then goto BREAK_cannotParse end if not metaData then return rep end-- goto BREAK_cannotParse
-- Convert ancient replays -- Convert ancient replays
metaData.mode=MODE_UPDATE_MAP[metaData.mode] or metaData.mode metaData.mode=MODE_UPDATE_MAP[metaData.mode] or metaData.mode
if not MODES[metaData.mode] then goto BREAK_cannotParse end if not MODES[metaData.mode] then return rep end-- goto BREAK_cannotParse
-- Create replay object -- Create replay object
rep={ rep={
@@ -409,13 +413,6 @@ function DATA.parseReplayData(fileName,fileData,ifFull)
tasUsed=metaData.tasUsed, tasUsed=metaData.tasUsed,
} }
if ifFull then rep.data=fileData end if ifFull then rep.data=fileData end
do return rep end return rep
-- Create unavailable replay object
::BREAK_cannotParse::
return {
fileName=fileName,
available=false,
}
end end
return DATA return DATA

View File

@@ -76,15 +76,17 @@ return {
D.rankPts=1 D.rankPts=1
for i=1,#P.field do for i=1,#P.field do
local h=getOpenHole(i) local h=getOpenHole(i)
local flag
for j=1,10 do for j=1,10 do
if P.field[i][j]>0 and h==j then goto post_pts_calc end if P.field[i][j]>0 and h==j then flag=true break end-- goto post_pts_calc
if P.field[i][j]==0 and h~=j then goto post_pts_calc end if P.field[i][j]==0 and h~=j then flag=true break end-- goto post_pts_calc
end end
if i==#P.field then goto post_pts_calc end if flag then break end
if P.field[i+1][h]==0 then goto post_pts_calc end if i==#P.field then break end-- goto post_pts_calc
if P.field[i+1][h]==0 then break end-- goto post_pts_calc
D.rankPts=D.rankPts+1 D.rankPts=D.rankPts+1
end end
::post_pts_calc:: -- ::post_pts_calc::
generateGuide(D.rankPts+20) generateGuide(D.rankPts+20)
end end
} }

View File

@@ -981,7 +981,7 @@ do-- function resetGameData(args)
GAME.replaying=true GAME.replaying=true
else else
GAME.frameStart=args:find'n' and 0 or 180-SETTING.reTime*60 GAME.frameStart=args:find'n' and 0 or 180-SETTING.reTime*60
GAME.seed=seed or math.random(1046101471,2662622626) GAME.seed=seed or math.random(1046101471)
GAME.pauseTime=0 GAME.pauseTime=0
GAME.pauseCount=0 GAME.pauseCount=0
GAME.saved=false GAME.saved=false

View File

@@ -652,7 +652,7 @@ do-- Userdata tables
showSpike=true, showSpike=true,
highCam=true, highCam=true,
nextPos=true, nextPos=true,
fullscreen=true, fullscreen=SYSTEM~='Web',
portrait=false, portrait=false,
msaa=0, msaa=0,
bg='on', bg='on',

View File

@@ -77,16 +77,19 @@ function Player:createLockFX()
for i=1,#CB do for i=1,#CB do
local y=self.curY+i-1 local y=self.curY+i-1
local L=self.clearedRow local L=self.clearedRow
local skip
for j=1,#L do for j=1,#L do
if L[j]==y then goto CONTINUE_skip end if L[j]==y then skip=true break end-- goto CONTINUE_skip
end end
y=-30*y if not skip then
for j=1,#CB[1] do y=-30*y
if CB[i][j] then for j=1,#CB[1] do
ins(self.lockFX,{30*(self.curX+j-2),y,0,t}) if CB[i][j] then
ins(self.lockFX,{30*(self.curX+j-2),y,0,t})
end
end end
end end
::CONTINUE_skip:: -- ::CONTINUE_skip::
end end
end end
end end
@@ -610,6 +613,7 @@ do-- function Player:dropPosition(x,y,size)
vy=vy+.0626 vy=vy+.0626
self:setPosition(x,y,size) self:setPosition(x,y,size)
if y>2600 then if y>2600 then
table.remove(PLAYERS,TABLE.find(PLAYERS,self))
return true return true
end end
end end
@@ -1041,16 +1045,20 @@ function Player:_checkClear(field,start,height,CB,CX)
h=h+1 h=h+1
-- Row filled -- Row filled
local full=true
for x=1,10 do for x=1,10 do
if field[h][x]<=0 then if field[h][x]<=0 then
goto CONTINUE_notFull full=false
break-- goto CONTINUE_notFull
end end
end end
cc=cc+1 if full then
if field[h].garbage then gbcc=gbcc+1 end cc=cc+1
ins(self.clearingRow,h-cc+1) if field[h].garbage then gbcc=gbcc+1 end
ins(self.clearedRow,h) ins(self.clearingRow,h-cc+1)
::CONTINUE_notFull:: ins(self.clearedRow,h)
end
-- ::CONTINUE_notFull::
end end
return cc,gbcc return cc,gbcc
end end
@@ -1265,20 +1273,22 @@ function Player:hold_norm(ifpre)
y=y+(#C.bk-#H.bk)*.5 y=y+(#C.bk-#H.bk)*.5
local iki=phyHoldKickX[x==int(x)] local iki=phyHoldKickX[x==int(x)]
local success
for Y=int(y),ceil(y+.5) do for Y=int(y),ceil(y+.5) do
for i=1,#iki do for i=1,#iki do
local X=x+iki[i] local X=x+iki[i]
if not self:ifoverlap(H.bk,X,Y) then if not self:ifoverlap(H.bk,X,Y) then
x,y=X,Y x,y=X,Y
goto BREAK_success success=true
break
end end
end end
if success then break end
end end
-- <for-else> All test failed, interrupt with sound if not success then -- All test failed, interrupt with sound
SFX.play('drop_cancel') SFX.play('drop_cancel')
do return end return
-- <for-end> end
::BREAK_success::
self.spinLast=false self.spinLast=false
@@ -1332,20 +1342,22 @@ function Player:hold_swap(ifpre)
y=y+(#C.bk-#H.bk)*.5 y=y+(#C.bk-#H.bk)*.5
local iki=phyHoldKickX[x==int(x)] local iki=phyHoldKickX[x==int(x)]
for Y=int(y),ceil(y+.5) do local success
for i=1,#iki do for Y=int(y),ceil(y+.5) do
local X=x+iki[i] for i=1,#iki do
if not self:ifoverlap(H.bk,X,Y) then local X=x+iki[i]
x,y=X,Y if not self:ifoverlap(H.bk,X,Y) then
goto BREAK_success x,y=X,Y
success=true
break
end
end end
if success then break end
end end
end if not success then -- All test failed, interrupt with sound
-- <for-else> All test failed, interrupt with sound
SFX.play('finesseError') SFX.play('finesseError')
do return end return
-- <for-end> end
::BREAK_success::
self.spinLast=false self.spinLast=false
@@ -2508,90 +2520,92 @@ local function update_alive(P,dt)
local stopAtFalling local stopAtFalling
-- Falling animation -- Falling animation
if P.falling>0 then repeat
stopAtFalling=true
P:_updateFalling(P.falling-1)
if P.falling>0 then if P.falling>0 then
goto THROW_stop stopAtFalling=true
end P:_updateFalling(P.falling-1)
end if P.falling>0 then
break-- goto THROW_stop
-- Update block state
if P.control then
-- Try spawn new block
if not P.cur then
if not stopAtFalling and P.waiting>0 then
P.waiting=P.waiting-1
end end
if P.waiting<=0 then
P:popNext()
end
goto THROW_stop
end end
-- Natural block falling -- Update block state
if P.cur then if P.control then
if P.curY>P.ghoY then -- Try spawn new block
local D=P.dropDelay if not P.cur then
local dist-- Drop distance if not stopAtFalling and P.waiting>0 then
if D>1 then P.waiting=P.waiting-1
D=D-1
if P.keyPressing[7] and P.downing>=ENV.sddas then
D=D-ceil(ENV.drop/ENV.sdarr)
end
if D<=0 then
dist=1
P.dropDelay=(D-1)%ENV.drop+1
else
P.dropDelay=D
goto THROW_stop
end
elseif D==1 then-- We don't know why dropDelay is 1, so checking ENV.drop>1 is neccessary
if ENV.drop>1 and P.downing>=ENV.sddas and (P.downing-ENV.sddas)%ENV.sdarr==0 then
dist=2
else
dist=1
end
-- Reset drop delay
P.dropDelay=ENV.drop
else-- High gravity case (>1G)
-- Add extra 1 if time to auto softdrop
if P.downing>ENV.sddas and (P.downing-ENV.sddas)%ENV.sdarr==0 then
dist=1/D+1
else
dist=1/D
end
end end
if P.waiting<=0 then
P:popNext()
end
break-- goto THROW_stop
end
-- Limit dropping to ghost at max -- Natural block falling
dist=min(dist,P.curY-P.ghoY) if P.cur then
if P.curY>P.ghoY then
-- Drop and create FXs local D=P.dropDelay
if ENV.moveFX and ENV.block and dist>1 then local dist-- Drop distance
for _=1,dist do if D>1 then
P:createMoveFX('down') D=D-1
P.curY=P.curY-1 if P.keyPressing[7] and P.downing>=ENV.sddas then
D=D-ceil(ENV.drop/ENV.sdarr)
end
if D<=0 then
dist=1
P.dropDelay=(D-1)%ENV.drop+1
else
P.dropDelay=D
break-- goto THROW_stop
end
elseif D==1 then-- We don't know why dropDelay is 1, so checking ENV.drop>1 is neccessary
if ENV.drop>1 and P.downing>=ENV.sddas and (P.downing-ENV.sddas)%ENV.sdarr==0 then
dist=2
else
dist=1
end
-- Reset drop delay
P.dropDelay=ENV.drop
else-- High gravity case (>1G)
-- Add extra 1 if time to auto softdrop
if P.downing>ENV.sddas and (P.downing-ENV.sddas)%ENV.sdarr==0 then
dist=1/D+1
else
dist=1/D
end
end end
-- Limit dropping to ghost at max
dist=min(dist,P.curY-P.ghoY)
-- Drop and create FXs
if ENV.moveFX and ENV.block and dist>1 then
for _=1,dist do
P:createMoveFX('down')
P.curY=P.curY-1
end
else
P.curY=P.curY-dist
end
P.spinLast=false
P:freshBlock('fresh')
P:checkTouchSound()
else else
P.curY=P.curY-dist P.lockDelay=P.lockDelay-1
end if P.lockDelay>=0 then
break-- goto THROW_stop
P.spinLast=false end
P:freshBlock('fresh') P:drop(true)
P:checkTouchSound() if P.bot then
else P.bot:lockWrongPlace()
P.lockDelay=P.lockDelay-1 end
if P.lockDelay>=0 then
goto THROW_stop
end
P:drop(true)
if P.bot then
P.bot:lockWrongPlace()
end end
end end
end end
end until true
::THROW_stop:: -- ::THROW_stop::
-- B2B bar animation -- B2B bar animation
if P.b2b1~=P.b2b then if P.b2b1~=P.b2b then
@@ -2911,16 +2925,20 @@ function Player:lose(force)
self:dropPosition() self:dropPosition()
freshPlayerPosition('update') freshPlayerPosition('update')
local finished=true
for i=1,#PLY_ALIVE-1 do for i=1,#PLY_ALIVE-1 do
if PLY_ALIVE[i].group==0 or PLY_ALIVE[i].group~=PLY_ALIVE[i+1].group then if PLY_ALIVE[i].group==0 or PLY_ALIVE[i].group~=PLY_ALIVE[i+1].group then
goto BREAK_notFinished finished=false
break-- goto BREAK_notFinished
end end
end end
-- Only 1 people or only 1 team survived, they win -- Only 1 people or only 1 team survived, they win
for i=1,#PLY_ALIVE do if finished then
PLY_ALIVE[i]:win() for i=1,#PLY_ALIVE do
PLY_ALIVE[i]:win()
end
end end
::BREAK_notFinished:: -- ::BREAK_notFinished::
end end
end end
--------------------------<\Event>-------------------------- --------------------------<\Event>--------------------------

View File

@@ -65,13 +65,15 @@ local seqGenerators={
local r local r
for _=1,hisLen do-- Reroll up to [hisLen] times for _=1,hisLen do-- Reroll up to [hisLen] times
r=rndGen:random(len) r=rndGen:random(len)
local rollAgain
for i=1,hisLen do for i=1,hisLen do
if r==history[i] then if r==history[i] then
goto CONTINUE_rollAgain rollAgain=true
break-- goto CONTINUE_rollAgain
end end
end end
do break end if not rollAgain then break end
::CONTINUE_rollAgain:: -- ::CONTINUE_rollAgain::
end end
if history[1]~=0 then if history[1]~=0 then
P:getNext(seq0[r]) P:getNext(seq0[r])
@@ -128,16 +130,21 @@ local seqGenerators={
-- print"======================" -- print"======================"
-- Pick a mino from pool -- Pick a mino from pool
local tryTime=0 local tryTime=0
::REPEAT_pickAgain:: local r
local r=_poolPick()-- Random mino-index in pool repeat-- ::REPEAT_pickAgain::
for i=1,len do local pickAgain
if r==history[i] then r=_poolPick()-- Random mino-index in pool
tryTime=tryTime+1 for i=1,len do
if tryTime<hisLen then if r==history[i] then
goto REPEAT_pickAgain tryTime=tryTime+1
if tryTime<hisLen then
pickAgain=true
break-- goto REPEAT_pickAgain
end
end end
end end
end if not pickAgain then break end
until true
-- Give mino to player & update history -- Give mino to player & update history
if history[1]~=0 then if history[1]~=0 then

View File

@@ -38,13 +38,15 @@ local function restart()
end end
local function checkBoard(b,p) local function checkBoard(b,p)
for i=1,8 do for i=1,8 do
local testNextLine
for j=1,3 do for j=1,3 do
if b[lines[i][j]]~=p then if b[lines[i][j]]~=p then
goto CONTINUE_testNextLine testNextLine=true
break-- goto CONTINUE_testNextLine
end end
end end
do return true end if not testNextLine then return true end
::CONTINUE_testNextLine:: -- ::CONTINUE_testNextLine::
end end
end end
local function full(L) local function full(L)

View File

@@ -127,8 +127,9 @@ local function checkLink(x1,y1,x2,y2)
while ruy>1 and not field[ruy-1][x2] do ruy=ruy-1 end while ruy>1 and not field[ruy-1][x2] do ruy=ruy-1 end
while rdy<field.r and not field[rdy+1][x2] do rdy=rdy+1 end while rdy<field.r and not field[rdy+1][x2] do rdy=rdy+1 end
for y=max(luy,ruy),min(ldy,rdy) do for y=max(luy,ruy),min(ldy,rdy) do
for x=x1+1,x2-1 do if field[y][x] then goto CONTINUE_nextRow end end local nextLine
do for x=x1+1,x2-1 do if field[y][x] then nextLine=true break end end-- goto CONTINUE_nextRow
if not nextLine then
local len=abs(x1-x2)+abs(y-y1)+abs(y-y2) local len=abs(x1-x2)+abs(y-y1)+abs(y-y2)
if len<bestLen then if len<bestLen then
bestLen=len bestLen=len
@@ -138,7 +139,7 @@ local function checkLink(x1,y1,x2,y2)
addPoint(bestLine,x2,y2) addPoint(bestLine,x2,y2)
end end
end end
::CONTINUE_nextRow:: -- ::CONTINUE_nextRow::
end end
end end
-- X-Y-X Check -- X-Y-X Check
@@ -150,8 +151,9 @@ local function checkLink(x1,y1,x2,y2)
while dlx>1 and not field[y2][dlx-1] do dlx=dlx-1 end while dlx>1 and not field[y2][dlx-1] do dlx=dlx-1 end
while drx<field.c and not field[y2][drx+1] do drx=drx+1 end while drx<field.c and not field[y2][drx+1] do drx=drx+1 end
for x=max(ulx,dlx),min(urx,drx) do for x=max(ulx,dlx),min(urx,drx) do
for y=y1+1,y2-1 do if field[y][x] then goto CONTINUE_nextCol end end local nextLine
do for y=y1+1,y2-1 do if field[y][x] then nextLine=true break end end-- goto CONTINUE_nextCol
if not nextLine then
local len=abs(y1-y2)+abs(x-x1)+abs(x-x2) local len=abs(y1-y2)+abs(x-x1)+abs(x-x2)
if len<bestLen then if len<bestLen then
bestLen=len bestLen=len
@@ -161,7 +163,7 @@ local function checkLink(x1,y1,x2,y2)
addPoint(bestLine,x2,y2) addPoint(bestLine,x2,y2)
end end
end end
::CONTINUE_nextCol:: -- ::CONTINUE_nextCol::
end end
end end
return bestLine return bestLine

View File

@@ -153,32 +153,34 @@ function player:click(y,x)
SFX.play('touch') SFX.play('touch')
local merged local merged
::REPEAT_merge:: repeat-- ::REPEAT_merge::
local cur=self.board[y][x] local repeating
local b1=TABLE.shift(self.board) local cur=self.board[y][x]
self.mergedTiles={} local b1=TABLE.shift(self.board)
local count=self:merge(b1,cur,y,x) self.mergedTiles={}
if count>2 then local count=self:merge(b1,cur,y,x)
merged=true if count>2 then
self.board=b1 merged=true
b1[y][x]=cur+1 self.board=b1
b1[y][x]=cur+1
if cur+1>self.maxTile then if cur+1>self.maxTile then
self.maxTile=cur+1 self.maxTile=cur+1
if self.maxTile>=6 then if self.maxTile>=6 then
ins(self.progress,("%s - %.3fs"):format(self.maxTile,TIME()-player.startTime)) ins(self.progress,("%s - %.3fs"):format(self.maxTile,TIME()-player.startTime))
end
SFX.play('reach')
end end
SFX.play('reach')
end
local getScore=4^cur*count local getScore=4^cur*count
self.score=self.score+getScore self.score=self.score+getScore
TEXT.show(getScore,player.x+self.selectX*100-50,player.y+self.selectY*100-50,40,'score',1.626/math.log(getScore,3)) TEXT.show(getScore,player.x+self.selectX*100-50,player.y+self.selectY*100-50,40,'score',1.626/math.log(getScore,3))
for i=1,#self.mergedTiles do for i=1,#self.mergedTiles do
newMergeFX(self.mergedTiles[i][1],self.mergedTiles[i][2],cur+1) newMergeFX(self.mergedTiles[i][1],self.mergedTiles[i][2],cur+1)
end
repeating=true-- goto REPEAT_merge
end end
goto REPEAT_merge until not repeating
end
ins(self.nexts,self:newTile()) ins(self.nexts,self:newTile())

View File

@@ -104,20 +104,23 @@ function scene.keyDown(key,isRep)
elseif key=='v' and kb.isDown('lctrl','rctrl') or key=='cV' then elseif key=='v' and kb.isDown('lctrl','rctrl') or key=='cV' then
local str=sys.getClipboardText() local str=sys.getClipboardText()
local args=str:sub((str:find(":") or 0)+1):split("!") local args=str:sub((str:find(":") or 0)+1):split("!")
if #args<4 then goto THROW_fail end repeat
if not ( if #args<4 then break end-- goto THROW_fail
DATA.pasteQuestArgs(args[1]) and if not (
DATA.pasteSequence(args[2]) and DATA.pasteQuestArgs(args[1]) and
DATA.pasteMission(args[3]) DATA.pasteSequence(args[2]) and
) then goto THROW_fail end DATA.pasteMission(args[3])
TABLE.cut(FIELD) ) then break end-- goto THROW_fail
FIELD[1]=DATA.newBoard() TABLE.cut(FIELD)
for i=4,#args do FIELD[1]=DATA.newBoard()
if args[i]:find("%S") and not DATA.pasteBoard(args[i],i-3) and i<#args then goto THROW_fail end for i=4,#args do
end if args[i]:find("%S") and not DATA.pasteBoard(args[i],i-3) and i<#args then break end-- goto THROW_fail
MES.new('check',text.importSuccess) end
do return end MES.new('check',text.importSuccess)
::THROW_fail::MES.new('error',text.dataCorrupted) return
until true
-- ::THROW_fail::
MES.new('error',text.dataCorrupted)
else else
return true return true
end end

View File

@@ -195,14 +195,17 @@ function scene.keyDown(key)
local F=FIELD[page] local F=FIELD[page]
local cleared=false local cleared=false
for i=#F,1,-1 do for i=#F,1,-1 do
local full
for j=1,10 do for j=1,10 do
if F[i][j]<=0 then goto CONTINUE_notFull end if F[i][j]<=0 then full=false break end-- goto CONTINUE_notFull
end end
cleared=true if full then
SYSFX.newShade(3,200,660-30*i,300,30) cleared=true
SYSFX.newRectRipple(3,200,660-30*i,300,30) SYSFX.newShade(3,200,660-30*i,300,30)
rem(F,i) SYSFX.newRectRipple(3,200,660-30*i,300,30)
::CONTINUE_notFull:: rem(F,i)
end
-- ::CONTINUE_notFull::
end end
if cleared then if cleared then
SFX.play('clear_3',.8) SFX.play('clear_3',.8)

View File

@@ -195,15 +195,19 @@ function scene.touchMove()
for n=1,#keys do for n=1,#keys do
local B=keys[n] local B=keys[n]
if B.ava then if B.ava then
local nextKey
for i=1,#L,2 do for i=1,#L,2 do
if (L[i]-B.x)^2+(L[i+1]-B.y)^2<=B.r^2 then if (L[i]-B.x)^2+(L[i+1]-B.y)^2<=B.r^2 then
goto CONTINUE_nextKey nextKey=true
break-- goto CONTINUE_nextKey
end end
end end
PLAYERS[1]:releaseKey(n) if not nextKey then
VK.release(n) PLAYERS[1]:releaseKey(n)
VK.release(n)
end
-- ::CONTINUE_nextKey::
end end
::CONTINUE_nextKey::
end end
end end
function scene.keyDown(key,isRep) function scene.keyDown(key,isRep)

View File

@@ -109,15 +109,19 @@ function scene.touchMove()
for n=1,#keys do for n=1,#keys do
local B=keys[n] local B=keys[n]
if B.ava then if B.ava then
local nextKey
for i=1,#L,2 do for i=1,#L,2 do
if (L[i]-B.x)^2+(L[i+1]-B.y)^2<=B.r^2 then if (L[i]-B.x)^2+(L[i+1]-B.y)^2<=B.r^2 then
goto CONTINUE_nextKey nextKey=true
break-- goto CONTINUE_nextKey
end end
end end
PLAYERS[1]:releaseKey(n) if not nextKey then
VK.release(n) PLAYERS[1]:releaseKey(n)
VK.release(n)
end
-- ::CONTINUE_nextKey::
end end
::CONTINUE_nextKey::
end end
end end
function scene.keyDown(key,isRep) function scene.keyDown(key,isRep)