Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- SPDX-FileCopyrightText: 2017 Daniel Ratcliffe
- --
- -- SPDX-License-Identifier: LicenseRef-CCPL
- --[[
- Falling - Based on Tetris by Alexey Pajitnov
- This version written by Gopher, at the request of Dan200, for
- ComputerCraft v1.6. No particular rights are reserved.
- --]]
- local function colorass(c, bw)
- return term.isColor() and c or bw
- end
- local block_s1 = {
- {
- { 1, 0, 0, 0 },
- { 1, 1, 0, 0 },
- { 0, 1, 0, 0 },
- { 0, 0, 0, 0 },
- },
- {
- { 0, 0, 0, 0 },
- { 0, 1, 1, 0 },
- { 1, 1, 0, 0 },
- { 0, 0, 0, 0 },
- },
- ch = colorass(" ", "{}"),
- fg = colorass(colors.blue, colors.black),
- bg = colorass(colors.cyan, colors.white),
- }
- local block_s2 = {
- {
- { 0, 1, 0, 0 },
- { 1, 1, 0, 0 },
- { 1, 0, 0, 0 },
- { 0, 0, 0, 0 },
- },
- {
- { 0, 0, 0, 0 },
- { 1, 1, 0, 0 },
- { 0, 1, 1, 0 },
- { 0, 0, 0, 0 },
- },
- ch = colorass(" ", "{}"),
- fg = colorass(colors.green, colors.black),
- bg = colorass(colors.lime, colors.white),
- }
- local block_line = {
- {
- { 0, 1, 0, 0 },
- { 0, 1, 0, 0 },
- { 0, 1, 0, 0 },
- { 0, 1, 0, 0 },
- },
- {
- { 0, 0, 0, 0 },
- { 1, 1, 1, 1 },
- { 0, 0, 0, 0 },
- { 0, 0, 0, 0 },
- },
- ch = colorass(" ", "[]"),
- fg = colorass(colors.pink, colors.black),
- bg = colorass(colors.red, colors.white),
- }
- local block_square = {
- {
- { 1, 1, 0, 0 },
- { 1, 1, 0, 0 },
- { 0, 0, 0, 0 },
- { 0, 0, 0, 0 },
- },
- ch = colorass(" ", "[]"),
- fg = colorass(colors.lightBlue, colors.black),
- bg = colorass(colors.blue, colors.white),
- }
- local block_L1 = {
- {
- { 1, 1, 0, 0 },
- { 0, 1, 0, 0 },
- { 0, 1, 0, 0 },
- { 0, 0, 0, 0 },
- },
- {
- { 0, 0, 0, 0 },
- { 1, 1, 1, 0 },
- { 1, 0, 0, 0 },
- { 0, 0, 0, 0 },
- },
- {
- { 0, 1, 0, 0 },
- { 0, 1, 0, 0 },
- { 0, 1, 1, 0 },
- { 0, 0, 0, 0 },
- },
- {
- { 0, 0, 1, 0 },
- { 1, 1, 1, 0 },
- { 0, 0, 0, 0 },
- { 0, 0, 0, 0 },
- },
- ch = colorass(" ", "()"),
- fg = colorass(colors.orange, colors.black),
- bg = colorass(colors.yellow, colors.white),
- }
- local block_L2 = {
- {
- { 0, 1, 0, 0 },
- { 0, 1, 0, 0 },
- { 1, 1, 0, 0 },
- { 0, 0, 0, 0 },
- },
- {
- { 0, 0, 0, 0 },
- { 1, 1, 1, 0 },
- { 0, 0, 1, 0 },
- { 0, 0, 0, 0 },
- },
- {
- { 0, 1, 1, 0 },
- { 0, 1, 0, 0 },
- { 0, 1, 0, 0 },
- { 0, 0, 0, 0 },
- },
- {
- { 1, 0, 0, 0 },
- { 1, 1, 1, 0 },
- { 0, 0, 0, 0 },
- { 0, 0, 0, 0 },
- },
- ch = colorass(" ", "()"),
- fg = colorass(colors.brown, colors.black),
- bg = colorass(colors.orange, colors.white),
- }
- local block_T = {
- {
- { 0, 1, 0, 0 },
- { 1, 1, 0, 0 },
- { 0, 1, 0, 0 },
- { 0, 0, 0, 0 },
- },
- {
- { 0, 0, 0, 0 },
- { 1, 1, 1, 0 },
- { 0, 1, 0, 0 },
- { 0, 0, 0, 0 },
- },
- {
- { 0, 1, 0, 0 },
- { 0, 1, 1, 0 },
- { 0, 1, 0, 0 },
- { 0, 0, 0, 0 },
- },
- {
- { 0, 1, 0, 0 },
- { 1, 1, 1, 0 },
- { 0, 0, 0, 0 },
- { 0, 0, 0, 0 },
- },
- ch = colorass(" ", "<>"),
- fg = colorass(colors.cyan, colors.black),
- bg = colorass(colors.purple, colors.white),
- }
- local blocks = { block_line, block_square, block_s1, block_s2, block_L1, block_L2, block_T }
- local points = { 4, 10, 30, 120 }
- local function lpad(text, amt)
- text = tostring(text)
- return string.rep(" ", amt - #text) .. text
- end
- local width, height = term.getSize()
- if height < 19 or width < 26 then
- print("Your screen is too small to play :(")
- return
- end
- local speedsByLevel = {
- 1.2,
- 1.0,
- .8,
- .65,
- .5,
- .4,
- .3,
- .25,
- .2,
- .15,
- .1,
- .05, }
- local level = 1
- local function playGame()
- local score = 0
- local lines = 0
- local initialLevel = level
- local next = blocks[math.random(1, #blocks)]
- local pit = {}
- local heightAdjust = 0
- if height <= 19 then
- heightAdjust = 1
- end
- local function drawScreen()
- term.setTextColor(colors.white)
- term.setBackgroundColor(colors.black)
- term.clear()
- term.setTextColor(colors.black)
- term.setBackgroundColor(colorass(colors.lightGray, colors.white))
- term.setCursorPos(22, 2)
- term.write("Score") --score
- term.setCursorPos(22, 5)
- term.write("Level") --level
- term.setCursorPos(22, 8)
- term.write("Lines") --lines
- term.setCursorPos(22, 12)
- term.write("Next") --next
- term.setCursorPos(21, 1)
- term.write(" ")
- term.setCursorPos(21, 2)
- term.write(" ") --score
- term.setCursorPos(21, 3)
- term.write(" ")
- term.setCursorPos(21, 4)
- term.write(" ")
- term.setCursorPos(21, 5)
- term.write(" ") --level
- term.setCursorPos(21, 6)
- term.write(" ")
- term.setCursorPos(21, 7)
- term.write(" ")
- term.setCursorPos(21, 8)
- term.write(" ") --lines
- term.setCursorPos(21, 9)
- term.write(" ")
- term.setCursorPos(21, 10)
- term.write(" ")
- term.setCursorPos(21, 11)
- term.write(" ")
- term.setCursorPos(21, 12)
- term.write(" ") --next
- term.setCursorPos(26, 12)
- term.write(" ") --next
- term.setCursorPos(21, 13)
- term.write(" ")
- term.setCursorPos(21, 14)
- term.write(" ")
- term.setCursorPos(21, 15)
- term.write(" ")
- term.setCursorPos(21, 16)
- term.write(" ")
- term.setCursorPos(21, 17)
- term.write(" ")
- term.setCursorPos(21, 18)
- term.write(" ")
- term.setCursorPos(21, 19)
- term.write(" ")
- term.setCursorPos(21, 20)
- term.write(" ")
- end
- local function updateNumbers()
- term.setTextColor(colors.white)
- term.setBackgroundColor(colors.black)
- term.setCursorPos(22, 3)
- term.write(lpad(score, 5)) --score
- term.setCursorPos(22, 6)
- term.write(lpad(level, 5)) --level
- term.setCursorPos(22, 9)
- term.write(lpad(lines, 5)) --lines
- end
- local function drawBlockAt(block, xp, yp, rot)
- term.setTextColor(block.fg)
- term.setBackgroundColor(block.bg)
- for y = 1, 4 do
- for x = 1, 4 do
- if block[rot][y][x] == 1 then
- term.setCursorPos((xp + x) * 2 - 3, yp + y - 1 - heightAdjust)
- term.write(block.ch)
- end
- end
- end
- end
- local function eraseBlockAt(block, xp, yp, rot)
- term.setTextColor(colors.white)
- term.setBackgroundColor(colors.black)
- for y = 1, 4 do
- for x = 1, 4 do
- if block[rot][y][x] == 1 then
- term.setCursorPos((xp + x) * 2 - 3, yp + y - 1 - heightAdjust)
- term.write(" ")
- end
- end
- end
- end
- local function testBlockAt(block, xp, yp, rot)
- for y = 1, 4 do
- local ty = yp + y - 1
- for x = 1, 4 do
- local tx = xp + x - 1
- if block[rot][y][x] == 1 then
- if tx > 10 or tx < 1 or ty > 20 or pit[ty][tx] ~= 0 then
- return true
- end
- end
- end
- end
- end
- local function pitBlock(block, xp, yp, rot)
- for y = 1, 4 do
- for x = 1, 4 do
- if block[rot][y][x] == 1 then
- pit[yp + y - 1][xp + x - 1] = block
- end
- end
- end
- end
- local function clearPit()
- for row = 1, 20 do
- pit[row] = {}
- for col = 1, 10 do
- pit[row][col] = 0
- end
- end
- end
- drawScreen()
- updateNumbers()
- --declare & init the pit
- clearPit()
- local halt = false
- local dropSpeed = speedsByLevel[math.min(level, 12)]
- local curBlock = next
- next = blocks[math.random(1, 7)]
- local curX, curY, curRot = 4, 1, 1
- local dropTimer = os.startTimer(dropSpeed)
- drawBlockAt(next, 11.5, 15 + heightAdjust, 1)
- drawBlockAt(curBlock, curX, curY, curRot)
- local function redrawPit()
- for r = 1 + heightAdjust, 20 do
- term.setCursorPos(1, r - heightAdjust)
- for c = 1, 10 do
- if pit[r][c] == 0 then
- term.setTextColor(colors.black)
- term.setBackgroundColor(colors.black)
- term.write(" ")
- else
- term.setTextColor(pit[r][c].fg)
- term.setBackgroundColor(pit[r][c].bg)
- term.write(pit[r][c].ch)
- end
- end
- end
- end
- local function hidePit()
- for r = 1 + heightAdjust, 20 do
- term.setCursorPos(1, r - heightAdjust)
- term.setTextColor(colors.black)
- term.setBackgroundColor(colors.black)
- term.write(" ")
- end
- end
- local function msgBox(message)
- local x = math.floor((17 - #message) / 2)
- term.setBackgroundColor(colorass(colors.lightGray, colors.white))
- term.setTextColor(colors.black)
- term.setCursorPos(x, 9)
- term.write("+" .. string.rep("-", #message + 2) .. "+")
- term.setCursorPos(x, 10)
- term.write("|")
- term.setCursorPos(x + #message + 3, 10)
- term.write("|")
- term.setCursorPos(x, 11)
- term.write("+" .. string.rep("-", #message + 2) .. "+")
- term.setTextColor(colors.white)
- term.setBackgroundColor(colors.black)
- term.setCursorPos(x + 1, 10)
- term.write(" " .. message .. " ")
- end
- local function clearRows()
- local rows = {}
- for r = 1, 20 do
- local count = 0
- for c = 1, 10 do
- if pit[r][c] ~= 0 then
- count = count + 1
- else
- break
- end
- end
- if count == 10 then
- rows[#rows + 1] = r
- end
- end
- if #rows > 0 then
- for _ = 1, 4 do
- sleep(.1)
- for r = 1, #rows do
- r = rows[r]
- term.setCursorPos(1, r - heightAdjust)
- for c = 1, 10 do
- term.setTextColor(pit[r][c].bg)
- term.setBackgroundColor(pit[r][c].fg)
- term.write(pit[r][c].ch)
- end
- end
- sleep(.1)
- for r = 1, #rows do
- r = rows[r]
- term.setCursorPos(1, r - heightAdjust)
- for c = 1, 10 do
- term.setTextColor(pit[r][c].fg)
- term.setBackgroundColor(pit[r][c].bg)
- term.write(pit[r][c].ch)
- end
- end
- end
- --now remove the rows and drop everything else
- term.setBackgroundColor(colors.black)
- for r = 1, #rows do
- r = rows[r]
- term.setCursorPos(1, r - heightAdjust)
- term.write(" ")
- end
- sleep(.25)
- for r = 1, #rows do
- table.remove(pit, rows[r])
- table.insert(pit, 1, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 })
- end
- redrawPit()
- lines = lines + #rows
- score = score + points[#rows] * math.min(level, 20)
- level = math.floor(lines / 10) + initialLevel
- dropSpeed = speedsByLevel[math.min(level, 12)]
- updateNumbers()
- end
- sleep(.25)
- end
- local function blockFall()
- if testBlockAt(curBlock, curX, curY + 1, curRot) then
- pitBlock(curBlock, curX, curY, curRot)
- --detect rows that clear
- clearRows()
- curBlock = next
- curX = 4
- curY = 1
- curRot = 1
- if testBlockAt(curBlock, curX, curY, curRot) then
- halt = true
- end
- drawBlockAt(curBlock, curX, curY, curRot)
- eraseBlockAt(next, 11.5, 15 + heightAdjust, 1)
- next = blocks[math.random(1, 7)]
- drawBlockAt(next, 11.5, 15 + heightAdjust, 1)
- return true
- else
- eraseBlockAt(curBlock, curX, curY, curRot)
- curY = curY + 1
- drawBlockAt(curBlock, curX, curY, curRot)
- return false
- end
- end
- while not halt do
- local e = { os.pullEvent() }
- if e[1] == "timer" then
- if e[2] == dropTimer then
- blockFall()
- dropTimer = os.startTimer(dropSpeed)
- end
- elseif e[1] == "key" then
- local key = e[2]
- local dx, dy, dr = 0, 0, 0
- if key == keys.left or key == keys.a then
- dx = -1
- elseif key == keys.right or key == keys.d then
- dx = 1
- elseif key == keys.up or key == keys.w then
- dr = 1
- elseif key == keys.down or key == keys.s then
- while not blockFall() do end
- dropTimer = os.startTimer(dropSpeed)
- elseif key == keys.space then
- hidePit()
- msgBox("Paused")
- while ({ os.pullEvent("key") })[2] ~= keys.space do end
- redrawPit()
- drawBlockAt(curBlock, curX, curY, curRot)
- dropTimer = os.startTimer(dropSpeed)
- end
- if dx + dr ~= 0 then
- if not testBlockAt(curBlock, curX + dx, curY + dy, dr > 0 and curRot % #curBlock + dr or curRot) then
- eraseBlockAt(curBlock, curX, curY, curRot)
- curX = curX + dx
- curY = curY + dy
- curRot = dr == 0 and curRot or curRot % #curBlock + dr
- drawBlockAt(curBlock, curX, curY, curRot)
- end
- end
- elseif e[1] == "term_resize" then
- local _, h = term.getSize()
- if h == 20 then
- heightAdjust = 0
- else
- heightAdjust = 1
- end
- redrawPit()
- drawBlockAt(curBlock, curX, curY, curRot)
- end
- end
- msgBox("Game Over!")
- while true do
- local _, k = os.pullEvent("key")
- if k == keys.space or k == keys.enter or k == keys.numPadEnter then
- break
- end
- end
- level = math.min(level, 9)
- end
- local selected = 1
- local playersDetected = false
- local function drawMenu()
- term.setBackgroundColor(colors.black)
- term.setTextColor(colorass(colors.red, colors.white))
- term.clear()
- local cx, cy = math.floor(width / 2), math.floor(height / 2)
- term.setCursorPos(cx - 6, cy - 2)
- term.write("F A L L I N G")
- if playersDetected then
- if selected == 0 then
- term.setTextColor(colorass(colors.blue, colors.black))
- term.setBackgroundColor(colorass(colors.gray, colors.white))
- else
- term.setTextColor(colorass(colors.lightBlue, colors.white))
- term.setBackgroundColor(colors.black)
- end
- term.setCursorPos(cx - 12, cy)
- term.write(" Play head-to-head game! ")
- end
- term.setCursorPos(cx - 10, cy + 1)
- if selected == 1 then
- term.setTextColor(colorass(colors.blue, colors.black))
- term.setBackgroundColor(colorass(colors.lightGray, colors.white))
- else
- term.setTextColor(colorass(colors.lightBlue, colors.white))
- term.setBackgroundColor(colors.black)
- end
- term.write(" Play from level: <" .. level .. "> ")
- term.setCursorPos(cx - 3, cy + 3)
- if selected == 2 then
- term.setTextColor(colorass(colors.blue, colors.black))
- term.setBackgroundColor(colorass(colors.lightGray, colors.white))
- else
- term.setTextColor(colorass(colors.lightBlue, colors.white))
- term.setBackgroundColor(colors.black)
- end
- term.write(" Quit ")
- end
- local function runMenu()
- drawMenu()
- while true do
- local event = { os.pullEvent() }
- if event[1] == "key" then
- local key = event[2]
- if key == keys.right or key == keys.d and selected == 1 then
- level = math.min(level + 1, 9)
- drawMenu()
- elseif key == keys.left or key == keys.a and selected == 1 then
- level = math.max(level - 1, 1)
- drawMenu()
- elseif key >= keys.one and key <= keys.nine and selected == 1 then
- level = key - keys.one + 1
- drawMenu()
- elseif key == keys.up or key == keys.w then
- selected = selected - 1
- if selected == 0 then
- selected = 2
- end
- drawMenu()
- elseif key == keys.down or key == keys.s then
- selected = selected % 2 + 1
- drawMenu()
- elseif key == keys.enter or key == keys.numPadEnter or key == keys.space then
- break --begin play!
- end
- end
- end
- end
- while true do
- runMenu()
- if selected == 2 then
- break
- end
- playGame()
- end
- term.setTextColor(colors.white)
- term.setBackgroundColor(colors.black)
- term.clear()
- term.setCursorPos(1, 1)
Add Comment
Please, Sign In to add comment