2019-10-10 08:39:53 +00:00
--
2019-10-10 08:16:32 +00:00
-- ## ##### ###### ###### ######
-- ## ## ## ## ## ## ## ###
-- ## ## ## ## ## ## ###
-- ## ## ## ###### ## ######
-- ## ## ## ## ## ## ###
-- ## ## ## ## ## ## ### ##
-- ##### ##### ## ## ###### ######
--
-- ComputerCraft port of Tetris
-- by LDDestroier
--
-- Supports wall kicking, holding, fast-dropping,
-- and ghost pieces.
--
-- TO-DO:
2019-11-21 08:36:38 +00:00
-- + Add random color pulsation (for effect!)
-- + Add a proper title screen. The current one is pathetic.
2019-10-10 08:16:32 +00:00
2020-03-30 00:55:31 +00:00
local sentInfos = 0
2019-10-10 08:16:32 +00:00
local scr_x , scr_y = term.getSize ( )
2019-11-21 06:56:52 +00:00
local keysDown = { }
2019-10-10 08:16:32 +00:00
local game = {
2019-11-17 05:10:11 +00:00
p = { } , -- stores player information
2019-11-21 06:56:52 +00:00
pp = { } , -- stores other player information that doesn't need to be sent during netplay
2019-11-17 05:10:11 +00:00
you = 1 , -- current player slot
2019-11-22 07:37:44 +00:00
instanceID = math.random ( 1 , 2 ^ 31 - 1 ) , -- random per-instance value to ensure skynet doesn't poopie
2019-11-17 05:10:11 +00:00
amountOfPlayers = 2 , -- amount of players for the current game
running = true , -- if set to false, will quit the game
2019-12-29 17:56:50 +00:00
moveHoldDelay = 0.1 , -- amount of time to hold left or right for it to keep moving that way
2020-09-04 01:48:11 +00:00
boardOverflow = 20 , -- amount of space above the board that it can overflow
2019-11-17 05:10:11 +00:00
paused = false , -- whether or not game is paused
canPause = true , -- if false, cannot pause game (such as in online multiplayer)
2019-11-22 07:37:44 +00:00
inputDelay = 0.05 , -- amount of time between each input
gameDelay = 0.05 , -- amount of time between game ticks
2020-03-30 00:55:31 +00:00
minimumLockTimer = 0.4 , -- shortest amount of time before a piece locks upon touching the ground
2020-09-04 01:48:11 +00:00
maximumLockTimer = 0.6 , -- longest amount of time before a piece locks upon touching the ground
2020-07-17 23:19:48 +00:00
appearanceDelay = 0.05 , -- amount of time to wait after placing a piece
2019-11-17 05:10:11 +00:00
config = {
2020-03-30 00:55:31 +00:00
TGMlock = false , -- replicate the piece locking from Tetris: The Grand Master
2020-09-04 02:16:59 +00:00
scrubMode = false , -- gives you nothing but I-pieces
2019-11-17 05:10:11 +00:00
} ,
2019-11-21 06:56:52 +00:00
control = { -- client's control scheme
moveLeft = keys.left , -- shift left
moveRight = keys.right , -- shift right
2020-09-04 01:48:11 +00:00
softDrop = keys.down , -- shift downwards
2019-11-21 06:56:52 +00:00
rotateLeft = keys.z , -- rotate counter-clockwise
rotateRight = keys.x , -- rotate clockwise
2020-09-04 01:48:11 +00:00
hardDrop = keys.up , -- instantly drop and place piece
sonicDrop = keys.space , -- instantly drop piece, but not place
2019-11-21 06:56:52 +00:00
hold = keys.leftShift , -- slot piece into hold buffer
2020-03-30 02:17:14 +00:00
quit = keys.q , -- fuck off
pause = keys.p
2019-11-21 06:56:52 +00:00
} ,
2020-09-04 01:48:11 +00:00
softDropSpeed = 2 , -- amount of spaces a soft drop will move a mino downwards
2019-11-21 06:56:52 +00:00
revControl = { } , -- a mirror of "control", but with the keys and values inverted
net = { -- all network-related values
isHost = true , -- the host holds all the cards
gameID = math.random ( 1 , 2 ^ 31 - 1 ) , -- per-game ID to prevent interference from other games
channel = 1294 , -- modem or skynet channel
active = true , -- whether or not you're using modems at all
waitingForGame = true , -- if you're waiting for another player to start the game
modem = peripheral.find ( " modem " ) , -- modem transmit object
useSkynet = false , -- if true, uses Skynet instead of modems
skynet = nil , -- skynet transmit object
skynetURL = " https://github.com/LDDestroier/CC/raw/master/API/skynet.lua " , -- exactly what it looks like
skynetPath = " /skynet.lua " -- location for Skynet API
2019-10-11 02:11:24 +00:00
} ,
timers = { } ,
2020-03-30 07:33:26 +00:00
timerNo = 1 ,
2019-10-10 08:16:32 +00:00
}
2019-11-21 06:56:52 +00:00
for k , v in pairs ( game.control ) do
game.revControl [ v ] = k
end
2020-03-30 07:33:26 +00:00
game.setPaletteColor = function ( ... )
if game.amountOfPlayers <= 1 then
term.setPaletteColor ( ... )
end
end
2019-11-21 06:56:52 +00:00
local getTime = function ( )
if os.epoch then
return os.epoch ( " utc " )
else
return 24 * os.day ( ) + os.time ( )
end
end
2019-10-11 02:11:24 +00:00
game.startTimer = function ( duration )
game.timers [ game.timerNo ] = duration
game.timerNo = game.timerNo + 1
return game.timerNo - 1
end
game.cancelTimer = function ( tID )
game.timers [ tID or 0 ] = nil
end
2019-11-16 03:22:44 +00:00
game.alterTimer = function ( tID , mod )
if game.timers [ tID ] then
game.timers [ tID ] = game.timers [ tID ] + mod
end
end
2019-10-10 08:16:32 +00:00
local tableCopy
tableCopy = function ( tbl )
local output = { }
for k , v in pairs ( tbl ) do
if type ( v ) == " table " then
output [ k ] = tableCopy ( v )
else
output [ k ] = v
end
end
return output
end
-- sets up brown as colors.special, for palette swapping magic(k)
2019-10-10 08:39:53 +00:00
local tColors = tableCopy ( colors )
tColors.white = 1
tColors.brown = nil -- brown is now white
tColors.special = 4096
2020-03-30 07:33:26 +00:00
term.setPaletteColor ( tColors.special , 0x353535 )
2019-10-10 08:39:53 +00:00
term.setPaletteColor ( tColors.white , 0xf0f0f0 )
2019-10-10 08:16:32 +00:00
-- initializes and fixes up a board
-- boards are 2D objects that can display perfectly square graphics
2019-11-21 06:56:52 +00:00
local clearBoard = function ( board , xpos , ypos , newXsize , newYsize , newBGcolor , topCull , clearContent )
2019-10-10 08:16:32 +00:00
board = board or { }
board.x = board.x or xpos or 1
board.y = board.y or ypos or 1
board.xSize = board.xSize or newXsize or 10
2019-11-17 05:10:11 +00:00
board.ySize = board.ySize or newYsize or 24 + game.boardOverflow
board.topCull = board.topCull or topCull or game.boardOverflow
2019-10-10 08:16:32 +00:00
board.BGcolor = board.BGcolor or newBGcolor or " f "
2020-09-04 01:48:11 +00:00
board.minoAmount = board.minoAmount or 0
2019-10-10 08:16:32 +00:00
for y = 1 , board.ySize do
board [ y ] = board [ y ] or { }
for x = 1 , board.xSize do
-- explanation on each space:
-- {
-- boolean; if true, the space is solid
-- string; the hex color of the space
-- number; the countdown until the space is made non-solid (inactive if 0)
-- number; the countdown until the space is colored to board.BGcolor (inactive if 0)
-- }
2019-11-21 06:56:52 +00:00
if clearContent then
board [ y ] [ x ] = { false , board.BGcolor , 0 , 0 }
else
board [ y ] [ x ] = board [ y ] [ x ] or { false , board.BGcolor , 0 , 0 }
end
2019-10-10 08:16:32 +00:00
end
end
return board
end
-- tetramino information
-- don't tamper with this or I'll beat your ass so hard that war veterans would blush
local minos = {
[ 1 ] = { -- I-piece
canRotate = true ,
2019-11-17 05:10:11 +00:00
canTspin = false ,
2020-03-30 00:55:31 +00:00
mainColor = " 3 " ,
2019-10-10 08:16:32 +00:00
shape = {
" " ,
" 3333 " ,
" " ,
" " ,
}
} ,
[ 2 ] = { -- L-piece
canRotate = true ,
2019-11-17 05:10:11 +00:00
canTspin = false ,
2020-03-30 00:55:31 +00:00
mainColor = " 1 " ,
2019-10-10 08:16:32 +00:00
shape = {
" 1 " ,
" 111 " ,
" " ,
}
} ,
[ 3 ] = { -- J-piece
canRotate = true ,
2019-11-17 05:10:11 +00:00
canTspin = false ,
2020-03-30 00:55:31 +00:00
mainColor = " b " ,
2019-10-10 08:16:32 +00:00
shape = {
" b " ,
" bbb " ,
" " ,
}
} ,
[ 4 ] = { -- O-piece
canRotate = true ,
2019-11-17 05:10:11 +00:00
canTspin = false ,
2020-03-30 00:55:31 +00:00
mainColor = " 4 " ,
2019-10-10 08:16:32 +00:00
shape = {
" 44 " ,
" 44 " ,
}
} ,
[ 5 ] = { -- T-piece
canRotate = true ,
2019-11-17 05:10:11 +00:00
canTspin = true ,
2020-03-30 00:55:31 +00:00
mainColor = " a " ,
2019-10-10 08:16:32 +00:00
shape = {
" a " ,
" aaa " ,
" " ,
}
} ,
[ 6 ] = { -- Z-piece
canRotate = true ,
2019-11-17 05:10:11 +00:00
canTspin = false ,
2020-03-30 00:55:31 +00:00
mainColor = " e " ,
2019-10-10 08:16:32 +00:00
shape = {
" ee " ,
" ee " ,
" " ,
}
} ,
[ 7 ] = { -- S-piece
canRotate = true ,
2019-11-17 05:10:11 +00:00
canTspin = false ,
2020-03-30 00:55:31 +00:00
mainColor = " 5 " ,
2019-10-10 08:16:32 +00:00
shape = {
" 55 " ,
" 55 " ,
" " ,
}
} ,
[ " gameover " ] = { -- special "mino" for game over
canRotate = false ,
shape = {
" ccc ccc c c ccccc ccc c c ccccc cccc " ,
" c c c cc cc c c c c c c c c " ,
" c c c cc cc c c c c c c c c " ,
" c cc ccccc c c c cccc c c c c cccc cccc " ,
" c c c c c c c c c c c c c c " ,
" c c c c c c c c c c c c c c " ,
" c c c c c c c c c c c c c c " ,
" ccc c c c c ccccc ccc c ccccc c c " ,
}
2019-11-16 03:22:44 +00:00
} ,
[ " yousuck " ] = {
canRotate = false ,
shape = {
" c c ccc c c ccc c c ccc c c " ,
" c c c c c c c c c c c c c c " ,
" c c c c c c c c c c c c " ,
" c c c c c c ccc c c c cc " ,
" c c c c c c c c c c c " ,
" c c c c c c c c c c c " ,
" c c c c c c c c c c c c c " ,
" c ccc ccc ccc ccc ccc c c " ,
}
2019-11-17 05:10:11 +00:00
} ,
[ " eatmyass " ] = {
canRotate = false ,
shape = {
" ccccc ccc ccccc c c c c ccc ccc ccc " ,
" c c c c cc cc c c c c c c c c " ,
" c c c c c c c c c c c c c c " ,
" cccc ccccc c c c c c ccccc ccc ccc " ,
" c c c c c c c c c c c " ,
" c c c c c c c c c c c " ,
" c c c c c c c c c c c c c " ,
" ccccc c c c c c c c c ccc ccc " ,
}
} ,
[ " nice " ] = { -- nice
canRotate = false ,
shape = {
" c " ,
" " ,
" c ccc c cccc cccc " ,
" c c c c c c c c " ,
" cc c c c c c " ,
" c c c c cccccc " ,
" c c c c c " ,
" c c c c c " ,
" c c c c c c c " ,
" c c c cccc cccc c " ,
}
2019-10-10 08:16:32 +00:00
}
}
2020-09-04 01:48:11 +00:00
for k , mino in pairs ( minos ) do
minos [ k ] . size = 0
for y = 1 , # mino.shape do
for x = 1 , # mino.shape [ y ] do
if mino.shape [ y ] : sub ( x , x ) ~= " " then
minos [ k ] . size = minos [ k ] . size + 1
end
end
end
end
2019-11-17 05:10:11 +00:00
local images = {
-- to do...add images...
}
2019-10-10 08:16:32 +00:00
-- converts blit colors to colors api, and back
local to_colors , to_blit = {
[ ' ' ] = 0 ,
[ ' 0 ' ] = 1 ,
[ ' 1 ' ] = 2 ,
[ ' 2 ' ] = 4 ,
[ ' 3 ' ] = 8 ,
[ ' 4 ' ] = 16 ,
[ ' 5 ' ] = 32 ,
[ ' 6 ' ] = 64 ,
[ ' 7 ' ] = 128 ,
[ ' 8 ' ] = 256 ,
[ ' 9 ' ] = 512 ,
[ ' a ' ] = 1024 ,
[ ' b ' ] = 2048 ,
[ ' c ' ] = 4096 ,
[ ' d ' ] = 8192 ,
[ ' e ' ] = 16384 ,
[ ' f ' ] = 32768 ,
} , { }
for k , v in pairs ( to_colors ) do
to_blit [ v ] = k
end
-- checks if (x, y) is a valid space on the board
local doesSpaceExist = function ( board , x , y )
return ( x >= 1 and x <= board.xSize ) and ( y >= 1 and y <= board.ySize )
end
-- checks if (x, y) is being occupied by a tetramino (or if it's off-board)
2019-10-11 02:11:24 +00:00
local isSpaceSolid = function ( board , _x , _y )
local x , y = math.floor ( _x ) , math.floor ( _y )
2019-10-10 08:16:32 +00:00
if doesSpaceExist ( board , x , y ) then
return board [ y ] [ x ] [ 1 ]
else
return true
end
end
-- ticks down a space's timers, which can cause it to become non-solid or background-colored
2019-10-11 02:11:24 +00:00
local ageSpace = function ( board , _x , _y )
local x , y = math.floor ( _x ) , math.floor ( _y )
2019-10-10 08:16:32 +00:00
if doesSpaceExist ( board , x , y ) then
-- make space non-solid if timer elapses
if board [ y ] [ x ] [ 3 ] ~= 0 then
board [ y ] [ x ] [ 3 ] = board [ y ] [ x ] [ 3 ] - 1
if board [ y ] [ x ] [ 3 ] == 0 then
board [ y ] [ x ] [ 1 ] = false
end
end
-- color space board.BGcolor if timer elapses
if board [ y ] [ x ] [ 4 ] ~= 0 then
board [ y ] [ x ] [ 4 ] = board [ y ] [ x ] [ 4 ] - 1
if board [ y ] [ x ] [ 4 ] == 0 then
board [ y ] [ x ] [ 2 ] = board.BGcolor
end
end
end
end
2019-11-21 06:56:52 +00:00
local transmit = function ( msg )
2019-11-22 07:37:44 +00:00
if game.net . active then
if game.net . useSkynet then
game.net . skynet.send ( game.net . channel , msg )
else
game.net . modem.transmit ( game.net . channel , game.net . channel , msg )
end
2019-11-21 06:56:52 +00:00
end
end
local sendInfo = function ( command , doSendTime , playerNumber )
2020-03-30 00:55:31 +00:00
sentInfos = sentInfos + 1
2019-11-21 06:56:52 +00:00
if game.net . isHost then
transmit ( {
command = command ,
gameID = game.net . gameID ,
time = doSendTime and getTime ( ) ,
p = playerNumber and game.p [ playerNumber ] or game.p ,
pNum = playerNumber ,
2019-11-22 22:52:36 +00:00
you = game.you ,
2019-11-21 06:56:52 +00:00
specialColor = { term.getPaletteColor ( tColors.special ) }
} )
else
transmit ( {
command = command ,
gameID = game.net . gameID ,
time = doSendTime and getTime ( ) ,
2019-11-22 22:52:36 +00:00
pNum = playerNumber ,
you = game.you ,
2019-11-21 06:56:52 +00:00
control = game.p [ game.you ] . control
} )
end
end
2019-10-10 08:16:32 +00:00
-- generates a "mino" object, which can be drawn and manipulated on a board
local makeNewMino = function ( minoType , board , x , y , replaceColor )
local mino = tableCopy ( minos [ minoType ] )
if replaceColor then
for yy = 1 , # mino.shape do
mino.shape [ yy ] = mino.shape [ yy ] : gsub ( " [^ ] " , replaceColor )
end
end
-- what color the ghost mino will be
mino.ghostColor = 0x353535
2019-10-10 08:39:53 +00:00
2019-10-10 08:16:32 +00:00
mino.x = x
mino.y = y
2020-07-17 23:19:48 +00:00
mino.didWallKick = false
2020-03-30 00:55:31 +00:00
mino.color = minos [ minoType ] . mainColor or " c "
2019-11-17 05:10:11 +00:00
mino.didTspin = false -- if the player has done a T-spin with this piece
2019-10-11 02:11:24 +00:00
mino.lockBreaks = 16 -- anti-infinite measure
2019-10-10 08:16:32 +00:00
mino.waitingForLock = false
mino.board = board
mino.minoType = minoType
-- checks to see if the mino is currently clipping with a solid board space (with the offset values)
2020-07-17 23:19:48 +00:00
mino.checkCollision = function ( xOffset , yOffset , doNotCountBorder )
2019-10-10 08:16:32 +00:00
local cx , cy
for y = 1 , # mino.shape do
for x = 1 , # mino.shape [ y ] do
cx = mino.x + x + ( xOffset or 0 )
cy = mino.y + y + ( yOffset or 0 )
if mino.shape [ y ] : sub ( x , x ) ~= " " then
2020-07-17 23:19:48 +00:00
if isSpaceSolid ( mino.board , cx , cy ) and not ( doNotCountBorder and not doesSpaceExist ( board , cx , cy ) ) then
2019-10-10 08:16:32 +00:00
return true
end
end
end
end
return false
end
-- rotates a mino, and kicks it off a wall if need be
mino.rotate = function ( direction )
local output = { }
local oldShape = tableCopy ( mino.shape )
local origX , origY = mino.x , mino.y
for y = 1 , # mino.shape do
output [ y ] = { }
for x = 1 , # mino.shape [ y ] do
if direction == 1 then
output [ y ] [ x ] = mino.shape [ # mino.shape - ( x - 1 ) ] : sub ( y , y )
elseif direction == - 1 then
output [ y ] [ x ] = mino.shape [ x ] : sub ( - y , - y )
else
error ( " invalid rotation direction (must be 1 or -1) " )
end
end
output [ y ] = table.concat ( output [ y ] )
end
mino.shape = output
2020-03-30 00:55:31 +00:00
-- check T-spin
local checkTspin = function ( mino )
2020-07-17 23:19:48 +00:00
if ( mino.checkCollision ( - 1 , 0 , false ) and mino.checkCollision ( 1 , 0 , false ) and mino.checkCollision ( 0 , - 1 , false ) ) then
if mino.didWallKick then
mino.didTspin = 1
else
mino.didTspin = 2
end
2020-03-30 00:55:31 +00:00
else
2020-07-17 23:19:48 +00:00
mino.didTspin = false
2020-03-30 00:55:31 +00:00
end
2020-07-17 23:19:48 +00:00
return mino.didTspin
2020-03-30 00:55:31 +00:00
end
2019-10-11 02:11:24 +00:00
-- try to kick off wall/floor
2019-10-10 08:16:32 +00:00
if mino.checkCollision ( 0 , 0 ) then
2019-10-22 06:17:47 +00:00
-- try T-spin triple rotation
if not mino.checkCollision ( - direction , 2 ) then
mino.y = mino.y + 2
mino.x = mino.x - direction
2020-07-17 23:19:48 +00:00
mino.didWallKick = true
2020-03-30 00:55:31 +00:00
checkTspin ( mino )
2019-10-22 06:17:47 +00:00
return true
end
2020-03-30 02:17:14 +00:00
-- kick off ceiling
for y = 1 , # mino.shape do
for x = - 1 , 1 do
if not mino.checkCollision ( x , y ) then
mino.x = mino.x + x
mino.y = mino.y + y
2020-07-17 23:19:48 +00:00
mino.didWallKick = true
2020-03-30 02:17:14 +00:00
--checkTspin(mino)
--return true
end
end
end
2019-10-11 02:11:24 +00:00
-- kick off floor
2020-03-30 00:55:31 +00:00
for y = 1 , math.floor ( # mino.shape / 2 ) do
2019-10-10 08:16:32 +00:00
if not mino.checkCollision ( 0 , - y ) then
mino.y = mino.y - y
2020-07-17 23:19:48 +00:00
mino.didWallKick = true
2020-03-30 00:55:31 +00:00
checkTspin ( mino )
2019-10-11 02:11:24 +00:00
return true
2020-03-30 02:17:14 +00:00
elseif not mino.checkCollision ( - 1 , - y ) then
mino.y = mino.y - y
mino.x = mino.x - 1
2020-07-17 23:19:48 +00:00
mino.didWallKick = true
2020-03-30 02:17:14 +00:00
checkTspin ( mino )
return true
elseif not mino.checkCollision ( 1 , - y ) then
mino.y = mino.y - y
mino.x = mino.x + 1
2020-07-17 23:19:48 +00:00
mino.didWallKick = true
2020-03-30 02:17:14 +00:00
checkTspin ( mino )
return true
2019-10-10 08:16:32 +00:00
end
end
2019-10-11 02:11:24 +00:00
-- kick off right wall
for x = 0 , - math.floor ( # mino.shape [ 1 ] / 2 ) , - 1 do
2019-10-10 08:16:32 +00:00
if not mino.checkCollision ( x , 0 ) then
mino.x = mino.x + x
2020-03-30 00:55:31 +00:00
checkTspin ( mino )
2019-10-11 02:11:24 +00:00
return true
end
-- try diagonal-down
if not mino.checkCollision ( x , 1 ) then
mino.x = mino.x + x
mino.y = mino.y + 1
2020-03-30 00:55:31 +00:00
sendInfo ( " send_info " , false )
checkTspin ( mino )
2019-10-11 02:11:24 +00:00
return true
2019-10-10 08:16:32 +00:00
end
end
2019-10-11 02:11:24 +00:00
-- kick off left wall
for x = 0 , math.floor ( # mino.shape [ 1 ] / 2 ) do
2019-10-10 08:16:32 +00:00
if not mino.checkCollision ( x , 0 ) then
mino.x = mino.x + x
2020-07-17 23:19:48 +00:00
mino.didWallKick = true
2020-03-30 00:55:31 +00:00
checkTspin ( mino )
2019-10-11 02:11:24 +00:00
return true
end
-- try diagonal-down
if not mino.checkCollision ( x , 1 ) then
mino.x = mino.x + x
mino.y = mino.y + 1
2020-03-30 00:55:31 +00:00
sendInfo ( " send_info " , false )
2020-07-17 23:19:48 +00:00
mino.didWallKick = true
2020-03-30 00:55:31 +00:00
checkTspin ( mino )
2019-10-11 02:11:24 +00:00
return true
2019-10-10 08:16:32 +00:00
end
end
2019-10-11 02:11:24 +00:00
mino.shape = oldShape
return false
else
2020-07-17 23:19:48 +00:00
checkTspin ( mino )
2019-10-11 02:11:24 +00:00
return true
2019-10-10 08:16:32 +00:00
end
end
-- draws a mino onto a board; you'll still need to render the board, though
2020-03-30 00:55:31 +00:00
mino.draw = function ( isSolid , colorReplace )
2019-10-10 08:16:32 +00:00
for y = 1 , # mino.shape do
for x = 1 , # mino.shape [ y ] do
if mino.shape [ y ] : sub ( x , x ) ~= " " then
2019-10-11 02:11:24 +00:00
if doesSpaceExist ( mino.board , x + math.floor ( mino.x ) , y + math.floor ( mino.y ) ) then
mino.board [ y + math.floor ( mino.y ) ] [ x + math.floor ( mino.x ) ] = {
2019-10-10 08:16:32 +00:00
isSolid or false ,
2020-03-30 00:55:31 +00:00
colorReplace or mino.shape [ y ] : sub ( x , x ) ,
2019-10-10 08:16:32 +00:00
isSolid and 0 or 0 ,
isSolid and 0 or 1
}
end
end
end
end
end
-- moves a mino, making sure not to clip with solid board spaces
mino.move = function ( x , y , doSlam )
if not mino.checkCollision ( x , y ) then
2020-07-17 23:19:48 +00:00
if not ( x == 0 and y == 0 ) then
mino.x = mino.x + x
mino.y = mino.y + y
mino.didTspin = false
mino.didWallKick = false
end
2019-10-10 08:16:32 +00:00
return true
elseif doSlam then
for sx = 0 , x , math.abs ( x ) / x do
if mino.checkCollision ( sx , 0 ) then
mino.x = mino.x + sx - math.abs ( x ) / x
break
end
2020-03-30 00:55:31 +00:00
if sx ~= 0 then
2020-07-17 23:19:48 +00:00
mino.didWallKick = false
2020-03-30 00:55:31 +00:00
mino.didTspin = false
end
2019-10-10 08:16:32 +00:00
end
2019-11-17 05:10:11 +00:00
for sy = 0 , math.ceil ( y ) , math.abs ( y ) / y do
2019-10-10 08:16:32 +00:00
if mino.checkCollision ( 0 , sy ) then
mino.y = mino.y + sy - math.abs ( y ) / y
break
end
2020-03-30 00:55:31 +00:00
if sy ~= 0 then
2020-07-17 23:19:48 +00:00
mino.didWallKick = false
2020-03-30 00:55:31 +00:00
end
2019-10-10 08:16:32 +00:00
end
else
return false
end
end
return mino
end
2019-10-11 02:11:24 +00:00
-- generates a random number, excluding those listed in the _psExclude table
local pseudoRandom = function ( randomPieces )
2019-11-17 05:10:11 +00:00
if game.config . scrubMode then
return 1
else
if # randomPieces == 0 then
for i = 1 , # minos do
randomPieces [ i ] = i
end
2019-10-11 02:11:24 +00:00
end
2019-11-17 05:10:11 +00:00
local rand = math.random ( 1 , # randomPieces )
local num = randomPieces [ rand ]
table.remove ( randomPieces , rand )
return num
2019-10-11 02:11:24 +00:00
end
end
2019-10-10 08:16:32 +00:00
-- initialize players
2019-11-17 05:10:11 +00:00
local initializePlayers = function ( amountOfPlayers )
local newPlayer = function ( xmod , ymod )
return {
xmod = xmod ,
ymod = ymod ,
2019-11-21 06:56:52 +00:00
control = { } ,
2019-11-17 05:10:11 +00:00
board = clearBoard ( { } , 2 + xmod , 2 + ymod , 10 , nil , " f " ) ,
holdBoard = clearBoard ( { } , 13 + xmod , 14 + ymod , 4 , 3 , " f " , 0 ) ,
queueBoard = clearBoard ( { } , 13 + xmod , 2 + ymod , 4 , 14 , " f " , 0 ) ,
2019-11-21 06:56:52 +00:00
randomPieces = { } , -- list of all minos for pseudo-random selection
flashingSpecial = false , -- if true, then this player is flashing the special color
} , {
frozen = false , -- if true, literally cannot move or act
2019-11-17 05:10:11 +00:00
hold = 0 , -- current piece being held
canHold = true , -- whether or not player can hold (can't hold twice in a row)
queue = { } , -- current queue of minos to use
garbage = 0 , -- amount of garbage you'll get after the next drop
lines = 0 , -- amount of lines cleared, "points"
combo = 0 , -- amount of consequative line clears
drawCombo = false , -- draw the combo message
lastLinesClear = 0 , -- previous amount of simultaneous line clears (does not reset if miss)
level = 1 , -- level determines speed of mino drop
fallSteps = 0.1 , -- amount of spaces the mino will draw each drop
}
end
2019-11-21 06:56:52 +00:00
game.p = { }
game.pp = { }
2019-11-17 05:10:11 +00:00
for i = 1 , ( amountOfPlayers or 1 ) do
2019-11-21 08:36:38 +00:00
game.p [ i ] , game.pp [ i ] = newPlayer ( ( scr_x / 2 - 8 * amountOfPlayers ) + ( i - 1 ) * 18 , 0 )
2019-11-17 05:10:11 +00:00
end
2019-10-10 08:16:32 +00:00
-- generates the initial queue of minos per player
2019-11-21 06:56:52 +00:00
for p = 1 , # game.pp do
2019-10-10 08:16:32 +00:00
for i = 1 , # minos do
2019-11-21 06:56:52 +00:00
game.pp [ p ] . queue [ i ] = pseudoRandom ( game.p [ p ] . randomPieces )
2019-10-10 08:16:32 +00:00
end
end
end
-- actually renders a board to the screen
2019-10-11 02:11:24 +00:00
local renderBoard = function ( board , bx , by , doAgeSpaces , blankColor )
2019-10-10 08:16:32 +00:00
local char , line
local tY = board.y + ( by or 0 )
2019-11-17 05:10:11 +00:00
for y = ( board.topCull or 0 ) + 1 , board.ySize , 3 do
2019-10-10 08:16:32 +00:00
line = { ( " \143 " ) : rep ( board.xSize ) , " " , " " }
term.setCursorPos ( board.x + ( bx or 0 ) , tY )
for x = 1 , board.xSize do
2019-10-11 02:11:24 +00:00
line [ 2 ] = line [ 2 ] .. ( blankColor or board [ y ] [ x ] [ 2 ] )
2019-10-10 08:16:32 +00:00
if board [ y + 1 ] then
2019-10-11 02:11:24 +00:00
line [ 3 ] = line [ 3 ] .. ( blankColor or board [ y + 1 ] [ x ] [ 2 ] )
2019-10-10 08:16:32 +00:00
else
line [ 3 ] = line [ 3 ] .. board.BGcolor
end
end
term.blit ( line [ 1 ] , line [ 2 ] , line [ 3 ] )
line = { ( " \131 " ) : rep ( board.xSize ) , " " , " " }
term.setCursorPos ( board.x + ( bx or 0 ) , tY + 1 )
for x = 1 , board.xSize do
if board [ y + 2 ] then
2019-10-11 02:11:24 +00:00
line [ 2 ] = line [ 2 ] .. ( blankColor or board [ y + 1 ] [ x ] [ 2 ] )
line [ 3 ] = line [ 3 ] .. ( blankColor or board [ y + 2 ] [ x ] [ 2 ] )
2019-10-10 08:16:32 +00:00
elseif board [ y + 1 ] then
2019-10-11 02:11:24 +00:00
line [ 2 ] = line [ 2 ] .. ( blankColor or board [ y + 1 ] [ x ] [ 2 ] )
2019-10-10 08:16:32 +00:00
line [ 3 ] = line [ 3 ] .. board.BGcolor
else
line [ 2 ] = line [ 2 ] .. board.BGcolor
line [ 3 ] = line [ 3 ] .. board.BGcolor
end
end
term.blit ( line [ 1 ] , line [ 2 ] , line [ 3 ] )
tY = tY + 2
end
if doAgeSpaces then
for y = 1 , board.ySize do
for x = 1 , board.xSize do
ageSpace ( board , x , y )
end
end
end
end
-- checks if you've done the one thing in tetris that you need to be doing
local checkIfLineCleared = function ( board , y )
for x = 1 , board.xSize do
if not board [ y ] [ x ] [ 1 ] then
return false
end
end
return true
end
-- draws the score of a player, and clears the space where the combo text is drawn
2019-11-21 06:56:52 +00:00
local drawScore = function ( player , cPlayer )
if not cPlayer.drawCombo then
2019-11-17 05:10:11 +00:00
term.setCursorPos ( 2 + player.xmod , 18 + player.ymod )
term.setTextColor ( tColors.white )
term.write ( ( " " ) : rep ( 14 ) )
term.setCursorPos ( 2 + player.xmod , 18 + player.ymod )
2019-11-21 06:56:52 +00:00
term.write ( " Lines: " .. cPlayer.lines )
2019-11-17 05:10:11 +00:00
term.setCursorPos ( 2 + player.xmod , 19 + player.ymod )
term.write ( ( " " ) : rep ( 14 ) )
end
2019-10-10 08:16:32 +00:00
end
2019-11-21 06:56:52 +00:00
local drawLevel = function ( player , cPlayer )
2019-11-17 05:10:11 +00:00
term.setCursorPos ( 13 + player.xmod , 17 + player.ymod )
2019-11-21 06:56:52 +00:00
term.write ( " Lv " .. cPlayer.level .. " " )
2019-10-11 02:11:24 +00:00
end
2019-10-10 08:16:32 +00:00
-- draws the player's simultaneous line clear after clearing one or more lines
-- also tells the player's combo, which is nice
2020-09-04 01:48:11 +00:00
local drawComboMessage = function ( player , cPlayer , lines , didTspin , didDoAllClear )
2019-10-10 08:16:32 +00:00
local msgs = {
2020-07-17 23:19:48 +00:00
[ 0 ] = " " ,
2019-10-10 08:16:32 +00:00
" SINGLE " ,
" DOUBLE " ,
" TRIPLE " ,
" TETRIS "
}
2019-11-17 05:10:11 +00:00
if not msgs [ lines ] then
return
end
2019-11-22 07:37:44 +00:00
term.setCursorPos ( player.xmod + 2 , player.ymod + 18 )
2019-11-17 05:10:11 +00:00
term.setTextColor ( tColors.white )
term.write ( ( " " ) : rep ( 16 ) )
2019-11-22 07:37:44 +00:00
term.setCursorPos ( player.xmod + 2 , player.ymod + 18 )
2020-09-04 01:48:11 +00:00
if didDoAllClear then
term.write ( " ALL CLEAR!! " )
2019-11-17 05:10:11 +00:00
else
2020-09-04 01:48:11 +00:00
if didTspin then
if didTspin == 1 then
term.write ( " T-SPIN MINI " )
elseif didTspin == 2 then
term.write ( " T-SPIN " )
end
else
if lines == cPlayer.lastLinesCleared then
if lines == 3 then
term.write ( " OH BABY A " )
else
term.write ( " ANOTHER " )
end
2019-11-17 05:10:11 +00:00
end
2019-10-11 02:11:24 +00:00
end
2020-09-04 01:48:11 +00:00
term.write ( msgs [ lines ] )
2019-10-11 02:11:24 +00:00
end
2020-07-17 23:19:48 +00:00
if cPlayer.combo >= 2 and lines > 0 then
2019-11-22 07:37:44 +00:00
term.setCursorPos ( player.xmod + 2 , player.ymod + 19 )
2019-10-10 08:39:53 +00:00
term.setTextColor ( tColors.white )
2019-10-10 08:16:32 +00:00
term.write ( ( " " ) : rep ( 16 ) )
2019-11-22 07:37:44 +00:00
term.setCursorPos ( player.xmod + 2 , player.ymod + 19 )
2019-11-21 06:56:52 +00:00
if lines == 4 and cPlayer.combo == 3 then
2019-11-17 05:10:11 +00:00
term.write ( " HOLY SHIT! " )
2019-11-21 06:56:52 +00:00
elseif lines == 4 and cPlayer.combo > 3 then
2019-11-17 05:10:11 +00:00
term.write ( " ALRIGHT JACKASS " )
else
2019-11-21 06:56:52 +00:00
term.write ( cPlayer.combo .. " x COMBO " )
2019-11-17 05:10:11 +00:00
end
2019-10-10 08:16:32 +00:00
end
end
-- god damn it you've fucked up
2019-11-21 06:56:52 +00:00
local gameOver = function ( player , cPlayer )
2019-11-16 03:22:44 +00:00
local mino
2019-12-29 17:56:50 +00:00
local waitTime
2019-11-21 06:56:52 +00:00
if cPlayer.lines == 0 then
2019-11-17 05:10:11 +00:00
mino = makeNewMino ( " eatmyass " , player.board , 12 , 3 + game.boardOverflow )
2020-03-30 02:32:06 +00:00
waitTime = 70
2019-11-21 06:56:52 +00:00
elseif cPlayer.lines <= 5 then
2019-11-17 05:10:11 +00:00
mino = makeNewMino ( " yousuck " , player.board , 12 , 3 + game.boardOverflow )
2020-03-30 02:32:06 +00:00
waitTime = 60
2019-11-21 06:56:52 +00:00
elseif cPlayer.lines == 69 or cPlayer.lines == 690 then
2019-11-17 05:10:11 +00:00
mino = makeNewMino ( " nice " , player.board , 12 , 3 + game.boardOverflow )
2020-03-30 02:32:06 +00:00
waitTime = 50
2019-11-16 03:22:44 +00:00
else
2019-11-17 05:10:11 +00:00
mino = makeNewMino ( " gameover " , player.board , 12 , 3 + game.boardOverflow )
2020-03-30 02:32:06 +00:00
waitTime = 70
2019-11-16 03:22:44 +00:00
end
2019-10-10 08:16:32 +00:00
local color = 0
2020-07-17 23:19:48 +00:00
local evt
local sTimer
local cTimer = os.startTimer ( 1 )
local canSkip = false
2019-12-29 17:56:50 +00:00
for i = 1 , waitTime do
2019-11-22 07:37:44 +00:00
mino.x = mino.x - 1
2019-10-10 08:16:32 +00:00
mino.draw ( )
2019-11-21 06:56:52 +00:00
sendInfo ( " send_info " , false )
2019-10-10 08:16:32 +00:00
renderBoard ( player.board , 0 , 0 , true )
2019-10-10 08:39:53 +00:00
for i = 1 , 20 do
color = color + 0.01
2020-03-30 07:33:26 +00:00
game.setPaletteColor ( 4096 , math.sin ( color ) / 2 + 0.5 , math.sin ( color ) / 2 , math.sin ( color ) / 2 )
2019-10-10 08:16:32 +00:00
end
2020-07-17 23:19:48 +00:00
sTimer = os.startTimer ( 0.05 )
while true do
evt = { os.pullEvent ( ) }
if evt [ 1 ] == " timer " then
if evt [ 2 ] == sTimer then
break
elseif evt [ 2 ] == cTimer then
canSkip = true
end
elseif evt [ 1 ] == " key " then
if canSkip then
return
end
end
end
2019-10-10 08:16:32 +00:00
end
return
end
2020-03-30 00:55:31 +00:00
-- used when darkening just-placed pieces
local normalPalettes = { }
local darkerPalettes = { }
for i = 1 , 16 do
normalPalettes [ ( " 0123456789abcdef " ) : sub ( i , i ) ] = { term.getPaletteColor ( 2 ^ ( i - 1 ) ) }
end
2020-03-30 03:23:06 +00:00
local genDarkerPalettes = function ( mult )
for i = 1 , 16 do
darkerPalettes [ ( " 0123456789abcdef " ) : sub ( i , i ) ] = {
normalPalettes [ ( " 0123456789abcdef " ) : sub ( i , i ) ] [ 1 ] * ( mult or 0.6 ) ,
normalPalettes [ ( " 0123456789abcdef " ) : sub ( i , i ) ] [ 2 ] * ( mult or 0.6 ) ,
normalPalettes [ ( " 0123456789abcdef " ) : sub ( i , i ) ] [ 3 ] * ( mult or 0.6 ) ,
}
end
end
genDarkerPalettes ( )
2020-03-30 00:55:31 +00:00
2019-11-17 05:10:11 +00:00
-- calculates the amount of garbage to send
local calculateGarbage = function ( lines , combo , backToBack , didTspin )
local output = 0
local clearTbl = { }
if didTspin then
clearTbl = {
2 ,
4 ,
6 ,
8 ,
10 ,
12 ,
14 ,
}
else
clearTbl = {
0 ,
1 ,
2 ,
4 ,
6 ,
8 ,
10
}
end
return ( clearTbl [ lines ] or 0 ) + backToBack + math.max ( 0 , combo - 2 )
end
-- actually give a player some garbage
2019-11-21 08:39:35 +00:00
local doleOutGarbage = function ( player , cPlayer , amount )
2019-11-17 05:10:11 +00:00
local board = player.board
local gx = math.random ( 1 , board.xSize )
local repeatProbability = 75 -- percent probability that garbage will leave the same hole open
for i = 1 , amount do
table.remove ( player.board , 1 )
player.board [ board.ySize ] = { }
for x = 1 , board.xSize do
if x ~= gx then
player.board [ board.ySize ] [ x ] = { true , " 8 " , 0 , 0 }
else
player.board [ board.ySize ] [ x ] = { false , board.BGcolor , 0 , 0 }
end
end
if math.random ( 0 , 100 ) > repeatProbability then
gx = math.random ( 1 , board.xSize )
end
2020-09-04 02:18:41 +00:00
board.minoAmount = board.minoAmount + board.xSize - 1
2019-11-17 05:10:11 +00:00
end
2019-11-21 06:56:52 +00:00
cPlayer.garbage = 0
2019-11-17 05:10:11 +00:00
end
2020-03-30 03:23:06 +00:00
local ldPalettes = function ( light )
if light then
for k , v in pairs ( normalPalettes ) do
if k == " c " then
--term.setPaletteColor(to_colors[k], 0xf0f0f0)
else
2020-03-30 07:33:26 +00:00
game.setPaletteColor ( to_colors [ k ] , table.unpack ( v ) )
2020-03-30 03:23:06 +00:00
end
end
else
for i = 1 , 0.3 , - 0.1 do
genDarkerPalettes ( i )
for k , v in pairs ( darkerPalettes ) do
if k == " c " then
2020-03-30 07:33:26 +00:00
--game.setPaletteColor(to_colors[k], 0xf0f0f0)
2020-03-30 03:23:06 +00:00
else
2020-03-30 07:33:26 +00:00
game.setPaletteColor ( to_colors [ k ] , table.unpack ( v ) )
2020-03-30 03:23:06 +00:00
end
end
sleep ( 0.05 )
end
end
genDarkerPalettes ( )
end
2019-10-10 08:16:32 +00:00
-- initiates a game as a specific player (takes a number)
local startGame = function ( playerNumber )
local mino , ghostMino
2019-11-17 05:10:11 +00:00
local dropTimer , inputTimer , lockTimer , tickTimer , comboTimer
2019-11-21 06:56:52 +00:00
local evt , board , player , cPlayer , control
2019-11-17 05:10:11 +00:00
local finished -- whether or not a mino is done being placed
local clearedLines = { } -- used when calculating cleared lines
2019-10-10 08:16:32 +00:00
2019-11-21 06:56:52 +00:00
if game.net . isHost then
2019-10-10 08:16:32 +00:00
2019-11-21 06:56:52 +00:00
player = game.p [ playerNumber ]
cPlayer = game.pp [ playerNumber ]
board = player.board
control = player.control
2019-11-17 05:10:11 +00:00
2020-03-30 00:55:31 +00:00
local draw = function ( isSolid , doSendInfo )
2019-11-22 22:52:36 +00:00
local canChangeSpecial = true
for k , v in pairs ( game.p ) do
if v.flashingSpecial then
canChangeSpecial = false
break
end
end
if canChangeSpecial then
2020-03-30 07:33:26 +00:00
game.setPaletteColor ( 4096 , mino.ghostColor )
2019-11-21 06:56:52 +00:00
end
ghostMino.x = mino.x
ghostMino.y = mino.y
ghostMino.move ( 0 , board.ySize , true )
ghostMino.draw ( false )
mino.draw ( isSolid , ageSpaces )
2020-03-30 00:55:31 +00:00
if doSendInfo then
sendInfo ( " send_info " , false , playerNumber )
end
2019-11-21 06:56:52 +00:00
renderBoard ( board , 0 , 0 , true )
2020-04-12 06:29:20 +00:00
renderBoard ( player.queueBoard , 0 , 0 , false )
2019-11-17 05:10:11 +00:00
end
2019-11-21 06:56:52 +00:00
local currentMinoType
local takeFromQueue = true
local interpretInput = function ( )
finished = false
game.cancelTimer ( inputTimer )
inputTimer = game.startTimer ( game.inputDelay )
if control.quit == 1 then
finished = true
game.running = false
2020-03-30 03:23:06 +00:00
game.paused = false
ldPalettes ( true )
2019-11-21 06:56:52 +00:00
sendInfo ( " quit_game " , false )
return
2019-11-17 05:10:11 +00:00
end
2019-11-21 06:56:52 +00:00
if game.paused then
if control.pause == 1 then
2020-03-30 03:23:06 +00:00
ldPalettes ( true )
2019-11-21 06:56:52 +00:00
game.paused = false
2019-11-17 05:10:11 +00:00
end
2019-11-21 06:56:52 +00:00
else
if control.pause == 1 then
2020-03-30 03:23:06 +00:00
ldPalettes ( false )
2019-11-21 06:56:52 +00:00
game.paused = true
2019-11-17 05:10:11 +00:00
end
2019-11-21 06:56:52 +00:00
if not cPlayer.frozen then
if control.moveLeft == 1 or ( control.moveLeft or 0 ) > 1 + game.moveHoldDelay then
if mino.move ( - 1 , 0 ) then
game.cancelTimer ( lockTimer or 0 )
mino.waitingForLock = false
2020-03-30 00:55:31 +00:00
draw ( nil , true )
2019-11-21 06:56:52 +00:00
end
2019-11-17 05:10:11 +00:00
end
2019-11-21 06:56:52 +00:00
if control.moveRight == 1 or ( control.moveRight or 0 ) >= 1 + game.moveHoldDelay then
if mino.move ( 1 , 0 ) then
game.cancelTimer ( lockTimer or 0 )
mino.waitingForLock = false
2020-03-30 00:55:31 +00:00
draw ( nil , true )
2019-11-21 06:56:52 +00:00
end
end
2020-09-04 01:48:11 +00:00
if control.softDrop then
2019-11-21 06:56:52 +00:00
game.cancelTimer ( lockTimer or 0 )
mino.waitingForLock = false
2020-09-04 01:48:11 +00:00
local oldY = mino.y
mino.move ( 0 , game.softDropSpeed , true )
if mino.y ~= oldY then
2020-03-30 00:55:31 +00:00
draw ( nil , true )
2019-11-21 06:56:52 +00:00
else
2020-03-30 00:55:31 +00:00
if game.config . TGMlock then
draw ( true , true )
cPlayer.canHold = true
finished = true
2020-09-04 01:48:11 +00:00
board.minoAmount = board.minoAmount + mino.size
2019-11-21 06:56:52 +00:00
else
2020-03-30 00:55:31 +00:00
if mino.waitingForLock then
game.alterTimer ( lockTimer , - 0.1 )
else
mino.lockBreaks = mino.lockBreaks - 1
2020-09-04 01:48:11 +00:00
lockTimer = game.startTimer ( math.min ( math.max ( 0.2 / cPlayer.fallSteps , game.minimumLockTimer ) , game.maximumLockTimer ) )
2020-03-30 00:55:31 +00:00
mino.waitingForLock = true
end
2019-11-21 06:56:52 +00:00
end
end
end
if control.rotateLeft == 1 then
if mino.rotate ( - 1 ) then
ghostMino.y = mino.y
ghostMino.rotate ( - 1 )
game.cancelTimer ( lockTimer or 0 )
mino.waitingForLock = false
2020-03-30 00:55:31 +00:00
draw ( nil , true )
2019-11-21 06:56:52 +00:00
end
end
if control.rotateRight == 1 then
if mino.rotate ( 1 ) then
ghostMino.y = mino.y
ghostMino.rotate ( 1 )
game.cancelTimer ( lockTimer or 0 )
mino.waitingForLock = false
2020-03-30 00:55:31 +00:00
draw ( nil , true )
2019-11-21 06:56:52 +00:00
end
end
if control.hold == 1 then
if cPlayer.canHold then
if cPlayer.hold == 0 then
takeFromQueue = true
else
takeFromQueue = false
end
cPlayer.hold , currentMinoType = currentMinoType , cPlayer.hold
cPlayer.canHold = false
player.holdBoard = clearBoard ( player.holdBoard , nil , nil , nil , nil , nil , nil , true )
makeNewMino (
cPlayer.hold ,
player.holdBoard ,
# minos [ cPlayer.hold ] . shape [ 1 ] == 2 and 1 or 0 ,
0
2020-03-30 00:55:31 +00:00
) . draw ( false )
2019-11-21 06:56:52 +00:00
sendInfo ( " send_info " , false , playerNumber )
renderBoard ( player.holdBoard , 0 , 0 , false )
finished = true
2020-03-30 00:55:31 +00:00
cPlayer.didHold = true
2019-11-21 06:56:52 +00:00
end
end
2020-09-04 01:48:11 +00:00
if control.hardDrop == 1 then
2019-11-21 06:56:52 +00:00
mino.move ( 0 , board.ySize , true )
2020-03-30 00:55:31 +00:00
if game.config . TGMlock then
draw ( false )
else
draw ( true , true )
cPlayer.canHold = true
finished = true
2020-09-04 01:48:11 +00:00
board.minoAmount = board.minoAmount + mino.size
2020-03-30 00:55:31 +00:00
end
2020-09-04 01:48:11 +00:00
elseif control.sonicDrop == 1 then
mino.move ( 0 , board.ySize , true )
draw ( false )
2019-11-17 05:10:11 +00:00
end
end
end
2019-11-21 06:56:52 +00:00
for k , v in pairs ( player.control ) do
2019-11-22 07:37:44 +00:00
player.control [ k ] = v + game.inputDelay
2019-11-17 05:10:11 +00:00
end
end
2019-10-10 08:16:32 +00:00
2019-11-21 06:56:52 +00:00
renderBoard ( player.holdBoard , 0 , 0 , true )
2019-10-10 08:16:32 +00:00
2019-11-21 06:56:52 +00:00
while game.running do
2019-10-11 02:11:24 +00:00
2019-11-21 06:56:52 +00:00
cPlayer.level = math.ceil ( ( 1 + cPlayer.lines ) / 10 )
cPlayer.fallSteps = 0.075 * ( 1.33 ^ cPlayer.level )
2020-03-30 00:55:31 +00:00
cPlayer.didHold = false
2019-10-10 08:16:32 +00:00
2019-11-21 06:56:52 +00:00
if takeFromQueue then
currentMinoType = cPlayer.queue [ 1 ]
end
2019-10-10 08:16:32 +00:00
2019-11-21 06:56:52 +00:00
mino = makeNewMino (
currentMinoType ,
board ,
math.floor ( board.xSize / 2 ) - 2 ,
2020-09-04 01:48:11 +00:00
game.boardOverflow - 1
2019-10-10 08:16:32 +00:00
)
2020-07-17 23:19:48 +00:00
if mino.checkCollision ( ) then
mino.y = mino.y - 1
end
2019-11-21 08:36:38 +00:00
cPlayer.mino = mino
2019-11-21 06:56:52 +00:00
ghostMino = makeNewMino (
currentMinoType ,
board ,
math.floor ( board.xSize / 2 ) - 2 ,
2020-09-04 01:48:11 +00:00
game.boardOverflow - 1 ,
2019-11-21 06:56:52 +00:00
" c "
2019-10-10 08:16:32 +00:00
)
2019-11-21 08:36:38 +00:00
cPlayer.ghostMino = ghostMino
2019-10-10 08:16:32 +00:00
2019-11-21 06:56:52 +00:00
if takeFromQueue then
table.remove ( cPlayer.queue , 1 )
table.insert ( cPlayer.queue , pseudoRandom ( player.randomPieces ) )
end
2019-10-10 08:16:32 +00:00
2019-11-21 06:56:52 +00:00
-- draw queue
player.queueBoard = clearBoard ( player.queueBoard , nil , nil , nil , nil , nil , nil , true )
for i = 1 , math.min ( # cPlayer.queue , 4 ) do
local m = makeNewMino (
cPlayer.queue [ i ] ,
player.queueBoard ,
# minos [ cPlayer.queue [ i ] ] . shape [ 1 ] == 2 and 1 or 0 ,
1 + ( 3 * ( i - 1 ) ) + ( i > 1 and 2 or 0 )
)
m.draw ( )
end
-- draw held piece
if cPlayer.hold ~= 0 then
local m = makeNewMino (
cPlayer.hold ,
player.holdBoard ,
# minos [ cPlayer.hold ] . shape [ 1 ] == 2 and 1 or 0 ,
0
)
end
2019-10-10 08:16:32 +00:00
2019-11-21 06:56:52 +00:00
takeFromQueue = true
2019-10-10 08:16:32 +00:00
2019-11-21 06:56:52 +00:00
drawScore ( player , cPlayer )
drawLevel ( player , cPlayer )
2019-10-10 08:16:32 +00:00
2019-11-21 06:56:52 +00:00
term.setCursorPos ( 13 + player.xmod , 13 + player.ymod )
term.write ( " HOLD " )
2019-10-11 02:11:24 +00:00
2019-11-21 06:56:52 +00:00
-- check to see if you've topped out
if mino.checkCollision ( ) then
for k , v in pairs ( game.pp ) do
game.pp [ k ] . frozen = true
end
sendInfo ( " game_over " , false )
gameOver ( player , cPlayer )
sendInfo ( " quit_game " , false )
return
end
2019-10-11 02:11:24 +00:00
2020-03-30 07:33:26 +00:00
mino.draw ( )
ghostMino.move ( 0 , board.ySize , true )
ghostMino.draw ( )
sendInfo ( " send_info " , false , playerNumber )
2019-11-21 06:56:52 +00:00
draw ( )
2019-10-11 02:11:24 +00:00
2019-12-31 09:44:49 +00:00
game.cancelTimer ( dropTimer )
game.cancelTimer ( lockTimer )
2019-11-21 06:56:52 +00:00
dropTimer = game.startTimer ( 0 )
inputTimer = game.startTimer ( game.inputDelay )
game.cancelTimer ( lockTimer or 0 )
2019-10-11 02:11:24 +00:00
2019-11-22 07:37:44 +00:00
tickTimer = os.startTimer ( game.inputDelay )
2019-11-21 06:56:52 +00:00
-- drop a piece
while game.running do
evt = { os.pullEvent ( ) }
control = game.p [ playerNumber ] . control
2019-10-11 02:11:24 +00:00
2019-11-21 06:56:52 +00:00
-- tick down internal game timer system
if evt [ 1 ] == " timer " then
if evt [ 2 ] == tickTimer then
--local delKeys = {}
for k , v in pairs ( game.timers ) do
game.timers [ k ] = v - 0.05
if v <= 0 then
os.queueEvent ( " gameTimer " , k )
game.timers [ k ] = nil
end
end
2019-11-22 07:37:44 +00:00
tickTimer = os.startTimer ( game.inputDelay )
2019-11-21 06:56:52 +00:00
elseif evt [ 2 ] == comboTimer then
cPlayer.drawCombo = false
drawScore ( player , cPlayer )
2019-10-10 08:16:32 +00:00
end
2019-10-11 02:11:24 +00:00
end
2019-11-17 05:10:11 +00:00
2019-11-21 06:56:52 +00:00
if player.paused then
if evt [ 1 ] == " gameTimer " then
if control.pause == 1 then
game.paused = false
end
2019-10-11 02:11:24 +00:00
end
2019-11-21 06:56:52 +00:00
else
if evt [ 1 ] == " key " and evt [ 3 ] == false then
2019-11-17 05:10:11 +00:00
interpretInput ( )
if finished then
break
2019-10-11 02:11:24 +00:00
end
2019-11-17 05:10:11 +00:00
2019-11-21 06:56:52 +00:00
elseif evt [ 1 ] == " gameTimer " then
if evt [ 2 ] == inputTimer then
interpretInput ( )
if finished then
break
end
elseif evt [ 2 ] == dropTimer then
dropTimer = game.startTimer ( 0 )
if not game.paused then
if not cPlayer.frozen then
2020-03-30 00:55:31 +00:00
mino.oldY = mino.y
2019-11-21 06:56:52 +00:00
if mino.checkCollision ( 0 , 1 ) then
if mino.lockBreaks == 0 then
draw ( true )
cPlayer.canHold = true
break
elseif not mino.waitingForLock then
mino.lockBreaks = mino.lockBreaks - 1
2020-09-04 01:48:11 +00:00
lockTimer = game.startTimer ( math.min ( math.max ( 0.2 / cPlayer.fallSteps , game.minimumLockTimer ) , game.maximumLockTimer ) )
2019-11-21 06:56:52 +00:00
mino.waitingForLock = true
end
else
mino.move ( 0 , cPlayer.fallSteps , true )
2020-03-30 00:55:31 +00:00
if math.floor ( mino.oldY ) ~= math.floor ( mino.y ) then
2020-03-30 07:33:26 +00:00
draw ( false , true )
--sendInfo("send_info", false)
2020-03-30 00:55:31 +00:00
end
2019-11-21 06:56:52 +00:00
draw ( )
end
2019-10-11 02:11:24 +00:00
end
end
2019-11-21 06:56:52 +00:00
elseif evt [ 2 ] == lockTimer then
if not game.paused then
cPlayer.canHold = true
draw ( true )
break
end
2019-10-10 08:16:32 +00:00
end
end
end
end
2019-11-21 06:56:52 +00:00
clearedLines = { }
for y = 1 , board.ySize do
if checkIfLineCleared ( board , y ) then
table.insert ( clearedLines , y )
2020-09-04 01:48:11 +00:00
board.minoAmount = board.minoAmount - board.xSize
2019-11-21 06:56:52 +00:00
end
2019-10-10 08:16:32 +00:00
end
2019-11-21 06:56:52 +00:00
if # clearedLines == 0 then
if cPlayer.canHold then
cPlayer.combo = 0
end
2020-07-17 23:19:48 +00:00
if mino.didTspin then
cPlayer.drawCombo = true
os.cancelTimer ( comboTimer or 0 )
comboTimer = os.startTimer ( 2 )
drawComboMessage ( player , cPlayer , # clearedLines , mino.didTspin )
end
2019-11-17 05:10:11 +00:00
else
2019-11-21 06:56:52 +00:00
cPlayer.combo = cPlayer.combo + 1
cPlayer.lines = cPlayer.lines + # clearedLines
cPlayer.drawCombo = true
os.cancelTimer ( comboTimer or 0 )
comboTimer = os.startTimer ( 2 )
if cPlayer.lastLinesCleared == # clearedLines and # clearedLines >= 3 then
player.backToBack = player.backToBack + 1
else
player.backToBack = 0
end
2019-11-17 05:10:11 +00:00
2020-09-04 01:48:11 +00:00
-- check for all clear
local didDoAllClear = board.minoAmount == 0
drawComboMessage ( player , cPlayer , # clearedLines , mino.didTspin , didDoAllClear )
2019-11-17 05:10:11 +00:00
2019-11-21 06:56:52 +00:00
cPlayer.lastLinesCleared = # clearedLines
2019-11-17 05:10:11 +00:00
2019-11-21 06:56:52 +00:00
-- give the other fucktard(s) some garbage
2020-09-04 01:48:11 +00:00
cPlayer.garbage = ( didDoAllClear and - 10 or 0 ) + cPlayer.garbage - calculateGarbage ( # clearedLines , cPlayer.combo , player.backToBack , mino.didTspin ) -- calculate T-spin later
2019-11-21 06:56:52 +00:00
if cPlayer.garbage < 0 then
for e , enemy in pairs ( game.pp ) do
if e ~= playerNumber then
enemy.garbage = enemy.garbage - cPlayer.garbage
end
2019-11-17 05:10:11 +00:00
end
end
2019-11-21 06:56:52 +00:00
cPlayer.garbage = math.max ( 0 , cPlayer.garbage )
2019-11-17 05:10:11 +00:00
2019-10-10 08:16:32 +00:00
for l = 1 , # clearedLines do
for x = 1 , board.xSize do
board [ clearedLines [ l ] ] [ x ] [ 2 ] = " c "
end
end
2019-11-21 06:56:52 +00:00
-- make the other network player see the flash
sendInfo ( " flash_special " , false )
player.flashingSpecial = true
2019-10-10 08:16:32 +00:00
renderBoard ( board , 0 , 0 , true )
2019-11-21 06:56:52 +00:00
for i = 1 , 0 , - 0.12 do
2020-03-30 07:33:26 +00:00
game.setPaletteColor ( 4096 , i , i , i )
2019-11-21 06:56:52 +00:00
sleep ( 0.05 )
end
for i = # clearedLines , 1 , - 1 do
table.remove ( board , clearedLines [ i ] )
end
for i = 1 , # clearedLines do
table.insert ( board , 1 , false )
end
board = clearBoard ( board )
player.flashingSpecial = false
2019-10-10 08:16:32 +00:00
end
2019-11-21 06:56:52 +00:00
-- take some garbage for yourself
if cPlayer.garbage > 0 then
2019-11-21 08:39:35 +00:00
doleOutGarbage ( player , cPlayer , cPlayer.garbage )
2019-10-10 08:16:32 +00:00
end
2020-03-30 00:55:31 +00:00
if # clearedLines == 0 and game.running and not cPlayer.didHold then
mino.draw ( false , " c " )
2020-03-30 07:33:26 +00:00
game.setPaletteColor ( colors.brown , table.unpack ( darkerPalettes [ mino.color ] ) )
2020-03-30 00:55:31 +00:00
renderBoard ( board , 0 , 0 , true )
sleep ( game.appearanceDelay )
mino.draw ( true )
2020-09-04 01:48:11 +00:00
--board.minoAmount = board.minoAmount + mino.size
2020-03-30 07:33:26 +00:00
renderBoard ( board , 0 , 0 , false )
2020-03-30 00:55:31 +00:00
end
2019-10-10 08:16:32 +00:00
end
2019-11-21 06:56:52 +00:00
else
-- if you're a client, take in all that board info and just fukkin draw it
2019-11-17 05:10:11 +00:00
2019-11-21 06:56:52 +00:00
inputTimer = os.startTimer ( game.inputDelay )
2019-11-22 07:37:44 +00:00
local timeoutTimer = os.startTimer ( 3 )
2019-11-17 05:10:11 +00:00
2019-11-21 06:56:52 +00:00
while game.running do
evt = { os.pullEvent ( ) }
if evt [ 1 ] == " new_player_info " then
player = game.p [ game.you ]
for k , v in pairs ( game.p ) do
renderBoard ( v.board , 0 , 0 , false )
renderBoard ( v.holdBoard , 0 , 0 , false )
renderBoard ( v.queueBoard , 0 , 0 , false )
drawScore ( v , game.pp [ k ] )
drawLevel ( v , game.pp [ k ] )
term.setCursorPos ( 13 + v.xmod , 13 + v.ymod )
term.write ( " HOLD " )
end
2019-11-22 07:37:44 +00:00
os.cancelTimer ( timeoutTimer or 0 )
timeoutTimer = os.startTimer ( 3 )
elseif evt [ 1 ] == " timer " then
if evt [ 2 ] == inputTimer then
os.cancelTimer ( inputTimer or 0 )
inputTimer = os.startTimer ( game.inputDelay )
if player then
for k , v in pairs ( player.control ) do
player.control [ k ] = v + game.inputDelay
end
2019-11-21 06:56:52 +00:00
end
2019-11-22 07:37:44 +00:00
elseif evt [ 2 ] == timeoutTimer then
return
2019-11-21 06:56:52 +00:00
end
end
2019-11-17 05:10:11 +00:00
end
2019-11-21 06:56:52 +00:00
2019-10-10 08:16:32 +00:00
end
end
-- records all key input
local getInput = function ( )
local evt
while true do
evt = { os.pullEvent ( ) }
if evt [ 1 ] == " key " and evt [ 3 ] == false then
keysDown [ evt [ 2 ] ] = 1
elseif evt [ 1 ] == " key_up " then
keysDown [ evt [ 2 ] ] = nil
end
2019-11-21 06:56:52 +00:00
if ( evt [ 1 ] == " key " and evt [ 3 ] == false ) or ( evt [ 1 ] == " key_up " ) then
if game.revControl [ evt [ 2 ] ] then
game.p [ game.you ] . control [ game.revControl [ evt [ 2 ] ] ] = keysDown [ evt [ 2 ] ]
2019-11-21 08:36:38 +00:00
if not game.net . isHost then
sendInfo ( " send_info " , false )
end
2019-11-21 06:56:52 +00:00
end
end
2019-10-10 08:16:32 +00:00
end
end
2019-11-21 06:56:52 +00:00
local cTime
local networking = function ( )
local evt , side , channel , repchannel , msg , distance
2019-11-22 22:52:36 +00:00
local currentPlayers = 1
2019-11-21 06:56:52 +00:00
while true do
if game.net . useSkynet then
evt , channel , msg = os.pullEvent ( " skynet_message " )
else
evt , side , channel , repchannel , msg , distance = os.pullEvent ( " modem_message " )
end
if channel == game.net . channel and type ( msg ) == " table " then
if game.net . waitingForGame then
if type ( msg.time ) == " number " and msg.command == " find_game " then
2019-11-22 07:37:44 +00:00
if msg.instanceID ~= game.instanceID then
if msg.time < cTime then
game.net . isHost = false
game.you = 2
game.net . gameID = msg.gameID
else
game.net . isHost = true
end
2019-11-21 06:56:52 +00:00
2019-11-22 07:37:44 +00:00
transmit ( {
gameID = game.net . gameID ,
time = cTime ,
command = " find_game " ,
instanceID = game.instanceID
} )
game.net . waitingForGame = false
os.queueEvent ( " new_game " , game.net . gameID )
return game.net . gameID
end
2019-11-21 06:56:52 +00:00
end
else
if msg.gameID == game.net . gameID then
2019-11-17 05:10:11 +00:00
2019-11-21 06:56:52 +00:00
if game.net . isHost then
if type ( msg.control ) == " table " then
2019-11-22 22:52:36 +00:00
if type ( msg.you ) == " number " and msg.you ~= game.you then
game.p [ msg.you ] . control = msg.control
for y = 1 , game.p [ msg.you ] . board.ySize do
for x = 1 , game.p [ msg.you ] . board.xSize do
ageSpace ( game.p [ msg.you ] . board , x , y )
end
2019-11-21 08:36:38 +00:00
end
end
2019-11-21 06:56:52 +00:00
end
else
2019-11-22 22:52:36 +00:00
if type ( msg.you ) == " number " and msg.you ~= game.you then
if type ( msg.p ) == " table " then
if msg.pNum then
for k , v in pairs ( msg.p ) do
if k ~= " control " then
game.p [ msg.pNum ] [ k ] = v
end
2019-11-21 06:56:52 +00:00
end
2019-11-22 22:52:36 +00:00
else
game.p = msg.p
2019-11-21 06:56:52 +00:00
end
2019-11-22 22:52:36 +00:00
if msg.specialColor then
2020-03-30 07:33:26 +00:00
game.setPaletteColor ( tColors.special , table.unpack ( msg.specialColor ) )
2019-11-22 22:52:36 +00:00
end
os.queueEvent ( " new_player_info " , msg.p )
2019-11-21 06:56:52 +00:00
end
2019-11-22 22:52:36 +00:00
if msg.command == " quit_game " then
return
2019-11-21 06:56:52 +00:00
end
2019-11-22 22:52:36 +00:00
if msg.command == " flash_special " then
for i = 1 , 0 , - 0.12 do
2020-03-30 07:33:26 +00:00
game.setPaletteColor ( 4096 , i , i , i )
2019-11-22 22:52:36 +00:00
renderBoard ( game.p [ msg.you ] . board , 0 , 0 , true )
sleep ( 0.05 )
end
2019-11-21 06:56:52 +00:00
end
end
end
end
end
2019-11-17 05:10:11 +00:00
end
end
2019-10-10 08:16:32 +00:00
end
2019-11-21 06:56:52 +00:00
local cwrite = function ( text , y , xdiff , wordPosCheck )
wordPosCheck = wordPosCheck or # text
term.setCursorPos ( math.floor ( scr_x / 2 - math.floor ( 0.5 + # text + ( xdiff or 0 ) ) / 2 ) , y or ( scr_y - 2 ) )
term.write ( text )
return ( scr_x / 2 ) - ( # text / 2 ) + wordPosCheck
end
2019-11-17 05:10:11 +00:00
2019-11-21 06:56:52 +00:00
local setUpModem = function ( )
if game.net . useSkynet then
if fs.exists ( game.net . skynetPath ) then
game.net . skynet = dofile ( game.net . skynetPath )
term.clear ( )
cwrite ( " Connecting to Skynet... " , scr_y / 2 )
game.net . skynet.open ( game.net . channel )
2019-11-22 07:37:44 +00:00
return true
2019-11-21 06:56:52 +00:00
else
term.clear ( )
cwrite ( " Downloading Skynet... " , scr_y / 2 )
local prog = http.get ( game.net . skynetURL )
if prog then
local file = fs.open ( game.net . skynetPath , " w " )
file.write ( prog.readAll ( ) )
file.close ( )
skynet = dofile ( game.net . skynetPath )
cwrite ( " Connecting to Skynet... " , 1 + scr_y / 2 )
skynet.open ( game.net . channel )
2019-11-22 07:37:44 +00:00
return true
2019-11-21 06:56:52 +00:00
else
2019-11-22 07:37:44 +00:00
return false , " Could not download Skynet. "
2019-11-21 06:56:52 +00:00
end
end
else
-- unload / close skynet
if game.net . skynet then
if game.net . skynet.socket then
game.net . skynet.socket . close ( )
end
game.net . skynet = nil
end
game.net . modem = peripheral.find ( " modem " )
if ( not game.net . modem ) and ccemux then
ccemux.attach ( " top " , " wireless_modem " )
game.net . modem = peripheral.find ( " modem " )
end
if game.net . modem then
game.net . modem.open ( game.net . channel )
2019-11-22 07:37:44 +00:00
return true
2019-11-21 06:56:52 +00:00
else
2019-11-22 07:37:44 +00:00
return false , " No modem was found. "
2019-11-21 06:56:52 +00:00
end
end
end
local pleaseWait = function ( )
local periods = 1
local maxPeriods = 5
term.setBackgroundColor ( tColors.black )
term.setTextColor ( tColors.gray )
term.clear ( )
local tID = os.startTimer ( 0.2 )
local evt , txt
if game.net . useSkynet then
txt = " Waiting for Skynet game "
else
txt = " Waiting for modem game "
end
while true do
cwrite ( " (Press 'Q' to cancel) " , 2 )
cwrite ( txt , scr_y - 2 , maxPeriods )
term.write ( ( " . " ) : rep ( periods ) )
evt = { os.pullEvent ( ) }
if evt [ 1 ] == " timer " and evt [ 2 ] == tID then
tID = os.startTimer ( 0.5 )
periods = ( periods % maxPeriods ) + 1
term.clearLine ( )
elseif evt [ 1 ] == " key " and evt [ 2 ] == keys.q then
return
end
end
end
local titleScreen = function ( ) -- mondo placeholder
term.setTextColor ( tColors.white )
term.setBackgroundColor ( tColors.black )
term.clear ( )
cwrite ( " LDris " , 3 )
cwrite ( " by LDDestroier " , 5 )
cwrite ( " Press 1 to play a game. " , 7 )
if game.net . useSkynet then
cwrite ( " Press 2 to play an HTTP game. " , 8 )
cwrite ( " Press S to disable Skynet. " , 9 )
else
cwrite ( " Press 2 to play a modem game. " , 8 )
cwrite ( " Press S to enable Skynet. " , 9 )
end
2019-11-22 07:37:44 +00:00
cwrite ( " Press H to see controls. " , 10 )
cwrite ( " Press Q to quit. " , 11 )
2019-11-21 06:56:52 +00:00
local evt
while true do
evt = { os.pullEvent ( ) }
if evt [ 1 ] == " key " then
if evt [ 2 ] == keys.one then
return " 1P "
elseif evt [ 2 ] == keys.two then
return " 2P "
elseif evt [ 2 ] == keys.s then
return " skynet "
2019-11-22 07:37:44 +00:00
elseif evt [ 2 ] == keys.h then
return " help "
2019-11-21 06:56:52 +00:00
elseif evt [ 2 ] == keys.q then
return " quit "
end
end
end
end
2019-11-22 07:37:44 +00:00
local screenError = function ( ... )
local lines = { ... }
term.setBackgroundColor ( tColors.black )
term.setTextColor ( tColors.white )
term.clear ( )
for i = 1 , # lines do
cwrite ( lines [ i ] , 2 + i )
end
cwrite ( " Press any key to continue. " , # lines + 4 )
sleep ( 0 )
repeat until os.pullEvent ( " key " )
end
-- a lot of these menus and whatnot are very primitive. I can improve that later
local showHelp = function ( )
term.setBackgroundColor ( tColors.black )
term.setTextColor ( tColors.white )
term.clear ( )
cwrite ( " CONTROLS (defaults): " , 2 )
term.setCursorPos ( 1 , 4 )
print ( " Move Piece: LEFT and RIGHT " )
print ( " Hard Drop: UP " )
2020-09-04 02:19:56 +00:00
print ( " Soft Drop: DOWN " )
print ( " Sonic Drop: SPACE " )
2019-11-22 07:37:44 +00:00
print ( " Rotate Piece: Z and X " )
print ( " Hold Piece: L.SHIFT " )
print ( " Quit: Q " )
print ( " \n Press any key to continue. " )
sleep ( 0 )
repeat until os.pullEvent ( " key " )
end
2019-11-21 06:56:52 +00:00
local main = function ( )
local rVal -- please wait result
local modeVal -- title screen mode result
local funcs
setUpModem ( )
while true do
game.you = 1
game.net . isHost = true
finished = false
game.running = true
while true do
modeVal = titleScreen ( )
if modeVal == " 1P " then
game.net . active = false
game.amountOfPlayers = 1
2019-11-22 07:37:44 +00:00
game.gameDelay = 0.05
2019-11-21 06:56:52 +00:00
break
elseif modeVal == " 2P " then
2019-11-22 07:37:44 +00:00
if setUpModem ( ) then
if ( game.net . skynet and game.net . useSkynet ) then
game.gameDelay = 0.1
else
game.gameDelay = 0.05
end
game.net . active = true
game.amountOfPlayers = 2
break
else
screenError ( " A modem is required for multiplayer. " )
finished = true
end
2019-11-21 06:56:52 +00:00
elseif modeVal == " skynet " then
2019-11-22 07:37:44 +00:00
if http.websocket then
game.net . useSkynet = not game.net . useSkynet
setUpModem ( )
else
screenError (
" Skynet requires websocket support. " ,
" Use CCEmuX, CC:Tweaked, " ,
" or CraftOS-PC 2.2 or higher to play. "
)
finished = true
end
elseif modeVal == " help " then
showHelp ( )
2019-11-21 06:56:52 +00:00
elseif modeVal == " quit " then
return false
end
end
if game.net . active then
game.net . waitingForGame = true
cTime = getTime ( )
transmit ( {
gameID = game.net . gameID ,
time = cTime ,
2019-11-22 07:37:44 +00:00
command = " find_game " ,
instanceID = game.instanceID
2019-11-21 06:56:52 +00:00
} )
if game.net . useSkynet then
rVal = parallel.waitForAny ( networking , pleaseWait , game.net . skynet.listen )
else
rVal = parallel.waitForAny ( networking , pleaseWait )
end
sleep ( 0.1 )
if rVal == 1 then
funcs = {
getInput ,
}
if game.net . active then
table.insert ( funcs , networking )
if game.net . useSkynet and game.net . skynet then
table.insert ( funcs , game.net . skynet.listen )
end
end
initializePlayers ( game.amountOfPlayers or 1 )
if game.net . isHost then
for k , v in pairs ( game.p ) do
funcs [ # funcs + 1 ] = function ( )
return startGame ( k )
end
end
else
funcs [ # funcs + 1 ] = startGame
end
else
finished = true
end
else
funcs = { getInput }
initializePlayers ( game.amountOfPlayers or 1 )
for k , v in pairs ( game.p ) do
funcs [ # funcs + 1 ] = function ( )
return startGame ( k )
end
end
end
if not finished then
term.setBackgroundColor ( tColors.gray )
term.clear ( )
parallel.waitForAny ( table.unpack ( funcs ) )
end
end
end
main ( )
2019-10-10 08:16:32 +00:00
2019-10-10 08:39:53 +00:00
-- reset palette to back from whence it came
for k , v in pairs ( colors ) do
if type ( v ) == " number " then
term.setPaletteColor ( v , term.nativePaletteColor ( v ) )
end
2019-10-10 08:16:32 +00:00
end
term.setBackgroundColor ( colors.black )
term.setTextColor ( colors.white )
2019-10-10 08:39:53 +00:00
2019-11-21 06:56:52 +00:00
if game.net . skynet then
if game.net . skynet.socket then
game.net . skynet.socket . close ( )
end
end
2019-10-11 02:11:24 +00:00
for i = 1 , 5 do
2019-10-10 08:39:53 +00:00
term.scroll ( 1 )
2019-10-11 02:11:24 +00:00
if i == 3 then
2019-10-10 08:39:53 +00:00
term.setCursorPos ( 1 , scr_y )
term.write ( " Thanks for playing! " )
end
sleep ( 0.05 )
end
2019-10-10 08:16:32 +00:00
term.setCursorPos ( 1 , scr_y )