Guest User

falling.lua

a guest
Sep 25th, 2024
29
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 15.92 KB | None | 0 0
  1. -- SPDX-FileCopyrightText: 2017 Daniel Ratcliffe
  2. --
  3. -- SPDX-License-Identifier: LicenseRef-CCPL
  4.  
  5. --[[
  6. Falling - Based on Tetris by Alexey Pajitnov
  7. This version written by Gopher, at the request of Dan200, for
  8. ComputerCraft v1.6. No particular rights are reserved.
  9. --]]
  10.  
  11. local function colorass(c, bw)
  12.   return term.isColor() and c or bw
  13. end
  14.  
  15. local block_s1 = {
  16.     {
  17.       { 1, 0, 0, 0 },
  18.       { 1, 1, 0, 0 },
  19.       { 0, 1, 0, 0 },
  20.       { 0, 0, 0, 0 },
  21.     },
  22.     {
  23.       { 0, 0, 0, 0 },
  24.       { 0, 1, 1, 0 },
  25.       { 1, 1, 0, 0 },
  26.       { 0, 0, 0, 0 },
  27.     },
  28.     ch = colorass("  ", "{}"),
  29.     fg = colorass(colors.blue, colors.black),
  30.     bg = colorass(colors.cyan, colors.white),
  31.   }
  32. local block_s2 = {
  33.     {
  34.       { 0, 1, 0, 0 },
  35.       { 1, 1, 0, 0 },
  36.       { 1, 0, 0, 0 },
  37.       { 0, 0, 0, 0 },
  38.     },
  39.     {
  40.       { 0, 0, 0, 0 },
  41.       { 1, 1, 0, 0 },
  42.       { 0, 1, 1, 0 },
  43.       { 0, 0, 0, 0 },
  44.     },
  45.     ch = colorass("  ", "{}"),
  46.     fg = colorass(colors.green, colors.black),
  47.     bg = colorass(colors.lime, colors.white),
  48.   }
  49. local block_line = {
  50.     {
  51.       { 0, 1, 0, 0 },
  52.       { 0, 1, 0, 0 },
  53.       { 0, 1, 0, 0 },
  54.       { 0, 1, 0, 0 },
  55.     },
  56.     {
  57.       { 0, 0, 0, 0 },
  58.       { 1, 1, 1, 1 },
  59.       { 0, 0, 0, 0 },
  60.       { 0, 0, 0, 0 },
  61.     },
  62.     ch = colorass("  ", "[]"),
  63.     fg = colorass(colors.pink, colors.black),
  64.     bg = colorass(colors.red, colors.white),
  65.   }
  66. local block_square = {
  67.     {
  68.       { 1, 1, 0, 0 },
  69.       { 1, 1, 0, 0 },
  70.       { 0, 0, 0, 0 },
  71.       { 0, 0, 0, 0 },
  72.     },
  73.     ch = colorass("  ", "[]"),
  74.     fg = colorass(colors.lightBlue, colors.black),
  75.     bg = colorass(colors.blue, colors.white),
  76.   }
  77. local block_L1 = {
  78.     {
  79.       { 1, 1, 0, 0 },
  80.       { 0, 1, 0, 0 },
  81.       { 0, 1, 0, 0 },
  82.       { 0, 0, 0, 0 },
  83.     },
  84.     {
  85.       { 0, 0, 0, 0 },
  86.       { 1, 1, 1, 0 },
  87.       { 1, 0, 0, 0 },
  88.       { 0, 0, 0, 0 },
  89.     },
  90.     {
  91.       { 0, 1, 0, 0 },
  92.       { 0, 1, 0, 0 },
  93.       { 0, 1, 1, 0 },
  94.       { 0, 0, 0, 0 },
  95.     },
  96.     {
  97.       { 0, 0, 1, 0 },
  98.       { 1, 1, 1, 0 },
  99.       { 0, 0, 0, 0 },
  100.       { 0, 0, 0, 0 },
  101.     },
  102.     ch = colorass("  ", "()"),
  103.     fg = colorass(colors.orange, colors.black),
  104.     bg = colorass(colors.yellow, colors.white),
  105.   }
  106. local block_L2 = {
  107.     {
  108.       { 0, 1, 0, 0 },
  109.       { 0, 1, 0, 0 },
  110.       { 1, 1, 0, 0 },
  111.       { 0, 0, 0, 0 },
  112.     },
  113.     {
  114.       { 0, 0, 0, 0 },
  115.       { 1, 1, 1, 0 },
  116.       { 0, 0, 1, 0 },
  117.       { 0, 0, 0, 0 },
  118.     },
  119.     {
  120.       { 0, 1, 1, 0 },
  121.       { 0, 1, 0, 0 },
  122.       { 0, 1, 0, 0 },
  123.       { 0, 0, 0, 0 },
  124.     },
  125.     {
  126.       { 1, 0, 0, 0 },
  127.       { 1, 1, 1, 0 },
  128.       { 0, 0, 0, 0 },
  129.       { 0, 0, 0, 0 },
  130.     },
  131.     ch = colorass("  ", "()"),
  132.     fg = colorass(colors.brown, colors.black),
  133.     bg = colorass(colors.orange, colors.white),
  134.   }
  135. local block_T = {
  136.     {
  137.       { 0, 1, 0, 0 },
  138.       { 1, 1, 0, 0 },
  139.       { 0, 1, 0, 0 },
  140.       { 0, 0, 0, 0 },
  141.     },
  142.     {
  143.       { 0, 0, 0, 0 },
  144.       { 1, 1, 1, 0 },
  145.       { 0, 1, 0, 0 },
  146.       { 0, 0, 0, 0 },
  147.     },
  148.     {
  149.       { 0, 1, 0, 0 },
  150.       { 0, 1, 1, 0 },
  151.       { 0, 1, 0, 0 },
  152.       { 0, 0, 0, 0 },
  153.     },
  154.     {
  155.       { 0, 1, 0, 0 },
  156.       { 1, 1, 1, 0 },
  157.       { 0, 0, 0, 0 },
  158.       { 0, 0, 0, 0 },
  159.     },
  160.     ch = colorass("  ", "<>"),
  161.     fg = colorass(colors.cyan, colors.black),
  162.     bg = colorass(colors.purple, colors.white),
  163.   }
  164.  
  165. local blocks = { block_line, block_square, block_s1, block_s2, block_L1, block_L2, block_T }
  166.  
  167. local points = { 4, 10, 30, 120 }
  168.  
  169. local function lpad(text, amt)
  170.   text = tostring(text)
  171.   return string.rep(" ", amt - #text) .. text
  172. end
  173.  
  174. local width, height = term.getSize()
  175.  
  176. if height < 19 or width < 26 then
  177.   print("Your screen is too small to play :(")
  178.   return
  179. end
  180.  
  181.  
  182. local speedsByLevel = {
  183.   1.2,
  184.   1.0,
  185.    .8,
  186.    .65,
  187.    .5,
  188.    .4,
  189.    .3,
  190.    .25,
  191.    .2,
  192.    .15,
  193.    .1,
  194.    .05, }
  195.  
  196. local level = 1
  197.  
  198. local function playGame()
  199.   local score = 0
  200.   local lines = 0
  201.   local initialLevel = level
  202.   local next = blocks[math.random(1, #blocks)]
  203.  
  204.   local pit = {}
  205.  
  206.  
  207.   local heightAdjust = 0
  208.  
  209.   if height <= 19 then
  210.     heightAdjust = 1
  211.   end
  212.  
  213.  
  214.  
  215.   local function drawScreen()
  216.     term.setTextColor(colors.white)
  217.     term.setBackgroundColor(colors.black)
  218.     term.clear()
  219.  
  220.     term.setTextColor(colors.black)
  221.     term.setBackgroundColor(colorass(colors.lightGray, colors.white))
  222.     term.setCursorPos(22, 2)
  223.     term.write("Score") --score
  224.     term.setCursorPos(22, 5)
  225.     term.write("Level")  --level
  226.     term.setCursorPos(22, 8)
  227.     term.write("Lines")  --lines
  228.     term.setCursorPos(22, 12)
  229.     term.write("Next") --next
  230.  
  231.     term.setCursorPos(21, 1)
  232.     term.write("      ")
  233.     term.setCursorPos(21, 2)
  234.     term.write(" ") --score
  235.     term.setCursorPos(21, 3)
  236.     term.write(" ")
  237.     term.setCursorPos(21, 4)
  238.     term.write("      ")
  239.     term.setCursorPos(21, 5)
  240.     term.write(" ")  --level
  241.     term.setCursorPos(21, 6)
  242.     term.write(" ")
  243.     term.setCursorPos(21, 7)
  244.     term.write("      ")
  245.     term.setCursorPos(21, 8)
  246.     term.write(" ")  --lines
  247.     term.setCursorPos(21, 9)
  248.     term.write(" ")
  249.     term.setCursorPos(21, 10)
  250.     term.write("      ")
  251.     term.setCursorPos(21, 11)
  252.     term.write("      ")
  253.     term.setCursorPos(21, 12)
  254.     term.write(" ") --next
  255.     term.setCursorPos(26, 12)
  256.     term.write(" ") --next
  257.     term.setCursorPos(21, 13)
  258.     term.write("      ")
  259.     term.setCursorPos(21, 14)
  260.     term.write(" ")
  261.     term.setCursorPos(21, 15)
  262.     term.write(" ")
  263.     term.setCursorPos(21, 16)
  264.     term.write(" ")
  265.     term.setCursorPos(21, 17)
  266.     term.write(" ")
  267.     term.setCursorPos(21, 18)
  268.     term.write(" ")
  269.     term.setCursorPos(21, 19)
  270.     term.write("      ")
  271.     term.setCursorPos(21, 20)
  272.     term.write("      ")
  273.   end
  274.  
  275.   local function updateNumbers()
  276.     term.setTextColor(colors.white)
  277.     term.setBackgroundColor(colors.black)
  278.  
  279.     term.setCursorPos(22, 3)
  280.     term.write(lpad(score, 5)) --score
  281.     term.setCursorPos(22, 6)
  282.     term.write(lpad(level, 5))  --level
  283.     term.setCursorPos(22, 9)
  284.     term.write(lpad(lines, 5))  --lines
  285.   end
  286.  
  287.   local function drawBlockAt(block, xp, yp, rot)
  288.     term.setTextColor(block.fg)
  289.     term.setBackgroundColor(block.bg)
  290.     for y = 1, 4 do
  291.       for x = 1, 4 do
  292.         if block[rot][y][x] == 1 then
  293.           term.setCursorPos((xp + x) * 2 - 3, yp + y - 1 - heightAdjust)
  294.           term.write(block.ch)
  295.         end
  296.       end
  297.     end
  298.   end
  299.  
  300.   local function eraseBlockAt(block, xp, yp, rot)
  301.     term.setTextColor(colors.white)
  302.     term.setBackgroundColor(colors.black)
  303.     for y = 1, 4 do
  304.       for x = 1, 4 do
  305.         if block[rot][y][x] == 1 then
  306.           term.setCursorPos((xp + x) * 2 - 3, yp + y - 1 - heightAdjust)
  307.           term.write("  ")
  308.         end
  309.       end
  310.     end
  311.   end
  312.  
  313.   local function testBlockAt(block, xp, yp, rot)
  314.     for y = 1, 4 do
  315.       local ty = yp + y - 1
  316.       for x = 1, 4 do
  317.         local tx = xp + x - 1
  318.         if block[rot][y][x] == 1 then
  319.           if tx > 10 or tx < 1 or ty > 20 or pit[ty][tx] ~= 0 then
  320.             return true
  321.           end
  322.         end
  323.       end
  324.     end
  325.   end
  326.  
  327.   local function pitBlock(block, xp, yp, rot)
  328.     for y = 1, 4 do
  329.       for x = 1, 4 do
  330.         if block[rot][y][x] == 1 then
  331.           pit[yp + y - 1][xp + x - 1] = block
  332.         end
  333.       end
  334.     end
  335.   end
  336.  
  337.  
  338.   local function clearPit()
  339.     for row = 1, 20 do
  340.       pit[row] = {}
  341.       for col = 1, 10 do
  342.         pit[row][col] = 0
  343.       end
  344.     end
  345.   end
  346.  
  347.  
  348.  
  349.   drawScreen()
  350.   updateNumbers()
  351.  
  352.   --declare & init the pit
  353.   clearPit()
  354.  
  355.  
  356.  
  357.   local halt = false
  358.   local dropSpeed = speedsByLevel[math.min(level, 12)]
  359.  
  360.  
  361.   local curBlock = next
  362.   next = blocks[math.random(1, 7)]
  363.  
  364.   local curX, curY, curRot = 4, 1, 1
  365.   local dropTimer = os.startTimer(dropSpeed)
  366.  
  367.   drawBlockAt(next, 11.5, 15 + heightAdjust, 1)
  368.   drawBlockAt(curBlock, curX, curY, curRot)
  369.  
  370.   local function redrawPit()
  371.     for r = 1 + heightAdjust, 20 do
  372.       term.setCursorPos(1, r - heightAdjust)
  373.       for c = 1, 10 do
  374.         if pit[r][c] == 0 then
  375.           term.setTextColor(colors.black)
  376.           term.setBackgroundColor(colors.black)
  377.           term.write("  ")
  378.         else
  379.           term.setTextColor(pit[r][c].fg)
  380.           term.setBackgroundColor(pit[r][c].bg)
  381.           term.write(pit[r][c].ch)
  382.         end
  383.       end
  384.     end
  385.   end
  386.  
  387.   local function hidePit()
  388.     for r = 1 + heightAdjust, 20 do
  389.       term.setCursorPos(1, r - heightAdjust)
  390.       term.setTextColor(colors.black)
  391.       term.setBackgroundColor(colors.black)
  392.       term.write("                    ")
  393.     end
  394.   end
  395.  
  396.   local function msgBox(message)
  397.     local x = math.floor((17 - #message) / 2)
  398.     term.setBackgroundColor(colorass(colors.lightGray, colors.white))
  399.     term.setTextColor(colors.black)
  400.     term.setCursorPos(x, 9)
  401.     term.write("+" .. string.rep("-", #message + 2) .. "+")
  402.     term.setCursorPos(x, 10)
  403.     term.write("|")
  404.     term.setCursorPos(x + #message + 3, 10)
  405.     term.write("|")
  406.     term.setCursorPos(x, 11)
  407.     term.write("+" .. string.rep("-", #message + 2) .. "+")
  408.     term.setTextColor(colors.white)
  409.     term.setBackgroundColor(colors.black)
  410.     term.setCursorPos(x + 1, 10)
  411.     term.write(" " .. message .. " ")
  412.   end
  413.  
  414.   local function clearRows()
  415.     local rows = {}
  416.     for r = 1, 20 do
  417.       local count = 0
  418.       for c = 1, 10 do
  419.         if pit[r][c] ~= 0 then
  420.           count = count + 1
  421.         else
  422.           break
  423.         end
  424.       end
  425.       if count == 10 then
  426.         rows[#rows + 1] = r
  427.       end
  428.     end
  429.  
  430.     if #rows > 0 then
  431.       for _ = 1, 4 do
  432.         sleep(.1)
  433.         for r = 1, #rows do
  434.           r = rows[r]
  435.           term.setCursorPos(1, r - heightAdjust)
  436.           for c = 1, 10 do
  437.             term.setTextColor(pit[r][c].bg)
  438.             term.setBackgroundColor(pit[r][c].fg)
  439.             term.write(pit[r][c].ch)
  440.           end
  441.         end
  442.         sleep(.1)
  443.         for r = 1, #rows do
  444.           r = rows[r]
  445.           term.setCursorPos(1, r - heightAdjust)
  446.           for c = 1, 10 do
  447.             term.setTextColor(pit[r][c].fg)
  448.             term.setBackgroundColor(pit[r][c].bg)
  449.             term.write(pit[r][c].ch)
  450.           end
  451.         end
  452.       end
  453.       --now remove the rows and drop everything else
  454.       term.setBackgroundColor(colors.black)
  455.       for r = 1, #rows do
  456.         r = rows[r]
  457.         term.setCursorPos(1, r - heightAdjust)
  458.         term.write("                    ")
  459.       end
  460.       sleep(.25)
  461.       for r = 1, #rows do
  462.         table.remove(pit, rows[r])
  463.         table.insert(pit, 1, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 })
  464.       end
  465.       redrawPit()
  466.       lines = lines + #rows
  467.       score = score + points[#rows] * math.min(level, 20)
  468.       level = math.floor(lines / 10) + initialLevel
  469.       dropSpeed = speedsByLevel[math.min(level, 12)]
  470.       updateNumbers()
  471.     end
  472.     sleep(.25)
  473.   end
  474.  
  475.   local function blockFall()
  476.     if testBlockAt(curBlock, curX, curY + 1, curRot) then
  477.       pitBlock(curBlock, curX, curY, curRot)
  478.       --detect rows that clear
  479.       clearRows()
  480.  
  481.       curBlock = next
  482.       curX = 4
  483.       curY = 1
  484.       curRot = 1
  485.       if testBlockAt(curBlock, curX, curY, curRot) then
  486.         halt = true
  487.       end
  488.       drawBlockAt(curBlock, curX, curY, curRot)
  489.       eraseBlockAt(next, 11.5, 15 + heightAdjust, 1)
  490.       next = blocks[math.random(1, 7)]
  491.       drawBlockAt(next, 11.5, 15 + heightAdjust, 1)
  492.       return true
  493.     else
  494.       eraseBlockAt(curBlock, curX, curY, curRot)
  495.       curY = curY + 1
  496.       drawBlockAt(curBlock, curX, curY, curRot)
  497.       return false
  498.     end
  499.   end
  500.  
  501.  
  502.   while not halt do
  503.     local e = { os.pullEvent() }
  504.     if e[1] == "timer" then
  505.       if e[2] == dropTimer then
  506.         blockFall()
  507.         dropTimer = os.startTimer(dropSpeed)
  508.       end
  509.     elseif e[1] == "key" then
  510.       local key = e[2]
  511.       local dx, dy, dr = 0, 0, 0
  512.       if key == keys.left or key == keys.a then
  513.         dx = -1
  514.       elseif key == keys.right or key == keys.d then
  515.         dx = 1
  516.       elseif key == keys.up or key == keys.w then
  517.         dr = 1
  518.       elseif key == keys.down or key == keys.s then
  519.         while not blockFall() do end
  520.         dropTimer = os.startTimer(dropSpeed)
  521.       elseif key == keys.space then
  522.         hidePit()
  523.         msgBox("Paused")
  524.         while ({ os.pullEvent("key") })[2] ~= keys.space do end
  525.         redrawPit()
  526.         drawBlockAt(curBlock, curX, curY, curRot)
  527.         dropTimer = os.startTimer(dropSpeed)
  528.       end
  529.       if dx + dr ~= 0 then
  530.         if not testBlockAt(curBlock, curX + dx, curY + dy, dr > 0 and curRot % #curBlock + dr or curRot) then
  531.           eraseBlockAt(curBlock, curX, curY, curRot)
  532.           curX = curX + dx
  533.           curY = curY + dy
  534.           curRot = dr == 0 and curRot or curRot % #curBlock + dr
  535.           drawBlockAt(curBlock, curX, curY, curRot)
  536.         end
  537.       end
  538.     elseif e[1] == "term_resize" then
  539.       local _, h = term.getSize()
  540.       if h == 20 then
  541.         heightAdjust = 0
  542.       else
  543.         heightAdjust = 1
  544.       end
  545.       redrawPit()
  546.       drawBlockAt(curBlock, curX, curY, curRot)
  547.     end
  548.   end
  549.  
  550.   msgBox("Game Over!")
  551.   while true do
  552.     local _, k = os.pullEvent("key")
  553.     if k == keys.space or k == keys.enter or k == keys.numPadEnter then
  554.       break
  555.     end
  556.   end
  557.  
  558.   level = math.min(level, 9)
  559. end
  560.  
  561.  
  562. local selected = 1
  563. local playersDetected = false
  564.  
  565. local function drawMenu()
  566.   term.setBackgroundColor(colors.black)
  567.   term.setTextColor(colorass(colors.red, colors.white))
  568.   term.clear()
  569.  
  570.   local cx, cy = math.floor(width / 2), math.floor(height / 2)
  571.  
  572.   term.setCursorPos(cx - 6, cy - 2)
  573.   term.write("F A L L I N G")
  574.  
  575.   if playersDetected then
  576.     if selected == 0 then
  577.       term.setTextColor(colorass(colors.blue, colors.black))
  578.       term.setBackgroundColor(colorass(colors.gray, colors.white))
  579.     else
  580.       term.setTextColor(colorass(colors.lightBlue, colors.white))
  581.       term.setBackgroundColor(colors.black)
  582.     end
  583.     term.setCursorPos(cx - 12, cy)
  584.     term.write(" Play head-to-head game! ")
  585.   end
  586.  
  587.   term.setCursorPos(cx - 10, cy + 1)
  588.   if selected == 1 then
  589.     term.setTextColor(colorass(colors.blue, colors.black))
  590.     term.setBackgroundColor(colorass(colors.lightGray, colors.white))
  591.   else
  592.     term.setTextColor(colorass(colors.lightBlue, colors.white))
  593.     term.setBackgroundColor(colors.black)
  594.   end
  595.   term.write(" Play from level: <" .. level .. "> ")
  596.  
  597.   term.setCursorPos(cx - 3, cy + 3)
  598.   if selected == 2 then
  599.     term.setTextColor(colorass(colors.blue, colors.black))
  600.     term.setBackgroundColor(colorass(colors.lightGray, colors.white))
  601.   else
  602.     term.setTextColor(colorass(colors.lightBlue, colors.white))
  603.     term.setBackgroundColor(colors.black)
  604.   end
  605.   term.write(" Quit ")
  606. end
  607.  
  608.  
  609. local function runMenu()
  610.   drawMenu()
  611.  
  612.   while true do
  613.     local event = { os.pullEvent() }
  614.     if event[1] == "key" then
  615.       local key = event[2]
  616.       if key == keys.right or key == keys.d and selected == 1 then
  617.         level = math.min(level + 1, 9)
  618.         drawMenu()
  619.       elseif key == keys.left or key == keys.a and selected == 1 then
  620.         level = math.max(level - 1, 1)
  621.         drawMenu()
  622.       elseif key >= keys.one and key <= keys.nine and selected == 1 then
  623.         level = key - keys.one + 1
  624.         drawMenu()
  625.       elseif key == keys.up or key == keys.w then
  626.         selected = selected - 1
  627.         if selected == 0 then
  628.           selected = 2
  629.         end
  630.         drawMenu()
  631.       elseif key == keys.down or key == keys.s then
  632.         selected = selected % 2 + 1
  633.         drawMenu()
  634.       elseif key == keys.enter or key == keys.numPadEnter or key == keys.space then
  635.         break --begin play!
  636.       end
  637.     end
  638.   end
  639. end
  640.  
  641. while true do
  642.   runMenu()
  643.   if selected == 2 then
  644.     break
  645.   end
  646.  
  647.   playGame()
  648. end
  649.  
  650.  
  651. term.setTextColor(colors.white)
  652. term.setBackgroundColor(colors.black)
  653. term.clear()
  654. term.setCursorPos(1, 1)
  655.  
Add Comment
Please, Sign In to add comment