User prompt
תיקח את טור האבנים חצי פוזישן למטה ביחס לאיפה שהם עכשיו קח את הלוח של שחקן 1 ושל המשתמש חצי פויזשן שמאלה ביחס לאיפה שהם עכשיו
User prompt
קח את הלוח של מחשבב 1 ושל המשתמש, קצת שמאלה ביחס לאיפה שהם עכשיו קח את טור האבנים שנפתחות קצת למטה
User prompt
המשחק נתקע עם הAI מסובב את האבן לא צריך להראות למשתמש את הסיבוב. רק בחירה, ואז כבר בלוח כמו שהמחשב מחליט
User prompt
אין קשר בין איפה שאני מניח את האבן, לאיפה שהוא שם אותה בפועל
User prompt
FI קרה עכשיו, שאחרי שהמחשב שינה כיוון לאבן האבן הפכה להיות של המשתמש ואז לא היה ניתן להתקדם במשחק בנוסף, הסיבוב לא קורה בצורה טובה, זה מסתובב לזוויות לא הגיוניות
User prompt
Please fix the bug: 'Cannot set properties of undefined (setting 'fill')' in or related to this line: 'turnOrderTexts[i].style.fill = isCurrentPlayer ? 0x00FF00 : 0xFFFFFF;' Line Number: 494
User prompt
יש כרגע בעיה המשחק לא נותן למשתמש לשחק כשתורו, והוא מחדש את האבנים על הלוח. תעשה בצד ימין למעלה, 4 מקומות בטור שמראים מה יהיה הסבב הבא. זאת אומרת, אם המשתמש בחר את האבן השלישית, ואז המחשבים השתבצו, אז בצד ימין למעלה המשתמש יופיע במקום 3, לפניו 2 המחשבים שלפניו, ואחריו המחשב שאחרי. באבנים, המחשב הראשון ייקח אבן על ידי סימון ואז הנחה, ואז השני, ואז יתאפשר למשתמש לבחור אבן ולא יתרענן לוח האבנים
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'toGlobal')' in or related to this line: 'var globalPos = obj.parent.toGlobal(obj.position);' Line Number: 181
User prompt
כפתור הסיבוב של האבן לא עובד כשאני מניח את האבן על הלוח, זה לא קולט ולא מניח אותה וממשיך את המשחק. כל תור של המחשב - דבר ראשון לסמן איזה אבן, אחרי שנייה לשים, אחרי שנייה הבא מסמן איזה אבן, אחרי שנייה שם, אחרי שנייה הבא מסמן, שם ואז ממשיכים. אם תור המשתמש באמצע כמובן מחכים
User prompt
קח את טור האבנים מעט למטה ביחס לאיפה שהוא עכשיו תצמצם במעט את הרווחים ביניהם קח את כל הלוחות במעט שמאלה ביחס לאיפה שהם עכשיו תגביה מעט את מיקום הלוח של השחקן ביחס לאיפה שהוא עכשיו
User prompt
עכשיו תיקח טיפה שמאלה כל אחד מהלוחות ביחס לאיפה שהוא עכשיו את האבנים שנשלפות שים במרכז המסך בטור את השם של הלוח של השחקן, שים מעל הלוח
User prompt
תגדיל את הלוחות של כולם תיקח ימינה ביחס למיקום הנוכחי של כל לוח את הלוחות של כולם את השמות של המחשבים, תשים מתחת ללוח שלהם את האבנים, שישלפו ויעמדו בטור ולא בשורה
User prompt
תגדיל את הלוחות של המחשבים שיהיו באותו גודל כמו של השחקן תמרכז את מיקום הלוח של השחקן תגדיל את הריבועים של הלוח שיתאימו לאבני הדומינו
User prompt
אם מקום על הלוח הוא בגודל 120 על 120, אז הדומינו שפותחים יהיה 120 על 240. 2 ריבועים מחוברים מה שנשלף, מתחתיו שיהיה כתוב המספר הסידורי שלו, בין 1 ל-48. לא רק המיקום שלו בין ה-4 שנפתחו
User prompt
האבנים גדולות מדי ביחס ללוח, כשאני גורר את האבן ללוח הוא לא ממקם אותה איפה שצריך. תתאים את הגדלים. כפתור סיבוב האבן לא עובד
User prompt
כשנשלפים 4 אבנים, מתחת לכל אחת מופיע המספר הסידורי שלה. הן ממוינות ככה שידוע מי הקטנה ומי הגדולה תעשה 4 לוחות, אחת למטה באמצע למשתמש, אחת למעלה באמצע למחשב השני, אחת בימין באמצע למחשב השלישי, אחת בשמאל באמצע למחשב השני. המחשב פשוט בוחר אבן שהוא יכול לחבר אותה באחד הכיוונים ומחבר
User prompt
תייצר את כל סוגי הלבנים בדומינו ותן להם את הדירוגים 1 עד 48. כל פעם 4 רנדומליים נשלפים כאשר המשתמש בוחר אבן, נפתח לו כפתור שאיתו הוא יכול לסובב את האבן. 90 180 או 270 מעלות ואז הוא גורר ושם איפה שהוא רוצה על הלוח שלו
Code edit (1 edits merged)
Please save this source code
User prompt
Kingdomino
Initial prompt
Game name Kingdomino There are 48 tiles, the game plays against 3 AI. Every player have a board on the size of 5*5. The player board is big, and the computers can be small. Every player start with 1*1 kingdom at the center of the board. Every turn, 4 tiles opens with rank (1-48) on them. at the first turn the player strat, and then with the clock arrow. After that, the one that pick the lowest tile last round start, and then the second lowest and so on. to the kingdom, you can connect every tile. after that, you can connect to a tile only macthcing tile. there are tiles with crown and tiles withuot crowns. If you have a crown on your tile, the colour of this crown gain 1 point for every macthing tile connect to this one in a row. The game ends after 12 rounds, and the one with the biggest points win
/**** * 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