tetris.lua 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. local S = minetest.get_translator("computer")
  2. local shapes = {
  3. { { x = {0, 1, 0, 1}, y = {0, 0, 1, 1} } },
  4. { { x = {1, 1, 1, 1}, y = {0, 1, 2, 3} },
  5. { x = {0, 1, 2, 3}, y = {1, 1, 1, 1} } },
  6. { { x = {0, 0, 1, 1}, y = {0, 1, 1, 2} },
  7. { x = {1, 2, 0, 1}, y = {0, 0, 1, 1} } },
  8. { { x = {1, 0, 1, 0}, y = {0, 1, 1, 2} },
  9. { x = {0, 1, 1, 2}, y = {0, 0, 1, 1} } },
  10. { { x = {1, 2, 1, 1}, y = {0, 0, 1, 2} },
  11. { x = {0, 1, 2, 2}, y = {1, 1, 1, 2} },
  12. { x = {1, 1, 0, 1}, y = {0, 1, 2, 2} },
  13. { x = {0, 0, 1, 2}, y = {0, 1, 1, 1} } },
  14. { { x = {1, 1, 1, 2}, y = {0, 1, 2, 2} },
  15. { x = {0, 1, 2, 0}, y = {1, 1, 1, 2} },
  16. { x = {0, 1, 1, 1}, y = {0, 0, 1, 2} },
  17. { x = {0, 1, 2, 2}, y = {1, 1, 1, 0} } },
  18. { { x = {1, 0, 1, 2}, y = {0, 1, 1, 1} },
  19. { x = {1, 1, 1, 2}, y = {0, 1, 2, 1} },
  20. { x = {0, 1, 2, 1}, y = {1, 1, 1, 2} },
  21. { x = {0, 1, 1, 1}, y = {1, 0, 1, 2} } } }
  22. local colors = { "computer_cyan.png", "computer_magenta.png", "computer_red.png",
  23. "computer_blue.png", "computer_green.png", "computer_orange.png", "computer_yellow.png" }
  24. local background = "image[0,0;3.55,6.66;computer_black.png]"
  25. local buttons = "button[3,4.5;0.6,0.6;left;<]"
  26. .."button[3.6,4.5;0.6,0.6;rotateleft;"..minetest.formspec_escape(S("L")).."]"
  27. .."button[4.2,4.5;0.6,0.6;down;v]"
  28. .."button[4.2,5.3;0.6,0.6;drop;V]"
  29. .."button[4.8,4.5;0.6,0.6;rotateright;"..minetest.formspec_escape(S("R")).."]"
  30. .."button[5.4,4.5;0.6,0.6;right;>]"
  31. .."button[3.5,3;2,2;new;"..minetest.formspec_escape(S("New Game")).."]"
  32. local formsize = "size[5.9,5.7]"
  33. local boardx, boardy = 0, 0
  34. local sizex, sizey, size = 0.29, 0.29, 0.31
  35. local comma = ","
  36. local semi = ";"
  37. local close = "]"
  38. local concat = table.concat
  39. local insert = table.insert
  40. local draw_shape = function(id, x, y, rot, posx, posy)
  41. local d = shapes[id][rot]
  42. local scr = {}
  43. local ins = #scr
  44. for i=1,4 do
  45. local tmp = { "image[",
  46. (d.x[i]+x)*sizex+posx, comma,
  47. (d.y[i]+y)*sizey+posy, semi,
  48. size, comma, size, semi,
  49. colors[id], close }
  50. ins = ins + 1
  51. scr[ins] = concat(tmp)
  52. end
  53. return concat(scr)
  54. end
  55. local function step(pos, fields)
  56. local meta = minetest.get_meta(pos)
  57. local t = minetest.deserialize(meta:get_string("tetris"))
  58. local function new_game(p)
  59. local nex = math.random(7)
  60. t = {
  61. board = {},
  62. boardstring = "",
  63. previewstring = draw_shape(nex, 0, 0, 1, 4, 1),
  64. score = 0,
  65. cur = math.random(7),
  66. nex = nex,
  67. x=4, y=0, rot=1
  68. }
  69. local timer = minetest.get_node_timer(p)
  70. timer:set(0.3, 0)
  71. end
  72. local function update_boardstring()
  73. local scr = {}
  74. local ins = #scr
  75. for i, line in pairs(t.board) do
  76. for _, tile in pairs(line) do
  77. local tmp = { "image[",
  78. tile[1]*sizex+boardx, comma,
  79. i*sizey+boardy, semi,
  80. size, comma, size, semi,
  81. colors[tile[2]], close }
  82. ins = ins + 1
  83. scr[ins] = concat(tmp)
  84. end
  85. end
  86. t.boardstring = concat(scr)
  87. end
  88. local function add()
  89. local d = shapes[t.cur][t.rot]
  90. for i=1,4 do
  91. local l = d.y[i] + t.y
  92. if not t.board[l] then t.board[l] = {} end
  93. insert(t.board[l], {d.x[i] + t.x, t.cur})
  94. end
  95. end
  96. local function scroll(l)
  97. for i=l, 1, -1 do
  98. t.board[i] = t.board[i-1] or {}
  99. end
  100. end
  101. local function check_lines()
  102. for i, line in pairs(t.board) do
  103. if #line >= 10 then
  104. scroll(i)
  105. t.score = t.score + 20
  106. end
  107. end
  108. end
  109. local function check_position(x, y, rot)
  110. local d = shapes[t.cur][rot]
  111. for i=1,4 do
  112. local cx, cy = d.x[i]+x, d.y[i]+y
  113. if cx < 0 or cx > 9 or cy < 0 or cy > 19 then
  114. return false
  115. end
  116. for _, tile in pairs(t.board[ cy ] or {}) do
  117. if tile[1] == cx then return false end
  118. end
  119. end
  120. return true
  121. end
  122. local function stuck()
  123. if check_position(t.x, t.y+1, t.rot) then return false end
  124. return true
  125. end
  126. local function tick()
  127. if stuck() then
  128. if t.y <= 0 then
  129. return false end
  130. add()
  131. check_lines()
  132. update_boardstring()
  133. t.cur, t.nex = t.nex, math.random(7)
  134. t.x, t.y, t.rot = 4, 0, 1
  135. t.previewstring = draw_shape(t.nex, 0, 0, 1, 4.1, 0.6)
  136. else
  137. t.y = t.y + 1
  138. end
  139. return true
  140. end
  141. local function move(dx, dy)
  142. local newx, newy = t.x+dx, t.y+dy
  143. if not check_position(newx, newy, t.rot) then return end
  144. t.x, t.y = newx, newy
  145. end
  146. local function rotate(dr)
  147. local no = #(shapes[t.cur])
  148. local newrot = (t.rot+dr) % no
  149. if newrot<1 then newrot = newrot+no end
  150. if not check_position(t.x, t.y, newrot) then return end
  151. t.rot = newrot
  152. end
  153. local function key()
  154. if fields.left then
  155. move(-1, 0)
  156. end
  157. if fields.rotateleft then
  158. rotate(-1)
  159. end
  160. if fields.down then
  161. t.score = t.score + 1
  162. move(0, 1)
  163. end
  164. if fields.drop then
  165. while not stuck() do
  166. t.score = t.score + 2
  167. move(0, 1)
  168. end
  169. end
  170. if fields.rotateright then
  171. rotate(1)
  172. end
  173. if fields.right then
  174. move(1, 0)
  175. end
  176. end
  177. local run = true
  178. if fields then
  179. if fields.new then
  180. new_game(pos)
  181. elseif t then
  182. key(fields)
  183. end
  184. elseif t then
  185. run = tick()
  186. end
  187. if t then
  188. local scr = { formsize, background,
  189. t.boardstring, t.previewstring,
  190. draw_shape(t.cur, t.x, t.y, t.rot, boardx, boardy),
  191. "label[3.8,0.1;"..S("Next...").."]label[3.8,2.7;"..S("Score: "),
  192. t.score, close, buttons }
  193. meta:set_string("formspec", concat(scr)
  194. ..default.gui_bg..default.gui_bg_img..default.gui_slots)
  195. meta:set_string("tetris", minetest.serialize(t))
  196. end
  197. return run
  198. end
  199. minetest.register_node("computer:tetris_arcade", {
  200. description=S("Tetris Arcade"),
  201. drawtype = "mesh",
  202. mesh = "tetris_arcade.obj",
  203. tiles = {"tetris_arcade.png"},
  204. paramtype = "light",
  205. paramtype2 = "facedir",
  206. groups = {snappy=3},
  207. on_rotate = minetest.get_modpath("screwdriver") and screwdriver.rotate_simple or nil,
  208. selection_box = {
  209. type = "fixed",
  210. fixed = {-0.5, -0.5, -0.5, 0.5, 1.5, 0.5}
  211. },
  212. collision_box = {
  213. type = "fixed",
  214. fixed = {-0.5, -0.5, -0.5, 0.5, 1.5, 0.5}
  215. },
  216. on_construct = function(pos)
  217. local meta = minetest.get_meta(pos)
  218. meta:set_string("formspec", formsize
  219. .."button[2,2.5;2,2;new;"..minetest.formspec_escape(S("New Game")).."]"
  220. ..default.gui_bg..default.gui_bg_img..default.gui_slots)
  221. end,
  222. on_timer = function(pos)
  223. return step(pos, nil)
  224. end,
  225. on_receive_fields = function(pos, formanme, fields, sender)
  226. step(pos, fields)
  227. end,
  228. on_place = function(itemstack, placer, pointed_thing)
  229. local pos = pointed_thing.above
  230. if minetest.is_protected(pos, placer:get_player_name()) or
  231. minetest.is_protected({x=pos.x, y=pos.y+1, z=pos.z}, placer:get_player_name()) then
  232. return itemstack
  233. end
  234. if minetest.get_node({x=pos.x, y=pos.y+1, z=pos.z}).name ~= "air" then
  235. minetest.chat_send_player(placer:get_player_name(), S("No room for place the Arcade!"))
  236. return itemstack
  237. end
  238. local dir = placer:get_look_dir()
  239. local node = {name="computer:tetris_arcade", param1=0, param2 = minetest.dir_to_facedir(dir)}
  240. minetest.set_node(pos, node)
  241. itemstack:take_item()
  242. return itemstack
  243. end
  244. })