local gc=love.graphics local setColor,rectangle=gc.setColor,gc.rectangle local floor,rnd=math.floor,math.random local ins,rem=table.insert,table.remove local setFont,mStr=FONT.set,GC.mStr local tileColor={ [-2]=COLOR.R, -- Bomb [-1]=COLOR.H, -- Stone {.39, 1.0, .39},-- Tile 1 {.39, .39, 1.0},-- Tile 2 {1.0, .70, .31},-- Tile 3 {.94, .31, .31},-- Tile 4 {.00, .71, .12},-- Tile 5 {.90, .20, .90},-- Tile 6 {.94, .47, .39},-- Tile 7 {.90, .00, .00},-- Tile 8 {.86, .86, .31},-- Tile 9 {.78, .31, .00},-- Tile 10 {.78, .55, .04},-- Tile 11 {.12, .12, .51},-- Tile 12 } local textColor={ [-2]=COLOR.dR, [-1]=COLOR.dH, {.26, .66, .26}, {.26, .26, .66}, {.66, .46, .20}, {.62, .20, .20}, {.00, .48, .08}, {.60, .14, .60}, {.62, .32, .26}, {.60, .00, .00}, {.58, .58, .20}, {.52, .20, .00}, {.52, .36, .20}, {.08, .80, .34}, } local tileTexts=setmetatable({ [-2]="B", [-1]="×", },{__index=function(self,k) self[k]=k return k end}) local player={x=340,y=90} function player:newTile() local r=rnd() if r<.006 then return self.maxTile elseif r<.026 then return -2 else local t=1 if rnd()<.3 then t=t+1 if rnd()<.3 then t=t+1 end end if self.maxTile>=4 and rnd()<.3 then t=t+1 if self.maxTile>=6 and rnd()<.3 then t=t+1 if self.maxTile>=8 and rnd()<.3 then t=t+1 end end end return t end end function player:reset() self.progress={} self.state=0 self.time=0 self.startTime=false self.score=0 self.maxTile=3 self.nexts,self.hold={self:newTile(),self:newTile(),self:newTile()},false self.selectX,self.selectY=false,false self.board={} for y=1,6 do self.board[y]={} for x=1,6 do self.board[y][x]=0 end end self.board[1][1]=false for _,n in next,{-1,-1,1,1,2,2,3,3} do local x,y repeat x,y=rnd(6),rnd(6) until not (x==1 and y==1) and self.board[y][x]==0 self.board[y][x]=n end end function player:merge(b,v,y,x) if b[y] and v==b[y][x] then ins(self.mergedTiles,{y,x}) b[y][x]=0 return 1 +self:merge(b,v,y,x-1) +self:merge(b,v,y,x+1) +self:merge(b,v,y-1,x) +self:merge(b,v,y+1,x) else return 0 end end local function availablePos(b,t) return t>0 and b==0 or t==-2 and b~=0 end local function newMergeFX(y,x,tile) local r,g,b if tile==-2 then r,g,b=1,.6,.3 end SYSFX.newShade(3,player.x+100*x-100,player.y+100*y-100,100,100,r,g,b) end function player:click(y,x) if y==1 and x==1 then self.nexts[1],self.hold=self.hold,self.nexts[1] SFX.play('hold') if not self.nexts[1] then rem(self.nexts,1) ins(self.nexts,self:newTile()) end elseif y~=self.selectY or x~=self.selectX then if availablePos(self.board[y][x],self.nexts[1]) then self.selectX,self.selectY=x,y else self.selectX,self.selectY=false,false end elseif y==self.selectY and x==self.selectX then if not availablePos(self.board[y][x],self.nexts[1]) then return end if self.state==0 then self.state=1 self.startTime=TIME() end if self.nexts[1]==-2 then self.board[y][x]=0 SFX.play('clear_2') rem(self.nexts,1) ins(self.nexts,self:newTile()) newMergeFX(y,x,-2) else self.board[y][x]=rem(self.nexts,1) SFX.play('touch') local cur,merged repeat local b1=TABLE.shift(self.board) cur=b1[y][x] self.mergedTiles={} local count=self:merge(b1,cur,y,x) if count>2 then merged=true self.board=b1 b1[y][x]=cur+1 if cur+1>self.maxTile then self.maxTile=cur+1 if self.maxTile>=6 then ins(self.progress,("%s - %.3fs"):format(self.maxTile,TIME()-player.startTime)) end SFX.play('reach') end local getScore=4^cur*count self.score=self.score+getScore TEXT.show(getScore,player.x+self.selectX*100-50,player.y+self.selectY*100-50,40,'score',1.626/math.log(getScore,3)) for i=1,#self.mergedTiles do newMergeFX(self.mergedTiles[i][1],self.mergedTiles[i][2],cur+1) end end until count<=2 ins(self.nexts,self:newTile()) self.selectX,self.selectY=false,false if merged then SFX.play('lock') if cur>=4 then SFX.play( cur>=8 and 'ren_mega' or cur>=7 and 'spin_3' or cur>=6 and 'spin_2' or cur>=5 and 'spin_1' or 'spin_0' ) end else for i=1,6 do if TABLE.find(self.board[i],0) then return end end self.state=2 SFX.play('fail') end end else self.selectX,self.selectY=x,y end end local function drawTile(x,y,v) if v and v~=0 then setColor(tileColor[v]) rectangle('fill',x*100-100,y*100-100,100,100) setColor(textColor[v]) mStr(tileTexts[v],x*100-50,y*100-92) end end function player:drawBoard() gc.push('transform') gc.translate(self.x,self.y) -- Board background setColor(COLOR.dX) rectangle("fill",0,0,600,600) -- Hold slot setColor(0,1,1,.4) rectangle("fill",0,0,100,100) gc.setLineWidth(10) setColor(COLOR.lC) rectangle("line",5,5,90,90) -- Hold tile setFont(60) drawTile(1,1,self.hold) -- Board tiles local b=self.board for y=1,6 do for x=1,6 do drawTile(x,y,b[y][x]) end end -- Board lines setColor(COLOR.Z) gc.setLineWidth(2) for x=1,5 do gc.line(x*100,0,x*100,600) end for y=1,5 do gc.line(0,y*100,600,y*100) end gc.setLineWidth(6) rectangle("line",0,0,600,600) -- Select box if self.selectX then local c=tileColor[self.nexts[1]] setColor(c[1],c[2],c[3],.6+.3*math.sin(TIME()*9.29)) rectangle("line",self.selectX*100-95,self.selectY*100-95,90,90) end gc.pop() end local scene={} function scene.enter() player:reset() BGM.play('truth') DiscordRPC.update("Playing Triple Town") end function scene.mouseClick(x,y) x,y=floor((x-player.x)/100)+1,floor((y-player.y)/100)+1 if x>=1 and x<=6 and y>=1 and y<=6 then player:click(y,x) end end function scene.touchClick(x,y) scene.mouseClick(x,y) end function scene.keyDown(key,isRep) if isRep then return end if key=='up' or key=='down' or key=='left' or key=='right' then if not player.selectX then player.selectX,player.selectY=3,3 else if key=='up' then player.selectY=math.max(player.selectY-1,1) elseif key=='down' then player.selectY=math.min(player.selectY+1,6) elseif key=='left' then player.selectX=math.max(player.selectX-1,1) elseif key=='right' then player.selectX=math.min(player.selectX+1,6) end end elseif key=='x' or key=='space' then if not player.selectX then player.selectX,player.selectY=3,3 else local y,x=player.selectY,player.selectX player:click(player.selectY,player.selectX) player.selectY,player.selectX=y,x end elseif key=='w' then love.mousepressed(love.mouse.getPosition()) elseif key=='z' or key=='q' then player:click(1,1) elseif key=='r' then if player.state~=1 or tryReset() then player:reset() end elseif key=='escape' then if tryBack() then SCN.back() end end end function scene.update() if player.state==1 then player.time=TIME()-player.startTime end end function scene.draw() setFont(40) setColor(1,1,1) gc.print(("%.3f"):format(player.time),1026,50) gc.print(player.score,1026,100) -- Progress time list setFont(25) setColor(.7,.7,.7) for i=1,#player.progress do gc.print(player.progress[i],1000,140+30*i) end gc.push('transform') gc.translate(745,13) setColor(COLOR.Z) gc.setLineWidth(4) gc.rectangle("line",-5,-5,200,70) for i=1,3 do setColor(tileColor[player.nexts[i]]) rectangle('fill',65*i-65,0,60,60) setFont(40) setColor(textColor[player.nexts[i]]) mStr(player.nexts[i],65*i-35,0) end gc.pop() player:drawBoard() end scene.widgetList={ WIDGET.newButton{name='reset',x=160,y=100,w=180,h=100,color='lG',font=50,fText=CHAR.icon.retry_spin,code=pressKey'r'}, WIDGET.newButton{name='back', x=1140,y=640,w=170,h=80,sound='back',font=60,fText=CHAR.icon.back,code=backScene}, } return scene