function TetrixBoard(ui) { this.ui = ui; this.isStarted = false; this.isPaused = false; this.inKeyPress = false; this._board = new Array(TetrixBoard.BoardWidth * TetrixBoard.BoardHeight); this.clearBoard(); this.curPiece = new TetrixPiece(); this.nextPiece = new TetrixPiece(); this.nextPiece.setRandomShape(); ui.timer.singleShot = true; ui.timer.timeout.connect(this, this.onTimer); ui.keyPressed.connect(this, this.onKeyPress); ui.paintRequested.connect(this, this.onPaint); ui.paintNextPieceRequested.connect(this, this.onPaintNextPiece); } TetrixBoard.BoardWidth = 10; TetrixBoard.BoardHeight = 22; TetrixBoard.prototype.start = function() { if (this.isPaused) return; this.isStarted = true; this.isWaitingAfterLine = false; this.numLinesRemoved = 0; this.numPiecesDropped = 0; this.score = 0; this.level = 1; this.clearBoard(); this.ui.linesRemovedChanged(this.numLinesRemoved); this.ui.scoreChanged(this.score); this.ui.levelChanged(this.level); this.newPiece(); this.ui.timer.start(this.timeoutTime()); } TetrixBoard.prototype.pause = function() { if (!this.isStarted) return; this.isPaused = !this.isPaused; if (this.isPaused) { this.ui.timer.stop(); } else { this.ui.timer.start(this.timeoutTime()); } this.ui.update(); } TetrixBoard.prototype.getShapeAt = function(x, y) { return this._board[(y * TetrixBoard.BoardWidth) + x]; } TetrixBoard.prototype.setShapeAt = function(x, y, newShape) { this._board[(y * TetrixBoard.BoardWidth) + x] = newShape; } TetrixBoard.prototype.clearBoard = function() { for (var i = 0; i < TetrixBoard.BoardHeight * TetrixBoard.BoardWidth; ++i) this._board[i] = TetrixShape.NoShape; } TetrixBoard.prototype.dropDown = function() { var dropHeight = 0; var newY = this.curY; while (newY > 0) { if (!this.tryMove(this.curPiece, this.curX, newY - 1)) break; --newY; ++dropHeight; } this.pieceDropped(dropHeight); } TetrixBoard.prototype.oneLineDown = function() { if (!this.tryMove(this.curPiece, this.curX, this.curY - 1)) this.pieceDropped(0); } TetrixBoard.prototype.pieceDropped = function(dropHeight) { for (var i = 0; i < 4; ++i) { var x = this.curX + this.curPiece.getX(i); var y = this.curY - this.curPiece.getY(i); this.setShapeAt(x, y, this.curPiece.shape); } ++this.numPiecesDropped; if ((this.numPiecesDropped % 25) == 0) { ++this.level; this.ui.timer.start(this.timeoutTime()); this.ui.levelChanged(this.level); } this.score += dropHeight + 7; this.ui.scoreChanged(this.score); this.removeFullLines(); if (!this.isWaitingAfterLine) this.newPiece(); if (this.isStarted && !this.ui.timer.active) this.ui.timer.start(this.timeoutTime()); } TetrixBoard.prototype.removeFullLines = function() { var numFullLines = 0; for (var i = TetrixBoard.BoardHeight - 1; i >= 0; --i) { var lineIsFull = true; for (var j = 0; j < TetrixBoard.BoardWidth; ++j) { if (this.getShapeAt(j, i) == TetrixShape.NoShape) { lineIsFull = false; break; } } if (lineIsFull) { ++numFullLines; for (var k = i; k < TetrixBoard.BoardHeight - 1; ++k) { for (var j = 0; j < TetrixBoard.BoardWidth; ++j) this.setShapeAt(j, k, this.getShapeAt(j, k + 1)); } for (var j = 0; j < TetrixBoard.BoardWidth; ++j) this.setShapeAt(j, TetrixBoard.BoardHeight - 1, TetrixShape.NoShape); } } if (numFullLines > 0) { this.numLinesRemoved += numFullLines; this.score += 10 * numFullLines; this.ui.linesRemovedChanged(this.numLinesRemoved); this.ui.scoreChanged(this.score); this.ui.timer.start(500); this.isWaitingAfterLine = true; this.curPiece.shape = TetrixShape.NoShape; this.ui.update(); } } TetrixBoard.prototype.newPiece = function() { this.curPiece = this.nextPiece; this.nextPiece = new TetrixPiece(); this.nextPiece.setRandomShape(); this.ui.showNextPiece(this.nextPiece.maxX - this.nextPiece.minX + 1, this.nextPiece.maxY - this.nextPiece.minY + 1); this.curX = TetrixBoard.BoardWidth / 2 + 1; this.curY = TetrixBoard.BoardHeight - 1 + this.curPiece.minY; if (!this.tryMove(this.curPiece, this.curX, this.curY)) { this.curPiece.shape = TetrixShape.NoShape; this.ui.timer.stop(); this.isStarted = false; } } TetrixBoard.prototype.tryMove = function(newPiece, newX, newY) { for (var i = 0; i < 4; ++i) { var x = newX + newPiece.getX(i); var y = newY - newPiece.getY(i); if ((x < 0) || (x >= TetrixBoard.BoardWidth) || (y < 0) || (y >= TetrixBoard.BoardHeight)) return false; if (this.getShapeAt(x, y) != TetrixShape.NoShape) return false; } this.curPiece = newPiece; this.curX = newX; this.curY = newY; this.ui.update(); return true; } TetrixBoard.prototype.onPaint = function(painter) { if (this.isPaused) { this.ui.drawPauseScreen(painter); return; } for (var i = 0; i < TetrixBoard.BoardHeight; ++i) { for (var j = 0; j < TetrixBoard.BoardWidth; ++j) { var shape = this.getShapeAt(j, TetrixBoard.BoardHeight - i - 1); if (shape != TetrixShape.NoShape) this.ui.drawSquare(painter, j, i, shape); } } if (this.curPiece.shape != TetrixShape.NoShape) { for (var i = 0; i < 4; ++i) { var x = this.curX + this.curPiece.getX(i); var y = this.curY - this.curPiece.getY(i); this.ui.drawSquare(painter, x, TetrixBoard.BoardHeight - y - 1, this.curPiece.shape); } } } TetrixBoard.prototype.onPaintNextPiece = function(painter) { for (var i = 0; i < 4; ++i) { var x = this.nextPiece.getX(i) - this.nextPiece.minX; var y = this.nextPiece.getY(i) - this.nextPiece.minY; this.ui.drawSquare(painter, x, y, this.nextPiece.shape); } } TetrixBoard.prototype.onKeyPress = function(key) { if (!this.isStarted || this.isPaused || (this.curPiece.shape == TetrixShape.NoShape)) return; this.inKeyPress = true; switch (key) { case Qt.Key_Left: this.tryMove(this.curPiece, this.curX - 1, this.curY); break; case Qt.Key_Right: this.tryMove(this.curPiece, this.curX + 1, this.curY); break; case Qt.Key_Down: this.tryMove(this.curPiece.rotatedRight(), this.curX, this.curY); break; case Qt.Key_Up: this.tryMove(this.curPiece.rotatedLeft(), this.curX, this.curY); break; case Qt.Key_Space: this.dropDown(); break; case Qt.Key_D: this.oneLineDown(); break; } this.inKeyPress = false; if (this.isStarted && !this.ui.timer.active) this.ui.timer.start(this.timeoutTime()); } TetrixBoard.prototype.onTimer = function() { if (this.isWaitingAfterLine) { this.isWaitingAfterLine = false; this.newPiece(); this.ui.timer.start(this.timeoutTime()); } else { if (!this.inKeyPress) { this.oneLineDown(); if (this.isStarted && !this.ui.timer.active) this.ui.timer.start(this.timeoutTime()); } } } TetrixBoard.prototype.timeoutTime = function() { return 1000 / (1 + this.level); }