/****
* 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