local max,min=math.max,math.min local int,abs=math.floor,math.abs local rem=table.remove local assert,resume,status=assert,coroutine.resume,coroutine.status local TEXT,GAME,CC=TEXT,GAME,CC local PLY_ALIVE=PLY_ALIVE local function update_misc(P,dt) --Finesse combo animation if P.finesseComboTime>0 then P.finesseComboTime=P.finesseComboTime-1 end --Update spike counter if P.spikeTime>0 then P.spikeTime=P.spikeTime-1 end --Update atkBuffer alert local t=P.atkBufferSum1 if tP.atkBufferSum then P.atkBufferSum1=t-.5 end --Update attack buffer 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 --Push up garbages local y=P.fieldBeneath if y>0 then P.fieldBeneath=max(y-P.gameEnv.pushSpeed,0) end --Move camera if P.gameEnv.highCam then if not P.alive then y=0 else y=30*max(min(#P.field-18.5-P.fieldBeneath/30,P.ghoY-17),0) end local f=P.fieldUp 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 --Update Score 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 --Update lock FX 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 --Update drop FX 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 --Update move FX 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 --Update clear FX 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.vx*.8-abs(O.x)^1.3*(O.x>0 and .1 or -.1) O.x=O.x+O.vx O.vy=O.vy*.8-abs(O.y)^1.2*(O.y>0 and .1 or -.1) O.y=O.y+O.vy O.va=O.va*.8-abs(O.a)^1.4*(O.a>0 and .08 or -.08) O.a=O.a+O.va if abs(O.a)<.0006 then O.a,O.va=0,0 end end --Update texts if P.bonus then TEXT.update(P.bonus) end --Update tasks 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 update={ } function update.alive(P,dt) local ENV=P.gameEnv local S=P.stat P.frameRun=P.frameRun+1 if P.frameRun<=180 then if P.frameRun==180 then if P.id==1 then SFX.play('start')end P.control=true P.timing=true P:popNext() elseif P.frameRun==60 or P.frameRun==120 then if P.id==1 then SFX.play('ready')end end if P.movDir~=0 then if P.moving15 and 4 or 8 if v~=tar then P.swappingAtkMode=v+(v3 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 local V=P.visTime for j=1,#P.field do local L=V[j] for i=1,10 do if L[i]>0 then L[i]=L[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 mov1 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*.2 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 THROW_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 --Update block state if P.control then --Try spawn new block if P.waiting>=0 then P.waiting=P.waiting-1 if P.waiting<0 then P:popNext() end goto THROW_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 THROW_stop end if D==1 then if ENV.moveFX and ENV.block then P:createMoveFX('down') end P.curY=P.curY-1 else D=min(1/D,P.curY-P.ghoY)--1/D=Drop dist, lowest to ghost 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'and P.AI_bot then CC.updateField(P) if not P.AIdata._20G and ENV.drop=0 then goto THROW_stop end P:drop(true) if P.AI_mode=='CC'and P.AI_bot then CC.updateField(P) end end end end ::THROW_stop:: --B2B bar animation if P.b2b1==P.b2b then elseif P.b2b1=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 update_misc(P,dt) end function update.remote_alive(P,dt) local frameRate=(P.stream[#P.stream-1]or 0)-P.frameRun frameRate= frameRate<26 and 1 or frameRate<50 and 2 or frameRate<80 and 3 or frameRate<120 and 5 or frameRate<160 and 7 or frameRate<200 and 10 or 20 for _=1,frameRate do local eventTime=P.stream[P.streamProgress] if eventTime then--Normal state, event forward if P.frameRun==eventTime then--Event time, execute action, read next so don't update immediately local event=P.stream[P.streamProgress+1] if event==0 then--Just wait elseif event<=32 then--Press key P:pressKey(event) elseif event<=64 then--Release key P:releaseKey(event-32) elseif event>0x2000000000000 then--Sending lines local sid=event%0x100 local amount=int(event/0x100)%0x100 local time=int(event/0x10000)%0x10000 local line=int(event/0x100000000)%0x10000 for _,p in next,PLY_ALIVE do if p.sid==sid then P:attack(p,amount,time,line,true) if P.gameEnv.atkFX then P:createBeam(p,amount,P.gameEnv.atkFX,P.cur.color) end break end end elseif event>0x1000000000000 then--Receiving lines local sid=event%0x100 for _,p in next,PLY_ALIVE do if p.sid==sid then P:receive( p, int(event/0x100)%0x100,--amount int(event/0x10000)%0x10000,--time int(event/0x100000000)%0x10000--line ) break end end end P.streamProgress=P.streamProgress+2 else--No event now, run one frame update.alive(P,dt/frameRate) P.stat.time=P.frameRun/60 end else--Pause state, no actions, quit loop break end end end return update