1
0
forked from sent/waves
waves/public/assets/g/tetris/Game_Logic.js
2025-04-09 17:11:14 -05:00

210 lines
4.7 KiB
JavaScript

/**
* @returns {[Number]} the line numbers of all the completed rows
*/
Game.prototype.getRows = function () {
var i,
rows = [],
res = [],
curRow;
// initialize the rows to 0
for (i = 0; i < 20; i += 1) {
rows[i] = 0;
}
// for each block
for (i = 0; i < this.blocks.length; i += 1) {
// increment the appropriate row
curRow = this.blocks[i].getY();
rows[curRow] += 1;
// if the row is full
if (rows[curRow] === 10) {
res.push(curRow);
}
}
return res;
};
/**
* Removes the rows from the field
*/
Game.prototype.removeRows = function (rows) {
var dropDist = {},
i, j,
remove = {},
curBlock,
curY;
// initialize drops to 0
for (i = -4; i < 20; i += 1) {
dropDist[i] = 0;
}
// for each removed row
for (i = 0; i < rows.length; i += 1) {
remove[rows[i]] = true;
// every row above this should be dropped another spot
for (j = -4; j < rows[i]; j += 1) {
dropDist[j] += 1;
}
}
// for each block
for (i = 0; i < this.blocks.length; i += 1) {
curBlock = this.blocks[i];
curY = curBlock.getY();
// if it is being removed
if (remove[curY]) {
// remove the block
this.removeBlock(i);
i -= 1;
} else {
// it is being dropped
curBlock.setPosition(curBlock.getX(), curBlock.getY() + dropDist[curY]);
}
}
};
Game.prototype.removeBlock = function(index) {
this.blocks[index].kill();
return this.blocks.splice(index, 1);
};
Game.prototype.applyGravity = function (dTime) {
this.timeToNextDrop -= dTime;
// drop until there is a positive time until the next drop time is positive, or the control group s bottomed out
while (this.timeToNextDrop < 0 && (!this.controlGroup.isBottomed())) {
this.dropBlock(true);
this.timeToNextDrop += this.dropPeriod;
}
// if it exited through bottoming, reset the drop period
if (this.controlGroup.isBottomed()) {
this.timeToNextDrop = this.dropPeriod;
}
};
/**
* Changes the shapes of the preview along the side
* @param {[Char]} queue - the queue of pieces
*/
Game.prototype.updatePreviews = function(queue) {
var i;
for (i = 0; i < queue.length; i += 1) {
this.previewGroups[i].setShape(queue[i]);
}
};
/**
* called when the user attempts to swap a block
*/
Game.prototype.swap = function() {
var i, j,
newShape,
oldShape = this.controlGroup.getShape(),
oldBlocks = this.controlGroup.getBlocks(),
newBlocks = [],
thisObject = this;
// can only be called once per drop
if (!this.swapAllowed) {
return;
}
this.swapAllowed = false;
// Reset the locking
this.resetLockCounter(false);
// remove the blocks
// for each block on the field
for (i = 0; i < this.blocks.length; i += 1) {
// if the block is part of the control group, remove it
for (j = 0; j < 4; j += 1) {
if (oldBlocks[j] === this.blocks[i]) {
this.removeBlock(i);
i -= 1;
}
}
}
// if there is a block waiting
if (this.swapGroup) {
newShape = this.swapGroup.getShape();
for (i = 0; i < 4; i += 1) {
newBlocks.push(new Block({blockX:-10, blockY:-10, shape: newShape, occupiedPositions: this.occupiedPositions}));
this.blocks.push(newBlocks[i]);
}
this.controlGroup = new ControlGroup(newBlocks, newShape, function(x, y){
return thisObject.isLegalPosition(x, y);
});
this.swapGroup.setShape(oldShape);
return;
}
// if there is no block waiting
this.swapGroup = new PreviewGroup(-100, 60);
this.swapGroup.setShape(oldShape);
this.newBlock(true);
};
/**
* locks the currnt piece in, registers lines and makes a new block
*/
Game.prototype.lockBlocks = function() {
// figure out if it a t-spin/t-spin mini
var tSpinType = this.controlGroup.getTSpin(),
scoreObject = {},
rows;
if (tSpinType === 'mini') {
scoreObject.miniT = true;
} else if (tSpinType === 'normal') {
scoreObject.normalT = true;
}
// look for rows
rows = this.getRows();
scoreObject.lines = rows.length;
if (rows.length > 0) {
this.removeRows(rows);
}
// apply the score
this.scoreTracker.updateScore(scoreObject);
this.newBlock();
this.resetLockCounter(false);
};
/**
* Resets the lock counter, and the slide counter if not soft
* @param {Boolean} soft = true if a soft reset, and the slide counter should not be reset
*/
Game.prototype.resetLockCounter = function (soft) {
if (soft) {
this.slideCount += 1;
} else {
this.slideCount = 0;
}
this.bottomTimer = this.bottomLockTime;
};
/**
* Determines if the game is over and returns a score object
* if it is. Otherwise, returns null
*/
Game.prototype.getResults = function() {
if (this.gameLost || this.scoreTracker.gameWon()) {
return this.scoreTracker.getResults();
}
return null;
};