// Main Application - Ties everything together let localGame = null; let renderer = null; let lastTime = 0; // Initialize when DOM is ready document.addEventListener('DOMContentLoaded', () => { // Connect to server network.connect(); // Initialize renderer renderer = new TetrisRenderer('battle-grid'); // Setup network listeners setupNetworkListeners(); // Setup keyboard controls setupKeyboardControls(); }); function setupNetworkListeners() { // Player joined lobby network.setListener('player-joined', (player) => { ui.updatePlayerList(network.getAllPlayers()); }); // Player left lobby network.setListener('player-left', (playerId) => { ui.updatePlayerList(network.getAllPlayers()); }); // Game started network.setListener('game-started', (players, states) => { ui.showScreen('game'); ui.displays.gameRoomName.textContent = 'GLOBAL LOBBY'; // Clear old boards renderer.clearAll(); // Create boards for all players states.forEach((state) => { const player = network.getPlayer(state.playerId); renderer.createPlayerBoard(state.playerId, player.name); // Initialize local game for current player if (state.playerId === network.currentPlayerId) { localGame = new TetrisGame(state.playerId); localGame.loadState(state); } }); // Set up battle grid layout updateBattleGridLayout(players.length); // Start game loop lastTime = performance.now(); requestAnimationFrame(gameLoop); }); // State update during game network.setListener('state-update', (states) => { // Update local game if it's our state const localState = states.find(s => s.playerId === network.currentPlayerId); if (localState) { localGame.loadState(localState); } // Check for game over const allStates = network.getAllGameStates(); const activePlayers = Object.values(allStates).filter(s => !s.eliminated); if (activePlayers.length <= 1) { endGame(allStates); } }); // Game over network.setListener('game-over', (data) => { endGame(data.states); }); } function setupKeyboardControls() { document.addEventListener('keydown', (e) => { if (ui.screens.game.classList.contains('active') && localGame) { switch (e.key) { case 'ArrowLeft': network.sendMove('left'); e.preventDefault(); break; case 'ArrowRight': network.sendMove('right'); e.preventDefault(); break; case 'ArrowDown': network.sendDrop(); e.preventDefault(); break; case 'ArrowUp': network.sendRotate(); e.preventDefault(); break; case ' ': network.sendHardDrop(); e.preventDefault(); break; } } }); } function updateBattleGridLayout(playerCount) { ui.displays.battleGrid.classList.remove('grid-2x2', 'grid-2x4'); if (playerCount <= 4) { ui.displays.battleGrid.classList.add('grid-2x2'); } else { ui.displays.battleGrid.classList.add('grid-2x4'); } } function endGame(states) { // Find winner const activePlayers = Object.values(states).filter(s => !s.eliminated); const eliminatedPlayers = Object.values(states).filter(s => s.eliminated); let winner = null; let scores = {}; if (activePlayers.length === 1) { const winnerState = activePlayers[0]; const winnerPlayer = network.getPlayer(winnerState.playerId); winner = winnerPlayer.name; } // Build scores list Object.values(states).forEach(state => { const player = network.getPlayer(state.playerId); if (player) { scores[player.name] = state.score; } }); ui.showGameOver(winner, scores); } function gameLoop(currentTime) { if (!ui.screens.game.classList.contains('active')) { return; } const deltaTime = currentTime - lastTime; lastTime = currentTime; // Update local game if (localGame) { localGame.update(deltaTime); } // Render all players const allStates = network.getAllGameStates(); Object.values(allStates).forEach(state => { renderer.renderPlayer(state.playerId, state); }); // Set active player highlight renderer.setActivePlayer(network.currentPlayerId); requestAnimationFrame(gameLoop); }