local gc=love.graphics local mt=love.math local Timer=love.timer.getTime local int,ceil,rnd=math.floor,math.ceil,math.random local max,min,abs,sin,cos,log=math.max,math.min,math.abs,math.sin,math.cos,math.log local ins,rem=table.insert,table.remove local format=string.format local scr=scr local setFont=setFont ---------------------------------------------------- local gameEnv0={ das=10,arr=2,sddas=2,sdarr=2, ihs=true,irs=true,ims=true, swap=true, ghost=.3,center=1, smooth=false,grid=false, bagLine=false, text=true, score=true, lockFX=2, dropFX=2, moveFX=2, clearFX=2, shakeFX=3, highCam=false, nextPos=false, drop=60,lock=60, wait=0,fall=0, bone=false, next=6, hold=true,oncehold=true, ospin=true, sequence="bag", freshMethod=NULL, bag={1,2,3,4,5,6,7}, face=NULL,skin=NULL, mission=NULL, life=0, pushSpeed=3, block=true, noTele=false, visible="show", freshLimit=1e99,easyFresh=true, Fkey=NULL, keyCancel={}, fine=false,fineKill=false, missionKill=false, target=1e99,dropPiece=NULL, mindas=0,minarr=0,minsdarr=0, bg="none",bgm="race" } local scs=spinCenters local kickList=require("parts/kickList") local CCblockID={6,5,4,3,2,1,0} ---------------------------------------------------- ---------------------------------------------------- local player={}--Player object local PLY={}--Lib ---------------------------------------------------- ---------------------------------------------------- local function updateLine(P,dt)--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-game.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.imgY-17),0) end if f~=y then P.fieldUp=f>y and max(f*.95+y*.05-2,y)or ceil(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 if L[i].code(P,L[i].data)then rem(L,i)end end end local function Pupdate_alive(P,dt) if P.timing then P.stat.time=P.stat.time+dt end if P.keyRec then--Update speeds local _=game.frame local v=0 for i=2,10 do v=v+i*(i-1)*7.2/(_-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/(_-P.dropTime[i])end P.dropSpeed=P.dropSpeed*.99+v*.1 if modeEnv.royaleMode then if P.keyPressing[9]then P.swappingAtkMode=min(P.swappingAtkMode+2,30) else P.swappingAtkMode=P.swappingAtkMode+((#P.field>15 and P.swappingAtkMode>4 or P.swappingAtkMode>8)and -1 or 1) end end end if not P.human 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=P.gameEnv.das,P.gameEnv.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(P,true) mov=das end end mov=mov+1 else if mov==das then P.act.insRight(P,true) else mov=mov+1 end end if mov>=das and P.gameEnv.shakeFX and P.cur and P:ifoverlap(P.cur.bk,P.curX+1,P.curY)then P.fieldOff.vx=P.gameEnv.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(P,true) mov=das end end mov=mov+1 else if mov==das then P.act.insLeft(P,true) else mov=mov+1 end end if mov>=das and P.gameEnv.shakeFX and P.cur and P:ifoverlap(P.cur.bk,P.curX-1,P.curY)then P.fieldOff.vx=-P.gameEnv.shakeFX*.5 end else P.movDir=0 end end elseif mov1 then if P.gameEnv.sdarr>0 then if d%P.gameEnv.sdarr==0 then P.act.down1(P) end else P.act.insDown(P) end if P.gameEnv.shakeFX then P.fieldOff.vy=P.gameEnv.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 P.gameEnv.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.imgY then local D=P.dropDelay if D>1 then P.dropDelay=D-1 goto stop end if D==1 then if P.gameEnv.moveFX and P.gameEnv.block then P:createMoveFX("down") end P.curY=P.curY-1 else D=1/D--Fall dist if D>P.curY-P.imgY then D=P.curY-P.imgY end if P.gameEnv.moveFX and P.gameEnv.block then for i=1,D do P:createMoveFX("down") P.curY=P.curY-1 end else P.curY=P.curY-D end -- assert(P.curY==int(P.curY),"y:"..P.curY.." fall:"..D.." D_env:"..P.gameEnv.drop) end P:freshBlock(true,true) P.spinLast=false if P.imgY~=P.curY then P.dropDelay=P.gameEnv.drop elseif P.AI_mode=="CC"then CC.updateField(P) if not P.AIdata._20G and P.gameEnv.drop=0 then goto stop end P:drop() if P.AI_mode=="CC"then CC.updateField(P) end end end ::stop:: if P.b2b1==P.b2b then elseif P.b2b10 then P.finesseComboTime=P.finesseComboTime-1 end updateLine(P,dt) updateFXs(P,dt) updateTasks(P) end local function Pupdate_dead(P,dt) if P.timing then P.stat.time=P.stat.time+dt end if P.keyRec then P.keySpeed=P.keySpeed*.96+P.stat.key/P.stat.time*60*.04 P.dropSpeed=P.dropSpeed*.96+P.stat.piece/P.stat.time*60*.04 --Final average speeds if 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,dt) updateFXs(P,dt) updateTasks(P) end ---------------------------------------------------- ---------------------------------------------------- local frameColor={ [0]=color.white, color.lGreen, color.lBlue, color.lPurple, color.lOrange, } local function drawCell(y,x,id) gc.draw(blockSkin[id],30*x-30,-30*y) end local function drawGrid(P) local FBN,FUP=P.fieldBeneath,P.fieldUp gc.setLineWidth(1) gc.setColor(1,1,1,.2) for x=1,9 do gc.line(30*x,-10,30*x,600) end for y=0,19 do y=30*(y-int((FBN+FUP)/30))+FBN+FUP gc.line(0,y,300,y) end end local function drawField(P) local V,F=P.visTime,P.field local start=int((P.fieldBeneath+P.fieldUp)/30+1) local rep=game.replaying if P.falling==-1 then--Blocks only for j=start,min(start+21,#F)do for i=1,10 do if F[j][i]>0 then if V[j][i]>0 then gc.setColor(1,1,1,min(V[j][i]*.05,1)) drawCell(j,i,F[j][i]) elseif rep then gc.setColor(1,1,1,.3+.08*sin(.5*(j-i)+Timer()*4)) gc.rectangle("fill",30*i-30,-30*j,30,30) end end end end else--With falling animation local ENV=P.gameEnv local dy,stepY=0,ENV.smooth and(P.falling/(ENV.fall+1))^2.5*30 or 30 local A=P.falling/ENV.fall local h=1 for j=start,min(start+21,#F)do while j==P.clearingRow[h]do h=h+1 dy=dy+stepY gc.translate(0,-stepY) gc.setColor(1,1,1,A) gc.rectangle("fill",0,30-30*j,300,stepY) end for i=1,10 do if F[j][i]>0 then if V[j][i]>0 then gc.setColor(1,1,1,min(V[j][i]*.05,1)) drawCell(j,i,F[j][i]) elseif rep then gc.setColor(1,1,1,.2) gc.rectangle("fill",30*i-30,-30*j,30,30) end end end end gc.translate(0,dy) end end local function drawFXs(P) --LockFX for i=1,#P.lockFX do local S=P.lockFX[i] if S[3]<.5 then gc.setColor(1,1,1,2*S[3]) gc.rectangle("fill",S[1],S[2],60*S[3],30) else gc.setColor(1,1,1,2-2*S[3]) gc.rectangle("fill",S[1]+30,S[2],60*S[3]-60,30) end end --DropFX for i=1,#P.dropFX do local S=P.dropFX[i] gc.setColor(1,1,1,.6-S[5]*.6) local w=30*S[3]*(1-S[5]*.5) gc.rectangle("fill",30*S[1]-30+15*S[3]-w*.5,-30*S[2],w,30*S[4]) end --MoveFX for i=1,#P.moveFX do local S=P.moveFX[i] gc.setColor(1,1,1,.6-S[4]*.6) drawCell(S[3],S[2],S[1]) end --ClearFX for i=1,#P.clearFX do local S=P.clearFX[i] local t=S[2] local x=t<.3 and 1-(3.3333*t-1)^2 or 1 local y=t<.2 and 5*t or 1-1.25*(t-.2) gc.setColor(1,1,1,y) gc.rectangle("fill",150-x*150,15-S[1]*30-y*15,300*x,y*30) end end local function drawGhost(P,clr) gc.setColor(1,1,1,P.gameEnv.ghost) for i=1,P.r do for j=1,P.c do if P.cur.bk[i][j]then drawCell(i+P.imgY-1,j+P.curX-1,clr) end end end end local function drawBlockOutline(P,clr,trans) SHADER.alpha:send("a",trans) gc.setShader(SHADER.alpha) local _=blockSkin[clr] for i=1,P.r do for j=1,P.c do if P.cur.bk[i][j]then local x=30*(j+P.curX)-60-3 local y=30-30*(i+P.curY)-3 gc.draw(_,x,y)gc.draw(_,x+6,y+6) gc.draw(_,x+6,y)gc.draw(_,x,y+6) end end end gc.setShader() end local function drawBlock(P,clr) gc.setColor(1,1,1) for i=1,P.r do for j=1,P.c do if P.cur.bk[i][j]then drawCell(i+P.curY-1,j+P.curX-1,clr) end end end end local function drawNextPreview(P,B) gc.setColor(1,1,1,.8) local x=int(6-#B[1]*.5) local y=21+ceil(P.fieldBeneath/30) for i=1,#B do for j=1,#B[1]do if B[i][j]then gc.draw(puzzleMark[-1],30*(x+j-2),30*(1-y-i)) end end end end local function drawHold(P,clr) if P.holded then gc.setColor(.6,.4,.4)end local B=P.hd.bk for i=1,#B do for j=1,#B[1]do if B[i][j]then drawCell(i+1.36-#B*.5,j+2.06-#B[1]*.5,clr) end end end end local Pdraw_norm do local attackColor={ {color.dGrey,color.white}, {color.grey,color.white}, {color.lPurple,color.white}, {color.lRed,color.white}, {color.dGreen,color.cyan}, } local RCPB={10,33,200,33,105,5,105,60} local function drawDial(x,y,speed) gc.setColor(1,1,1) mStr(int(speed),x,y-18) gc.setLineWidth(4) gc.setColor(1,1,1,.4) gc.circle("line",x,y,30,10) gc.setLineWidth(2) gc.setColor(1,1,1,.6) gc.circle("line",x,y,30,10) gc.setColor(1,1,1,.8) gc.draw(IMG.dialNeedle,x,y,2.094+(speed<=175 and .02094*speed or 4.712-52.36/(speed-125)),nil,nil,5,4) end function Pdraw_norm(P) local _ local ENV=P.gameEnv local FBN,FUP=P.fieldBeneath,P.fieldUp gc.push("transform") gc.translate(P.x,P.y)gc.scale(P.size) --Field-related things gc.push("transform") gc.translate(150,70) --Things shake with field gc.push("transform") gc.translate(P.fieldOff.x,P.fieldOff.y) --Fill field gc.setColor(0,0,0,.6) gc.rectangle("fill",0,-10,300,610) --Draw grid if ENV.grid then drawGrid(P)end --In-field things gc.push("transform") gc.translate(0,600+FBN+FUP) gc.setScissor(scr.x+(P.absFieldX+P.fieldOff.x)*scr.k,scr.y+(P.absFieldY+P.fieldOff.y)*scr.k,300*P.size*scr.k,610*P.size*scr.k) --Draw dangerous area gc.setColor(1,0,0,.3) gc.rectangle("fill",0,-600,300,-610-FUP-FBN) --Draw field drawField(P) --Draw spawn line gc.setColor(1,sin(Timer())*.4+.5,0,.5) gc.setLineWidth(4) gc.line(0,-600-FBN,300,-600-FBN) --Draw FXs drawFXs(P) --Draw current block if P.cur and P.waiting==-1 then local curColor=P.cur.color --Draw ghost if ENV.ghost then drawGhost(P,curColor)end local dy=ENV.smooth and P.imgY~=P.curY and(P.dropDelay/ENV.drop-1)*30 or 0 gc.translate(0,-dy) local trans=P.lockDelay/ENV.lock --Draw block if ENV.block then drawBlockOutline(P,curColor,trans) drawBlock(P,curColor) end --Draw rotate center local x=30*(P.curX+P.sc[2])-15 if ENV.center and ENV.block then gc.setColor(1,1,1,ENV.center) gc.draw(IMG.spinCenter,x,-30*(P.curY+P.sc[1])+15,nil,nil,nil,4,4) end gc.translate(0,dy) if ENV.center and ENV.ghost then gc.setColor(1,1,1,trans*ENV.center) gc.draw(IMG.spinCenter,x,-30*(P.imgY+P.sc[1])+15,nil,nil,nil,4,4) end end --Draw next preview if ENV.nextPos and P.next[1]then drawNextPreview(P,P.next[1].bk) end gc.setScissor() gc.pop() gc.setLineWidth(2) gc.setColor(P.frameColor) gc.rectangle("line",-1,-11,302,612)--Boarder gc.rectangle("line",301,-3,15,604)--AtkBuffer boarder gc.rectangle("line",-16,-3,15,604)--B2b bar boarder --Buffer line local h=0 for i=1,#P.atkBuffer do local A=P.atkBuffer[i] local bar=A.amount*30 if h+bar>600 then bar=600-h end if not A.sent then --Appear if A.time<20 then bar=bar*(20*A.time)^.5*.05 end if A.countdown>0 then --Timing gc.setColor(attackColor[A.lv][1]) gc.rectangle("fill",303,599-h,11,-bar) gc.setColor(attackColor[A.lv][2]) gc.rectangle("fill",303,599-h-bar,11,bar*(1-A.countdown/A.cd0)) else --Warning local t=math.sin((Timer()-i)*30)*.5+.5 local c1,c2=attackColor[A.lv][1],attackColor[A.lv][2] gc.setColor(c1[1]*t+c2[1]*(1-t),c1[2]*t+c2[2]*(1-t),c1[3]*t+c2[3]*(1-t)) gc.rectangle("fill",303,599-h,11,-bar) end else gc.setColor(attackColor[A.lv][1]) bar=bar*(20-A.time)*.05 gc.rectangle("fill",303,599-h,11,-bar) --Disappear end h=h+bar end --B2B indictator local a,b=P.b2b,P.b2b1 if a>b then a,b=b,a end gc.setColor(.8,1,.2) gc.rectangle("fill",-14,599,11,-b*.5) gc.setColor(P.b2b<40 and color.white or P.b2b<=1e3 and color.lRed or color.lBlue) gc.rectangle("fill",-14,599,11,-a*.5) gc.setColor(1,1,1) if Timer()%.5<.3 then gc.rectangle("fill",-15,b<40 and 578.5 or 98.5,13,3) end --LockDelay indicator if ENV.easyFresh then gc.setColor(1,1,1) else gc.setColor(1,.26,.26) end if P.lockDelay>=0 then gc.rectangle("fill",0,602,300*P.lockDelay/ENV.lock,6)--Lock delay indicator end _=3 for i=1,min(ENV.freshLimit-P.freshTime,15)do gc.rectangle("fill",_,615,14,5) _=_+20 end --Draw Hold if ENV.hold then gc.push("transform") gc.translate(-140,116) gc.setColor(0,0,0,.4)gc.rectangle("fill",0,-80,124,80) gc.setColor(1,1,1)gc.rectangle("line",0,-80,124,80) mText(drawableText.hold,62,-131) if P.hd then drawHold(P,P.hd.color) end gc.pop() end --Draw Next(s) local N=ENV.next*72 if ENV.next>0 then gc.setColor(0,0,0,.4)gc.rectangle("fill",316,36,124,N) gc.setColor(1,1,1)gc.rectangle("line",316,36,124,N) mText(drawableText.next,378,-15) N=1 while N<=ENV.next and P.next[N]do local b,c=P.next[N].bk,P.next[N].color for i=1,#b do for j=1,#b[1] do if b[i][j]then drawCell(i-2.4*N-#b*.5,j+12.6-#b[1]*.5,c) end end end N=N+1 end end --Draw Bagline(s) if ENV.bagLine then local L=ENV.bagLen local C=-P.pieceCount%L--Phase gc.setColor(.8,.5,.5) for i=C,N-1,L do local y=72*i+36 gc.line(318+P.fieldOff.x,y,438,y) end end --Draw target selecting pad if modeEnv.royaleMode then if P.atkMode then gc.setColor(1,.8,0,P.swappingAtkMode*.02) gc.rectangle("fill",RCPB[2*P.atkMode-1],RCPB[2*P.atkMode],90,35,8,4) end gc.setColor(1,1,1,P.swappingAtkMode*.025) setFont(18) for i=1,4 do gc.rectangle("line",RCPB[2*i-1],RCPB[2*i],90,35,8,4) mStr(text.atkModeName[i],RCPB[2*i-1]+45,RCPB[2*i]+3) end end gc.pop() --Bonus texts TEXT.draw(P.bonus) gc.pop() --Speed dials setFont(25) drawDial(510,580,P.dropSpeed) drawDial(555,635,P.keySpeed) gc.setColor(1,1,1) gc.draw(drawableText.bpm,540,550) gc.draw(drawableText.kpm,494,643) --Score & Time setFont(25) gc.setColor(0,0,0,.3) gc.print(P.score1,18,579) gc.print(format("%.2f",P.stat.time),18,609) gc.setColor(color.lYellow)gc.print(P.score1,20,580) gc.setColor(color.sky)gc.print(format("%.2f",P.stat.time),20,610) --FinesseCombo if P.finesseCombo>2 then _=P.finesseComboTime local T=P.finesseCombo.."x" if _>0 then gc.setColor(1,1,1,_*.2) gc.print(T,20,640) gc.setColor(1,1,1,1.2-_*.1) gc.push("transform") gc.translate(20,670) gc.scale(1+_*.08) gc.print(T,0,-30) gc.pop() else gc.setColor(1,1,1) gc.print(T,20,640) end end --Lives if P.life>0 then gc.setColor(1,1,1) if P.life<=3 then for i=1,P.life do gc.draw(IMG.lifeIcon,450+25*i,665,nil,.8) end else gc.draw(IMG.lifeIcon,475,665,nil,.8) setFont(20) gc.print("x",503,665) gc.print(P.life,517,665) end end --Display Ys -- gc.setLineWidth(6) -- if P.curY then gc.setColor(1,.4,0,.626)gc.line(0,611-P.curY*30,300,611-P.curY*30)end -- if P.imgY then gc.setColor(0,1,.4,.626)gc.line(0,615-P.imgY*30,300,615-P.imgY*30)end -- if P.minY then gc.setColor(0,.4,1,.626)gc.line(0,619-P.minY*30,300,619-P.minY*30)end --Other messages gc.setColor(1,1,1) if curMode.mesDisp then curMode.mesDisp(P) end --Missions if P.curMission then local missionEnum=missionEnum local L=ENV.mission --Draw current mission setFont(35) if ENV.missionKill then gc.setColor(1,.7+.2*sin(Timer()*3),.4) else gc.setColor(1,1,1) end gc.print(missionEnum[L[P.curMission]],85,180) --Draw next mission gc.setColor(1,1,1) setFont(17) for i=1,3 do local t=L[P.curMission+i] if t then t=missionEnum[t] gc.print(t,87-26*i,187) else break end end end --Draw starting counter gc.setColor(1,1,1) if game.frame<180 then local count=179-game.frame gc.push("transform") gc.translate(305,290) setFont(95) if count%60>45 then gc.scale(1+(count%60-45)^2*.01,1)end mStr(int(count/60+1),0,0) gc.pop() end gc.pop() end end local function Pdraw_small(P) --Draw content P.frameWait=P.frameWait-1 if P.frameWait==0 then P.frameWait=10 gc.setCanvas(P.canvas) gc.clear(0,0,0,.4) gc.push("transform") gc.origin() gc.setColor(1,1,1,P.result and max(20-P.endCounter,0)*.05 or 1) --Field local F=P.field for j=1,#F do for i=1,10 do if F[j][i]>0 then gc.draw(blockSkinMini[F[j][i]],6*i-6,120-6*j) end end end --Draw boarder if P.alive then gc.setLineWidth(2) gc.setColor(P.frameColor) gc.rectangle("line",0,0,60,120) end --Draw badge if modeEnv.royaleMode then gc.setColor(1,1,1) for i=1,P.strength do gc.draw(IMG.badgeIcon,12*i-7,4,nil,.5) end end --Draw result if P.result then gc.setColor(1,1,1,min(P.endCounter,60)*.01) setFont(17)mStr(P.result,32,47) setFont(15)mStr(P.modeData.event,30,82) end gc.pop() gc.setCanvas() end --Draw Canvas gc.setColor(1,1,1) gc.draw(P.canvas,P.x,P.y,nil,P.size*10) if P.killMark then gc.setLineWidth(3) gc.setColor(1,0,0,min(P.endCounter,25)*.04) gc.circle("line",P.centerX,P.centerY,(840-20*min(P.endCounter,30))*P.size) end setFont(30) end local function Pdraw_demo(P) local _ local ENV=P.gameEnv local curColor=P.cur.color --Camera gc.push("transform") gc.translate(P.x,P.y)gc.scale(P.size)gc.translate(P.fieldOff.x,P.fieldOff.y) --Frame gc.setColor(.1,.1,.1,.8) gc.rectangle("fill",0,0,300,600) gc.setLineWidth(2) gc.setColor(1,1,1) gc.rectangle("line",-1,-1,302,602) gc.push("transform") gc.translate(0,600) if P.falling==-1 then --Field block only for j=int(P.fieldBeneath/30+1),#P.field do for i=1,10 do if P.field[j][i]>0 then gc.setColor(1,1,1,min(P.visTime[j][i]*.05,1)) drawCell(j,i,P.field[j][i]) end end end else --Field with falling animation local dy,stepY=0,ENV.smooth and(P.falling/(ENV.fall+1))^2.5*30 or 30 local A=P.falling/ENV.fall local h,H=1,#P.field for j=int(P.fieldBeneath/30+1),H do while j==P.clearingRow[h]do h=h+1 dy=dy+stepY gc.translate(0,-stepY) gc.setColor(1,1,1,A) gc.rectangle("fill",0,630-30*j,300,stepY) end for i=1,10 do if P.field[j][i]>0 then gc.setColor(1,1,1,min(P.visTime[j][i]*.05,1)) drawCell(j,i,P.field[j][i]) end end end gc.translate(0,dy) end drawFXs(P) if P.cur and P.waiting==-1 then --Draw ghost if ENV.ghost then gc.setColor(1,1,1,ENV.ghost) for i=1,P.r do for j=1,P.c do if P.cur.bk[i][j]then drawCell(i+P.imgY-1,j+P.curX-1,curColor) end end end end --Draw block gc.setColor(1,1,1) for i=1,P.r do for j=1,P.c do if P.cur.bk[i][j]then drawCell(i+P.curY-1,j+P.curX-1,curColor) end end end end gc.pop() --Draw hold local blockImg=TEXTURE.miniBlock if P.hd then local id=P.hd.id _=P.color[id] gc.setColor(_[1],_[2],_[3],.3) _=blockImg[id] gc.draw(_,15,30,nil,16,nil,0,_:getHeight()*.5) end --Draw next local N=1 while N<=ENV.next and P.next[N]do local id=P.next[N].id _=P.color[id] gc.setColor(_[1],_[2],_[3],.3) _=blockImg[id] gc.draw(_,285,40*N-10,nil,16,nil,_:getWidth(),_:getHeight()*.5) N=N+1 end gc.setColor(1,1,1) gc.translate(-P.fieldOff.x,-P.fieldOff.y) TEXT.draw(P.bonus) gc.pop() end function player.drawTargetLine(P,r) if r<21+(P.fieldBeneath+P.fieldUp)/30 and r>0 then gc.setLineWidth(4) gc.setColor(1,r>10 and 0 or rnd(),.5) local dx,dy=150+P.fieldOff.x,70+P.fieldOff.y+P.fieldBeneath+P.fieldUp gc.line(dx,600-30*r+dy,300+dx,600-30*r+dy) end end ---------------------------------------------------- ---------------------------------------------------- local function without(L,e) for i=1,#L do if L[i]==e then return end end return true end local function getNewStatTable() local T={ time=0,score=0, key=0,rotate=0,hold=0, extraPiece=0,finesseRate=0, piece=0,row=0,dig=0, atk=0,digatk=0, send=0,recv=0,pend=0,off=0, clear={},clears={},spin={},spins={}, pc=0,hpc=0,b2b=0,b3b=0, maxCombo=0,maxFinesseCombo=0, } for i=1,25 do T.clear[i]={0,0,0,0,0} T.spin[i]={0,0,0,0,0,0} T.clears[i]=0 T.spins[i]=0 end return T end local function pressKey(P,i) if P.keyAvailable[i]then P.keyPressing[i]=true P.act[i](P) if P.control then if P.keyRec then ins(P.keyTime,1,game.frame) P.keyTime[11]=nil end end P.stat.key=P.stat.key+1 end end local function releaseKey(P,i) P.keyPressing[i]=false end local function pressKey_Rec(P,i) if P.keyAvailable[i]then if game.recording then ins(game.rec,game.frame+1) ins(game.rec,i) end P.keyPressing[i]=true P.act[i](P) if P.control then if P.keyRec then ins(P.keyTime,1,game.frame) P.keyTime[11]=nil end end P.stat.key=P.stat.key+1 end end local function releaseKey_Rec(P,i) if game.recording then ins(game.rec,game.frame+1) ins(game.rec,-i) end P.keyPressing[i]=false end local function loadGameEnv(P)--Load gameEnv P.gameEnv={}--Current game setting environment local ENV=P.gameEnv local E --Load game settings for k,v in next,gameEnv0 do if modeEnv[k]~=nil then v=modeEnv[k] --Mode setting -- DBP("mode-"..k..":"..tostring(v)) elseif game.setting[k]~=nil then v=game.setting[k] --Game setting -- DBP("game-"..k..":"..tostring(v)) elseif setting[k]~=nil then v=setting[k] --Global setting -- DBP("global-"..k..":"..tostring(v)) -- else -- DBP("default-"..k..":"..tostring(v)) end ENV[k]=v --Default setting end end local function applyGameEnv(P)--Finish gameEnv processing local ENV=P.gameEnv P._20G=ENV.drop==0 P.dropDelay=ENV.drop P.lockDelay=ENV.lock P.color={} for _=1,7 do P.color[_]=SKIN.libColor[ENV.skin[_]] end P.keepVisible=ENV.visible=="show" P.showTime= ENV.visible=="show"and 1e99 or ENV.visible=="time"and 300 or ENV.visible=="fast"and 20 or ENV.visible=="none"and 0 P.life=ENV.life P.keyAvailable={true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true} if ENV.noTele then for i=11,20 do if i~=14 then P.keyAvailable[i]=false virtualkey[i].ava=false end end end for _,v in next,ENV.keyCancel do P.keyAvailable[v]=false virtualkey[v].ava=false end if type(ENV.mission)=="table"then P.curMission=1 end ENV.das=max(ENV.das,ENV.mindas) ENV.arr=max(ENV.arr,ENV.minarr) ENV.sdarr=max(ENV.sdarr,ENV.minsdarr) ENV.next=min(ENV.next,setting.maxNext) if ENV.sequence~="bag"and ENV.sequence~="loop"then ENV.bagLine=false else ENV.bagLen=#ENV.bag end if ENV.next==0 then ENV.nextPos=false end if ENV.lockFX==0 then ENV.lockFX=nil end if ENV.dropFX==0 then ENV.dropFX=nil end if ENV.moveFX==0 then ENV.moveFX=nil end if ENV.clearFX==0 then ENV.clearFX=nil end if ENV.shakeFX==0 then ENV.shakeFX=nil end if ENV.ghost==0 then ENV.ghost=nil end if ENV.center==0 then ENV.center=nil end end local prepareSequence do local freshMethod local freshPrepare={ rnd=function(P) local bag=P.gameEnv.bag P:getNext(bag[rnd(#bag)]) freshMethod.rnd(P) end, his4=function(P) P.his={} freshMethod.his4(P) end, fixed=function(P) local bag=P.gameEnv.bag for i=1,#bag do P:getNext(bag[i]) end end, } freshMethod={ none=NULL, bag=function(P) while #P.next<6 do local bag0,bag=P.gameEnv.bag,{} for i=1,#bag0 do bag[i]=bag0[i]end repeat P:getNext(rem(bag,P:RND(#bag)))until not bag[1] end end, his4=function(P) while #P.next<6 do local bag=P.gameEnv.bag local L=#bag for n=1,4 do local j,i=0 repeat i=bag[P:RND(L)] j=j+1 until i~=P.his[1]and i~=P.his[2]and i~=P.his[3]and i~=P.his[4]or j==4 P:getNext(i) P.his[n]=i end end end, rnd=function(P) while #P.next<6 do local bag=P.gameEnv.bag local L=#bag for i=1,4 do local count=0 repeat i=bag[P:RND(L)] count=count+1 until i~=P.next[#P.next].id or count>=L P:getNext(i) end end end, reverb=function(P) while #P.next<6 do local bag0,bag=P.gameEnv.bag,{} for i=1,#bag0 do bag[i]=bag0[i]end repeat local r=rem(bag,P:RND(#bag)) local p=1 repeat P:getNext(r) p=p-.15-rnd() until p<0 until not bag[1] end end, loop=function(P) while #P.next<6 do local bag=P.gameEnv.bag for i=1,#bag do P:getNext(bag[i]) end end end, fixed=function(P) if P.cur or P.hd then return end P:lose() end, } function prepareSequence(P)--Call freshPrepare and set newNext local ENV=P.gameEnv if type(ENV.sequence)=="string"then P.newNext=freshMethod[ENV.sequence] if freshPrepare[ENV.sequence]then freshPrepare[ENV.sequence](P) else P:newNext() end else if type(ENV.freshMethod)=="function"then if ENV.sequence then ENV.sequence(P)end P.newNext=ENV.freshMethod else LOG.print("Wrong sequence generator code","warn") ENV.sequence="bag" prepareSequence(P) end end end end local function loadAI(P,AIdata)--Load AI params local ENV=P.gameEnv P.AI_mode=AIdata.type P.AI_stage=1 P.AI_keys={} P.AI_delay=AIdata.delay or min(int(ENV.drop*.8),AIdata.delta*rnd()*4) P.AI_delay0=AIdata.delta P.AIdata={ type=AIdata.type, delay=AIdata.delay, delta=AIdata.delta, next=AIdata.next, hold=AIdata.hold, _20G=P._20G, bag=AIdata.bag, node=AIdata.node, } if not CC then P.AI_mode="9S"end if P.AI_mode=="CC"then P.RS=kickList.AIRS 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.free(opt)CC.free(wei) for i=1,AIdata.next do CC.addNext(P.AI_bot,CCblockID[P.next[i].id]) end elseif P.AI_mode=="9S"then P.RS=kickList.TRS end end local function newEmptyPlayer(id,x,y,size) local P={id=id} players[id]=P players.alive[id]=P --Inherit functions of player class for k,v in next,player do P[k]=v end if P.id==1 and game.recording then P.pressKey=pressKey_Rec P.releaseKey=releaseKey_Rec else P.pressKey=pressKey P.releaseKey=releaseKey end P.update=Pupdate_alive P.fieldOff={x=0,y=0,vx=0,vy=0}--For shake FX P.x,P.y,P.size=x,y,size or 1 P.frameColor=frameColor[0] P.small=P.size<.1--If draw in small mode if P.small then P.centerX,P.centerY=P.x+300*P.size,P.y+600*P.size P.canvas=love.graphics.newCanvas(60,120) P.frameWait=rnd(30,120) P.draw=Pdraw_small else P.keyRec=true--If calculate keySpeed P.centerX,P.centerY=P.x+300*P.size,P.y+370*P.size P.absFieldX=P.x+150*P.size P.absFieldY=P.y+60*P.size P.draw=Pdraw_norm P.bonus={}--Text objects end P.randGen=mt.newRandomGenerator(game.seed) P.small=false P.alive=true P.control=false P.timing=false P.stat=getNewStatTable() P.modeData={point=0,event=0,counter=0}--Data use by mode P.keyTime={}P.keySpeed=0 P.dropTime={}P.dropSpeed=0 for i=1,10 do P.keyTime[i]=-1e5 end for i=1,10 do P.dropTime[i]=-1e5 end P.field,P.visTime={},{} P.atkBuffer={sum=0} --Royale-related P.badge,P.strength=0,0 P.atkMode,P.swappingAtkMode=1,20 P.atker,P.atking,P.lastRecv={} P.dropDelay,P.lockDelay=0,0 P.color={} P.showTime=nil P.keepVisible=true --P.cur={bk=matrix[2], id=shapeID, color=colorID, name=nameID} --P.sc,P.dir={0,0},0--SpinCenterCoord, direction --P.r,P.c=0,0--row, col --P.hd={...},same as P.cur -- P.curX,P.curY,P.imgY,P.minY=0,0,0,0--x,y,ghostY P.holded=false P.next={} P.freshTime=0 P.spinLast=false P.lastClear={ id=1,--block id name=1,--block name row=0,--line cleared spin=false,--if spin mini=false,--if mini pc=false,--if pc special=false,--if special clear (spin, >=4, pc) } P.spinSeq=0--For Ospin, each digit mean a spin P.ctrlCount=0--Key press time, for finesse check P.pieceCount=0--Count pieces from next, for drawing bagline P.human=false P.RS=kickList.TRS -- P.newNext=nil--Call prepareSequence()to get a function to get new next 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 P.waiting,P.falling=-1,-1 P.clearingRow,P.clearedRow={},{}--Clearing animation height,cleared row mark P.combo,P.b2b=0,0 P.finesseCombo=0 P.garbageBeneath=0 P.fieldBeneath=0 P.fieldUp=0 P.score1,P.b2b1=0,0 P.finesseComboTime=0 P.dropFX,P.moveFX,P.lockFX,P.clearFX={},{},{},{} P.tasks={}--Tasks P.bonus={}--Texts P.endCounter=0--Used after gameover P.result=nil--String:"WIN"/"K.O." return P end ---------------------------------------------------- ---------------------------------------------------- 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)) 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)) end function player.createLockFX(P) local BK=P.cur.bk local t=12-P.gameEnv.lockFX*2 for i=1,P.r do local y=P.curY+i-1 if without(P.clearedRow,y)then y=-30*y for j=1,P.c do if BK[i][j]then ins(P.lockFX,{30*(P.curX+j-2),y,0,t}) end end end end end function player.createDropFX(P,x,y,w,h) ins(P.dropFX,{x,y,w,h,0,13-2*P.gameEnv.dropFX}) end function player.createMoveFX(P,dir) local T=10-1.5*P.gameEnv.moveFX local C=P.cur.color local x=P.curX-1 local y=P.gameEnv.smooth and P.curY+P.dropDelay/P.gameEnv.drop-2 or P.curY-1 if dir=="left"then for i=1,P.r do for j=P.c,1,-1 do if P.cur.bk[i][j]then ins(P.moveFX,{C,x+j,y+i,0,T}) break end end end elseif dir=="right"then for i=1,P.r do for j=1,P.c do if P.cur.bk[i][j]then ins(P.moveFX,{C,x+j,y+i,0,T}) break end end end elseif dir=="down"then for j=1,P.c do for i=P.r,1,-1 do if P.cur.bk[i][j]then ins(P.moveFX,{C,x+j,y+i,0,T}) break end end end else for i=1,P.r do for j=1,P.c do if P.cur.bk[i][j]then ins(P.moveFX,{C,x+j,y+i,0,T}) end end end end end function player.createClearingFX(P,y,spd) ins(P.clearFX,{y,0,spd}) end function player.createBeam(P,R,send,time,target,color,clear,combo) local x1,y1,x2,y2 if P.small then x1,y1=P.centerX,P.centerY else x1,y1=P.x+(30*(P.curX+P.sc[2])-30+15+150)*P.size,P.y+(600-30*(P.curY+P.sc[1])+15+70)*P.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 end local radius,corner local a,r,g,b=1,unpack(SKIN.libColor[color]) if clear.special then radius=10+3*send+100/(target+4) local t=clear.row if t==1 then corner=3 r=.3+r*.4 g=.3+g*.4 b=.3+b*.4 elseif t==2 then corner=5 r=.5+r*.5 g=.5+g*.5 b=.5+b*.5 elseif t<6 then corner=6 r=.6+r*.4 g=.6+g*.4 b=.6+b*.4 else corner=20 r=.8+r*.2 g=.8+g*.2 b=.8+b*.2 end else if combo>3 then radius=min(15+combo,30) corner=3 else radius=30 corner=4 end r=1-r*.3 g=1-g*.3 b=1-b*.3 end if modeEnv.royaleMode and not(P.human or R.human)then radius=radius*.4 a=.35 end sysFX.newAttack(x1,y1,x2,y2,radius*(setting.atkFX+3)*.12,corner,type==1 and"fill"or"line",r,g,b,a*(setting.atkFX+5)*.1) end function player.newTask(P,code,data) local L=P.tasks ins(L,{ code=code, data=data, }) end ---------------------------------------------------- ---------------------------------------------------- function player.RND(P,a,b) local R=P.randGen return R:random(a,b) end function player.solid(P,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] [x]>0--to catch bug (nil[*]) end function player.ifoverlap(P,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 for i=1,#bk do if P.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 end end end end function player.ckfull(P,i) for j=1,10 do if P.field[i][j]<=0 then return end end return true end function player.attack(P,R,send,time,...) if setting.atkFX>0 then P:createBeam(R,send,time,...) end R.lastRecv=P if R.atkBuffer.sum<20 then local B=R.atkBuffer if send>20-B.sum then send=20-B.sum end--No more then 20 local m,k=#B,1 while k<=m and time>B[k].countdown do k=k+1 end for i=m,k,-1 do B[i+1]=B[i] end B[k]={ pos=P:RND(10), amount=send, countdown=time, cd0=time, time=0, sent=false, lv=min(int(send^.69),5), }--Sorted insert(by time) B.sum=B.sum+send R.stat.recv=R.stat.recv+send if R.sound then SFX.play(send<4 and "blip_1"or"blip_2",min(send+1,5)*.1) end end end function player.garbageRelease(P) local n,flag=1 while true do local A=P.atkBuffer[n] if A and A.countdown<=0 and not A.sent then P:garbageRise(12+A.lv,A.amount,A.pos) P.atkBuffer.sum=P.atkBuffer.sum-A.amount A.sent,A.time=true,0 P.stat.pend=P.stat.pend+A.amount n=n+1 flag=true else break end end if flag and P.AI_mode=="CC"then CC.updateField(P)end end function player.garbageRise(P,color,amount,pos) local _ local t=P.showTime*2 for _=1,amount do ins(P.field,1,freeRow.get(color)) ins(P.visTime,1,freeRow.get(t)) P.field[1][pos]=0 end P.fieldBeneath=P.fieldBeneath+amount*30 if P.cur then P.curY=P.curY+amount P.imgY=P.imgY+amount end P.garbageBeneath=P.garbageBeneath+amount for i=1,#P.clearingRow do P.clearingRow[i]=P.clearingRow[i]+amount end P:freshBlock(false,false) for i=1,#P.lockFX do _=P.lockFX[i] _[2]=_[2]-30*amount--Shift 30px per line cleared end for i=1,#P.dropFX do _=P.dropFX[i] _[3],_[5]=_[3]+amount,_[5]+amount end if #P.field>42 then P:lose()end end local invList={2,1,4,3,5,6,7} function player.pushLine(P,L,mir) local S=P.gameEnv.skin for i=1,#L do local r=freeRow.get(0) if not mir then for j=1,10 do r[j]=S[L[i][j]]or 0 end else for j=1,10 do r[j]=S[invList[L[i][11-j]]]or 0 end end ins(P.field,1,r) ins(P.visTime,1,freeRow.get(20)) end P.fieldBeneath=P.fieldBeneath+120 P.curY=P.curY+#L P.imgY=P.imgY+#L P:freshBlock(false,false) end function player.pushNext(P,L,mir) for i=1,#L do P:getNext(mir and invList[L[i]]or L[i]) 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)) 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) return end end end end function player.changeAtkMode(P,m) if P.atkMode==m then return end P.atkMode=m if m==1 then P:changeAtk(randomTarget(P)) elseif m==2 or m==3 then P:freshTarget() elseif m==4 then P:changeAtk() end end function player.changeAtk(P,R) -- if not P.human then R=players[1]end--1vALL mode? if P.atking then local K=P.atking.atker for i=1,#K do if K[i]==P then rem(K,i) break end end end if R then P.atking=R ins(R.atker,P) else P.atking=nil end end function player.freshBlock(P,keepGhost,control,system) local ENV=P.gameEnv if not keepGhost and P.cur then P.imgY=min(#P.field+1,P.curY) if P._20G or P.keyPressing[7]and ENV.sdarr==0 then local _=P.imgY --Move ghost to bottom while not P:ifoverlap(P.cur.bk,P.curX,P.imgY-1)do P.imgY=P.imgY-1 end --Cancel spinLast if _~=P.imgY then P.spinLast=false end --Create FX if dropped if P.curY>P.imgY then if ENV.dropFX and ENV.block and P.curY-P.imgY-P.r>-1 then P:createDropFX(P.curX,P.curY-1,P.c,P.curY-P.imgY-P.r+1) end if ENV.shakeFX then P.fieldOff.vy=ENV.shakeFX*.5 end P.curY=P.imgY end else while not P:ifoverlap(P.cur.bk,P.curX,P.imgY-1)do P.imgY=P.imgY-1 end end end if control then if ENV.easyFresh then local d0=ENV.lock if P.lockDelay=P.gameEnv.das then local x=P.curX+P.movDir if not P:ifoverlap(C.bk,x,y)then P.curX=x end end --IRS if P.gameEnv.irs then if _[5]then P:spin(2,true) else if _[3]then if _[4]then P:spin(2,true) else P:spin(1,true) end elseif _[4]then P:spin(3,true) end end end --Spawn SFX if P.sound and id<8 then SFX.fplay(spawnSFX_name[id],setting.spawn) end end function player.spin(P,d,ifpre) local iki=P.RS[P.cur.id] if type(iki)=="table"then local idir=(P.dir+d)%4 local icb=blocks[P.cur.id][idir] local isc=scs[P.cur.id][idir] local ir,ic=#icb,#icb[1] local ix,iy=P.curX+P.sc[2]-isc[2],P.curY+P.sc[1]-isc[1] iki=iki[P.dir*10+idir] if not iki then if P.gameEnv.easyFresh then P:freshBlock(false,true) end SFX.fieldPlay(ifpre and"prerotate"or "rotate",nil,P) return end for test=1,#iki do local x,y=ix+iki[test][1],iy+iki[test][2] if not P:ifoverlap(icb,x,y)and(P.freshTime<=P.gameEnv.freshLimit or iki[test][2]<0)then ix,iy=x,y if P.gameEnv.moveFX and P.gameEnv.block then P:createMoveFX() end P.curX,P.curY,P.dir=ix,iy,idir P.sc,P.cur.bk=scs[P.cur.id][idir],icb P.r,P.c=ir,ic P.spinLast=test==2 and 0 or 1 if not ifpre then P:freshBlock(false,true) end if iki[test][2]>0 and not P.gameEnv.easyFresh then P.freshTime=P.freshTime+1 end if P.sound then SFX.fieldPlay(ifpre and"prerotate"or P:ifoverlap(P.cur.bk,P.curX,P.curY+1)and P:ifoverlap(P.cur.bk,P.curX-1,P.curY)and P:ifoverlap(P.cur.bk,P.curX+1,P.curY)and"rotatekick"or"rotate",nil,P) end P.stat.rotate=P.stat.rotate+1 return end end else iki(P,d) end end function player.hold(P,ifpre) if not P.holded and (ifpre or P.waiting==-1) and P.gameEnv.hold then local H,C=P.hd,P.cur if not(H or C)then return end --Finesse check if not(H and C and H.id==C.id and H.name==C.name or P.ctrlCount>1)then P.ctrlCount=0 end P.holded=P.gameEnv.oncehold P.spinLast=false P.spinSeq=0 P.cur,P.hd=H,C--Swap hold H,C=P.hd,P.cur if H then local hid=P.hd.id P.hd.bk=blocks[hid][P.gameEnv.face[hid]] end if not C then C=rem(P.next,1) P:newNext() if C then P.cur=C P.pieceCount=P.pieceCount+1 if P.AI_mode=="CC"then local next=P.next[P.AIdata.next] if next then CC.addNext(P.AI_bot,CCblockID[next.id]) end end else P.holded=false end end if C then P:resetBlock() P:freshBlock(false,true) P.dropDelay=P.gameEnv.drop P.lockDelay=P.gameEnv.lock P.freshTime=max(P.freshTime-5,0) if P:ifoverlap(P.cur.bk,P.curX,P.curY)then P:lock()P:lose()end end if P.sound then SFX.play(ifpre and"prehold"or"hold") end P.stat.hold=P.stat.hold+1 end end function player.getNext(P,n) local E=P.gameEnv ins(P.next,{bk=blocks[n][E.face[n]],id=n,color=E.bone and 12 or E.skin[n],name=n}) end function player.popNext(P)--Pop next queue to hand P.holded=false P.spinLast=false P.spinSeq=0 P.ctrlCount=0 P.cur=rem(P.next,1) P:newNext() if P.cur then P.pieceCount=P.pieceCount+1 if P.AI_mode=="CC"then local next=P.next[P.AIdata.next] if next then CC.addNext(P.AI_bot,CCblockID[next.id]) end end local _=P.keyPressing --IHS if _[8]and P.gameEnv.hold and P.gameEnv.ihs then P:hold(true) _[8]=false else P:resetBlock() end P.dropDelay=P.gameEnv.drop P.lockDelay=P.gameEnv.lock P.freshTime=0 if P.cur then if P:ifoverlap(P.cur.bk,P.curX,P.curY)then P:lock() P:lose() end P:freshBlock(false,true,true) end --IHdS if _[6]then P.act.hardDrop(P) _[6]=false end end end function player.cancel(P,N)--Cancel Garbage local k=0 --Pointer, attack bar selected local off=0 --Lines offseted local bf=P.atkBuffer ::R:: if bf.sum>0 then local A repeat k=k+1 A=bf[k] if not A then return off end until not A.sent if N>=A.amount then local O=A.amount--Cur Offset N=N-O off=off+O bf.sum=bf.sum-O A.sent,A.time=true,0 if N>0 then goto R end else off=off+N A.amount=A.amount-N bf.sum=bf.sum-N end end return off end do--player.drop(P)--Place piece local b2bPoint={50,100,180,1000,1200} local b2bATK={3,5,8,12,18} local clearSCR={80,200,400} local spinSCR={--[blockName][row] {200,750,1300},--Z {200,750,1300},--S {220,700,1300},--L {220,700,1300},--J {250,800,1400},--T {260,900,1700,4000},--O {300,1200,1700,4000},--I {220,800,2000,3000,8000},--Else } --B2BMUL:1.2/2.0 --Techrash:1K;MUL:1.3/1.8 --Mini*=.6 local reAtk={0,0,1,1,1,2,2,3,3} local reDef={0,1,1,2,3,3,4,4,5} local spinName={"zspin","sspin","jspin","lspin","tspin","ospin","ispin","zspin","sspin","pspin","qspin","fspin","espin","tspin","uspin","vspin","wspin","xspin","jspin","lspin","rspin","yspin","hspin","nspin","ispin"} local clearName={"single","double","triple","techrash","pentcrash"} local spin_n={[0]="spin_0","spin_1","spin_2","spin_3","spin_3","spin_3"} local clear_n={"clear_1","clear_2","clear_3","clear_4","clear_4"} local ren_n={}for i=1,11 do ren_n[i]="ren_"..i end local finesseList={ [1]={ {1,2,1,0,1,2,2,1}, {2,2,2,1,1,2,3,2,2}, },--Z [3]={ {1,2,1,0,1,2,2,1}, {2,2,3,2,1,2,3,3,2}, {3,4,3,2,3,4,4,3}, {2,3,2,1,2,3,3,2,2}, },--L [6]={ {1,2,2,1,0,1,2,2,1}, },--O [7]={ {1,2,1,0,1,2,1}, {2,2,2,2,1,1,2,2,2,2}, },--I } finesseList[1][3],finesseList[1][4],finesseList[7][3],finesseList[7][4]=finesseList[1][1],finesseList[1][2],finesseList[7][1],finesseList[7][2]--"2-phase" SZI finesseList[2]=finesseList[1]--S=Z finesseList[4],finesseList[5]=finesseList[3],finesseList[3]--J=L=T function player.drop(P) 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 P.waiting=ENV.wait local cmb=P.combo local CB,CX,CY=P.cur,P.curX,P.curY local clear--If (perfect)clear local cc,gbcc=0,0--Row/garbage-row cleared,full-part local atk,exblock=0,0--Attack & extra defense local send,off=0,0--Sending lines remain & offset local cscore,sendTime=10,0--Score & send Time local dospin=0 local mini --Tri-corner spin check if P.spinLast then if CB.id<6 then local x,y=CX+P.sc[2],CY+P.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 c==0 then goto NTC end 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 c>2 then dospin=dospin+2 end end ::NTC:: end --Immovable spin check if P:ifoverlap(CB.bk,CX,CY+1)and P:ifoverlap(CB.bk,CX-1,CY)and P:ifoverlap(CB.bk,CX+1,CY)then dospin=dospin+2 end --Lock block to field P:lock() --Clear list of cleared-rows if P.clearedRow[1]then P.clearedRow={}end --Check rows to be cleared for i=0,P.r-1 do local h=CY+i if P:ckfull(h)then cc=cc+1 P.clearingRow[cc]=h-cc+1 P.clearedRow[cc]=h end end --Create clearing FX if cc>0 and ENV.clearFX then local t=7-ENV.clearFX*1 for i=1,cc do P:createClearingFX(P.clearedRow[i],t) end end --Create locking FX if ENV.lockFX then if cc==0 then P:createLockFX() else _=#P.lockFX if _>0 then for i=1,_ do rem(P.lockFX) end end end end --Final spin check if dospin>0 then if cc>0 then dospin=dospin+(P.spinLast or 0) if dospin<3 then mini=CB.id<6 and cc7 then finesse=true elseif CY<=18 then local y0=CY local x,c=CX,P.c local B=CB.bk for x=1,c do local y for i=#B,1,-1 do if B[i][x]then y=i goto L1 end end goto L2 ::L1:: if y then x=CX+x-1 for y=y0+y,#P.field do --Roof=finesse if P:solid(x,y)then finesse=true goto L2 end end end end else finesse=true end ::L2:: --Remove rows need to be cleared if cc>0 then for i=cc,1,-1 do _=P.clearedRow[i] freeRow.discard(rem(P.field,_)) freeRow.discard(rem(P.visTime,_)) if _<=P.garbageBeneath then P.garbageBeneath=P.garbageBeneath-1 gbcc=gbcc+1 end end end --Cancel no-sense clearing FX _=#P.clearingRow while _>0 and P.clearingRow[_]>#P.field do P.clearingRow[_]=nil _=_-1 end if P.clearingRow[1]then P.falling=ENV.fall elseif cc==P.r then clear=true end --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 local id=CB.id local d=P.ctrlCount-finesseList[id][P.dir+1][CX] finePts=d<=0 and 5 or max(3-d,0) else finePts=5 end P.stat.finesseRate=P.stat.finesseRate+finePts if finePts<5 then P.stat.extraPiece=P.stat.extraPiece+1 if ENV.fineKill then P:lose() end if P.sound then if ENV.fineKill then SFX.play("finesseError_long",.6) elseif ENV.fine then SFX.play("finesseError",.8) end end end if finePts<=1 then P.finesseCombo=0 else P.finesseCombo=P.finesseCombo+1 if P.finesseCombo>2 then P.finesseComboTime=12 end if P.sound then SFX.fieldPlay("lock",nil,P)end end if cc>0 then--If lines cleared, about 200 lines below local C=P.lastClear C.id,C.name=CB.id,CB.name C.row=cc C.spin=dospin cmb=cmb+1 if dospin then cscore=(spinSCR[CB.name]or spinSCR[8])[cc] if P.b2b>1000 then P:showText(text.b3b..text.block[CB.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 VOC.play("b3b",CHN) end elseif P.b2b>=50 then P:showText(text.b2b..text.block[CB.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 VOC.play("b2b",CHN) end else P:showText(text.block[CB.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") atk=atk*.25 sendTime=sendTime+60 cscore=cscore*.5 P.b2b=P.b2b+b2bPoint[cc]*.5 if P.sound then VOC.play("mini",CHN) end else P.b2b=P.b2b+b2bPoint[cc] end C.mini=mini C.special=true if P.sound then SFX.play(spin_n[cc]) VOC.play(spinName[CB.name],CHN) end elseif cc>=4 then cscore=cc==4 and 1000 or 1500 if P.b2b>1000 then P:showText(text.b3b..text.clear[cc],0,-30,50,"fly") atk=cc*1.5 sendTime=100 exblock=exblock+1 cscore=cscore*1.8 STAT.b3b=STAT.b3b+1 if P.sound then VOC.play("b3b",CHN) end elseif P.b2b>=50 then P:showText(text.b2b..text.clear[cc],0,-30,50,"drive") sendTime=80 atk=cc+1 cscore=cscore*1.3 STAT.b2b=STAT.b2b+1 if P.sound then VOC.play("b2b",CHN) end else P:showText(text.clear[cc],0,-30,70,"stretch") sendTime=60 atk=cc end P.b2b=P.b2b+cc*100-300 C.special=true else C.special=false end if P.sound then VOC.play(clearName[cc],CHN) end --PC/HPC bonus C.pc,C.hpc=false,false if clear and #P.field==0 then P:showText(text.PC,0,-80,50,"flicker") atk=atk*.5+min(8+STAT.pc*2,20) exblock=exblock+2 sendTime=sendTime+120 if STAT.row+cc>4 then P.b2b=1200 cscore=cscore+300*min(6+STAT.pc,10) else cscore=cscore+626 end STAT.pc=STAT.pc+1 if P.sound then SFX.play("clear") VOC.play("perfect_clear",CHN) end C.pc=true C.special=true elseif clear and(cc>1 or #P.field==P.garbageBeneath)then P: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 SFX.play("clear") VOC.play("half_clear",CHN) end C.hpc=true C.special=true end --Normal clear, reduce B2B point if not C.special then P.b2b=max(P.b2b-250,0) P:showText(text.clear[cc],0,-30,35,"appear",(8-cc)*.3) atk=cc-.5 sendTime=20+atk*20 cscore=cscore+clearSCR[cc] end --Combo bonus sendTime=sendTime+25*cmb if cmb>1 then atk=atk*(1+(cc==1 and .15 or .25)*min(cmb-1,12)) 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") cscore=cscore+min(50*cmb,500)*(2*cc-1) end if P.b2b>1200 then P.b2b=1200 end --Bonus atk/def when focused if modeEnv.royaleMode then local i=min(#P.atker,9) if i>1 then atk=atk+reAtk[i] exblock=exblock+reDef[i] end end --Send Lines send=atk if send>0 then 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) end send=int(send*(1+P.strength*.25))--Badge Buff if send>0 then P:showText(send,0,80,35,"zoomout") _=P:cancel(send) send=send-_ off=off+_ if send>0 then local T if modeEnv.royaleMode then if P.atkMode==4 then local M=#P.atker if M>0 then for i=1,M do P:attack(P.atker[i],send,sendTime,M,CB.color,C,cmb) end else T=randomTarget(P) end else P:freshTarget() T=P.atking end elseif #players.alive>1 then T=randomTarget(P) end if T then P:attack(T,send,sendTime,1,CB.color,C,cmb) end end if P.sound and send>3 then SFX.play("emit",min(send,7)*.1)end end end --Check clearing task if P.curMission then local t=ENV.mission[P.curMission] local success if t<5 then if C.row==t and(t==4 or not C.special)then success=true end elseif t<9 then if C.row==t-4 and C.spin then success=true end elseif t==9 then if C.pc then success=true end elseif t<90 then if C.row==t%10 and C.name==int(t/10)and C.spin then success=true end end if success then P.curMission=P.curMission+1 SFX.play("reach") if P.curMission>#ENV.mission then P.curMission=nil P:win("finish") end elseif ENV.missionKill then P:showText(text.missionFailed,0,140,40,"flicker",.5) SFX.play("finesseError_long",.6) P:lose() end end --SFX & Vibrate if P.sound then SFX.play(clear_n[cc]) SFX.play(ren_n[min(cmb,11)]) if cmb>14 then SFX.play("ren_mega",(cmb-10)*.1)end VIB(cc+1) end else--No lines clear cmb=0 --Spin bonus if dospin then P:showText(text.block[CB.name]..text.spin,0,-30,45,"appear") P.b2b=P.b2b+20 if P.sound then SFX.play("spin_0") VOC.play(spinName[CB.name],CHN) end cscore=30 end if P.b2b>1000 then P.b2b=max(P.b2b-40,1000) end P:garbageRelease() end P.combo=cmb --DropSpeed bonus if P._20G then cscore=cscore*2 elseif ENV.drop<1 then cscore=cscore*1.5 elseif ENV.drop<3 then cscore=cscore*1.2 end --Speed bonus if P.dropSpeed>60 then cscore=cscore*(.9+P.dropSpeed/600) end cscore=int(cscore) if ENV.score then P:showText(cscore,(P.curX+P.sc[2]-5.5)*30,(10-P.curY-P.sc[1])*30+P.fieldBeneath+P.fieldUp,int(8-120/(cscore+20))*5,"score",2) end --Update stat 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) if atk>0 then STAT.atk=STAT.atk+atk if send>0 then STAT.send=STAT.send+int(send) end if off>0 then STAT.off=STAT.off+off end end if gbcc>0 then STAT.dig=STAT.dig+gbcc STAT.digatk=STAT.digatk+atk*gbcc/cc end local n=CB.name if dospin then _=STAT.spin[n] _[cc+1]=_[cc+1]+1--Spin[1~25][0~4] _=STAT.spins _[cc+1]=_[cc+1]+1--Spin[0~4] elseif cc>0 then _=STAT.clear[n] _[cc]=_[cc]+1--Clear[1~25][1~5] _=STAT.clears _[cc]=_[cc]+1--Clear[1~5] end --Drop event _=ENV.dropPiece if _ then _(P)end end end ---------------------------------------------------- ---------------------------------------------------- local function gameOver()--Save record if game.replaying then return end FILE.saveData() local M=curMode local R=M.getRank if R then local P=players[1] R=R(P)--New rank if R then local r=modeRanks[M.name]--Old rank local needSave if R>r then modeRanks[M.name]=R needSave=true end if R>0 then LOG.print(text.getRank..text.ranks[R],color.green) if M.unlock then for i=1,#M.unlock do local m=M.unlock[i] local n=Modes[m].name if not modeRanks[n]then modeRanks[n]=Modes[m].score and 0 or 6 needSave=true end end end end if needSave then FILE.saveUnlock() end local D=M.score(P) local L=M.records local p=#L--Rank-1 if p>0 then while M.comp(D,L[p])do--If higher rank p=p-1 if p==0 then break end end end if p<10 then if p==0 then P:showTextF(text.newRecord,0,-100,100,"beat",.5) end D.date=os.date("%Y/%m/%d %H:%M") ins(L,p+1,D) if L[11]then L[11]=nil end FILE.saveRecord(M.name,L) end end end end function player.die(P)--Called when win/lose,not really die! P.alive=false P.timing=false P.control=false P.update=Pupdate_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 end for i=1,#P.field do for j=1,10 do P.visTime[i][j]=min(P.visTime[i][j],20) end end end function player.win(P,result) P:die() P.result="WIN" if modeEnv.royaleMode then P.modeData.event=1 P:changeAtk() end if P.human then game.result=result or"win" SFX.play("win") VOC.play("win") if modeEnv.royaleMode then BGM.play("8-bit happiness") end end if curMode.id=="custom_puzzle"then P:showTextF(text.win,0,0,90,"beat",.4) else P:showTextF(text.win,0,0,90,"beat",.5,.2) end if P.human then gameOver() TASK.new(TICK.autoPause,{0}) if marking then P:showTextF(text.marking,0,-226,25,"appear",.4,.0626) end end P:newTask(TICK.finish) end function player.lose(P) if P.life>0 then for _=#P.field,1,-1 do freeRow.discard(P.field[_]) freeRow.discard(P.visTime[_]) P.field[_],P.visTime[_]=nil end if P.AI_mode=="CC"then CC.destroy(P.AI_bot) P.hd=nil loadAI(P,P.AIdata) P:popNext() end P.life=P.life-1 P.fieldBeneath=0 P.b2b=0 for i=1,#P.atkBuffer do local A=P.atkBuffer[i] if not A.sent then A.sent=true A.time=0 end end P.atkBuffer.sum=0 for i=1,21 do P:createClearingFX(i,1.5) end sysFX.newShade(.5,1,1,1,P.x+150*P.size,P.y+60*P.size,300*P.size,610*P.size) sysFX.newRectRipple(.3,P.x+150*P.size,P.y+60*P.size,300*P.size,610*P.size) sysFX.newRipple(.3,P.x+(475+25*(P.life<3 and P.life or 0)+12)*P.size,P.y+(665+12)*P.size,20) --300+25*i,595 SFX.play("clear_3") SFX.play("emit") return end P:die() for i=1,#players.alive do if players.alive[i]==P then rem(players.alive,i) break end end P.result="K.O." if modeEnv.royaleMode then P:changeAtk() P.modeData.event=#players.alive+1 P.strength=0 if P.lastRecv then local A,i=P,0 repeat A,i=A.lastRecv,i+1 until not A or A.alive or A==P or i==3 if A and A.alive then if P.id==1 or A.id==1 then P.killMark=A.id==1 end A.modeData.point,A.badge=A.modeData.point+1,A.badge+P.badge+1 for i=A.strength+1,4 do if A.badge>=royaleData.powerUp[i]then A.strength=i A.frameColor=frameColor[A.strength] end end P.lastRecv=A if P.id==1 or A.id==1 then TASK.new(TICK.throwBadge,{A.ai,P,max(3,P.badge)*4}) end end else P.badge=-1 end freshMostBadge() freshMostDangerous() if #players.alive==royaleData.stage[game.stage]then royaleLevelup() end P:showTextF(P.modeData.event,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.human then game.result="gameover" SFX.play("fail") VOC.play("lose") if modeEnv.royaleMode then if P.modeData.event==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) TASK.new(TICK.autoPause,{0}) if marking then P:showTextF(text.marking,0,-226,25,"appear",.4,.0626) end else P:newTask(TICK.lose) end if #players.alive==1 then players.alive[1]:win() end end function PLY.check_lineReach(P) if P.stat.row>=P.gameEnv.target then P:win("finish") end end function PLY.check_attackReach(P) if P.stat.atk>=P.gameEnv.target then P:win("finish") end end --------------------------<\Events>-------------------------- ---------------------------------------------------- player.act={} function player.act.moveLeft(P,auto) if not auto then P.ctrlCount=P.ctrlCount+1 end P.movDir=-1 if P.keyPressing[9]then if P.gameEnv.swap then P:changeAtkMode(1) P.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") end P.curX=P.curX-1 P:freshBlock(false,true) if P.sound and P.curY==P.imgY then SFX.play("move")end if not auto then P.moving=0 end P.spinLast=false else P.moving=P.gameEnv.das end else P.moving=0 end end function player.act.moveRight(P,auto) if not auto then P.ctrlCount=P.ctrlCount+1 end P.movDir=1 if P.keyPressing[9]then if P.gameEnv.swap then P:changeAtkMode(2) P.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") end P.curX=P.curX+1 P:freshBlock(false,true) if P.sound and P.curY==P.imgY then SFX.play("move")end if not auto then P.moving=0 end P.spinLast=false else P.moving=P.gameEnv.das end else P.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 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 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 end end function player.act.hardDrop(P) if P.keyPressing[9]then if P.gameEnv.swap then P:changeAtkMode(3) end P.keyPressing[6]=false elseif P.control and P.waiting==-1 and P.cur then if P.curY>P.imgY then if P.gameEnv.dropFX and P.gameEnv.block and P.curY-P.imgY-P.r>-1 then P:createDropFX(P.curX,P.curY-1,P.c,P.curY-P.imgY-P.r+1) end P.curY=P.imgY P.spinLast=false if P.gameEnv.shakeFX then P.fieldOff.vy=P.gameEnv.shakeFX*.6 end if P.sound then SFX.fieldPlay("drop",nil,P) VIB(1) end end P.lockDelay=-1 P:drop() P.keyPressing[6]=false end end function player.act.softDrop(P) if P.keyPressing[9]then if P.gameEnv.swap then P:changeAtkMode(4) end else P.downing=1 if P.control and P.waiting==-1 and P.cur then if P.curY>P.imgY then P.curY=P.curY-1 P:freshBlock(true,true) P.spinLast=false end end end end function player.act.hold(P) if P.control and P.waiting==-1 then P:hold() end end function player.act.func(P) P.gameEnv.Fkey(P) end function player.act.restart(P) if game.frame<240 or game.result then resetPartGameData() else LOG.print(text.holdR,20,color.orange) end 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") end P.curX=P.curX-1 P:freshBlock(false,true) end if P.curX~=x0 then P.spinLast=false end if P.gameEnv.shakeFX then P.fieldOff.vx=-P.gameEnv.shakeFX*.5 end if auto then if P.ctrlCount==0 then P.ctrlCount=1 end else P.ctrlCount=P.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") end P.curX=P.curX+1 P:freshBlock(false,true) end if P.curX~=x0 then P.spinLast=false end if P.gameEnv.shakeFX then P.fieldOff.vx=P.gameEnv.shakeFX*.5 end if auto then if P.ctrlCount==0 then P.ctrlCount=1 end else P.ctrlCount=P.ctrlCount+1 end end function player.act.insDown(P) if P.cur and P.curY>P.imgY then if P.gameEnv.dropFX and P.gameEnv.block and P.curY-P.imgY-P.r>-1 then P:createDropFX(P.curX,P.curY-1,P.c,P.curY-P.imgY-P.r+1) end if P.gameEnv.shakeFX then P.fieldOff.vy=P.gameEnv.shakeFX*.5 end P.curY=P.imgY P.lockDelay=P.gameEnv.lock P.spinLast=false P:freshBlock(true,true) end end function player.act.down1(P) if P.cur and P.curY>P.imgY then if P.gameEnv.moveFX and P.gameEnv.block then P:createMoveFX("down") end P.curY=P.curY-1 P:freshBlock(true,true) P.spinLast=false end end function player.act.down4(P) if P.cur and P.curY>P.imgY then local y=max(P.curY-4,P.imgY) if P.gameEnv.dropFX and P.gameEnv.block and P.curY-y-P.r>-1 then P:createDropFX(P.curX,P.curY-1,P.c,P.curY-y-P.r+1) end P.curY=y P:freshBlock(true,true) P.spinLast=false end end function player.act.down10(P) if P.cur and P.curY>P.imgY then local y=max(P.curY-10,P.imgY) if P.gameEnv.dropFX and P.gameEnv.block and P.curY-y-P.r>-1 then P:createDropFX(P.curX,P.curY-1,P.c,P.curY-y-P.r+1) end P.curY=y P:freshBlock(true,true) P.spinLast=false end end function player.act.dropLeft(P) if not P.cur then return end P.act.insLeft(P) P.act.hardDrop(P) end function player.act.dropRight(P) if not P.cur then return end P.act.insRight(P) P.act.hardDrop(P) end function player.act.zangiLeft(P) if not P.cur then return end P.act.insLeft(P) P.act.insDown(P) P.act.insRight(P) P.act.hardDrop(P) end function player.act.zangiRight(P) if not P.cur then return end P.act.insRight(P) P.act.insDown(P) P.act.insLeft(P) P.act.hardDrop(P) end --Give operations a num name do local A=player.act local T={ A.moveLeft ,A.moveRight, A.rotRight, A.rotLeft, A.rot180 ,A.hardDrop, A.softDrop, A.hold, A.func ,A.restart, A.insLeft, A.insRight, A.insDown ,A.down1, A.down4, A.down10, A.dropLeft ,A.dropRight, A.zangiLeft,A.zangiRight }for i=1,20 do A[i]=T[i]end end ---------------------------------------------------- ---------------------------------------------------- function PLY.newDemoPlayer(id,x,y,size) local P=newEmptyPlayer(id,x,y,size) -- rewrite some args P.small=false P.centerX,P.centerY=P.x+300*P.size,P.y+600*P.size P.absFieldX=P.x+150*P.size P.absFieldY=P.y+60*P.size P.draw=Pdraw_demo P.control=true P.gameEnv={ das=10,arr=2,sddas=2,sdarr=2, swap=true, ghost=setting.ghost, center=setting.center, smooth=setting.smooth, grid=setting.grid, text=setting.text, score=setting.score, lockFX=setting.lockFX, dropFX=setting.dropFX, moveFX=setting.moveFX, clearFX=setting.clearFX, shakeFX=setting.shakeFX, drop=1e99,lock=1e99, wait=10,fall=20, bone=false, next=6, hold=true,oncehold=true, ospin=true, sequence="bag", bag={1,2,3,4,5,6,7}, face={0,0,0,0,0,0,0}, skin=setting.skin, mission=false, life=1e99, pushSpeed=3, block=true, noTele=false, visible="show", freshLimit=1e99,easyFresh=true, keyCancel={}, mindas=0,minarr=0,minsdarr=0, } applyGameEnv(P) prepareSequence(P) P.human=false P.sound=true loadAI(P,{ type="CC", next=5, hold=true, delay=30, delta=4, bag="bag", node=100000, }) P:popNext() end function PLY.newRemotePlayer(id,x,y,size,actions) local P=newEmptyPlayer(id,x,y,size) P.human=false P.sound=false P.remote=true -- P.updateAction=buildActionFunctionFromActions(P, actions) loadGameEnv(P) applyGameEnv(P) prepareSequence(P) end function PLY.newAIPlayer(id,x,y,size,AIdata) local P=newEmptyPlayer(id,x,y,size) local ENV=P.gameEnv if P.small then ENV.text=false ENV.lockFX=nil ENV.dropFX=nil ENV.moveFX=nil ENV.shakeFX=nil end loadGameEnv(P) applyGameEnv(P) local ENV=P.gameEnv ENV.face={0,0,0,0,0,0,0} ENV.skin={1,5,8,2,10,3,7} prepareSequence(P) P.human=false P.sound=false loadAI(P,AIdata) end function PLY.newPlayer(id,x,y,size) local P=newEmptyPlayer(id,x,y,size) loadGameEnv(P) applyGameEnv(P) prepareSequence(P) P.human=true P.sound=true P.RS=kickList.TRS end ---------------------------------------------------- return PLY