14
.github/workflows/main.yml
vendored
14
.github/workflows/main.yml
vendored
@@ -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
|
||||||
|
|||||||
Submodule Zframework updated: 20a5757a9c...4aa87c6147
9
conf.lua
9
conf.lua
@@ -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
|
||||||
|
|||||||
15
main.lua
15
main.lua
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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',
|
||||||
|
|||||||
@@ -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>--------------------------
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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())
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
Reference in New Issue
Block a user