diff --git a/parts/AITemplate.lua b/parts/AITemplate.lua
index 9d8960fe..80331f40 100644
--- a/parts/AITemplate.lua
+++ b/parts/AITemplate.lua
@@ -1,4 +1,3 @@
-local int=math.floor
local AISpeed={60,50,45,35,25,15,9,6,4,3}
return function(type,speedLV,next,hold,node)
if type=="CC"then
@@ -12,7 +11,7 @@ return function(type,speedLV,next,hold,node)
elseif type=="9S"then
return{
type="9S",
- delta=int(AISpeed[speedLV]*.5),
+ delta=math.floor(AISpeed[speedLV]*.5),
}
end
end
\ No newline at end of file
diff --git a/parts/player.lua b/parts/player.lua
index cc9f880c..bde5d197 100644
--- a/parts/player.lua
+++ b/parts/player.lua
@@ -1027,6 +1027,274 @@ local function Pdraw_demo(P)
end
----------------------------------------------------
+----------------------------------------------------
+local function pressKey(P,i)
+ P.keyPressing[i]=true
+ P.act[i](P)
+ if P.control then
+ if P.keyRec then
+ ins(P.keyTime,1,game.frame)
+ P.keyTime[11]=nil
+ end
+ P.stat.key=P.stat.key+1
+ end
+end
+local function releaseKey(P,i)
+ P.keyPressing[i]=false
+end
+local function pressKey_Rec(P,i)
+ if game.recording then
+ ins(game.rec,game.frame)
+ ins(game.rec,i)
+ end
+ P.keyPressing[i]=true
+ P.act[i](P)
+ if P.control then
+ if P.keyRec then
+ ins(P.keyTime,1,game.frame)
+ P.keyTime[11]=nil
+ end
+ P.stat.key=P.stat.key+1
+ end
+end
+local function releaseKey_Rec(P,i)
+ if game.recording then
+ ins(game.rec,game.frame)
+ ins(game.rec,-i)
+ end
+ P.keyPressing[i]=false
+end
+local function without(L,e)
+ for i=1,#L do
+ if L[i]==e then return end
+ end
+ return true
+end
+local function getNewStatTable()
+ local T={
+ time=0,score=0,
+ key=0,rotate=0,hold=0,
+ extraPiece=0,extraRate=0,
+ piece=0,row=0,dig=0,
+ atk=0,digatk=0,
+ send=0,recv=0,pend=0,off=0,
+ clear={},clears={},spin={},spins={},
+ pc=0,hpc=0,b2b=0,b3b=0,
+ }
+ for i=1,25 do
+ T.clear[i]={0,0,0,0,0}
+ T.spin[i]={0,0,0,0,0}
+ T.clears[i]=0
+ T.spins[i]=0
+ end
+ return T
+end
+local function newEmptyPlayer(id,x,y,size)
+ local P={id=id}
+ players[id]=P
+ players.alive[id]=P
+
+ --Inherit functions of player class
+ for k,v in next,player do P[k]=v end
+ if P.id==1 and game.recording then
+ P.pressKey=pressKey_Rec
+ P.releaseKey=releaseKey_Rec
+ else
+ P.pressKey=pressKey
+ P.releaseKey=releaseKey
+ end
+ P.update=Pupdate_alive
+
+ P.fieldOff={x=0,y=0,vx=0,vy=0}--For shake FX
+ P.x,P.y,P.size=x,y,size or 1
+ P.frameColor=frameColor[0]
+
+ P.small=P.size<.1--If draw in small mode
+ if P.small then
+ P.centerX,P.centerY=P.x+300*P.size,P.y+600*P.size
+ P.canvas=love.graphics.newCanvas(60,120)
+ P.frameWait=rnd(30,120)
+ P.draw=Pdraw_small
+ else
+ P.keyRec=true--If calculate keySpeed
+ P.centerX,P.centerY=P.x+300*P.size,P.y+370*P.size
+ P.absFieldX=P.x+150*P.size
+ P.absFieldY=P.y+60*P.size
+ P.draw=Pdraw_norm
+ P.bonus={}--Text objects
+ end
+ P.randGen=mt.newRandomGenerator(game.seed)
+
+ P.small=false
+ P.alive=true
+ P.control=false
+ P.timing=false
+ P.stat=getNewStatTable()
+
+ P.modeData={point=0,event=0,counter=0}--Data use by mode
+ P.keyTime={}P.keySpeed=0
+ P.dropTime={}P.dropSpeed=0
+ for i=1,10 do P.keyTime[i]=-1e5 end
+ for i=1,10 do P.dropTime[i]=-1e5 end
+
+ P.field,P.visTime={},{}
+ P.atkBuffer={sum=0}
+
+ --Royale-related
+ P.badge,P.strength=0,0
+ P.atkMode,P.swappingAtkMode=1,20
+ P.atker,P.atking,P.lastRecv={}
+
+ P.dropDelay,P.lockDelay=0,0
+ P.color={}
+ P.showTime=nil
+ P.keepVisible=true
+
+ --P.cur={bk=matrix[2], id=shapeID, color=colorID, name=nameID}
+ --P.sc,P.dir={0,0},0--SpinCenterCoord, direction
+ --P.r,P.c=0,0--row, col
+ --P.hd={...},same as P.cur
+ -- P.curX,P.curY,P.imgY,P.minY=0,0,0,0--x,y,ghostY
+ P.holded=false
+ P.next={}
+
+ P.freshTime=0
+ P.spinLast,P.lastClear=false,nil
+ P.spinSeq=0--For Ospin, each digit mean a spin
+ P.ctrlCount=0--Key press time, for finesse check
+ P.pieceCount=0--Count pieces from next, for drawing bagline
+
+ P.human=false
+ P.RS=kickList.TRS
+
+ -- P.newNext=nil--Call prepareSequence()to get a function to get new next
+
+ P.keyPressing={}for i=1,12 do P.keyPressing[i]=false end
+ P.movDir,P.moving,P.downing=0,0,0--Last move key,DAS charging,downDAS charging
+ P.waiting,P.falling=-1,-1
+ P.clearingRow,P.clearedRow={},{}--Clearing animation height,cleared row mark
+ P.combo,P.b2b=0,0
+ P.garbageBeneath=0
+ P.fieldBeneath=0
+
+ P.score1,P.b2b1=0,0
+ P.dropFX,P.moveFX,P.lockFX,P.clearFX={},{},{},{}
+ P.tasks={}--Tasks
+ P.bonus={}--Texts
+
+ P.endCounter=0--Used after gameover
+ P.result=nil--String:"WIN"/"K.O."
+
+ return P
+end
+local function loadGameEnv(P)--Load gameEnv
+ P.gameEnv={}--Current game setting environment
+ local ENV=P.gameEnv
+ local E
+ --Load game settings
+ for k,v in next,gameEnv0 do
+ if modeEnv[k]~=nil then
+ v=modeEnv[k] --Mode setting
+ -- DBP("mode-"..k..":"..tostring(v))
+ elseif game.setting[k]~=nil then
+ v=game.setting[k] --Game setting
+ -- DBP("game-"..k..":"..tostring(v))
+ elseif setting[k]~=nil then
+ v=setting[k] --Global setting
+ -- DBP("global-"..k..":"..tostring(v))
+ -- else
+ -- DBP("default-"..k..":"..tostring(v))
+ end
+ ENV[k]=v --Default setting
+ end
+end
+local function applyGameEnv(P)--Finish gameEnv processing
+ local ENV=P.gameEnv
+
+ P.dropDelay=ENV.drop
+ P.lockDelay=ENV.lock
+
+ P.color={}
+ for _=1,7 do
+ P.color[_]=SKIN.libColor[ENV.skin[_]]
+ end
+
+ P.keepVisible=ENV.visible=="show"
+ P.showTime=
+ ENV.visible=="show"and 1e99 or
+ ENV.visible=="time"and 300 or
+ ENV.visible=="fast"and 20 or
+ ENV.visible=="none"and 0
+
+ P.life=ENV.life
+
+ ENV.das=max(ENV.das,ENV.mindas)
+ ENV.arr=max(ENV.arr,ENV.minarr)
+ ENV.sdarr=max(ENV.sdarr,ENV.minsdarr)
+ ENV.next=min(ENV.next,setting.maxNext)
+
+ if ENV.sequence~="bag"and ENV.sequence~="loop"then
+ ENV.bagLine=false
+ else
+ ENV.bagLen=#ENV.bag
+ end
+
+ if ENV.lockFX==0 then ENV.lockFX=nil end
+ if ENV.dropFX==0 then ENV.dropFX=nil end
+ if ENV.moveFX==0 then ENV.moveFX=nil end
+ if ENV.clearFX==0 then ENV.clearFX=nil end
+ if ENV.shakeFX==0 then ENV.shakeFX=nil end
+ if ENV.ghost==0 then ENV.ghost=nil end
+ if ENV.center==0 then ENV.center=nil end
+end
+local function prepareSequence(P)--Call freshPrepare and set newNext
+ local ENV=P.gameEnv
+ if type(ENV.sequence)=="string"then
+ freshPrepare[ENV.sequence](P)
+ P.newNext=freshMethod[ENV.sequence]
+ else
+ assert(type(ENV.sequence)=="function"and type(ENV.freshMethod)=="function","wrong sequence generator code")
+ ENV.sequence(P)
+ P.newNext=ENV.freshMethod
+ end
+end
+local function loadAI(P,AIdata)--Load AI params
+ local ENV=P.gameEnv
+ P.AI_mode=AIdata.type
+ P.AI_stage=1
+ P.AI_keys={}
+ P.AI_delay=AIdata.delay or min(int(ENV.drop*.8),2*AIdata.delta)
+ P.AI_delay0=AIdata.delta
+ P.AIdata={
+ type=AIdata.type,
+ delay=AIdata.delay,
+ delta=AIdata.delta,
+
+ next=AIdata.next,
+ hold=AIdata.hold,
+ _20G=ENV._20G,
+ bag=AIdata.bag,
+ 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.bag=="bag")
+ 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
+ end
+end
+----------------------------------------------------
+
----------------------------------------------------
function player.showText(P,text,dx,dy,font,style,spd,stop)
if P.gameEnv.text then
@@ -1036,12 +1304,6 @@ end
function player.showTextF(P,text,dx,dy,font,style,spd,stop)
ins(P.bonus,TEXT.getText(text,150+dx,300+dy,font*P.size,style,spd,stop))
end
-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=12-P.gameEnv.lockFX*2
@@ -1166,25 +1428,6 @@ function player.RND(P,a,b)
return R:random(a,b)
end
-local function getNewStatTable()
- local T={
- time=0,score=0,
- key=0,rotate=0,hold=0,
- extraPiece=0,extraRate=0,
- piece=0,row=0,dig=0,
- atk=0,digatk=0,
- send=0,recv=0,pend=0,off=0,
- clear={},clears={},spin={},spins={},
- pc=0,hpc=0,b2b=0,b3b=0,
- }
- for i=1,25 do
- T.clear[i]={0,0,0,0,0}
- T.spin[i]={0,0,0,0,0}
- T.clears[i]=0
- T.spins[i]=0
- end
- return T
-end
function player.solid(P,x,y)
if x<1 or x>10 or y<1 then return true end
if y>#P.field then return false end
@@ -2108,46 +2351,6 @@ function player.drop(P)--Place piece
end
----------------------------------------------------
-----------------------------------------------------
-local AM={}
-function AM.pressKey(P,i)
- P.keyPressing[i]=true
- P.act[i](P)
- if P.control then
- if P.keyRec then
- ins(P.keyTime,1,game.frame)
- P.keyTime[11]=nil
- end
- P.stat.key=P.stat.key+1
- end
-end
-function AM.releaseKey(P,i)
- P.keyPressing[i]=false
-end
-function AM.pressKey_Rec(P,i)
- if game.recording then
- ins(game.rec,game.frame)
- ins(game.rec,i)
- end
- P.keyPressing[i]=true
- P.act[i](P)
- if P.control then
- if P.keyRec then
- ins(P.keyTime,1,game.frame)
- P.keyTime[11]=nil
- end
- P.stat.key=P.stat.key+1
- end
-end
-function AM.releaseKey_Rec(P,i)
- if game.recording then
- ins(game.rec,game.frame)
- ins(game.rec,-i)
- end
- P.keyPressing[i]=false
-end
-----------------------------------------------------
-
----------------------------------------------------
local function gameOver()--Save record
if game.replaying then return end
@@ -2253,10 +2456,13 @@ function player.lose(P)
end
if P.AI_mode=="CC"then
- CC_updateField(P)
+ P.hd=nil
+ loadAI(P,P.AIdata)
+ P:popNext()
end
P.life=P.life-1
+ P.fieldBeneath=0
P.b2b=0
for i=1,#P.atkBuffer do
local A=P.atkBuffer[i]
@@ -2272,7 +2478,7 @@ function player.lose(P)
end
sysFX.newShade(.5,1,1,1,P.x+150*P.size,P.y+60*P.size,300*P.size,610*P.size)
sysFX.newRectRipple(.3,P.x+150*P.size,P.y+60*P.size,300*P.size,610*P.size)
- sysFX.newRipple(.3,P.x+(300+25+25*P.life+12)*P.size,P.y+(595+12)*P.size,20)
+ sysFX.newRipple(.3,P.x+(450+25+25*P.life+12)*P.size,P.y+(665+12)*P.size,20)
--300+25*i,595
SFX.play("clear_3")
SFX.play("emit")
@@ -2626,207 +2832,6 @@ end
----------------------------------------------------
----------------------------------------------------
-local function newEmptyPlayer(id,x,y,size)
- local P={id=id}
- players[id]=P
- players.alive[id]=P
-
- --Inherit functions of player class
- for k,v in next,player do P[k]=v end
- if P.id==1 and game.recording then
- P.pressKey=AM.pressKey_Rec
- P.releaseKey=AM.releaseKey_Rec
- else
- P.pressKey=AM.pressKey
- P.releaseKey=AM.releaseKey
- end
- P.update=Pupdate_alive
-
- P.fieldOff={x=0,y=0,vx=0,vy=0}--For shake FX
- P.x,P.y,P.size=x,y,size or 1
- P.frameColor=frameColor[0]
-
- P.small=P.size<.1--If draw in small mode
- if P.small then
- P.centerX,P.centerY=P.x+300*P.size,P.y+600*P.size
- P.canvas=love.graphics.newCanvas(60,120)
- P.frameWait=rnd(30,120)
- P.draw=Pdraw_small
- else
- P.keyRec=true--If calculate keySpeed
- P.centerX,P.centerY=P.x+300*P.size,P.y+370*P.size
- P.absFieldX=P.x+150*P.size
- P.absFieldY=P.y+60*P.size
- P.draw=Pdraw_norm
- P.bonus={}--Text objects
- end
- P.randGen=mt.newRandomGenerator(game.seed)
-
- P.small=false
- P.alive=true
- P.control=false
- P.timing=false
- P.stat=getNewStatTable()
-
- P.modeData={point=0,event=0,counter=0}--Data use by mode
- P.keyTime={}P.keySpeed=0
- P.dropTime={}P.dropSpeed=0
- for i=1,10 do P.keyTime[i]=-1e5 end
- for i=1,10 do P.dropTime[i]=-1e5 end
-
- P.field,P.visTime={},{}
- P.atkBuffer={sum=0}
-
- --Royale-related
- P.badge,P.strength=0,0
- P.atkMode,P.swappingAtkMode=1,20
- P.atker,P.atking,P.lastRecv={}
-
- P.dropDelay,P.lockDelay=0,0
- P.color={}
- P.showTime=nil
- P.keepVisible=true
-
- --P.cur={bk=matrix[2], id=shapeID, color=colorID, name=nameID}
- --P.sc,P.dir={0,0},0--SpinCenterCoord, direction
- --P.r,P.c=0,0--row, col
- --P.hd={...},same as P.cur
- -- P.curX,P.curY,P.imgY,P.minY=0,0,0,0--x,y,ghostY
- P.holded=false
- P.next={}
-
- P.freshTime=0
- P.spinLast,P.lastClear=false,nil
- P.spinSeq=0--For Ospin, each digit mean a spin
- P.ctrlCount=0--Key press time, for finesse check
- P.pieceCount=0--Count pieces from next, for drawing bagline
-
- P.human=false
- P.RS=kickList.TRS
-
- -- P.newNext=nil--Call prepareSequence()to get a function to get new next
-
- P.keyPressing={}for i=1,12 do P.keyPressing[i]=false end
- P.movDir,P.moving,P.downing=0,0,0--Last move key,DAS charging,downDAS charging
- P.waiting,P.falling=-1,-1
- P.clearingRow,P.clearedRow={},{}--Clearing animation height,cleared row mark
- P.combo,P.b2b=0,0
- P.garbageBeneath=0
- P.fieldBeneath=0
-
- P.score1,P.b2b1=0,0
- P.dropFX,P.moveFX,P.lockFX,P.clearFX={},{},{},{}
- P.tasks={}--Tasks
- P.bonus={}--Texts
-
- P.endCounter=0--Used after gameover
- P.result=nil--String:"WIN"/"K.O."
-
- return P
-end
-local function loadGameEnv(P)--Load gameEnv
- P.gameEnv={}--Current game setting environment
- local ENV=P.gameEnv
- local E
- --Load game settings
- for k,v in next,gameEnv0 do
- if modeEnv[k]~=nil then
- v=modeEnv[k] --Mode setting
- -- DBP("mode-"..k..":"..tostring(v))
- elseif game.setting[k]~=nil then
- v=game.setting[k] --Game setting
- -- DBP("game-"..k..":"..tostring(v))
- elseif setting[k]~=nil then
- v=setting[k] --Global setting
- -- DBP("global-"..k..":"..tostring(v))
- -- else
- -- DBP("default-"..k..":"..tostring(v))
- end
- ENV[k]=v --Default setting
- end
-end
-local function applyGameEnv(P)--Finish gameEnv processing
- local ENV=P.gameEnv
-
- P.dropDelay=ENV.drop
- P.lockDelay=ENV.lock
-
- P.color={}
- for _=1,7 do
- P.color[_]=SKIN.libColor[ENV.skin[_]]
- end
-
- P.keepVisible=ENV.visible=="show"
- P.showTime=
- ENV.visible=="show"and 1e99 or
- ENV.visible=="time"and 300 or
- ENV.visible=="fast"and 20 or
- ENV.visible=="none"and 0
-
- P.life=ENV.life
-
- ENV.das=max(ENV.das,ENV.mindas)
- ENV.arr=max(ENV.arr,ENV.minarr)
- ENV.sdarr=max(ENV.sdarr,ENV.minsdarr)
- ENV.next=min(ENV.next,setting.maxNext)
-
- if ENV.sequence~="bag"and ENV.sequence~="loop"then
- ENV.bagLine=false
- else
- ENV.bagLen=#ENV.bag
- end
-
- if ENV.lockFX==0 then ENV.lockFX=nil end
- if ENV.dropFX==0 then ENV.dropFX=nil end
- if ENV.moveFX==0 then ENV.moveFX=nil end
- if ENV.clearFX==0 then ENV.clearFX=nil end
- if ENV.shakeFX==0 then ENV.shakeFX=nil end
- if ENV.ghost==0 then ENV.ghost=nil end
- if ENV.center==0 then ENV.center=nil end
-end
-local function prepareSequence(P)--Call freshPrepare and set newNext
- local ENV=P.gameEnv
- if type(ENV.sequence)=="string"then
- freshPrepare[ENV.sequence](P)
- P.newNext=freshMethod[ENV.sequence]
- else
- assert(type(ENV.sequence)=="function"and type(ENV.freshMethod)=="function","wrong sequence generator code")
- ENV.sequence(P)
- P.newNext=ENV.freshMethod
- end
-end
-local function loadAI(P,AIdata)--Load AI params
- local ENV=P.gameEnv
- P.AI_mode=AIdata.type
- P.AI_stage=1
- P.AI_keys={}
- P.AI_delay=AIdata.delay or min(int(ENV.drop*.8),2*AIdata.delta)
- P.AI_delay0=AIdata.delta
- P.AIdata={
- next=AIdata.next,
- hold=AIdata.hold,
- _20G=ENV._20G,
- bag=AIdata.bag=="bag",
- 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.bag)
- 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
- end
-end
-
function PLY.newDemoPlayer(id,x,y,size)
local P=newEmptyPlayer(id,x,y,size)