Fix garbage elimination to check board overflow after piece locks
- Move elimination check from addGarbageToPlayer to lockPiece - Check if top 2 rows have blocks after piece locks (board overflow) - Re-compute opponents in sendGarbage loop to skip eliminated players - Preserve game state after game over for viewing final results - Reset all player variables at start of new game Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
+52
-20
@@ -405,6 +405,7 @@ function spawnPiece(player) {
|
||||
function lockPiece(player) {
|
||||
if (!player.currentPiece) return;
|
||||
|
||||
// Lock piece into board
|
||||
for (let row = 0; row < player.currentPiece.shape.length; row++) {
|
||||
for (let col = 0; col < player.currentPiece.shape[row].length; col++) {
|
||||
if (player.currentPiece.shape[row][col]) {
|
||||
@@ -419,10 +420,29 @@ function lockPiece(player) {
|
||||
|
||||
const rowsCleared = clearRows(player);
|
||||
|
||||
// Check if board overflowed (top 2 rows have blocks) - this means player is eliminated
|
||||
let boardOverflowed = false;
|
||||
for (let row = 0; row < 2; row++) {
|
||||
for (let col = 0; col < BOARD_WIDTH; col++) {
|
||||
if (player.board[row][col] !== 0) {
|
||||
boardOverflowed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (boardOverflowed) break;
|
||||
}
|
||||
if (boardOverflowed) {
|
||||
player.eliminated = true;
|
||||
console.log(`[ELIMINATION] ${player.name} eliminated - board overflowed`);
|
||||
broadcastState();
|
||||
checkGameOver();
|
||||
return;
|
||||
}
|
||||
|
||||
const spawnResult = spawnPiece(player);
|
||||
if (!spawnResult) {
|
||||
player.eliminated = true;
|
||||
console.log(`[ELIMINATION] ${player.name} eliminated - piece could not spawn (board full at y=${player.currentPiece?.y})`);
|
||||
console.log(`[ELIMINATION] ${player.name} eliminated - piece could not spawn`);
|
||||
}
|
||||
|
||||
// Reset canHold for the new piece
|
||||
@@ -456,20 +476,23 @@ function clearRows(player) {
|
||||
|
||||
function sendGarbage(sender, rowsCleared) {
|
||||
// Number of garbage rows equals number of lines cleared
|
||||
const opponents = Array.from(lobby.players.values()).filter(p => p.id !== sender.id && !p.eliminated);
|
||||
if (opponents.length === 0) {
|
||||
console.log(`[GARBAGE] ${sender.name} cleared ${rowsCleared} row(s) but no opponents to send garbage to`);
|
||||
return;
|
||||
}
|
||||
|
||||
const garbageLog = [];
|
||||
for (let i = 0; i < rowsCleared; i++) {
|
||||
// Re-compute opponents each iteration to exclude players eliminated by previous garbage
|
||||
const opponents = Array.from(lobby.players.values()).filter(p => p.id !== sender.id && !p.eliminated);
|
||||
if (opponents.length === 0) {
|
||||
break;
|
||||
}
|
||||
const target = opponents[Math.floor(Math.random() * opponents.length)];
|
||||
garbageLog.push(target.name);
|
||||
addGarbageToPlayer(target, sender.name);
|
||||
}
|
||||
|
||||
console.log(`[GARBAGE] ${sender.name} cleared ${rowsCleared} row(s) -> sent garbage to: ${garbageLog.join(', ')}`);
|
||||
if (garbageLog.length > 0) {
|
||||
console.log(`[GARBAGE] ${sender.name} cleared ${rowsCleared} row(s) -> sent garbage to: ${garbageLog.join(', ')}`);
|
||||
} else {
|
||||
console.log(`[GARBAGE] ${sender.name} cleared ${rowsCleared} row(s) but no opponents to send garbage to`);
|
||||
}
|
||||
}
|
||||
|
||||
function addGarbageToPlayer(player, senderName) {
|
||||
@@ -484,17 +507,9 @@ function addGarbageToPlayer(player, senderName) {
|
||||
player.garbageReceived.push({ rows: 1, sender: senderName });
|
||||
|
||||
// Push current piece up by 1 row if it exists (y decreases when moving up)
|
||||
// Don't eliminate here - let the piece lock and check board overflow then
|
||||
if (player.currentPiece) {
|
||||
const oldY = player.currentPiece.y;
|
||||
player.currentPiece.y--;
|
||||
// Eliminate if the piece is pushed above the board or collides
|
||||
if (player.currentPiece.y < 0) {
|
||||
player.eliminated = true;
|
||||
console.log(`[ELIMINATION] ${player.name} eliminated by ${senderName} - piece pushed above board (y=${oldY} -> ${player.currentPiece.y})`);
|
||||
} else if (!isValidPosition(player.currentPiece, player.currentPiece.x, player.currentPiece.y, player.board)) {
|
||||
player.eliminated = true;
|
||||
console.log(`[ELIMINATION] ${player.name} eliminated by ${senderName} - piece collision after garbage (piece at x=${player.currentPiece.x}, y=${player.currentPiece.y})`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -514,6 +529,7 @@ function startGame() {
|
||||
// Initialize shared piece queue
|
||||
lobby.pieceQueue = createPieceQueue(14); // 98 pieces (~14 bags)
|
||||
|
||||
// Reset all player variables for the new game
|
||||
for (const player of lobby.players.values()) {
|
||||
player.board = createEmptyBoard();
|
||||
player.score = 0;
|
||||
@@ -521,9 +537,12 @@ function startGame() {
|
||||
player.level = 1;
|
||||
player.eliminated = false;
|
||||
player.dropInterval = 1000;
|
||||
player.dropCounter = 0;
|
||||
player.holdPiece = null;
|
||||
player.canHold = true;
|
||||
player.garbageReceived = [];
|
||||
player.currentPiece = null;
|
||||
player.nextPiece = null;
|
||||
lobby.playerSequenceIndex.set(player.id, 0);
|
||||
}
|
||||
|
||||
@@ -593,13 +612,19 @@ function checkGameOver() {
|
||||
console.log(`[GAMEOVER CHECK] Active players: ${activePlayers.length} (${activePlayers.map(p => p.name).join(', ')})`);
|
||||
if (activePlayers.length <= 1) {
|
||||
console.log(`[GAME OVER] ${activePlayers.length === 1 ? `Winner: ${activePlayers[0].name}` : 'No winner (all eliminated)'}`);
|
||||
io.to(LOBBY_ROOM).emit('game-over', { states: getStates() });
|
||||
|
||||
// Stop the game interval but keep game state visible for viewing
|
||||
if (lobby.gameInterval) {
|
||||
clearInterval(lobby.gameInterval);
|
||||
lobby.gameInterval = null;
|
||||
}
|
||||
lobby.gameStarted = false;
|
||||
|
||||
// Set all players to not ready for next game (but keep their final state)
|
||||
for (const player of lobby.players.values()) {
|
||||
player.ready = false;
|
||||
}
|
||||
|
||||
// Move spectators to players for next round
|
||||
for (const [id, spectator] of lobby.spectators.entries()) {
|
||||
const player = {
|
||||
@@ -611,12 +636,16 @@ function checkGameOver() {
|
||||
board: createEmptyBoard(),
|
||||
currentPiece: null,
|
||||
nextPiece: null,
|
||||
holdPiece: null,
|
||||
canHold: true,
|
||||
eliminated: false,
|
||||
ready: false,
|
||||
dropCounter: 0,
|
||||
dropInterval: 1000
|
||||
dropInterval: 1000,
|
||||
garbageReceived: []
|
||||
};
|
||||
lobby.players.set(id, player);
|
||||
lobby.playerSequenceIndex.set(id, 0);
|
||||
spectator.socket = io.sockets.sockets.get(id);
|
||||
if (spectator.socket) {
|
||||
spectator.socket.data.playerName = spectator.name;
|
||||
@@ -624,13 +653,16 @@ function checkGameOver() {
|
||||
}
|
||||
lobby.spectators.clear();
|
||||
|
||||
// Broadcast game over with final states
|
||||
io.to(LOBBY_ROOM).emit('game-over', { states: getStates() });
|
||||
|
||||
// Broadcast updated player list
|
||||
io.to(LOBBY_ROOM).emit('player-joined', {
|
||||
player: null,
|
||||
players: getPlayersList()
|
||||
});
|
||||
|
||||
console.log(`Game over. Moved ${activePlayers.length === 1 ? 0 : lobby.players.size} players to next round`);
|
||||
console.log(`Game over. Reset ${lobby.players.size} players for next round`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user