358 lines
9.4 KiB
Lua
358 lines
9.4 KiB
Lua
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
|