Jump to content

  • Log In with Google      Sign In   
  • Create Account

SynaGl0w

Member Since 24 Jan 2009
Offline Last Active Mar 27 2013 09:08 AM

Topics I've Started

Tetris clone in BASH script

21 March 2013 - 11:14 AM

Way back while learning BASH scripting I made a tetris clone, as is common practice when learning a new language. Being a C++ guy, the result was horrible to look at. You can also tell that I got lazy with comments. Plenty of unfinished things as well. Behold:

 

#!/bin/bash

#-----------------------------------------------------------------------------
# A tetromino stacking game written entirely in BASH script! =D
#
# Because I can...
# 
#-----------------------------------------------------------------------------
# Version 0.1 Beta:
#	- The game is functional
#	- Todo:
#		- Overtime bonus to score after all 10 lines of level 10 are cleared
#		- Highscores
#=============================================================================

#=============================================================================
#-----------------------------------------------------------------------------
# [ Global Variables ]
#-----------------------------------------------------------------------------
#=============================================================================
declare -r TETRIBASHTITLE="TetriBASH"
declare -ri TETRIBASHVERSION=0
declare -ri TETRIBASHSUBVERS=1
declare -r TETRIBASHRELEASE="Beta"
declare -r TETRIBASHDATE="2010 - 2012"
declare -r TETRIBASHINFO="A tetromino stacking game written entirely in"
declare -r TETRIBASHINFO2="BASH script! =D"
declare -r TETRIBASHINFO3="Because I can..."

declare -i TETRIBASHSTATE=0	# Indicates the current game state
declare -i TETRIBASHDEBUG=0	# Value of 1 enables debug mode

declare TIMESTART="0.0" 	# Start time of a frame
declare TIMEEND="0.0"		# End time of a frame
declare DELTATIME="0.0"		# Time elapsed for the frame
declare ACCUMULATOR="0.0"	# Primary gameplay accumulator

declare -ri TERMULT=2	# and chaos		# Multiplier to determin tetromino block width in characters (Do not change!)
declare -ri TERMWIDTH=$(tput cols)		# Character width of the terminal
declare -ri TERMHEIGHT=$(tput lines)	# Character height of the terminal

declare -ri GAMEWIDTH=34											# Width of the game area
declare -ri GAMEOFFSETX=$((($TERMWIDTH / 2) - ($GAMEWIDTH / 2)))	# X offset of the game area
declare -ri GAMEOFFSETY=2											# Y offset of the game area

declare -ri GAMEBLOCKSIZE=4											# Width and height of the game block array
declare -ri GAMEBLOCKAREA=$(($GAMEBLOCKSIZE * $GAMEBLOCKSIZE))		# Size of the game block array

declare -i GAMESCORE=0			# Game score
declare -i GAMESCOREMULTDEF=33	# Score Multiplier Default
declare -i GAMESCOREMULT=33		# Score Multiplier
declare -i GAMESCOREMULTINC=100	# Score Multiplier increase per level
declare -i GAMELEVEL=0			# Game level
declare -i GAMELINES=0			# Number of lines cleared
declare -i GAMELINESPERLEVEL=10	# Number of lines that need to be cleared to advance in level
declare -i GAMELEVELLINES=0		# Number of lines cleared this level	
declare -i GAMEFAILUREMAX=10	# NUmber of blocks to place after failure before showing Game Over message
declare -i GAMEFAILURECOUNT=0	# Number of blocks placed on top of eachother
declare -i GAMEFAILURE=0		# Indicates a game is determined to be lost
declare -i GAMECURRENT=0		# Current active block ID
declare -i GAMECURRENTROT=0		# Current active block rotation
declare -i GAMENEXT=0			# The next block ID
declare -i GAMERUNNING=0		# Indicates the game is running

declare -a GAMECURRENTARRAY		# Current active block array
declare -a GAMENEXTARRAY		# Next block array
declare -a GAMEBLOCKBUFFER		# Current active block rotation buffer

declare -i GAMECLEARINPROGRESS=0	# Indicates a line clear is in progress
declare -i GAMEOVERINPROGRESS=0		# Indicates game over is in progress
declare -i GAMELINESTOCLEAR=0		# Number of lines that need clearing
declare -a GAMELINESBUFFER			# Lists of lines that need clearing
declare -i GAMECLEARANIMFRAMES=3	# Number of frames of clearing animation
declare -r GAMECLEARCHAR=":"

declare -i GAMEBLOCKX=0			# X position of active game block relative to terminal
declare -i GAMEBLOCKY=0			# Y position of active game block relative to terminal		
declare -i GAMEBLOCKAPX=0		# X position of active game block relative to the play area
declare -i GAMEBLOCKAPY=0		# Y position of active game block relative to the play area

declare GAMEINTERVAL="0.5"		# Fall rate in seconds
declare GAMECLEARINTERVAL="0.2"	# Clear rate in seconds
declare GAMEOVERINTERVAL="5.0"	# Game Over message interval in seconds

declare -i FRAMEUPDATED=0		# Indicates drawing has been done in the current frame

declare -ri TBASHW=10									# Width of the play area in blocks
declare -ri TBASHH=20									# Height of the play area in blocks
declare -ri TBASHSIZE=$(($TBASHW * $TBASHH))			# Size of the play area array
declare -ri TBASHAREAOFFSETX=$GAMEOFFSETX				# X offset of play area including border
declare -ri TBASHAREAOFFSETY=$GAMEOFFSETY				# Y offset of play area including border
declare -ri TBASHAREAW=$((($TBASHW * $TERMULT) + 2))	# Width of play area including border
declare -ri TBASHAREAH=$(($TBASHH + 2))					# Height of play area including border
declare -ri TBASHOFFSETX=$(($TBASHAREAOFFSETX + 1))		# X offset of play area
declare -ri TBASHOFFSETY=$(($TBASHAREAOFFSETY + 1))		# Y offset of play area

declare -ri TBASHGAMEOVEROFFSETX=$(($TBASHAREAOFFSETX + 2))
declare -ri TBASHGAMEOVEROFFSETY=$(($TBASHAREAOFFSETY + ($TBASHAREAH / 2) - 2))
declare -ri TBASHGAMEOVERWIDTH=$(($TBASHAREAW - 4))
declare -ri TBASHGAMEOVERHEIGHT=3

declare -ri TBASHSCOREW=10
declare -ri TBASHSCOREH=3
declare -ri TBASHSCOREOFFSETX=$(($TBASHAREAW + 2 + $GAMEOFFSETX))
declare -ri TBASHSCOREOFFSETY=$GAMEOFFSETY
declare -ri TBASHSCOREVALUEX=$(($TBASHSCOREOFFSETX + 1))
declare -ri TBASHSCOREVALUEY=$(($TBASHSCOREOFFSETY + 1))

declare -ri TBASHLEVELW=10
declare -ri TBASHLEVELH=3
declare -ri TBASHLEVELOFFSETX=$(($TBASHAREAW + 2 + $GAMEOFFSETX))
declare -ri TBASHLEVELOFFSETY=$(($GAMEOFFSETY + 1 + $TBASHSCOREH))
declare -ri TBASHLEVELVALUEX=$(($TBASHLEVELOFFSETX + 1))
declare -ri TBASHLEVELVALUEY=$(($TBASHLEVELOFFSETY + 1))

declare -ri TBASHLINESW=10
declare -ri TBASHLINESH=3
declare -ri TBASHLINESOFFSETX=$(($TBASHAREAW + 2 + $GAMEOFFSETX))
declare -ri TBASHLINESOFFSETY=$(($GAMEOFFSETY + 1 + $TBASHSCOREH + 1 + $TBASHLEVELH))
declare -ri TBASHLINESVALUEX=$(($TBASHLINESOFFSETX + 1))
declare -ri TBASHLINESVALUEY=$(($TBASHLINESOFFSETY + 1))

declare -ri TBASHNEXTW=10
declare -ri TBASHNEXTH=6
declare -ri TBASHNEXTOFFSETX=$(($TBASHAREAW + 2 + $GAMEOFFSETX))
declare -ri TBASHNEXTOFFSETY=$(($GAMEOFFSETY + $TBASHAREAH - $TBASHNEXTH))
declare -ri TBASHNEXTVALUEX=$(($TBASHNEXTOFFSETX + 1))
declare -ri TBASHNEXTVALUEY=$(($TBASHNEXTOFFSETY + 1))

declare -ri MAINTITLEW=49
declare -ri MAINTITLEH=5
declare -ri MAINTITLEX=$((($TERMWIDTH / 2) - ($MAINTITLEW / 2)))
declare -ri MAINTITLEY=1
declare -r MAINTITLELINE1="\e[0;31m  ______      __       _ ____  ___   _____ __  __\e[0m"
declare -r MAINTITLELINE2="\e[1;31m /_  __/___  / /______(_) __ )/   | / ___// / / /\e[0m"
declare -r MAINTITLELINE3="\e[0;33m  / /  / _ \\/ __/ ___/ / __  / /| | \\__ \\/ /_/ / \e[0m"
declare -r MAINTITLELINE4="\e[1;33m / /  /  __/ /_/ /  / / /_/ / ___ |___/ / __  /  \e[0m"
declare -r MAINTITLELINE5="\e[1;37m/_/   \\___/\\__/_/  /_/_____/_/  |_/____/_/ /_/   \e[0m"

declare -ri TBASHABOUTW=49
declare -ri TBASHABOUTH=7
declare -ri TBASHABOUTX=$((($TERMWIDTH / 2) - ($TBASHABOUTW / 2)))
declare -ri TBASHABOUTY=$(($MAINTITLEH + 5))

declare -ri MAINMENUW=15
declare -ri MAINMENUH=4
declare -ri MAINMENUX=$((($TERMWIDTH / 2) - ($MAINMENUW / 2)))
declare -ri MAINMENUY=$(($MAINTITLEH + $MAINTITLEY + 3))
declare -ri MAINMENUITEMCOUNT=4
declare -a MAINMENUITEMS
MAINMENUITEMS[0]="New Game\e[0m"
MAINMENUITEMS[1]="High Scores\e[0m"
MAINMENUITEMS[2]="About\e[0m"
MAINMENUITEMS[3]="Exit\e[0m"
declare -a MAINMENUITEMY
MAINMENUITEMY[0]=$MAINMENUY
MAINMENUITEMY[1]=$(($MAINMENUY + 2))
MAINMENUITEMY[2]=$(($MAINMENUY + 4))
MAINMENUITEMY[3]=$(($MAINMENUY + 6))
declare -i MAINMENUSELECTION=0
declare -r MAINMENUITEMNOTSEL="    \e[0;33m"
declare -r MAINMENUITEMSELECT="\e[1;37m──> \e[1;33m"

declare -ri MENUBOTTOMDECORX=$MAINTITLEX
declare -ri MENUBOTTOMDECORY=$(($TERMHEIGHT - 5))

declare -r SCREENINFOSTRING=$(printf "%s %d.%d %s" "$TETRIBASHTITLE" $TETRIBASHVERSION $TETRIBASHSUBVERS "$TETRIBASHRELEASE")
declare -ri SCREENINFOSTRINGX=$((($TERMWIDTH / 2) - (${#SCREENINFOSTRING} / 2)))
declare -ri SCREENINFOSTRINGY=$(($TERMHEIGHT - 1))

declare -r BH="─"
declare -r BV="│"
declare -r BTL="┌"
declare -r BTR="┐"
declare -r BBL="└"
declare -r BBR="┘"

declare -r BLK1="\e[43m\e[1;33m[]"
declare -r BLK2="\e[42m\e[1;32m()"
declare -r BLK3="\e[46m\e[1;36m::"
declare -r BLK4="\e[41m\e[1;31m[]"
declare -r BLK5="\e[44m\e[1;34m{}"
declare -r BLK6="\e[47m\e[1;37m++"
declare -r BLK7="\e[45m\e[1;35m<>"

declare -a TBASHARRAY

#================================== Block 1 ==================================
declare -a BLK1ARRAY=(0 0 0 0 1 1 1 0 0 1 0 0 0 0 0 0)
declare -a BLK1ARRAYR2=(0 1 0 0 1 1 0 0 0 1 0 0 0 0 0 0)
declare -a BLK1ARRAYR3=(0 1 0 0 1 1 1 0 0 0 0 0 0 0 0 0)
declare -a BLK1ARRAYR4=(0 1 0 0 0 1 1 0 0 1 0 0 0 0 0 0)

#================================== Block 2 ==================================
declare -a BLK2ARRAY=(0 0 0 0 0 2 2 0 0 2 2 0 0 0 0 0)

#================================== Block 3 ==================================
declare -a BLK3ARRAY=(0 0 0 0 3 3 3 3 0 0 0 0 0 0 0 0)
declare -a BLK3ARRAYR2=(0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0)
declare -a BLK3ARRAYR3=(0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0)

#================================== Block 4 ==================================
declare -a BLK4ARRAY=(0 0 0 0 4 4 0 0 0 4 4 0 0 0 0 0)
declare -a BLK4ARRAYR2=(0 4 0 0 4 4 0 0 4 0 0 0 0 0 0 0)

#================================== Block 5 ==================================
declare -a BLK5ARRAY=(0 0 0 0 0 5 5 0 5 5 0 0 0 0 0 0)
declare -a BLK5ARRAYR2=(5 0 0 0 5 5 0 0 0 5 0 0 0 0 0 0)

#================================== Block 6 ==================================
declare -a BLK6ARRAY=(0 0 0 0 6 6 6 0 0 0 6 0 0 0 0 0)
declare -a BLK6ARRAYR2=(0 6 0 0 0 6 0 0 6 6 0 0 0 0 0 0)
declare -a BLK6ARRAYR3=(6 0 0 0 6 6 6 0 0 0 0 0 0 0 0 0)
declare -a BLK6ARRAYR4=(0 6 6 0 0 6 0 0 0 6 0 0 0 0 0 0)

#================================== Block 7 ==================================
declare -a BLK7ARRAY=(0 0 0 0 7 7 7 0 7 0 0 0 0 0 0 0)
declare -a BLK7ARRAYR2=(7 7 0 0 0 7 0 0 0 7 0 0 0 0 0 0)
declare -a BLK7ARRAYR3=(0 0 7 0 7 7 7 0 0 0 0 0 0 0 0 0)
declare -a BLK7ARRAYR4=(0 7 0 0 0 7 0 0 0 7 7 0 0 0 0 0)

#=============================================================================
#-----------------------------------------------------------------------------
# [ Function Declarations ]
#-----------------------------------------------------------------------------
#=============================================================================
function ZeroTetriBashArray()
{
	for((i=0; i<TBASHSIZE; i++)); do
	{
		TBASHARRAY[$i]=0
	}
	done
}

function GameOverClearTetriBashArray()
{
	for((i=0; i<TBASHSIZE; i++)); do
	{
		TBASHARRAY[$i]=8
	}
	done
}

function ZeroBlockBuffer()
{
	for((i=0; i<GAMEBLOCKAREA; i++)); do
	{
		GAMEBLOCKBUFFER[$i]=0
	}
	done
}

function ZeroLinesBuffer()
{
	for((i=0; i<TBASHH; i++)); do
	{
		GAMELINESBUFFER[$i]=0
	}
	done
}

function DrawBorder()
{
	if [ -z "$1" ] || [ -z "$2" ] || [ -z "$3" ] || [ -z "$4" ]; then
	{
		return 1
	}
	fi

	local BWIDTH=$(($3 - 2))
	local BHEIGHT=$(($4 - 2))
	local BVERTVPOS=$(($2 + 1))
	local BVERTHPOS=$1

	printf "\e[%d;%dH${BTL}" $2 $1

	for((i=0; i<BWIDTH; i++)); do
	{
		printf "${BH}"
	}
	done

	printf "${BTR}"

	for((i=0; i<BHEIGHT; i++)); do
	{
		printf "\e[%d;%dH${BV}" $BVERTVPOS $BVERTHPOS
		BVERTVPOS=$(($BVERTVPOS + 1))
	}
	done

	BVERTVPOS=$(($2 + 1))
	BVERTHPOS=$(($1 + $3 - 1))

	for((i=0; i<BHEIGHT; i++)); do
	{
		printf "\e[%d;%dH${BV}" $BVERTVPOS $BVERTHPOS
		BVERTVPOS=$(($BVERTVPOS + 1))
	}
	done

	printf "\e[%d;%dH${BBL}" $(($2 + $4 - 1)) $1
	
	for((i=0; i<BWIDTH; i++)); do
	{
		printf "${BH}"
	}
	done

	printf "${BBR}"

	return 0
}

function DrawTetriBashArray()
{
	local BLAPOS=0

	for((i=0; i<TBASHH; i++)); do
	{
		for((j=0; j<TBASHW; j++)); do
		{
			BLAPOS=$((($i * $TBASHW) + $j))
			
			case ${TBASHARRAY[$BLAPOS]} in
				1) printf "\e[%d;%dH${BLK1}\e[0m" $(($TBASHOFFSETY + $i)) $(($TBASHOFFSETX + ($j * 2)));;
				2) printf "\e[%d;%dH${BLK2}\e[0m" $(($TBASHOFFSETY + $i)) $(($TBASHOFFSETX + ($j * 2)));;
				3) printf "\e[%d;%dH${BLK3}\e[0m" $(($TBASHOFFSETY + $i)) $(($TBASHOFFSETX + ($j * 2)));;
				4) printf "\e[%d;%dH${BLK4}\e[0m" $(($TBASHOFFSETY + $i)) $(($TBASHOFFSETX + ($j * 2)));;
				5) printf "\e[%d;%dH${BLK5}\e[0m" $(($TBASHOFFSETY + $i)) $(($TBASHOFFSETX + ($j * 2)));;
				6) printf "\e[%d;%dH${BLK6}\e[0m" $(($TBASHOFFSETY + $i)) $(($TBASHOFFSETX + ($j * 2)));;
				7) printf "\e[%d;%dH${BLK7}\e[0m" $(($TBASHOFFSETY + $i)) $(($TBASHOFFSETX + ($j * 2)));;
				8) printf "\e[%d;%dH::\e[0m" $(($TBASHOFFSETY + $i)) $(($TBASHOFFSETX + ($j * 2)));;
			esac
		}
		done
	}
	done

	FRAMEUPDATED=1
}

function DrawTetriBashArrayEx()
{
	local BLAPOS=0

	for((i=0; i<TBASHH; i++)); do
	{
		for((j=0; j<TBASHW; j++)); do
		{
			BLAPOS=$((($i * $TBASHW) + $j))
			
			case ${TBASHARRAY[$BLAPOS]} in
				0) printf "\e[%d;%dH  \e[0m" $(($TBASHOFFSETY + $i)) $(($TBASHOFFSETX + ($j * 2)));;
				1) printf "\e[%d;%dH${BLK1}\e[0m" $(($TBASHOFFSETY + $i)) $(($TBASHOFFSETX + ($j * 2)));;
				2) printf "\e[%d;%dH${BLK2}\e[0m" $(($TBASHOFFSETY + $i)) $(($TBASHOFFSETX + ($j * 2)));;
				3) printf "\e[%d;%dH${BLK3}\e[0m" $(($TBASHOFFSETY + $i)) $(($TBASHOFFSETX + ($j * 2)));;
				4) printf "\e[%d;%dH${BLK4}\e[0m" $(($TBASHOFFSETY + $i)) $(($TBASHOFFSETX + ($j * 2)));;
				5) printf "\e[%d;%dH${BLK5}\e[0m" $(($TBASHOFFSETY + $i)) $(($TBASHOFFSETX + ($j * 2)));;
				6) printf "\e[%d;%dH${BLK6}\e[0m" $(($TBASHOFFSETY + $i)) $(($TBASHOFFSETX + ($j * 2)));;
				7) printf "\e[%d;%dH${BLK7}\e[0m" $(($TBASHOFFSETY + $i)) $(($TBASHOFFSETX + ($j * 2)));;
			esac
		}
		done
	}
	done

	FRAMEUPDATED=1
}

function HUDDrawArea()
{
	DrawBorder $TBASHAREAOFFSETX $TBASHAREAOFFSETY $TBASHAREAW $TBASHAREAH
	FRAMEUPDATED=1
}

function HUDDrawGameOver()
{
	DrawBorder $TBASHGAMEOVEROFFSETX $TBASHGAMEOVEROFFSETY $TBASHGAMEOVERWIDTH $TBASHGAMEOVERHEIGHT
	printf "\e[%d;%dH\e[1;31m   Game Over!   \e[0m" $(($TBASHGAMEOVEROFFSETY + 1)) $(($TBASHGAMEOVEROFFSETX + 1))
	FRAMEUPDATED=1
}

function HUDDrawScore()
{
	DrawBorder $TBASHSCOREOFFSETX $TBASHSCOREOFFSETY $TBASHSCOREW $TBASHSCOREH
	printf "\e[%d;%dH\e[1;33mScore\e[0m" $(($TBASHSCOREOFFSETY + 0)) $(($TBASHSCOREOFFSETX + 2))
	FRAMEUPDATED=1
}

function HUDDrawLevel()
{
	DrawBorder $TBASHLEVELOFFSETX $TBASHLEVELOFFSETY $TBASHLEVELW $TBASHLEVELH
	printf "\e[%d;%dH\e[1;33mLevel\e[0m" $(($TBASHLEVELOFFSETY + 0)) $(($TBASHLEVELOFFSETX + 2))
	FRAMEUPDATED=1
}

function HUDDrawLines()
{
	DrawBorder $TBASHLINESOFFSETX $TBASHLINESOFFSETY $TBASHLINESW $TBASHLINESH
	printf "\e[%d;%dH\e[1;33mLines\e[0m" $(($TBASHLINESOFFSETY + 0)) $(($TBASHLINESOFFSETX + 2))
	FRAMEUPDATED=1
}

function HUDDrawNext()
{
	DrawBorder $TBASHNEXTOFFSETX $TBASHNEXTOFFSETY $TBASHNEXTW $TBASHNEXTH
	printf "\e[%d;%dH\e[1;33mNext\e[0m" $(($TBASHNEXTOFFSETY + 0)) $(($TBASHNEXTOFFSETX + 2))
	FRAMEUPDATED=1
}

function HUDUpdateScore()
{
	printf "\e[%d;%dH\e[1;36m%d\e[0m" $TBASHSCOREVALUEY $TBASHSCOREVALUEX $GAMESCORE
	FRAMEUPDATED=1
}

function HUDUpdateLevel()
{
	printf "\e[%d;%dH\e[1;36m%d\e[0m" $TBASHLEVELVALUEY $TBASHLEVELVALUEX $GAMELEVEL
	FRAMEUPDATED=1
}

function HUDUpdateLines()
{
	printf "\e[%d;%dH\e[1;36m%d\e[0m" $TBASHLINESVALUEY $TBASHLINESVALUEX $GAMELINES
	FRAMEUPDATED=1
}

function HUDUpdateNext()
{
	local BLAPOS=0;
	local VY=$TBASHNEXTVALUEY;

	case $GAMENEXT in
		0) GAMENEXTARRAY=("${BLK1ARRAY[@]}");;
		1) GAMENEXTARRAY=("${BLK2ARRAY[@]}");;
		2) GAMENEXTARRAY=("${BLK3ARRAY[@]}");;
		3) GAMENEXTARRAY=("${BLK4ARRAY[@]}");;
		4) GAMENEXTARRAY=("${BLK5ARRAY[@]}");;
		5) GAMENEXTARRAY=("${BLK6ARRAY[@]}");;
		6) GAMENEXTARRAY=("${BLK7ARRAY[@]}");;
	esac

	printf "\e[%d;%dH" $TBASHNEXTVALUEY $TBASHNEXTVALUEX

	for((i=0; i<GAMEBLOCKSIZE; i++)); do
	{
		for((j=0; j<GAMEBLOCKSIZE; j++)); do
		{
			BLAPOS=$((($i * $GAMEBLOCKSIZE) + $j))
			
			case ${GAMENEXTARRAY[$BLAPOS]} in
				0) printf "\e[0m  ";;
				1) printf "${BLK1}";;
				2) printf "${BLK2}";;
				3) printf "${BLK3}";;
				4) printf "${BLK4}";;
				5) printf "${BLK5}";;
				6) printf "${BLK6}";;
				7) printf "${BLK7}";;
				*) printf "\e[0m  ";;
			esac
		}
		done
		
		VY=$(($VY + 1))
		printf "\e[%d;%dH" $VY $TBASHNEXTVALUEX
	}
	done

	FRAMEUPDATED=1
}

function DrawTetriBashHUD()
{
	HUDDrawArea
	HUDDrawScore
	HUDDrawLevel
	HUDDrawLines
	HUDDrawNext

	HUDUpdateScore
	HUDUpdateLevel
	HUDUpdateLines
	HUDUpdateNext

	FRAMEUPDATED=1
}

function FillArrayDemoBlocks()
{
	TBASHARRAY[15]=1
	TBASHARRAY[16]=1
	TBASHARRAY[17]=1
	TBASHARRAY[26]=1
	TBASHARRAY[21]=2
	TBASHARRAY[22]=2
	TBASHARRAY[31]=2
	TBASHARRAY[32]=2
	TBASHARRAY[38]=3
	TBASHARRAY[48]=3
	TBASHARRAY[58]=3
	TBASHARRAY[68]=3
	TBASHARRAY[51]=4
	TBASHARRAY[52]=4
	TBASHARRAY[62]=4
	TBASHARRAY[63]=4
	TBASHARRAY[75]=5
	TBASHARRAY[76]=5
	TBASHARRAY[84]=5
	TBASHARRAY[85]=5
	TBASHARRAY[103]=6
	TBASHARRAY[113]=6
	TBASHARRAY[114]=6
	TBASHARRAY[115]=6
	TBASHARRAY[138]=7
	TBASHARRAY[146]=7
	TBASHARRAY[147]=7
	TBASHARRAY[148]=7
}

function DrawTetriBashTitle()
{
	printf "\e[%d;%dH${MAINTITLELINE1}" $MAINTITLEY $MAINTITLEX
	printf "\e[%d;%dH${MAINTITLELINE2}" $(($MAINTITLEY + 1)) $MAINTITLEX
	printf "\e[%d;%dH${MAINTITLELINE3}" $(($MAINTITLEY + 2)) $MAINTITLEX
	printf "\e[%d;%dH${MAINTITLELINE4}" $(($MAINTITLEY + 3)) $MAINTITLEX
	printf "\e[%d;%dH${MAINTITLELINE5}" $(($MAINTITLEY + 4)) $MAINTITLEX
	FRAMEUPDATED=1
}

function DrawTetriBashMenuDecor()
{
	printf "\e[%d;%dH \e[0m" $MENUBOTTOMDECORY $MENUBOTTOMDECORX
	printf "\e[%d;%dH \e[0m" $(($MENUBOTTOMDECORY + 1)) $MENUBOTTOMDECORX
	printf "\e[%d;%dH \e[0m" $(($MENUBOTTOMDECORY + 2)) $MENUBOTTOMDECORX
	printf "\e[%d;%dH \e[0m" $(($MENUBOTTOMDECORY + 3)) $MENUBOTTOMDECORX
	FRAMEUPDATED=1
}

function DrawTetriBashVersionString()
{
	printf "\e[%d;%dH%s\e[0m" $SCREENINFOSTRINGY $SCREENINFOSTRINGX "$SCREENINFOSTRING"
	FRAMEUPDATED=1
}

function DrawTetriBashMainMenu()
{
	for((i=0; i<MAINMENUITEMCOUNT; i++)); do
	{
		if [ $i -eq $MAINMENUSELECTION ]; then
		{
			printf "\e[%d;%dH${MAINMENUITEMSELECT}${MAINMENUITEMS[$i]}" ${MAINMENUITEMY[$i]} $MAINMENUX
		}
		else
		{
			printf "\e[%d;%dH${MAINMENUITEMNOTSEL}${MAINMENUITEMS[$i]}" ${MAINMENUITEMY[$i]} $MAINMENUX
		}
		fi
	}
	done
	
	FRAMEUPDATED=1
}

function SetMainMenuSelection()
{
	if [ -z "$1" ]; then
	{
		return 1
	}
	fi
	
	if [ $1 -lt 0 ] || [ $1 -ge $MAINMENUITEMCOUNT ]; then
	{
		return 1
	}
	fi

	if [ $1 -eq $MAINMENUSELECTION ]; then
	{
		return 0
	}
	fi
	
	printf "\e[%d;%dH${MAINMENUITEMNOTSEL}${MAINMENUITEMS[$MAINMENUSELECTION]}" ${MAINMENUITEMY[$MAINMENUSELECTION]} $MAINMENUX
	MAINMENUSELECTION=$1
	printf "\e[%d;%dH${MAINMENUITEMSELECT}${MAINMENUITEMS[$MAINMENUSELECTION]}" ${MAINMENUITEMY[$MAINMENUSELECTION]} $MAINMENUX
	FRAMEUPDATED=1

	return 0
}

function ChangeMainMenuSelectionUp()
{
	local NEXTITEM=$MAINMENUSELECTION
	
	if [ $NEXTITEM -eq 0 ]; then
	{
		NEXTITEM=$(($MAINMENUITEMCOUNT - 1))
	}
	else
	{
		NEXTITEM=$(($NEXTITEM - 1))
	}
	fi
	
	SetMainMenuSelection $NEXTITEM
}

function ChangeMainMenuSelectionDown()
{
	local NEXTITEM=$MAINMENUSELECTION
	
	if [ $NEXTITEM -eq $(($MAINMENUITEMCOUNT - 1)) ]; then
	{
		NEXTITEM=0
	}
	else
	{
		NEXTITEM=$(($NEXTITEM + 1))
	}
	fi
	
	SetMainMenuSelection $NEXTITEM
}

function GameSetCurrentBlock()
{
	case $GAMECURRENT in
		0) GAMECURRENTARRAY=("${BLK1ARRAY[@]}");;
		1) GAMECURRENTARRAY=("${BLK2ARRAY[@]}");;
		2) GAMECURRENTARRAY=("${BLK3ARRAY[@]}");;
		3) GAMECURRENTARRAY=("${BLK4ARRAY[@]}");;
		4) GAMECURRENTARRAY=("${BLK5ARRAY[@]}");;
		5) GAMECURRENTARRAY=("${BLK6ARRAY[@]}");;
		6) GAMECURRENTARRAY=("${BLK7ARRAY[@]}");;
	esac

	GAMEBLOCKX=$(($TBASHOFFSETX + ($GAMEBLOCKSIZE * 2) - 2))
	GAMEBLOCKY=$TBASHOFFSETY
	GAMEBLOCKAPX=3
	GAMEBLOCKAPY=0
}

function GameDrawCurrentBlock()
{
	local BLAPOS=0

	for((i=0; i<GAMEBLOCKSIZE; i++)); do
	{
		for((j=0; j<GAMEBLOCKSIZE; j++)); do
		{
			BLAPOS=$((($i * $GAMEBLOCKSIZE) + $j))
			
			case ${GAMECURRENTARRAY[$BLAPOS]} in
				1) printf "\e[%d;%dH${BLK1}\e[0m\e[1;1H" $(($GAMEBLOCKY + $i)) $(($GAMEBLOCKX + ($j * 2)));;
				2) printf "\e[%d;%dH${BLK2}\e[0m\e[1;1H" $(($GAMEBLOCKY + $i)) $(($GAMEBLOCKX + ($j * 2)));;
				3) printf "\e[%d;%dH${BLK3}\e[0m\e[1;1H" $(($GAMEBLOCKY + $i)) $(($GAMEBLOCKX + ($j * 2)));;
				4) printf "\e[%d;%dH${BLK4}\e[0m\e[1;1H" $(($GAMEBLOCKY + $i)) $(($GAMEBLOCKX + ($j * 2)));;
				5) printf "\e[%d;%dH${BLK5}\e[0m\e[1;1H" $(($GAMEBLOCKY + $i)) $(($GAMEBLOCKX + ($j * 2)));;
				6) printf "\e[%d;%dH${BLK6}\e[0m\e[1;1H" $(($GAMEBLOCKY + $i)) $(($GAMEBLOCKX + ($j * 2)));;
				7) printf "\e[%d;%dH${BLK7}\e[0m\e[1;1H" $(($GAMEBLOCKY + $i)) $(($GAMEBLOCKX + ($j * 2)));;
			esac
		}
		done
	}
	done

	FRAMEUPDATED=1
}

function GameClearCurrentBlock()
{
	local BLAPOS=0

	for((i=0; i<GAMEBLOCKSIZE; i++)); do
	{
		for((j=0; j<GAMEBLOCKSIZE; j++)); do
		{
			BLAPOS=$((($i * $GAMEBLOCKSIZE) + $j))
			
			case ${GAMECURRENTARRAY[$BLAPOS]} in
				1) printf "\e[%d;%dH\e[0m  \e[1;1H" $(($GAMEBLOCKY + $i)) $(($GAMEBLOCKX + ($j * 2)));;
				2) printf "\e[%d;%dH\e[0m  \e[1;1H" $(($GAMEBLOCKY + $i)) $(($GAMEBLOCKX + ($j * 2)));;
				3) printf "\e[%d;%dH\e[0m  \e[1;1H" $(($GAMEBLOCKY + $i)) $(($GAMEBLOCKX + ($j * 2)));;
				4) printf "\e[%d;%dH\e[0m  \e[1;1H" $(($GAMEBLOCKY + $i)) $(($GAMEBLOCKX + ($j * 2)));;
				5) printf "\e[%d;%dH\e[0m  \e[1;1H" $(($GAMEBLOCKY + $i)) $(($GAMEBLOCKX + ($j * 2)));;
				6) printf "\e[%d;%dH\e[0m  \e[1;1H" $(($GAMEBLOCKY + $i)) $(($GAMEBLOCKX + ($j * 2)));;
				7) printf "\e[%d;%dH\e[0m  \e[1;1H" $(($GAMEBLOCKY + $i)) $(($GAMEBLOCKX + ($j * 2)));;
			esac
		}
		done
	}
	done

	FRAMEUPDATED=1
}

function GameGenerateBlock()
{
	GAMECURRENTROT=0
	GAMECURRENT=$GAMENEXT
	GAMENEXT=$(($RANDOM % 7))
	GameSetCurrentBlock
	GameDrawCurrentBlock
	HUDUpdateNext
}

function GameCommitBlock()
{
	local BLAPOS=0
	local BLKX=0
	local BLKY=0

	for((i=0; i<GAMEBLOCKSIZE; i++)); do
	{
		for((j=0; j<GAMEBLOCKSIZE; j++)); do
		{
			BLAPOS=$((($i * $GAMEBLOCKSIZE) + $j))			
			BLKX=$(($j + $GAMEBLOCKAPX))			
			BLKY=$(($i + $GAMEBLOCKAPY))			

			if [ $BLKX -lt 0 ] || [ $BLKX -gt $(($TBASHW - 1)) ]; then
			{
				continue
			}
			fi
			
			if [ $BLKY -gt $(($TBASHH - 1)) ]; then
			{
				continue	
			}
			fi

			if [ ${GAMECURRENTARRAY[$BLAPOS]} -gt 0 ]; then
			{
				if [ ${TBASHARRAY[$((($BLKY * $TBASHW) + $BLKX))]} -gt 0 ]; then
				{
					GAMEFAILURE=1
				}
				fi

				TBASHARRAY[$((($BLKY * $TBASHW) + $BLKX))]=${GAMECURRENTARRAY[$BLAPOS]}
			}
			fi
		}
		done
	}
	done
	
	if [ $GAMEFAILURE -eq 0 ]; then
	{
		GAMESCORE=$(($GAMESCORE + 1))
		HUDUpdateScore
	}
	fi
}

function GameEraseLine()
{
	local BLAPOS=0
	local YPOSSTART=0

	if [ -z "$1" ]; then
	{
		return 0
	}
	fi

	YPOSSTART=$1

	if [ $1 -gt $(($TBASHH - 1)) ]; then
	{
		return 0
	}
	fi

	for((k=YPOSSTART; k>0; k--)); do
	{
		for((j=0; j<TBASHW; j++)); do
		{
			BLAPOS=$((($k * $TBASHW) + $j))
			TBASHARRAY[$BLAPOS]=${TBASHARRAY[$(($BLAPOS - $TBASHW))]}
		}
		done
	}
	done

	return 1
}

function GameClearLines()
{
	local BLAPOS=0

	for((i=0; i<GAMELINESTOCLEAR; i++)); do
	{
		GameEraseLine ${GAMELINESBUFFER[$i]}
	}
	done

	DrawTetriBashArrayEx
	GAMESCORE=$(($GAMESCORE + (($GAMELINESTOCLEAR * ($GAMELEVEL + 1)) * ($GAMESCOREMULT * ($GAMELEVEL + 1)))))
	GAMELINES=$(($GAMELINES + $GAMELINESTOCLEAR))
	GAMELEVELLINES=$(($GAMELEVELLINES + $GAMELINESTOCLEAR))	
	if [ $GAMELEVELLINES -ge $GAMELINESPERLEVEL ] && [ $GAMELEVEL -lt 10 ]; then
	{
		GAMELEVELLINES=$(($GAMELEVELLINES - $GAMELINESPERLEVEL))
		GAMELEVEL=$(($GAMELEVEL + 1))
		GAMESCOREMULT=$(($GAMESCOREMULTDEF + ($GAMELEVEL * $GAMESCOREMULTINC)))
		GAMEINTERVAL=$(echo "$GAMEINTERVAL - 0.03" | bc)
		HUDUpdateLevel
	}
	fi
	HUDUpdateScore
	HUDUpdateLines
}

function GameDetectLines()
{
	local BLAPOS=0
	local BLKCOUNT=0
	local LINECLEARS=0

	ZeroLinesBuffer	
	
	for((i=0; i<TBASHH; i++)); do
	{
		BLKCOUNT=0
		for((j=0; j<TBASHW; j++)); do
		{
			BLAPOS=$((($i * $TBASHW) + $j))
			
			if [ ${TBASHARRAY[$BLAPOS]} -gt 0 ]; then
			{
				BLKCOUNT=$(($BLKCOUNT + 1))
			}
			fi
		}
		done
		
		if [ $BLKCOUNT -eq $TBASHW ]; then
		{
			GAMELINESBUFFER[$LINECLEARS]=$i
			LINECLEARS=$(($LINECLEARS + 1))
		}
		fi
	}
	done

	if [ $LINECLEARS -gt 0 ]; then
	{
		GAMELINESTOCLEAR=$LINECLEARS
		GAMECLEARINPROGRESS=1
		ACCUMULATOR="0.0"
		GameDrawLineClear
		return 1
	}
	fi

	return 0
}

function GameDrawLineClear()
{
	local BLAPOS=0

	for((i=0; i<GAMELINESTOCLEAR; i++)); do
	{
		for((j=0; j<TBASHW; j++)); do
		{
			BLAPOS=$(((${GAMELINESBUFFER[$i]} * $TBASHW) + $j))
			printf "\e[%d;%dH${GAMECLEARCHAR}${GAMECLEARCHAR}\e[0m" $(($TBASHOFFSETY + ${GAMELINESBUFFER[$i]})) $(($TBASHOFFSETX + ($j * 2)))
		}
		done
	}
	done
	
	FRAMEUPDATED=1
}

function GameCheckMoveLeft()
{
	local BLAPOS=0
	local BLKX=0
	local BLKY=0

	for((i=0; i<GAMEBLOCKSIZE; i++)); do
	{
		for((j=0; j<GAMEBLOCKSIZE; j++)); do
		{
			BLAPOS=$((($i * $GAMEBLOCKSIZE) + $j))			
			BLKX=$(($j + $GAMEBLOCKAPX))			
			BLKY=$(($i + $GAMEBLOCKAPY))			

			if [ $BLKX -lt 0 ] || [ $BLKX -gt $(($TBASHW - 1)) ]; then
			{
				continue
			}
			fi

			if [ ${GAMECURRENTARRAY[$BLAPOS]} -gt 0 ]; then
			{
				
				if [ $(($BLKX - 1)) -lt 0 ]; then
				{
					return 0
				}
				fi

				if [ ${TBASHARRAY[$((($BLKY * $TBASHW) + $BLKX - 1))]} -gt 0 ]; then
				{
					return 0
				}
				fi
			}
			fi
		}
		done
	}
	done

	return 1
}

function GameCheckMoveRight()
{
	local BLAPOS=0
	local BLKX=0
	local BLKY=0

	for((i=0; i<GAMEBLOCKSIZE; i++)); do
	{
		for((j=0; j<GAMEBLOCKSIZE; j++)); do
		{
			BLAPOS=$((($i * $GAMEBLOCKSIZE) + $j))			
			BLKX=$(($j + $GAMEBLOCKAPX))			
			BLKY=$(($i + $GAMEBLOCKAPY))			

			if [ $BLKX -lt 0 ] || [ $BLKX -gt $(($TBASHW - 1)) ]; then
			{
				continue
			}
			fi

			if [ ${GAMECURRENTARRAY[$BLAPOS]} -gt 0 ]; then
			{
				
				if [ $(($BLKX + 1)) -gt $(($TBASHW - 1)) ]; then
				{
					return 0
				}
				fi
				
				if [ ${TBASHARRAY[$((($BLKY * $TBASHW) + $BLKX + 1))]} -gt 0 ]; then
				{
					return 0
				}
				fi
			}
			fi
		}
		done
	}
	done

	return 1
}

function GameCheckMoveDown()
{
	local BLAPOS=0
	local BLKX=0
	local BLKY=0

	for((i=0; i<GAMEBLOCKSIZE; i++)); do
	{
		for((j=0; j<GAMEBLOCKSIZE; j++)); do
		{
			BLAPOS=$((($i * $GAMEBLOCKSIZE) + $j))			
			BLKX=$(($j + $GAMEBLOCKAPX))			
			BLKY=$(($i + $GAMEBLOCKAPY))			

			if [ $BLKX -lt 0 ] || [ $BLKX -gt $(($TBASHW - 1)) ]; then
			{
				continue
			}
			fi

			if [ ${GAMECURRENTARRAY[$BLAPOS]} -gt 0 ]; then
			{	
				if [ $(($BLAPOS + $GAMEBLOCKSIZE)) -lt $GAMEBLOCKAREA ]; then
				{
					if [ ${GAMECURRENTARRAY[$(($BLAPOS + $GAMEBLOCKSIZE))]} -gt 0 ]; then
					{
						continue
					}
					fi
				}
				fi

				if [ $(($BLKY + 1)) -gt $(($TBASHH - 1)) ]; then
				{
					return 0
				}
				fi

				if [ ${TBASHARRAY[$((($BLKY * $TBASHW) + $BLKX + $TBASHW))]} -gt 0 ]; then
				{
					return 0
				}
				fi
			}
			fi
		}
		done
	}
	done

	return 1
}

function GameMoveBlockLeft()
{
	GameCheckMoveLeft
	if [ $? -eq 1 ]; then
	{
		GameClearCurrentBlock
		GAMEBLOCKAPX=$(($GAMEBLOCKAPX - 1))
		GAMEBLOCKX=$(($GAMEBLOCKX - 2))
		GameDrawCurrentBlock
	}
	fi
}

function GameMoveBlockRight()
{
	GameCheckMoveRight
	if [ $? -eq 1 ]; then
	{
		GameClearCurrentBlock
		GAMEBLOCKAPX=$(($GAMEBLOCKAPX + 1))
		GAMEBLOCKX=$(($GAMEBLOCKX + 2))
		GameDrawCurrentBlock
	}
	fi
}

function GameMoveBlockDown()
{
	if [ ! -z "$1" ]; then
	{
		if [ $1 -eq 1 ]; then
		{
			if [ $GAMEFAILURE -eq 0 ]; then
			{
				ACCUMULATOR="0.0"
			}
			else
			{
				return
			}
			fi
		}
		fi
	}
	fi

	GameCheckMoveDown
	if [ $? -eq 1 ]; then
	{
		GameClearCurrentBlock
		GAMEBLOCKAPY=$(($GAMEBLOCKAPY + 1))
		GAMEBLOCKY=$(($GAMEBLOCKY + 1))
		GameDrawCurrentBlock
	}
	else
	{
		GameCommitBlock
		GameDetectLines
		if [ $? -eq 0 ]; then
		{
			GameGenerateBlock
		}
		fi
	}
	fi
}

function GameCheckRotate()
{
	local NEWROT=0
	local BLAPOS=0
	local BLKX=0
	local BLKY=0
	
	if [ -z "$1" ]; then
	{
		return 0
	}
	fi
	
	if [ $1 -eq 0 ]; then
	{
		if [ $GAMECURRENTROT -eq 0 ]; then
		{
			NEWROT=3
		}
		else
		{
			NEWROT=$(($GAMECURRENTROT - 1))
		}
		fi
	}
	else
	{
		if [ $GAMECURRENTROT -eq 3 ]; then
		{
			NEWROT=0
		}
		else
		{
			NEWROT=$(($GAMECURRENTROT + 1))
		}
		fi
	}
	fi

	ZeroBlockBuffer

	if [ $GAMECURRENT -eq 0 ]; then
	{
		case $NEWROT in
			0) GAMEBLOCKBUFFER=("${BLK1ARRAY[@]}");;
			1) GAMEBLOCKBUFFER=("${BLK1ARRAYR2[@]}");;
			2) GAMEBLOCKBUFFER=("${BLK1ARRAYR3[@]}");;
			3) GAMEBLOCKBUFFER=("${BLK1ARRAYR4[@]}");;
		esac
	}
	elif [ $GAMECURRENT -eq 1 ]; then
	{
		GAMEBLOCKBUFFER=("${BLK2ARRAY[@]}")
		return 1
	}
	elif [ $GAMECURRENT -eq 2 ]; then
	{
		case $NEWROT in
			0) GAMEBLOCKBUFFER=("${BLK3ARRAY[@]}");;
			1) GAMEBLOCKBUFFER=("${BLK3ARRAYR2[@]}");;
			2) GAMEBLOCKBUFFER=("${BLK3ARRAY[@]}");;
			3) GAMEBLOCKBUFFER=("${BLK3ARRAYR3[@]}");;
		esac
	}
	elif [ $GAMECURRENT -eq 3 ]; then
	{
		case $NEWROT in
			0) GAMEBLOCKBUFFER=("${BLK4ARRAY[@]}");;
			1) GAMEBLOCKBUFFER=("${BLK4ARRAYR2[@]}");;
			2) GAMEBLOCKBUFFER=("${BLK4ARRAY[@]}");;
			3) GAMEBLOCKBUFFER=("${BLK4ARRAYR2[@]}");;
		esac
	}
	elif [ $GAMECURRENT -eq 4 ]; then
	{
		case $NEWROT in
			0) GAMEBLOCKBUFFER=("${BLK5ARRAY[@]}");;
			1) GAMEBLOCKBUFFER=("${BLK5ARRAYR2[@]}");;
			2) GAMEBLOCKBUFFER=("${BLK5ARRAY[@]}");;
			3) GAMEBLOCKBUFFER=("${BLK5ARRAYR2[@]}");;
		esac
	}
	elif [ $GAMECURRENT -eq 5 ]; then
	{
		case $NEWROT in
			0) GAMEBLOCKBUFFER=("${BLK6ARRAY[@]}");;
			1) GAMEBLOCKBUFFER=("${BLK6ARRAYR2[@]}");;
			2) GAMEBLOCKBUFFER=("${BLK6ARRAYR3[@]}");;
			3) GAMEBLOCKBUFFER=("${BLK6ARRAYR4[@]}");;
		esac
	}
	elif [ $GAMECURRENT -eq 6 ]; then
	{
		case $NEWROT in
			0) GAMEBLOCKBUFFER=("${BLK7ARRAY[@]}");;
			1) GAMEBLOCKBUFFER=("${BLK7ARRAYR2[@]}");;
			2) GAMEBLOCKBUFFER=("${BLK7ARRAYR3[@]}");;
			3) GAMEBLOCKBUFFER=("${BLK7ARRAYR4[@]}");;
		esac
	}
	fi

	for((i=0; i<GAMEBLOCKSIZE; i++)); do
	{
		for((j=0; j<GAMEBLOCKSIZE; j++)); do
		{
			BLAPOS=$((($i * $GAMEBLOCKSIZE) + $j))			
			BLKX=$(($j + $GAMEBLOCKAPX))			
			BLKY=$(($i + $GAMEBLOCKAPY))

			if [ ${GAMEBLOCKBUFFER[$BLAPOS]} -gt 0 ]; then
			{	
				if [ $BLKY -gt $(($TBASHH - 1)) ] || [ $BLKX -gt $(($TBASHW - 1)) ] || [ $BLKX -lt 0 ]; then
				{
					return 0
				}
				fi

				if [ ${TBASHARRAY[$((($BLKY * $TBASHW) + $BLKX))]} -gt 0 ]; then
				{
					return 0
				}
				fi
			}
			fi
		}
		done
	}
	done
	
	GAMECURRENTROT=$NEWROT
	return 1
}

function GameRotateBlockLeft()
{
	GameCheckRotate 0
	if [ $? -eq 1 ]; then
	{
		GameClearCurrentBlock
		GAMECURRENTARRAY=("${GAMEBLOCKBUFFER[@]}")
		GameDrawCurrentBlock
	}
	fi
}

function GameRotateBlockRight()
{
	GameCheckRotate 1
	if [ $? -eq 1 ]; then
	{
		GameClearCurrentBlock
		GAMECURRENTARRAY=("${GAMEBLOCKBUFFER[@]}")
		GameDrawCurrentBlock
	}
	fi
}

function InitGame()
{
	GAMESCORE=0
	GAMELEVEL=0
	GAMELINES=0
	GAMEFAILURE=0
	GAMEFAILURECOUNT=0
	GAMEOVERINPROGRESS=0
	GAMECLEARINPROGRESS=0
	GAMELINESTOCLEAR=0
	GAMESCOREMULT=$(($GAMESCOREMULTDEF + ($GAMELEVEL * $GAMESCOREMULTINC)))
	GAMECURRENT=$(($RANDOM % 7))
	GAMENEXT=$(($RANDOM % 7))
	GAMEINTERVAL="0.5"
	ACCUMULATOR="0.0"
	
	ZeroTetriBashArray
	DrawTetriBashArray
	GameSetCurrentBlock
	GameDrawCurrentBlock
}

function SetGameStateMenu()
{
	TETRIBASHSTATE=1
	GAMERUNNING=0
	clear
	DrawTetriBashTitle
	DrawTetriBashMainMenu
	DrawTetriBashMenuDecor
	DrawTetriBashVersionString
}

function SetGameStatePlay()
{
	clear
	TETRIBASHSTATE=2
	GAMERUNNING=1
	InitGame
	DrawTetriBashHUD
}

function SetGameStateAbout()
{
	clear
	TETRIBASHSTATE=3
	GAMERUNNING=0
	DrawTetriBashTitle
	DrawTetriBashVersionString
	DrawBorder $TBASHABOUTX $TBASHABOUTY $TBASHABOUTW $TBASHABOUTH
	printf "\e[%d;%dH\e[1;32m${TETRIBASHINFO}\e[0m" $(($TBASHABOUTY + 1)) $(($TBASHABOUTX + 1))
	printf "\e[%d;%dH\e[1;32m${TETRIBASHINFO2}\e[0m" $(($TBASHABOUTY + 2)) $(($TBASHABOUTX + 1))
	printf "\e[%d;%dH\e[1;32m${TETRIBASHINFO3}\e[0m" $(($TBASHABOUTY + 4)) $(($TBASHABOUTX + 1))
}

function SetGameStatePause()
{
	clear
	TETRIBASHSTATE=4
	GAMERUNNING=0
}

function SetGameStateExit()
{
	clear
	TETRIBASHSTATE=0
	GAMERUNNING=0
}

function ExecuteMainMenuSelection()
{
	case $MAINMENUSELECTION in
		0) SetGameStatePlay;;
		2) SetGameStateAbout;;
		3) SetGameStateExit;;
	esac
}


#=============================================================================
#-----------------------------------------------------------------------------
# [ TetriBASH Script ]
#-----------------------------------------------------------------------------
#=============================================================================
# Clear Screen
clear
stty -echo -icanon time 0 min 0

SetGameStateMenu

# Game Loop
while true; do
{
	TIMESTART=$(date +%s.%N)	

	KEY=$(dd bs=1 count=1 2> /dev/null; echo ".")
	KEY=${KEY%.}
	if [ $TETRIBASHSTATE -eq 1 ]; then
	{
		case $KEY in
			q) SetGameStateExit;;
			w) ChangeMainMenuSelectionUp;;
			a) ChangeMainMenuSelectionUp;;
			s) ChangeMainMenuSelectionDown;;
			d) ChangeMainMenuSelectionDown;;
			k) ExecuteMainMenuSelection;;
			# ?) printf "$KEY" ;;
		esac
	}
	elif [ $TETRIBASHSTATE -eq 2 ]; then
	{
		if [ $GAMERUNNING -eq 1 ]; then
		{
			if [ $GAMECLEARINPROGRESS -eq 1 ]; then
			{
				case $KEY in
					q) SetGameStateMenu;;
				esac

				if [[ $(echo "if (${ACCUMULATOR} > ${GAMECLEARINTERVAL}) 1" | bc) -eq 1 ]]; then
				{
					GameClearLines
					GAMECLEARINPROGRESS=0
					GAMELINESTOCLEAR=0
					GameGenerateBlock
				}
				fi
			}
			elif [ $GAMEOVERINPROGRESS -eq 1 ]; then
			{
				case $KEY in
					q) SetGameStateMenu;;
				esac

				if [[ $(echo "if (${ACCUMULATOR} > ${GAMEOVERINTERVAL}) 1" | bc) -eq 1 ]]; then
				{
					SetGameStateMenu
				}
				fi
			}
			else
			{
				case $KEY in
					q) SetGameStateMenu;;
					w) DrawTetriBashArray;;
					a) GameMoveBlockLeft;;
					s) GameMoveBlockDown 1;;
					d) GameMoveBlockRight;;
					j) GameRotateBlockLeft;;
					l) GameRotateBlockRight;;
					# ?) printf "%d\n" "'$KEY" ;;
				esac

				if [[ $(echo "if (${ACCUMULATOR} > ${GAMEINTERVAL}) 1" | bc) -eq 1 ]]; then
				{
					GameMoveBlockDown
					if [ $GAMEFAILURE -eq 1 ]; then
					{
						GAMEFAILURECOUNT=$(($GAMEFAILURECOUNT + 1))
						if [ $GAMEFAILURECOUNT -eq $GAMEFAILUREMAX ]; then
						{
							GAMEOVERINPROGRESS=1
							ACCUMULATOR="0.0"
							GameOverClearTetriBashArray
							DrawTetriBashArray
							HUDDrawGameOver
						}
						fi
						GAMEINTERVAL=$(echo "$GAMEINTERVAL - 0.05" | bc)
					}
					fi
					ACCUMULATOR=$(echo "$ACCUMULATOR - $GAMEINTERVAL" | bc)
				}
				fi
			}
			fi
		}
		fi
	}
	elif [ $TETRIBASHSTATE -eq 3 ]; then
	{
		case $KEY in
			q) SetGameStateMenu;;
		esac
	}
	elif [ $TETRIBASHSTATE -eq 4 ]; then
	{
		case $KEY in
			q) SetGameStateExit ;;
			w) DrawTetriBashArray ;;
			a) DrawBorder 4 2 10 10 ;;
			s) DrawTetriBashHUD ;;
			d) DrawTetriBashTitle;;
			?) printf "%d\n" "'$KEY" ;;
		esac
	}
	else
	{
		break
	}
	fi

	if [ $FRAMEUPDATED -eq 1 ]; then
	{
		if [ $TETRIBASHDEBUG -eq 1 ]; then
		{	
			if [ $TETRIBASHSTATE -eq 2 ]; then
			{	
				printf "\e[1;2H\e[1;32mDebug:BlkPos(%d,%d) BlkTerm(%d,%d) Delta(%2.3g) Accu(%2.3g) LC(%d)      \e[0m" $GAMEBLOCKAPX $GAMEBLOCKAPY $GAMEBLOCKX $GAMEBLOCKY $DELTATIME $ACCUMULATOR $GAMECLEARINPROGRESS
			}
			fi
 		}
		fi
		printf "\e[1;1H"
		FRAMEUPDATED=0
	}
	fi

	TIMEEND=$(date +%s.%N)
	DELTATIME=$(echo "$TIMEEND - $TIMESTART" | bc)
	if [ $TETRIBASHSTATE -eq 2 ] && [ $GAMERUNNING -eq 1 ]; then
	{
		ACCUMULATOR=$(echo "$ACCUMULATOR + $DELTATIME" | bc)
	}
	fi
}
done

# Clean Up
printf "\e[0m"
clear
stty sane
exit 0

 

I attached the script file as well, just drop the .txt.

 

The controls are as follows:

K - Select menu item

Q - quit or back

WASD - menu nav and block movement

J and L - rotate piece

 

Don't hold down keys too long or the key buffer will sometimes fill up quicker than it gets emptied (does not seem to happen as quickly while running slower in a VM) .


PARTNERS