/*
* Copyright (C) 2007 Dag Jonny Nedrelid
*
* A Tetris Clone, made for real-time fun.
*/
var Speed = 600;
var boardRowSize = 14;
var boardColSize = 10;
var nextBrick = makeNewBrick();
var activeBrick;
var needNewBrick = true;
var gameRunning = true;
var PointSpdCounter = 0;
var Points = 0;
var Level = 1;
var Paused = false;
// The board. [x,y,fill_state (1 = active brick, 2 = landed brick)].
var Board = [[[0,0,0],[35,0,0],[70,0,0],[105,0,0],[140,0,0],[175,0,0],[210,0,0],[245,0,0],[280,0,0],[315,0,0]],
[[0,35,0],[35,35,0],[70,35,0],[105,35,0],[140,35,0],[175,35,0],[210,35,0],[245,35,0],[280,35,0],[315,35,0]],
[[0,70,0],[35,70,0],[70,70,0],[105,70,0],[140,70,0],[175,70,0],[210,70,0],[245,70,0],[280,70,0],[315,70,0]],
[[0,105,0],[35,105,0],[70,105,0],[105,105,0],[140,105,0],[175,105,0],[210,105,0],[245,105,0],[280,105,0],[315,105,0]],
[[0,140,0],[35,140,0],[70,140,0],[105,140,0],[140,140,0],[175,140,0],[210,140,0],[245,140,0],[280,140,0],[315,140,0]],
[[0,175,0],[35,175,0],[70,175,0],[105,175,0],[140,175,0],[175,175,0],[210,175,0],[245,175,0],[280,175,0],[315,175,0]],
[[0,210,0],[35,210,0],[70,210,0],[105,210,0],[140,210,0],[175,210,0],[210,210,0],[245,210,0],[280,210,0],[315,210,0]],
[[0,245,0],[35,245,0],[70,245,0],[105,245,0],[140,245,0],[175,245,0],[210,245,0],[245,245,0],[280,245,0],[315,245,0]],
[[0,280,0],[35,280,0],[70,280,0],[105,280,0],[140,280,0],[175,280,0],[210,280,0],[245,280,0],[280,280,0],[315,280,0]],
[[0,315,0],[35,315,0],[70,315,0],[105,315,0],[140,315,0],[175,315,0],[210,315,0],[245,315,0],[280,315,0],[315,315,0]],
[[0,350,0],[35,350,0],[70,350,0],[105,350,0],[140,350,0],[175,350,0],[210,350,0],[245,350,0],[280,350,0],[315,350,0]],
[[0,385,0],[35,385,0],[70,385,0],[105,385,0],[140,385,0],[175,385,0],[210,385,0],[245,385,0],[280,385,0],[315,385,0]],
[[0,420,0],[35,420,0],[70,420,0],[105,420,0],[140,420,0],[175,420,0],[210,420,0],[245,420,0],[280,420,0],[315,420,0]],
[[0,455,0],[35,455,0],[70,455,0],[105,455,0],[140,455,0],[175,455,0],[210,455,0],[245,455,0],[280,455,0],[315,455,0]]];
var NextBrickBoard = [[[0,0,0],[15,0,0],[30,0,0],[45,0,0]],
[[0,15,0],[15,15,0],[30,15,0],[45,15,0]]];
function KTrix() {
if (gameRunning == true && Paused == false) {
document.getElementById('trixcmd').focus();
// Create a new brick if needed.
if (needNewBrick) {
activeBrick = nextBrick;
nextBrick = makeNewBrick();
needNewBrick = false;
// Update point panel.
updatePointpanel();
}
// Update board.
updateBoard();
// Set up brick for next round's fall.
brickMustFall();
// Check for game over.
isGameOver();
// Check if we have completed the game.
winCheck();
// Loop.
setTimeout('KTrix()',Speed);
} else if (Paused == true && gameRunning == true) {
// Do nothing, except wait for un-pause.
setTimeout('KTrix()',Speed);
}
}
function doMove(e) {
if (!gameRunning)
return;
var keynum, loop_a, loop_b;
if (window.event)
keynum = e.keyCode;
else if (e.which)
keynum = e.which;
// 37 = left, 39 = right, 38 = up, 40 = down, 80 = P for pause.
if ((Paused == false && keynum == 37 &&
activeBrick[0][1] > 0 && activeBrick[1][1] > 0 &&
activeBrick[2][1] > 0 && activeBrick[3][1] > 0) && (
Board[activeBrick[0][0]][activeBrick[0][1]-1][2] != 2 &&
Board[activeBrick[1][0]][activeBrick[1][1]-1][2] != 2 &&
Board[activeBrick[2][0]][activeBrick[2][1]-1][2] != 2 &&
Board[activeBrick[3][0]][activeBrick[3][1]-1][2] != 2)) {
// No collision, move brick left.
for (loop_a = 0; loop_a <= 15; loop_a++) {
activeBrick[loop_a][1] -= 1;
}
updateBoard();
} else if ((Paused == false && keynum == 39 &&
activeBrick[0][1] < boardColSize-1 &&
activeBrick[1][1] < boardColSize-1 &&
activeBrick[2][1] < boardColSize-1 &&
activeBrick[3][1] < boardColSize-1) && (
Board[activeBrick[0][0]][activeBrick[0][1]+1][2] != 2 &&
Board[activeBrick[1][0]][activeBrick[1][1]+1][2] != 2 &&
Board[activeBrick[2][0]][activeBrick[2][1]+1][2] != 2 &&
Board[activeBrick[3][0]][activeBrick[3][1]+1][2] != 2)) {
// No collision, move brick right.
for (loop_a = 0; loop_a <= 15; loop_a++) {
activeBrick[loop_a][1] += 1;
}
updateBoard();
} else if ((Paused == false && keynum == 40 &&
activeBrick[0][0] < boardRowSize-1 &&
activeBrick[1][0] < boardRowSize-1 &&
activeBrick[2][0] < boardRowSize-1 &&
activeBrick[3][0] < boardRowSize-1) && (
Board[activeBrick[0][0]+1][activeBrick[0][1]][2] != 2 &&
Board[activeBrick[1][0]+1][activeBrick[1][1]][2] != 2 &&
Board[activeBrick[2][0]+1][activeBrick[2][1]][2] != 2 &&
Board[activeBrick[3][0]+1][activeBrick[3][1]][2] != 2)) {
// No collision, move brick down.
for (loop_a = 0; loop_a <= 15; loop_a++) {
activeBrick[loop_a][0] += 1;
}
updateBoard();
} else if ((Paused == false && keynum == 38 &&
activeBrick[4][0] < boardRowSize-1 &&
activeBrick[5][0] < boardRowSize-1 &&
activeBrick[6][0] < boardRowSize-1 &&
activeBrick[7][0] < boardRowSize-1) && (
activeBrick[4][1] >= 0 && activeBrick[5][1] >= 0 &&
activeBrick[6][1] >= 0 && activeBrick[7][1] >= 0) && (
activeBrick[4][1] < boardColSize &&
activeBrick[5][1] < boardColSize &&
activeBrick[6][1] < boardColSize &&
activeBrick[7][1] < boardColSize) && (
Board[activeBrick[4][0]][activeBrick[4][1]][2] != 2 &&
Board[activeBrick[5][0]][activeBrick[5][1]][2] != 2 &&
Board[activeBrick[6][0]][activeBrick[6][1]][2] != 2 &&
Board[activeBrick[7][0]][activeBrick[7][1]][2] != 2)) {
// After checking if the next shape in line won't
// crash in any walls, roof, ground or other landed
// bricks, we can transform the brick.
// Make copy of active brick.
var tmpBrick = [[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],
[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]];
for (loop_a = 0; loop_a <= 15; loop_a++) {
for (loop_b = 0; loop_b <= 1; loop_b++) {
tmpBrick[loop_a][loop_b] = activeBrick[loop_a][loop_b];
}
}
// Move first brick shape out of play down
// to fourth position in transform line.
activeBrick[12][0] = tmpBrick[0][0];
activeBrick[13][0] = tmpBrick[1][0];
activeBrick[14][0] = tmpBrick[2][0];
activeBrick[15][0] = tmpBrick[3][0];
activeBrick[12][1] = tmpBrick[0][1];
activeBrick[13][1] = tmpBrick[1][1];
activeBrick[14][1] = tmpBrick[2][1];
activeBrick[15][1] = tmpBrick[3][1];
// Move second shape in line into play.
activeBrick[0][0] = tmpBrick[4][0];
activeBrick[1][0] = tmpBrick[5][0];
activeBrick[2][0] = tmpBrick[6][0];
activeBrick[3][0] = tmpBrick[7][0];
activeBrick[0][1] = tmpBrick[4][1];
activeBrick[1][1] = tmpBrick[5][1];
activeBrick[2][1] = tmpBrick[6][1];
activeBrick[3][1] = tmpBrick[7][1];
// Move that which was third,
// into second place for next transform.
activeBrick[4][0] = tmpBrick[8][0];
activeBrick[5][0] = tmpBrick[9][0];
activeBrick[6][0] = tmpBrick[10][0];
activeBrick[7][0] = tmpBrick[11][0];
activeBrick[4][1] = tmpBrick[8][1];
activeBrick[5][1] = tmpBrick[9][1];
activeBrick[6][1] = tmpBrick[10][1];
activeBrick[7][1] = tmpBrick[11][1];
// Move that which was fourth,
// into third place for next transform.
activeBrick[8][0] = tmpBrick[12][0];
activeBrick[9][0] = tmpBrick[13][0];
activeBrick[10][0] = tmpBrick[14][0];
activeBrick[11][0] = tmpBrick[15][0];
activeBrick[8][1] = tmpBrick[12][1];
activeBrick[9][1] = tmpBrick[13][1];
activeBrick[10][1] = tmpBrick[14][1];
activeBrick[11][1] = tmpBrick[15][1];
updateBoard();
} else if (keynum == 80) {
if (Paused) {
Paused = false;
updatePointpanel();
} else {
Paused = true;
document.getElementById('Pointpanel').innerHTML = ''
+ '<br /><br /><br /><br />'
+ 'GAME PAUSED!<br /><br />'
+ 'Press P to continue.';
}
}
}
function makeNewBrick() {
/*
Every brick will contain 4 shapes for rotation/transformation
(Sub-array 0-3 = shape1, 4-7 = shape2, 8-11 = shape3, 12-15 = shape4).
3rd and 4th shape is repeated with the first two for proper rotation
if a 3rd and 4th brick shape should not exist naturally for the brick.
*/
// ####
var Brick1 = [[0,3],[0,4],[0,5],[0,6],
[0,5],[1,5],[2,5],[3,5],
[0,3],[0,4],[0,5],[0,6],
[0,5],[1,5],[2,5],[3,5]];
// ##
// ##
var Brick2 = [[0,4],[0,5],[1,4],[1,5],
[0,4],[0,5],[1,4],[1,5],
[0,4],[0,5],[1,4],[1,5],
[0,4],[0,5],[1,4],[1,5]];
// ##
// ##
var Brick3 = [[0,4],[0,5],[1,5],[1,6],
[0,6],[1,6],[1,5],[2,5],
[0,4],[0,5],[1,5],[1,6],
[0,6],[1,6],[1,5],[2,5]];
// ##
// ##
var Brick4 = [[0,5],[0,6],[1,4],[1,5],
[0,4],[1,4],[1,5],[2,5],
[0,5],[0,6],[1,4],[1,5],
[0,4],[1,4],[1,5],[2,5]];
// #
// ###
var Brick5 = [[0,4],[1,4],[1,5],[1,6],
[0,4],[0,5],[1,4],[2,4],
[0,4],[0,5],[0,6],[1,6],
[0,6],[1,6],[2,6],[2,5]];
// #
// ###
var Brick6 = [[0,6],[1,4],[1,5],[1,6],
[0,4],[1,4],[2,4],[2,5],
[0,4],[0,5],[0,6],[1,4],
[0,5],[0,6],[1,6],[2,6]];
// #
// ###
var Brick7 = [[0,5],[1,4],[1,5],[1,6],
[0,5],[1,5],[1,6],[2,5],
[0,4],[0,5],[0,6],[1,5],
[0,5],[1,4],[1,5],[2,5]];
// Collect bricks.
var Bricklist = [Brick1,Brick2,Brick3,Brick4,Brick5,Brick6,Brick7];
// Choose a random brick.
return Bricklist[Math.round(Math.random()*6)];
}
function getNextShape() {
var loop_a, loop_b, loop_c;
// Make copy of next brick.
var tmpBrick = [[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],
[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]];
for (loop_a = 0; loop_a <= 15; loop_a++) {
for (loop_b = 0; loop_b <= 1; loop_b++) {
tmpBrick[loop_a][loop_b] = nextBrick[loop_a][loop_b];
}
}
// Adapt shape for brick view (move left for smaller board).
for (loop_a = 0; loop_a <= 3; loop_a++) {
tmpBrick[loop_a][1] -= 3;
}
// Reset and update NextBrickBoard.
for (loop_a = 0; loop_a <= 1; loop_a++) {
for (loop_b = 0; loop_b <= 3; loop_b++) {
NextBrickBoard[loop_a][loop_b][2] = 0;
}
}
// Put next brick (first shape) on NextBrickBoard.
for (loop_a = 0; loop_a <= 1; loop_a++) {
for (loop_b = 0; loop_b <= 3; loop_b++) {
for (loop_c = 0; loop_c <= 3; loop_c++) {
if (tmpBrick[loop_c][0] == loop_a &&
tmpBrick[loop_c][1] == loop_b) {
NextBrickBoard[loop_a][loop_b][2] = 1;
}
}
}
}
// Update NextBrickView.
var whatBrick = 1;
for (loop_a = 0; loop_a <= 1; loop_a++) {
for (loop_b = 0; loop_b <= 3; loop_b++) {
if (NextBrickBoard[loop_a][loop_b][2] == 1) {
document.getElementById('MiniBrick'+whatBrick).style.left = NextBrickBoard[loop_a][loop_b][0] +'px';
document.getElementById('MiniBrick'+whatBrick).style.top = NextBrickBoard[loop_a][loop_b][1] +'px';
document.getElementById('MiniBrick'+whatBrick).style.visibility = 'visible';
whatBrick += 1;
}
}
}
}
function brickMustFall() {
var loop_a;
if ((activeBrick[0][0] < boardRowSize-1 &&
activeBrick[1][0] < boardRowSize-1 &&
activeBrick[2][0] < boardRowSize-1 &&
activeBrick[3][0] < boardRowSize-1) && (
Board[activeBrick[0][0]+1][activeBrick[0][1]][2] != 2 &&
Board[activeBrick[1][0]+1][activeBrick[1][1]][2] != 2 &&
Board[activeBrick[2][0]+1][activeBrick[2][1]][2] != 2 &&
Board[activeBrick[3][0]+1][activeBrick[3][1]][2] != 2)) {
// If the brick isn't gonna hit another landed brick or
// the bottom, we can continue with another fall.
for (loop_a = 0; loop_a <= 15; loop_a++) {
activeBrick[loop_a][0] += 1;
}
} else {
// If the brick is going to hit other bricks or the
// bottom of the board, we register it as landed in
// the board array and draw it.
for (loop_a = 0; loop_a <= 3; loop_a++) {
Board[activeBrick[loop_a][0]][activeBrick[loop_a][1]][2] = 2;
}
for (loop_a = 0; loop_a <= 3; loop_a++) {
document.getElementById('container').innerHTML += ''
+ '<div style="width:35px; height:35px; position:absolute; left:'
+ Board[activeBrick[loop_a][0]][activeBrick[loop_a][1]][0] +'px; top:'
+ Board[activeBrick[loop_a][0]][activeBrick[loop_a][1]][1]
+ 'px; background-image:url(firkant.gif)"> </div>';
}
// Turn on the switch for a new brick spawn.
needNewBrick = true;
}
}
function updateBoard() {
var loop_a, loop_b, loop_c;
// Remove all 1 values (bricks in action)
// and update with new brick values.
for (loop_a = 0; loop_a < boardRowSize; loop_a++) {
for (loop_b = 0; loop_b < boardColSize; loop_b++) {
// Remove existing value.
if (Board[loop_a][loop_b][2] == 1)
Board[loop_a][loop_b][2] = 0;
// Track brick and update its new position on board.
for (loop_c = 0; loop_c <= 3; loop_c++) {
if (loop_a == activeBrick[loop_c][0] &&
loop_b == activeBrick[loop_c][1]) {
Board[loop_a][loop_b][2] = 1;
}
}
}
}
// Draw board with new active brick values.
var whatBrick = 1;
for (loop_a = 0; loop_a < boardRowSize; loop_a++) {
for (loop_b = 0; loop_b < boardColSize; loop_b++) {
if (Board[loop_a][loop_b][2] == 1) {
document.getElementById('Brick'+whatBrick).style.left = Board[loop_a][loop_b][0] +'px';
document.getElementById('Brick'+whatBrick).style.top = Board[loop_a][loop_b][1] +'px';
document.getElementById('Brick'+whatBrick).style.visibility = 'visible';
whatBrick += 1;
}
}
}
// Check for completed rows with landed brick's.
// Delete them if found and give player points.
var colCounter;
for (loop_a = 0; loop_a < boardRowSize; loop_a++) {
colCounter = 0;
for (loop_b = 0; loop_b < boardColSize; loop_b++) {
if (Board[loop_a][loop_b][2] == 2)
colCounter += 1;
}
if (colCounter == boardColSize) {
// Delete row if it was full of bricks
for (loop_b = 0; loop_b < boardColSize; loop_b++) {
Board[loop_a][loop_b][2] = 0;
}
// Move all status-2 brick that was
// above the removed row 1 step down.
gravitateBoard(loop_a);
// Give points for 1 row removed.
// Every row is worth 100 points.
Points += 100;
PointSpdCounter += 1;
// For every 1000 points the
// speed goes up 50 nanoseconds.
if (PointSpdCounter == 10) {
Speed -= (Speed != 0 ? 50 : 0);
PointSpdCounter = 0;
Level += 1;
}
// Update point panel.
updatePointpanel();
}
}
}
function gravitateBoard(rowRemoved) {
var loop_a, loop_b;
// Move status-2 (landed) bricks above
// removed row 1 step down and and redraw.
for (loop_a = rowRemoved-1; loop_a > 0; loop_a--) {
for (loop_b = 0; loop_b < boardColSize; loop_b++) {
if (Board[loop_a][loop_b][2] == 2) {
Board[loop_a][loop_b][2] = 0;
Board[loop_a+1][loop_b][2] = 2;
}
}
}
document.getElementById('container').innerHTML = '';
for (loop_a = 0; loop_a < boardRowSize; loop_a++) {
for (loop_b = 0; loop_b < boardColSize; loop_b++) {
if (Board[loop_a][loop_b][2] == 2) {
document.getElementById('container').innerHTML += ''
+ '<div style="width:35px; height:35px; position:absolute; left:'
+ Board[loop_a][loop_b][0] +'px; top:'
+ Board[loop_a][loop_b][1]
+ 'px; background-image:url(firkant.gif)"> </div>';
}
}
}
}
function updatePointpanel() {
document.getElementById('Pointpanel').innerHTML = ''
+ '<div align="center" id="PointpanelLive">'
+ '<span class="header">Point panel</span>'
+ '</div><br />'
+ 'Points: ' + Points + '<br /><br />'
+ 'Level: ' + Level + '<br />'
+ (Level == 1 ? 'Trix Noob<br /><br />' : '')
+ (Level == 2 ? 'Trix Trainee<br /><br />' : '')
+ (Level == 3 ? 'Trix Wannabe<br /><br />' : '')
+ (Level == 4 ? 'Trix Amateur<br /><br />' : '')
+ (Level == 5 ? 'Trix Average<br /><br />' : '')
+ (Level == 6 ? 'Trix Trained<br /><br />' : '')
+ (Level == 7 ? 'Trix Pro<br /><br />':'')
+ (Level == 8 ? 'Trix Elite<br /><br />':'')
+ (Level == 9 ? 'Trix Prodigy<br /><br />':'')
+ (Level == 10 ? 'Trix Master<br /><br />':'')
+ 'Next brick: <br />'
+ '<div id="NextBrickView">'
+ '<div id="MiniBrick1"></div>'
+ '<div id="MiniBrick2"></div>'
+ '<div id="MiniBrick3"></div>'
+ '<div id="MiniBrick4"></div>'
+ '</div><br />'
+ 'Brick delay: ' + Speed + '<br />'
+ '(Nano seconds)<br /><br />'
+ '<div align="center">Need pause?<br />'
+ 'Press the P Key.</div><br />';
getNextShape();
}
function isGameOver() {
var loop_a;
// Check if there are status-2 bricks on
// the top row spawn area on our board
for (loop_a = 3; loop_a < 8; loop_a++) {
if (Board[0][loop_a][2] == 2) {
// Game is over
document.getElementById('Pointpanel').innerHTML = ''
+ '<br /><br /><br />Points: '
+ Points + '<br /><br />'
+ 'GAME OVER' + '<br /><br />'
+ 'Reload to play again(F5)' + '<br />';
// Stop the game
gameRunning = false;
return;
}
}
}
function winCheck() {
// Check if we have reached level 11.
if (Level == 11) {
document.getElementById('Pointpanel').innerHTML = ''
+ '<br /><br />Points: '
+ Points + '<br /><br />'
+ 'GAME COMPLETED!<br />'
+ 'You defeated level 10!<br /><br />'
+ 'Reload to play again(F5)<br />';
gameRunning = false;
}
}
function About() {
var msg = "A tetris clone by Dag Jonny Nedrelid.\n"
+ "Created 26-27 December 2007.\n"
alert(msg);
}