Skip to content

Instantly share code, notes, and snippets.

@x4fx77x4f
Created October 20, 2020 07:49
Show Gist options
  • Save x4fx77x4f/4cb61ea0d46067d93238448ec2b381c9 to your computer and use it in GitHub Desktop.
Save x4fx77x4f/4cb61ea0d46067d93238448ec2b381c9 to your computer and use it in GitHub Desktop.
Minesweeper in StarfallEx. State is not kept in sync across clients.
--@name Minesweeper
--@author x4fx77x4f
--@client
local hook_add = hook.add
local hook_remove = hook.remove
local IN_KEY_USE = IN_KEY.USE
local IN_KEY_ATTACK = IN_KEY.ATTACK
local IN_KEY_ATTACK2 = IN_KEY.ATTACK2
local material_create = material.create
local math_floor = math.floor
local math_random = math.random
local render_createRenderTarget = render.createRenderTarget
local render_drawRect = render.drawRect
local render_drawTexturedRectUV = render.drawTexturedRectUV
local render_cursorPos = render.cursorPos
local render_selectRenderTarget = render.selectRenderTarget
local render_setFilterMag = render.setFilterMag
local render_setRenderTargetTexture = render.setRenderTargetTexture
local render_setMaterial = render.setMaterial
local timer_systime = timer.systime
local tostring = tostring
local unpack = unpack
local texture = material_create("UnlitGeneric")
texture:setTextureURL("$basetexture", "https://i.imgur.com/O0vf4Fa.png", function()
local atlas = {
[0] = {0.046875, 0, 0.0625, 0.015625},
[1] = {0, 0.015625, 0.015625, 0.03125},
[2] = {0.015625, 0.015625, 0.03125, 0.03125},
[3] = {0.03125, 0.015625, 0.046875, 0.03125},
[4] = {0.046875, 0.015625, 0.0625, 0.03125},
[5] = {0, 0.03125, 0.015625, 0.046875},
[6] = {0.015625, 0.03125, 0.03125, 0.046875},
[7] = {0.03125, 0.03125, 0.046875, 0.046875},
[8] = {0.046875, 0.03125, 0.0625, 0.046875}
}
local w = 16
local h = 16
local mn = 40
local field1 = {}
local field2 = {}
local function init()
for y=1, h do
local row1 = {}
local row2 = {}
for x=1, w do
row1[x] = 0
row2[x] = 1
end
field1[y] = row1
field2[y] = row2
end
for m=1, mn do
local mx, my
repeat
mx, my = math_random(1, w), math_random(1, h)
until field1[my][mx] >= 0
if my > 1 then
local row1 = field1[my-1]
if mx > 1 then
row1[mx-1] = row1[mx-1]+1
end
row1[mx] = row1[mx]+1
if mx < w then
row1[mx+1] = row1[mx+1]+1
end
end
local row2 = field1[my]
if mx > 1 then
row2[mx-1] = row2[mx-1]+1
end
row2[mx] = -mn
if mx < w then
row2[mx+1] = row2[mx+1]+1
end
if my < h then
local row3 = field1[my+1]
if mx > 1 then
row3[mx-1] = row3[mx-1]+1
end
row3[mx] = row3[mx]+1
if mx < w then
row3[mx+1] = row3[mx+1]+1
end
end
end
end
init()
local mw = 512/w
local mh = 512/h
local mw2 = mw/2
local mh2 = mh/2
local cx, cy
local updatePending = true
render_createRenderTarget("main")
hook_add("render", "", function()
cx, cy = render_cursorPos()
render_setFilterMag(1)
if updatePending then
render_selectRenderTarget("main")
render_setMaterial(texture)
for y=1, h do
local row1 = field1[y]
local row2 = field2[y]
for x=1, w do
local mx = x*mw-mw
local my = y*mh-mh
local state = row2[x]
if state == 0 then
if row1[x] < 0 then
render_drawTexturedRectUV(mx, my, mw, mh, 0.03125, 0, 0.046875, 0.015625)
else
render_drawTexturedRectUV(mx, my, mw, mh, unpack(atlas[row1[x]]))
end
elseif state == 1 then
render_drawTexturedRectUV(mx, my, mw, mh, 0, 0, 0.015625, 0.015625)
else
render_drawTexturedRectUV(mx, my, mw, mh, 0.015625, 0, 0.03125, 0.015625)
end
end
end
updatePending = false
render_selectRenderTarget()
end
render_setRenderTargetTexture("main")
render_drawTexturedRectUV(0, 0, 512, 512, 0, 0, 0.5, 0.5)
end)
local seen = {}
for y=1, h do
seen[y] = {}
end
local function traverse(x, y)
if x < 1 or y < 1 or x > w or y > h or seen[y][x] then
return
end
seen[y][x] = true
field2[y][x] = 0
if field1[y][x] == 0 then
traverse(x, y-1)
traverse(x+1, y-1)
traverse(x+1, y)
traverse(x+1, y+1)
traverse(x, y+1)
traverse(x-1, y+1)
traverse(x-1, y)
traverse(x-1, y-1)
end
end
local lost = false
local lastTime = 0
hook_add("keyPress", "", function(ply, key)
if not cx then
return
end
local now = timer_systime()
if now-lastTime < 0.1 then
return
end
lastTime = now
local mode
if key == IN_KEY_ATTACK or key == IN_KEY_USE then
mode = 0
if lost then
init()
lost = false
updatePending = true
return
end
elseif key == IN_KEY_ATTACK2 then
mode = 2
else
return
end
updatePending = true
local x, y = math_floor(cx/512*w)+1, math_floor(cy/512*h)+1
if mode == 2 then
local row = field2[y]
if row[x] == 1 then
row[x] = 2
elseif row[x] == 2 then
row[x] = 1
end
elseif field2[y][x] ~= 2 then
local m = field1[y][x]
if m < 0 then
for y=1, h do
local row = field2[y]
for x=1, w do
row[x] = 0
end
end
lost = true
elseif m == 0 then
for y=1, h do
seen[y] = {}
end
traverse(x, y)
else
field2[y][x] = mode
end
end
end)
end)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment