summaryrefslogtreecommitdiff
path: root/noncore/games/tetrix/gtetrix.cpp
Side-by-side diff
Diffstat (limited to 'noncore/games/tetrix/gtetrix.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r--noncore/games/tetrix/gtetrix.cpp514
1 files changed, 514 insertions, 0 deletions
diff --git a/noncore/games/tetrix/gtetrix.cpp b/noncore/games/tetrix/gtetrix.cpp
new file mode 100644
index 0000000..d1f38b1
--- a/dev/null
+++ b/noncore/games/tetrix/gtetrix.cpp
@@ -0,0 +1,514 @@
+/**********************************************************************
+** Copyright (C) 2000 Trolltech AS. All rights reserved.
+**
+** This file is part of Qtopia Environment.
+**
+** This file may be distributed and/or modified under the terms of the
+** GNU General Public License version 2 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+** See http://www.trolltech.com/gpl/ for GPL licensing information.
+**
+** Contact info@trolltech.com if any conditions of this licensing are
+** not clear to you.
+**
+**********************************************************************/
+
+
+#include "gtetrix.h"
+
+#include <string.h>
+
+GenericTetrix::GenericTetrix(int boardWidth,int boardHeight)
+{
+ int i,j;
+
+ width = boardWidth;
+ height = boardHeight;
+ boardPtr = new int[height*width]; // Note the order, this makes it easier
+ // to remove full lines.
+ for(i = 0 ; i < height ; i++)
+ for(j = 0 ; j < width ; j++)
+ board(j,i) = 0;
+ currentLine = -1; // -1 if no falling piece.
+ currentPos = 0;
+ showNext = 0; // FALSE
+ nLinesRemoved = 0;
+ nPiecesDropped = 0;
+ score = 0;
+ level = 1;
+ gameID = 0;
+ nClearLines = height;
+}
+
+GenericTetrix::~GenericTetrix()
+{
+ delete[] boardPtr;
+}
+
+
+void GenericTetrix::clearBoard(int fillRandomLines)
+{
+ int i,j;
+
+ if (fillRandomLines >= height)
+ fillRandomLines = height - 1;
+
+ erasePiece();
+ for(i = height - nClearLines - 1 ; i >= fillRandomLines ; i--)
+ for(j = 0 ; j < width ; j++)
+ if (board(j,i) != 0) {
+ draw(j,i,0);
+ board(j,i) = 0;
+ }
+ if (fillRandomLines != 0)
+ for (i = 0 ; i < fillRandomLines ; i++) {
+ fillRandom(i);
+ }
+ nClearLines = height - fillRandomLines;
+}
+
+void GenericTetrix::showBoard()
+{
+ int i,j;
+
+ showPiece();
+ for(i = height - nClearLines - 1 ; i >= 0 ; i--)
+ for(j = 0 ; j < width ; j++)
+ if (board(j,i) != 0)
+ draw(j,i,board(j,i));
+}
+
+void GenericTetrix::hideBoard()
+{
+ int i,j;
+
+ erasePiece();
+ for(i = height - nClearLines - 1 ; i >= 0 ; i--)
+ for(j = 0 ; j < width ; j++)
+ if (board(j,i) != 0)
+ draw(j,i,0);
+}
+
+void GenericTetrix::startGame(int gameType,int fillRandomLines)
+{
+ gameID = gameType;
+ clearBoard(fillRandomLines);
+ nLinesRemoved = 0;
+ updateRemoved(nLinesRemoved);
+ nClearLines = height;
+ nPiecesDropped = 0;
+ score = 0;
+ updateScore(score);
+ level = 1;
+ updateLevel(level);
+ newPiece();
+}
+
+void GenericTetrix::revealNextPiece(int revealIt)
+{
+ if (showNext == revealIt)
+ return;
+ showNext = revealIt;
+ if (!showNext)
+ eraseNextPiece();
+ else
+ showNextPiece();
+}
+
+void GenericTetrix::updateBoard(int x1,int y1,int x2, int y2,
+ int dontUpdateBlanks)
+{
+ int i,j;
+ int tmp;
+
+ if (x1 > x2) {
+ tmp = x2;
+ x2 = x1;
+ x1 = tmp;
+ }
+ if (y1 > y2) {
+ tmp = y2;
+ y2 = y1;
+ y1 = tmp;
+ }
+ if (x1 < 0)
+ x1 = 0;
+ if (x2 >= width)
+ x2 = width - 1;
+ if (y1 < 0)
+ y1 = 0;
+ if (y2 >= height)
+ y2 = height - 1;
+ for(i = y1 ; i <= y2 ; i++)
+ for(j = x1 ; j <= x2 ; j++)
+ if (!dontUpdateBlanks || board(j,height - i - 1) != 0)
+ draw(j,height - i - 1,board(j,height - i - 1));
+ showPiece(); // Remember to update piece correctly!!!!
+}
+
+
+void GenericTetrix::fillRandom(int line)
+{
+ int i,j;
+ int holes;
+
+ for(i = 0 ; i < width ; i++)
+ board(i,line) = TetrixPiece::randomValue(7);
+ holes = 0;
+ for(i = 0 ; i < width ; i++)
+ if (board(i,line) == 0) // Count holes in the line.
+ holes++;
+ if (holes == 0) // Full line, make a random hole:
+ board(TetrixPiece::randomValue(width),line) = 0;
+ if (holes == width) // Empty line, make a random square:
+ board(TetrixPiece::randomValue(width),line) =
+ TetrixPiece::randomValue(6) + 1;
+ for(j = 0 ; j < width ; j++)
+ draw(j,i,board(j,i));
+}
+
+void GenericTetrix::moveLeft(int steps)
+{
+ while(steps) {
+ if (!canMoveTo(currentPos - 1,currentLine))
+ return;
+ moveTo(currentPos - 1,currentLine);
+ steps--;
+ }
+}
+
+void GenericTetrix::moveRight(int steps)
+{
+ while(steps) {
+ if (!canMoveTo(currentPos + 1,currentLine))
+ return;
+ moveTo(currentPos + 1,currentLine);
+ steps--;
+ }
+}
+
+void GenericTetrix::rotateLeft()
+{
+ TetrixPiece tmp(currentPiece);
+
+ tmp.rotateLeft();
+ if (!canPosition(tmp))
+ return;
+ position(tmp);
+ currentPiece = tmp;
+}
+
+void GenericTetrix::rotateRight()
+{
+ TetrixPiece tmp(currentPiece);
+
+ tmp.rotateRight();
+ if (!canPosition(tmp))
+ return;
+ position(tmp);
+ currentPiece = tmp;
+}
+
+void GenericTetrix::dropDown()
+{
+ if (currentLine == -1)
+ return;
+
+ int dropHeight = 0;
+ int newLine = currentLine;
+ while(newLine) {
+ if (!canMoveTo(currentPos,newLine - 1))
+ break;
+ newLine--;
+ dropHeight++;
+ }
+ if (dropHeight != 0)
+ moveTo(currentPos,newLine);
+ internalPieceDropped(dropHeight);
+}
+
+void GenericTetrix::oneLineDown()
+{
+ if (currentLine == -1)
+ return;
+ if (canMoveTo(currentPos,currentLine - 1)) {
+ moveTo(currentPos,currentLine - 1);
+ } else {
+ internalPieceDropped(0);
+ }
+}
+
+void GenericTetrix::newPiece()
+{
+ currentPiece = nextPiece;
+ if (showNext)
+ eraseNextPiece();
+ nextPiece.setRandomType();
+ if (showNext)
+ showNextPiece();
+ currentLine = height - 1 + currentPiece.getMinY();
+ currentPos = width/2 + 1;
+ if (!canMoveTo(currentPos,currentLine)) {
+ currentLine = -1;
+ gameOver();
+ } else {
+ showPiece();
+ }
+}
+
+void GenericTetrix::removePiece()
+{
+ erasePiece();
+ currentLine = -1;
+}
+
+void GenericTetrix::drawNextSquare(int,int,int)
+{
+
+}
+
+void GenericTetrix::pieceDropped(int)
+{
+ newPiece();
+}
+
+void GenericTetrix::updateRemoved(int)
+{
+}
+
+void GenericTetrix::updateScore(int)
+{
+}
+
+void GenericTetrix::updateLevel(int)
+{
+}
+
+void GenericTetrix::removeFullLines()
+{
+ int i,j,k;
+ int nFullLines;
+
+ for(i = 0 ; i < height - nClearLines ; i++) {
+ for(j = 0 ; j < width ; j++)
+ if (board(j,i) == 0)
+ break;
+ if (j == width) {
+ nFullLines = 1;
+ for(k = i + 1 ; k < height - nClearLines ; k++) {
+ for(j = 0 ; j < width ; j++)
+ if (board(j,k) == 0)
+ break;
+ if (j == width) {
+ nFullLines++;
+ } else {
+ for(j = 0 ; j < width ; j++) {
+ if (board(j,k - nFullLines) != board(j,k)) {
+ board(j,k - nFullLines) = board(j,k);
+ draw( j,k - nFullLines,
+ board(j,k - nFullLines));
+ }
+ }
+ }
+ }
+ nClearLines = nClearLines + nFullLines;
+ nLinesRemoved = nLinesRemoved + nFullLines;
+ updateRemoved(nLinesRemoved);
+ score = score + 10*nFullLines; // updateScore must be
+ // called by caller!
+ for (i = height - nClearLines ;
+ i < height - nClearLines + nFullLines ;
+ i++)
+ for(j = 0 ; j < width ; j++)
+ if (board(j,i) != 0) {
+ draw(j,i,0);
+ board(j,i) = 0;
+ }
+ }
+ }
+}
+
+void GenericTetrix::showPiece()
+{
+ int x,y;
+
+ if (currentLine == -1)
+ return;
+
+ for(int i = 0 ; i < 4 ; i++) {
+ currentPiece.getCoord(i,x,y);
+ draw(currentPos + x,currentLine - y,currentPiece.getType());
+ }
+}
+
+void GenericTetrix::erasePiece()
+{
+ int x,y;
+
+ if (currentLine == -1)
+ return;
+
+ for(int i = 0 ; i < 4 ; i++) {
+ currentPiece.getCoord(i,x,y);
+ draw(currentPos + x,currentLine - y,0);
+ }
+}
+
+void GenericTetrix::internalPieceDropped(int dropHeight)
+{
+ gluePiece();
+ nPiecesDropped++;
+ if (nPiecesDropped % 25 == 0) {
+ level++;
+ updateLevel(level);
+ }
+ score = score + 7 + dropHeight;
+ removeFullLines();
+ updateScore(score);
+ pieceDropped(dropHeight);
+}
+
+void GenericTetrix::gluePiece()
+{
+ int x,y;
+ int min;
+
+ if (currentLine == -1)
+ return;
+
+ for(int i = 0 ; i < 4 ; i++) {
+ currentPiece.getCoord(i,x,y);
+ board(currentPos + x,currentLine - y) = currentPiece.getType();
+ }
+ min = currentPiece.getMinY();
+ if (currentLine - min >= height - nClearLines)
+ nClearLines = height - currentLine + min - 1;
+}
+
+void GenericTetrix::showNextPiece(int erase)
+{
+ int x,y;
+ int minX = nextPiece.getMinX();
+ int minY = nextPiece.getMinY();
+ int maxX = nextPiece.getMaxX();
+ int maxY = nextPiece.getMaxY();
+
+ int xOffset = (3 - (maxX - minX))/2;
+ int yOffset = (3 - (maxY - minY))/2;
+
+ for(int i = 0 ; i < 4 ; i++) {
+ nextPiece.getCoord(i,x,y);
+ if (erase)
+ drawNextSquare(x + xOffset - minX,
+ y + yOffset - minY,0);
+ else
+ drawNextSquare(x + xOffset - minX,
+ y + yOffset - minY,nextPiece.getType());
+ }
+}
+
+int GenericTetrix::canPosition(TetrixPiece &piece)
+{
+ if (currentLine == -1)
+ return 0;
+
+ int x,y;
+
+ for(int i = 0 ; i < 4 ; i++) {
+ piece.getCoord(i,x,y);
+ x = currentPos + x;
+ y = currentLine - y; // Board and pieces have inverted y-coord. systems.
+ if (x < 0 || x >= width || y < 0 || y >= height)
+ return 0; // Outside board, cannot put piece here.
+ if (board(x,y) != 0)
+ return 0; // Over a non-zero square, cannot put piece here.
+ }
+ return 1; // Inside board and no non-zero squares underneath.
+
+}
+
+int GenericTetrix::canMoveTo(int xPosition,int line)
+{
+ if (currentLine == -1)
+ return 0;
+
+ int x,y;
+
+ for(int i = 0 ; i < 4 ; i++) {
+ currentPiece.getCoord(i,x,y);
+ x = xPosition + x;
+ y = line - y; // Board and pieces have inverted y-coord. systems.
+ if (x < 0 || x >= width || y < 0 || y >= height)
+ return 0; // Outside board, cannot put piece here.
+ if (board(x,y) != 0)
+ return 0; // Over a non-zero square, cannot put piece here.
+ }
+ return 1; // Inside board and no non-zero squares underneath.
+}
+
+void GenericTetrix::moveTo(int xPosition,int line)
+{
+ if (currentLine == -1)
+ return;
+ optimizedMove(xPosition,line,currentPiece);
+ currentPos = xPosition;
+ currentLine = line;
+}
+
+void GenericTetrix::position(TetrixPiece &piece)
+{
+ if (currentLine == -1)
+ return;
+
+ optimizedMove(currentPos,currentLine,piece);
+}
+
+void GenericTetrix::optimizedMove(int newPos, int newLine,
+ TetrixPiece &newPiece)
+{
+ int updates [8][3];
+ int nUpdates;
+ int value;
+ int x,y;
+ int i,j;
+
+ for(i = 0 ; i < 4 ; i++) { // Put the erasing coords into updates
+ currentPiece.getCoord(i,x,y);
+ updates[i][0] = currentPos + x;
+ updates[i][1] = currentLine - y;
+ updates[i][2] = 0;
+ }
+ nUpdates = 4;
+ for(i = 0 ; i < 4 ; i++) { // Any drawing coord same as an erasing one?
+ newPiece.getCoord(i,x,y);
+ x = newPos + x;
+ y = newLine - y;
+ for (j = 0 ; j < 4 ; j++)
+ if (updates[j][0] == x && updates[j][1] == y) { // Same coord,
+ // don't have to erase
+ if (currentPiece.getType() == newPiece.getType())
+ updates[j][2] = -1; // Correct on screen, no update!
+ else
+ updates[j][2] = newPiece.getType();
+ break;
+ }
+ if (j == 4) { // This coord does not overlap an erasing one
+ updates[nUpdates][0] = x;
+ updates[nUpdates][1] = y;
+ updates[nUpdates][2] = newPiece.getType();
+ nUpdates++;
+ }
+ }
+ for (i = 0 ; i < nUpdates ; i++) { // Do the updating
+ x = updates[i][0];
+ y = updates[i][1];
+ value = updates[i][2];
+ if (value != -1) // Only update if new value != current
+ draw(x,y,value);
+ }
+}