commit 20b30e0731128e9db1a1a35f50bc59796d838909 Author: Kimapr Date: Tue Mar 28 10:42:05 2023 +0500 worksgit add -A! diff --git a/main.lua b/main.lua new file mode 100644 index 0000000..645eb69 --- /dev/null +++ b/main.lua @@ -0,0 +1,840 @@ +local board={} +local bw,bh=10,10 +local g=love.graphics +local font=g.newFont(9,"mono") +font:setFilter("nearest") +g.setFont(font) +local colors={ + function(a,b) + g.setColor(1,0,0,b*a) + g.polygon("fill",0.5,0, 1,0.5, 0.5,1, 0,0.5) + g.setColor(1,0,0,a) + g.polygon("line",0.5,0, 1,0.5, 0.5,1, 0,0.5) + end, + function(a,b) + local w=0.5^0.5 + local p=(1-w)/2 + g.setColor(1,1,0,b*a) + g.rectangle("fill",p,p,w,w) + g.setColor(1,1,0,a) + g.rectangle("line",p,p,w,w) + end, + function(a,b) + g.setColor(0,1,0,b*a) + g.circle("fill",0.5,0.5,0.45,8) + g.setColor(0,1,0,a) + g.circle("line",0.5,0.5,0.45,8) + end, + function(a,b) + g.translate(0,0.15) + g.translate(0.5,0.5) + g.rotate(math.pi/2*3) + g.translate(-0.5,-0.5) + g.setColor(0,1,1,b*a) + g.circle("fill",0.5,0.5,0.5,3) + g.setColor(0,1,1,a) + g.circle("line",0.5,0.5,0.5,3) + end, + function(a,b) + g.translate(0.5,0.5) + g.rotate(math.pi/2*3) + g.translate(-0.5,-0.5) + g.setColor(1,0,1,b*a) + g.circle("fill",0.5,0.5,0.45,6) + g.setColor(1,0,1,a) + g.circle("line",0.5,0.5,0.45,6) + end, + function(a,b) + g.setColor(0,0,1,b*a) + g.setColor(0,0,1,a) + g.line(0.1,0.4, 0.5,0, 0.9,0.4) + g.line(0.1,1-0.4, 0.5,1-0, 0.9,1-0.4) + g.line(0.3,0.5, 0.7,0.5) + end, +} +local gobjs={} +local cgobjs={} +local lgobjs={} +local mgobjs={} +for k,v in ipairs(colors) do + gobjs[k]={c=k} + cgobjs[k]={c=k,super="charge"} + lgobjs[k]={c=k,super="lines"} + mgobjs[k]={c=k,super="color"} +end +local cc=3 +local tt=0 +local bat=1 +local batd=bat +local score=0 +local scored=score +local function znoise(...) + return love.math.noise(...)*2-1 +end +local function drawfig(n,a) + g.push("all") + g.scale(2-(a or 1)) + g.translate(-0.5,-0.5) + g.translate(0.1,0.1) + g.scale(0.8) + colors[n.c](a or 1,n.super=="charge" and ((math.sin(tt*math.pi*2)*0.5+0.5)*0.4+0.1) or 0) + if n.super=="lines" then + local hps,vps={},{} + local det=10 + for n=0,det do + local dmul=(det-math.abs(n-det/2))/det*4 + hps[n*2+1],hps[n*2+2]=n/det,0.5+znoise(tt,583,-775,n)*0.1*dmul + vps[n*2+1],vps[n*2+2]=0.5+znoise(tt,-492,444,n)*0.1*dmul,n/det + end + g.line(hps) + g.line(vps) + elseif n.super=="color" then + local l={} + local det=100 + for n=0,det do + l[n*2+1],l[n*2+2]=0.5+znoise(tt,55,51,n*math.pi/det*2),0.5+znoise(tt,44,25,n*math.pi/det*2) + end + g.setLineJoin("none") + g.polygon("line",l) + end + g.scale(0.02) + g.pop() +end + +local function pti(x,y) + return y+(x-1)*bh +end + +local trans=love.math.newTransform() +local anims={} +local falling={} +local booms={} + +local function smtar(x,y,tx,ty) + local i=pti(x,y) + local anim + if not anims[i] then + if x==tx and y==ty then return end + anims[i]={ + cx=x,cy=y, + tx=tx,ty=ty, + x=x,y=y + } + end + anim=anims[i] + anim.tx,anim.ty=tx,ty +end + +local function setbsize(x,y,w,h) + trans:reset() + trans:translate(x,y) + trans:scale(w/bw,h/bh) +end + +local gemrng +local function randgem() + local objl=gemrng:random()>0.99 and cgobjs or gobjs + return objl[gemrng:random(math.floor(cc))] +end +local function nextgem(o) + local c=o.c%math.floor(cc)+1 + return (o.super and cgobjs or gobjs)[c] +end +local function isgem(o) + return type(o)=="table" and colors[o.c] +end +local function eqgem(a,b) + return isgem(a) and isgem(b) and a.c==b.c +end + +local function badboigemcheck(c,am,ac,rm) + c=isgem(c) and c.c + if not c then return end + if ac~=5 and ac~=4 then return end + local aa={} + for k,v in pairs(am) do + local cc=board[v[1]][v[2]] + if isgem(cc) and (cc.super and cc.super~="charge") then + return + end + aa[#aa+1]=k + end + local e=aa[gemrng:random(#aa)] + local rc=ac==5 and mgobjs[c] or lgobjs[c] + rm[e][3]=rc +end +local function megascan(c,rm) + local ogc=c + if not isgem(ogc) then return end + rm=rm or {} + if ogc.super~="color" then return end + for x=1,bw do + for y=1,bh do + local i=pti(x,y) + local c=board[x][y] + if eqgem(c,ogc) then + rm[i]=rm[i] or {x,y} + end + end end + return next(rm) and rm +end +local function check(x,y,rm,oam,obm) + local c=board[x][y] + if not c then return end + local ac,bc=1,1 + local am,bm={},{} + oam,obm=oam or {}, obm or {} + do + local i=pti(x,y) + local v={x,y} + am[i],bm[i]=v,v + end + rm=rm or {} + for d,v in ipairs{{-1,0},{1,0},{0,-1},{0,1}} do + local ox,oy=unpack(v) + local x,y=x+ox,y+oy + while x>=1 and x<=bw and y>=1 and y<=bh do + local i=pti(x,y) + if eqgem(board[x][y],c) then + if d>2 and not oam[i] then + ac=ac+1 + am[i]={x,y} + oam[i]=true + elseif d<=2 and not obm[i] then + bc=bc+1 + bm[i]={x,y} + obm[i]=true + end + else + break + end + x,y=x+ox,y+oy + end + end + if ac>=3 then + for k,v in pairs(am) do rm[k]=v end + badboigemcheck(c,am,ac,rm) + end + if bc>=3 then + for k,v in pairs(bm) do rm[k]=v end + badboigemcheck(c,bm,bc,rm) + end + return next(rm) and rm,oam,obm +end + +local falltest=false + +local function drawboard(x,y,w,h) + g.push("all") + g.applyTransform(trans) + g.setLineWidth(0.1) + g.stencil(function() + g.rectangle("fill",0,0,bw,bh) + end) + g.push("all") + g.translate(0.1,-1-0.05) + local bat=math.min(batd,1) + g.setColor((1-bat^2),bat^0.5,math.max(0,batd-1)^0.5) + g.rectangle("line",0,0,bw/2-0.1,0.8) + g.rectangle("fill",0.2,0.2,(bw/2-0.5)*bat,0.4) + g.rectangle("line",bw/2-0.09,0.2,0.2,0.4) + g.pop() + g.push("all") + local sctext=("%.1i"):format(math.floor(scored+.5)) + local xx,yy=trans:transformPoint(0,0) + local tty=0.8/font:getHeight() + local ttx=font:getWidth(sctext)*tty + g.translate(bw-ttx,-1.1) + g.scale(tty) + g.setColor(1,1,1) + g.print(sctext) + g.pop() + if not falltest then + g.setStencilTest("greater",0) + end + for x=1,bw do + for y=1,bh do + g.push() + local tx,ty=x,y + local anim=anims[pti(x,y)] + if anim then + tx,ty=anim.cx or x, anim.cy or y + end + g.translate(tx-0.5,ty-0.5) + if isgem(board[x][y]) then + drawfig(board[x][y]) + end + g.pop() + end + end + for x,falling in ipairs(falling) do + for fall,_ in pairs(falling) do + for i,c in ipairs(fall.figs) do + g.push("all") + local tx,ty=fall.x,fall.y-i+1 + g.translate(tx-0.5,ty-0.5) + if isgem(c) then + drawfig(c) + end + g.pop() + end + end + end + for v,_ in pairs(booms) do + g.push("all") + local tx,ty=v.x,v.y + g.translate(tx-0.5,ty-0.5) + drawfig(v.c,v.a) + g.pop() + end + g.setStencilTest() + g.setColor(0.2,0.2,0.2) + g.rectangle("line",0,0,bw,bh) + g.pop() +end +local function fall(l) + local cols={} + for k,v in pairs(l) do + local x,y=unpack(v) + cols[x]=cols[x] or {l={},m={}} + cols.l[#cols+1]=y + cols.m[y]=true + end +end +local killall + +local function kill(x,y,rc) + if not board[x][y] then print("Whar") return end + if board[x][y].super=="charge" then + bat=math.min(2,bat+0.1) + end + do + local tx,ty=x,y + local anim=anims[pti(x,y)] + if anim then + tx,ty=anim.cx,anim.cy + end + booms[{ + x=tx,y=ty, + a=1,c=board[x][y] or mgobjs[4] + }]=true + end + if rc then + board[x][y]=rc + return true + end + board[x][y]=nil + local fall={} + for y=y-1,gem and 1 or (-bh+1),-1 do + if board[x][y] then + if not fall.figs then + fall.x,fall.y=x,y + fall.figs={} + fall.vel=0 + falling[x][fall]=true + end + fall.figs[#fall.figs+1]=board[x][y] + board[x][y]=nil + elseif fall.figs then + fall={} + end + end + local my,mfall=math.huge + local unfell={} + local yls={} + local cx=x + for x=1,bw do + local yl + for y=bh,0,-1 do + if not board[x][y] then + yl=y + break + end + end + unfell[x]={} + local tt={} + for k,v in pairs(falling[x]) do + tt[#tt+1]=k + end + table.sort(tt,function(a,b) + return a.y>b.y + end) + for _,fall in ipairs(tt) do + if cx==x and fall.ya[2] or b[1]>b[1] + end) + local checks={} + for k,v in ipairs(tt) do + local a=kill(unpack(v)) + if a then + checks[k]=v + end + end + local rm,oam,obm={},{},{} + for k,v in pairs(checks) do + local x,y=unpack(v) + check(x,y,rm,oam,obm) + end + if next(rm) then + killall(rm) + end + score=score+#tt +end + +local function dropall(off,die) + for x=1,bw do + falling[x]=falling[x] or {} + local fall={ + x=x,y=bh+(off or 0), + vel=0, + figs={} + } + falling[x][fall]=true + for y=bh,1,-1 do + fall.figs[#fall.figs+1]=board[x][y] + board[x][y]=nil + end + end + if die then + for x,falling in pairs(falling) do + for fall,_ in pairs(falling) do + fall.die=true + end + end + end +end + +local function fillboard() + cc=3 + score=0 + bat=1 + gemrng=love.math.newRandomGenerator(991) + for x=1,bw do + board[x]={} + for y=1,bh do + local a=randgem() + board[x][y]=a + end + end + for n=1,math.huge do + local good=true + local rm={} + local kills + for x=1,bw do + for y=1,bh do + kills=check(x,y,rm) or kills + end + end + if not next(rm) then break end + for k,v in pairs(rm) do + local x,y=unpack(v) + board[x][y]=randgem() + end + end + dropall(-bh) +end +local dbg=false + +function love.load() + fillboard() +end + +local grabbed=nil +local dying=false +local running=false + +function love.mousepressed(x,y,b) + x,y=trans:inverseTransformPoint(x,y) + x,y=x+1-0.5,y+1-0.5 + local ix,iy=math.floor(x+.5),math.floor(y+.5) + if b==2 and dbg then + for ix=ix-50,iy+50 do + for iy=iy-50,iy+50 do + if board[ix] and board[ix][iy] and math.random()>0.1 then + kill(ix,iy) + end + end end + end + if b~=1 then return end + running=true + if ix<1 or ix>bw or + iy<1 or iy>bh + then + return + end + if grabbed then + return + end + grabbed={ + ix,iy, + ix-x,iy-y, + } +end + +function love.mousereleased(x,y,b) + if b~=1 then return end + if grabbed then + local ix,iy,ox,oy,px,py=unpack(grabbed) + if ix and px and (ix~=px or iy~=py) then + board[ix][iy],board[px][py]= + board[px][py],board[ix][iy] + local kills=check(ix,iy,check(px,py,megascan(board[ix][iy],megascan(board[px][py])))) + if kills then + local ii,pi=pti(ix,iy),pti(px,py) + local ania,anib=anims[ii],anims[pi] + anims[ii],anims[pi]=anib,ania + ania=ania or {x=ix,y=iy} + anib=anib or {x=px,y=py} + ania.x,anib.x=anib.x,ania.x + ania.y,anib.y=anib.y,ania.y + grabbed=nil + killall(kills) + return + else + board[ix][iy],board[px][py]= + board[px][py],board[ix][iy] + end + end + grabbed=nil + smtar(ix,iy,ix,iy) + if px then + smtar(px,py,px,py) + end + return + end +end + +local gacc=50 + +-- i forgor how intersections work so here's a thingy to figure it out +-- A1-----A2 +-- B1-----B2 +-- +-- B1-----B2 +-- A1-----A2 + +local function inters(a1,a2,b1,b2) + return + (a1<=b1 and a2>=b1) + or (b1<=a1 and b2>=a1) +end + +local function negdiff(a,b) + return math.abs(a-b)<0.01 +end + +local function sign(a) + return a>0 and 1 or (a<0 and -1 or 0) +end + +local function interp(a,b,dt) + return a+sign(b-a)*math.min((b-a)*sign(b-a),math.max(dt,(b-a)*sign(b-a)*math.max(dt,0.01)*10)) +end + +local animc=0 +local entc=0 +local boomc=0 +local slow=false +local accumdt=0 +local tps=120 + +function love.update(dt) + dt=math.min(dt,0.2)*(slow and 0.05 or 1) + accumdt=accumdt+dt + local fcc=0 + while accumdt>1/tps do + fcc=fcc+1 + local dt=1/tps + accumdt=accumdt-dt + if fcc>10 then return end + if running then + bat=math.max(0,bat-dt*0.015*(math.max(bat,0.0625)^0.5)) + end + if running then + batd=interp(batd,bat,dt) + scored=interp(scored,score,dt) + end + if bat==0 and not dying then + dying=true + dropall(0,true) + end + if grabbed then + local x,y,ox,oy,px,py=unpack(grabbed) + local mx,my=love.mouse.getPosition() + mx,my=trans:inverseTransformPoint(mx,my) + mx,my=mx+1-0.5+ox,my+1-0.5+oy + mx,my=math.floor(mx+.5),math.floor(my+.5) + if math.abs(x-mx)>math.abs(y-my) then + mx,my=math.min(bw,math.max(1,x+sign(mx-x))),y + elseif math.abs(y-my)>0 then + my,mx=math.min(bh,math.max(1,y+sign(my-y))),x + end + if px then + smtar(px,py,px,py) + end + grabbed[5],grabbed[6]=mx,my + if not board[x][y] then + elseif board[mx][my] then + smtar(mx,my,x,y) + smtar(x,y,mx,my) + end + end + animc=0 + entc=0 + boomc=0 + for k,v in pairs(anims) do + animc=animc+1 + v.cx=interp(v.cx,v.tx,dt*2) + v.cy=interp(v.cy,v.ty,dt*2) + if negdiff(v.cx,v.x) and negdiff(v.cy,v.y) then + anims[k]=nil + end + end + local tk={} + if running then + for x,falling in ipairs(falling) do + for fall,_ in pairs(falling) do + entc=entc+1 + fall.vel=fall.vel+dt*gacc + fall.y=fall.y+fall.vel*dt + local iy=math.floor(fall.y) + for fallb,_ in pairs(falling) do + if fall~=fallb and inters( + fall.y-#fall.figs+1-0.5,fall.y+0.5, + fallb.y-#fallb.figs+1-0.5,fallb.y+0.5 + ) and fall.die==fallb.die then + local wa,wb=#fall.figs,#fallb.figs + fall.vel=(fall.vel*wa+fallb.vel*wb)/(wa+wb) + if fallb.y=bh} or {iy>=bh+#fall.figs})[1] then + falling[fall]=nil + if not fall.die then + local off=math.min(iy,bh) + for i,fig in ipairs(fall.figs) do + while board[x][off] do + off=off-1 + end + if off<=bh and off>=1 then + board[x][off]=fig + end + off=off-1 + end + for i=off+1,off+#fall.figs do + tk[#tk+1]={x,i} + end + end + end + end + end + end + if entc==0 and dying then + dying=false + running=false + fillboard() + end + local oam,obm,rm={},{},{} + for k,v in pairs(tk) do + local x,y=unpack(v) + check(x,y,rm,oam,obm) + end + killall(rm) + for v,_ in pairs(booms) do + boomc=boomc+1 + v.a=v.a-dt/math.abs(v.a)*4 + if v.a<=0.01 then + booms[v]=nil + end + end + tt=tt+dt + end +end + +local yes=true + +function love.keypressed(k) + local x,y=love.mouse.getPosition() + x,y=trans:inverseTransformPoint(x,y) + x,y=math.floor(x)+1,math.floor(y)+1 + x=math.max(1,math.min(bw,x)) + y=math.max(1,math.min(bh,y)) + if dbg and tonumber(k) then + print(gobjs[tonumber(k)],tonumber(k)) + board[x][y]=gobjs[tonumber(k)] or board[x][y] + end + if dbg and isgem(board[x][y]) then + local c=board[x][y].c + if k=="h" then + board[x][y]=cgobjs[c] + elseif k=="j" then + board[x][y]=lgobjs[c] + elseif k=="k" then + board[x][y]=mgobjs[c] + end + end + if k=="f2" then + yes=not yes + elseif k=="f3" then + dbg=not dbg + elseif k=="f4" then + local unfell={} + local yls={} + local cx=x + for x=1,bw do + local yl + for y=bh,0,-1 do + if not board[x][y] then + yl=y + break + end + end + unfell[x]={} + local tt={} + for k,v in pairs(falling[x]) do + tt[#tt+1]=k + end + table.sort(tt,function(a,b) + return a.y>b.y + end) + for _,fall in ipairs(tt) do + falling[x][fall]=nil + for k,v in ipairs(fall.figs) do + unfell[x][yl]={board[x][yl]} + board[x][yl]=v + yl=yl-1 + end + end + yls[x]=yl + end + elseif k=="f5" then + slow=not slow + elseif k=="f7" then + falltest=not falltest + elseif k=="f8" then + bat=bat*0.25 + end +end + +function love.draw() + if dbg then + g.push("all") + g.scale(2,2) + love.graphics.print(("FPS: %i; dt: %.2f; anims: %i; fallings: %i; booms: %i"):format( + love.timer.getFPS(), + math.floor(love.timer.getDelta()*100000)/100, + animc, entc, boomc + )) + g.pop() + end + local sw,sh=g.getDimensions() + local ww=math.min(sw,sh) + local y + if falltest then + ww=math.min(sw,sh)*0.5 + y=(sh)/2 + end + local x,y=(sw-ww)/2,y or (sh-ww)/2 + setbsize(x+ww*0.1,y+ww*0.1+ww/bh*0.2,ww*0.8,ww*0.8) + if yes then + drawboard() + end +end