123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285 |
- -- Based on https://github.com/minetest-mods/homedecor_modpack/blob/master/computer/tetris.lua
- local shapes = {
- { { x = {0, 1, 0, 1}, y = {0, 0, 1, 1} } },
- { { x = {1, 1, 1, 1}, y = {0, 1, 2, 3} },
- { x = {0, 1, 2, 3}, y = {1, 1, 1, 1} } },
- { { x = {0, 0, 1, 1}, y = {0, 1, 1, 2} },
- { x = {1, 2, 0, 1}, y = {0, 0, 1, 1} } },
- { { x = {1, 0, 1, 0}, y = {0, 1, 1, 2} },
- { x = {0, 1, 1, 2}, y = {0, 0, 1, 1} } },
- { { x = {1, 2, 1, 1}, y = {0, 0, 1, 2} },
- { x = {0, 1, 2, 2}, y = {1, 1, 1, 2} },
- { x = {1, 1, 0, 1}, y = {0, 1, 2, 2} },
- { x = {0, 0, 1, 2}, y = {0, 1, 1, 1} } },
- { { x = {1, 1, 1, 2}, y = {0, 1, 2, 2} },
- { x = {0, 1, 2, 0}, y = {1, 1, 1, 2} },
- { x = {0, 1, 1, 1}, y = {0, 0, 1, 2} },
- { x = {0, 1, 2, 2}, y = {1, 1, 1, 0} } },
- { { x = {1, 0, 1, 2}, y = {0, 1, 1, 1} },
- { x = {1, 1, 1, 2}, y = {0, 1, 2, 1} },
- { x = {0, 1, 2, 1}, y = {1, 1, 1, 2} },
- { x = {0, 1, 1, 1}, y = {1, 0, 1, 2} } } }
- local base_color_texture = "laptop_tetris_block.png"
- local base_color_alpha = '128'
- local colors = { base_color_texture.."^[colorize:#00FFFF:"..base_color_alpha, base_color_texture.."^[colorize:#FF00FF:"..base_color_alpha, base_color_texture.."^[colorize:#FF0000:"..base_color_alpha,
- base_color_texture.."^[colorize:#0000FF:"..base_color_alpha, base_color_texture.."^[colorize:#00FF00:"..base_color_alpha, base_color_texture.."^[colorize:#FF4500:"..base_color_alpha,
- base_color_texture.."^[colorize:#FFFF00:"..base_color_alpha }
- local boardx, boardy = 0, 0
- local sizex, sizey, size = 0.42, 0.44, 0.47
- local comma = ","
- local semi = ";"
- local close = "]"
- local concat = table.concat
- local insert = table.insert
- local tetris_class = {}
- tetris_class.__index = tetris_class
- local function get_tetris(app, data)
- local self = setmetatable({}, tetris_class)
- self.data = data
- self.app = app
- return self
- end
- function tetris_class:new_game()
- local nex = math.random(7)
- self.data.t = {
- board = {},
- boardstring = "",
- previewstring = self:draw_shape(nex, 0, 0, 1, 6.5, 0.8),
- score = 0,
- cur = math.random(7),
- nex = nex,
- x=4, y=0, rot=1
- }
- self.app:get_timer():start(0.3)
- end
- function tetris_class:update_boardstring()
- local scr = {}
- local ins = #scr
- local fixed_color
- if self.app.os.theme.monochrome_textcolor then
- fixed_color = base_color_texture.."^[colorize:"..
- self.app.os.theme.monochrome_textcolor..
- ":"..base_color_alpha
- end
- for i, line in pairs(self.data.t.board) do
- for _, tile in pairs(line) do
- local tmp = { "image[",
- tile[1]*sizex+boardx, comma,
- i*sizey+boardy, semi,
- size, comma, size, semi,
- fixed_color or colors[tile[2]], close }
- ins = ins + 1
- scr[ins] = concat(tmp)
- end
- end
- self.data.t.boardstring = concat(scr)
- end
- function tetris_class:add()
- local t = self.data.t
- local d = shapes[t.cur][t.rot]
- for i=1,4 do
- local l = d.y[i] + t.y
- if not t.board[l] then t.board[l] = {} end
- insert(t.board[l], {d.x[i] + t.x, t.cur})
- end
- end
- function tetris_class:scroll(l)
- for i=l, 1, -1 do
- self.data.t.board[i] = self.data.t.board[i-1] or {}
- end
- end
- function tetris_class:check_lines()
- for i, line in pairs(self.data.t.board) do
- if #line >= 10 then
- self:scroll(i)
- self.data.t.score = self.data.t.score + 20
- end
- end
- end
- function tetris_class:check_position(x, y, rot)
- local d = shapes[self.data.t.cur][rot]
- for i=1,4 do
- local cx, cy = d.x[i]+x, d.y[i]+y
- if cx < 0 or cx > 9 or cy < 0 or cy > 19 then
- return false
- end
- for _, tile in pairs(self.data.t.board[ cy ] or {}) do
- if tile[1] == cx then return false end
- end
- end
- return true
- end
- function tetris_class:stuck()
- local t = self.data.t
- if self:check_position(t.x, t.y+1, t.rot) then
- return false
- else
- return true
- end
- end
- function tetris_class:tick()
- local t = self.data.t
- if self:stuck() then
- if t.y <= 0 then
- return false
- end
- self:add()
- self:check_lines()
- self:update_boardstring()
- t.cur, t.nex = t.nex, math.random(7)
- t.x, t.y, t.rot = 4, 0, 1
- t.previewstring = self:draw_shape(t.nex, 0, 0, 1, 6.5, 0.8)
- else
- t.y = t.y + 1
- end
- return true
- end
- function tetris_class:move(dx, dy)
- local t = self.data.t
- local newx, newy = t.x+dx, t.y+dy
- if not self:check_position(newx, newy, t.rot) then
- return
- end
- t.x, t.y = newx, newy
- end
- function tetris_class:rotate(dr)
- local t = self.data.t
- local no = #(shapes[t.cur])
- local newrot = (t.rot+dr) % no
- if newrot<1 then newrot = newrot+no end
- if not self:check_position(t.x, t.y, newrot) then
- return
- end
- t.rot = newrot
- end
- function tetris_class:key(fields)
- local t = self.data.t
- if fields.left then
- self:move(-1, 0)
- end
- if fields.rotateleft then
- self:rotate(-1)
- end
- if fields.down then
- t.score = t.score + 1
- self:move(0, 1)
- end
- if fields.drop then
- while not self:stuck() do
- t.score = t.score + 2
- self:move(0, 1)
- end
- end
- if fields.rotateright then
- self:rotate(1)
- end
- if fields.right then
- self:move(1, 0)
- end
- end
- function tetris_class:draw_shape(id, x, y, rot, posx, posy)
- local d = shapes[id][rot]
- local scr = {}
- local ins = #scr
- local color = colors[id]
- if self.app.os.theme.monochrome_textcolor then
- color = base_color_texture.."^[colorize:"..
- self.app.os.theme.monochrome_textcolor..
- ":"..base_color_alpha
- end
- for i=1,4 do
- local tmp = { "image[",
- (d.x[i]+x)*sizex+posx, comma,
- (d.y[i]+y)*sizey+posy, semi,
- size, comma, size, semi,
- color, close }
- ins = ins + 1
- scr[ins] = concat(tmp)
- end
- return concat(scr)
- end
- laptop.register_app("tetris", {
- app_name = "Tetris",
- app_icon = "laptop_tetris_icon.png",
- app_info = "Falling Tile Game",
- formspec_func = function(app, mtos)
- local data = mtos.bdev:get_app_storage('ram', 'tetris')
- local tetris = get_tetris(app, data)
- if not data.t then
- return mtos.theme:get_button('2,4;2,2', 'major', 'new', 'New Game', 'Start a new game')
- end
- local buttons = mtos.theme:get_button('6,6;1,1', 'minor', 'left', '<')..
- mtos.theme:get_button('6,5;1,1', 'minor', 'rotateleft', 'L')..
- mtos.theme:get_button('7,5;1,1', 'minor', 'down', 'v')..
- mtos.theme:get_button('7,6;1,1', 'minor', 'drop', 'V')..
- mtos.theme:get_button('8,5;1,1', 'minor', 'rotateright', 'R')..
- mtos.theme:get_button('8,6;1,1', 'minor', 'right', '>')..
- mtos.theme:get_button('6,3.5;3,1', 'major', 'new', 'New Game', 'Start a new game')
- local t = tetris.data.t
- return 'container[3,1]background[0,-0.05;4.35,9;'.. mtos.theme.contrast_background .. ']' ..
- t.boardstring .. t.previewstring ..
- tetris:draw_shape(t.cur, t.x, t.y, t.rot, boardx, boardy) ..
- mtos.theme:get_label('6.5,0.1', 'Next...') ..
- mtos.theme:get_label('6.5,2.7', 'Score:...'..t.score) ..
- buttons .. 'container_end[]'
- end,
- receive_fields_func = function(app, mtos, sender, fields)
- local data = mtos.bdev:get_app_storage('ram', 'tetris')
- local tetris = get_tetris(app, data)
- if fields.new then
- tetris:new_game()
- elseif fields.continue then
- app:get_timer():start(0.3)
- else
- tetris:key(fields)
- end
- end,
- on_timer = function(app, mtos)
- local data = mtos.bdev:get_app_storage('ram', 'tetris')
- if not data.t then
- return false
- else
- return get_tetris(app, data):tick()
- end
- end,
- })
|