/****
* Classes
****/
var ActionButton = Container.expand(function () {
var self = Container.call(this);
self.init = function (text, action, x, y) {
self.action = action;
// Button graphics
self.buttonGraphics = self.attachAsset('actionButton', {
anchorX: 0.5,
anchorY: 0.5
});
// Button text
self.buttonText = new Text2(text, {
size: 28,
fill: 0xFFFFFF
});
self.buttonText.anchor.set(0.5, 0.5);
self.addChild(self.buttonText);
self.x = x;
self.y = y;
return self;
};
self.down = function (x, y, obj) {
if (self.action) {
self.action();
}
};
return self;
});
var DiplomacyPanel = Container.expand(function () {
var self = Container.call(this);
self.init = function (targetCountry) {
self.targetCountry = targetCountry;
self.visible = false;
// Panel background
self.panelBg = LK.getAsset('diplomacypanel', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 3,
scaleY: 4
});
self.addChild(self.panelBg);
// Panel title
self.titleText = new Text2("Diplomacy with Country " + targetCountry, {
size: 32,
fill: 0x000000
});
self.titleText.anchor.set(0.5, 0.5);
self.titleText.y = -80;
self.addChild(self.titleText);
// Declare war button
self.warButton = new ActionButton();
self.warButton.init("Declare War", function () {
declareWar(targetCountry);
self.hide();
}, 0, 40);
// Show declare war button in easy mode
self.warButton.visible = true;
self.addChild(self.warButton);
// Peace treaty button
self.peaceButton = new ActionButton();
self.peaceButton.init("Peace Treaty", function () {
makePeace(targetCountry);
self.hide();
}, 0, 100);
self.addChild(self.peaceButton);
// Show/hide peace button depending on war state and difficulty
self.updateButtons = function () {
if (selectedDifficulty === "hardcore") {
self.peaceButton.visible = false;
} else if (warDeclarations[self.targetCountry]) {
self.peaceButton.visible = true;
} else {
self.peaceButton.visible = false;
}
};
self.updateButtons();
// Close button
self.closeButton = new ActionButton();
self.closeButton.init("Close", function () {
self.hide();
}, 0, 160);
self.addChild(self.closeButton);
// Position panel in center of screen
self.x = 2048 / 2;
self.y = 2732 / 2;
return self;
};
self.show = function () {
self.visible = true;
self.updateButtons && self.updateButtons();
game.addChild(self);
};
self.hide = function () {
self.visible = false;
if (self.parent) {
self.parent.removeChild(self);
}
};
return self;
});
var Ship = Container.expand(function () {
var self = Container.call(this);
self.init = function (owner, x, y) {
self.owner = owner;
self.hp = 3; // Ships have more health than armies
self.selected = false;
// Armies carried by ship (default 2 for player, 0 for AI, can be changed)
self.armies = owner === 1 ? 2 : 0;
// Ship graphics
self.shipGraphics = self.attachAsset('ship', {
anchorX: 0.5,
anchorY: 0.5
});
// Color based on owner
if (owner === 1) {
self.shipGraphics.tint = 0x27ae60; // Green for player
} else if (owner === 2) {
self.shipGraphics.tint = 0xe74c3c; // Red for enemy
} else if (owner === 3) {
self.shipGraphics.tint = 0x2a2f94; // Blue
} else if (owner === 4) {
self.shipGraphics.tint = 0x8e44ad; // Purple
} else if (owner === 5) {
self.shipGraphics.tint = 0xf39c12; // Orange
} else if (owner === 6) {
self.shipGraphics.tint = 0x00bcd4; // Cyan
}
// HP display
self.hpText = new Text2(self.hp.toString(), {
size: 48,
fill: 0xFFFFFF
});
self.hpText.anchor.set(0.5, 0.5);
self.hpText.x = 0;
self.hpText.y = -45;
self.addChild(self.hpText);
// Armies display (above ship)
self.armyText = new Text2(self.armies.toString(), {
size: 54,
fill: 0x000000
});
self.armyText.anchor.set(0.5, 0.5);
self.armyText.x = 0;
self.armyText.y = -80;
self.addChild(self.armyText);
self.x = x;
self.y = y;
return self;
};
self.takeDamage = function (damage) {
self.hp -= damage;
self.hpText.setText(self.hp.toString());
return self.hp <= 0;
};
self.down = function (x, y, obj) {
if (gameState === 'playing' && self.owner === 1) {
selectShip(self);
// Show possible moves for this ship (all sea territories) when clicked
// Remove all previous highlights first
for (var i = 0; i < territories.length; i++) {
if (territories[i].isSea) {
territories[i].showAsTarget = true;
territories[i].updateGraphics();
}
}
} else if (gameState === 'playing' && selectedShip && selectedShip.owner === 1 && self.owner === 2) {
// Check if ships are close enough for naval combat
var distance = Math.abs(selectedShip.x - self.x) + Math.abs(selectedShip.y - self.y);
if (distance < 200) {
// Initiate naval combat
navalCombat(selectedShip, self);
selectedShip.selected = false;
selectedShip.shipGraphics.tint = 0x27ae60; // Reset color
selectedShip = null;
endPlayerTurn();
}
}
};
return self;
});
// Game state variables
var Territory = Container.expand(function () {
var self = Container.call(this);
self.init = function (id, x, y, owner, isSea) {
self.id = id;
self.owner = owner; // 0 = neutral, 1 = player, 2 = enemy
self.isSea = isSea || false;
self.armies = owner === 0 || self.isSea ? 0 : Math.floor(Math.random() * 3) + 1;
self.selected = false;
self.lastSelected = false;
// Track if this territory was ever colonizable (for attack logic)
self.wasColonizable = !!self.isColonizable;
// Create territory graphics
self.updateGraphics();
// Position
self.x = x;
self.y = y;
// Army display (only for land territories)
if (!self.isSea) {
self.armyText = new Text2(self.armies.toString(), {
size: 24,
fill: 0x000000
});
self.armyText.anchor.set(0.5, 0.5);
self.armyText.x = 0;
self.armyText.y = 0;
self.addChild(self.armyText);
}
return self;
};
self.updateGraphics = function () {
// Remove existing graphics
if (self.graphics) {
self.removeChild(self.graphics);
}
var assetName = 'seaTerritory'; // Default to sea
if (self.isSea) {
assetName = 'seaTerritory';
} else if (self.selected) {
assetName = 'selectedTerritory';
} else if (self.showAsTarget) {
assetName = 'targetTerritory';
} else {
// Assign different country colors based on owner
if (self.owner === 1) {
assetName = 'country1Territory'; // Green for player
} else if (self.owner === 2) {
assetName = 'country2Territory'; // Red for enemy
} else if (self.owner === 3) {
assetName = 'country3Territory'; // Blue
} else if (self.owner === 4) {
assetName = 'country4Territory'; // Purple
} else if (self.owner === 5) {
assetName = 'country5Territory'; // Orange
} else if (self.owner === 6) {
assetName = 'country6Territory'; // Cyan
} else if (self.isColonizable) {
assetName = 'colonizableTerritory'; // Use dedicated gray asset for colonizable territories
} else {
assetName = 'seaTerritory'; // Unassigned territories become sea
}
}
self.graphics = self.attachAsset(assetName, {
anchorX: 0.5,
anchorY: 0.5
});
};
self.setOwner = function (newOwner, armies) {
self.owner = newOwner;
if (!self.isSea) {
self.armies = armies || 1;
self.armyText.setText(self.armies.toString());
}
self.updateGraphics();
};
self.addArmies = function (count) {
if (!self.isSea) {
self.armies += count;
self.armyText.setText(self.armies.toString());
// Ensure army text is visible and on top after army change
self.removeChild(self.armyText);
self.addChild(self.armyText);
}
};
self.down = function (x, y, obj) {
if (gameState === 'playing') {
// Handle ship movement to sea territories
if (selectedShip && self.isSea) {
// Allow movement to any sea territory
if (self.isSea) {
// Move ship to any sea territory
selectedShip.x = self.x;
selectedShip.y = self.y;
selectedShip.selected = false;
selectedShip.shipGraphics.tint = 0x27ae60; // Reset color
// Remove all sea highlights after move
for (var i = 0; i < territories.length; i++) {
if (territories[i].isSea && territories[i].showAsTarget) {
territories[i].showAsTarget = false;
territories[i].updateGraphics();
}
}
selectedShip = null;
endPlayerTurn();
return;
}
}
// Handle ship colonization of distant territories
if (selectedShip && self.isColonizable && self.owner === 0 && !self.isSea) {
// Check if ship is close enough to colonize (must be adjacent or very close)
var distance = Math.abs(selectedShip.x - self.x) + Math.abs(selectedShip.y - self.y);
if (distance <= territorySpacing * 1.5) {
// Colonize the territory
self.setOwner(selectedShip.owner, selectedShip.armies && selectedShip.armies > 0 ? selectedShip.armies : 2); // Use ship's armies if present, else 2
self.isColonizable = false; // No longer colonizable
self.wasColonizable = true; // Mark as previously colonizable for attack logic
// Ensure army text is visible and on top after colonization
if (self.armyText) {
self.armyText.setText(self.armies.toString());
self.removeChild(self.armyText);
self.addChild(self.armyText);
}
if (selectedShip.owner === 1) {
// Player gets money reward for colonization
playerMoney += self.colonizationReward;
if (playerMoneyText) {
playerMoneyText.setText("Money: " + playerMoney);
}
if (instructionText) {
instructionText.setText("Island colonized! Gained $" + self.colonizationReward);
}
}
LK.getSound('capture').play();
selectedShip.selected = false;
selectedShip.shipGraphics.tint = 0x27ae60; // Reset color
// Remove all armies from ship after landing
selectedShip.armies = 0;
if (selectedShip.armyText) {
selectedShip.armyText.setText("0");
}
selectedShip = null;
updateTerritoryCount();
endPlayerTurn();
return;
} else {
if (instructionText && selectedShip.owner === 1) {
instructionText.setText("Ship must be closer to colonize this island");
}
}
}
// Amphibious assault: allow attacking enemy territory from ship if at war and adjacent
if (selectedShip && !self.isSea && self.owner > 1 && warDeclarations[self.owner]) {
var distance = Math.abs(selectedShip.x - self.x) + Math.abs(selectedShip.y - self.y);
if (distance <= territorySpacing * 1.5 && selectedShip.armies && selectedShip.armies > 0) {
// Simple combat: if ship's armies > defender, take over, else reduce both
var attackPower = selectedShip.armies;
var defensePower = self.armies;
if (attackPower > defensePower) {
self.setOwner(selectedShip.owner, attackPower - defensePower);
selectedShip.armies = 0;
if (selectedShip.armyText) selectedShip.armyText.setText("0");
if (instructionText && selectedShip.owner === 1) {
instructionText.setText("Amphibious assault successful!");
}
LK.getSound('capture').play();
} else {
selectedShip.armies = 0;
if (selectedShip.armyText) selectedShip.armyText.setText("0");
if (defensePower > attackPower) {
self.armies = defensePower - attackPower;
if (self.armyText) self.armyText.setText(self.armies.toString());
}
if (instructionText && selectedShip.owner === 1) {
instructionText.setText("Amphibious assault failed!");
}
LK.getSound('attack').play();
}
selectedShip.selected = false;
selectedShip.shipGraphics.tint = 0x27ae60;
selectedShip = null;
updateTerritoryCount();
endPlayerTurn();
return;
} else if (distance <= territorySpacing * 1.5 && (!selectedShip.armies || selectedShip.armies === 0)) {
if (instructionText && selectedShip.owner === 1) {
instructionText.setText("Ship has no armies to land!");
}
return;
}
}
// Allow colonization of colonizable territory with armies (if adjacent and enough armies)
if (!self.isSea && self.isColonizable && self.owner === 0 && selectedTerritory && selectedTerritory.owner === 1 && !selectedTerritory.isSea) {
// Must be adjacent
var neighbors = getNeighbors(self);
var isNeighbor = false;
for (var i = 0; i < neighbors.length; i++) {
if (neighbors[i] === selectedTerritory) {
isNeighbor = true;
break;
}
}
if (isNeighbor && selectedTerritory.armies > 1) {
// Colonize with armies: move 2 armies, leave at least 1 behind
self.setOwner(1, 2);
self.isColonizable = false;
self.wasColonizable = true; // Mark as previously colonizable for attack logic
// Ensure army text is visible and on top after colonization
if (self.armyText) {
self.armyText.setText(self.armies.toString());
self.removeChild(self.armyText);
self.addChild(self.armyText);
}
selectedTerritory.armies -= 2;
selectedTerritory.armyText.setText(selectedTerritory.armies.toString());
playerMoney += self.colonizationReward;
if (playerMoneyText) {
playerMoneyText.setText("Money: " + playerMoney);
}
if (instructionText) {
instructionText.setText("Island colonized with armies! Gained $" + self.colonizationReward);
}
LK.getSound('capture').play();
updateTerritoryCount();
endPlayerTurn();
return;
} else if (isNeighbor && selectedTerritory.armies <= 1) {
if (instructionText) {
instructionText.setText("Need at least 2 armies to colonize with armies!");
}
return;
}
}
// Allow loading armies from player's territory onto ship if adjacent
if (selectedShip && self.owner === 1 && !self.isSea && self.armies > 1) {
var distance = Math.abs(selectedShip.x - self.x) + Math.abs(selectedShip.y - self.y);
if (distance <= territorySpacing * 1.5) {
// Move up to all but 1 army from territory to ship (max 5 on ship)
var canLoad = Math.min(self.armies - 1, 5 - selectedShip.armies);
if (canLoad > 0) {
self.armies -= canLoad;
selectedShip.armies += canLoad;
if (self.armyText) self.armyText.setText(self.armies.toString());
if (selectedShip.armyText) selectedShip.armyText.setText(selectedShip.armies.toString());
if (instructionText) instructionText.setText("Loaded " + canLoad + " armies onto ship.");
return;
} else {
if (instructionText) instructionText.setText("Ship is full or not enough armies to load.");
return;
}
}
}
selectTerritory(self);
} else if (gameState === 'selectingTarget' && self.showAsTarget) {
executeAttack(self);
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2c3e50
});
/****
* Game Code
****/
// Difficulty selection
var selectedDifficulty = null; // "easy", "medium", "hard"
var difficultyButtons = [];
var difficultyText = null;
// Game state variables
// Territory and game assets
var gameState = 'playing'; // 'playing', 'gameOver', 'victory', 'selectingTarget'
var attackTargets = []; // Available targets for attack
var currentTurn = 1; // 1 = player, 2 = enemy
var selectedTerritory = null;
var territories = [];
var playerTerritories = 0;
var enemyTerritories = 0;
var totalTerritories = 0;
var playerMoney = 100; // Starting money
var aiMoney = 100; // Starting AI money
var incomePerTerritory = 10; // Money generated per territory per turn
// Diplomacy variables
var warDeclarations = {}; // Track which countries we're at war with
var peaceOfferCooldowns = {}; // Track cooldowns for peace offers after rejection
var diplomacyPanel = null;
// Ship variables
var ships = [];
var selectedShip = null;
// Power selection variables
var selectedAttackPower = 1;
var maxAttackPower = 1;
var powerSelectionMode = false;
// UI elements
var turnText, scoreText, instructionText, playerArmyText, playerMoneyText;
var powerText, powerDownButton, powerUpButton;
var actionButtons = [];
// Game settings
var mapWidth = 8;
var mapHeight = 12;
var territorySpacing = 140;
var startX = 2048 / 2 - mapWidth * territorySpacing / 2 + territorySpacing / 2;
var startY = 300;
// Create the game map
function createMap() {
var id = 0;
// We'll store adjacency for sea territories here
var seaAdjacency = {};
// Create contiguous regions for each country with sea territories
// Divide the map into regions for 6 countries
for (var row = 0; row < mapHeight; row++) {
for (var col = 0; col < mapWidth; col++) {
var x = startX + col * territorySpacing;
var y = startY + row * territorySpacing;
var isSea = false;
var owner = 0; // default to neutral/sea
// Create sea lanes (vertical strips)
// Connect the two sea lanes at rows 5 and 6 (expanded connection)
if (col === 2 || col === 5 || (row === 5 || row === 6) && (col === 3 || col === 4)) {
isSea = true;
owner = 0; // Neutral sea
} else {
// Determine owner based on map regions to create contiguous countries
if (row < mapHeight / 3) {
// Top third - countries 1 and 2
if (col < mapWidth / 2) {
owner = 1; // Country 1 (Green) - top left
} else {
owner = 2; // Country 2 (Red) - top right
}
} else if (row < mapHeight * 2 / 3) {
// Middle third - countries 3 and 4
if (col < mapWidth / 2) {
owner = 3; // Country 3 (Blue) - middle left
} else {
owner = 4; // Country 4 (Purple) - middle right
}
} else {
// Bottom third - countries 5 and 6
if (col < mapWidth / 2) {
owner = 5; // Country 5 (Orange) - bottom left
} else {
owner = 6; // Country 6 (Cyan) - bottom right
}
}
// If no specific owner assigned, make it sea
if (owner === 0 && !isSea) {
isSea = true;
}
}
// --- Convert border sea to land ---
// If this tile is at the border and would be sea, convert to land and assign to nearest country
if ((row === 0 || row === mapHeight - 1 || col === 0 || col === mapWidth - 1) && isSea) {
isSea = false;
// Assign to nearest country by region logic
if (row < mapHeight / 3) {
owner = col < mapWidth / 2 ? 1 : 2;
} else if (row < mapHeight * 2 / 3) {
owner = col < mapWidth / 2 ? 3 : 4;
} else {
owner = col < mapWidth / 2 ? 5 : 6;
}
}
var territory = new Territory();
territory.init(id, x, y, owner, isSea);
territories.push(territory);
game.addChild(territory);
id++;
}
}
// Build adjacency for sea territories (by index)
for (var i = 0; i < territories.length; i++) {
if (territories[i].isSea) {
var neighbors = getNeighbors(territories[i]);
seaAdjacency[i] = [];
for (var j = 0; j < neighbors.length; j++) {
if (neighbors[j].isSea) {
var neighborIndex = territories.indexOf(neighbors[j]);
if (neighborIndex !== -1) {
seaAdjacency[i].push(neighborIndex);
}
}
}
}
}
// Attach adjacency info to each sea territory for easy access
for (var i = 0; i < territories.length; i++) {
if (territories[i].isSea) {
territories[i].adjacentSeaIndices = seaAdjacency[i];
}
}
// (Colonizable islands removed)
// Create initial ships for player and enemy
createShips();
updateTerritoryCount();
}
// Create initial ships
function createShips() {
// Find sea territories for ship placement
var seaTerritories = [];
for (var i = 0; i < territories.length; i++) {
if (territories[i].isSea) {
seaTerritories.push(territories[i]);
}
}
// Place initial ships
if (seaTerritories.length > 0) {
// Player ship - automatically select it to start on the ship
var playerShip = new Ship();
var playerSeaPos = seaTerritories[Math.floor(Math.random() * seaTerritories.length)];
playerShip.init(1, playerSeaPos.x, playerSeaPos.y);
playerShip.armies = 2;
if (playerShip.armyText) playerShip.armyText.setText("2");
ships.push(playerShip);
// Auto-select the player ship so they start on it
selectShip(playerShip);
// Enemy ship
var enemyShip = new Ship();
var enemySeaPos = seaTerritories[Math.floor(Math.random() * seaTerritories.length)];
enemyShip.init(2, enemySeaPos.x, enemySeaPos.y);
enemyShip.armies = 0;
if (enemyShip.armyText) enemyShip.armyText.setText("0");
ships.push(enemyShip);
// Ensure ships are always rendered above sea territories by adding them after all territories are added
game.addChild(playerShip);
game.addChild(enemyShip);
}
}
// Ship selection
function selectShip(ship) {
if (selectedDifficulty === null) return;
if (currentTurn !== 1) return;
// Deselect previous selections
if (selectedTerritory) {
selectedTerritory.selected = false;
selectedTerritory.updateGraphics();
selectedTerritory = null;
}
if (selectedShip) {
selectedShip.selected = false;
selectedShip.shipGraphics.tint = 0x27ae60; // Reset to green
}
// Select new ship
selectedShip = ship;
ship.selected = true;
ship.shipGraphics.tint = 0xf1c40f; // Yellow when selected
// Update armyText in case it was changed
if (ship.armyText) {
ship.armyText.setText(ship.armies.toString());
}
// Remove all possible move highlights when selecting a ship, only show on click
for (var i = 0; i < territories.length; i++) {
if (territories[i].isSea) {
territories[i].showAsTarget = false;
territories[i].updateGraphics();
}
}
// Do not show possible moves here; will be shown on ship click (down event)
hidePowerSelection();
updateInstructions();
}
// Generate income based on territories owned
function generateIncome() {
var income = playerTerritories * incomePerTerritory;
playerMoney += income;
if (playerMoneyText) {
playerMoneyText.setText("Money: " + playerMoney + " (+$" + income + ")");
}
}
// Update territory ownership counts
function updateTerritoryCount() {
playerTerritories = 0;
enemyTerritories = 0;
var playerTotalArmies = 0;
var country1Count = 0,
country2Count = 0,
country3Count = 0;
var country4Count = 0,
country5Count = 0,
country6Count = 0;
totalTerritories = territories.length;
for (var i = 0; i < territories.length; i++) {
if (territories[i].owner === 1) {
playerTerritories++;
country1Count++;
playerTotalArmies += territories[i].armies;
} else if (territories[i].owner === 2) {
enemyTerritories++;
country2Count++;
} else if (territories[i].owner === 3) {
country3Count++;
} else if (territories[i].owner === 4) {
country4Count++;
} else if (territories[i].owner === 5) {
country5Count++;
} else if (territories[i].owner === 6) {
country6Count++;
}
}
// (Removed scoreText update for country colors and territory counts)
// Update player army display
if (playerArmyText) {
playerArmyText.setText("Total Armies: " + playerTotalArmies);
}
// Update money display
if (playerMoneyText) {
playerMoneyText.setText("Money: " + playerMoney);
}
// Check victory conditions
// Count total non-sea territories
var totalNonSeaTerritories = 0;
for (var i = 0; i < territories.length; i++) {
if (!territories[i].isSea) {
totalNonSeaTerritories++;
}
}
if (playerTerritories === totalNonSeaTerritories) {
gameState = 'victory';
LK.showYouWin();
} else if (enemyTerritories >= Math.floor(totalTerritories * 0.75)) {
gameState = 'gameOver';
LK.showGameOver();
} else if (playerTerritories === 0) {
gameState = 'gameOver';
LK.showGameOver();
}
}
// Declare war function
function declareWar(countryId) {
warDeclarations[countryId] = true;
if (instructionText) {
instructionText.setText("War declared on Country " + countryId + "! You can now attack their territories.");
}
// If diplomacyPanel is open, update buttons
if (diplomacyPanel && diplomacyPanel.targetCountry === countryId) {
diplomacyPanel.updateButtons();
}
}
// Make peace function
function makePeace(countryId) {
if (selectedDifficulty === "hardcore") {
if (instructionText) {
instructionText.setText("Peace treaties are disabled in Hardcore mode!");
}
return;
}
// Prevent peace offer if cooldown is active
if (peaceOfferCooldowns[countryId] && peaceOfferCooldowns[countryId] > 0) {
if (instructionText) {
instructionText.setText("You must wait " + peaceOfferCooldowns[countryId] + " turns before offering peace to Country " + countryId + " again.");
}
return;
}
if (warDeclarations[countryId]) {
// In easy mode, always accept peace treaty
if (selectedDifficulty === "easy" || Math.random() < 0.5) {
warDeclarations[countryId] = false;
if (instructionText) {
instructionText.setText("Peace treaty signed with Country " + countryId + ". You can no longer attack their territories.");
}
// If diplomacyPanel is open, update buttons
if (diplomacyPanel && diplomacyPanel.targetCountry === countryId) {
diplomacyPanel.updateButtons();
}
if (peaceOfferCooldowns[countryId]) peaceOfferCooldowns[countryId] = 0; // Reset cooldown on acceptance
} else {
if (instructionText) {
instructionText.setText("Peace treaty rejected by Country " + countryId + "!");
}
// Set cooldown for 10 turns after rejection
peaceOfferCooldowns[countryId] = 10;
}
}
}
// Territory selection
function selectTerritory(territory) {
if (selectedDifficulty === null) return;
if (currentTurn !== 1) return; // Only during player turn
// If we're in target selection mode, cancel it
if (gameState === 'selectingTarget') {
// Clear target highlighting
for (var i = 0; i < attackTargets.length; i++) {
attackTargets[i].showAsTarget = false;
attackTargets[i].updateGraphics();
}
gameState = 'playing';
attackTargets = [];
}
// Deselect previous territory
if (selectedTerritory) {
selectedTerritory.selected = false;
selectedTerritory.updateGraphics();
// Ensure previous territory's army text remains visible
selectedTerritory.armyText.setText(selectedTerritory.armies.toString());
// Re-add army text to ensure it's visible
selectedTerritory.removeChild(selectedTerritory.armyText);
selectedTerritory.addChild(selectedTerritory.armyText);
}
// Handle enemy territory clicks - show diplomacy panel
if (territory.owner !== 1 && territory.owner !== 0) {
// Create diplomacy panel if it doesn't exist
if (!diplomacyPanel) {
diplomacyPanel = new DiplomacyPanel();
diplomacyPanel.init(territory.owner);
} else {
// Update existing panel for new country
diplomacyPanel.targetCountry = territory.owner;
diplomacyPanel.titleText.setText("Diplomacy with Country " + territory.owner);
if (diplomacyPanel.updateButtons) diplomacyPanel.updateButtons();
}
diplomacyPanel.show();
return;
}
// Select new territory
if (territory.owner === 1) {
// Only select player territories
selectedTerritory = territory;
territory.selected = true;
territory.updateGraphics();
// Ensure army text is visible and updated
territory.armyText.setText(territory.armies.toString());
// Bring army text to front to ensure it's visible
territory.removeChild(territory.armyText);
territory.addChild(territory.armyText);
// Show power selection for territories with armies > 1
if (!territory.isSea && territory.armies > 1) {
showPowerSelection(territory.armies - 1);
} else {
hidePowerSelection();
}
updateInstructions();
} else {
hidePowerSelection();
}
}
// Get neighboring territories
function getNeighbors(territory) {
var neighbors = [];
var index = territories.indexOf(territory);
var row = Math.floor(index / mapWidth);
var col = index % mapWidth;
// Check all 4 directions
var directions = [{
row: -1,
col: 0
},
// up
{
row: 1,
col: 0
},
// down
{
row: 0,
col: -1
},
// left
{
row: 0,
col: 1
} // right
];
for (var i = 0; i < directions.length; i++) {
var newRow = row + directions[i].row;
var newCol = col + directions[i].col;
if (newRow >= 0 && newRow < mapHeight && newCol >= 0 && newCol < mapWidth) {
var neighborIndex = newRow * mapWidth + newCol;
neighbors.push(territories[neighborIndex]);
}
}
return neighbors;
}
// Attack action
function attackTerritory() {
if (selectedDifficulty === null) return;
if (!selectedTerritory || selectedTerritory.armies <= 1) return;
var neighbors = getNeighbors(selectedTerritory);
var targets = [];
for (var i = 0; i < neighbors.length; i++) {
if (neighbors[i].owner !== 1) {
// Allow attacking if:
// - Neutral (owner 0)
// - At war with the country
// - The territory was previously colonizable and is now enemy-owned (owner 2-6)
// - The territory was a neutral/colonizable territory, is now enemy-owned, and we are at war with that enemy
var n = neighbors[i];
var canAttack = false;
if (n.owner === 0) {
canAttack = true;
} else if (warDeclarations[n.owner]) {
canAttack = true;
} else if (n.owner > 1 && n.owner <= 6 && n.isColonizable === true) {
canAttack = true;
} else if (n.owner > 1 && n.owner <= 6 && typeof n.wasColonizable !== "undefined" && n.wasColonizable === true && warDeclarations[n.owner]) {
// If this territory was previously colonizable, is now enemy-owned, and we are at war with that enemy
canAttack = true;
}
if (canAttack) {
targets.push(n);
}
}
}
if (targets.length > 0) {
// Show target selection mode
gameState = 'selectingTarget';
attackTargets = targets;
// Highlight all possible targets
for (var i = 0; i < targets.length; i++) {
targets[i].showAsTarget = true;
targets[i].updateGraphics();
}
if (instructionText) {
instructionText.setText("Select a territory to attack");
}
}
}
// Execute attack on selected target
function executeAttack(target) {
if (!selectedTerritory || !target) return;
// Clear target highlighting
for (var i = 0; i < attackTargets.length; i++) {
attackTargets[i].showAsTarget = false;
attackTargets[i].updateGraphics();
}
// Simple combat resolution using selected attack power
var attackPower = selectedAttackPower;
var defensePower = target.armies;
if (attackPower > defensePower) {
// Victory
target.setOwner(1, attackPower - defensePower);
selectedTerritory.armies = selectedTerritory.armies - attackPower;
selectedTerritory.armyText.setText(selectedTerritory.armies.toString());
LK.getSound('capture').play();
} else {
// Defeat - lose the armies used in attack
selectedTerritory.armies = selectedTerritory.armies - attackPower;
selectedTerritory.armyText.setText(selectedTerritory.armies.toString());
if (defensePower > attackPower) {
target.armies = defensePower - attackPower;
target.armyText.setText(target.armies.toString());
}
}
LK.getSound('attack').play();
updateTerritoryCount();
// Reset game state
gameState = 'playing';
attackTargets = [];
endPlayerTurn();
}
// Recruit armies action
function recruitArmies() {
if (selectedDifficulty === null) return;
if (!selectedTerritory) return;
var recruitCost = 100; // Increased cost to recruit armies
if (playerMoney >= recruitCost) {
playerMoney -= recruitCost;
selectedTerritory.addArmies(2);
if (playerMoneyText) {
playerMoneyText.setText("Money: " + playerMoney);
}
endPlayerTurn();
} else {
// Not enough money - show feedback but don't end turn
if (instructionText) {
instructionText.setText("Not enough money! Need $" + recruitCost + " to recruit");
}
}
}
// Build ship action
function buildShip() {
if (selectedDifficulty === null) return;
if (!selectedTerritory || selectedTerritory.isSea) return;
var shipCost = 200; //{4Z} // Increased cost
// Determine which country's money to use
var owner = selectedTerritory.owner;
if (owner === 0 || owner === undefined) return; // Only countries can build ships
// Only allow if the country has enough money
var canBuild = false;
if (owner === 1 && playerMoney >= shipCost) {
canBuild = true;
} else if (owner === 2 && aiMoney >= shipCost) {
canBuild = true;
} else if (owner > 2) {
// For AI countries 3-6, give them their own money pool if not present
if (typeof window['countryMoney' + owner] === "undefined") {
window['countryMoney' + owner] = 100;
}
if (window['countryMoney' + owner] >= shipCost) {
canBuild = true;
}
}
if (canBuild) {
// Find adjacent sea territory
var neighbors = getNeighbors(selectedTerritory);
var seaNeighbors = [];
for (var i = 0; i < neighbors.length; i++) {
if (neighbors[i].isSea) {
seaNeighbors.push(neighbors[i]);
}
}
if (seaNeighbors.length > 0) {
// Deduct money from the correct pool
if (owner === 1) {
playerMoney -= shipCost;
} else if (owner === 2) {
aiMoney -= shipCost;
} else if (owner > 2) {
window['countryMoney' + owner] -= shipCost;
}
var seaPos = seaNeighbors[0];
var newShip = new Ship();
newShip.init(owner, seaPos.x, seaPos.y);
ships.push(newShip);
// Ensure new ships are rendered above sea territories
game.addChild(newShip);
if (owner === 1 && playerMoneyText) {
playerMoneyText.setText("Money: " + playerMoney);
}
endPlayerTurn();
} else {
if (instructionText && owner === 1) {
instructionText.setText("No adjacent sea territory to build ship!");
}
}
} else {
if (instructionText && owner === 1) {
instructionText.setText("Not enough money! Need $" + shipCost + " to build ship");
}
}
}
// Naval combat
function navalCombat(attackerShip, defenderShip) {
var damage = 1;
var defenderDestroyed = defenderShip.takeDamage(damage);
if (defenderDestroyed) {
// Remove destroyed ship
var index = ships.indexOf(defenderShip);
if (index > -1) {
ships.splice(index, 1);
}
defenderShip.destroy();
LK.getSound('capture').play();
} else {
LK.getSound('attack').play();
}
}
// Per-country ship build timers for AI countries 2-6
// All countries (1-6) can build ships, recruit armies, declare war, and colonize
var countryShipTimers = {};
// Per-country war declaration timers for AI countries 2-6 (enemy and other AIs)
var countryWarTimers = {};
for (var c = 2; c <= 6; c++) {
// For war timers: if not at war, 12 turns; if at war, 30 turns (will be set dynamically in aiTurn)
countryWarTimers[c] = Math.floor(Math.random() * 3) + 10; // randomize initial timer between 10-12
}
for (var c = 2; c <= 6; c++) {
// All AI countries 2-6: build ships every 3-5 turns by default
countryShipTimers[c] = Math.floor(Math.random() * 3) + 3;
}
// End player turn
function endPlayerTurn() {
if (selectedTerritory) {
selectedTerritory.selected = false;
selectedTerritory.updateGraphics();
selectedTerritory = null;
hidePowerSelection();
}
hidePowerSelection();
// Generate income based on territories owned
generateIncome();
// Decrease peace offer cooldowns at end of player turn
for (var k in peaceOfferCooldowns) {
if (peaceOfferCooldowns.hasOwnProperty(k) && peaceOfferCooldowns[k] > 0) {
peaceOfferCooldowns[k]--;
}
}
currentTurn = 2;
updateInstructions();
// AI turn after short delay
LK.setTimeout(function () {
aiTurn();
}, 1000);
}
// Helper: AI build ship for a country if possible
function aiBuildShipForCountry(countryId) {
// Find all territories owned by this country
var owned = [];
for (var i = 0; i < territories.length; i++) {
if (territories[i].owner === countryId && !territories[i].isSea) {
owned.push(territories[i]);
}
}
// Try to build ship from a random owned territory with adjacent sea
if (owned.length > 0) {
var t = owned[Math.floor(Math.random() * owned.length)];
var neighbors = getNeighbors(t);
var seaNeighbors = [];
for (var j = 0; j < neighbors.length; j++) {
if (neighbors[j].isSea) seaNeighbors.push(neighbors[j]);
}
if (seaNeighbors.length > 0) {
// Deduct money if needed (handled in buildShip, but we do it here for AI)
if (typeof window['countryMoney' + countryId] === "undefined") {
window['countryMoney' + countryId] = 100;
}
var shipCost = 200;
if (window['countryMoney' + countryId] >= shipCost) {
window['countryMoney' + countryId] -= shipCost;
var seaPos = seaNeighbors[0];
var newShip = new Ship();
newShip.init(countryId, seaPos.x, seaPos.y);
ships.push(newShip);
game.addChild(newShip);
return true;
}
}
}
return false;
}
// Simple AI turn
function aiTurn() {
// Generate AI income
var aiIncome = enemyTerritories * incomePerTerritory;
aiMoney += aiIncome;
var enemyTerrs = [];
for (var i = 0; i < territories.length; i++) {
if (territories[i].owner === 2) {
enemyTerrs.push(territories[i]);
}
}
if (enemyTerrs.length > 0) {
var aiTerritory = enemyTerrs[Math.floor(Math.random() * enemyTerrs.length)];
var neighbors = getNeighbors(aiTerritory);
var playerTargets = [];
// In easy mode, AI never attacks
if (selectedDifficulty === "easy") {
// AI does not attack, just does economy/ship/army actions below
playerTargets = [];
} else {
for (var j = 0; j < neighbors.length; j++) {
// AI can attack player territories if war is declared on AI (country 2)
if (neighbors[j].owner === 1 && warDeclarations[2]) {
playerTargets.push(neighbors[j]);
}
}
}
if (playerTargets.length > 0 && aiTerritory.armies > 1) {
// AI attacks
var target = playerTargets[Math.floor(Math.random() * playerTargets.length)];
var attackPower = aiTerritory.armies - 1;
var defensePower = target.armies;
if (attackPower > defensePower) {
target.setOwner(2, attackPower - defensePower);
aiTerritory.armies = 1;
aiTerritory.armyText.setText(aiTerritory.armies.toString());
} else {
aiTerritory.armies = 1;
aiTerritory.armyText.setText(aiTerritory.armies.toString());
if (defensePower > attackPower) {
target.armies = defensePower - attackPower;
target.armyText.setText(target.armies.toString());
}
}
} else {
// AI decides what to do based on money and strategy
var action = Math.random();
var recruitCost = 50;
var shipCost = 100;
if (action < 0.4 && aiMoney >= recruitCost) {
// 40% chance to recruit armies if affordable
aiMoney -= recruitCost;
aiTerritory.addArmies(2);
} else if (action < 0.7 && aiMoney >= shipCost) {
// 30% chance to build ship if possible and affordable
var seaNeighbors = [];
for (var k = 0; k < neighbors.length; k++) {
if (neighbors[k].isSea) {
seaNeighbors.push(neighbors[k]);
}
}
if (seaNeighbors.length > 0) {
// Build ship in adjacent sea
aiMoney -= shipCost;
var seaPos = seaNeighbors[0];
var newShip = new Ship();
newShip.init(2, seaPos.x, seaPos.y);
ships.push(newShip);
// Ensure AI ships are rendered above sea territories
game.addChild(newShip);
} else {
// No sea nearby, recruit if affordable or just add basic army
if (aiMoney >= recruitCost) {
aiMoney -= recruitCost;
aiTerritory.addArmies(2);
} else {
aiTerritory.addArmies(1);
}
}
} else {
// Default action - add basic army (free)
aiTerritory.addArmies(1);
}
}
}
// AI war declaration logic for hard difficulty
if (selectedDifficulty === "hard") {
// --- Special: Country 6 always declares war on country 5 every 5 turns ---
if (typeof window.country6War5Timer === "undefined") {
window.country6War5Timer = 5;
}
window.country6War5Timer--;
if (window.country6War5Timer <= 0) {
if (!warDeclarations[5]) {
warDeclarations[5] = true;
if (instructionText) {
instructionText.setText("Country 6 has declared war on Country 5!");
}
}
window.country6War5Timer = 5;
}
// --- New: AI countries declare war on weaker neighbors if stronger ---
for (var c = 2; c <= 6; c++) {
// Only consider if not already at war with all other countries
for (var i = 0; i < territories.length; i++) {
if (territories[i].owner === c && !territories[i].isSea) {
var neighbors = getNeighbors(territories[i]);
for (var j = 0; j < neighbors.length; j++) {
var neighbor = neighbors[j];
// Only consider land neighbors owned by another country (not self, not neutral, not sea)
if (neighbor.owner !== c && neighbor.owner > 0 && neighbor.owner <= 6 && !neighbor.isSea && !warDeclarations[neighbor.owner]) {
// If AI's territory has more armies than neighbor, declare war
if (territories[i].armies > neighbor.armies) {
warDeclarations[neighbor.owner] = true;
if (neighbor.owner === 1 && instructionText) {
instructionText.setText("Country " + c + " has declared war on you due to your weak border!");
}
}
}
}
}
}
}
// --- AI peace offer logic (not in hardcore) ---
if (selectedDifficulty !== "hardcore") {
for (var c = 2; c <= 6; c++) {
// If AI country is at war with player, has lost territories, and random chance, offer peace
if (warDeclarations[c]) {
// Count AI's territories
var aiTerrCount = 0;
for (var i = 0; i < territories.length; i++) {
if (territories[i].owner === c && !territories[i].isSea) {
aiTerrCount++;
}
}
// If AI is weak (few territories) or random chance, offer peace
if (aiTerrCount < 3 || Math.random() < 0.15) {
// 50% chance player accepts, always accept in easy mode
if (selectedDifficulty === "easy" || Math.random() < 0.5) {
warDeclarations[c] = false;
if (instructionText) {
instructionText.setText("Country " + c + " has offered a peace treaty. Peace has been established!");
}
if (diplomacyPanel && diplomacyPanel.targetCountry === c) {
diplomacyPanel.updateButtons();
}
} else {
if (instructionText) {
instructionText.setText("Country " + c + " has offered a peace treaty, but you rejected it!");
}
}
}
}
}
}
// AI countries 2-6 may declare war more frequently
for (var c = 2; c <= 6; c++) {
// Only consider declaring war on countries we are not already at war with
if (!warDeclarations[c]) {
countryWarTimers[c]--;
if (countryWarTimers[c] <= 0) {
// Declare war on a random other country (not self)
var possibleTargets = [];
for (var t = 1; t <= 6; t++) {
if (t !== c && !warDeclarations[t]) {
possibleTargets.push(t);
}
}
if (possibleTargets.length > 0) {
var target = possibleTargets[Math.floor(Math.random() * possibleTargets.length)];
warDeclarations[target] = true;
// Optionally, show a message if the player is the target
if (target === 1 && instructionText) {
instructionText.setText("Country " + c + " has declared war on you!");
}
}
// Reset timer for next declaration (12 turns if not at war, 30 if at war)
if (warDeclarations[c]) {
countryWarTimers[c] = 30;
} else {
countryWarTimers[c] = 12;
}
}
} else {
// If already at war, use longer timer before next declaration
countryWarTimers[c]--;
if (countryWarTimers[c] <= 0) {
// Try to declare war on another country (not self, not already at war)
var possibleTargets = [];
for (var t = 1; t <= 6; t++) {
if (t !== c && !warDeclarations[t]) {
possibleTargets.push(t);
}
}
if (possibleTargets.length > 0) {
var target = possibleTargets[Math.floor(Math.random() * possibleTargets.length)];
warDeclarations[target] = true;
if (target === 1 && instructionText) {
instructionText.setText("Country " + c + " has declared war on you!");
}
}
// Reset timer for next declaration (30 turns if at war)
countryWarTimers[c] = 30;
}
}
}
}
// In easy mode, AI never declares war (handled by not attacking above)
// AI countries 2-6: build ships every 3-5 turns if possible
for (var c = 2; c <= 6; c++) {
if (typeof countryShipTimers[c] === "undefined") {
countryShipTimers[c] = Math.floor(Math.random() * 3) + 3;
}
countryShipTimers[c]--;
if (countryShipTimers[c] <= 0) {
var built = aiBuildShipForCountry(c);
countryShipTimers[c] = Math.floor(Math.random() * 3) + 3;
}
}
// All AI countries 2-6: recruit armies every turn if possible
for (var c = 2; c <= 6; c++) {
for (var i = 0; i < territories.length; i++) {
if (territories[i].owner === c && !territories[i].isSea) {
if (typeof window['countryMoney' + c] === "undefined") {
window['countryMoney' + c] = 100;
}
var recruitCost = 50;
if (window['countryMoney' + c] >= recruitCost) {
window['countryMoney' + c] -= recruitCost;
territories[i].addArmies(2);
}
}
}
}
// AI ship movement and naval combat
// Loop for all AI countries (2-6) to give each their own ship logic
for (var aiCountry = 2; aiCountry <= 6; aiCountry++) {
var aiShips = [];
for (var i = 0; i < ships.length; i++) {
if (ships[i].owner === aiCountry) {
aiShips.push(ships[i]);
}
}
if (aiShips.length > 0) {
var aiShip = aiShips[Math.floor(Math.random() * aiShips.length)];
// Look for enemy ships to attack (player or any other country at war)
var enemyShips = [];
for (var i = 0; i < ships.length; i++) {
if (ships[i].owner !== aiCountry && ships[i].owner !== 0) {
// Only attack if at war or if player (for country 2)
if (aiCountry === 2) {
if (ships[i].owner === 1 && warDeclarations[2]) {
var distance = Math.abs(ships[i].x - aiShip.x) + Math.abs(ships[i].y - aiShip.y);
if (distance < 200) {
enemyShips.push(ships[i]);
}
}
} else {
// For AI countries 3-6, attack ships of any country at war
if (warDeclarations[aiCountry] || warDeclarations[ships[i].owner]) {
var distance = Math.abs(ships[i].x - aiShip.x) + Math.abs(ships[i].y - aiShip.y);
if (distance < 200) {
enemyShips.push(ships[i]);
}
}
}
}
}
if (enemyShips.length > 0) {
// Attack nearest enemy ship
var target = enemyShips[0];
navalCombat(aiShip, target);
} else {
// Look for colonizable territories
var colonizableTargets = [];
for (var i = 0; i < territories.length; i++) {
if (territories[i].isColonizable && territories[i].owner === 0 && !territories[i].isSea) {
var distance = Math.abs(territories[i].x - aiShip.x) + Math.abs(territories[i].y - aiShip.y);
if (distance <= territorySpacing * 1.5) {
colonizableTargets.push(territories[i]);
}
}
}
if (colonizableTargets.length > 0) {
// Colonize nearest available territory
var target = colonizableTargets[0];
target.setOwner(aiCountry, 2);
target.isColonizable = false; // No longer colonizable
target.wasColonizable = true; // Mark as previously colonizable for attack logic
// Give money to correct AI pool
if (aiCountry === 2) {
aiMoney += target.colonizationReward;
} else {
if (typeof window['countryMoney' + aiCountry] === "undefined") {
window['countryMoney' + aiCountry] = 100;
}
window['countryMoney' + aiCountry] += target.colonizationReward;
}
} else {
// Move to random sea territory or towards colonizable islands
var moveTargets = [];
// Add sea territories
for (var i = 0; i < territories.length; i++) {
if (territories[i].isSea) {
moveTargets.push(territories[i]);
}
}
// Add positions near colonizable islands
for (var i = 0; i < territories.length; i++) {
if (territories[i].isColonizable && territories[i].owner === 0) {
moveTargets.push(territories[i]);
}
}
if (moveTargets.length > 0) {
var newPos = moveTargets[Math.floor(Math.random() * moveTargets.length)];
aiShip.x = newPos.x;
aiShip.y = newPos.y;
}
}
}
}
}
updateTerritoryCount();
// Decrease peace offer cooldowns at end of AI turn
for (var k in peaceOfferCooldowns) {
if (peaceOfferCooldowns.hasOwnProperty(k) && peaceOfferCooldowns[k] > 0) {
peaceOfferCooldowns[k]--;
}
}
currentTurn = 1;
updateInstructions();
}
// Create UI elements
function createUI() {
// Turn indicator
turnText = new Text2("Your Turn", {
size: 40,
fill: 0xFFFFFF
});
turnText.anchor.set(0.5, 0);
LK.gui.top.addChild(turnText);
turnText.y = 100;
// (Removed scoreText display for country colors and territory counts)
// Player army count display
playerArmyText = new Text2("Total Armies: 0", {
size: 32,
fill: 0x7ed321
});
playerArmyText.anchor.set(0.5, 0);
LK.gui.top.addChild(playerArmyText);
playerArmyText.y = 190;
// Player money display
playerMoneyText = new Text2("Money: " + playerMoney, {
size: 32,
fill: 0xf5a623
});
playerMoneyText.anchor.set(0.5, 0);
LK.gui.top.addChild(playerMoneyText);
playerMoneyText.y = 230;
// Instructions
instructionText = new Text2("Select your territory, then choose an action", {
size: 28,
fill: 0xFFFFFF
});
instructionText.anchor.set(0.5, 1);
LK.gui.bottom.addChild(instructionText);
instructionText.y = -200;
// Action buttons
var attackBtn = new ActionButton();
attackBtn.init("Attack", attackTerritory, 2048 / 2 - 200, 2732 - 120);
actionButtons.push(attackBtn);
game.addChild(attackBtn);
var recruitBtn = new ActionButton();
recruitBtn.init("Recruit", recruitArmies, 2048 / 2 - 60, 2732 - 120);
actionButtons.push(recruitBtn);
game.addChild(recruitBtn);
var buildShipBtn = new ActionButton();
buildShipBtn.init("Build Ship", buildShip, 2048 / 2 + 80, 2732 - 120);
actionButtons.push(buildShipBtn);
game.addChild(buildShipBtn);
// Skip Turn button
var skipTurnBtn = new ActionButton();
skipTurnBtn.init("Skip Turn", function () {
if (selectedDifficulty === null) return;
if (currentTurn === 1) {
endPlayerTurn();
}
}, 2048 / 2 + 220, 2732 - 120);
actionButtons.push(skipTurnBtn);
game.addChild(skipTurnBtn);
// Power selection display
powerText = new Text2("Attack Power: 1/1", {
size: 28,
fill: 0xffff00
});
powerText.anchor.set(0.5, 1);
LK.gui.bottom.addChild(powerText);
powerText.y = -240;
powerText.visible = false;
// Power adjustment buttons
var powerDownBtn = new ActionButton();
powerDownBtn.init("-", decreasePower, 2048 / 2 - 100, 2732 - 180);
actionButtons.push(powerDownBtn);
game.addChild(powerDownBtn);
powerDownBtn.visible = false;
var powerUpBtn = new ActionButton();
powerUpBtn.init("+", increasePower, 2048 / 2 + 100, 2732 - 180);
actionButtons.push(powerUpBtn);
game.addChild(powerUpBtn);
powerUpBtn.visible = false;
// Store power buttons for visibility control
powerDownButton = powerDownBtn;
powerUpButton = powerUpBtn;
}
// Power selection functions
function decreasePower() {
if (selectedDifficulty === null) return;
if (selectedAttackPower > 1) {
selectedAttackPower--;
updatePowerDisplay();
}
}
function increasePower() {
if (selectedDifficulty === null) return;
if (selectedAttackPower < maxAttackPower) {
selectedAttackPower++;
updatePowerDisplay();
}
}
function updatePowerDisplay() {
if (powerText) {
powerText.setText("Attack Power: " + selectedAttackPower + "/" + maxAttackPower);
}
}
function showPowerSelection(maxPower) {
maxAttackPower = maxPower;
selectedAttackPower = Math.min(selectedAttackPower, maxAttackPower);
powerSelectionMode = true;
if (powerText) {
powerText.visible = true;
updatePowerDisplay();
}
if (powerDownButton && powerUpButton) {
powerDownButton.visible = true;
powerUpButton.visible = true;
}
}
function hidePowerSelection() {
powerSelectionMode = false;
if (powerText) {
powerText.visible = false;
}
if (powerDownButton && powerUpButton) {
powerDownButton.visible = false;
powerUpButton.visible = false;
}
}
// Update instruction text
function updateInstructions() {
if (selectedDifficulty === null) {
if (instructionText) {
instructionText.setText("Please select a difficulty (Easy, Medium, Hard)");
}
return;
}
if (currentTurn === 1) {
if (turnText) {
turnText.setText("Your Turn");
}
if (instructionText) {
if (selectedShip) {
instructionText.setText("Ship selected - Move to sea or attack enemy ships");
} else if (selectedTerritory) {
if (selectedTerritory.isSea) {
instructionText.setText("Sea territory selected - Ships can move here");
} else if (powerSelectionMode) {
instructionText.setText("Use +/- to choose attack power, then Attack, Recruit ($100), or Build Ship ($200)");
} else {
instructionText.setText("Territory selected - Attack, Recruit ($100), or Build Ship ($200)");
}
} else {
instructionText.setText("Select your territory/ship (green), then choose an action");
}
}
} else {
if (turnText) {
turnText.setText("Enemy Turn");
}
if (instructionText) {
instructionText.setText("Enemy is thinking...");
}
}
}
// Game update loop for naval combat highlighting
game.update = function () {
// Highlight enemy ships in combat range when player ship is selected
if (selectedShip && selectedShip.owner === 1) {
for (var i = 0; i < ships.length; i++) {
if (ships[i].owner === 2) {
var distance = Math.abs(selectedShip.x - ships[i].x) + Math.abs(selectedShip.y - ships[i].y);
if (distance < 200) {
// Highlight enemy ship in range
ships[i].shipGraphics.tint = 0xff6b6b; // Red tint for attackable
} else {
ships[i].shipGraphics.tint = 0xe74c3c; // Default red for enemy
}
}
}
} else {
// Reset all ship colors when no ship selected
for (var i = 0; i < ships.length; i++) {
if (ships[i].owner === 2) {
ships[i].shipGraphics.tint = 0xe74c3c; // Default red for enemy
} else if (ships[i].owner === 1 && ships[i] !== selectedShip) {
ships[i].shipGraphics.tint = 0x27ae60; // Default green for player
}
}
}
};
// Difficulty selection UI
function showDifficultySelection() {
// Block all game actions until difficulty is selected
gameState = "selectingDifficulty";
// Hide all action buttons
for (var i = 0; i < actionButtons.length; i++) {
actionButtons[i].visible = false;
}
// Hide power selection
hidePowerSelection();
// Create a full-screen overlay container for difficulty selection
if (typeof difficultyOverlay !== "undefined" && difficultyOverlay.parent) {
difficultyOverlay.parent.removeChild(difficultyOverlay);
}
difficultyOverlay = new Container();
difficultyOverlay.x = 0;
difficultyOverlay.y = 0;
// Add a semi-transparent background to block game interaction
var overlayBg = LK.getAsset('selectedTerritory', {
anchorX: 0,
anchorY: 0,
scaleX: 2048 / 120,
scaleY: 2732 / 120
});
overlayBg.alpha = 0.85;
overlayBg.tint = 0x222222;
difficultyOverlay.addChild(overlayBg);
// Show difficulty selection text
difficultyText = new Text2("Select Difficulty", {
size: 60,
fill: 0xffffff
});
difficultyText.anchor.set(0.5, 0.5);
difficultyText.x = 2048 / 2;
difficultyText.y = 2732 / 2 - 200;
difficultyOverlay.addChild(difficultyText);
// Button positions
var btnY = 2732 / 2;
var btnSpacing = 220;
var btnLabels = [{
label: "Easy",
value: "easy"
}, {
label: "Medium",
value: "medium"
}, {
label: "Hard",
value: "hard"
}, {
label: "Hardcore",
value: "hardcore"
}];
for (var i = 0; i < btnLabels.length; i++) {
var btn = new ActionButton();
btn.init(btnLabels[i].label, function (difficulty) {
return function () {
selectDifficulty(difficulty);
};
}(btnLabels[i].value), 2048 / 2 + (i - 1.5) * btnSpacing, btnY);
difficultyButtons.push(btn);
difficultyOverlay.addChild(btn);
}
// Add overlay to game
game.addChild(difficultyOverlay);
}
// Remove difficulty selection UI and start the game
function selectDifficulty(difficulty) {
selectedDifficulty = difficulty;
// If hardcore, set war with all countries (2-6) and block peace
if (selectedDifficulty === "hardcore") {
for (var c = 2; c <= 6; c++) {
warDeclarations[c] = true;
}
}
// Remove difficulty UI overlay
if (typeof difficultyOverlay !== "undefined" && difficultyOverlay.parent) {
difficultyOverlay.parent.removeChild(difficultyOverlay);
}
difficultyButtons = [];
// Show action buttons
for (var i = 0; i < actionButtons.length; i++) {
actionButtons[i].visible = true;
}
// Set game state to playing and update UI
gameState = "playing";
updateInstructions();
}
// Initialize the game
createMap();
createUI();
showDifficultySelection();
updateInstructions(); /****
* Classes
****/
var ActionButton = Container.expand(function () {
var self = Container.call(this);
self.init = function (text, action, x, y) {
self.action = action;
// Button graphics
self.buttonGraphics = self.attachAsset('actionButton', {
anchorX: 0.5,
anchorY: 0.5
});
// Button text
self.buttonText = new Text2(text, {
size: 28,
fill: 0xFFFFFF
});
self.buttonText.anchor.set(0.5, 0.5);
self.addChild(self.buttonText);
self.x = x;
self.y = y;
return self;
};
self.down = function (x, y, obj) {
if (self.action) {
self.action();
}
};
return self;
});
var DiplomacyPanel = Container.expand(function () {
var self = Container.call(this);
self.init = function (targetCountry) {
self.targetCountry = targetCountry;
self.visible = false;
// Panel background
self.panelBg = LK.getAsset('diplomacypanel', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 3,
scaleY: 4
});
self.addChild(self.panelBg);
// Panel title
self.titleText = new Text2("Diplomacy with Country " + targetCountry, {
size: 32,
fill: 0x000000
});
self.titleText.anchor.set(0.5, 0.5);
self.titleText.y = -80;
self.addChild(self.titleText);
// Declare war button
self.warButton = new ActionButton();
self.warButton.init("Declare War", function () {
declareWar(targetCountry);
self.hide();
}, 0, 40);
// Show declare war button in easy mode
self.warButton.visible = true;
self.addChild(self.warButton);
// Peace treaty button
self.peaceButton = new ActionButton();
self.peaceButton.init("Peace Treaty", function () {
makePeace(targetCountry);
self.hide();
}, 0, 100);
self.addChild(self.peaceButton);
// Show/hide peace button depending on war state and difficulty
self.updateButtons = function () {
if (selectedDifficulty === "hardcore") {
self.peaceButton.visible = false;
} else if (warDeclarations[self.targetCountry]) {
self.peaceButton.visible = true;
} else {
self.peaceButton.visible = false;
}
};
self.updateButtons();
// Close button
self.closeButton = new ActionButton();
self.closeButton.init("Close", function () {
self.hide();
}, 0, 160);
self.addChild(self.closeButton);
// Position panel in center of screen
self.x = 2048 / 2;
self.y = 2732 / 2;
return self;
};
self.show = function () {
self.visible = true;
self.updateButtons && self.updateButtons();
game.addChild(self);
};
self.hide = function () {
self.visible = false;
if (self.parent) {
self.parent.removeChild(self);
}
};
return self;
});
var Ship = Container.expand(function () {
var self = Container.call(this);
self.init = function (owner, x, y) {
self.owner = owner;
self.hp = 3; // Ships have more health than armies
self.selected = false;
// Armies carried by ship (default 2 for player, 0 for AI, can be changed)
self.armies = owner === 1 ? 2 : 0;
// Ship graphics
self.shipGraphics = self.attachAsset('ship', {
anchorX: 0.5,
anchorY: 0.5
});
// Color based on owner
if (owner === 1) {
self.shipGraphics.tint = 0x27ae60; // Green for player
} else if (owner === 2) {
self.shipGraphics.tint = 0xe74c3c; // Red for enemy
} else if (owner === 3) {
self.shipGraphics.tint = 0x2a2f94; // Blue
} else if (owner === 4) {
self.shipGraphics.tint = 0x8e44ad; // Purple
} else if (owner === 5) {
self.shipGraphics.tint = 0xf39c12; // Orange
} else if (owner === 6) {
self.shipGraphics.tint = 0x00bcd4; // Cyan
}
// HP display
self.hpText = new Text2(self.hp.toString(), {
size: 48,
fill: 0xFFFFFF
});
self.hpText.anchor.set(0.5, 0.5);
self.hpText.x = 0;
self.hpText.y = -45;
self.addChild(self.hpText);
// Armies display (above ship)
self.armyText = new Text2(self.armies.toString(), {
size: 54,
fill: 0x000000
});
self.armyText.anchor.set(0.5, 0.5);
self.armyText.x = 0;
self.armyText.y = -80;
self.addChild(self.armyText);
self.x = x;
self.y = y;
return self;
};
self.takeDamage = function (damage) {
self.hp -= damage;
self.hpText.setText(self.hp.toString());
return self.hp <= 0;
};
self.down = function (x, y, obj) {
if (gameState === 'playing' && self.owner === 1) {
selectShip(self);
// Show possible moves for this ship (all sea territories) when clicked
// Remove all previous highlights first
for (var i = 0; i < territories.length; i++) {
if (territories[i].isSea) {
territories[i].showAsTarget = true;
territories[i].updateGraphics();
}
}
} else if (gameState === 'playing' && selectedShip && selectedShip.owner === 1 && self.owner === 2) {
// Check if ships are close enough for naval combat
var distance = Math.abs(selectedShip.x - self.x) + Math.abs(selectedShip.y - self.y);
if (distance < 200) {
// Initiate naval combat
navalCombat(selectedShip, self);
selectedShip.selected = false;
selectedShip.shipGraphics.tint = 0x27ae60; // Reset color
selectedShip = null;
endPlayerTurn();
}
}
};
return self;
});
// Game state variables
var Territory = Container.expand(function () {
var self = Container.call(this);
self.init = function (id, x, y, owner, isSea) {
self.id = id;
self.owner = owner; // 0 = neutral, 1 = player, 2 = enemy
self.isSea = isSea || false;
self.armies = owner === 0 || self.isSea ? 0 : Math.floor(Math.random() * 3) + 1;
self.selected = false;
self.lastSelected = false;
// Track if this territory was ever colonizable (for attack logic)
self.wasColonizable = !!self.isColonizable;
// Create territory graphics
self.updateGraphics();
// Position
self.x = x;
self.y = y;
// Army display (only for land territories)
if (!self.isSea) {
self.armyText = new Text2(self.armies.toString(), {
size: 24,
fill: 0x000000
});
self.armyText.anchor.set(0.5, 0.5);
self.armyText.x = 0;
self.armyText.y = 0;
self.addChild(self.armyText);
}
return self;
};
self.updateGraphics = function () {
// Remove existing graphics
if (self.graphics) {
self.removeChild(self.graphics);
}
var assetName = 'seaTerritory'; // Default to sea
if (self.isSea) {
assetName = 'seaTerritory';
} else if (self.selected) {
assetName = 'selectedTerritory';
} else if (self.showAsTarget) {
assetName = 'targetTerritory';
} else {
// Assign different country colors based on owner
if (self.owner === 1) {
assetName = 'country1Territory'; // Green for player
} else if (self.owner === 2) {
assetName = 'country2Territory'; // Red for enemy
} else if (self.owner === 3) {
assetName = 'country3Territory'; // Blue
} else if (self.owner === 4) {
assetName = 'country4Territory'; // Purple
} else if (self.owner === 5) {
assetName = 'country5Territory'; // Orange
} else if (self.owner === 6) {
assetName = 'country6Territory'; // Cyan
} else if (self.isColonizable) {
assetName = 'colonizableTerritory'; // Use dedicated gray asset for colonizable territories
} else {
assetName = 'seaTerritory'; // Unassigned territories become sea
}
}
self.graphics = self.attachAsset(assetName, {
anchorX: 0.5,
anchorY: 0.5
});
};
self.setOwner = function (newOwner, armies) {
self.owner = newOwner;
if (!self.isSea) {
self.armies = armies || 1;
self.armyText.setText(self.armies.toString());
}
self.updateGraphics();
};
self.addArmies = function (count) {
if (!self.isSea) {
self.armies += count;
self.armyText.setText(self.armies.toString());
// Ensure army text is visible and on top after army change
self.removeChild(self.armyText);
self.addChild(self.armyText);
}
};
self.down = function (x, y, obj) {
if (gameState === 'playing') {
// Handle ship movement to sea territories
if (selectedShip && self.isSea) {
// Allow movement to any sea territory
if (self.isSea) {
// Move ship to any sea territory
selectedShip.x = self.x;
selectedShip.y = self.y;
selectedShip.selected = false;
selectedShip.shipGraphics.tint = 0x27ae60; // Reset color
// Remove all sea highlights after move
for (var i = 0; i < territories.length; i++) {
if (territories[i].isSea && territories[i].showAsTarget) {
territories[i].showAsTarget = false;
territories[i].updateGraphics();
}
}
selectedShip = null;
endPlayerTurn();
return;
}
}
// Handle ship colonization of distant territories
if (selectedShip && self.isColonizable && self.owner === 0 && !self.isSea) {
// Check if ship is close enough to colonize (must be adjacent or very close)
var distance = Math.abs(selectedShip.x - self.x) + Math.abs(selectedShip.y - self.y);
if (distance <= territorySpacing * 1.5) {
// Colonize the territory
self.setOwner(selectedShip.owner, selectedShip.armies && selectedShip.armies > 0 ? selectedShip.armies : 2); // Use ship's armies if present, else 2
self.isColonizable = false; // No longer colonizable
self.wasColonizable = true; // Mark as previously colonizable for attack logic
// Ensure army text is visible and on top after colonization
if (self.armyText) {
self.armyText.setText(self.armies.toString());
self.removeChild(self.armyText);
self.addChild(self.armyText);
}
if (selectedShip.owner === 1) {
// Player gets money reward for colonization
playerMoney += self.colonizationReward;
if (playerMoneyText) {
playerMoneyText.setText("Money: " + playerMoney);
}
if (instructionText) {
instructionText.setText("Island colonized! Gained $" + self.colonizationReward);
}
}
LK.getSound('capture').play();
selectedShip.selected = false;
selectedShip.shipGraphics.tint = 0x27ae60; // Reset color
// Remove all armies from ship after landing
selectedShip.armies = 0;
if (selectedShip.armyText) {
selectedShip.armyText.setText("0");
}
selectedShip = null;
updateTerritoryCount();
endPlayerTurn();
return;
} else {
if (instructionText && selectedShip.owner === 1) {
instructionText.setText("Ship must be closer to colonize this island");
}
}
}
// Amphibious assault: allow attacking enemy territory from ship if at war and adjacent
if (selectedShip && !self.isSea && self.owner > 1 && warDeclarations[self.owner]) {
var distance = Math.abs(selectedShip.x - self.x) + Math.abs(selectedShip.y - self.y);
if (distance <= territorySpacing * 1.5 && selectedShip.armies && selectedShip.armies > 0) {
// Simple combat: if ship's armies > defender, take over, else reduce both
var attackPower = selectedShip.armies;
var defensePower = self.armies;
if (attackPower > defensePower) {
self.setOwner(selectedShip.owner, attackPower - defensePower);
selectedShip.armies = 0;
if (selectedShip.armyText) selectedShip.armyText.setText("0");
if (instructionText && selectedShip.owner === 1) {
instructionText.setText("Amphibious assault successful!");
}
LK.getSound('capture').play();
} else {
selectedShip.armies = 0;
if (selectedShip.armyText) selectedShip.armyText.setText("0");
if (defensePower > attackPower) {
self.armies = defensePower - attackPower;
if (self.armyText) self.armyText.setText(self.armies.toString());
}
if (instructionText && selectedShip.owner === 1) {
instructionText.setText("Amphibious assault failed!");
}
LK.getSound('attack').play();
}
selectedShip.selected = false;
selectedShip.shipGraphics.tint = 0x27ae60;
selectedShip = null;
updateTerritoryCount();
endPlayerTurn();
return;
} else if (distance <= territorySpacing * 1.5 && (!selectedShip.armies || selectedShip.armies === 0)) {
if (instructionText && selectedShip.owner === 1) {
instructionText.setText("Ship has no armies to land!");
}
return;
}
}
// Allow colonization of colonizable territory with armies (if adjacent and enough armies)
if (!self.isSea && self.isColonizable && self.owner === 0 && selectedTerritory && selectedTerritory.owner === 1 && !selectedTerritory.isSea) {
// Must be adjacent
var neighbors = getNeighbors(self);
var isNeighbor = false;
for (var i = 0; i < neighbors.length; i++) {
if (neighbors[i] === selectedTerritory) {
isNeighbor = true;
break;
}
}
if (isNeighbor && selectedTerritory.armies > 1) {
// Colonize with armies: move 2 armies, leave at least 1 behind
self.setOwner(1, 2);
self.isColonizable = false;
self.wasColonizable = true; // Mark as previously colonizable for attack logic
// Ensure army text is visible and on top after colonization
if (self.armyText) {
self.armyText.setText(self.armies.toString());
self.removeChild(self.armyText);
self.addChild(self.armyText);
}
selectedTerritory.armies -= 2;
selectedTerritory.armyText.setText(selectedTerritory.armies.toString());
playerMoney += self.colonizationReward;
if (playerMoneyText) {
playerMoneyText.setText("Money: " + playerMoney);
}
if (instructionText) {
instructionText.setText("Island colonized with armies! Gained $" + self.colonizationReward);
}
LK.getSound('capture').play();
updateTerritoryCount();
endPlayerTurn();
return;
} else if (isNeighbor && selectedTerritory.armies <= 1) {
if (instructionText) {
instructionText.setText("Need at least 2 armies to colonize with armies!");
}
return;
}
}
// Allow loading armies from player's territory onto ship if adjacent
if (selectedShip && self.owner === 1 && !self.isSea && self.armies > 1) {
var distance = Math.abs(selectedShip.x - self.x) + Math.abs(selectedShip.y - self.y);
if (distance <= territorySpacing * 1.5) {
// Move up to all but 1 army from territory to ship (max 5 on ship)
var canLoad = Math.min(self.armies - 1, 5 - selectedShip.armies);
if (canLoad > 0) {
self.armies -= canLoad;
selectedShip.armies += canLoad;
if (self.armyText) self.armyText.setText(self.armies.toString());
if (selectedShip.armyText) selectedShip.armyText.setText(selectedShip.armies.toString());
if (instructionText) instructionText.setText("Loaded " + canLoad + " armies onto ship.");
return;
} else {
if (instructionText) instructionText.setText("Ship is full or not enough armies to load.");
return;
}
}
}
selectTerritory(self);
} else if (gameState === 'selectingTarget' && self.showAsTarget) {
executeAttack(self);
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2c3e50
});
/****
* Game Code
****/
// Difficulty selection
var selectedDifficulty = null; // "easy", "medium", "hard"
var difficultyButtons = [];
var difficultyText = null;
// Game state variables
// Territory and game assets
var gameState = 'playing'; // 'playing', 'gameOver', 'victory', 'selectingTarget'
var attackTargets = []; // Available targets for attack
var currentTurn = 1; // 1 = player, 2 = enemy
var selectedTerritory = null;
var territories = [];
var playerTerritories = 0;
var enemyTerritories = 0;
var totalTerritories = 0;
var playerMoney = 100; // Starting money
var aiMoney = 100; // Starting AI money
var incomePerTerritory = 10; // Money generated per territory per turn
// Diplomacy variables
var warDeclarations = {}; // Track which countries we're at war with
var peaceOfferCooldowns = {}; // Track cooldowns for peace offers after rejection
var diplomacyPanel = null;
// Ship variables
var ships = [];
var selectedShip = null;
// Power selection variables
var selectedAttackPower = 1;
var maxAttackPower = 1;
var powerSelectionMode = false;
// UI elements
var turnText, scoreText, instructionText, playerArmyText, playerMoneyText;
var powerText, powerDownButton, powerUpButton;
var actionButtons = [];
// Game settings
var mapWidth = 8;
var mapHeight = 12;
var territorySpacing = 140;
var startX = 2048 / 2 - mapWidth * territorySpacing / 2 + territorySpacing / 2;
var startY = 300;
// Create the game map
function createMap() {
var id = 0;
// We'll store adjacency for sea territories here
var seaAdjacency = {};
// Create contiguous regions for each country with sea territories
// Divide the map into regions for 6 countries
for (var row = 0; row < mapHeight; row++) {
for (var col = 0; col < mapWidth; col++) {
var x = startX + col * territorySpacing;
var y = startY + row * territorySpacing;
var isSea = false;
var owner = 0; // default to neutral/sea
// Create sea lanes (vertical strips)
// Connect the two sea lanes at rows 5 and 6 (expanded connection)
if (col === 2 || col === 5 || (row === 5 || row === 6) && (col === 3 || col === 4)) {
isSea = true;
owner = 0; // Neutral sea
} else {
// Determine owner based on map regions to create contiguous countries
if (row < mapHeight / 3) {
// Top third - countries 1 and 2
if (col < mapWidth / 2) {
owner = 1; // Country 1 (Green) - top left
} else {
owner = 2; // Country 2 (Red) - top right
}
} else if (row < mapHeight * 2 / 3) {
// Middle third - countries 3 and 4
if (col < mapWidth / 2) {
owner = 3; // Country 3 (Blue) - middle left
} else {
owner = 4; // Country 4 (Purple) - middle right
}
} else {
// Bottom third - countries 5 and 6
if (col < mapWidth / 2) {
owner = 5; // Country 5 (Orange) - bottom left
} else {
owner = 6; // Country 6 (Cyan) - bottom right
}
}
// If no specific owner assigned, make it sea
if (owner === 0 && !isSea) {
isSea = true;
}
}
// --- Convert border sea to land ---
// If this tile is at the border and would be sea, convert to land and assign to nearest country
if ((row === 0 || row === mapHeight - 1 || col === 0 || col === mapWidth - 1) && isSea) {
isSea = false;
// Assign to nearest country by region logic
if (row < mapHeight / 3) {
owner = col < mapWidth / 2 ? 1 : 2;
} else if (row < mapHeight * 2 / 3) {
owner = col < mapWidth / 2 ? 3 : 4;
} else {
owner = col < mapWidth / 2 ? 5 : 6;
}
}
var territory = new Territory();
territory.init(id, x, y, owner, isSea);
territories.push(territory);
game.addChild(territory);
id++;
}
}
// Build adjacency for sea territories (by index)
for (var i = 0; i < territories.length; i++) {
if (territories[i].isSea) {
var neighbors = getNeighbors(territories[i]);
seaAdjacency[i] = [];
for (var j = 0; j < neighbors.length; j++) {
if (neighbors[j].isSea) {
var neighborIndex = territories.indexOf(neighbors[j]);
if (neighborIndex !== -1) {
seaAdjacency[i].push(neighborIndex);
}
}
}
}
}
// Attach adjacency info to each sea territory for easy access
for (var i = 0; i < territories.length; i++) {
if (territories[i].isSea) {
territories[i].adjacentSeaIndices = seaAdjacency[i];
}
}
// (Colonizable islands removed)
// Create initial ships for player and enemy
createShips();
updateTerritoryCount();
}
// Create initial ships
function createShips() {
// Find sea territories for ship placement
var seaTerritories = [];
for (var i = 0; i < territories.length; i++) {
if (territories[i].isSea) {
seaTerritories.push(territories[i]);
}
}
// Place initial ships
if (seaTerritories.length > 0) {
// Player ship - automatically select it to start on the ship
var playerShip = new Ship();
var playerSeaPos = seaTerritories[Math.floor(Math.random() * seaTerritories.length)];
playerShip.init(1, playerSeaPos.x, playerSeaPos.y);
playerShip.armies = 2;
if (playerShip.armyText) playerShip.armyText.setText("2");
ships.push(playerShip);
// Auto-select the player ship so they start on it
selectShip(playerShip);
// Enemy ship
var enemyShip = new Ship();
var enemySeaPos = seaTerritories[Math.floor(Math.random() * seaTerritories.length)];
enemyShip.init(2, enemySeaPos.x, enemySeaPos.y);
enemyShip.armies = 0;
if (enemyShip.armyText) enemyShip.armyText.setText("0");
ships.push(enemyShip);
// Ensure ships are always rendered above sea territories by adding them after all territories are added
game.addChild(playerShip);
game.addChild(enemyShip);
}
}
// Ship selection
function selectShip(ship) {
if (selectedDifficulty === null) return;
if (currentTurn !== 1) return;
// Deselect previous selections
if (selectedTerritory) {
selectedTerritory.selected = false;
selectedTerritory.updateGraphics();
selectedTerritory = null;
}
if (selectedShip) {
selectedShip.selected = false;
selectedShip.shipGraphics.tint = 0x27ae60; // Reset to green
}
// Select new ship
selectedShip = ship;
ship.selected = true;
ship.shipGraphics.tint = 0xf1c40f; // Yellow when selected
// Update armyText in case it was changed
if (ship.armyText) {
ship.armyText.setText(ship.armies.toString());
}
// Remove all possible move highlights when selecting a ship, only show on click
for (var i = 0; i < territories.length; i++) {
if (territories[i].isSea) {
territories[i].showAsTarget = false;
territories[i].updateGraphics();
}
}
// Do not show possible moves here; will be shown on ship click (down event)
hidePowerSelection();
updateInstructions();
}
// Generate income based on territories owned
function generateIncome() {
var income = playerTerritories * incomePerTerritory;
playerMoney += income;
if (playerMoneyText) {
playerMoneyText.setText("Money: " + playerMoney + " (+$" + income + ")");
}
}
// Update territory ownership counts
function updateTerritoryCount() {
playerTerritories = 0;
enemyTerritories = 0;
var playerTotalArmies = 0;
var country1Count = 0,
country2Count = 0,
country3Count = 0;
var country4Count = 0,
country5Count = 0,
country6Count = 0;
totalTerritories = territories.length;
for (var i = 0; i < territories.length; i++) {
if (territories[i].owner === 1) {
playerTerritories++;
country1Count++;
playerTotalArmies += territories[i].armies;
} else if (territories[i].owner === 2) {
enemyTerritories++;
country2Count++;
} else if (territories[i].owner === 3) {
country3Count++;
} else if (territories[i].owner === 4) {
country4Count++;
} else if (territories[i].owner === 5) {
country5Count++;
} else if (territories[i].owner === 6) {
country6Count++;
}
}
// (Removed scoreText update for country colors and territory counts)
// Update player army display
if (playerArmyText) {
playerArmyText.setText("Total Armies: " + playerTotalArmies);
}
// Update money display
if (playerMoneyText) {
playerMoneyText.setText("Money: " + playerMoney);
}
// Check victory conditions
// Count total non-sea territories
var totalNonSeaTerritories = 0;
for (var i = 0; i < territories.length; i++) {
if (!territories[i].isSea) {
totalNonSeaTerritories++;
}
}
if (playerTerritories === totalNonSeaTerritories) {
gameState = 'victory';
LK.showYouWin();
} else if (enemyTerritories >= Math.floor(totalTerritories * 0.75)) {
gameState = 'gameOver';
LK.showGameOver();
} else if (playerTerritories === 0) {
gameState = 'gameOver';
LK.showGameOver();
}
}
// Declare war function
function declareWar(countryId) {
warDeclarations[countryId] = true;
if (instructionText) {
instructionText.setText("War declared on Country " + countryId + "! You can now attack their territories.");
}
// If diplomacyPanel is open, update buttons
if (diplomacyPanel && diplomacyPanel.targetCountry === countryId) {
diplomacyPanel.updateButtons();
}
}
// Make peace function
function makePeace(countryId) {
if (selectedDifficulty === "hardcore") {
if (instructionText) {
instructionText.setText("Peace treaties are disabled in Hardcore mode!");
}
return;
}
// Prevent peace offer if cooldown is active
if (peaceOfferCooldowns[countryId] && peaceOfferCooldowns[countryId] > 0) {
if (instructionText) {
instructionText.setText("You must wait " + peaceOfferCooldowns[countryId] + " turns before offering peace to Country " + countryId + " again.");
}
return;
}
if (warDeclarations[countryId]) {
// In easy mode, always accept peace treaty
if (selectedDifficulty === "easy" || Math.random() < 0.5) {
warDeclarations[countryId] = false;
if (instructionText) {
instructionText.setText("Peace treaty signed with Country " + countryId + ". You can no longer attack their territories.");
}
// If diplomacyPanel is open, update buttons
if (diplomacyPanel && diplomacyPanel.targetCountry === countryId) {
diplomacyPanel.updateButtons();
}
if (peaceOfferCooldowns[countryId]) peaceOfferCooldowns[countryId] = 0; // Reset cooldown on acceptance
} else {
if (instructionText) {
instructionText.setText("Peace treaty rejected by Country " + countryId + "!");
}
// Set cooldown for 10 turns after rejection
peaceOfferCooldowns[countryId] = 10;
}
}
}
// Territory selection
function selectTerritory(territory) {
if (selectedDifficulty === null) return;
if (currentTurn !== 1) return; // Only during player turn
// If we're in target selection mode, cancel it
if (gameState === 'selectingTarget') {
// Clear target highlighting
for (var i = 0; i < attackTargets.length; i++) {
attackTargets[i].showAsTarget = false;
attackTargets[i].updateGraphics();
}
gameState = 'playing';
attackTargets = [];
}
// Deselect previous territory
if (selectedTerritory) {
selectedTerritory.selected = false;
selectedTerritory.updateGraphics();
// Ensure previous territory's army text remains visible
selectedTerritory.armyText.setText(selectedTerritory.armies.toString());
// Re-add army text to ensure it's visible
selectedTerritory.removeChild(selectedTerritory.armyText);
selectedTerritory.addChild(selectedTerritory.armyText);
}
// Handle enemy territory clicks - show diplomacy panel
if (territory.owner !== 1 && territory.owner !== 0) {
// Create diplomacy panel if it doesn't exist
if (!diplomacyPanel) {
diplomacyPanel = new DiplomacyPanel();
diplomacyPanel.init(territory.owner);
} else {
// Update existing panel for new country
diplomacyPanel.targetCountry = territory.owner;
diplomacyPanel.titleText.setText("Diplomacy with Country " + territory.owner);
if (diplomacyPanel.updateButtons) diplomacyPanel.updateButtons();
}
diplomacyPanel.show();
return;
}
// Select new territory
if (territory.owner === 1) {
// Only select player territories
selectedTerritory = territory;
territory.selected = true;
territory.updateGraphics();
// Ensure army text is visible and updated
territory.armyText.setText(territory.armies.toString());
// Bring army text to front to ensure it's visible
territory.removeChild(territory.armyText);
territory.addChild(territory.armyText);
// Show power selection for territories with armies > 1
if (!territory.isSea && territory.armies > 1) {
showPowerSelection(territory.armies - 1);
} else {
hidePowerSelection();
}
updateInstructions();
} else {
hidePowerSelection();
}
}
// Get neighboring territories
function getNeighbors(territory) {
var neighbors = [];
var index = territories.indexOf(territory);
var row = Math.floor(index / mapWidth);
var col = index % mapWidth;
// Check all 4 directions
var directions = [{
row: -1,
col: 0
},
// up
{
row: 1,
col: 0
},
// down
{
row: 0,
col: -1
},
// left
{
row: 0,
col: 1
} // right
];
for (var i = 0; i < directions.length; i++) {
var newRow = row + directions[i].row;
var newCol = col + directions[i].col;
if (newRow >= 0 && newRow < mapHeight && newCol >= 0 && newCol < mapWidth) {
var neighborIndex = newRow * mapWidth + newCol;
neighbors.push(territories[neighborIndex]);
}
}
return neighbors;
}
// Attack action
function attackTerritory() {
if (selectedDifficulty === null) return;
if (!selectedTerritory || selectedTerritory.armies <= 1) return;
var neighbors = getNeighbors(selectedTerritory);
var targets = [];
for (var i = 0; i < neighbors.length; i++) {
if (neighbors[i].owner !== 1) {
// Allow attacking if:
// - Neutral (owner 0)
// - At war with the country
// - The territory was previously colonizable and is now enemy-owned (owner 2-6)
// - The territory was a neutral/colonizable territory, is now enemy-owned, and we are at war with that enemy
var n = neighbors[i];
var canAttack = false;
if (n.owner === 0) {
canAttack = true;
} else if (warDeclarations[n.owner]) {
canAttack = true;
} else if (n.owner > 1 && n.owner <= 6 && n.isColonizable === true) {
canAttack = true;
} else if (n.owner > 1 && n.owner <= 6 && typeof n.wasColonizable !== "undefined" && n.wasColonizable === true && warDeclarations[n.owner]) {
// If this territory was previously colonizable, is now enemy-owned, and we are at war with that enemy
canAttack = true;
}
if (canAttack) {
targets.push(n);
}
}
}
if (targets.length > 0) {
// Show target selection mode
gameState = 'selectingTarget';
attackTargets = targets;
// Highlight all possible targets
for (var i = 0; i < targets.length; i++) {
targets[i].showAsTarget = true;
targets[i].updateGraphics();
}
if (instructionText) {
instructionText.setText("Select a territory to attack");
}
}
}
// Execute attack on selected target
function executeAttack(target) {
if (!selectedTerritory || !target) return;
// Clear target highlighting
for (var i = 0; i < attackTargets.length; i++) {
attackTargets[i].showAsTarget = false;
attackTargets[i].updateGraphics();
}
// Simple combat resolution using selected attack power
var attackPower = selectedAttackPower;
var defensePower = target.armies;
if (attackPower > defensePower) {
// Victory
target.setOwner(1, attackPower - defensePower);
selectedTerritory.armies = selectedTerritory.armies - attackPower;
selectedTerritory.armyText.setText(selectedTerritory.armies.toString());
LK.getSound('capture').play();
} else {
// Defeat - lose the armies used in attack
selectedTerritory.armies = selectedTerritory.armies - attackPower;
selectedTerritory.armyText.setText(selectedTerritory.armies.toString());
if (defensePower > attackPower) {
target.armies = defensePower - attackPower;
target.armyText.setText(target.armies.toString());
}
}
LK.getSound('attack').play();
updateTerritoryCount();
// Reset game state
gameState = 'playing';
attackTargets = [];
endPlayerTurn();
}
// Recruit armies action
function recruitArmies() {
if (selectedDifficulty === null) return;
if (!selectedTerritory) return;
var recruitCost = 100; // Increased cost to recruit armies
if (playerMoney >= recruitCost) {
playerMoney -= recruitCost;
selectedTerritory.addArmies(2);
if (playerMoneyText) {
playerMoneyText.setText("Money: " + playerMoney);
}
endPlayerTurn();
} else {
// Not enough money - show feedback but don't end turn
if (instructionText) {
instructionText.setText("Not enough money! Need $" + recruitCost + " to recruit");
}
}
}
// Build ship action
function buildShip() {
if (selectedDifficulty === null) return;
if (!selectedTerritory || selectedTerritory.isSea) return;
var shipCost = 200; //{4Z} // Increased cost
// Determine which country's money to use
var owner = selectedTerritory.owner;
if (owner === 0 || owner === undefined) return; // Only countries can build ships
// Only allow if the country has enough money
var canBuild = false;
if (owner === 1 && playerMoney >= shipCost) {
canBuild = true;
} else if (owner === 2 && aiMoney >= shipCost) {
canBuild = true;
} else if (owner > 2) {
// For AI countries 3-6, give them their own money pool if not present
if (typeof window['countryMoney' + owner] === "undefined") {
window['countryMoney' + owner] = 100;
}
if (window['countryMoney' + owner] >= shipCost) {
canBuild = true;
}
}
if (canBuild) {
// Find adjacent sea territory
var neighbors = getNeighbors(selectedTerritory);
var seaNeighbors = [];
for (var i = 0; i < neighbors.length; i++) {
if (neighbors[i].isSea) {
seaNeighbors.push(neighbors[i]);
}
}
if (seaNeighbors.length > 0) {
// Deduct money from the correct pool
if (owner === 1) {
playerMoney -= shipCost;
} else if (owner === 2) {
aiMoney -= shipCost;
} else if (owner > 2) {
window['countryMoney' + owner] -= shipCost;
}
var seaPos = seaNeighbors[0];
var newShip = new Ship();
newShip.init(owner, seaPos.x, seaPos.y);
ships.push(newShip);
// Ensure new ships are rendered above sea territories
game.addChild(newShip);
if (owner === 1 && playerMoneyText) {
playerMoneyText.setText("Money: " + playerMoney);
}
endPlayerTurn();
} else {
if (instructionText && owner === 1) {
instructionText.setText("No adjacent sea territory to build ship!");
}
}
} else {
if (instructionText && owner === 1) {
instructionText.setText("Not enough money! Need $" + shipCost + " to build ship");
}
}
}
// Naval combat
function navalCombat(attackerShip, defenderShip) {
var damage = 1;
var defenderDestroyed = defenderShip.takeDamage(damage);
if (defenderDestroyed) {
// Remove destroyed ship
var index = ships.indexOf(defenderShip);
if (index > -1) {
ships.splice(index, 1);
}
defenderShip.destroy();
LK.getSound('capture').play();
} else {
LK.getSound('attack').play();
}
}
// Per-country ship build timers for AI countries 2-6
// All countries (1-6) can build ships, recruit armies, declare war, and colonize
var countryShipTimers = {};
// Per-country war declaration timers for AI countries 2-6 (enemy and other AIs)
var countryWarTimers = {};
for (var c = 2; c <= 6; c++) {
// For war timers: if not at war, 12 turns; if at war, 30 turns (will be set dynamically in aiTurn)
countryWarTimers[c] = Math.floor(Math.random() * 3) + 10; // randomize initial timer between 10-12
}
for (var c = 2; c <= 6; c++) {
// All AI countries 2-6: build ships every 3-5 turns by default
countryShipTimers[c] = Math.floor(Math.random() * 3) + 3;
}
// End player turn
function endPlayerTurn() {
if (selectedTerritory) {
selectedTerritory.selected = false;
selectedTerritory.updateGraphics();
selectedTerritory = null;
hidePowerSelection();
}
hidePowerSelection();
// Generate income based on territories owned
generateIncome();
// Decrease peace offer cooldowns at end of player turn
for (var k in peaceOfferCooldowns) {
if (peaceOfferCooldowns.hasOwnProperty(k) && peaceOfferCooldowns[k] > 0) {
peaceOfferCooldowns[k]--;
}
}
currentTurn = 2;
updateInstructions();
// AI turn after short delay
LK.setTimeout(function () {
aiTurn();
}, 1000);
}
// Helper: AI build ship for a country if possible
function aiBuildShipForCountry(countryId) {
// Find all territories owned by this country
var owned = [];
for (var i = 0; i < territories.length; i++) {
if (territories[i].owner === countryId && !territories[i].isSea) {
owned.push(territories[i]);
}
}
// Try to build ship from a random owned territory with adjacent sea
if (owned.length > 0) {
var t = owned[Math.floor(Math.random() * owned.length)];
var neighbors = getNeighbors(t);
var seaNeighbors = [];
for (var j = 0; j < neighbors.length; j++) {
if (neighbors[j].isSea) seaNeighbors.push(neighbors[j]);
}
if (seaNeighbors.length > 0) {
// Deduct money if needed (handled in buildShip, but we do it here for AI)
if (typeof window['countryMoney' + countryId] === "undefined") {
window['countryMoney' + countryId] = 100;
}
var shipCost = 200;
if (window['countryMoney' + countryId] >= shipCost) {
window['countryMoney' + countryId] -= shipCost;
var seaPos = seaNeighbors[0];
var newShip = new Ship();
newShip.init(countryId, seaPos.x, seaPos.y);
ships.push(newShip);
game.addChild(newShip);
return true;
}
}
}
return false;
}
// Simple AI turn
function aiTurn() {
// Generate AI income
var aiIncome = enemyTerritories * incomePerTerritory;
aiMoney += aiIncome;
var enemyTerrs = [];
for (var i = 0; i < territories.length; i++) {
if (territories[i].owner === 2) {
enemyTerrs.push(territories[i]);
}
}
if (enemyTerrs.length > 0) {
var aiTerritory = enemyTerrs[Math.floor(Math.random() * enemyTerrs.length)];
var neighbors = getNeighbors(aiTerritory);
var playerTargets = [];
// In easy mode, AI never attacks
if (selectedDifficulty === "easy") {
// AI does not attack, just does economy/ship/army actions below
playerTargets = [];
} else {
for (var j = 0; j < neighbors.length; j++) {
// AI can attack player territories if war is declared on AI (country 2)
if (neighbors[j].owner === 1 && warDeclarations[2]) {
playerTargets.push(neighbors[j]);
}
}
}
if (playerTargets.length > 0 && aiTerritory.armies > 1) {
// AI attacks
var target = playerTargets[Math.floor(Math.random() * playerTargets.length)];
var attackPower = aiTerritory.armies - 1;
var defensePower = target.armies;
if (attackPower > defensePower) {
target.setOwner(2, attackPower - defensePower);
aiTerritory.armies = 1;
aiTerritory.armyText.setText(aiTerritory.armies.toString());
} else {
aiTerritory.armies = 1;
aiTerritory.armyText.setText(aiTerritory.armies.toString());
if (defensePower > attackPower) {
target.armies = defensePower - attackPower;
target.armyText.setText(target.armies.toString());
}
}
} else {
// AI decides what to do based on money and strategy
var action = Math.random();
var recruitCost = 50;
var shipCost = 100;
if (action < 0.4 && aiMoney >= recruitCost) {
// 40% chance to recruit armies if affordable
aiMoney -= recruitCost;
aiTerritory.addArmies(2);
} else if (action < 0.7 && aiMoney >= shipCost) {
// 30% chance to build ship if possible and affordable
var seaNeighbors = [];
for (var k = 0; k < neighbors.length; k++) {
if (neighbors[k].isSea) {
seaNeighbors.push(neighbors[k]);
}
}
if (seaNeighbors.length > 0) {
// Build ship in adjacent sea
aiMoney -= shipCost;
var seaPos = seaNeighbors[0];
var newShip = new Ship();
newShip.init(2, seaPos.x, seaPos.y);
ships.push(newShip);
// Ensure AI ships are rendered above sea territories
game.addChild(newShip);
} else {
// No sea nearby, recruit if affordable or just add basic army
if (aiMoney >= recruitCost) {
aiMoney -= recruitCost;
aiTerritory.addArmies(2);
} else {
aiTerritory.addArmies(1);
}
}
} else {
// Default action - add basic army (free)
aiTerritory.addArmies(1);
}
}
}
// AI war declaration logic for hard difficulty
if (selectedDifficulty === "hard") {
// --- Special: Country 6 always declares war on country 5 every 5 turns ---
if (typeof window.country6War5Timer === "undefined") {
window.country6War5Timer = 5;
}
window.country6War5Timer--;
if (window.country6War5Timer <= 0) {
if (!warDeclarations[5]) {
warDeclarations[5] = true;
if (instructionText) {
instructionText.setText("Country 6 has declared war on Country 5!");
}
}
window.country6War5Timer = 5;
}
// --- New: AI countries declare war on weaker neighbors if stronger ---
for (var c = 2; c <= 6; c++) {
// Only consider if not already at war with all other countries
for (var i = 0; i < territories.length; i++) {
if (territories[i].owner === c && !territories[i].isSea) {
var neighbors = getNeighbors(territories[i]);
for (var j = 0; j < neighbors.length; j++) {
var neighbor = neighbors[j];
// Only consider land neighbors owned by another country (not self, not neutral, not sea)
if (neighbor.owner !== c && neighbor.owner > 0 && neighbor.owner <= 6 && !neighbor.isSea && !warDeclarations[neighbor.owner]) {
// If AI's territory has more armies than neighbor, declare war
if (territories[i].armies > neighbor.armies) {
warDeclarations[neighbor.owner] = true;
if (neighbor.owner === 1 && instructionText) {
instructionText.setText("Country " + c + " has declared war on you due to your weak border!");
}
}
}
}
}
}
}
// --- AI peace offer logic (not in hardcore) ---
if (selectedDifficulty !== "hardcore") {
for (var c = 2; c <= 6; c++) {
// If AI country is at war with player, has lost territories, and random chance, offer peace
if (warDeclarations[c]) {
// Count AI's territories
var aiTerrCount = 0;
for (var i = 0; i < territories.length; i++) {
if (territories[i].owner === c && !territories[i].isSea) {
aiTerrCount++;
}
}
// If AI is weak (few territories) or random chance, offer peace
if (aiTerrCount < 3 || Math.random() < 0.15) {
// 50% chance player accepts, always accept in easy mode
if (selectedDifficulty === "easy" || Math.random() < 0.5) {
warDeclarations[c] = false;
if (instructionText) {
instructionText.setText("Country " + c + " has offered a peace treaty. Peace has been established!");
}
if (diplomacyPanel && diplomacyPanel.targetCountry === c) {
diplomacyPanel.updateButtons();
}
} else {
if (instructionText) {
instructionText.setText("Country " + c + " has offered a peace treaty, but you rejected it!");
}
}
}
}
}
}
// AI countries 2-6 may declare war more frequently
for (var c = 2; c <= 6; c++) {
// Only consider declaring war on countries we are not already at war with
if (!warDeclarations[c]) {
countryWarTimers[c]--;
if (countryWarTimers[c] <= 0) {
// Declare war on a random other country (not self)
var possibleTargets = [];
for (var t = 1; t <= 6; t++) {
if (t !== c && !warDeclarations[t]) {
possibleTargets.push(t);
}
}
if (possibleTargets.length > 0) {
var target = possibleTargets[Math.floor(Math.random() * possibleTargets.length)];
warDeclarations[target] = true;
// Optionally, show a message if the player is the target
if (target === 1 && instructionText) {
instructionText.setText("Country " + c + " has declared war on you!");
}
}
// Reset timer for next declaration (12 turns if not at war, 30 if at war)
if (warDeclarations[c]) {
countryWarTimers[c] = 30;
} else {
countryWarTimers[c] = 12;
}
}
} else {
// If already at war, use longer timer before next declaration
countryWarTimers[c]--;
if (countryWarTimers[c] <= 0) {
// Try to declare war on another country (not self, not already at war)
var possibleTargets = [];
for (var t = 1; t <= 6; t++) {
if (t !== c && !warDeclarations[t]) {
possibleTargets.push(t);
}
}
if (possibleTargets.length > 0) {
var target = possibleTargets[Math.floor(Math.random() * possibleTargets.length)];
warDeclarations[target] = true;
if (target === 1 && instructionText) {
instructionText.setText("Country " + c + " has declared war on you!");
}
}
// Reset timer for next declaration (30 turns if at war)
countryWarTimers[c] = 30;
}
}
}
}
// In easy mode, AI never declares war (handled by not attacking above)
// AI countries 2-6: build ships every 3-5 turns if possible
for (var c = 2; c <= 6; c++) {
if (typeof countryShipTimers[c] === "undefined") {
countryShipTimers[c] = Math.floor(Math.random() * 3) + 3;
}
countryShipTimers[c]--;
if (countryShipTimers[c] <= 0) {
var built = aiBuildShipForCountry(c);
countryShipTimers[c] = Math.floor(Math.random() * 3) + 3;
}
}
// All AI countries 2-6: recruit armies every turn if possible
for (var c = 2; c <= 6; c++) {
for (var i = 0; i < territories.length; i++) {
if (territories[i].owner === c && !territories[i].isSea) {
if (typeof window['countryMoney' + c] === "undefined") {
window['countryMoney' + c] = 100;
}
var recruitCost = 50;
if (window['countryMoney' + c] >= recruitCost) {
window['countryMoney' + c] -= recruitCost;
territories[i].addArmies(2);
}
}
}
}
// AI ship movement and naval combat
// Loop for all AI countries (2-6) to give each their own ship logic
for (var aiCountry = 2; aiCountry <= 6; aiCountry++) {
var aiShips = [];
for (var i = 0; i < ships.length; i++) {
if (ships[i].owner === aiCountry) {
aiShips.push(ships[i]);
}
}
if (aiShips.length > 0) {
var aiShip = aiShips[Math.floor(Math.random() * aiShips.length)];
// Look for enemy ships to attack (player or any other country at war)
var enemyShips = [];
for (var i = 0; i < ships.length; i++) {
if (ships[i].owner !== aiCountry && ships[i].owner !== 0) {
// Only attack if at war or if player (for country 2)
if (aiCountry === 2) {
if (ships[i].owner === 1 && warDeclarations[2]) {
var distance = Math.abs(ships[i].x - aiShip.x) + Math.abs(ships[i].y - aiShip.y);
if (distance < 200) {
enemyShips.push(ships[i]);
}
}
} else {
// For AI countries 3-6, attack ships of any country at war
if (warDeclarations[aiCountry] || warDeclarations[ships[i].owner]) {
var distance = Math.abs(ships[i].x - aiShip.x) + Math.abs(ships[i].y - aiShip.y);
if (distance < 200) {
enemyShips.push(ships[i]);
}
}
}
}
}
if (enemyShips.length > 0) {
// Attack nearest enemy ship
var target = enemyShips[0];
navalCombat(aiShip, target);
} else {
// Look for colonizable territories
var colonizableTargets = [];
for (var i = 0; i < territories.length; i++) {
if (territories[i].isColonizable && territories[i].owner === 0 && !territories[i].isSea) {
var distance = Math.abs(territories[i].x - aiShip.x) + Math.abs(territories[i].y - aiShip.y);
if (distance <= territorySpacing * 1.5) {
colonizableTargets.push(territories[i]);
}
}
}
if (colonizableTargets.length > 0) {
// Colonize nearest available territory
var target = colonizableTargets[0];
target.setOwner(aiCountry, 2);
target.isColonizable = false; // No longer colonizable
target.wasColonizable = true; // Mark as previously colonizable for attack logic
// Give money to correct AI pool
if (aiCountry === 2) {
aiMoney += target.colonizationReward;
} else {
if (typeof window['countryMoney' + aiCountry] === "undefined") {
window['countryMoney' + aiCountry] = 100;
}
window['countryMoney' + aiCountry] += target.colonizationReward;
}
} else {
// Move to random sea territory or towards colonizable islands
var moveTargets = [];
// Add sea territories
for (var i = 0; i < territories.length; i++) {
if (territories[i].isSea) {
moveTargets.push(territories[i]);
}
}
// Add positions near colonizable islands
for (var i = 0; i < territories.length; i++) {
if (territories[i].isColonizable && territories[i].owner === 0) {
moveTargets.push(territories[i]);
}
}
if (moveTargets.length > 0) {
var newPos = moveTargets[Math.floor(Math.random() * moveTargets.length)];
aiShip.x = newPos.x;
aiShip.y = newPos.y;
}
}
}
}
}
updateTerritoryCount();
// Decrease peace offer cooldowns at end of AI turn
for (var k in peaceOfferCooldowns) {
if (peaceOfferCooldowns.hasOwnProperty(k) && peaceOfferCooldowns[k] > 0) {
peaceOfferCooldowns[k]--;
}
}
currentTurn = 1;
updateInstructions();
}
// Create UI elements
function createUI() {
// Turn indicator
turnText = new Text2("Your Turn", {
size: 40,
fill: 0xFFFFFF
});
turnText.anchor.set(0.5, 0);
LK.gui.top.addChild(turnText);
turnText.y = 100;
// (Removed scoreText display for country colors and territory counts)
// Player army count display
playerArmyText = new Text2("Total Armies: 0", {
size: 32,
fill: 0x7ed321
});
playerArmyText.anchor.set(0.5, 0);
LK.gui.top.addChild(playerArmyText);
playerArmyText.y = 190;
// Player money display
playerMoneyText = new Text2("Money: " + playerMoney, {
size: 32,
fill: 0xf5a623
});
playerMoneyText.anchor.set(0.5, 0);
LK.gui.top.addChild(playerMoneyText);
playerMoneyText.y = 230;
// Instructions
instructionText = new Text2("Select your territory, then choose an action", {
size: 28,
fill: 0xFFFFFF
});
instructionText.anchor.set(0.5, 1);
LK.gui.bottom.addChild(instructionText);
instructionText.y = -200;
// Action buttons
var attackBtn = new ActionButton();
attackBtn.init("Attack", attackTerritory, 2048 / 2 - 200, 2732 - 120);
actionButtons.push(attackBtn);
game.addChild(attackBtn);
var recruitBtn = new ActionButton();
recruitBtn.init("Recruit", recruitArmies, 2048 / 2 - 60, 2732 - 120);
actionButtons.push(recruitBtn);
game.addChild(recruitBtn);
var buildShipBtn = new ActionButton();
buildShipBtn.init("Build Ship", buildShip, 2048 / 2 + 80, 2732 - 120);
actionButtons.push(buildShipBtn);
game.addChild(buildShipBtn);
// Skip Turn button
var skipTurnBtn = new ActionButton();
skipTurnBtn.init("Skip Turn", function () {
if (selectedDifficulty === null) return;
if (currentTurn === 1) {
endPlayerTurn();
}
}, 2048 / 2 + 220, 2732 - 120);
actionButtons.push(skipTurnBtn);
game.addChild(skipTurnBtn);
// Power selection display
powerText = new Text2("Attack Power: 1/1", {
size: 28,
fill: 0xffff00
});
powerText.anchor.set(0.5, 1);
LK.gui.bottom.addChild(powerText);
powerText.y = -240;
powerText.visible = false;
// Power adjustment buttons
var powerDownBtn = new ActionButton();
powerDownBtn.init("-", decreasePower, 2048 / 2 - 100, 2732 - 180);
actionButtons.push(powerDownBtn);
game.addChild(powerDownBtn);
powerDownBtn.visible = false;
var powerUpBtn = new ActionButton();
powerUpBtn.init("+", increasePower, 2048 / 2 + 100, 2732 - 180);
actionButtons.push(powerUpBtn);
game.addChild(powerUpBtn);
powerUpBtn.visible = false;
// Store power buttons for visibility control
powerDownButton = powerDownBtn;
powerUpButton = powerUpBtn;
}
// Power selection functions
function decreasePower() {
if (selectedDifficulty === null) return;
if (selectedAttackPower > 1) {
selectedAttackPower--;
updatePowerDisplay();
}
}
function increasePower() {
if (selectedDifficulty === null) return;
if (selectedAttackPower < maxAttackPower) {
selectedAttackPower++;
updatePowerDisplay();
}
}
function updatePowerDisplay() {
if (powerText) {
powerText.setText("Attack Power: " + selectedAttackPower + "/" + maxAttackPower);
}
}
function showPowerSelection(maxPower) {
maxAttackPower = maxPower;
selectedAttackPower = Math.min(selectedAttackPower, maxAttackPower);
powerSelectionMode = true;
if (powerText) {
powerText.visible = true;
updatePowerDisplay();
}
if (powerDownButton && powerUpButton) {
powerDownButton.visible = true;
powerUpButton.visible = true;
}
}
function hidePowerSelection() {
powerSelectionMode = false;
if (powerText) {
powerText.visible = false;
}
if (powerDownButton && powerUpButton) {
powerDownButton.visible = false;
powerUpButton.visible = false;
}
}
// Update instruction text
function updateInstructions() {
if (selectedDifficulty === null) {
if (instructionText) {
instructionText.setText("Please select a difficulty (Easy, Medium, Hard)");
}
return;
}
if (currentTurn === 1) {
if (turnText) {
turnText.setText("Your Turn");
}
if (instructionText) {
if (selectedShip) {
instructionText.setText("Ship selected - Move to sea or attack enemy ships");
} else if (selectedTerritory) {
if (selectedTerritory.isSea) {
instructionText.setText("Sea territory selected - Ships can move here");
} else if (powerSelectionMode) {
instructionText.setText("Use +/- to choose attack power, then Attack, Recruit ($100), or Build Ship ($200)");
} else {
instructionText.setText("Territory selected - Attack, Recruit ($100), or Build Ship ($200)");
}
} else {
instructionText.setText("Select your territory/ship (green), then choose an action");
}
}
} else {
if (turnText) {
turnText.setText("Enemy Turn");
}
if (instructionText) {
instructionText.setText("Enemy is thinking...");
}
}
}
// Game update loop for naval combat highlighting
game.update = function () {
// Highlight enemy ships in combat range when player ship is selected
if (selectedShip && selectedShip.owner === 1) {
for (var i = 0; i < ships.length; i++) {
if (ships[i].owner === 2) {
var distance = Math.abs(selectedShip.x - ships[i].x) + Math.abs(selectedShip.y - ships[i].y);
if (distance < 200) {
// Highlight enemy ship in range
ships[i].shipGraphics.tint = 0xff6b6b; // Red tint for attackable
} else {
ships[i].shipGraphics.tint = 0xe74c3c; // Default red for enemy
}
}
}
} else {
// Reset all ship colors when no ship selected
for (var i = 0; i < ships.length; i++) {
if (ships[i].owner === 2) {
ships[i].shipGraphics.tint = 0xe74c3c; // Default red for enemy
} else if (ships[i].owner === 1 && ships[i] !== selectedShip) {
ships[i].shipGraphics.tint = 0x27ae60; // Default green for player
}
}
}
};
// Difficulty selection UI
function showDifficultySelection() {
// Block all game actions until difficulty is selected
gameState = "selectingDifficulty";
// Hide all action buttons
for (var i = 0; i < actionButtons.length; i++) {
actionButtons[i].visible = false;
}
// Hide power selection
hidePowerSelection();
// Create a full-screen overlay container for difficulty selection
if (typeof difficultyOverlay !== "undefined" && difficultyOverlay.parent) {
difficultyOverlay.parent.removeChild(difficultyOverlay);
}
difficultyOverlay = new Container();
difficultyOverlay.x = 0;
difficultyOverlay.y = 0;
// Add a semi-transparent background to block game interaction
var overlayBg = LK.getAsset('selectedTerritory', {
anchorX: 0,
anchorY: 0,
scaleX: 2048 / 120,
scaleY: 2732 / 120
});
overlayBg.alpha = 0.85;
overlayBg.tint = 0x222222;
difficultyOverlay.addChild(overlayBg);
// Show difficulty selection text
difficultyText = new Text2("Select Difficulty", {
size: 60,
fill: 0xffffff
});
difficultyText.anchor.set(0.5, 0.5);
difficultyText.x = 2048 / 2;
difficultyText.y = 2732 / 2 - 200;
difficultyOverlay.addChild(difficultyText);
// Button positions
var btnY = 2732 / 2;
var btnSpacing = 220;
var btnLabels = [{
label: "Easy",
value: "easy"
}, {
label: "Medium",
value: "medium"
}, {
label: "Hard",
value: "hard"
}, {
label: "Hardcore",
value: "hardcore"
}];
for (var i = 0; i < btnLabels.length; i++) {
var btn = new ActionButton();
btn.init(btnLabels[i].label, function (difficulty) {
return function () {
selectDifficulty(difficulty);
};
}(btnLabels[i].value), 2048 / 2 + (i - 1.5) * btnSpacing, btnY);
difficultyButtons.push(btn);
difficultyOverlay.addChild(btn);
}
// Add overlay to game
game.addChild(difficultyOverlay);
}
// Remove difficulty selection UI and start the game
function selectDifficulty(difficulty) {
selectedDifficulty = difficulty;
// If hardcore, set war with all countries (2-6) and block peace
if (selectedDifficulty === "hardcore") {
for (var c = 2; c <= 6; c++) {
warDeclarations[c] = true;
}
}
// Remove difficulty UI overlay
if (typeof difficultyOverlay !== "undefined" && difficultyOverlay.parent) {
difficultyOverlay.parent.removeChild(difficultyOverlay);
}
difficultyButtons = [];
// Show action buttons
for (var i = 0; i < actionButtons.length; i++) {
actionButtons[i].visible = true;
}
// Set game state to playing and update UI
gameState = "playing";
updateInstructions();
}
// Initialize the game
createMap();
createUI();
showDifficultySelection();
updateInstructions();
green grass. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
cyan grass. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
gray grass. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
sea territory. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
soldier. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
blue grass. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
white grass. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
red grass. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
yellow grass. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
pixelart empty button. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
paper piece pixel. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
pixel ship. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
swords pixelart. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat