mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2025-07-04 02:52:56 +00:00

Unfortunately we can't apply the config changes due to backwards compatibility. This'll be something we may need to PR into Forge. CraftTweaker support still needs to be added.
651 lines
15 KiB
Lua
651 lines
15 KiB
Lua
--[[
|
|
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 everythign 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 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.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)
|