/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var GameTile = Container.expand(function (leftType, rightType, leftCrowns, rightCrowns, number) { var self = Container.call(this); self.leftType = leftType; self.rightType = rightType; self.leftCrowns = leftCrowns; self.rightCrowns = rightCrowns; self.number = number; self.selected = false; self.rotation = 0; // 0, 90, 180, 270 degrees self.currentRotationAngle = 0; // Track rotation angle in degrees self.isDragging = false; self.ownerPlayer = null; // Track which player owns this tile // Create tile background var bg = self.addChild(LK.getAsset('tileSlot', { anchorX: 0.5, anchorY: 0.5 })); // Create terrain sections var leftTerrain = self.addChild(LK.getAsset(leftType, { x: -60, y: 0, anchorX: 0.5, anchorY: 0.5 })); var rightTerrain = self.addChild(LK.getAsset(rightType, { x: 60, y: 0, anchorX: 0.5, anchorY: 0.5 })); // Add crowns for (var i = 0; i < leftCrowns; i++) { self.addChild(LK.getAsset('crown', { x: -60 - 35 + i * 15, y: -35, anchorX: 0.5, anchorY: 0.5 })); } for (var i = 0; i < rightCrowns; i++) { self.addChild(LK.getAsset('crown', { x: 60 - 35 + i * 15, y: -35, anchorX: 0.5, anchorY: 0.5 })); } // Remove the number display from here as it's handled in drawCurrentTiles // Add rotation button (only visible when selected) var rotateBtn = self.addChild(new Text2('↻', { size: 30, fill: 0x00FF00 })); rotateBtn.anchor.set(0.5, 0.5); rotateBtn.x = 100; rotateBtn.y = -50; rotateBtn.alpha = 0; self.rotateBtn = rotateBtn; // Store original terrain references for rotation self.leftTerrain = leftTerrain; self.rightTerrain = rightTerrain; self.rotateTile = function () { self.currentRotationAngle = (self.currentRotationAngle + 90) % 360; self.rotation = self.currentRotationAngle * Math.PI / 180; }; self.updateTileVisuals = function () { // Normalize rotation angle to 0, 90, 180, or 270 degrees self.currentRotationAngle = (self.currentRotationAngle % 360 + 360) % 360; if (self.currentRotationAngle % 90 !== 0) { self.currentRotationAngle = Math.round(self.currentRotationAngle / 90) * 90; } // Set Container rotation based on angle self.rotation = self.currentRotationAngle * Math.PI / 180; }; self.setSelected = function (selected) { self.selected = selected; if (selected) { if (!self.selectedBg) { self.selectedBg = self.addChildAt(LK.getAsset('selectedTile', { anchorX: 0.5, anchorY: 0.5 }), 0); } self.rotateBtn.alpha = 1; } else { if (self.selectedBg) { self.removeChild(self.selectedBg); self.selectedBg = null; } self.rotateBtn.alpha = 0; } }; self.down = function (x, y, obj) { // Prevent interaction if tile is owned by AI player or during AI turn if (self.ownerPlayer && self.ownerPlayer !== 0) { return; } if (gameState === 'aiTurn') { return; } if (gameState === 'selectTile' && currentPlayer === 0) { selectTile(self); } else if (gameState === 'placeTile' && currentPlayer === 0 && self.selected) { // Check if clicked on rotation button using local coordinates directly if (x > 85 && x < 115 && y > -65 && y < -35) { self.rotateTile(); LK.getSound('selectSound').play(); } else { // Start dragging self.isDragging = true; draggedTile = self; } } }; return self; }); var Kingdom = Container.expand(function (playerIndex) { var self = Container.call(this); self.playerIndex = playerIndex; self.grid = []; self.score = 0; self.hasMoved = false; // Track if player has moved kingdom // Initialize 5x5 grid for (var i = 0; i < 5; i++) { self.grid[i] = []; for (var j = 0; j < 5; j++) { self.grid[i][j] = null; } } // Place castle at center self.grid[2][2] = { type: 'castle', crowns: 0 }; // Draw kingdom grid self.drawKingdom = function () { // Clear existing visuals for (var i = self.children.length - 1; i >= 0; i--) { self.removeChild(self.children[i]); } for (var i = 0; i < 5; i++) { for (var j = 0; j < 5; j++) { var cell = self.addChild(LK.getAsset('kingdomCell', { x: j * 125, y: i * 125, anchorX: 0, anchorY: 0 })); if (self.grid[i][j]) { var terrain = self.addChild(LK.getAsset(self.grid[i][j].type, { x: j * 125 + 62.5, y: i * 125 + 62.5, anchorX: 0.5, anchorY: 0.5 })); // Add crowns if present for (var c = 0; c < self.grid[i][j].crowns; c++) { var crown = self.addChild(LK.getAsset('crown', { x: j * 125 + 62.5 - 35 + c * 15, y: i * 125 + 35, anchorX: 0.5, anchorY: 0.5 })); } } } } }; self.canPlaceTile = function (tile, row, col) { // Check if positions are valid and empty based on rotation var positions = self.getTilePositions(tile, row, col); if (!positions) { return false; } if (self.grid[positions[0][0]][positions[0][1]] !== null || self.grid[positions[1][0]][positions[1][1]] !== null) { return false; } // Check if adjacent to existing kingdom var adjacent = false; for (var p = 0; p < positions.length; p++) { var r = positions[p][0]; var c = positions[p][1]; // Check all 4 directions var directions = [[-1, 0], [1, 0], [0, -1], [0, 1]]; for (var d = 0; d < directions.length; d++) { var nr = r + directions[d][0]; var nc = c + directions[d][1]; if (nr >= 0 && nr < 5 && nc >= 0 && nc < 5 && self.grid[nr][nc] !== null) { adjacent = true; break; } } if (adjacent) { break; } } if (!adjacent) { return false; } // Check terrain matching - need at least one matching adjacent terrain var validConnections = 0; for (var p = 0; p < positions.length; p++) { var r = positions[p][0]; var c = positions[p][1]; var directions = [[-1, 0], [1, 0], [0, -1], [0, 1]]; for (var d = 0; d < directions.length; d++) { var nr = r + directions[d][0]; var nc = c + directions[d][1]; if (nr >= 0 && nr < 5 && nc >= 0 && nc < 5 && self.grid[nr][nc] !== null) { if (self.grid[nr][nc].type === 'castle') { // Castle connection is always valid - everything matches castle validConnections++; } else { // Check if terrain matches var terrainIndex = p; var tileType = terrainIndex === 0 ? tile.leftType : tile.rightType; if (self.grid[nr][nc].type === tileType) { validConnections++; } } } } } return validConnections >= 1; }; self.getTilePositions = function (tile, row, col) { var positions; if (tile.currentRotationAngle === 0) { // Horizontal: left-right if (col >= 4) { return null; } positions = [[row, col], [row, col + 1]]; } else if (tile.currentRotationAngle === 90) { // Vertical: top-bottom if (row >= 4) { return null; } positions = [[row, col], [row + 1, col]]; } else if (tile.currentRotationAngle === 180) { // Horizontal: right-left if (col >= 4) { return null; } positions = [[row, col + 1], [row, col]]; } else { // 270 // Vertical: bottom-top if (row >= 4) { return null; } positions = [[row + 1, col], [row, col]]; } // Check bounds for (var i = 0; i < positions.length; i++) { if (positions[i][0] < 0 || positions[i][0] >= 5 || positions[i][1] < 0 || positions[i][1] >= 5) { return null; } } return positions; }; self.placeTile = function (tile, row, col) { var positions = self.getTilePositions(tile, row, col); if (!positions) { return false; } // Place based on rotation if (tile.currentRotationAngle === 0 || tile.currentRotationAngle === 180) { // Horizontal placement self.grid[positions[0][0]][positions[0][1]] = { type: tile.leftType, crowns: tile.leftCrowns }; self.grid[positions[1][0]][positions[1][1]] = { type: tile.rightType, crowns: tile.rightCrowns }; } else { // Vertical placement self.grid[positions[0][0]][positions[0][1]] = { type: tile.leftType, crowns: tile.leftCrowns }; self.grid[positions[1][0]][positions[1][1]] = { type: tile.rightType, crowns: tile.rightCrowns }; } self.drawKingdom(); return true; }; self.calculateScore = function () { var visited = []; var totalScore = 0; for (var i = 0; i < 5; i++) { visited[i] = []; for (var j = 0; j < 5; j++) { visited[i][j] = false; } } for (var i = 0; i < 5; i++) { for (var j = 0; j < 5; j++) { if (!visited[i][j] && self.grid[i][j] && self.grid[i][j].type !== 'castle') { var result = self.floodFill(i, j, self.grid[i][j].type, visited); totalScore += result.size * result.crowns; } } } self.score = totalScore; return totalScore; }; self.floodFill = function (row, col, terrainType, visited) { if (row < 0 || row >= 5 || col < 0 || col >= 5) { return { size: 0, crowns: 0 }; } if (visited[row][col]) { return { size: 0, crowns: 0 }; } if (!self.grid[row][col] || self.grid[row][col].type !== terrainType) { return { size: 0, crowns: 0 }; } visited[row][col] = true; var size = 1; var crowns = self.grid[row][col].crowns; var directions = [[-1, 0], [1, 0], [0, -1], [0, 1]]; for (var d = 0; d < directions.length; d++) { var result = self.floodFill(row + directions[d][0], col + directions[d][1], terrainType, visited); size += result.size; crowns += result.crowns; } return { size: size, crowns: crowns }; }; // Check if kingdom can be moved in a direction self.canMoveKingdom = function (direction) { // Find bounds of current kingdom var minRow = 5, maxRow = -1, minCol = 5, maxCol = -1; for (var i = 0; i < 5; i++) { for (var j = 0; j < 5; j++) { if (self.grid[i][j] !== null) { minRow = Math.min(minRow, i); maxRow = Math.max(maxRow, i); minCol = Math.min(minCol, j); maxCol = Math.max(maxCol, j); } } } // Check if movement is possible if (direction === 'up' && minRow <= 0) { return false; } if (direction === 'down' && maxRow >= 4) { return false; } if (direction === 'left' && minCol <= 0) { return false; } if (direction === 'right' && maxCol >= 4) { return false; } return true; }; // Move entire kingdom in a direction self.moveKingdom = function (direction) { if (!self.canMoveKingdom(direction)) { return false; } var newGrid = []; for (var i = 0; i < 5; i++) { newGrid[i] = []; for (var j = 0; j < 5; j++) { newGrid[i][j] = null; } } var deltaRow = 0, deltaCol = 0; if (direction === 'up') { deltaRow = -1; } if (direction === 'down') { deltaRow = 1; } if (direction === 'left') { deltaCol = -1; } if (direction === 'right') { deltaCol = 1; } // Move all tiles for (var i = 0; i < 5; i++) { for (var j = 0; j < 5; j++) { if (self.grid[i][j] !== null) { var newRow = i + deltaRow; var newCol = j + deltaCol; if (newRow >= 0 && newRow < 5 && newCol >= 0 && newCol < 5) { newGrid[newRow][newCol] = self.grid[i][j]; } } } } self.grid = newGrid; self.drawKingdom(); self.hasMoved = true; // Mark that kingdom has been moved return true; }; self.drawKingdom(); return self; }); var StartScreen = Container.expand(function () { var self = Container.call(this); // Create background overlay var overlay = self.addChild(LK.getAsset('kingdomBackground', { x: 1024, y: 1366, anchorX: 0.5, anchorY: 0.5, scaleX: 3, scaleY: 4 })); overlay.alpha = 0.95; overlay.tint = 0x000000; // Game title var titleText = self.addChild(new Text2('KINGDOMINO', { size: 80, fill: 0xFFD700 })); titleText.anchor.set(0.5, 0.5); titleText.x = 1024; titleText.y = 300; // Instructions text var instructionsText = self.addChild(new Text2('HOW TO PLAY:\n\n• Select a tile each round\n• Click on selected tile or ↻ button to rotate\n• Connect it to your kingdom\n• Castle connections are always valid\n• Other terrains must match at least one side\n• Score = Territory Size × Crown Count\n• Move kingdom for -10 points\n• Trash tile for -5 points', { size: 45, fill: 0xFFFFFF })); instructionsText.anchor.set(0.5, 0.5); instructionsText.x = 1024; instructionsText.y = 800; // Crown scoring explanation var crownText = self.addChild(new Text2('CROWN SCORING:\nLarger connected territories\nwith more crowns = higher score!', { size: 40, fill: 0xFFD700 })); crownText.anchor.set(0.5, 0.5); crownText.x = 1024; crownText.y = 1200; // Start button var startButton = self.addChild(new Text2('TAP TO START', { size: 60, fill: 0x00FF00 })); startButton.anchor.set(0.5, 0.5); startButton.x = 1024; startButton.y = 1500; // Pulsing animation for start button var pulseScale = 1.0; var pulseDirection = 1; self.update = function () { pulseScale += pulseDirection * 0.02; if (pulseScale > 1.2) { pulseScale = 1.2; pulseDirection = -1; } else if (pulseScale < 1.0) { pulseScale = 1.0; pulseDirection = 1; } startButton.scaleX = pulseScale; startButton.scaleY = pulseScale; }; self.down = function (x, y, obj) { // Start the game startGame(); }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x2F4F2F }); /**** * Game Code ****/ // Add game background var gameBackground = game.addChild(LK.getAsset('gameBoard', { x: 1024, y: 1366, anchorX: 0.5, anchorY: 0.5, scaleX: 1.28, scaleY: 1.71 })); // Send background to the very back game.addChildAt(gameBackground, 0); // Game state variables var showingStartScreen = true; var startScreen = null; // Initialize basic game assets var gameState = 'selectTile'; // 'selectTile', 'placeTile', 'gameOver' var currentPlayer = 0; var round = 1; var maxRounds = 12; var selectedTile = null; var draggedTile = null; var placementRow = -1; var placementCol = -1; // Penalty tracking flags var hasUsedTrash = false; var hasMovedKingdom = false; // Player kingdoms var kingdoms = []; var players = ['Human', 'AI1', 'AI2', 'AI3']; var turnOrder = [0, 1, 2, 3]; // Tile deck var tileDeck = []; var currentTiles = []; var selectedTiles = []; // UI elements var scoreTxt = new Text2('Round: 1', { size: 60, fill: 0xFFFFFF }); scoreTxt.anchor.set(1, 0); scoreTxt.x = -120; scoreTxt.y = 10; LK.gui.topRight.addChild(scoreTxt); var playerScoreTxt = new Text2('Your Score: 0', { size: 60, fill: 0xFFFFFF }); playerScoreTxt.anchor.set(0.5, 0); playerScoreTxt.x = 0; playerScoreTxt.y = -850; playerScoreTxt.alpha = 0; // Hide initially LK.gui.center.addChild(playerScoreTxt); var instructionTxt = new Text2('Select a tile', { size: 40, fill: 0x000000 }); instructionTxt.anchor.set(0.5, 1); LK.gui.bottom.addChild(instructionTxt); // AI players score display var aiScoresContainer = new Container(); aiScoresContainer.x = 0; aiScoresContainer.y = -750; aiScoresContainer.alpha = 0; // Hide initially LK.gui.center.addChild(aiScoresContainer); var aiScoreTexts = []; for (var i = 1; i < 4; i++) { var aiScoreTxt = new Text2('AI ' + i + ' Score: 0', { size: 50, fill: 0xFFFFFF }); aiScoreTxt.anchor.set(0.5, 0); aiScoreTxt.y = (i - 1) * 45; aiScoresContainer.addChild(aiScoreTxt); aiScoreTexts.push(aiScoreTxt); } // Function to update AI scores display function updateAIScoresDisplay() { for (var i = 1; i < 4; i++) { var kingdom = kingdoms[i]; var score = kingdom.calculateScore(); if (kingdom.hasMoved) { score = Math.max(0, score - 10); } aiScoreTexts[i - 1].setText('AI ' + i + ' Score: ' + score); } } // Movement control buttons in center of bottom kingdoms var moveButtonContainer = new Container(); moveButtonContainer.x = 1024; // Center of screen moveButtonContainer.y = 2450 - 50; game.addChild(moveButtonContainer); var moveUpBtn = new Text2('↑', { size: 50, fill: 0xFFFFFF }); moveUpBtn.anchor.set(0.5, 0.5); moveUpBtn.x = -75; moveUpBtn.y = 0; moveButtonContainer.addChild(moveUpBtn); var moveLeftBtn = new Text2('←', { size: 50, fill: 0xFFFFFF }); moveLeftBtn.anchor.set(0.5, 0.5); moveLeftBtn.x = -125; moveLeftBtn.y = 50; moveButtonContainer.addChild(moveLeftBtn); var moveRightBtn = new Text2('→', { size: 50, fill: 0xFFFFFF }); moveRightBtn.anchor.set(0.5, 0.5); moveRightBtn.x = -25; moveRightBtn.y = 50; moveButtonContainer.addChild(moveRightBtn); var moveDownBtn = new Text2('↓', { size: 50, fill: 0xFFFFFF }); moveDownBtn.anchor.set(0.5, 0.5); moveDownBtn.x = -75; moveDownBtn.y = 100; moveButtonContainer.addChild(moveDownBtn); // Trash button in center var trashBtn = new Text2('🗑', { size: 60, fill: 0xFF0000 }); trashBtn.anchor.set(0.5, 0.5); trashBtn.x = 1174; // Center of screen area trashBtn.y = 2500 - 50; game.addChild(trashBtn); var trashLabel = new Text2('Trash (-5pts)', { size: 30, fill: 0xFFFFFF }); trashLabel.anchor.set(0.5, 0); trashLabel.x = 1174; trashLabel.y = 2540 - 50; game.addChild(trashLabel); // Rotation button in center var globalRotateBtn = new Text2('↻', { size: 150, fill: 0x00FF00 }); globalRotateBtn.anchor.set(0.5, 0.5); globalRotateBtn.x = 934 + 40 + 100 - 40 - 10; // Center of screen area globalRotateBtn.y = 2350 - 200 - 50; game.addChild(globalRotateBtn); var rotateLabel = new Text2('Rotate', { size: 50, fill: 0xFFFFFF }); rotateLabel.anchor.set(0.5, 0); rotateLabel.x = 934 + 40 + 100 - 40 - 10; rotateLabel.y = 2410 - 200 - 50; game.addChild(rotateLabel); // Movement cost label near movement buttons var moveCostLabel = new Text2('Move (-10pts)', { size: 30, fill: 0xFFFFFF }); moveCostLabel.anchor.set(0.5, 0); moveCostLabel.x = 949; moveCostLabel.y = 2345; game.addChild(moveCostLabel); // Turn order display var turnOrderContainer = new Container(); turnOrderContainer.x = -200; turnOrderContainer.y = 75; LK.gui.topRight.addChild(turnOrderContainer); var turnOrderTexts = []; for (var i = 0; i < 4; i++) { var turnText = new Text2('', { size: 35, fill: 0xFFFFFF }); turnText.anchor.set(1, 0); turnText.y = i * 45; turnOrderContainer.addChild(turnText); turnOrderTexts.push(turnText); } // Update turn order display function updateTurnOrderDisplay() { var playerNames = ['YOU', 'AI 1', 'AI 2', 'AI 3']; for (var i = 0; i < 4; i++) { if (turnOrderTexts[i]) { var playerIndex = turnOrder[i]; var isCurrentPlayer = i === turnOrder.indexOf(currentPlayer); turnOrderTexts[i].setText(i + 1 + '. ' + playerNames[playerIndex]); turnOrderTexts[i].tint = isCurrentPlayer ? 0x00FF00 : 0xFFFFFF; } } } // Initialize tile deck function initializeTileDeck() { // Complete set of 48 Kingdomino tiles with exact terrain and crown combinations var tileData = [ // Tiles 1-8: Wheat fields { leftType: 'wheat', rightType: 'wheat', leftCrowns: 0, rightCrowns: 0 }, { leftType: 'wheat', rightType: 'wheat', leftCrowns: 0, rightCrowns: 0 }, { leftType: 'forest', rightType: 'forest', leftCrowns: 0, rightCrowns: 0 }, { leftType: 'forest', rightType: 'forest', leftCrowns: 0, rightCrowns: 0 }, { leftType: 'forest', rightType: 'forest', leftCrowns: 0, rightCrowns: 0 }, { leftType: 'forest', rightType: 'forest', leftCrowns: 0, rightCrowns: 0 }, { leftType: 'lake', rightType: 'lake', leftCrowns: 0, rightCrowns: 0 }, { leftType: 'lake', rightType: 'lake', leftCrowns: 0, rightCrowns: 0 }, // Tiles 9-16: Grassland { leftType: 'lake', rightType: 'lake', leftCrowns: 0, rightCrowns: 0 }, { leftType: 'grassland', rightType: 'grassland', leftCrowns: 0, rightCrowns: 0 }, { leftType: 'grassland', rightType: 'grassland', leftCrowns: 0, rightCrowns: 0 }, { leftType: 'swamp', rightType: 'swamp', leftCrowns: 0, rightCrowns: 0 }, { leftType: 'wheat', rightType: 'forest', leftCrowns: 0, rightCrowns: 0 }, { leftType: 'wheat', rightType: 'lake', leftCrowns: 0, rightCrowns: 0 }, { leftType: 'wheat', rightType: 'grassland', leftCrowns: 0, rightCrowns: 0 }, { leftType: 'wheat', rightType: 'swamp', leftCrowns: 0, rightCrowns: 0 }, // Tiles 17-24: Forest { leftType: 'forest', rightType: 'lake', leftCrowns: 0, rightCrowns: 0 }, { leftType: 'forest', rightType: 'grassland', leftCrowns: 0, rightCrowns: 0 }, { leftType: 'wheat', rightType: 'forest', leftCrowns: 1, rightCrowns: 0 }, { leftType: 'wheat', rightType: 'lake', leftCrowns: 1, rightCrowns: 0 }, { leftType: 'wheat', rightType: 'grassland', leftCrowns: 1, rightCrowns: 0 }, { leftType: 'wheat', rightType: 'swamp', leftCrowns: 1, rightCrowns: 0 }, { leftType: 'wheat', rightType: 'mine', leftCrowns: 1, rightCrowns: 0 }, { leftType: 'forest', rightType: 'wheat', leftCrowns: 1, rightCrowns: 0 }, { leftType: 'forest', rightType: 'wheat', leftCrowns: 1, rightCrowns: 0 }, // Tiles 25-32: Lake { leftType: 'forest', rightType: 'wheat', leftCrowns: 1, rightCrowns: 0 }, { leftType: 'forest', rightType: 'wheat', leftCrowns: 1, rightCrowns: 0 }, { leftType: 'forest', rightType: 'lake', leftCrowns: 1, rightCrowns: 0 }, { leftType: 'forest', rightType: 'grassland', leftCrowns: 1, rightCrowns: 0 }, { leftType: 'lake', rightType: 'wheat', leftCrowns: 1, rightCrowns: 0 }, { leftType: 'lake', rightType: 'wheat', leftCrowns: 1, rightCrowns: 0 }, { leftType: 'lake', rightType: 'forest', leftCrowns: 1, rightCrowns: 0 }, { leftType: 'lake', rightType: 'forest', leftCrowns: 1, rightCrowns: 0 }, // Tiles 33-40: Swamp and Mine { leftType: 'lake', rightType: 'forest', leftCrowns: 1, rightCrowns: 0 }, { leftType: 'lake', rightType: 'forest', leftCrowns: 1, rightCrowns: 0 }, { leftType: 'wheat', rightType: 'grassland', leftCrowns: 0, rightCrowns: 1 }, { leftType: 'lake', rightType: 'grassland', leftCrowns: 0, rightCrowns: 1 }, { leftType: 'wheat', rightType: 'swamp', leftCrowns: 0, rightCrowns: 1 }, { leftType: 'grassland', rightType: 'swamp', leftCrowns: 0, rightCrowns: 1 }, { leftType: 'mine', rightType: 'wheat', leftCrowns: 1, rightCrowns: 0 }, { leftType: 'wheat', rightType: 'grassland', leftCrowns: 0, rightCrowns: 2 }, // Tiles 41-48: Crown tiles { leftType: 'lake', rightType: 'grassland', leftCrowns: 0, rightCrowns: 2 }, { leftType: 'wheat', rightType: 'swamp', leftCrowns: 0, rightCrowns: 2 }, { leftType: 'grassland', rightType: 'swamp', leftCrowns: 0, rightCrowns: 2 }, { leftType: 'mine', rightType: 'wheat', leftCrowns: 2, rightCrowns: 0 }, { leftType: 'swamp', rightType: 'mine', leftCrowns: 0, rightCrowns: 2 }, { leftType: 'swamp', rightType: 'mine', leftCrowns: 0, rightCrowns: 2 }, { leftType: 'wheat', rightType: 'mine', leftCrowns: 0, rightCrowns: 3 }]; // Create shuffled deck var shuffledIndices = []; for (var i = 0; i < 48; i++) { shuffledIndices.push(i); } // Shuffle the indices for (var i = shuffledIndices.length - 1; i > 0; i--) { var j = Math.floor(Math.random() * (i + 1)); var temp = shuffledIndices[i]; shuffledIndices[i] = shuffledIndices[j]; shuffledIndices[j] = temp; } // Create tileDeck with shuffled order and original tile numbers for (var i = 0; i < 48; i++) { var data = tileData[shuffledIndices[i]]; tileDeck.push({ leftType: data.leftType, rightType: data.rightType, leftCrowns: data.leftCrowns, rightCrowns: data.rightCrowns, number: shuffledIndices[i] + 1 // Use the original tile number from shuffled deck }); } } // Initialize kingdoms function initializeKingdoms() { for (var i = 0; i < 4; i++) { var kingdom = new Kingdom(i); kingdoms.push(kingdom); // Position kingdoms around the screen if (i === 0) { // Human player - right side bottom kingdom.x = 1360 - 30 + 15 + 5 + 3 + 3 + 3 + 3; kingdom.y = 1800; // Bottom position kingdom.scaleX = 1.0; kingdom.scaleY = 1.0; // Add background for kingdom var kingdomBg = game.addChild(LK.getAsset('kingdomBackground', { x: kingdom.x + 312, y: kingdom.y + 312, anchorX: 0.5, anchorY: 0.5 })); game.addChild(kingdom); // Add wall above kingdom var wall = game.addChild(LK.getAsset('wall', { x: kingdom.x, y: kingdom.y - 165, anchorX: 0, anchorY: 0 })); // Add player label below kingdom var playerLabel = new Text2('YOUR KINGDOM', { size: 40, fill: 0x000000 }); playerLabel.anchor.set(0.5, 0); playerLabel.x = kingdom.x + 312; playerLabel.y = kingdom.y + 625; // Below kingdom game.addChild(playerLabel); } else if (i === 1) { // AI 1 - left side top kingdom.x = 50; kingdom.y = 700; // Top position kingdom.scaleX = 1.0; kingdom.scaleY = 1.0; // Add background for kingdom var kingdomBg = game.addChild(LK.getAsset('kingdomBackground', { x: kingdom.x + 312, y: kingdom.y + 312, anchorX: 0.5, anchorY: 0.5 })); game.addChild(kingdom); // Add wall above kingdom var wall = game.addChild(LK.getAsset('wall', { x: kingdom.x, y: kingdom.y - 165, anchorX: 0, anchorY: 0 })); // Add player label var playerLabel = new Text2('AI PLAYER 1', { size: 40, fill: 0x000000 }); playerLabel.anchor.set(0.5, 0); playerLabel.x = kingdom.x + 312; playerLabel.y = kingdom.y + 625; // Below kingdom game.addChild(playerLabel); } else if (i === 2) { // AI 2 - right side top kingdom.x = 1360 - 30 + 15 + 5 + 3 + 3 + 3 + 3; kingdom.y = 700; // Top position kingdom.scaleX = 1.0; kingdom.scaleY = 1.0; // Add background for kingdom var kingdomBg = game.addChild(LK.getAsset('kingdomBackground', { x: kingdom.x + 312, y: kingdom.y + 312, anchorX: 0.5, anchorY: 0.5 })); game.addChild(kingdom); // Add wall above kingdom var wall = game.addChild(LK.getAsset('wall', { x: kingdom.x, y: kingdom.y - 165, anchorX: 0, anchorY: 0 })); // Add player label var playerLabel = new Text2('AI PLAYER 2', { size: 40, fill: 0x000000 }); playerLabel.anchor.set(0.5, 0); playerLabel.x = kingdom.x + 312; playerLabel.y = kingdom.y + 625; // Below kingdom game.addChild(playerLabel); } else if (i === 3) { // AI 3 - left side bottom kingdom.x = 50; kingdom.y = 1800; // Bottom position kingdom.scaleX = 1.0; kingdom.scaleY = 1.0; // Add background for kingdom var kingdomBg = game.addChild(LK.getAsset('kingdomBackground', { x: kingdom.x + 312, y: kingdom.y + 312, anchorX: 0.5, anchorY: 0.5 })); game.addChild(kingdom); // Add wall above kingdom var wall = game.addChild(LK.getAsset('wall', { x: kingdom.x, y: kingdom.y - 165, anchorX: 0, anchorY: 0 })); // Add player label var playerLabel = new Text2('AI PLAYER 3', { size: 40, fill: 0x000000 }); playerLabel.anchor.set(0.5, 0); playerLabel.x = kingdom.x + 312; playerLabel.y = kingdom.y + 625; // Below kingdom game.addChild(playerLabel); } } } // Draw current tiles function drawCurrentTiles() { // Clear existing tiles for (var i = 0; i < currentTiles.length; i++) { if (currentTiles[i].parent) { currentTiles[i].parent.removeChild(currentTiles[i]); } // Also remove the global number text if (currentTiles[i].globalNumberText && currentTiles[i].globalNumberText.parent) { currentTiles[i].globalNumberText.parent.removeChild(currentTiles[i].globalNumberText); } } currentTiles = []; // Add background for tile selection area var tilesBackground = game.addChild(LK.getAsset('tilesBackground', { x: 1024, y: 1375, anchorX: 0.5, anchorY: 0.5 })); // Send background to back but in front of game background game.addChildAt(tilesBackground, 1); // Get 4 tiles from deck var tilesToShow = []; for (var i = 0; i < 4; i++) { if (tileDeck.length > 0) { tilesToShow.push(tileDeck.shift()); } } // Sort tiles by their original number (lowest to highest) tilesToShow.sort(function (a, b) { return a.number - b.number; }); // Draw sorted tiles in a column centered on screen for (var i = 0; i < tilesToShow.length; i++) { var tileData = tilesToShow[i]; var tile = new GameTile(tileData.leftType, tileData.rightType, tileData.leftCrowns, tileData.rightCrowns, tileData.number); tile.x = 1024; // Center horizontally (screen width / 2) tile.y = 1041 + i * 220; // Position cards moved up by 125 pixels from original position currentTiles.push(tile); game.addChild(tile); // Add global tile number below the tile (showing the actual shuffled tile number) var globalNumberText = new Text2(tileData.number.toString(), { size: 40, fill: 0x000000 }); globalNumberText.anchor.set(0.5, 0); globalNumberText.x = tile.x; globalNumberText.y = tile.y + 80; // Position below the tile game.addChild(globalNumberText); // Store reference to remove it later tile.globalNumberText = globalNumberText; } } // Select tile function selectTile(tile) { if (gameState !== 'selectTile' || currentPlayer !== 0) { return; } if (selectedTile) { selectedTile.setSelected(false); } selectedTile = tile; tile.setSelected(true); gameState = 'placeTile'; updateTurnOrderDisplay(); instructionTxt.setText('Click to place tile on your kingdom'); LK.getSound('selectSound').play(); } // AI turn function aiTurn() { if (currentPlayer === 0) { return; } // Prevent user interaction during AI turn gameState = 'aiTurn'; updateTurnOrderDisplay(); // AI selects random available tile var availableTiles = []; for (var i = 0; i < currentTiles.length; i++) { if (!currentTiles[i].selected) { availableTiles.push(currentTiles[i]); } } if (availableTiles.length > 0) { var randomTile = availableTiles[Math.floor(Math.random() * availableTiles.length)]; selectedTile = randomTile; randomTile.setSelected(true); // Mark tile as owned by current AI player to prevent user interaction randomTile.ownerPlayer = currentPlayer; instructionTxt.setText('AI Player ' + currentPlayer + ' selecting tile...'); LK.getSound('selectSound').play(); // Delay before placing tile LK.setTimeout(function () { // AI places tile with smart priority: comprehensively check for 2-matching terrain connections first var kingdom = kingdoms[currentPlayer]; var placed = false; var bestPlacements = []; // First pass: Systematically check ALL positions and rotations for 2-matching terrain connections for (var row = 0; row < 5 && !placed; row++) { for (var col = 0; col < 5 && !placed; col++) { for (var rot = 0; rot < 4 && !placed; rot++) { // Set rotation internally without visual update var originalRotation = selectedTile.currentRotationAngle; selectedTile.currentRotationAngle = rot * 90; if (kingdom.canPlaceTile(selectedTile, row, col)) { // Check if this placement has 2 matching terrain connections var positions = kingdom.getTilePositions(selectedTile, row, col); if (positions) { var matchingConnections = 0; var castleConnections = 0; for (var p = 0; p < positions.length; p++) { var r = positions[p][0]; var c = positions[p][1]; var directions = [[-1, 0], [1, 0], [0, -1], [0, 1]]; for (var d = 0; d < directions.length; d++) { var nr = r + directions[d][0]; var nc = c + directions[d][1]; if (nr >= 0 && nr < 5 && nc >= 0 && nc < 5 && kingdom.grid[nr][nc] !== null) { if (kingdom.grid[nr][nc].type === 'castle') { castleConnections++; } else { // Check if terrain matches (not castle) var terrainIndex = p; var tileType = terrainIndex === 0 ? selectedTile.leftType : selectedTile.rightType; if (kingdom.grid[nr][nc].type === tileType) { matchingConnections++; } } } } } // Store placement info for later evaluation bestPlacements.push({ row: row, col: col, rotation: rot * 90, matchingConnections: matchingConnections, castleConnections: castleConnections, totalConnections: matchingConnections + castleConnections }); } } // Restore original rotation selectedTile.currentRotationAngle = originalRotation; } } } // Sort placements: prioritize terrain matches over castle connections bestPlacements.sort(function (a, b) { // First priority: 2+ matching terrain connections if (a.matchingConnections >= 2 && b.matchingConnections < 2) { return -1; } if (b.matchingConnections >= 2 && a.matchingConnections < 2) { return 1; } // Second priority: more terrain matches if (a.matchingConnections !== b.matchingConnections) { return b.matchingConnections - a.matchingConnections; } // Third priority: castle connections only if no terrain matches if (a.matchingConnections === 0 && b.matchingConnections === 0) { return b.castleConnections - a.castleConnections; } // Fourth priority: total connections return b.totalConnections - a.totalConnections; }); // Place the tile using the best placement found if (bestPlacements.length > 0) { var bestPlacement = bestPlacements[0]; selectedTile.currentRotationAngle = bestPlacement.rotation; selectedTile.updateTileVisuals(); kingdom.placeTile(selectedTile, bestPlacement.row, bestPlacement.col); placed = true; } // If tile couldn't be placed, try moving kingdom if (!placed) { var directions = ['up', 'down', 'left', 'right']; for (var d = 0; d < directions.length && !placed; d++) { if (kingdom.canMoveKingdom(directions[d])) { var oldHasMoved = kingdom.hasMoved; kingdom.moveKingdom(directions[d]); if (!oldHasMoved) { kingdom.score = Math.max(0, kingdom.calculateScore() - 10); } updateAIScoresDisplay(); // Try placing again after movement for (var attempts2 = 0; attempts2 < 100 && !placed; attempts2++) { var row = Math.floor(Math.random() * 5); var col = Math.floor(Math.random() * 4); for (var rot = 0; rot < 4 && !placed; rot++) { var originalRotation = selectedTile.currentRotationAngle; selectedTile.currentRotationAngle = rot * 90; if (kingdom.canPlaceTile(selectedTile, row, col)) { selectedTile.updateTileVisuals(); kingdom.placeTile(selectedTile, row, col); placed = true; } else { selectedTile.currentRotationAngle = originalRotation; } } } } } } if (placed) { updateAIScoresDisplay(); selectedTiles.push({ tile: selectedTile, player: currentPlayer }); // Remove tile from display selectedTile.parent.removeChild(selectedTile); // Also remove the global number text if (selectedTile.globalNumberText && selectedTile.globalNumberText.parent) { selectedTile.globalNumberText.parent.removeChild(selectedTile.globalNumberText); } selectedTile = null; LK.getSound('placeSound').play(); } else { // AI couldn't place tile even after trying to move, trash it kingdom.score = Math.max(0, kingdom.calculateScore() - 5); updateAIScoresDisplay(); selectedTiles.push({ tile: selectedTile, player: currentPlayer }); selectedTile.parent.removeChild(selectedTile); if (selectedTile.globalNumberText && selectedTile.globalNumberText.parent) { selectedTile.globalNumberText.parent.removeChild(selectedTile.globalNumberText); } selectedTile = null; LK.getSound('placeSound').play(); } instructionTxt.setText('AI Player ' + currentPlayer + ' placed tile'); LK.setTimeout(function () { nextPlayer(); }, 1000); }, 1000); } } // Next player function nextPlayer() { // Check if all 4 players have selected tiles in this round if (selectedTiles.length === 4) { // All players finished, start new round round++; if (round > maxRounds) { endGame(); return; } // Update turn order based on selected tiles selectedTiles.sort(function (a, b) { return a.tile.number - b.tile.number; }); turnOrder = []; for (var i = 0; i < selectedTiles.length; i++) { turnOrder.push(selectedTiles[i].player); } selectedTiles = []; currentPlayer = turnOrder[0]; drawCurrentTiles(); scoreTxt.setText('Round: ' + round); updateTurnOrderDisplay(); if (currentPlayer === 0) { gameState = 'selectTile'; instructionTxt.setText('Select a tile'); } else { LK.setTimeout(aiTurn, 500); } } else { // Move to next player in current round var currentTurnIndex = turnOrder.indexOf(currentPlayer); var nextTurnIndex = (currentTurnIndex + 1) % 4; currentPlayer = turnOrder[nextTurnIndex]; updateTurnOrderDisplay(); if (currentPlayer !== 0) { LK.setTimeout(aiTurn, 500); } else { gameState = 'selectTile'; instructionTxt.setText('Select a tile'); } } } // End game function endGame() { gameState = 'gameOver'; // Calculate final scores var finalScores = []; for (var i = 0; i < kingdoms.length; i++) { // Use stored score for human player (includes penalties), calculate for AI var finalScore = i === 0 ? kingdoms[i].score : kingdoms[i].calculateScore(); finalScores.push({ player: i, score: finalScore }); } finalScores.sort(function (a, b) { return b.score - a.score; }); var playerRank = 1; for (var i = 0; i < finalScores.length; i++) { if (finalScores[i].player === 0) { playerRank = i + 1; break; } } // Show results window first showResultsWindow(finalScores, playerRank); } // Kingdom click handler function handleKingdomClick(x, y) { if (gameState !== 'placeTile' || currentPlayer !== 0 || !selectedTile) { return; } var kingdom = kingdoms[0]; // Convert click coordinates to kingdom local coordinates // Account for kingdom position offset var relativeX = x - kingdom.x; var relativeY = y - kingdom.y; // Calculate grid position based on cell size (125px) var row = Math.floor(relativeY / 125); var col = Math.floor(relativeX / 125); // Ensure coordinates are within valid bounds if (row < 0 || row >= 5 || col < 0 || col >= 5) { return; } // For horizontal tiles, ensure there's space for both cells if ((selectedTile.currentRotationAngle === 0 || selectedTile.currentRotationAngle === 180) && col >= 4) { col = 3; // Ensure tile fits horizontally } // For vertical tiles, ensure there's space for both cells if ((selectedTile.currentRotationAngle === 90 || selectedTile.currentRotationAngle === 270) && row >= 4) { row = 3; // Ensure tile fits vertically } if (kingdom.canPlaceTile(selectedTile, row, col)) { kingdom.placeTile(selectedTile, row, col); selectedTiles.push({ tile: selectedTile, player: currentPlayer }); // Remove tile from game selectedTile.parent.removeChild(selectedTile); // Also remove the global number text if (selectedTile.globalNumberText && selectedTile.globalNumberText.parent) { selectedTile.globalNumberText.parent.removeChild(selectedTile.globalNumberText); } selectedTile = null; LK.getSound('placeSound').play(); gameState = 'waitingForOthers'; instructionTxt.setText('Wait for other players...'); // Update score playerScoreTxt.setText('Your Score: ' + kingdom.calculateScore()); nextPlayer(); } } // Game move handler for dragging game.move = function (x, y, obj) { if (draggedTile && draggedTile.isDragging) { draggedTile.x = x; draggedTile.y = y; } }; // Game up handler for dropping tiles game.up = function (x, y, obj) { if (draggedTile && draggedTile.isDragging) { draggedTile.isDragging = false; // Try to place tile on kingdom handleKingdomClick(x, y); draggedTile = null; } }; // Movement button handlers moveUpBtn.down = function () { if (currentPlayer === 0 && (gameState === 'selectTile' || gameState === 'placeTile')) { var kingdom = kingdoms[0]; if (kingdom.canMoveKingdom('up')) { kingdom.moveKingdom('up'); if (!hasMovedKingdom) { kingdom.score = Math.max(0, kingdom.calculateScore() - 10); hasMovedKingdom = true; } else { kingdom.score = kingdom.calculateScore(); } playerScoreTxt.setText('Your Score: ' + kingdom.score); LK.getSound('selectSound').play(); } } }; moveDownBtn.down = function () { if (currentPlayer === 0 && (gameState === 'selectTile' || gameState === 'placeTile')) { var kingdom = kingdoms[0]; if (kingdom.canMoveKingdom('down')) { kingdom.moveKingdom('down'); if (!hasMovedKingdom) { kingdom.score = Math.max(0, kingdom.calculateScore() - 10); hasMovedKingdom = true; } else { kingdom.score = kingdom.calculateScore(); } playerScoreTxt.setText('Your Score: ' + kingdom.score); LK.getSound('selectSound').play(); } } }; moveLeftBtn.down = function () { if (currentPlayer === 0 && (gameState === 'selectTile' || gameState === 'placeTile')) { var kingdom = kingdoms[0]; if (kingdom.canMoveKingdom('left')) { kingdom.moveKingdom('left'); if (!hasMovedKingdom) { kingdom.score = Math.max(0, kingdom.calculateScore() - 10); hasMovedKingdom = true; } else { kingdom.score = kingdom.calculateScore(); } playerScoreTxt.setText('Your Score: ' + kingdom.score); LK.getSound('selectSound').play(); } } }; moveRightBtn.down = function () { if (currentPlayer === 0 && (gameState === 'selectTile' || gameState === 'placeTile')) { var kingdom = kingdoms[0]; if (kingdom.canMoveKingdom('right')) { kingdom.moveKingdom('right'); if (!hasMovedKingdom) { kingdom.score = Math.max(0, kingdom.calculateScore() - 10); hasMovedKingdom = true; } else { kingdom.score = kingdom.calculateScore(); } playerScoreTxt.setText('Your Score: ' + kingdom.score); LK.getSound('selectSound').play(); } } }; // Trash button handler trashBtn.down = function () { if (currentPlayer === 0 && gameState === 'placeTile' && selectedTile) { // Remove tile and deduct points only if first time using trash var kingdom = kingdoms[0]; if (!hasUsedTrash) { kingdom.score = Math.max(0, kingdom.calculateScore() - 5); hasUsedTrash = true; } else { // No penalty for subsequent trash uses kingdom.score = kingdom.calculateScore(); } playerScoreTxt.setText('Your Score: ' + kingdom.score); // Remove tile from display selectedTile.parent.removeChild(selectedTile); if (selectedTile.globalNumberText && selectedTile.globalNumberText.parent) { selectedTile.globalNumberText.parent.removeChild(selectedTile.globalNumberText); } selectedTiles.push({ tile: selectedTile, player: currentPlayer }); selectedTile = null; LK.getSound('placeSound').play(); gameState = 'waitingForOthers'; instructionTxt.setText('Wait for other players...'); nextPlayer(); } }; // Global rotation button handler globalRotateBtn.down = function () { if (currentPlayer === 0 && gameState === 'placeTile' && selectedTile) { selectedTile.rotateTile(); LK.getSound('selectSound').play(); } }; // Game event handlers game.down = function (x, y, obj) { if (gameState === 'placeTile' && currentPlayer === 0 && !draggedTile) { handleKingdomClick(x, y); } }; game.update = function () { // Game update logic handled by event system and timeouts }; // Show results window with final scores function showResultsWindow(finalScores, playerRank) { // Create results overlay var resultsOverlay = game.addChild(LK.getAsset('kingdomBackground', { x: 1024, y: 1366, anchorX: 0.5, anchorY: 0.5, scaleX: 2.5, scaleY: 3 })); resultsOverlay.alpha = 0.95; resultsOverlay.tint = 0x000000; // Results title var resultsTitle = game.addChild(new Text2('FINAL RESULTS', { size: 80, fill: 0xFFD700 })); resultsTitle.anchor.set(0.5, 0.5); resultsTitle.x = 1024; resultsTitle.y = 600; // Display scores var playerNames = ['YOU', 'AI PLAYER 1', 'AI PLAYER 2', 'AI PLAYER 3']; for (var i = 0; i < finalScores.length; i++) { var rank = i + 1; var playerIndex = finalScores[i].player; var score = finalScores[i].score; var playerName = playerNames[playerIndex]; var rankText = game.addChild(new Text2(rank + '. ' + playerName + ': ' + score, { size: 60, fill: rank === 1 ? 0xFFD700 : playerIndex === 0 ? 0x00FF00 : 0xFFFFFF })); rankText.anchor.set(0.5, 0.5); rankText.x = 1024; rankText.y = 800 + i * 80; } // Continue button var continueButton = game.addChild(new Text2('TAP TO CONTINUE', { size: 50, fill: 0x00FF00 })); continueButton.anchor.set(0.5, 0.5); continueButton.x = 1024; continueButton.y = 1400; // Pulsing animation for continue button var pulseScale = 1.0; var pulseDirection = 1; var resultsUpdateHandler = function resultsUpdateHandler() { pulseScale += pulseDirection * 0.02; if (pulseScale > 1.2) { pulseScale = 1.2; pulseDirection = -1; } else if (pulseScale < 1.0) { pulseScale = 1.0; pulseDirection = 1; } continueButton.scaleX = pulseScale; continueButton.scaleY = pulseScale; }; // Click handler for continue button var resultsClickHandler = function resultsClickHandler(x, y, obj) { // Remove results window game.removeChild(resultsOverlay); game.removeChild(resultsTitle); for (var i = 0; i < finalScores.length; i++) { var rankText = game.children[game.children.length - 1]; if (rankText && rankText.setText) { game.removeChild(rankText); } } game.removeChild(continueButton); // Remove event handlers game.update = originalGameUpdate; game.down = originalGameDown; // Show appropriate end screen if (playerRank === 1) { LK.showYouWin(); } else { LK.showGameOver(); } }; // Store original handlers var originalGameUpdate = game.update; var originalGameDown = game.down; // Override game handlers for results window game.update = resultsUpdateHandler; game.down = resultsClickHandler; } // Function to start the actual game function startGame() { if (startScreen) { game.removeChild(startScreen); startScreen = null; } showingStartScreen = false; // Reset penalty flags for new game hasUsedTrash = false; hasMovedKingdom = false; // Show score displays now that game is starting aiScoresContainer.alpha = 1; playerScoreTxt.alpha = 1; // Initialize game initializeTileDeck(); initializeKingdoms(); drawCurrentTiles(); // Start with human player gameState = 'selectTile'; updateTurnOrderDisplay(); updateAIScoresDisplay(); instructionTxt.setText('Select a tile'); } // Show start screen initially if (showingStartScreen) { startScreen = new StartScreen(); game.addChild(startScreen); }
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var GameTile = Container.expand(function (leftType, rightType, leftCrowns, rightCrowns, number) {
var self = Container.call(this);
self.leftType = leftType;
self.rightType = rightType;
self.leftCrowns = leftCrowns;
self.rightCrowns = rightCrowns;
self.number = number;
self.selected = false;
self.rotation = 0; // 0, 90, 180, 270 degrees
self.currentRotationAngle = 0; // Track rotation angle in degrees
self.isDragging = false;
self.ownerPlayer = null; // Track which player owns this tile
// Create tile background
var bg = self.addChild(LK.getAsset('tileSlot', {
anchorX: 0.5,
anchorY: 0.5
}));
// Create terrain sections
var leftTerrain = self.addChild(LK.getAsset(leftType, {
x: -60,
y: 0,
anchorX: 0.5,
anchorY: 0.5
}));
var rightTerrain = self.addChild(LK.getAsset(rightType, {
x: 60,
y: 0,
anchorX: 0.5,
anchorY: 0.5
}));
// Add crowns
for (var i = 0; i < leftCrowns; i++) {
self.addChild(LK.getAsset('crown', {
x: -60 - 35 + i * 15,
y: -35,
anchorX: 0.5,
anchorY: 0.5
}));
}
for (var i = 0; i < rightCrowns; i++) {
self.addChild(LK.getAsset('crown', {
x: 60 - 35 + i * 15,
y: -35,
anchorX: 0.5,
anchorY: 0.5
}));
}
// Remove the number display from here as it's handled in drawCurrentTiles
// Add rotation button (only visible when selected)
var rotateBtn = self.addChild(new Text2('↻', {
size: 30,
fill: 0x00FF00
}));
rotateBtn.anchor.set(0.5, 0.5);
rotateBtn.x = 100;
rotateBtn.y = -50;
rotateBtn.alpha = 0;
self.rotateBtn = rotateBtn;
// Store original terrain references for rotation
self.leftTerrain = leftTerrain;
self.rightTerrain = rightTerrain;
self.rotateTile = function () {
self.currentRotationAngle = (self.currentRotationAngle + 90) % 360;
self.rotation = self.currentRotationAngle * Math.PI / 180;
};
self.updateTileVisuals = function () {
// Normalize rotation angle to 0, 90, 180, or 270 degrees
self.currentRotationAngle = (self.currentRotationAngle % 360 + 360) % 360;
if (self.currentRotationAngle % 90 !== 0) {
self.currentRotationAngle = Math.round(self.currentRotationAngle / 90) * 90;
}
// Set Container rotation based on angle
self.rotation = self.currentRotationAngle * Math.PI / 180;
};
self.setSelected = function (selected) {
self.selected = selected;
if (selected) {
if (!self.selectedBg) {
self.selectedBg = self.addChildAt(LK.getAsset('selectedTile', {
anchorX: 0.5,
anchorY: 0.5
}), 0);
}
self.rotateBtn.alpha = 1;
} else {
if (self.selectedBg) {
self.removeChild(self.selectedBg);
self.selectedBg = null;
}
self.rotateBtn.alpha = 0;
}
};
self.down = function (x, y, obj) {
// Prevent interaction if tile is owned by AI player or during AI turn
if (self.ownerPlayer && self.ownerPlayer !== 0) {
return;
}
if (gameState === 'aiTurn') {
return;
}
if (gameState === 'selectTile' && currentPlayer === 0) {
selectTile(self);
} else if (gameState === 'placeTile' && currentPlayer === 0 && self.selected) {
// Check if clicked on rotation button using local coordinates directly
if (x > 85 && x < 115 && y > -65 && y < -35) {
self.rotateTile();
LK.getSound('selectSound').play();
} else {
// Start dragging
self.isDragging = true;
draggedTile = self;
}
}
};
return self;
});
var Kingdom = Container.expand(function (playerIndex) {
var self = Container.call(this);
self.playerIndex = playerIndex;
self.grid = [];
self.score = 0;
self.hasMoved = false; // Track if player has moved kingdom
// Initialize 5x5 grid
for (var i = 0; i < 5; i++) {
self.grid[i] = [];
for (var j = 0; j < 5; j++) {
self.grid[i][j] = null;
}
}
// Place castle at center
self.grid[2][2] = {
type: 'castle',
crowns: 0
};
// Draw kingdom grid
self.drawKingdom = function () {
// Clear existing visuals
for (var i = self.children.length - 1; i >= 0; i--) {
self.removeChild(self.children[i]);
}
for (var i = 0; i < 5; i++) {
for (var j = 0; j < 5; j++) {
var cell = self.addChild(LK.getAsset('kingdomCell', {
x: j * 125,
y: i * 125,
anchorX: 0,
anchorY: 0
}));
if (self.grid[i][j]) {
var terrain = self.addChild(LK.getAsset(self.grid[i][j].type, {
x: j * 125 + 62.5,
y: i * 125 + 62.5,
anchorX: 0.5,
anchorY: 0.5
}));
// Add crowns if present
for (var c = 0; c < self.grid[i][j].crowns; c++) {
var crown = self.addChild(LK.getAsset('crown', {
x: j * 125 + 62.5 - 35 + c * 15,
y: i * 125 + 35,
anchorX: 0.5,
anchorY: 0.5
}));
}
}
}
}
};
self.canPlaceTile = function (tile, row, col) {
// Check if positions are valid and empty based on rotation
var positions = self.getTilePositions(tile, row, col);
if (!positions) {
return false;
}
if (self.grid[positions[0][0]][positions[0][1]] !== null || self.grid[positions[1][0]][positions[1][1]] !== null) {
return false;
}
// Check if adjacent to existing kingdom
var adjacent = false;
for (var p = 0; p < positions.length; p++) {
var r = positions[p][0];
var c = positions[p][1];
// Check all 4 directions
var directions = [[-1, 0], [1, 0], [0, -1], [0, 1]];
for (var d = 0; d < directions.length; d++) {
var nr = r + directions[d][0];
var nc = c + directions[d][1];
if (nr >= 0 && nr < 5 && nc >= 0 && nc < 5 && self.grid[nr][nc] !== null) {
adjacent = true;
break;
}
}
if (adjacent) {
break;
}
}
if (!adjacent) {
return false;
}
// Check terrain matching - need at least one matching adjacent terrain
var validConnections = 0;
for (var p = 0; p < positions.length; p++) {
var r = positions[p][0];
var c = positions[p][1];
var directions = [[-1, 0], [1, 0], [0, -1], [0, 1]];
for (var d = 0; d < directions.length; d++) {
var nr = r + directions[d][0];
var nc = c + directions[d][1];
if (nr >= 0 && nr < 5 && nc >= 0 && nc < 5 && self.grid[nr][nc] !== null) {
if (self.grid[nr][nc].type === 'castle') {
// Castle connection is always valid - everything matches castle
validConnections++;
} else {
// Check if terrain matches
var terrainIndex = p;
var tileType = terrainIndex === 0 ? tile.leftType : tile.rightType;
if (self.grid[nr][nc].type === tileType) {
validConnections++;
}
}
}
}
}
return validConnections >= 1;
};
self.getTilePositions = function (tile, row, col) {
var positions;
if (tile.currentRotationAngle === 0) {
// Horizontal: left-right
if (col >= 4) {
return null;
}
positions = [[row, col], [row, col + 1]];
} else if (tile.currentRotationAngle === 90) {
// Vertical: top-bottom
if (row >= 4) {
return null;
}
positions = [[row, col], [row + 1, col]];
} else if (tile.currentRotationAngle === 180) {
// Horizontal: right-left
if (col >= 4) {
return null;
}
positions = [[row, col + 1], [row, col]];
} else {
// 270
// Vertical: bottom-top
if (row >= 4) {
return null;
}
positions = [[row + 1, col], [row, col]];
}
// Check bounds
for (var i = 0; i < positions.length; i++) {
if (positions[i][0] < 0 || positions[i][0] >= 5 || positions[i][1] < 0 || positions[i][1] >= 5) {
return null;
}
}
return positions;
};
self.placeTile = function (tile, row, col) {
var positions = self.getTilePositions(tile, row, col);
if (!positions) {
return false;
}
// Place based on rotation
if (tile.currentRotationAngle === 0 || tile.currentRotationAngle === 180) {
// Horizontal placement
self.grid[positions[0][0]][positions[0][1]] = {
type: tile.leftType,
crowns: tile.leftCrowns
};
self.grid[positions[1][0]][positions[1][1]] = {
type: tile.rightType,
crowns: tile.rightCrowns
};
} else {
// Vertical placement
self.grid[positions[0][0]][positions[0][1]] = {
type: tile.leftType,
crowns: tile.leftCrowns
};
self.grid[positions[1][0]][positions[1][1]] = {
type: tile.rightType,
crowns: tile.rightCrowns
};
}
self.drawKingdom();
return true;
};
self.calculateScore = function () {
var visited = [];
var totalScore = 0;
for (var i = 0; i < 5; i++) {
visited[i] = [];
for (var j = 0; j < 5; j++) {
visited[i][j] = false;
}
}
for (var i = 0; i < 5; i++) {
for (var j = 0; j < 5; j++) {
if (!visited[i][j] && self.grid[i][j] && self.grid[i][j].type !== 'castle') {
var result = self.floodFill(i, j, self.grid[i][j].type, visited);
totalScore += result.size * result.crowns;
}
}
}
self.score = totalScore;
return totalScore;
};
self.floodFill = function (row, col, terrainType, visited) {
if (row < 0 || row >= 5 || col < 0 || col >= 5) {
return {
size: 0,
crowns: 0
};
}
if (visited[row][col]) {
return {
size: 0,
crowns: 0
};
}
if (!self.grid[row][col] || self.grid[row][col].type !== terrainType) {
return {
size: 0,
crowns: 0
};
}
visited[row][col] = true;
var size = 1;
var crowns = self.grid[row][col].crowns;
var directions = [[-1, 0], [1, 0], [0, -1], [0, 1]];
for (var d = 0; d < directions.length; d++) {
var result = self.floodFill(row + directions[d][0], col + directions[d][1], terrainType, visited);
size += result.size;
crowns += result.crowns;
}
return {
size: size,
crowns: crowns
};
};
// Check if kingdom can be moved in a direction
self.canMoveKingdom = function (direction) {
// Find bounds of current kingdom
var minRow = 5,
maxRow = -1,
minCol = 5,
maxCol = -1;
for (var i = 0; i < 5; i++) {
for (var j = 0; j < 5; j++) {
if (self.grid[i][j] !== null) {
minRow = Math.min(minRow, i);
maxRow = Math.max(maxRow, i);
minCol = Math.min(minCol, j);
maxCol = Math.max(maxCol, j);
}
}
}
// Check if movement is possible
if (direction === 'up' && minRow <= 0) {
return false;
}
if (direction === 'down' && maxRow >= 4) {
return false;
}
if (direction === 'left' && minCol <= 0) {
return false;
}
if (direction === 'right' && maxCol >= 4) {
return false;
}
return true;
};
// Move entire kingdom in a direction
self.moveKingdom = function (direction) {
if (!self.canMoveKingdom(direction)) {
return false;
}
var newGrid = [];
for (var i = 0; i < 5; i++) {
newGrid[i] = [];
for (var j = 0; j < 5; j++) {
newGrid[i][j] = null;
}
}
var deltaRow = 0,
deltaCol = 0;
if (direction === 'up') {
deltaRow = -1;
}
if (direction === 'down') {
deltaRow = 1;
}
if (direction === 'left') {
deltaCol = -1;
}
if (direction === 'right') {
deltaCol = 1;
}
// Move all tiles
for (var i = 0; i < 5; i++) {
for (var j = 0; j < 5; j++) {
if (self.grid[i][j] !== null) {
var newRow = i + deltaRow;
var newCol = j + deltaCol;
if (newRow >= 0 && newRow < 5 && newCol >= 0 && newCol < 5) {
newGrid[newRow][newCol] = self.grid[i][j];
}
}
}
}
self.grid = newGrid;
self.drawKingdom();
self.hasMoved = true; // Mark that kingdom has been moved
return true;
};
self.drawKingdom();
return self;
});
var StartScreen = Container.expand(function () {
var self = Container.call(this);
// Create background overlay
var overlay = self.addChild(LK.getAsset('kingdomBackground', {
x: 1024,
y: 1366,
anchorX: 0.5,
anchorY: 0.5,
scaleX: 3,
scaleY: 4
}));
overlay.alpha = 0.95;
overlay.tint = 0x000000;
// Game title
var titleText = self.addChild(new Text2('KINGDOMINO', {
size: 80,
fill: 0xFFD700
}));
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
titleText.y = 300;
// Instructions text
var instructionsText = self.addChild(new Text2('HOW TO PLAY:\n\n• Select a tile each round\n• Click on selected tile or ↻ button to rotate\n• Connect it to your kingdom\n• Castle connections are always valid\n• Other terrains must match at least one side\n• Score = Territory Size × Crown Count\n• Move kingdom for -10 points\n• Trash tile for -5 points', {
size: 45,
fill: 0xFFFFFF
}));
instructionsText.anchor.set(0.5, 0.5);
instructionsText.x = 1024;
instructionsText.y = 800;
// Crown scoring explanation
var crownText = self.addChild(new Text2('CROWN SCORING:\nLarger connected territories\nwith more crowns = higher score!', {
size: 40,
fill: 0xFFD700
}));
crownText.anchor.set(0.5, 0.5);
crownText.x = 1024;
crownText.y = 1200;
// Start button
var startButton = self.addChild(new Text2('TAP TO START', {
size: 60,
fill: 0x00FF00
}));
startButton.anchor.set(0.5, 0.5);
startButton.x = 1024;
startButton.y = 1500;
// Pulsing animation for start button
var pulseScale = 1.0;
var pulseDirection = 1;
self.update = function () {
pulseScale += pulseDirection * 0.02;
if (pulseScale > 1.2) {
pulseScale = 1.2;
pulseDirection = -1;
} else if (pulseScale < 1.0) {
pulseScale = 1.0;
pulseDirection = 1;
}
startButton.scaleX = pulseScale;
startButton.scaleY = pulseScale;
};
self.down = function (x, y, obj) {
// Start the game
startGame();
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2F4F2F
});
/****
* Game Code
****/
// Add game background
var gameBackground = game.addChild(LK.getAsset('gameBoard', {
x: 1024,
y: 1366,
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.28,
scaleY: 1.71
}));
// Send background to the very back
game.addChildAt(gameBackground, 0);
// Game state variables
var showingStartScreen = true;
var startScreen = null;
// Initialize basic game assets
var gameState = 'selectTile'; // 'selectTile', 'placeTile', 'gameOver'
var currentPlayer = 0;
var round = 1;
var maxRounds = 12;
var selectedTile = null;
var draggedTile = null;
var placementRow = -1;
var placementCol = -1;
// Penalty tracking flags
var hasUsedTrash = false;
var hasMovedKingdom = false;
// Player kingdoms
var kingdoms = [];
var players = ['Human', 'AI1', 'AI2', 'AI3'];
var turnOrder = [0, 1, 2, 3];
// Tile deck
var tileDeck = [];
var currentTiles = [];
var selectedTiles = [];
// UI elements
var scoreTxt = new Text2('Round: 1', {
size: 60,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(1, 0);
scoreTxt.x = -120;
scoreTxt.y = 10;
LK.gui.topRight.addChild(scoreTxt);
var playerScoreTxt = new Text2('Your Score: 0', {
size: 60,
fill: 0xFFFFFF
});
playerScoreTxt.anchor.set(0.5, 0);
playerScoreTxt.x = 0;
playerScoreTxt.y = -850;
playerScoreTxt.alpha = 0; // Hide initially
LK.gui.center.addChild(playerScoreTxt);
var instructionTxt = new Text2('Select a tile', {
size: 40,
fill: 0x000000
});
instructionTxt.anchor.set(0.5, 1);
LK.gui.bottom.addChild(instructionTxt);
// AI players score display
var aiScoresContainer = new Container();
aiScoresContainer.x = 0;
aiScoresContainer.y = -750;
aiScoresContainer.alpha = 0; // Hide initially
LK.gui.center.addChild(aiScoresContainer);
var aiScoreTexts = [];
for (var i = 1; i < 4; i++) {
var aiScoreTxt = new Text2('AI ' + i + ' Score: 0', {
size: 50,
fill: 0xFFFFFF
});
aiScoreTxt.anchor.set(0.5, 0);
aiScoreTxt.y = (i - 1) * 45;
aiScoresContainer.addChild(aiScoreTxt);
aiScoreTexts.push(aiScoreTxt);
}
// Function to update AI scores display
function updateAIScoresDisplay() {
for (var i = 1; i < 4; i++) {
var kingdom = kingdoms[i];
var score = kingdom.calculateScore();
if (kingdom.hasMoved) {
score = Math.max(0, score - 10);
}
aiScoreTexts[i - 1].setText('AI ' + i + ' Score: ' + score);
}
}
// Movement control buttons in center of bottom kingdoms
var moveButtonContainer = new Container();
moveButtonContainer.x = 1024; // Center of screen
moveButtonContainer.y = 2450 - 50;
game.addChild(moveButtonContainer);
var moveUpBtn = new Text2('↑', {
size: 50,
fill: 0xFFFFFF
});
moveUpBtn.anchor.set(0.5, 0.5);
moveUpBtn.x = -75;
moveUpBtn.y = 0;
moveButtonContainer.addChild(moveUpBtn);
var moveLeftBtn = new Text2('←', {
size: 50,
fill: 0xFFFFFF
});
moveLeftBtn.anchor.set(0.5, 0.5);
moveLeftBtn.x = -125;
moveLeftBtn.y = 50;
moveButtonContainer.addChild(moveLeftBtn);
var moveRightBtn = new Text2('→', {
size: 50,
fill: 0xFFFFFF
});
moveRightBtn.anchor.set(0.5, 0.5);
moveRightBtn.x = -25;
moveRightBtn.y = 50;
moveButtonContainer.addChild(moveRightBtn);
var moveDownBtn = new Text2('↓', {
size: 50,
fill: 0xFFFFFF
});
moveDownBtn.anchor.set(0.5, 0.5);
moveDownBtn.x = -75;
moveDownBtn.y = 100;
moveButtonContainer.addChild(moveDownBtn);
// Trash button in center
var trashBtn = new Text2('🗑', {
size: 60,
fill: 0xFF0000
});
trashBtn.anchor.set(0.5, 0.5);
trashBtn.x = 1174; // Center of screen area
trashBtn.y = 2500 - 50;
game.addChild(trashBtn);
var trashLabel = new Text2('Trash (-5pts)', {
size: 30,
fill: 0xFFFFFF
});
trashLabel.anchor.set(0.5, 0);
trashLabel.x = 1174;
trashLabel.y = 2540 - 50;
game.addChild(trashLabel);
// Rotation button in center
var globalRotateBtn = new Text2('↻', {
size: 150,
fill: 0x00FF00
});
globalRotateBtn.anchor.set(0.5, 0.5);
globalRotateBtn.x = 934 + 40 + 100 - 40 - 10; // Center of screen area
globalRotateBtn.y = 2350 - 200 - 50;
game.addChild(globalRotateBtn);
var rotateLabel = new Text2('Rotate', {
size: 50,
fill: 0xFFFFFF
});
rotateLabel.anchor.set(0.5, 0);
rotateLabel.x = 934 + 40 + 100 - 40 - 10;
rotateLabel.y = 2410 - 200 - 50;
game.addChild(rotateLabel);
// Movement cost label near movement buttons
var moveCostLabel = new Text2('Move (-10pts)', {
size: 30,
fill: 0xFFFFFF
});
moveCostLabel.anchor.set(0.5, 0);
moveCostLabel.x = 949;
moveCostLabel.y = 2345;
game.addChild(moveCostLabel);
// Turn order display
var turnOrderContainer = new Container();
turnOrderContainer.x = -200;
turnOrderContainer.y = 75;
LK.gui.topRight.addChild(turnOrderContainer);
var turnOrderTexts = [];
for (var i = 0; i < 4; i++) {
var turnText = new Text2('', {
size: 35,
fill: 0xFFFFFF
});
turnText.anchor.set(1, 0);
turnText.y = i * 45;
turnOrderContainer.addChild(turnText);
turnOrderTexts.push(turnText);
}
// Update turn order display
function updateTurnOrderDisplay() {
var playerNames = ['YOU', 'AI 1', 'AI 2', 'AI 3'];
for (var i = 0; i < 4; i++) {
if (turnOrderTexts[i]) {
var playerIndex = turnOrder[i];
var isCurrentPlayer = i === turnOrder.indexOf(currentPlayer);
turnOrderTexts[i].setText(i + 1 + '. ' + playerNames[playerIndex]);
turnOrderTexts[i].tint = isCurrentPlayer ? 0x00FF00 : 0xFFFFFF;
}
}
}
// Initialize tile deck
function initializeTileDeck() {
// Complete set of 48 Kingdomino tiles with exact terrain and crown combinations
var tileData = [
// Tiles 1-8: Wheat fields
{
leftType: 'wheat',
rightType: 'wheat',
leftCrowns: 0,
rightCrowns: 0
}, {
leftType: 'wheat',
rightType: 'wheat',
leftCrowns: 0,
rightCrowns: 0
}, {
leftType: 'forest',
rightType: 'forest',
leftCrowns: 0,
rightCrowns: 0
}, {
leftType: 'forest',
rightType: 'forest',
leftCrowns: 0,
rightCrowns: 0
}, {
leftType: 'forest',
rightType: 'forest',
leftCrowns: 0,
rightCrowns: 0
}, {
leftType: 'forest',
rightType: 'forest',
leftCrowns: 0,
rightCrowns: 0
}, {
leftType: 'lake',
rightType: 'lake',
leftCrowns: 0,
rightCrowns: 0
}, {
leftType: 'lake',
rightType: 'lake',
leftCrowns: 0,
rightCrowns: 0
},
// Tiles 9-16: Grassland
{
leftType: 'lake',
rightType: 'lake',
leftCrowns: 0,
rightCrowns: 0
}, {
leftType: 'grassland',
rightType: 'grassland',
leftCrowns: 0,
rightCrowns: 0
}, {
leftType: 'grassland',
rightType: 'grassland',
leftCrowns: 0,
rightCrowns: 0
}, {
leftType: 'swamp',
rightType: 'swamp',
leftCrowns: 0,
rightCrowns: 0
}, {
leftType: 'wheat',
rightType: 'forest',
leftCrowns: 0,
rightCrowns: 0
}, {
leftType: 'wheat',
rightType: 'lake',
leftCrowns: 0,
rightCrowns: 0
}, {
leftType: 'wheat',
rightType: 'grassland',
leftCrowns: 0,
rightCrowns: 0
}, {
leftType: 'wheat',
rightType: 'swamp',
leftCrowns: 0,
rightCrowns: 0
},
// Tiles 17-24: Forest
{
leftType: 'forest',
rightType: 'lake',
leftCrowns: 0,
rightCrowns: 0
}, {
leftType: 'forest',
rightType: 'grassland',
leftCrowns: 0,
rightCrowns: 0
}, {
leftType: 'wheat',
rightType: 'forest',
leftCrowns: 1,
rightCrowns: 0
}, {
leftType: 'wheat',
rightType: 'lake',
leftCrowns: 1,
rightCrowns: 0
}, {
leftType: 'wheat',
rightType: 'grassland',
leftCrowns: 1,
rightCrowns: 0
}, {
leftType: 'wheat',
rightType: 'swamp',
leftCrowns: 1,
rightCrowns: 0
}, {
leftType: 'wheat',
rightType: 'mine',
leftCrowns: 1,
rightCrowns: 0
}, {
leftType: 'forest',
rightType: 'wheat',
leftCrowns: 1,
rightCrowns: 0
}, {
leftType: 'forest',
rightType: 'wheat',
leftCrowns: 1,
rightCrowns: 0
},
// Tiles 25-32: Lake
{
leftType: 'forest',
rightType: 'wheat',
leftCrowns: 1,
rightCrowns: 0
}, {
leftType: 'forest',
rightType: 'wheat',
leftCrowns: 1,
rightCrowns: 0
}, {
leftType: 'forest',
rightType: 'lake',
leftCrowns: 1,
rightCrowns: 0
}, {
leftType: 'forest',
rightType: 'grassland',
leftCrowns: 1,
rightCrowns: 0
}, {
leftType: 'lake',
rightType: 'wheat',
leftCrowns: 1,
rightCrowns: 0
}, {
leftType: 'lake',
rightType: 'wheat',
leftCrowns: 1,
rightCrowns: 0
}, {
leftType: 'lake',
rightType: 'forest',
leftCrowns: 1,
rightCrowns: 0
}, {
leftType: 'lake',
rightType: 'forest',
leftCrowns: 1,
rightCrowns: 0
},
// Tiles 33-40: Swamp and Mine
{
leftType: 'lake',
rightType: 'forest',
leftCrowns: 1,
rightCrowns: 0
}, {
leftType: 'lake',
rightType: 'forest',
leftCrowns: 1,
rightCrowns: 0
}, {
leftType: 'wheat',
rightType: 'grassland',
leftCrowns: 0,
rightCrowns: 1
}, {
leftType: 'lake',
rightType: 'grassland',
leftCrowns: 0,
rightCrowns: 1
}, {
leftType: 'wheat',
rightType: 'swamp',
leftCrowns: 0,
rightCrowns: 1
}, {
leftType: 'grassland',
rightType: 'swamp',
leftCrowns: 0,
rightCrowns: 1
}, {
leftType: 'mine',
rightType: 'wheat',
leftCrowns: 1,
rightCrowns: 0
}, {
leftType: 'wheat',
rightType: 'grassland',
leftCrowns: 0,
rightCrowns: 2
},
// Tiles 41-48: Crown tiles
{
leftType: 'lake',
rightType: 'grassland',
leftCrowns: 0,
rightCrowns: 2
}, {
leftType: 'wheat',
rightType: 'swamp',
leftCrowns: 0,
rightCrowns: 2
}, {
leftType: 'grassland',
rightType: 'swamp',
leftCrowns: 0,
rightCrowns: 2
}, {
leftType: 'mine',
rightType: 'wheat',
leftCrowns: 2,
rightCrowns: 0
}, {
leftType: 'swamp',
rightType: 'mine',
leftCrowns: 0,
rightCrowns: 2
}, {
leftType: 'swamp',
rightType: 'mine',
leftCrowns: 0,
rightCrowns: 2
}, {
leftType: 'wheat',
rightType: 'mine',
leftCrowns: 0,
rightCrowns: 3
}];
// Create shuffled deck
var shuffledIndices = [];
for (var i = 0; i < 48; i++) {
shuffledIndices.push(i);
}
// Shuffle the indices
for (var i = shuffledIndices.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var temp = shuffledIndices[i];
shuffledIndices[i] = shuffledIndices[j];
shuffledIndices[j] = temp;
}
// Create tileDeck with shuffled order and original tile numbers
for (var i = 0; i < 48; i++) {
var data = tileData[shuffledIndices[i]];
tileDeck.push({
leftType: data.leftType,
rightType: data.rightType,
leftCrowns: data.leftCrowns,
rightCrowns: data.rightCrowns,
number: shuffledIndices[i] + 1 // Use the original tile number from shuffled deck
});
}
}
// Initialize kingdoms
function initializeKingdoms() {
for (var i = 0; i < 4; i++) {
var kingdom = new Kingdom(i);
kingdoms.push(kingdom);
// Position kingdoms around the screen
if (i === 0) {
// Human player - right side bottom
kingdom.x = 1360 - 30 + 15 + 5 + 3 + 3 + 3 + 3;
kingdom.y = 1800; // Bottom position
kingdom.scaleX = 1.0;
kingdom.scaleY = 1.0;
// Add background for kingdom
var kingdomBg = game.addChild(LK.getAsset('kingdomBackground', {
x: kingdom.x + 312,
y: kingdom.y + 312,
anchorX: 0.5,
anchorY: 0.5
}));
game.addChild(kingdom);
// Add wall above kingdom
var wall = game.addChild(LK.getAsset('wall', {
x: kingdom.x,
y: kingdom.y - 165,
anchorX: 0,
anchorY: 0
}));
// Add player label below kingdom
var playerLabel = new Text2('YOUR KINGDOM', {
size: 40,
fill: 0x000000
});
playerLabel.anchor.set(0.5, 0);
playerLabel.x = kingdom.x + 312;
playerLabel.y = kingdom.y + 625; // Below kingdom
game.addChild(playerLabel);
} else if (i === 1) {
// AI 1 - left side top
kingdom.x = 50;
kingdom.y = 700; // Top position
kingdom.scaleX = 1.0;
kingdom.scaleY = 1.0;
// Add background for kingdom
var kingdomBg = game.addChild(LK.getAsset('kingdomBackground', {
x: kingdom.x + 312,
y: kingdom.y + 312,
anchorX: 0.5,
anchorY: 0.5
}));
game.addChild(kingdom);
// Add wall above kingdom
var wall = game.addChild(LK.getAsset('wall', {
x: kingdom.x,
y: kingdom.y - 165,
anchorX: 0,
anchorY: 0
}));
// Add player label
var playerLabel = new Text2('AI PLAYER 1', {
size: 40,
fill: 0x000000
});
playerLabel.anchor.set(0.5, 0);
playerLabel.x = kingdom.x + 312;
playerLabel.y = kingdom.y + 625; // Below kingdom
game.addChild(playerLabel);
} else if (i === 2) {
// AI 2 - right side top
kingdom.x = 1360 - 30 + 15 + 5 + 3 + 3 + 3 + 3;
kingdom.y = 700; // Top position
kingdom.scaleX = 1.0;
kingdom.scaleY = 1.0;
// Add background for kingdom
var kingdomBg = game.addChild(LK.getAsset('kingdomBackground', {
x: kingdom.x + 312,
y: kingdom.y + 312,
anchorX: 0.5,
anchorY: 0.5
}));
game.addChild(kingdom);
// Add wall above kingdom
var wall = game.addChild(LK.getAsset('wall', {
x: kingdom.x,
y: kingdom.y - 165,
anchorX: 0,
anchorY: 0
}));
// Add player label
var playerLabel = new Text2('AI PLAYER 2', {
size: 40,
fill: 0x000000
});
playerLabel.anchor.set(0.5, 0);
playerLabel.x = kingdom.x + 312;
playerLabel.y = kingdom.y + 625; // Below kingdom
game.addChild(playerLabel);
} else if (i === 3) {
// AI 3 - left side bottom
kingdom.x = 50;
kingdom.y = 1800; // Bottom position
kingdom.scaleX = 1.0;
kingdom.scaleY = 1.0;
// Add background for kingdom
var kingdomBg = game.addChild(LK.getAsset('kingdomBackground', {
x: kingdom.x + 312,
y: kingdom.y + 312,
anchorX: 0.5,
anchorY: 0.5
}));
game.addChild(kingdom);
// Add wall above kingdom
var wall = game.addChild(LK.getAsset('wall', {
x: kingdom.x,
y: kingdom.y - 165,
anchorX: 0,
anchorY: 0
}));
// Add player label
var playerLabel = new Text2('AI PLAYER 3', {
size: 40,
fill: 0x000000
});
playerLabel.anchor.set(0.5, 0);
playerLabel.x = kingdom.x + 312;
playerLabel.y = kingdom.y + 625; // Below kingdom
game.addChild(playerLabel);
}
}
}
// Draw current tiles
function drawCurrentTiles() {
// Clear existing tiles
for (var i = 0; i < currentTiles.length; i++) {
if (currentTiles[i].parent) {
currentTiles[i].parent.removeChild(currentTiles[i]);
}
// Also remove the global number text
if (currentTiles[i].globalNumberText && currentTiles[i].globalNumberText.parent) {
currentTiles[i].globalNumberText.parent.removeChild(currentTiles[i].globalNumberText);
}
}
currentTiles = [];
// Add background for tile selection area
var tilesBackground = game.addChild(LK.getAsset('tilesBackground', {
x: 1024,
y: 1375,
anchorX: 0.5,
anchorY: 0.5
}));
// Send background to back but in front of game background
game.addChildAt(tilesBackground, 1);
// Get 4 tiles from deck
var tilesToShow = [];
for (var i = 0; i < 4; i++) {
if (tileDeck.length > 0) {
tilesToShow.push(tileDeck.shift());
}
}
// Sort tiles by their original number (lowest to highest)
tilesToShow.sort(function (a, b) {
return a.number - b.number;
});
// Draw sorted tiles in a column centered on screen
for (var i = 0; i < tilesToShow.length; i++) {
var tileData = tilesToShow[i];
var tile = new GameTile(tileData.leftType, tileData.rightType, tileData.leftCrowns, tileData.rightCrowns, tileData.number);
tile.x = 1024; // Center horizontally (screen width / 2)
tile.y = 1041 + i * 220; // Position cards moved up by 125 pixels from original position
currentTiles.push(tile);
game.addChild(tile);
// Add global tile number below the tile (showing the actual shuffled tile number)
var globalNumberText = new Text2(tileData.number.toString(), {
size: 40,
fill: 0x000000
});
globalNumberText.anchor.set(0.5, 0);
globalNumberText.x = tile.x;
globalNumberText.y = tile.y + 80; // Position below the tile
game.addChild(globalNumberText);
// Store reference to remove it later
tile.globalNumberText = globalNumberText;
}
}
// Select tile
function selectTile(tile) {
if (gameState !== 'selectTile' || currentPlayer !== 0) {
return;
}
if (selectedTile) {
selectedTile.setSelected(false);
}
selectedTile = tile;
tile.setSelected(true);
gameState = 'placeTile';
updateTurnOrderDisplay();
instructionTxt.setText('Click to place tile on your kingdom');
LK.getSound('selectSound').play();
}
// AI turn
function aiTurn() {
if (currentPlayer === 0) {
return;
}
// Prevent user interaction during AI turn
gameState = 'aiTurn';
updateTurnOrderDisplay();
// AI selects random available tile
var availableTiles = [];
for (var i = 0; i < currentTiles.length; i++) {
if (!currentTiles[i].selected) {
availableTiles.push(currentTiles[i]);
}
}
if (availableTiles.length > 0) {
var randomTile = availableTiles[Math.floor(Math.random() * availableTiles.length)];
selectedTile = randomTile;
randomTile.setSelected(true);
// Mark tile as owned by current AI player to prevent user interaction
randomTile.ownerPlayer = currentPlayer;
instructionTxt.setText('AI Player ' + currentPlayer + ' selecting tile...');
LK.getSound('selectSound').play();
// Delay before placing tile
LK.setTimeout(function () {
// AI places tile with smart priority: comprehensively check for 2-matching terrain connections first
var kingdom = kingdoms[currentPlayer];
var placed = false;
var bestPlacements = [];
// First pass: Systematically check ALL positions and rotations for 2-matching terrain connections
for (var row = 0; row < 5 && !placed; row++) {
for (var col = 0; col < 5 && !placed; col++) {
for (var rot = 0; rot < 4 && !placed; rot++) {
// Set rotation internally without visual update
var originalRotation = selectedTile.currentRotationAngle;
selectedTile.currentRotationAngle = rot * 90;
if (kingdom.canPlaceTile(selectedTile, row, col)) {
// Check if this placement has 2 matching terrain connections
var positions = kingdom.getTilePositions(selectedTile, row, col);
if (positions) {
var matchingConnections = 0;
var castleConnections = 0;
for (var p = 0; p < positions.length; p++) {
var r = positions[p][0];
var c = positions[p][1];
var directions = [[-1, 0], [1, 0], [0, -1], [0, 1]];
for (var d = 0; d < directions.length; d++) {
var nr = r + directions[d][0];
var nc = c + directions[d][1];
if (nr >= 0 && nr < 5 && nc >= 0 && nc < 5 && kingdom.grid[nr][nc] !== null) {
if (kingdom.grid[nr][nc].type === 'castle') {
castleConnections++;
} else {
// Check if terrain matches (not castle)
var terrainIndex = p;
var tileType = terrainIndex === 0 ? selectedTile.leftType : selectedTile.rightType;
if (kingdom.grid[nr][nc].type === tileType) {
matchingConnections++;
}
}
}
}
}
// Store placement info for later evaluation
bestPlacements.push({
row: row,
col: col,
rotation: rot * 90,
matchingConnections: matchingConnections,
castleConnections: castleConnections,
totalConnections: matchingConnections + castleConnections
});
}
}
// Restore original rotation
selectedTile.currentRotationAngle = originalRotation;
}
}
}
// Sort placements: prioritize terrain matches over castle connections
bestPlacements.sort(function (a, b) {
// First priority: 2+ matching terrain connections
if (a.matchingConnections >= 2 && b.matchingConnections < 2) {
return -1;
}
if (b.matchingConnections >= 2 && a.matchingConnections < 2) {
return 1;
}
// Second priority: more terrain matches
if (a.matchingConnections !== b.matchingConnections) {
return b.matchingConnections - a.matchingConnections;
}
// Third priority: castle connections only if no terrain matches
if (a.matchingConnections === 0 && b.matchingConnections === 0) {
return b.castleConnections - a.castleConnections;
}
// Fourth priority: total connections
return b.totalConnections - a.totalConnections;
});
// Place the tile using the best placement found
if (bestPlacements.length > 0) {
var bestPlacement = bestPlacements[0];
selectedTile.currentRotationAngle = bestPlacement.rotation;
selectedTile.updateTileVisuals();
kingdom.placeTile(selectedTile, bestPlacement.row, bestPlacement.col);
placed = true;
}
// If tile couldn't be placed, try moving kingdom
if (!placed) {
var directions = ['up', 'down', 'left', 'right'];
for (var d = 0; d < directions.length && !placed; d++) {
if (kingdom.canMoveKingdom(directions[d])) {
var oldHasMoved = kingdom.hasMoved;
kingdom.moveKingdom(directions[d]);
if (!oldHasMoved) {
kingdom.score = Math.max(0, kingdom.calculateScore() - 10);
}
updateAIScoresDisplay();
// Try placing again after movement
for (var attempts2 = 0; attempts2 < 100 && !placed; attempts2++) {
var row = Math.floor(Math.random() * 5);
var col = Math.floor(Math.random() * 4);
for (var rot = 0; rot < 4 && !placed; rot++) {
var originalRotation = selectedTile.currentRotationAngle;
selectedTile.currentRotationAngle = rot * 90;
if (kingdom.canPlaceTile(selectedTile, row, col)) {
selectedTile.updateTileVisuals();
kingdom.placeTile(selectedTile, row, col);
placed = true;
} else {
selectedTile.currentRotationAngle = originalRotation;
}
}
}
}
}
}
if (placed) {
updateAIScoresDisplay();
selectedTiles.push({
tile: selectedTile,
player: currentPlayer
});
// Remove tile from display
selectedTile.parent.removeChild(selectedTile);
// Also remove the global number text
if (selectedTile.globalNumberText && selectedTile.globalNumberText.parent) {
selectedTile.globalNumberText.parent.removeChild(selectedTile.globalNumberText);
}
selectedTile = null;
LK.getSound('placeSound').play();
} else {
// AI couldn't place tile even after trying to move, trash it
kingdom.score = Math.max(0, kingdom.calculateScore() - 5);
updateAIScoresDisplay();
selectedTiles.push({
tile: selectedTile,
player: currentPlayer
});
selectedTile.parent.removeChild(selectedTile);
if (selectedTile.globalNumberText && selectedTile.globalNumberText.parent) {
selectedTile.globalNumberText.parent.removeChild(selectedTile.globalNumberText);
}
selectedTile = null;
LK.getSound('placeSound').play();
}
instructionTxt.setText('AI Player ' + currentPlayer + ' placed tile');
LK.setTimeout(function () {
nextPlayer();
}, 1000);
}, 1000);
}
}
// Next player
function nextPlayer() {
// Check if all 4 players have selected tiles in this round
if (selectedTiles.length === 4) {
// All players finished, start new round
round++;
if (round > maxRounds) {
endGame();
return;
}
// Update turn order based on selected tiles
selectedTiles.sort(function (a, b) {
return a.tile.number - b.tile.number;
});
turnOrder = [];
for (var i = 0; i < selectedTiles.length; i++) {
turnOrder.push(selectedTiles[i].player);
}
selectedTiles = [];
currentPlayer = turnOrder[0];
drawCurrentTiles();
scoreTxt.setText('Round: ' + round);
updateTurnOrderDisplay();
if (currentPlayer === 0) {
gameState = 'selectTile';
instructionTxt.setText('Select a tile');
} else {
LK.setTimeout(aiTurn, 500);
}
} else {
// Move to next player in current round
var currentTurnIndex = turnOrder.indexOf(currentPlayer);
var nextTurnIndex = (currentTurnIndex + 1) % 4;
currentPlayer = turnOrder[nextTurnIndex];
updateTurnOrderDisplay();
if (currentPlayer !== 0) {
LK.setTimeout(aiTurn, 500);
} else {
gameState = 'selectTile';
instructionTxt.setText('Select a tile');
}
}
}
// End game
function endGame() {
gameState = 'gameOver';
// Calculate final scores
var finalScores = [];
for (var i = 0; i < kingdoms.length; i++) {
// Use stored score for human player (includes penalties), calculate for AI
var finalScore = i === 0 ? kingdoms[i].score : kingdoms[i].calculateScore();
finalScores.push({
player: i,
score: finalScore
});
}
finalScores.sort(function (a, b) {
return b.score - a.score;
});
var playerRank = 1;
for (var i = 0; i < finalScores.length; i++) {
if (finalScores[i].player === 0) {
playerRank = i + 1;
break;
}
}
// Show results window first
showResultsWindow(finalScores, playerRank);
}
// Kingdom click handler
function handleKingdomClick(x, y) {
if (gameState !== 'placeTile' || currentPlayer !== 0 || !selectedTile) {
return;
}
var kingdom = kingdoms[0];
// Convert click coordinates to kingdom local coordinates
// Account for kingdom position offset
var relativeX = x - kingdom.x;
var relativeY = y - kingdom.y;
// Calculate grid position based on cell size (125px)
var row = Math.floor(relativeY / 125);
var col = Math.floor(relativeX / 125);
// Ensure coordinates are within valid bounds
if (row < 0 || row >= 5 || col < 0 || col >= 5) {
return;
}
// For horizontal tiles, ensure there's space for both cells
if ((selectedTile.currentRotationAngle === 0 || selectedTile.currentRotationAngle === 180) && col >= 4) {
col = 3; // Ensure tile fits horizontally
}
// For vertical tiles, ensure there's space for both cells
if ((selectedTile.currentRotationAngle === 90 || selectedTile.currentRotationAngle === 270) && row >= 4) {
row = 3; // Ensure tile fits vertically
}
if (kingdom.canPlaceTile(selectedTile, row, col)) {
kingdom.placeTile(selectedTile, row, col);
selectedTiles.push({
tile: selectedTile,
player: currentPlayer
});
// Remove tile from game
selectedTile.parent.removeChild(selectedTile);
// Also remove the global number text
if (selectedTile.globalNumberText && selectedTile.globalNumberText.parent) {
selectedTile.globalNumberText.parent.removeChild(selectedTile.globalNumberText);
}
selectedTile = null;
LK.getSound('placeSound').play();
gameState = 'waitingForOthers';
instructionTxt.setText('Wait for other players...');
// Update score
playerScoreTxt.setText('Your Score: ' + kingdom.calculateScore());
nextPlayer();
}
}
// Game move handler for dragging
game.move = function (x, y, obj) {
if (draggedTile && draggedTile.isDragging) {
draggedTile.x = x;
draggedTile.y = y;
}
};
// Game up handler for dropping tiles
game.up = function (x, y, obj) {
if (draggedTile && draggedTile.isDragging) {
draggedTile.isDragging = false;
// Try to place tile on kingdom
handleKingdomClick(x, y);
draggedTile = null;
}
};
// Movement button handlers
moveUpBtn.down = function () {
if (currentPlayer === 0 && (gameState === 'selectTile' || gameState === 'placeTile')) {
var kingdom = kingdoms[0];
if (kingdom.canMoveKingdom('up')) {
kingdom.moveKingdom('up');
if (!hasMovedKingdom) {
kingdom.score = Math.max(0, kingdom.calculateScore() - 10);
hasMovedKingdom = true;
} else {
kingdom.score = kingdom.calculateScore();
}
playerScoreTxt.setText('Your Score: ' + kingdom.score);
LK.getSound('selectSound').play();
}
}
};
moveDownBtn.down = function () {
if (currentPlayer === 0 && (gameState === 'selectTile' || gameState === 'placeTile')) {
var kingdom = kingdoms[0];
if (kingdom.canMoveKingdom('down')) {
kingdom.moveKingdom('down');
if (!hasMovedKingdom) {
kingdom.score = Math.max(0, kingdom.calculateScore() - 10);
hasMovedKingdom = true;
} else {
kingdom.score = kingdom.calculateScore();
}
playerScoreTxt.setText('Your Score: ' + kingdom.score);
LK.getSound('selectSound').play();
}
}
};
moveLeftBtn.down = function () {
if (currentPlayer === 0 && (gameState === 'selectTile' || gameState === 'placeTile')) {
var kingdom = kingdoms[0];
if (kingdom.canMoveKingdom('left')) {
kingdom.moveKingdom('left');
if (!hasMovedKingdom) {
kingdom.score = Math.max(0, kingdom.calculateScore() - 10);
hasMovedKingdom = true;
} else {
kingdom.score = kingdom.calculateScore();
}
playerScoreTxt.setText('Your Score: ' + kingdom.score);
LK.getSound('selectSound').play();
}
}
};
moveRightBtn.down = function () {
if (currentPlayer === 0 && (gameState === 'selectTile' || gameState === 'placeTile')) {
var kingdom = kingdoms[0];
if (kingdom.canMoveKingdom('right')) {
kingdom.moveKingdom('right');
if (!hasMovedKingdom) {
kingdom.score = Math.max(0, kingdom.calculateScore() - 10);
hasMovedKingdom = true;
} else {
kingdom.score = kingdom.calculateScore();
}
playerScoreTxt.setText('Your Score: ' + kingdom.score);
LK.getSound('selectSound').play();
}
}
};
// Trash button handler
trashBtn.down = function () {
if (currentPlayer === 0 && gameState === 'placeTile' && selectedTile) {
// Remove tile and deduct points only if first time using trash
var kingdom = kingdoms[0];
if (!hasUsedTrash) {
kingdom.score = Math.max(0, kingdom.calculateScore() - 5);
hasUsedTrash = true;
} else {
// No penalty for subsequent trash uses
kingdom.score = kingdom.calculateScore();
}
playerScoreTxt.setText('Your Score: ' + kingdom.score);
// Remove tile from display
selectedTile.parent.removeChild(selectedTile);
if (selectedTile.globalNumberText && selectedTile.globalNumberText.parent) {
selectedTile.globalNumberText.parent.removeChild(selectedTile.globalNumberText);
}
selectedTiles.push({
tile: selectedTile,
player: currentPlayer
});
selectedTile = null;
LK.getSound('placeSound').play();
gameState = 'waitingForOthers';
instructionTxt.setText('Wait for other players...');
nextPlayer();
}
};
// Global rotation button handler
globalRotateBtn.down = function () {
if (currentPlayer === 0 && gameState === 'placeTile' && selectedTile) {
selectedTile.rotateTile();
LK.getSound('selectSound').play();
}
};
// Game event handlers
game.down = function (x, y, obj) {
if (gameState === 'placeTile' && currentPlayer === 0 && !draggedTile) {
handleKingdomClick(x, y);
}
};
game.update = function () {
// Game update logic handled by event system and timeouts
};
// Show results window with final scores
function showResultsWindow(finalScores, playerRank) {
// Create results overlay
var resultsOverlay = game.addChild(LK.getAsset('kingdomBackground', {
x: 1024,
y: 1366,
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.5,
scaleY: 3
}));
resultsOverlay.alpha = 0.95;
resultsOverlay.tint = 0x000000;
// Results title
var resultsTitle = game.addChild(new Text2('FINAL RESULTS', {
size: 80,
fill: 0xFFD700
}));
resultsTitle.anchor.set(0.5, 0.5);
resultsTitle.x = 1024;
resultsTitle.y = 600;
// Display scores
var playerNames = ['YOU', 'AI PLAYER 1', 'AI PLAYER 2', 'AI PLAYER 3'];
for (var i = 0; i < finalScores.length; i++) {
var rank = i + 1;
var playerIndex = finalScores[i].player;
var score = finalScores[i].score;
var playerName = playerNames[playerIndex];
var rankText = game.addChild(new Text2(rank + '. ' + playerName + ': ' + score, {
size: 60,
fill: rank === 1 ? 0xFFD700 : playerIndex === 0 ? 0x00FF00 : 0xFFFFFF
}));
rankText.anchor.set(0.5, 0.5);
rankText.x = 1024;
rankText.y = 800 + i * 80;
}
// Continue button
var continueButton = game.addChild(new Text2('TAP TO CONTINUE', {
size: 50,
fill: 0x00FF00
}));
continueButton.anchor.set(0.5, 0.5);
continueButton.x = 1024;
continueButton.y = 1400;
// Pulsing animation for continue button
var pulseScale = 1.0;
var pulseDirection = 1;
var resultsUpdateHandler = function resultsUpdateHandler() {
pulseScale += pulseDirection * 0.02;
if (pulseScale > 1.2) {
pulseScale = 1.2;
pulseDirection = -1;
} else if (pulseScale < 1.0) {
pulseScale = 1.0;
pulseDirection = 1;
}
continueButton.scaleX = pulseScale;
continueButton.scaleY = pulseScale;
};
// Click handler for continue button
var resultsClickHandler = function resultsClickHandler(x, y, obj) {
// Remove results window
game.removeChild(resultsOverlay);
game.removeChild(resultsTitle);
for (var i = 0; i < finalScores.length; i++) {
var rankText = game.children[game.children.length - 1];
if (rankText && rankText.setText) {
game.removeChild(rankText);
}
}
game.removeChild(continueButton);
// Remove event handlers
game.update = originalGameUpdate;
game.down = originalGameDown;
// Show appropriate end screen
if (playerRank === 1) {
LK.showYouWin();
} else {
LK.showGameOver();
}
};
// Store original handlers
var originalGameUpdate = game.update;
var originalGameDown = game.down;
// Override game handlers for results window
game.update = resultsUpdateHandler;
game.down = resultsClickHandler;
}
// Function to start the actual game
function startGame() {
if (startScreen) {
game.removeChild(startScreen);
startScreen = null;
}
showingStartScreen = false;
// Reset penalty flags for new game
hasUsedTrash = false;
hasMovedKingdom = false;
// Show score displays now that game is starting
aiScoresContainer.alpha = 1;
playerScoreTxt.alpha = 1;
// Initialize game
initializeTileDeck();
initializeKingdoms();
drawCurrentTiles();
// Start with human player
gameState = 'selectTile';
updateTurnOrderDisplay();
updateAIScoresDisplay();
instructionTxt.setText('Select a tile');
}
// Show start screen initially
if (showingStartScreen) {
startScreen = new StartScreen();
game.addChild(startScreen);
}
טחנת דגן בלב שדה חיטה עם רקע צהוב. In-Game asset. 2d. High contrast. No shadows
כתר בעל קווי מתאר שחורים. In-Game asset. 2d. High contrast. No shadows
יער מלא בעצים. In-Game asset. 2d. High contrast. No shadows
מכרה זהב עם רקע כהה. In-Game asset. 2d. High contrast. No shadows
ים עם אי בודד במרכזו. In-Game asset. 2d. High contrast. No shadows
מרעה ירוק עם דיר קטן במרכזו. In-Game asset. 2d. High contrast. No shadows
ביצה טובענית בצבעי חום. In-Game asset. 2d. High contrast. No shadows
טירה אפורה. In-Game asset. 2d. High contrast. No shadows
שקיעה ירוקה עם צבעים כהים למעלה וכהים למטה, למטה זה עצים ולמעלה הרים, השמש לא רואים אותה באמצע, ציורי ופסטורלי מהאגדות. In-Game asset. 2d. High contrast. No shadows
ריבוע חלול עם קו מתאר חום. In-Game asset. 2d. High contrast. No shadows
תמונה מלבנית בצבע שמנת ביחס 2 על1 ממוסגרת עם מסגרת דקה בצבע חום. In-Game asset. 2d. High contrast. No shadows
אדמה חולית בצורת ריבוע בצבע צהוב עם פינות מעוגלות. In-Game asset. 2d. High contrast. No shadows