382 lines
7.4 KiB
Lua
382 lines
7.4 KiB
Lua
local int,max,min,abs=math.floor,math.max,math.min,math.abs
|
|
local rem=table.remove
|
|
local resume=coroutine.resume
|
|
local status=coroutine.status
|
|
local assert=assert
|
|
|
|
local function updateLine(P)--Attacks, line pushing, cam moving
|
|
local bf=P.atkBuffer
|
|
for i=#bf,1,-1 do
|
|
local A=bf[i]
|
|
A.time=A.time+1
|
|
if not A.sent then
|
|
if A.countdown>0 then
|
|
A.countdown=max(A.countdown-P.gameEnv.garbageSpeed,0)
|
|
end
|
|
else
|
|
if A.time>20 then
|
|
rem(bf,i)
|
|
end
|
|
end
|
|
end
|
|
|
|
local y=P.fieldBeneath
|
|
if y>0 then
|
|
P.fieldBeneath=max(y-P.gameEnv.pushSpeed,0)
|
|
end
|
|
|
|
if P.gameEnv.highCam then
|
|
local f=P.fieldUp
|
|
if not P.alive then
|
|
y=0
|
|
else
|
|
y=30*max(min(#P.field-19.5-P.fieldBeneath/30,P.ghoY-17),0)
|
|
end
|
|
if f~=y then
|
|
P.fieldUp=f>y and max(f*.95+y*.05-2,y)or min(f*.97+y*.03+1,y)
|
|
end
|
|
end
|
|
end
|
|
local function updateFXs(P,dt)
|
|
if P.stat.score>P.score1 then
|
|
if P.stat.score-P.score1<10 then
|
|
P.score1=P.score1+1
|
|
else
|
|
P.score1=int(min(P.score1*.9+P.stat.score*.1+1))
|
|
end
|
|
end
|
|
|
|
--LockFX
|
|
for i=#P.lockFX,1,-1 do
|
|
local S=P.lockFX[i]
|
|
S[3]=S[3]+S[4]*dt
|
|
if S[3]>1 then
|
|
rem(P.lockFX,i)
|
|
end
|
|
end
|
|
|
|
--DropFX
|
|
for i=#P.dropFX,1,-1 do
|
|
local S=P.dropFX[i]
|
|
S[5]=S[5]+S[6]*dt
|
|
if S[5]>1 then
|
|
rem(P.dropFX,i)
|
|
end
|
|
end
|
|
|
|
--MoveFX
|
|
for i=#P.moveFX,1,-1 do
|
|
local S=P.moveFX[i]
|
|
S[4]=S[4]+S[5]*dt
|
|
if S[4]>1 then
|
|
rem(P.moveFX,i)
|
|
end
|
|
end
|
|
|
|
--ClearFX
|
|
for i=#P.clearFX,1,-1 do
|
|
local S=P.clearFX[i]
|
|
S[2]=S[2]+S[3]*dt
|
|
if S[2]>1 then
|
|
rem(P.clearFX,i)
|
|
end
|
|
end
|
|
|
|
--Field shaking
|
|
if P.gameEnv.shakeFX then
|
|
local O=P.fieldOff
|
|
O.vx,O.vy=O.vx*.8-abs(O.x)^1.2*(O.x>0 and .1 or -.1),O.vy*.8-abs(O.y)^1.2*(O.y>0 and .1 or -.1)
|
|
O.x,O.y=O.x+O.vx,O.y+O.vy
|
|
if abs(O.x)<.3 then O.x=0 end
|
|
if abs(O.y)<.3 then O.y=0 end
|
|
end
|
|
|
|
if P.bonus then
|
|
TEXT.update(P.bonus)
|
|
end
|
|
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
|
|
|
|
local function update_alive(P,dt)
|
|
local ENV=P.gameEnv
|
|
if P.timing then
|
|
local S=P.stat
|
|
S.time=S.time+dt
|
|
S.frame=S.frame+1
|
|
end
|
|
if P.keyRec then--Update speeds
|
|
local frame=GAME.frame
|
|
|
|
local v=0
|
|
for i=2,10 do v=v+i*(i-1)*7.2/(frame-P.keyTime[i]+1)end
|
|
P.keySpeed=P.keySpeed*.99+v*.1
|
|
|
|
v=0
|
|
for i=2,10 do v=v+i*(i-1)*7.2/(frame-P.dropTime[i])end
|
|
P.dropSpeed=P.dropSpeed*.99+v*.1
|
|
|
|
if GAME.modeEnv.royaleMode then
|
|
v=P.swappingAtkMode
|
|
if P.keyPressing[9]then
|
|
P.swappingAtkMode=min(v+2,30)
|
|
else
|
|
local tar=#P.field>15 and 4 or 8
|
|
if v~=tar then
|
|
P.swappingAtkMode=v+(v<tar and 1 or -1)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
if P.type=="computer"and P.control and P.waiting==-1 then
|
|
local C=P.AI_keys
|
|
P.AI_delay=P.AI_delay-1
|
|
if not C[1]then
|
|
P.AI_stage=AIFUNC[P.AI_mode][P.AI_stage](P,C)
|
|
elseif P.AI_delay<=0 then
|
|
P:pressKey(C[1])P:releaseKey(C[1])
|
|
if P.AI_mode~="CC"or C[1]>3 then
|
|
P.AI_delay=P.AI_delay0*2
|
|
else
|
|
P.AI_delay=P.AI_delay0*.5
|
|
end
|
|
rem(C,1)
|
|
end
|
|
end
|
|
|
|
--Fresh visible time
|
|
if not P.keepVisible then
|
|
for j=1,#P.field do for i=1,10 do
|
|
if P.visTime[j][i]>0 then P.visTime[j][i]=P.visTime[j][i]-1 end
|
|
end end
|
|
end
|
|
|
|
--Moving pressed
|
|
if P.movDir~=0 then
|
|
local das,arr=ENV.das,ENV.arr
|
|
local mov=P.moving
|
|
if P.waiting==-1 then
|
|
if P.movDir==1 then
|
|
if P.keyPressing[2]then
|
|
if arr>0 then
|
|
if mov==das+arr or mov==das then
|
|
if not P.cur or P:ifoverlap(P.cur.bk,P.curX+1,P.curY)then
|
|
mov=das+arr-1
|
|
else
|
|
P:act_moveRight(true)
|
|
mov=das
|
|
end
|
|
end
|
|
mov=mov+1
|
|
else
|
|
if mov==das then
|
|
P:act_insRight(true)
|
|
else
|
|
mov=mov+1
|
|
end
|
|
end
|
|
if mov>=das and ENV.shakeFX and P.cur and P:ifoverlap(P.cur.bk,P.curX+1,P.curY)then
|
|
P.fieldOff.vx=ENV.shakeFX*.5
|
|
end
|
|
else
|
|
P.movDir=0
|
|
end
|
|
else
|
|
if P.keyPressing[1]then
|
|
if arr>0 then
|
|
if mov==das+arr or mov==das then
|
|
if not P.cur or P:ifoverlap(P.cur.bk,P.curX-1,P.curY)then
|
|
mov=das+arr-1
|
|
else
|
|
P:act_moveLeft(true)
|
|
mov=das
|
|
end
|
|
end
|
|
mov=mov+1
|
|
else
|
|
if mov==das then
|
|
P:act_insLeft(true)
|
|
else
|
|
mov=mov+1
|
|
end
|
|
end
|
|
if mov>=das and ENV.shakeFX and P.cur and P:ifoverlap(P.cur.bk,P.curX-1,P.curY)then
|
|
P.fieldOff.vx=-ENV.shakeFX*.5
|
|
end
|
|
else
|
|
P.movDir=0
|
|
end
|
|
end
|
|
elseif mov<das then
|
|
mov=mov+1
|
|
end
|
|
P.moving=mov
|
|
end
|
|
|
|
--Drop pressed
|
|
if P.keyPressing[7]and not P.keyPressing[9]then
|
|
local d=P.downing-ENV.sddas
|
|
P.downing=P.downing+1
|
|
if d>1 then
|
|
if ENV.sdarr>0 then
|
|
if d%ENV.sdarr==0 then
|
|
P:act_down1()
|
|
end
|
|
else
|
|
P:act_insDown()
|
|
end
|
|
if ENV.shakeFX then
|
|
P.fieldOff.vy=ENV.shakeFX*.3
|
|
end
|
|
end
|
|
else
|
|
P.downing=0
|
|
end
|
|
|
|
--Falling animation
|
|
if P.falling>=0 then
|
|
P.falling=P.falling-1
|
|
if P.falling>=0 then
|
|
goto stop
|
|
else
|
|
local L=#P.clearingRow
|
|
if P.sound and ENV.fall>0 and #P.field+L>P.clearingRow[L]then SFX.play("fall")end
|
|
P.clearingRow={}
|
|
end
|
|
end
|
|
|
|
--Try spawn new block
|
|
if not P.control then goto stop end
|
|
if P.waiting>=0 then
|
|
P.waiting=P.waiting-1
|
|
if P.waiting<0 then P:popNext()end
|
|
goto stop
|
|
end
|
|
|
|
--Natural block falling
|
|
if P.cur then
|
|
if P.curY>P.ghoY then
|
|
local D=P.dropDelay
|
|
if D>1 then
|
|
P.dropDelay=D-1
|
|
goto stop
|
|
end
|
|
|
|
if D==1 then
|
|
if ENV.moveFX and ENV.block then
|
|
P:createMoveFX("down")
|
|
end
|
|
P.curY=P.curY-1
|
|
else
|
|
D=max(1/D,P.curY-P.ghoY)--Fall dist, max to dist between cur/gho
|
|
if ENV.moveFX and ENV.block then
|
|
for _=1,D do
|
|
P:createMoveFX("down")
|
|
P.curY=P.curY-1
|
|
end
|
|
else
|
|
P.curY=P.curY-D
|
|
end
|
|
end
|
|
P:freshBlock("fresh")
|
|
P.spinLast=false
|
|
|
|
if P.ghoY~=P.curY then
|
|
P.dropDelay=ENV.drop
|
|
elseif P.AI_mode=="CC"then
|
|
CC.updateField(P)
|
|
if not P.AIdata._20G and ENV.drop<P.AI_delay0*.5 then
|
|
CC.switch20G(P)
|
|
end
|
|
end
|
|
else
|
|
P.lockDelay=P.lockDelay-1
|
|
if P.lockDelay>=0 then goto stop end
|
|
P:drop()
|
|
if P.AI_mode=="CC"then
|
|
CC.updateField(P)
|
|
end
|
|
end
|
|
end
|
|
::stop::
|
|
|
|
--B2B bar animation
|
|
if P.b2b1==P.b2b then
|
|
elseif P.b2b1<P.b2b then
|
|
P.b2b1=min(P.b2b1*.98+P.b2b*.02+.4,P.b2b)
|
|
else
|
|
P.b2b1=max(P.b2b1*.95+P.b2b*.05-.6,P.b2b)
|
|
end
|
|
|
|
--Finesse combo animation
|
|
if P.finesseComboTime>0 then
|
|
P.finesseComboTime=P.finesseComboTime-1
|
|
end
|
|
|
|
--Update FXs
|
|
updateLine(P)
|
|
updateFXs(P,dt)
|
|
updateTasks(P)
|
|
end
|
|
|
|
local update={
|
|
alive=update_alive,
|
|
}
|
|
function update.dead(P,dt)
|
|
if P.keyRec then
|
|
local S=P.stat
|
|
P.keySpeed=P.keySpeed*.96+S.key/S.frame*144
|
|
P.dropSpeed=P.dropSpeed*.96+S.piece/S.frame*144
|
|
--Final average speeds
|
|
if GAME.modeEnv.royaleMode then
|
|
P.swappingAtkMode=min(P.swappingAtkMode+2,30)
|
|
end
|
|
end
|
|
if P.falling>=0 then
|
|
P.falling=P.falling-1
|
|
if P.falling<0 then
|
|
local L=#P.clearingRow
|
|
if P.sound and P.gameEnv.fall>0 and #P.field+L>P.clearingRow[L]then SFX.play("fall")end
|
|
P.clearingRow={}
|
|
end
|
|
end
|
|
if P.b2b1>0 then
|
|
P.b2b1=max(0,P.b2b1*.92-1)
|
|
end
|
|
if P.finesseComboTime>0 then
|
|
P.finesseComboTime=P.finesseComboTime-1
|
|
end
|
|
updateLine(P)
|
|
updateFXs(P,dt)
|
|
updateTasks(P)
|
|
end
|
|
function update.remote_alive(P,dt)
|
|
::readNext::
|
|
local pos=P.streamProgress
|
|
local tar=P.stream[pos]
|
|
if tar then
|
|
if P.stat.frame==tar then
|
|
local key=P.stream[pos+1]
|
|
if key>0 then--Press key
|
|
P:pressKey(key)
|
|
elseif key<0 then--Release key
|
|
P:releaseKey(-key)
|
|
else--Receiving garbage
|
|
--TODO:
|
|
end
|
|
P.streamProgress=pos+2
|
|
goto readNext
|
|
end
|
|
update_alive(P,dt)
|
|
end
|
|
end
|
|
return update |