diff --git a/public/game.js b/public/game.js index 6bb826d..d58ea86 100644 --- a/public/game.js +++ b/public/game.js @@ -172,25 +172,31 @@ class GameUI { } initializePlayers() { - const emptyCells = this.map.getEmptyCells(); - const shuffled = emptyCells.sort(() => Math.random() - 0.5); - - // Place starting units for each player + // Place starting units for each player at fixed positions that are always passable + // Use corners of the map to ensure they don't overlap const positions = [ - { q: 2, r: 2 }, // Player 1 - top area - { q: MAP_SIZE - 3, r: MAP_SIZE - 3 }, // Player 2 - bottom area - { q: 2, r: MAP_SIZE - 3 }, // Player 3 - { q: MAP_SIZE - 3, r: 2 } // Player 4 + { q: 1, r: 1 }, // Player 1 - top-left + { q: MAP_SIZE - 2, r: MAP_SIZE - 2 }, // Player 2 - bottom-right + { q: 1, r: MAP_SIZE - 2 }, // Player 3 - bottom-left + { q: MAP_SIZE - 2, r: 1 } // Player 4 - top-right ]; - + for (let i = 1; i <= this.playerCount; i++) { - const pos = positions[i - 1] || shuffled[i]; - if (pos) { - const cell = this.map.getCell(pos.q, pos.r); - if (cell && cell.isPassable()) { - this.map.setOwner(pos.q, pos.r, i); - cell.setStrength(8); + const pos = positions[i - 1]; + if (!pos) continue; + + // Force the cell to be passable and set ownership + const cell = this.map.getCell(pos.q, pos.r); + if (cell) { + // Make sure cell is passable + if (cell.type === CELL_TYPES.BLOCKED) { + cell.type = CELL_TYPES.EMPTY; } + this.map.setOwner(pos.q, pos.r, i); + cell.setStrength(8); + console.log(`[GAME] Player ${i} placed at (${pos.q}, ${pos.r})`); + } else { + console.error(`[GAME] Failed to place Player ${i} at (${pos.q}, ${pos.r})`); } } } @@ -201,17 +207,24 @@ class GameUI { const sqrt3 = Math.sqrt(3); // Calculate map bounds with proper padding for hex visibility - // For pointy-top hex: width = sqrt(3) * size, height = 2 * size - // Rightmost hex (q=19, r=19): x = HEX_SIZE * sqrt3 * (19 + 19/2) = HEX_SIZE * sqrt3 * 28.5 - // Leftmost hex (q=0, r=0): x = 0 - // Add padding for full hex visibility (hex radius on each side) - const hexPadding = HEX_SIZE * 2; // Extra padding for hex radius + // For pointy-top hex: width = sqrt(3) * size + // Rightmost hex center (q=19, r=19): x = HEX_SIZE * sqrt3 * (19 + 19/2) = HEX_SIZE * sqrt3 * 28.5 + // Leftmost hex center (q=0, r=0): x = 0 + // Add padding for full hex visibility + const hexPadding = HEX_SIZE * 2.5; // Extra padding for hex radius const mapWidth = HEX_SIZE * sqrt3 * ((MAP_SIZE - 1) + (MAP_SIZE - 1) / 2); const mapHeight = HEX_SIZE * 1.5 * (MAP_SIZE - 1); - this.offsetX = hexPadding; - this.offsetY = hexPadding; + // Center the map on canvas + this.offsetX = (canvasWidth - mapWidth) / 2; + this.offsetY = (canvasHeight - mapHeight) / 2; + + // Ensure minimum padding + if (this.offsetX < hexPadding) this.offsetX = hexPadding; + if (this.offsetY < hexPadding) this.offsetY = hexPadding; + + console.log(`[GAME] Map centered: offsetX=${this.offsetX}, offsetY=${this.offsetY}, canvas=${canvasWidth}x${canvasHeight}`); } setupEventListeners() { @@ -553,14 +566,16 @@ class GameUI { this.log(`Player ${this.currentPlayer}'s turn`); console.log(`[GAME] Player ${this.currentPlayer}'s turn started (${this.playerTypes[this.currentPlayer]})`); + // Reset isProcessingTurn BEFORE awaiting AI turn + // This allows the next AI's endTurn() call to proceed + this.isProcessingTurn = false; + // Check if next player is AI and await completion await this.checkAndRunAITurn(); } catch (error) { console.error(`[GAME] Error in endTurn():`, error); this.log(`Error during turn transition: ${error.message}`, 'error'); - } finally { this.isProcessingTurn = false; - console.log(`[GAME] endTurn() completed for Player ${this.currentPlayer}`); } }