local gc=love.graphics local Timer=love.timer.getTime local int,ceil,abs,rnd,max,min=math.floor,math.ceil,math.abs,math.random,math.max,math.min local ins,rem=table.insert,table.remove local format=string.format local actName=actName--controllings' id local scr=scr--screen camera -------------------------------------------------- local gameEnv0={ noFly=false, das=10,arr=2, sddas=2,sdarr=2, quickR=true,swap=true, ghost=true,center=true, smooth=false,grid=false, lockFX=3,dropFX=3, shakeFX=3, _20G=false,bone=false, drop=60,lock=60, wait=0,fall=0, next=6,hold=true, oncehold=true, ospin=true, sequence="bag7", face=NULL, skin=NULL, pushSpeed=3, block=true, visible="show", Fkey=NULL,puzzle=false, freshLimit=1e99,easyFresh=true, fine=false,fineKill=false, target=1e99,dropPiece=NULL, mindas=0,minarr=0,minsdarr=0, bg="none",bgm="race" } local comboAtk={0,0,1,1,2,2,2,3,3,4,3}--2 else local b2bPoint={50,100,180} local b2bATK={3,5,8} local clearSCR={80,200,400} local spinSCR={--[blockName][row] {200,750,1600},--Z {200,750,1600},--S {220,700,1600},--L {220,700,1600},--J {250,800,1500},--T {260,900,1800},--O {300,1200,1700},--I } --B2BMUL:1.2/2.0 --Techrash:1K;MUL:1.3/1.8 --Mini*=.6 local visible_opt={show=1e99,time=300,fast=20,none=5} 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","lspin","jspin","tspin","ospin","ispin"} local clearName={"single","double","triple"} local spin_n={[0]="spin_0","spin_1","spin_2","spin_3"} local clear_n={"clear_1","clear_2","clear_3","clear_4"} local ren_n={}for i=1,11 do ren_n[i]="ren_"..i end local initCenterX={6,6,6,6,6,6.5,6.5}--1 added local initCenterY={22,22,22,22,22,22.5,21.5}--1 added local CCblockID={4,3,5,6,1,2,0} local scs=require("parts/spinCenters") local kickList=require("parts/kickList") local finesseCtrlPar={ [1]={ {1,2,1,0,1,2,2,1}, {2,2,3,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 }--SZI逆态视为顺态 finesseCtrlPar[2]=finesseCtrlPar[1]--SZ算法相同 finesseCtrlPar[4]=finesseCtrlPar[3]--JLT算法相同 finesseCtrlPar[5]=finesseCtrlPar[3]--JLT算法相同 local CCblockID={4,3,5,6,1,2,0} local freshMethod={ none=NULL, bag7=function(P) if #P.next<6 then local bag={1,2,3,4,5,6,7} ::L::P:getNext(rem(bag,rnd(#bag))) if bag[1]then goto L end end end, his4=function(P) if #P.next<6 then local j,i=0 repeat i,j=rnd(7),j+1 until i~=P.his[1]and i~=P.his[2]and i~=P.his[3]and i~=P.his[4] P:getNext(i) rem(P.his,1)P.his[4]=i end end, rnd=function(P) ::L::local i=rnd(7) if i==P.next[5].id then goto L end P:getNext(i) end,--random drought1=function(P) if #P.next<6 then local bag={1,2,3,4,5,6} ::L::P:getNext(rem(bag,rnd(#bag))) if bag[1]then goto L end end end, drought2=function(P) if #P.next<6 then local bag={1,1,1,1,2,2,2,2,6,6,6,6,3,3,4,4,5,7} ::L::P:getNext(rem(bag,rnd(#bag))) if bag[1]then goto L end end end, } ------------------------------------------------- --------------------------------------------------- local frameColor={ [0]=color.white, color.lightGreen, color.lightBlue, color.lightPurple, color.lightOrange, } local attackColor={ {color.darkGrey,color.white}, {color.grey,color.white}, {color.lightPurple,color.white}, {color.lightRed,color.white}, {color.darkGreen,color.cyan}, } local function drawPixel(y,x,id) gc.draw(blockSkin[id],30*x-30,600-30*y) end local function drawDial(x,y,speed) gc.setColor(1,1,1) mStr(int(speed),x,y-18) gc.draw(dialCircle,x,y,nil,nil,nil,32,32) gc.setColor(1,1,1,.6) gc.draw(dialNeedle,x,y,2.094+(speed<=175 and .02094*speed or 4.712-52.36/(speed-125)),nil,nil,5,4) end local function Pdraw_norm(P) gc.push("transform") gc.translate(P.x,P.y)gc.scale(P.size) --Camera gc.setColor(0,0,0,.6)gc.rectangle("fill",0,0,600,690) gc.setLineWidth(7)gc.setColor(frameColor[P.strength])gc.rectangle("line",0,0,600,690) --Boarder gc.translate(150+P.fieldOff.x,70+P.fieldOff.y) if P.gameEnv.grid then 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(P.fieldBeneath/30))+P.fieldBeneath gc.line(0,y,300,y) end end--Grid gc.translate(0,P.fieldBeneath) 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) if P.falling==-1 then 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)) drawPixel(j,i,P.field[j][i]) end end end else--field block only local dy,stepY=0,P.gameEnv.smooth and(P.falling/(P.gameEnv.fall+1))^2.5*30 or 30 local A=P.falling/P.gameEnv.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)) drawPixel(j,i,P.field[j][i]) end end end gc.translate(0,dy) end--Field with falling animation for i=1,#P.lockFX do local _=P.lockFX[i] if _[3]<.5 then gc.setColor(1,1,1,2*_[3]) gc.rectangle("fill",_[1],_[2],60*_[3],30) else gc.setColor(1,1,1,2-2*_[3]) gc.rectangle("fill",_[1]+30,_[2],60*_[3]-60,30) end end--lockFX for i=1,#P.dropFX do local _=P.dropFX[i] gc.setColor(1,1,1,_[1]*.12) for x=_[3],_[5]do for y=_[6],_[4]do drawPixel(y,x,_[2]) end end end--dropFX if P.waiting==-1 then if P.gameEnv.ghost then gc.setColor(1,1,1,.3) for i=1,P.r do for j=1,P.c do if P.cur.bk[i][j]then drawPixel(i+P.y_img-1,j+P.curX-1,P.cur.color) end end end end--Ghost -- local dy=setting.smooth and(P.y_img~=P.curY and or 1)^4*30 or 0 local dy if P.gameEnv.smooth then if P.y_img~=P.curY then dy=(min(P.dropDelay,1e99)/P.gameEnv.drop-1)*30 else dy=0 end --[[ if P.y_img~=P.curY then dy=(min(P.dropDelay,8e98)/P.gameEnv.drop)^4*30 else dy=(min(P.lockDelay,8e98)/P.gameEnv.lock)^(P.gameEnv._20G and 3 or 7)*30 end ]] else dy=0 end gc.translate(0,-dy) local trans=P.lockDelay/P.gameEnv.lock if P.gameEnv.block then gc.setColor(1,1,1,trans) for i=1,P.r do for j=1,P.c do if P.cur.bk[i][j]then gc.rectangle("fill",30*(j+P.curX-1)-33,597-30*(i+P.curY-1),36,36) end end end--White Boarder(indicate lockdelay) gc.setColor(1,1,1) for i=1,P.r do for j=1,P.c do if P.cur.bk[i][j]then drawPixel(i+P.curY-1,j+P.curX-1,P.cur.color) end end end--Block end if P.gameEnv.center then gc.setColor(1,1,1,trans) local x=30*(P.curX+P.sc[2]-1)-15 gc.draw(spinCenter,x,600-30*(P.curY+P.sc[1]-1)+15,nil,nil,nil,4,4) gc.translate(0,dy) gc.setColor(1,1,1,.5) gc.draw(spinCenter,x,600-30*(P.y_img+P.sc[1]-1)+15,nil,nil,nil,4,4) goto E end--Rotate center gc.translate(0,dy) end ::E:: gc.setScissor()--In-playField things gc.setColor(1,1,1) gc.draw(P.dust) gc.translate(0,-P.fieldBeneath) gc.setBlendMode("replace","alphamultiply")--SPEED UPUP(?) gc.setLineWidth(2) gc.rectangle("line",-1,-11,302,612)--Draw boarder gc.rectangle("line",301,0,15,601)--Draw atkBuffer boarder 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 if A.time<20 then bar=bar*(20*A.time)^.5*.05 --Appear end if A.countdown>0 then gc.setColor(attackColor[A.lv][1]) gc.rectangle("fill",303,599-h,11,-bar+3) gc.setColor(attackColor[A.lv][2]) gc.rectangle("fill",303,599-h+(-bar+3),11,-(-bar+3)*(1-A.countdown/A.cd0)) --Timing else 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+3) --Warning end else gc.setColor(attackColor[A.lv][1]) bar=bar*(20-A.time)*.05 gc.rectangle("fill",303,599-h,11,-bar+2) --Disappear end h=h+bar end--Buffer line 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.lightRed or color.lightBlue) 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 gc.rectangle("line",-16,-3,15,604)--Draw b2b bar boarder --B2B indictator gc.translate(-P.fieldOff.x,-P.fieldOff.y) gc.setBlendMode("alpha") if P.gameEnv.hold then mDraw(drawableText.hold,-81,-10) if P.holded then gc.setColor(.6,.5,.5)end local B=P.hd.bk for i=1,#B do for j=1,#B[1]do if B[i][j]then drawPixel(i+17.5-#B*.5,j-2.7-#B[1]*.5,P.hd.color) end end end end--Hold gc.setColor(1,1,1) mDraw(drawableText.next,381,-10) local N=1 ::L:: if N<=P.gameEnv.next and P.next[N]then 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 drawPixel(i+20-2.4*N-#b*.5,j+12.7-#b[1]*.5,c) end end end N=N+1 goto L end --Next gc.setColor(.8,.8,.8) gc.draw(drawableText.modeName,-135,-65) gc.draw(drawableText.levelName,437-drawableText.levelName:getWidth(),-65) gc.setColor(1,1,1) if frame<180 then local count=179-frame gc.push("transform") gc.translate(155,220) 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--Draw starting counter drawTexts(P.bonus)--Bonus texts setFont(25) drawDial(360,520,P.dropSpeed) drawDial(405,575,P.keySpeed) gc.setColor(1,1,1) mStr(format("%.2f",P.stat.time),-81,518)--Time mStr(P.score1,-81,560)--Score gc.draw(drawableText.bpm,390,490) gc.draw(drawableText.kpm,344,583) --Speed dials gc.setColor(1,1,1) curMode.mesDisp(P)--Other messages 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) gc.draw(royaleCtrlPad) end gc.pop() end local function Pdraw_small(P) P.frameWait=P.frameWait-1 if P.frameWait==0 then P.frameWait=8 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) 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--Field if P.alive then gc.setLineWidth(2) gc.setColor(frameColor[P.strength])gc.rectangle("line",1,1,58,118) end--Draw boarder if modeEnv.royaleMode then gc.setColor(1,1,1) for i=1,P.strength do gc.draw(badgeIcon,12*i-7,4,nil,.5) end end 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() --draw content end gc.setColor(1,1,1) gc.draw(P.canvas,P.x,P.y,nil,P.size*10) --draw Canvas 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) gc.push("transform") gc.translate(P.x,P.y)gc.scale(P.size)gc.translate(P.fieldOff.x,P.fieldOff.y) --Camera 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) --Frame if P.falling==-1 then 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)) drawPixel(j,i,P.field[j][i]) end end end else--field block only local dy,stepY=0,P.gameEnv.smooth and(P.falling/(P.gameEnv.fall+1))^2.5*30 or 30 local A=P.falling/P.gameEnv.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)) drawPixel(j,i,P.field[j][i]) end end end gc.translate(0,dy) end--Field with falling animation for i=1,#P.lockFX do local _=P.lockFX[i] if _[3]<.5 then gc.setColor(1,1,1,3*_[3]) gc.rectangle("fill",_[1],_[2],60*_[3],30) else gc.setColor(1,1,1,3-3*_[3]) gc.rectangle("fill",_[1]+30,_[2],60*_[3]-60,30) end end--lockFX for i=1,#P.dropFX do local S=P.dropFX[i] gc.setColor(1,1,1,S[1]*.12) for x=S[3],S[5]do for y=S[6],S[4]do drawPixel(y,x,S[2]) end end end--dropFX if P.waiting==-1 then gc.setColor(1,1,1,.3) for i=1,P.r do for j=1,P.c do if P.cur.bk[i][j]then drawPixel(i+P.y_img-1,j+P.curX-1,P.cur.color) end end end --Ghost draw gc.setColor(1,1,1) for i=1,P.r do for j=1,P.c do if P.cur.bk[i][j]then drawPixel(i+P.curY-1,j+P.curX-1,P.cur.color) end end end--Block end local id=P.hd.id if id>0 then local _=P.color[id] gc.setColor(_[1],_[2],_[3],.3) _=miniBlock[P.hd.id] gc.draw(_,15,30,nil,16,nil,0,_:getHeight()*.5) end local N=1 ::L:: if N<=P.gameEnv.next and P.next[N]then local id=P.next[N].id local _=P.color[id] gc.setColor(_[1],_[2],_[3],.3) _=miniBlock[id] gc.draw(_,285,40*N-10,nil,16,nil,_:getWidth(),_:getHeight()*.5) N=N+1 goto L end --Next gc.setColor(1,1,1) gc.draw(P.dust) gc.translate(-P.fieldOff.x,-P.fieldOff.y) drawTexts(P.bonus) gc.pop() 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 for i=#P.lockFX,1,-1 do local _=P.lockFX[i] _[3]=_[3]+_[4] if _[3]>1 then rem(P.lockFX,i) end end--lockFX for i=#P.dropFX,1,-1 do local S=P.dropFX[i] S[1]=S[1]-1+P.gameEnv.dropFX*.15 if S[1]<=0 then rem(P.dropFX,i) end end--dropFX 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--field shaking if P.bonus then updateText(P.bonus) end for i=#P.atkBuffer,1,-1 do local A=P.atkBuffer[i] A.time=A.time+1 if not A.sent then if A.countdown>0 then A.countdown=max(A.countdown-garbageSpeed,0) end else if A.time>20 then rem(P.atkBuffer,i) end end end if P.fieldBeneath>0 then P.fieldBeneath=max(P.fieldBeneath-P.gameEnv.pushSpeed,0)end if not P.small then P.dust:update(dt) end end local function Pupdate_alive(P,dt) if P.timing then P.stat.time=P.stat.time+dt end if P.keyRec then local _=frame local v=0 for i=2,10 do v=v+i*(i-1)*7.2/(_-P.keyTime[i])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 --Update speeds 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=AI_think[P.AI_mode][P.AI_stage](P,C) elseif P.AI_delay<=0 then P:pressKey(C[1])P:releaseKey(C[1]) local k=#C for i=1,k do C[i]=C[i+1]end--table.remove(C,1) P.AI_delay=P.AI_delay0*2 end end 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--Fresh visible time if P.moving<0 then if P.keyPressing[1]then local flag=false local moving=-P.moving-1--remove sign mark if movingP.gameEnv.das+P.gameEnv.arr then moving=P.gameEnv.das flag=true end end if flag then local x=P.curX if P.gameEnv.arr==0 then P.act.insLeft(P,true) else P.act.moveLeft(P,true) end end if P.gameEnv.shakeFX and P:ifoverlap(P.cur.bk,P.curX-1,P.curY)then P.fieldOff.vx=-P.gameEnv.shakeFX*.5 end P.moving=-moving-1 else P.moving=0 end elseif P.moving>0 then if P.keyPressing[2]then local flag=false local moving=P.moving-1--remove sign mark if movingP.gameEnv.das+P.gameEnv.arr then moving=P.gameEnv.das flag=true end end if flag then local x=P.curX if P.gameEnv.arr==0 then P.act.insRight(P,true) else P.act.moveRight(P,true) end end if P.gameEnv.shakeFX and P:ifoverlap(P.cur.bk,P.curX+1,P.curY)then P.fieldOff.vx=P.gameEnv.shakeFX*.5 end P.moving=moving+1 else P.moving=0 end end if P.keyPressing[7]and not P.keyPressing[9]then local d=P.downing-P.gameEnv.sddas P.downing=P.downing+1 if d>1 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 if P.falling>=0 then P.falling=P.falling-1 if P.falling>=0 then goto stop else local L=#P.clearingRow if P.human and P.gameEnv.fall>0 and #P.field+L>P.clearingRow[L]then SFX.play("fall")end P.clearingRow={} end end if not P.control then goto stop end if P.waiting==0 then P:freshNext()end if P.waiting>=0 then P.waiting=P.waiting-1 goto stop end if P.curY~=P.y_img then local D=P.dropDelay if D>1 then P.dropDelay=D-1 goto stop end if D==1 then P.curY=P.curY-1 else local _=P.curY-P.y_img--max fall dist D=1/D--fall dist if D<_ then P.curY=P.curY-D assert(P.curY==int(P.curY),"y:"..P.curY.." fall:"..D.." D_env:"..P.gameEnv.drop) else P.curY=P.y_img end end P.spinLast=false if P.y_img~=P.curY then P.dropDelay=P.gameEnv.drop elseif P.AI_mode=="CC"then P.AI_needFresh=true if not P.AIdata._20G and P.gameEnv.drop=0 then goto stop end P:drop() if P.AI_mode=="CC"then P.AI_needFresh=true end end ::stop:: if P.b2b1==P.b2b then elseif P.b2b1=0 then P.falling=P.falling-1 if P.falling>=0 then goto stop else local L=#P.clearingRow if P.human and P.gameEnv.fall>0 and #P.field+L>P.clearingRow[L]then SFX.play("fall")end P.clearingRow={} end end::stop:: if P.endCounter<40 then for j=1,#P.field do for i=1,10 do if P.visTime[j][i]<20 then P.visTime[j][i]=P.visTime[j][i]+.5 end end end--Make field visible end if P.b2b1>0 then P.b2b1=max(0,P.b2b1*.92-1)end updateFXs(P,dt) end -------------------------------------------------- player={}local player=player -------------------------------------------------------- local textFX=textFX function player.showText(P,text,dx,dy,font,style,spd,stop) if P.bonus then P.bonus[#P.bonus+1]=getTEXT(text,150+dx,300+dy,font*P.size,style,spd,stop) end end local function without(L,e) for i=1,#L do if L[i]==e then return end end return true end function player.createLockFX(P) local BK=P.cur.bk local t=.1-P.gameEnv.lockFX*.02 for i=1,P.r do local y=P.curY+i-1 if without(P.clearedRow,y)then for j=1,P.c do if BK[i][j]then ins(P.lockFX,{30*(P.curX+j-2),600-30*y,0,t}) end end end end end function player.createShade(P,x1,y1,x2,y2)--x1y2! if P.gameEnv.block and y1>=y2 then P.dropFX[#P.dropFX+1]={5,P.cur.color,x1,y1,x2,y2} end end function player.createBeam(P,R,send,time,target,color,clear,spin,mini,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]-1)-30+15+150)*P.size,P.y+(600-30*(P.curY+P.sc[1]-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>10 then radius=10+3*send+100/(target+4) local t=clear%10 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 FX_attack[#FX_attack+1]={ x=x1,y=y1,--current pos x1=x1,y1=y1,--start pos x2=x2,y2=y2,--end pos rad=radius*(setting.atkFX+3)*.12, corner=corner, type=type==1 and"fill"or"line", r=r,g=g,b=b,a=a*(setting.atkFX+5)*.1, t=0, drag={},--Afterimage coordinate list } end -------------------------------------------------- -------------------------------------------------- local function 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 end local function getBlockPosition(P)--for stereo sfx return(P.curX+P.sc[2]-6.5)*.15 end local OspinList={ {111,5,2, 0,-1,false},--T {111,5,2,-1,-1,false},--T {111,5,0,-1, 0,false},--T {333,5,2,-1,-1,false},--T {333,5,2, 0,-1,false},--T {333,5,0, 0, 0,false},--T {313,1,2,-1, 0,false},--Z {313,1,2, 0,-1,false},--Z {313,1,2, 0, 0,false},--Z {131,2,2, 0, 0,false},--S {131,2,2,-1,-1,false},--S {131,2,2,-1, 0,false},--S {113,3,2,-1,-1,false},--L {331,3,0,-1, 0,false},--L {331,4,2, 0,-1,false},--J {113,4,0, 0, 0,false},--J {222,7,2,-1, 0, true},--I {222,7,2,-2, 0, true},--I {222,7,2, 0, 0, true},--I }--key,type,dir,dx,dy,ifFix 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.fineError(P,rate) P.stat.extraPiece=P.stat.extraPiece+1 P.stat.extraRate=P.stat.extraRate+rate if P.human then if P.gameEnv.fineKill then SFX.play("finesseError_long") P:lose() elseif setting.fine then SFX.play("finesseError") end elseif P.gameEnv.fineKill then P:lose() end end function player.garbageSend(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 B.sum+send>20 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=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.human 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 ::L:: 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 goto E end goto L ::E:: if flag and P.AI_mode=="CC"then CC_updateField(P)end end function player.garbageRise(P,color,amount,pos) 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 P.curY=P.curY+amount P:freshgho() for i=1,#P.clearingRow do P.clearingRow[i]=P.clearingRow[i]+amount end for i=1,#P.lockFX do local _=P.lockFX[i] _[2]=_[2]-30*amount--calculated pos!Must *=-30 end for i=1,#P.dropFX do local _=P.dropFX[i] _[4],_[6]=_[4]+amount,_[6]+amount end if #P.field>40 then P:lose()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~=mostBadge and mostBadge or secBadge or randomTarget(P)) elseif P.atkMode==3 then P:changeAtk(P~=mostDangerous and mostDangerous or 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 R.atker[#R.atker+1]=P else P.atking=nil end end function player.freshgho(P) P.y_img=min(#P.field+1,P.curY) if P.gameEnv._20G or P.keyPressing[7]and P.gameEnv.sdarr==0 then while not P:ifoverlap(P.cur.bk,P.curX,P.y_img-1)do P.y_img=P.y_img-1 P.spinLast=false end if P.curY>P.y_img then if P.gameEnv.dropFX then P:createShade(P.curX,P.curY+1,P.curX+P.c-1,P.y_img+P.r-1) end if P.gameEnv.shakeFX then P.fieldOff.vy=P.gameEnv.shakeFX*.5 end P.curY=P.y_img end else while not P:ifoverlap(P.cur.bk,P.curX,P.y_img-1)do P.y_img=P.y_img-1 end end end function player.freshLockDelay(P) if P.lockDelay100 then for i=1,#OspinList do local L=OspinList[i] if D==L[1]then local id,dir=L[2],L[3] local bk=blocks[id][dir] local x,y=P.curX+L[4],P.curY+L[5] if not P:ifoverlap(bk,x,y)and P:ifoverlap(bk,x,y+1)and(L[6]or P:ifoverlap(bk,x-1,y)and P:ifoverlap(bk,x+1,y))then local C=P.cur C.id=id C.bk=bk P.curX,P.curY=x,y P.r,P.c=#bk,#bk[1] P.dir,P.sc=dir,scs[id][dir] P.spinLast=2 P.stat.rotate=P.stat.rotate+1 P:freshgho() SFX.play("rotatekick",nil,getBlockPosition(P)) return end end end end else P.spinSeq=0 end end return end 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] local t--succssful test local iki=P.RS[P.cur.id][P.dir*10+idir] for i=1,P.freshTime<=1.2*P.gameEnv.freshLimit and #iki or 1 do local x,y=ix+iki[i][1],iy+iki[i][2] if not P:ifoverlap(icb,x,y)then ix=x;iy=y;t=i goto spin end end do return end ::spin:: if P.gameEnv.dropFX then P:createShade(P.curX,P.curY+P.r-1,P.curX+P.c-1,P.curY) end local y0=P.curY 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=t==2 and 0 or 1 if not ifpre then P:freshgho()end if P.gameEnv.easyFresh or y0>P.curY then P:freshLockDelay()end if P.human then SFX.play(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,getBlockPosition(P)) end P.stat.rotate=P.stat.rotate+1 end function player.resetBlock(P) local id=P.cur.id local face=P.gameEnv.face[id] local sc=scs[id][face] P.sc=sc --spin center P.dir=face --block direction P.r,P.c=#P.cur.bk,#P.cur.bk[1] --row/column P.curX=initCenterX[id]-sc[2] P.curY=initCenterY[id]-sc[1]+ceil(P.fieldBeneath/30) if abs(P.moving)>P.gameEnv.das and not P:ifoverlap(P.cur.bk,P.curX+(P.moving>0 and 1 or -1),P.curY)then P.curX=P.curX+(P.moving>0 and 1 or -1) end --IMS end function player.hold(P,ifpre) if not P.holded and (ifpre or P.waiting==-1) and P.gameEnv.hold then --Finesse check local H,B=P.hd,P.cur if H and H.id==B.id and H.name==B.name then P:fineError(1.5) elseif P.ctrlCount>1 then P:fineError(2) end P.holded=P.gameEnv.oncehold P.spinLast=false P.ctrlCount=0 P.spinSeq=0 P.cur,P.hd=P.hd,P.cur local hid=P.hd.id P.hd.bk=blocks[hid][P.gameEnv.face[hid]] if P.cur.id==0 then P.cur=rem(P.next,1) P:newNext() if P.AI_mode=="CC"then BOT.addNext(P.AI_bot,CCblockID[P.next[P.AIdata.next].id])end end P:resetBlock() P:freshgho() P.dropDelay,P.lockDelay,P.freshTime=P.gameEnv.drop,P.gameEnv.lock,max(P.freshTime-5,0) if P:ifoverlap(P.cur.bk,P.curX,P.curY)then P:lock()P:lose()end if P.human then SFX.play(ifpre and"prehold"or"hold") end P.stat.hold=P.stat.hold+1 end end function player.getNext(P,n) P.next[#P.next+1]={bk=blocks[n][P.gameEnv.face[n]],id=n,color=P.gameEnv.bone and 12 or P.gameEnv.skin[n],name=n} end --function player.newNext()--check/add new next to next queue,defined when create player function player.freshNext(P) P.holded=false P.spinLast=false P.spinSeq=0 P.ctrlCount=0 P.cur=rem(P.next,1) P:newNext() if P.AI_mode=="CC"then BOT.addNext(P.AI_bot,CCblockID[P.next[P.AIdata.next].id])end local _=P.keyPressing if P.gameEnv.hold and _[8]then P:hold(true) else P:resetBlock() end --IHS P.dropDelay,P.lockDelay,P.freshTime=P.gameEnv.drop,P.gameEnv.lock,0 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 --IRS if P:ifoverlap(P.cur.bk,P.curX,P.curY)then P:lock()P:lose()end P:freshgho() if _[6]then P.act.hardDrop(P)_[6]=false end --IHdS end function player.drop(P)--Place piece local _ local CHN=getFreeVoiceChannel() P.dropTime[11]=ins(P.dropTime,1,frame)--update speed dial local cmb=P.combo P.waiting=P.gameEnv.wait local send,exblock=0,0--Send&Send Time local cscore,sendTime=0,0 local dospin=0 local mini --spin判定 if P.spinLast then if P.cur.id<6 then local x,y=P.curX+P.sc[2]-1,P.curY+P.sc[1]-1 local c=0 if solid(P,x-1,y+1)then c=c+1 end if solid(P,x+1,y+1)then c=c+1 end if c==0 then goto NTC end if solid(P,x-1,y-1)then c=c+1 end if solid(P,x+1,y-1)then c=c+1 end if c>2 then dospin=dospin+1 end end--三角 ::NTC:: if P.cur.id~=6 and P:ifoverlap(P.cur.bk,P.curX-1,P.curY)and P:ifoverlap(P.cur.bk,P.curX+1,P.curY)and P:ifoverlap(P.cur.bk,P.curX,P.curY+1)then dospin=dospin+2 end--卡块 end --锁定 P:lock() --清空消行列表 if P.clearedRow[1]then P.clearedRow={}end --消行 local cc=0 for i=0,P.r-1 do local h=P.curY+i if P:ckfull(h)then cc=cc+1 P.clearingRow[cc]=h-cc+1 P.clearedRow[cc]=h if not P.small then local S=P.dust for _=1,100 do S:setPosition(rnd(300),600-30*h+rnd(30)) S:emit(2) end end end end _=#P.clearingRow ::L::if _>0 and P.clearingRow[_]>#P.field then P.clearingRow[_]=nil _=_-1 goto L end if P.clearingRow[1]then P.falling=P.gameEnv.fall end --处理锁定特效 if P.gameEnv.lockFX then if cc==0 then P:createLockFX() elseif P.lockFX[1]then P.lockFX={} end end --spin结算 if P.spinLast then if cc>0 then if dospin>0 then dospin=dospin+P.spinLast if dospin<2 then mini=P.cur.id<6 and cc<3 and cc2 then dir=dir-2 end end--SZI的逆态视为顺态 local R,I=P.ctrlCount,finesseCtrlPar[id][dir][P.curX]--Real key/Ideal key local d=R-I if d>0 then if I==0 then I=1 end local rate=R/I if rate>2.5 then rate=2.5 end P:fineError(rate) --非最简 end end if cc>0 then cmb=cmb+1 if cc==4 then cscore=1000 if P.b2b>1000 then P:showText(text.techrashB3B,0,-30,50,"fly") send=6 sendTime=100 exblock=exblock+1 cscore=cscore*1.8 P.stat.b3b=P.stat.b3b+1 if P.human then VOICE("b3b",CHN) end elseif P.b2b>=50 then P:showText(text.techrashB2B,0,-30,50,"drive") sendTime=80 send=5 cscore=cscore*1.3 P.stat.b2b=P.stat.b2b+1 if P.human then VOICE("b2b",CHN) end else P:showText(text.techrash,0,-30,70,"stretch") sendTime=60 send=4 end P.b2b=P.b2b+120 P.lastClear=74 P.stat.clear_4=P.stat.clear_4+1 if P.human then VOICE("techrash",CHN) end elseif cc>0 then local clearKey=clear_n if dospin then cscore=spinSCR[P.cur.name][cc] if P.b2b>1000 then P:showText(text.b3b..text.spin[P.cur.name]..text.clear[cc],0,-30,35,"spin") send=b2bATK[cc]+.5*cc exblock=exblock+1 cscore=cscore*2 P.stat.b3b=P.stat.b3b+1 if P.human then VOICE("b3b",CHN) end elseif P.b2b>=50 then P:showText(text.b2b..text.spin[P.cur.name]..text.clear[cc],0,-30,35,"spin") send=b2bATK[cc] cscore=cscore*1.2 P.stat.b2b=P.stat.b2b+1 if P.human then VOICE("b2b",CHN) end else P:showText(text.spin[P.cur.name]..text.clear[cc],0,-30,45,"spin") send=2*cc end sendTime=20+send*20 if mini then P:showText(text.mini,0,-80,35,"appear") send=send*.5 sendTime=sendTime+60 cscore=cscore*.6 P.b2b=P.b2b+b2bPoint[cc]*.5 if P.human then VOICE("mini",CHN) end else P.b2b=P.b2b+b2bPoint[cc] end P.lastClear=P.cur.id*10+cc clearKey=spin_n if P.human then SFX.play(spin_n[cc]) VOICE(spinName[P.cur.name],CHN) end elseif #P.field>0 then P.b2b=max(P.b2b-250,0) P:showText(text.clear[cc],0,-30,27+cc*3,"appear",(8-cc)*.3) send=cc-.75 sendTime=20+send*20 cscore=cscore+clearSCR[cc] P.lastClear=cc end P.stat[clearKey[cc]]=P.stat[clearKey[cc]]+1 if P.human then VOICE(clearName[cc],CHN) end end sendTime=sendTime+25*cmb if cmb>2 then send=send+(comboAtk[cmb]or 2) P:showText(text.cmb[min(cmb,20)],0,25,15+min(cmb,25)*3,cmb<10 and"appear"or"flicker") cscore=cscore+min(20*cmb,300)*cc end if #P.field==0 then P:showText(text.PC,0,-80,50,"flicker") send=send^.5+min(6+P.stat.pc,10) exblock=exblock+2 sendTime=sendTime+60 if P.stat.row+cc>4 then P.b2b=1200 cscore=cscore+300*min(6+P.stat.pc,10) else cscore=cscore+626 end P.stat.pc=P.stat.pc+1 P.lastClear=P.cur.id*10+5 if P.human then SFX.play("perfectclear") VOICE("pc",CHN) end end if P.human 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 if P.b2b>1200 then P.b2b=1200 end if modeEnv.royaleMode then local i=min(#P.atker,9) if i>1 then send=send+reAtk[i] exblock=exblock+reDef[i] end end--Bonus atk/def when focused if send>0 then P.stat.atk=P.stat.atk+int(send) --ATK statistics if exblock then exblock=int(exblock*(1+P.strength*.25))end send=int(send*(1+P.strength*.25)) --Badge Buff if send==0 then goto L end P:showText(send,0,80,35,"zoomout") if exblock==0 then goto L end P:showText(exblock,0,120,20,"zoomout") ::L:: send=send+exblock local k=0 ::R:: if P.atkBuffer.sum>0 and send>0 then ::F:: k=k+1 local A=P.atkBuffer[k] if not A then goto E end if A.sent then goto F end if send>=A.amount then send=send-A.amount P.atkBuffer.sum=P.atkBuffer.sum-A.amount A.sent,A.time=true,0 if send>0 then goto R end else A.amount=A.amount-send P.atkBuffer.sum=P.atkBuffer.sum-send send=0 end end ::E:: send=send-exblock 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:garbageSend(P.atker[i],send,sendTime,M,P.cur.color,P.lastClear,dospin,mini,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:garbageSend(T,send,sendTime,1,P.cur.color,P.lastClear,dospin,mini,cmb) end P.stat.send=P.stat.send+send if P.human and send>3 then SFX.play("emit",min(send,8)*.1)end end end else cmb=0 local dropScore=10 if dospin then P:showText(text.spin[P.cur.name],0,-30,45,"appear") P.b2b=P.b2b+20 P.stat.spin_0=P.stat.spin_0+1 if P.human then SFX.play("spin_0") VOICE(spinName[P.cur.name],CHN) end dropScore=25--spin bonus end if P.gameEnv._20G then dropScore=dropScore*2 elseif P.gameEnv.drop<3 then dropScore=dropScore*1.5 end--dropSpeed bonus if P.dropSpeed>60 then dropScore=dropScore*P.dropSpeed/60 elseif P.dropSpeed>120 then dropScore=dropScore*1,2*P.dropSpeed/120 elseif P.dropSpeed>180 then dropScore=dropScore*1.5*P.dropSpeed/180 end--speed bonus cscore=cscore+dropScore if P.b2b>1000 then P.b2b=max(P.b2b-40,1000) end P:garbageRelease() end P.combo=cmb P.stat.score=P.stat.score+int(cscore) P.stat.piece,P.stat.row=P.stat.piece+1,P.stat.row+cc _=P.gameEnv.dropPiece if _ then _(P)end if P.human then SFX.play("lock",nil,getBlockPosition(P))end end function player.pressKey(P,i) P.keyPressing[i]=true P.act[actName[i]](P) if P.control then if P.keyRec then ins(P.keyTime,1,frame) P.keyTime[11]=nil end P.stat.key=P.stat.key+1 end --ins(rec,{i,frame}) end function player.releaseKey(P,i) if P.keyPressing[i]then P.keyPressing[i]=false -- if recording then ins(rec,{-i,frame})end end end -------------------------------------------------- ---------------------------------------------------- local function gameOver() 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.id]--old rank if R>r then modeRanks[M.id]=R if r==0 then for i=1,#M.unlock do local m=M.unlock[i] if not modeRanks[m]then modeRanks[m]=modes[m].score and 0 or 6 end end end saveUnlock() end local D=M.score(P) local L=M.records local p=#L--排名数-1 if p>0 then ::L:: if M.comp(D,L[p])then--是否靠前 p=p-1 if p>0 then goto L end end end if p<10 then if p==0 then P:showText(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 saveRecord(M.saveFileName,L) end end end end--Save record function player.die(P)--Same thing 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 clearTask(P) 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.reach_winCheck(P) if P.stat.row>=P.gameEnv.target then P:win("finish") 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 gameResult=result or"win" SFX.play("win") VOICE("win") if modeEnv.royaleMode then BGM.play("8-bit happiness") end end newTask(Event_task.finish,P) if curMode.id=="custom_puzzle"then P:showText(text.win,0,0,90,"beat",.4) else P:showText(text.win,0,0,90,"beat",.5,.2) end if P.human then gameOver() end end function player.lose(P) if P.invincible 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 P.AI_needFresh=true end 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:showText(P.modeData.event,0,-120,60,"appear",1,12) 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 end end P.lastRecv=A if P.id==1 or A.id==1 then newTask(Event_task.throwBadge,A,{P,max(3,P.badge)*4}) end freshMostBadge() end else P.badge=-1 end freshMostDangerous() for i=1,#players.alive do if players.alive[i].atking==P then players.alive[i]:freshTarget() end end if #players.alive==royaleData.stage[gameStage]then royaleLevelup() end end P.gameEnv.keepVisible=P.gameEnv.visible~="show" P:showText(text.lose,0,0,90,"appear",.5,.2) if P.human then gameResult="lose" SFX.play("fail") VOICE("lose") if modeEnv.royaleMode then BGM.play("end")end end if #players.alive==1 then players.alive[1]:win() end if #players==1 or(P.human and not players[2].human)then gameOver() end newTask(#players>1 and Event_task.lose or Event_task.finish,P) end -------------------------<\Events>-------------------------- -------------------------------------------------- player.act={} function player.act.moveLeft(P,auto) if not auto then P.ctrlCount=P.ctrlCount+1 end if P.keyPressing[9]then if P.gameEnv.swap then P:changeAtkMode(1) end elseif P.control and P.waiting==-1 then if not P:ifoverlap(P.cur.bk,P.curX-1,P.curY)then P.curX=P.curX-1 local y0=P.curY P:freshgho() if P.gameEnv.easyFresh or y0~=P.curY then P:freshLockDelay()end if P.human and P.curY==P.y_img then SFX.play("move")end P.spinLast=false if not auto then P.moving=-1 end else P.moving=-P.gameEnv.das-1 end else P.moving=-1 end end function player.act.moveRight(P,auto) if not auto then P.ctrlCount=P.ctrlCount+1 end if P.keyPressing[9]then if P.gameEnv.swap then P:changeAtkMode(2) end elseif P.control and P.waiting==-1 then if not P:ifoverlap(P.cur.bk,P.curX+1,P.curY)then P.curX=P.curX+1 local y0=P.curY P:freshgho() if P.gameEnv.easyFresh or y0~=P.curY then P:freshLockDelay()end if P.human and P.curY==P.y_img then SFX.play("move")end P.spinLast=false if not auto then P.moving=1 end else P.moving=P.gameEnv.das+1 end else P.moving=1 end end function player.act.rotRight(P) if P.control and P.waiting==-1 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 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 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 then if P.curY~=P.y_img then if P.gameEnv.dropFX then P:createShade(P.curX,P.curY+1,P.curX+P.c-1,P.y_img+P.r-1) end P.curY=P.y_img P.spinLast=false if P.gameEnv.shakeFX then P.fieldOff.vy=P.gameEnv.shakeFX*.6 end if P.human then SFX.play("drop",nil,getBlockPosition(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 then if P.curY~=P.y_img then P.curY=P.curY-1 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 P.gameEnv.quickR or frame<180 then clearTask("play") resetPartGameData() end end function player.act.insLeft(P,auto) if P.gameEnv.nofly then return end local x0,y0=P.curX,P.curY while not P:ifoverlap(P.cur.bk,P.curX-1,P.curY)do P.curX=P.curX-1 if P.gameEnv.dropFX then P:createShade(P.curX+P.c,P.curY+P.r-1,P.curX+P.c,P.curY) end P:freshgho() end if x0~=P.curX then if P.gameEnv.easyFresh or y0~=P.curY then P:freshLockDelay()end 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 P.gameEnv.nofly then return end local x0,y0=P.curX,P.curY while not P:ifoverlap(P.cur.bk,P.curX+1,P.curY)do P.curX=P.curX+1 if P.gameEnv.dropFX then P:createShade(P.curX-1,P.curY+P.r-1,P.curX-1,P.curY) end P:freshgho() end if x0~=P.curX then if P.gameEnv.easyFresh or y0~=P.curY then P:freshLockDelay()end 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.curY~=P.y_img then if P.gameEnv.dropFX then P:createShade(P.curX,P.curY+1,P.curX+P.c-1,P.y_img+P.r-1) end if P.gameEnv.shakeFX then P.fieldOff.vy=P.gameEnv.shakeFX*.5 end P.curY,P.lockDelay,P.spinLast=P.y_img,P.gameEnv.lock,false end end function player.act.down1(P) if P.curY~=P.y_img then P.curY=P.curY-1 P.spinLast=false end end function player.act.down4(P) for _=1,4 do if P.curY~=P.y_img then P.curY=P.curY-1 P.spinLast=false else break end end end function player.act.down10(P) for _=1,10 do if P.curY~=P.y_img then P.curY=P.curY-1 P.spinLast=false else break end end end function player.act.dropLeft(P) if P.gameEnv.nofly then return end P.act.insLeft(P) P.act.hardDrop(P) end function player.act.dropRight(P) if P.gameEnv.nofly then return end P.act.insRight(P) P.act.hardDrop(P) end function player.act.addLeft(P) if P.gameEnv.nofly then return end P.act.insLeft(P) P.act.insDown(P) P.act.insRight(P) P.act.hardDrop(P) end function player.act.addRight(P) if P.gameEnv.nofly then return end P.act.insRight(P) P.act.insDown(P) P.act.insLeft(P) P.act.hardDrop(P) end -------------------------------------------------- function newDemoPlayer(id,x,y,size) local P={id=id}players[id]=P P.invincible=true for k,v in next,player do P[k]=v end players.alive[#players.alive+1]=P P.x,P.y,P.size=x,y,size P.fieldOff={x=0,y=0,vx=0,vy=0} P.small,P.keyRec=false,false P.draw=Pdraw_demo P.update=Pupdate_alive 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.alive=true P.control=true P.timing=false P.stat={ time=0,score=0, key=0,extraPiece=0,extraRate=0, rotate=0,hold=0,piece=0,row=0, atk=0,send=0,recv=0,pend=0, clear_1=0,clear_2=0,clear_3=0,clear_4=0, spin_0=0,spin_1=0,spin_2=0,spin_3=0, pc=0,b2b=0,b3b=0, } P.modeData={point=0,event=0,counter=0} P.keyTime={}P.keySpeed=0 P.dropTime={}P.dropSpeed=0 P.atker={}P.strength=0 P.field,P.visTime={},{} P.atkBuffer={sum=0} P.gameEnv={ noFly=false, das=10,arr=2, sddas=2,sdarr=2, quickR=true,swap=true, ghost=setting.ghost,center=setting.center, smooth=setting.smooth,grid=setting.grid, lockFX=setting.lockFX,dropFX=setting.dropFX, shakeFX=setting.shakeFX, _20G=false,bone=false, drop=1e99,lock=1e99, wait=10,fall=20, next=6,hold=true, oncehold=true, ospin=true, sequence="bag7", face={0,0,0,0,0,0,0}, skin={1,5,2,8,10,3,7}, pushSpeed=3, block=true, visible="show", Fkey=nil,puzzle=false, freshLimit=1e99,easyFresh=true, fine=false,fineKill=false, target=1e99,dropPiece=NULL, mindas=0,minarr=0,minsdarr=0, } local ENV=P.gameEnv if ENV.lockFX==0 then ENV.lockFX=nil end if ENV.dropFX==0 then ENV.dropFX=nil end if ENV.shakeFX==0 then ENV.shakeFX=nil end P.color={} for _=1,7 do P.color[_]=skin.libColor[ENV.skin[_]] end P.cur={bk={{}},id=0,color=0,name=0} P.sc,P.dir,P.r,P.c={0,0},0,0,0 P.curX,P.curY,P.y_img=0,0,0 P.hd={bk={{}},id=0,color=0,name=0} P.holded=false P.next={} P.dropDelay,P.lockDelay=1e99,1e99 P.freshTime=0 P.spinLast,P.lastClear=false,nil P.spinSeq=0 P.ctrlCount=0 local bag1={1,2,3,4,5,6,7} for _=1,7 do P:getNext(rem(bag1,rnd(#bag1))) end P.newNext=freshMethod.bag7 if ENV.sequence==1 then P.bag={} elseif ENV.sequence==2 then P.his={}for i=1,4 do P.his[i]=P.next.id[i+3]end elseif ENV.sequence==3 then end P.human=false P.AI_mode="CC" P.AI_stage=1 P.AI_needFresh=false P.AI_keys={} P.AI_delay,P.AI_delay0=3,3 P.AIdata={next=5,hold=true,_20G=false,bag7=true,node=80000} if not BOT then P.AI_mode="9S"end if P.AI_mode=="CC"then P.RS=kickList.AIRS local opt,wei=BOT.getConf() BOT.setHold(opt,P.AIdata.hold) BOT.set20G(opt,P.AIdata._20G) BOT.setBag(opt,P.AIdata.bag7) BOT.setNode(opt,P.AIdata.node) P.AI_bot=BOT.new(opt,wei) BOT.free(opt)BOT.free(wei) local CCBID={4,3,5,6,1,2,0} for i=1,5 do BOT.addNext(P.AI_bot,CCBID[P.next[i].id]) end elseif P.AI_mode=="9S"then P.RS=kickList.TRS end P.showTime=1e99 P.keepVisible=true P.keyPressing={}for i=1,12 do P.keyPressing[i]=false end P.moving,P.downing=0,0 P.waiting,P.falling=-1,-1 P.clearingRow,P.clearedRow={},{} P.combo,P.b2b=0,0 P.fieldBeneath=0 P.score1,P.b2b1=0,0 P.dropFX,P.lockFX={},{} P.bonus={} P.dust=clearDust:clone() P.dust:start() P:freshNext() end function newPlayer(id,x,y,size,AIdata) players[id]={id=id} local P=players[id] for k,v in next,player do P[k]=v end--inherit functions of player class players.alive[#players.alive+1]=P P.x,P.y,P.size=x,y,size or 1 P.fieldOff={x=0,y=0,vx=0,vy=0}--for shake FX 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.dust=clearDust:clone() P.dust:start() P.bonus={}--texts end P.update=Pupdate_alive P.alive=true P.control=false P.timing=false P.stat={ time=0,score=0, key=0,extraPiece=0,extraRate=0, rotate=0,hold=0,piece=0,row=0, atk=0,send=0,recv=0,pend=0, clear_1=0,clear_2=0,clear_3=0,clear_4=0, spin_0=0,spin_1=0,spin_2=0,spin_3=0, pc=0,b2b=0,b3b=0, }--Current gamestat P.modeData={point=0,event=0,counter=0}--data use by mode P.keyTime={}for i=1,10 do P.keyTime[i]=-1e5 end P.keySpeed=0 P.dropTime={}for i=1,10 do P.dropTime[i]=-1e5 end P.dropSpeed=0 P.field,P.visTime={},{} P.atkBuffer={sum=0} P.badge,P.strength=0,0 P.atkMode,P.swappingAtkMode=1,20 P.atker,P.atking,P.lastRecv={} --Royale-related P.gameEnv={}--Current game setting environment local ENV=P.gameEnv for k,v in next,gameEnv0 do if modeEnv[k]~=nil then v=modeEnv[k] elseif setting[k]~=nil then v=setting[k] end ENV[k]=v end--load game settings ENV.das=max(ENV.das,ENV.mindas) ENV.arr=max(ENV.arr,ENV.minarr) ENV.sdarr=max(ENV.sdarr,ENV.minsdarr) P.cur={bk={{}},id=0,color=0,name=0}--shape,shapeID,colorID,nameID P.sc,P.dir,P.r,P.c={0,0},0,0,0--spinCenter,direction,row,col P.curX,P.curY,P.y_img=0,0,0--x,y,ghostY P.hd={bk={{}},id=0,color=0,name=0} P.holded=false P.next={} P.dropDelay,P.lockDelay=ENV.drop,ENV.lock P.freshTime=0 P.spinLast,P.lastClear=false,nil P.spinSeq=0--for Ospin,each digit mean a spin P.ctrlCount=0--key press time,for finesse check P.his={rnd(7),rnd(7),rnd(7),rnd(7)} local s=ENV.sequence if s=="bag7"or s=="his4"then local bag1={1,2,3,4,5,6,7} for _=1,7 do P:getNext(rem(bag1,rnd(#bag1))) end elseif s=="rnd"then for _=1,6 do local r=rnd(7) P:getNext(r) end elseif s=="drought1"then local bag1={1,2,3,4,5,6} for _=1,6 do P:getNext(rem(bag1,rnd(#bag1))) end elseif s=="drought2"then local bag1={1,2,3,4,6,6} for _=1,6 do P:getNext(rem(bag1,rnd(#bag1))) end end P.newNext=freshMethod[ENV.sequence] if ENV.sequence==1 then P.bag={}--Bag7 elseif ENV.sequence==2 then P.his={}for i=1,4 do P.his[i]=P.next.id[i+3]end--History4 elseif ENV.sequence==3 then--Pure random end if AIdata then P.human=false P.AI_mode=AIdata.type P.AI_stage=1 P.AI_needFresh=false P.AI_keys={} P.AI_delay=min(int(ENV.drop*.8),2*AIdata.delta) P.AI_delay0=AIdata.delta P.AIdata={ next=AIdata.next, hold=AIdata.hold, _20G=ENV._20G, bag7=AIdata.bag7=="bag7", node=AIdata.node, } if not BOT then P.AI_mode="9S"end if P.AI_mode=="CC"then P.RS=kickList.AIRS local opt,wei=BOT.getConf() BOT.setHold(opt,P.AIdata.hold) BOT.set20G(opt,P.AIdata._20G) BOT.setBag(opt,P.AIdata.bag7) BOT.setNode(opt,P.AIdata.node) P.AI_bot=BOT.new(opt,wei) BOT.free(opt)BOT.free(wei) for i=1,AIdata.next do BOT.addNext(P.AI_bot,CCblockID[P.next[i].id]) end elseif P.AI_mode=="9S"then P.RS=kickList.TRS P.AI_keys={} end ENV.face={0,0,0,0,0,0,0} ENV.skin={1,5,2,8,10,3,7} else P.human=true P.RS=kickList.TRS players.human=players.human+1 ENV.next=min(ENV.next,setting.maxNext) end if P.small then ENV.lockFX=nil ENV.dropFX=nil ENV.shakeFX=nil else if ENV.lockFX==0 then ENV.lockFX=nil end if ENV.dropFX==0 then ENV.dropFX=nil end if ENV.shakeFX==0 then ENV.shakeFX=nil end end P.color={} for _=1,7 do P.color[_]=skin.libColor[ENV.skin[_]] end P.showTime=visible_opt[ENV.visible] P.keepVisible=ENV.visible=="show" P.keyPressing={}for i=1,12 do P.keyPressing[i]=false end P.moving,P.downing=0,0 P.waiting,P.falling=-1,-1 P.clearingRow,P.clearedRow={},{}--clearing animation height,cleared row mark P.combo,P.b2b=0,0 P.fieldBeneath=0 P.score1,P.b2b1=0,0 P.dropFX,P.lockFX={},{} P.endCounter=0--used after gameover P.result=nil--string:"WIN"/"K.O." end