Files
Techmino/player.lua
2020-04-30 01:23:11 +08:00

2384 lines
56 KiB
Lua

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
-------------------------<GameData>-------------------------
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,
}
-------------------------</GameData>------------------------
--------------------------<Pnt/Upd>-------------------------
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 moving<P.gameEnv.das then
moving=moving+1
if moving==P.gameEnv.das then
if P.waiting==-1 then
flag=true
end
end
else
moving=moving+1
if moving>P.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 moving<P.gameEnv.das then
moving=moving+1
if moving==P.gameEnv.das then
if P.waiting==-1 then
flag=true
end
end
else
moving=moving+1
if moving>P.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<P.AI_delay0*.5 then
CC_switch20G(P)
end
end
if P.freshTime<=P.gameEnv.freshLimit then
P.lockDelay=P.gameEnv.lock
end
else
P.lockDelay=P.lockDelay-1
if P.lockDelay>=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<P.b2b then
P.b2b1=min(P.b2b1*.98+P.b2b*.02+.4,P.b2b)
else
P.b2b1=max(P.b2b1*.95+P.b2b*.05-.6,P.b2b)
end
updateFXs(P,dt)
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
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
-------------------------</Pnt/Upd>-------------------------
player={}local player=player
----------------------------<FX>----------------------------
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)--x1<x2,y1>y2!
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
-------------------------</FX>-------------------------
-------------------------<Method>-------------------------
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.lockDelay<P.gameEnv.lock then
P.dropDelay=P.gameEnv.drop
P.freshTime=P.freshTime+1
if P.freshTime<=P.gameEnv.freshLimit then
P.lockDelay=P.gameEnv.lock
end
end
end
function player.lock(P)
for i=1,P.r do
local y=P.curY+i-1
if not P.field[y]then P.field[y],P.visTime[y]=freeRow.get(0),freeRow.get(0)end
for j=1,P.c do
if P.cur.bk[i][j]then
P.field[y][P.curX+j-1]=P.cur.color
P.visTime[y][P.curX+j-1]=P.showTime
end
end
end
end
function player.spin(P,d,ifpre)
if P.cur.id==6 then--O-spin!
if P.human then
SFX.play("rotate",nil,getBlockPosition(P))
end
if P.gameEnv.easyFresh then
P:freshLockDelay()
end
if P.gameEnv.ospin then
local x,y=P.curX,P.curY
if y==P.y_img and((solid(P,x-1,y)or solid(P,x-1,y+1)))and(solid(P,x+2,y)or solid(P,x+2,y+1))then
local D=P.spinSeq%100*10+d
P.spinSeq=D
if D>100 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 cc<P.r
end
else
dospin=false
end
elseif cc==0 then
if dospin==0 then
dospin=false
end
end
else
dospin=false
end
--极简判定:遮挡判断法
local finesse
if P.curY<=18 then
local y0=P.curY
local x,c=P.curX,P.c
local B=P.cur.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=P.curX+x-1
for y=y0+y,#P.field do
if solid(P,x,y)then
finesse=true
goto L2
end--有遮挡视为最简
end
end
end
end
::L2::
--移除消去的行
for i=cc,1,-1 do
_=P.clearedRow[i]
freeRow.discard(rem(P.field,_))
freeRow.discard(rem(P.visTime,_))
end
if not finesse then--极简判定:操作判断法
if dospin then P.ctrlCount=P.ctrlCount-2 end--对无遮挡spin宽松两步
local id=P.cur.id
local dir=P.dir+1
if id<3 or id==7 then
if dir>2 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
-------------------------</Methods>-------------------------
--------------------------<Events>--------------------------
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>--------------------------
-------------------------<Controls>-------------------------
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
-------------------------</Controls>-------------------------
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