/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var ActionButton = Container.expand(function (text, action, color) { var self = Container.call(this); var buttonGraphics = self.attachAsset(action + 'Button', { anchorX: 0.5, anchorY: 0.5 }); var buttonLabel = new Text2(text, { size: 28, fill: 0xFFFFFF }); buttonLabel.anchor.set(0.5, 0.5); self.addChild(buttonLabel); self.action = action; self.down = function (x, y, obj) { game.handleActionButton(self); }; return self; }); var ConnectionLine = Container.expand(function (territory1, territory2) { var self = Container.call(this); self.territory1 = territory1; self.territory2 = territory2; self.connectionVisible = true; // Create a simple line representation using two small rectangles var lineGraphics = self.attachAsset('selectHighlight', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.1, scaleY: 0.1 }); lineGraphics.alpha = 0.3; lineGraphics.tint = 0x808080; self.update = function () { if (self.connectionVisible) { // Position the line between the two territories var midX = (self.territory1.x + self.territory2.x) / 2; var midY = (self.territory1.y + self.territory2.y) / 2; self.x = midX; self.y = midY; // Calculate distance and scale accordingly var distance = Math.sqrt(Math.pow(self.territory1.x - self.territory2.x, 2) + Math.pow(self.territory1.y - self.territory2.y, 2)); lineGraphics.scaleX = distance / 1000; lineGraphics.scaleY = 0.05; // Calculate rotation var angle = Math.atan2(self.territory2.y - self.territory1.y, self.territory2.x - self.territory1.x); lineGraphics.rotation = angle; } }; return self; }); var Countryball = Container.expand(function (country) { var self = Container.call(this); self.country = country; self.selected = false; self.territory = null; self.alliances = []; self.power = country.basePower || 10; self.resources = country.baseResources || 20; self.money = country.baseMoney || 100; self.isAI = country.isAI || false; var ballGraphics = self.attachAsset('countryball', { anchorX: 0.5, anchorY: 0.5, tint: country.color }); var countryLabel = new Text2(country.name, { size: 24, fill: 0x000000 }); countryLabel.anchor.set(0.5, 0); countryLabel.y = 60; self.addChild(countryLabel); var highlight = self.attachAsset('selectHighlight', { anchorX: 0.5, anchorY: 0.5 }); highlight.alpha = 0; self.setSelected = function (selected) { self.selected = selected; highlight.alpha = selected ? 0.5 : 0; }; self.attack = function (target) { if (self.resources < 5) { return false; } // Apply special abilities var attackMultiplier = 1; var defenseMultiplier = 1; if (self.country.specialAbility && typeof self.country.specialAbility.effect === 'function') { attackMultiplier = self.country.specialAbility.effect(self, target, "attack"); } if (target.country.specialAbility && typeof target.country.specialAbility.effect === 'function') { defenseMultiplier = target.country.specialAbility.effect(target, self, "defense"); } var attackStrength = (self.power + Math.floor(Math.random() * 10)) * attackMultiplier; var defenseStrength = (target.power + Math.floor(Math.random() * 10)) * defenseMultiplier; self.resources -= 5; // Animate the attack with scaling tween({ target: self, to: { scaleX: 1.2, scaleY: 1.2 }, duration: 100 }); //{w}{x}{y} tween({ target: self, to: { scaleX: 1, scaleY: 1 }, duration: 100, delay: 100 }); //{z}{A}{B}{C}{D} if (attackStrength > defenseStrength) { // Successful attack animation tween({ target: target, to: { rotation: 0.2 }, duration: 200 }); //{E}{F}{G}{H}{I} tween({ target: target, to: { rotation: -0.2 }, duration: 200, delay: 200 }); //{J}{K}{L}{M}{N}{O} tween({ target: target, to: { rotation: 0 }, duration: 200, delay: 400 }); //{P}{Q}{R}{S}{T}{U} target.power = Math.max(1, target.power - 5); self.power += 3; // Check if target is weakened enough to lose territory if (target.power <= 5 && target.territory) { // Conquer a random territory from the target var targetTerritories = []; for (var i = 0; i < territories.length; i++) { if (territories[i].owner === target) { targetTerritories.push(territories[i]); } } if (targetTerritories.length > 0) { var territoryToConquer = targetTerritories[Math.floor(Math.random() * targetTerritories.length)]; territoryToConquer.claim(self); // Visual effect for territory conquest tween(territoryToConquer, { scaleX: 1.5, scaleY: 1.5 }, { duration: 300, easing: tween.bounceOut }); tween(territoryToConquer, { scaleX: 1, scaleY: 1 }, { duration: 300, delay: 300 }); } } return true; } else { // Failed attack animation tween({ target: self, to: { rotation: 0.2 }, duration: 200 }); //{X}{Y}{Z}{10}{11} tween({ target: self, to: { rotation: -0.2 }, duration: 200, delay: 200 }); //{12}{13}{14}{15}{16}{17} tween({ target: self, to: { rotation: 0 }, duration: 200, delay: 400 }); //{18}{19}{1a}{1b}{1c}{1d} self.power = Math.max(1, self.power - 2); target.power += 1; return false; } }; self.formAlliance = function (target) { if (self.alliances.indexOf(target) === -1) { self.alliances.push(target); target.alliances.push(self); return true; } return false; }; self.update = function () { if (self.territory) { // Apply resource generation special ability if it exists var resourceMultiplier = 1; if (self.country.specialAbility && typeof self.country.specialAbility.effect === 'function') { resourceMultiplier = self.country.specialAbility.effect(self, null, "resources"); } self.resources += 0.05 * resourceMultiplier; // Calculate total territory value for resource generation var totalTerritoryValue = 0; for (var t = 0; t < territories.length; t++) { if (territories[t].owner === self) { totalTerritoryValue += territories[t].value; } } self.money += 0.1 * resourceMultiplier * totalTerritoryValue; // Visual effect for resource generation (subtle pulse) if (LK.ticks % 120 === 0) { tween({ target: self, to: { scaleX: 1.05, scaleY: 1.05 }, duration: 500 }); //{1o}{1p}{1q}{1r} tween({ target: self, to: { scaleX: 1, scaleY: 1 }, duration: 500, delay: 500 }); //{1s}{1t}{1u}{1v}{1w}{1x} } } // Check for collisions with other countryballs for (var i = 0; i < countryballs.length; i++) { var otherBall = countryballs[i]; if (otherBall !== self) { var distance = Math.sqrt(Math.pow(self.x - otherBall.x, 2) + Math.pow(self.y - otherBall.y, 2)); // If countryballs are very close (collision), trigger battle if (distance < 120) { // Only trigger battle if they're not allies and both have sufficient resources if (self.alliances.indexOf(otherBall) === -1 && self.resources >= 5 && otherBall.resources >= 5) { // Add visual collision effect tween(self, { scaleX: 1.3, scaleY: 1.3 }, { duration: 200, easing: tween.bounceOut }); tween(self, { scaleX: 1, scaleY: 1 }, { duration: 200, delay: 200 }); // Trigger automatic battle if (Math.random() > 0.5) { self.attack(otherBall); } else { otherBall.attack(self); } } } } } // Enhanced AI behavior - more aggressive and strategic with territory expansion if (self.isAI && LK.ticks % 300 === 0 && Math.random() < 0.3) { // Territory expansion every 5 seconds (300 ticks) for AI countries var possibleTargets = []; var weakTargets = []; var strongTargets = []; var allyTargets = []; var neutralTargets = []; var availableTerritories = []; var enemyTerritories = []; // Find all possible targets and territories for (var i = 0; i < countryballs.length; i++) { var target = countryballs[i]; if (target !== self) { possibleTargets.push(target); // Categorize targets if (self.alliances.indexOf(target) !== -1) { allyTargets.push(target); } else if (target.power < self.power * 0.8) { weakTargets.push(target); } else if (target.power > self.power * 1.2) { strongTargets.push(target); } else { neutralTargets.push(target); } } } // Find available territories to expand to for (var i = 0; i < territories.length; i++) { var territory = territories[i]; if (!territory.owner && self.money >= 25 * territory.value) { // Check if territory is connected to current territory or close enough if (self.territory) { var distance = Math.sqrt(Math.pow(self.territory.x - territory.x, 2) + Math.pow(self.territory.y - territory.y, 2)); if (distance < 400 || self.territory.connections.indexOf(territory) !== -1) { availableTerritories.push(territory); } } else { availableTerritories.push(territory); } } else if (territory.owner && territory.owner !== self && self.alliances.indexOf(territory.owner) === -1) { enemyTerritories.push(territory); } } // AI Decision Making - Territory expansion priority if (availableTerritories.length > 0 && Math.random() < 0.4) { // Expand to available territory var targetTerritory = availableTerritories[Math.floor(Math.random() * availableTerritories.length)]; if (self.money >= 25 * targetTerritory.value) { targetTerritory.claim(self); self.money -= 25 * targetTerritory.value; self.power += targetTerritory.value; } } else if (weakTargets.length > 0 && Math.random() < 0.5) { // Attack weak targets to take their territories var targetToAttack = weakTargets[Math.floor(Math.random() * weakTargets.length)]; if (self.resources >= 5 && self.alliances.indexOf(targetToAttack) === -1) { var attackSuccess = self.attack(targetToAttack); if (attackSuccess && targetToAttack.power <= 5 && targetToAttack.territory) { // Take over their territory targetToAttack.territory.claim(self); } } } else if (possibleTargets.length > 0 && Math.random() < 0.3) { // Random attacks on any target var randomTarget = possibleTargets[Math.floor(Math.random() * possibleTargets.length)]; if (self.resources >= 5 && self.alliances.indexOf(randomTarget) === -1) { var attackSuccess = self.attack(randomTarget); if (attackSuccess && randomTarget.power <= 5 && randomTarget.territory) { // Take over their territory randomTarget.territory.claim(self); } } } // AI movement strategy - move towards targets or territories var targetToApproach = null; if (availableTerritories.length > 0) { // Move towards unclaimed territories targetToApproach = availableTerritories[Math.floor(Math.random() * availableTerritories.length)]; } else if (self.power > 15 && weakTargets.length > 0) { // Strong AI approaches weak targets targetToApproach = weakTargets[Math.floor(Math.random() * weakTargets.length)]; } else if (neutralTargets.length > 0) { // Approach neutral targets targetToApproach = neutralTargets[Math.floor(Math.random() * neutralTargets.length)]; } else if (possibleTargets.length > 0) { // Fallback to random target targetToApproach = possibleTargets[Math.floor(Math.random() * possibleTargets.length)]; } // Move towards target for collision-based combat or territory claiming if (targetToApproach && self.resources >= 5) { var dx = targetToApproach.x - self.x; var dy = targetToApproach.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 120) { // Move closer to target var moveSpeed = 3; // Increased speed for more aggressive expansion self.x += dx / distance * moveSpeed; self.y += dy / distance * moveSpeed; } } } }; self.down = function (x, y, obj) { game.handleCountryballSelect(self); }; return self; }); var MainMenu = Container.expand(function () { var self = Container.call(this); var menuBackground = self.attachAsset('menuBackground', { anchorX: 0.5, anchorY: 0.5, scaleX: 3, scaleY: 3 }); menuBackground.alpha = 0.8; // Set initial visibility state self.visible = true; // Create the submenus first before trying to access them self.settingsMenu = new Container(); self.creditsMenu = new Container(); // Ensure submenus are hidden initially self.settingsMenu.visible = false; self.creditsMenu.visible = false; var titleText = new Text2("COUNTRYBALL WARFARE", { size: 60, fill: 0xFFFFFF }); titleText.anchor.set(0.5, 0); titleText.y = -350; self.addChild(titleText); // Add start game button var startButton = new Text2("START GAME", { size: 48, fill: 0xFFFF00 }); startButton.anchor.set(0.5, 0.5); startButton.y = -100; startButton.interactive = true; self.addChild(startButton); // Add settings button var settingsButton = new Text2("SETTINGS", { size: 48, fill: 0xFFFF00 }); settingsButton.anchor.set(0.5, 0.5); settingsButton.y = 0; settingsButton.interactive = true; self.addChild(settingsButton); // Add credits button var creditsButton = new Text2("CREDITS", { size: 48, fill: 0xFFFF00 }); creditsButton.anchor.set(0.5, 0.5); creditsButton.y = 100; creditsButton.interactive = true; self.addChild(creditsButton); // Settings menu (hidden initially) self.settingsMenu = new Container(); self.settingsMenu.visible = false; var settingsTitle = new Text2("SETTINGS", { size: 48, fill: 0xFFFFFF }); settingsTitle.anchor.set(0.5, 0); settingsTitle.y = -300; self.settingsMenu.addChild(settingsTitle); // Sound toggle button self.soundEnabled = storage.soundEnabled !== undefined ? storage.soundEnabled : true; var soundToggleText = new Text2("SOUND: " + (self.soundEnabled ? "ON" : "OFF"), { size: 36, fill: 0xFFFF00 }); soundToggleText.anchor.set(0.5, 0.5); soundToggleText.y = -150; soundToggleText.interactive = true; self.settingsMenu.addChild(soundToggleText); // Music toggle button self.musicEnabled = storage.musicEnabled !== undefined ? storage.musicEnabled : true; var musicToggleText = new Text2("MUSIC: " + (self.musicEnabled ? "ON" : "OFF"), { size: 36, fill: 0xFFFF00 }); musicToggleText.anchor.set(0.5, 0.5); musicToggleText.y = -50; musicToggleText.interactive = true; self.settingsMenu.addChild(musicToggleText); // Back button for settings var backButton = new Text2("BACK", { size: 36, fill: 0xFFFF00 }); backButton.anchor.set(0.5, 0.5); backButton.y = 150; backButton.interactive = true; self.settingsMenu.addChild(backButton); self.addChild(self.settingsMenu); // Credits menu (hidden initially) self.creditsMenu = new Container(); self.creditsMenu.visible = false; var creditsTitle = new Text2("CREDITS", { size: 48, fill: 0xFFFFFF }); creditsTitle.anchor.set(0.5, 0); creditsTitle.y = -300; self.creditsMenu.addChild(creditsTitle); var creditsDeveloper = new Text2("GAME DEVELOPMENT BY", { size: 36, fill: 0xFFFFFF }); creditsDeveloper.anchor.set(0.5, 0); creditsDeveloper.y = -200; self.creditsMenu.addChild(creditsDeveloper); var creditsUser = new Text2("YOU", { size: 42, fill: 0xFFFF00 }); creditsUser.anchor.set(0.5, 0); creditsUser.y = -130; self.creditsMenu.addChild(creditsUser); var creditsAssistant = new Text2("AND", { size: 36, fill: 0xFFFFFF }); creditsAssistant.anchor.set(0.5, 0); creditsAssistant.y = -70; self.creditsMenu.addChild(creditsAssistant); var creditsAI = new Text2("AVA", { size: 42, fill: 0xFFFF00 }); creditsAI.anchor.set(0.5, 0); creditsAI.y = -10; self.creditsMenu.addChild(creditsAI); // Back button for credits var creditsBackButton = new Text2("BACK", { size: 36, fill: 0xFFFF00 }); creditsBackButton.anchor.set(0.5, 0.5); creditsBackButton.y = 150; creditsBackButton.interactive = true; self.creditsMenu.addChild(creditsBackButton); self.addChild(self.creditsMenu); // Event handlers startButton.down = function () { game.startGame(); }; settingsButton.down = function () { self.showSettings(); }; creditsButton.down = function () { self.showCredits(); }; backButton.down = function () { self.hideSettings(); }; creditsBackButton.down = function () { self.hideCredits(); }; soundToggleText.down = function () { self.soundEnabled = !self.soundEnabled; storage.soundEnabled = self.soundEnabled; soundToggleText.setText("SOUND: " + (self.soundEnabled ? "ON" : "OFF")); }; musicToggleText.down = function () { self.musicEnabled = !self.musicEnabled; storage.musicEnabled = self.musicEnabled; musicToggleText.setText("MUSIC: " + (self.musicEnabled ? "ON" : "OFF")); if (self.musicEnabled) { LK.playMusic('battleMusic'); } else { LK.stopMusic(); } }; self.showSettings = function () { // Hide main menu buttons startButton.visible = false; settingsButton.visible = false; creditsButton.visible = false; // Show settings menu self.settingsMenu.visible = true; // Ensure credits menu is hidden self.creditsMenu.visible = false; }; self.hideSettings = function () { // Show main menu buttons startButton.visible = true; settingsButton.visible = true; creditsButton.visible = true; // Hide settings menu self.settingsMenu.visible = false; }; self.showCredits = function () { // Hide main menu buttons startButton.visible = false; settingsButton.visible = false; creditsButton.visible = false; // Show credits menu self.creditsMenu.visible = true; // Ensure settings menu is hidden self.settingsMenu.visible = false; }; self.hideCredits = function () { // Show main menu buttons startButton.visible = true; settingsButton.visible = true; creditsButton.visible = true; // Hide credits menu self.creditsMenu.visible = false; }; return self; }); var StatsDisplay = Container.expand(function () { var self = Container.call(this); var background = self.attachAsset('menuBackground', { anchorX: 0.5, anchorY: 0 }); background.alpha = 0.7; self.titleText = new Text2("COUNTRY STATS", { size: 36, fill: 0x000000 }); self.titleText.anchor.set(0.5, 0); self.titleText.y = 20; self.addChild(self.titleText); self.nameText = new Text2("", { size: 30, fill: 0x000000 }); self.nameText.anchor.set(0.5, 0); self.nameText.y = 80; self.addChild(self.nameText); self.powerText = new Text2("", { size: 24, fill: 0x000000 }); self.powerText.anchor.set(0.5, 0); self.powerText.y = 120; self.addChild(self.powerText); self.resourcesText = new Text2("", { size: 24, fill: 0x000000 }); self.resourcesText.anchor.set(0.5, 0); self.resourcesText.y = 160; self.addChild(self.resourcesText); self.moneyText = new Text2("", { size: 24, fill: 0x008000 }); self.moneyText.anchor.set(0.5, 0); self.moneyText.y = 190; self.addChild(self.moneyText); self.alliancesText = new Text2("", { size: 24, fill: 0x000000 }); self.alliancesText.anchor.set(0.5, 0); self.alliancesText.y = 200; self.addChild(self.alliancesText); self.update = function (countryball) { if (!countryball) { self.visible = false; return; } self.visible = true; self.nameText.setText(countryball.country.name); self.powerText.setText("Military Power: " + Math.floor(countryball.power)); self.resourcesText.setText("Resources: " + Math.floor(countryball.resources)); self.moneyText.setText("Money: $" + Math.floor(countryball.money)); var allianceText = "Alliances: "; if (countryball.alliances.length === 0) { allianceText += "None"; } else { for (var i = 0; i < countryball.alliances.length; i++) { if (i > 0) { allianceText += ", "; } allianceText += countryball.alliances[i].country.name; } } self.alliancesText.setText(allianceText); }; return self; }); var TechUpgrade = Container.expand(function (name, cost, effect, description) { var self = Container.call(this); self.name = name; self.cost = cost; self.effect = effect; self.description = description; self.purchased = false; var background = self.attachAsset('menuBackground', { anchorX: 0.5, anchorY: 0.5, width: 200, height: 120 }); background.alpha = 0.8; var nameText = new Text2(name, { size: 20, fill: 0x000000 }); nameText.anchor.set(0.5, 0); nameText.y = -40; self.addChild(nameText); var costText = new Text2("Cost: " + cost, { size: 16, fill: 0x000000 }); costText.anchor.set(0.5, 0); costText.y = -15; self.addChild(costText); var descText = new Text2(description, { size: 12, fill: 0x000000 }); descText.anchor.set(0.5, 0.5); descText.y = 10; self.addChild(descText); self.down = function (x, y, obj) { game.purchaseTechUpgrade(self); }; return self; }); var Territory = Container.expand(function (position, value) { var self = Container.call(this); self.value = value || 1; self.owner = null; var territoryGraphics = self.attachAsset('territory', { anchorX: 0.5, anchorY: 0.5 }); var valueText = new Text2("+" + self.value, { size: 24, fill: 0xFFFFFF }); valueText.anchor.set(0.5, 0.5); self.addChild(valueText); self.x = position.x; self.y = position.y; self.connections = []; // Array to store connected territories self.claim = function (countryball) { if (self.owner) { self.owner.territory = null; } self.owner = countryball; countryball.territory = self; territoryGraphics.tint = countryball.country.color; }; // Add method to connect territories self.connectTo = function (otherTerritory) { if (self.connections.indexOf(otherTerritory) === -1) { self.connections.push(otherTerritory); otherTerritory.connections.push(self); } }; self.down = function (x, y, obj) { game.handleTerritorySelect(self); }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x87CEEB // Sky blue background }); /**** * Game Code ****/ // Game configuration var countryData = [{ name: "USAball", color: 0xff0000, basePower: 15, baseResources: 30, baseMoney: 150, isAI: false, specialAbility: { name: "Air Superiority", description: "25% more effective when attacking", effect: function effect(self, target, action) { if (action === "attack") { return 1.25; } return 1; } } }, { name: "UKball", color: 0x0000ff, basePower: 12, baseResources: 25, baseMoney: 125, isAI: true, specialAbility: { name: "Naval Power", description: "Generates 20% more resources", effect: function effect(self, target, action) { if (action === "resources") { return 1.2; } return 1; } } }, { name: "Germanyball", color: 0x000000, basePower: 13, baseResources: 28, baseMoney: 135, isAI: true, specialAbility: { name: "Industrial Efficiency", description: "Technology costs 15% less", effect: function effect(self, target, action) { if (action === "tech") { return 0.85; } return 1; } } }, { name: "Franceball", color: 0x0055ff, basePower: 11, baseResources: 22, baseMoney: 110, isAI: true, specialAbility: { name: "Diplomatic Influence", description: "Alliance bonuses increased by 20%", effect: function effect(self, target, action) { if (action === "alliance") { return 1.2; } return 1; } } }, { name: "Russiaball", color: 0xffffff, basePower: 14, baseResources: 20, baseMoney: 120, isAI: true, specialAbility: { name: "Winter Resistance", description: "30% more effective when defending", effect: function effect(self, target, action) { if (action === "defense") { return 1.3; } return 1; } } }, { name: "Chinaball", color: 0xffff00, basePower: 15, baseResources: 35, baseMoney: 160, isAI: true, specialAbility: { name: "Population Advantage", description: "Territories provide 25% more power", effect: function effect(self, target, action) { if (action === "territory") { return 1.25; } return 1; } } }]; // Game variables var countryballs = []; var territories = []; var connectionLines = []; var selectedCountryball = null; var targetCountryball = null; var statsDisplay = null; var attackButton = null; var allianceButton = null; var scoreText = null; var moneyText = null; var techUpgrades = []; var techMenuOpen = false; var techButton = null; var eventDisplay = null; var lastEventTime = 0; var worldEvents = [{ name: "Economic Crisis", description: "Resources reduced by 20% for all nations", effect: function effect() { for (var i = 0; i < countryballs.length; i++) { countryballs[i].resources *= 0.8; } return "Economic Crisis hit all nations!"; } }, { name: "Natural Disaster", description: "Random territory loses value", effect: function effect() { var randomTerritory = territories[Math.floor(Math.random() * territories.length)]; randomTerritory.value = Math.max(1, randomTerritory.value - 1); var message = "Natural disaster in " + (randomTerritory.owner ? randomTerritory.owner.country.name : "unclaimed territory"); return message; } }, { name: "Technological Breakthrough", description: "Random nation gains power", effect: function effect() { var randomCountry = countryballs[Math.floor(Math.random() * countryballs.length)]; randomCountry.power += 5; return randomCountry.country.name + " achieved a technological breakthrough!"; } }, { name: "Peace Summit", description: "Relations improve between nations", effect: function effect() { for (var i = 0; i < countryballs.length; i++) { if (Math.random() < 0.3 && !countryballs[i].isAI) { for (var j = 0; j < countryballs.length; j++) { if (i !== j && countryballs[i].alliances.indexOf(countryballs[j]) === -1) { countryballs[i].formAlliance(countryballs[j]); return countryballs[i].country.name + " and " + countryballs[j].country.name + " formed an alliance at the Peace Summit!"; } } } } return "Peace Summit ended with minor agreements."; } }]; // Initialize the game game.init = function () { // Create main menu var mainMenu = new MainMenu(); mainMenu.x = 2048 / 2; mainMenu.y = 2732 / 2; game.mainMenu = mainMenu; game.addChild(mainMenu); // Set gameStarted flag to false initially game.gameStarted = false; // Create score text but don't add to GUI yet scoreText = new Text2("Score: 0", { size: 36, fill: 0xFFFFFF }); scoreText.anchor.set(0, 0); scoreText.x = 120; scoreText.y = 30; // Create event display but don't add to GUI yet eventDisplay = new Text2("", { size: 28, fill: 0xFFFFFF }); eventDisplay.anchor.set(0.5, 0); eventDisplay.x = 2048 / 2; eventDisplay.y = 100; eventDisplay.alpha = 0; }; game.handleCountryballSelect = function (countryball) { // Don't allow selecting AI countryballs as the active player if (countryball.isAI) { if (selectedCountryball) { // If we already have a selected countryball, set this as target if (targetCountryball) { targetCountryball.setSelected(false); } targetCountryball = countryball; targetCountryball.setSelected(true); } } else { // Set as the active player if (selectedCountryball) { selectedCountryball.setSelected(false); } if (targetCountryball) { targetCountryball.setSelected(false); targetCountryball = null; } selectedCountryball = countryball; selectedCountryball.setSelected(true); statsDisplay.update(selectedCountryball); } }; game.handleTerritorySelect = function (territory) { // If we have a selected countryball, claim the territory if (selectedCountryball) { // Check if territory is already owned by this countryball if (territory.owner === selectedCountryball) { return; } // Check if we have enough money to claim it if (selectedCountryball.money >= 25 * territory.value) { territory.claim(selectedCountryball); selectedCountryball.money -= 25 * territory.value; selectedCountryball.power += territory.value; statsDisplay.update(selectedCountryball); game.updateScore(); } } }; game.handleActionButton = function (button) { if (button.action === "tech") { // Toggle tech menu visibility techMenuOpen = !techMenuOpen; for (var i = 0; i < techUpgrades.length; i++) { techUpgrades[i].visible = techMenuOpen; } return; } if (!selectedCountryball || !targetCountryball && button.action !== "tech") { return; } if (button.action === "attack") { if (selectedCountryball.attack(targetCountryball)) { // Successful attack if (storage.soundEnabled !== false) { LK.getSound('attack').play(); } LK.effects.flashObject(targetCountryball, 0xff0000, 500); // Check if we defeated the target if (targetCountryball.power <= 5) { // Take their territory if they have one if (targetCountryball.territory) { targetCountryball.territory.claim(selectedCountryball); } } } else { // Failed attack LK.effects.flashObject(selectedCountryball, 0xff0000, 500); } statsDisplay.update(selectedCountryball); game.updateScore(); } else if (button.action === "alliance") { // Apply alliance special ability if it exists var allianceMultiplier = 1; if (selectedCountryball.country.specialAbility && typeof selectedCountryball.country.specialAbility.effect === 'function') { allianceMultiplier = selectedCountryball.country.specialAbility.effect(selectedCountryball, targetCountryball, "alliance"); } if (selectedCountryball.formAlliance(targetCountryball)) { if (storage.soundEnabled !== false) { LK.getSound('alliance').play(); } LK.effects.flashObject(targetCountryball, 0x00ff00, 500); // Alliance bonus - both countries get a small power boost var powerBoost = 2 * allianceMultiplier; selectedCountryball.power += powerBoost; targetCountryball.power += powerBoost; statsDisplay.update(selectedCountryball); } } }; // Add tech upgrade handler game.purchaseTechUpgrade = function (techUpgrade) { if (!selectedCountryball) { return; } // Apply tech cost special ability if it exists var techCostMultiplier = 1; if (selectedCountryball.country.specialAbility && typeof selectedCountryball.country.specialAbility.effect === 'function') { techCostMultiplier = selectedCountryball.country.specialAbility.effect(selectedCountryball, null, "tech"); } var adjustedCost = Math.floor(techUpgrade.cost * techCostMultiplier); // Check if player has enough money and hasn't purchased it yet if (selectedCountryball.money >= adjustedCost && !techUpgrade.purchased) { selectedCountryball.money -= adjustedCost; techUpgrade.purchased = true; // Apply the upgrade effect if (typeof techUpgrade.effect === 'function') { techUpgrade.effect(selectedCountryball); } // Visual feedback LK.effects.flashObject(techUpgrade, 0x00ff00, 500); tween({ target: techUpgrade, to: { alpha: 0.5 }, duration: 300 }); //{8A}{8B}{8C} // Update stats statsDisplay.update(selectedCountryball); game.updateScore(); // Show event notification game.showEventNotification(selectedCountryball.country.name + " acquired " + techUpgrade.name + " technology!"); } else if (techUpgrade.purchased) { // Already purchased feedback LK.effects.flashObject(techUpgrade, 0xff0000, 500); } else { // Not enough resources feedback LK.effects.flashObject(techUpgrade, 0xffff00, 500); } }; // Add world events system game.triggerRandomEvent = function () { // Only trigger events if some time has passed since the last one if (LK.ticks - lastEventTime < 600) { return; } // 5% chance each update to trigger an event if (Math.random() < 0.05) { var randomEvent = worldEvents[Math.floor(Math.random() * worldEvents.length)]; var message = randomEvent.effect(); game.showEventNotification(message); lastEventTime = LK.ticks; } }; // Add notification display game.showEventNotification = function (message) { eventDisplay.setText(message); eventDisplay.alpha = 1; tween({ target: eventDisplay, to: { y: 120 }, duration: 500 }); //{8M}{8N}{8O}{8P} tween({ target: eventDisplay, to: { alpha: 0 }, duration: 500, delay: 3000 }); //{8Q}{8R}{8S}{8T} tween({ target: eventDisplay, to: { y: 100 }, duration: 500, delay: 3500 }); //{8U}{8V}{8W}{8X} }; game.updateScore = function () { var playerScore = 0; // Calculate score based on power, resources, territories and alliances var playerBall = countryballs[0]; // First countryball is the player playerScore += playerBall.power * 5; playerScore += playerBall.resources * 2; playerScore += playerBall.alliances.length * 50; // Add score for territories for (var i = 0; i < territories.length; i++) { if (territories[i].owner === playerBall) { playerScore += territories[i].value * 20; } } LK.setScore(Math.floor(playerScore)); scoreText.setText("Score: " + LK.getScore()); // Check win condition var playerTerritories = 0; for (var i = 0; i < territories.length; i++) { if (territories[i].owner === playerBall) { playerTerritories++; } } if (playerTerritories >= territories.length / 2) { LK.showYouWin(); } // Check lose condition var playerHasTerritories = false; for (var i = 0; i < territories.length; i++) { if (territories[i].owner === playerBall) { playerHasTerritories = true; break; } } if (!playerHasTerritories && playerBall.power < 5) { LK.showGameOver(); } }; // Initialize the menu game.init(); // Move event handler game.move = function (x, y, obj) { // Nothing to do for move events in this game }; // Add game start functionality game.startGame = function () { // Clear the stage first - remove all children while (game.children.length > 0) { game.removeChild(game.children[0]); } // Clear any existing game elements countryballs = []; territories = []; techUpgrades = []; selectedCountryball = null; targetCountryball = null; // Set game started flag game.gameStarted = true; // Remove main menu from GUI if it exists if (game.mainMenu) { if (game.mainMenu.parent) { game.mainMenu.parent.removeChild(game.mainMenu); } game.mainMenu = null; } // Play background music if enabled if (storage.musicEnabled !== false) { LK.playMusic('battleMusic'); } // Add GUI elements now that the game is starting LK.gui.addChild(scoreText); // Create money display moneyText = new Text2("Money: $0", { size: 36, fill: 0x00FF00 }); moneyText.anchor.set(1, 0); moneyText.x = 2048 - 120; moneyText.y = 30; LK.gui.addChild(moneyText); // Create the title var titleText = new Text2("COUNTRYBALL WARFARE", { size: 48, fill: 0xFFFFFF }); titleText.anchor.set(0.5, 0); titleText.x = 2048 / 2; titleText.y = 30; LK.gui.addChild(titleText); // Create territories with better distribution and connections var territoryPositions = [{ x: 250, y: 300 }, { x: 500, y: 280 }, { x: 750, y: 320 }, { x: 1000, y: 280 }, { x: 1250, y: 320 }, { x: 1500, y: 280 }, { x: 1750, y: 320 }, { x: 150, y: 500 }, { x: 400, y: 480 }, { x: 650, y: 520 }, { x: 900, y: 480 }, { x: 1150, y: 520 }, { x: 1400, y: 480 }, { x: 1650, y: 520 }, { x: 1900, y: 480 }, { x: 200, y: 700 }, { x: 450, y: 680 }, { x: 700, y: 720 }, { x: 950, y: 680 }, { x: 1200, y: 720 }, { x: 1450, y: 680 }, { x: 1700, y: 720 }, { x: 1950, y: 680 }, { x: 300, y: 900 }, { x: 550, y: 880 }, { x: 800, y: 920 }, { x: 1050, y: 880 }, { x: 1300, y: 920 }, { x: 1550, y: 880 }, { x: 1800, y: 920 }, { x: 150, y: 1100 }, { x: 400, y: 1080 }, { x: 650, y: 1120 }, { x: 900, y: 1080 }, { x: 1150, y: 1120 }, { x: 1400, y: 1080 }, { x: 1650, y: 1120 }, { x: 1900, y: 1080 }, { x: 250, y: 1300 }, { x: 500, y: 1280 }, { x: 750, y: 1320 }, { x: 1000, y: 1280 }, { x: 1250, y: 1320 }, { x: 1500, y: 1280 }, { x: 1750, y: 1320 }, { x: 350, y: 1500 }, { x: 600, y: 1480 }, { x: 850, y: 1520 }, { x: 1100, y: 1480 }, { x: 1350, y: 1520 }, { x: 1600, y: 1480 }, { x: 400, y: 1700 }, { x: 700, y: 1680 }, { x: 1000, y: 1720 }, { x: 1300, y: 1680 }, { x: 1600, y: 1720 }, { x: 500, y: 1900 }, { x: 800, y: 1880 }, { x: 1100, y: 1920 }, { x: 1400, y: 1880 }, { x: 1700, y: 1920 }, { x: 600, y: 2100 }, { x: 900, y: 2080 }, { x: 1200, y: 2120 }, { x: 1500, y: 2080 }, { x: 750, y: 2300 }, { x: 1050, y: 2280 }, { x: 1350, y: 2320 }]; for (var i = 0; i < territoryPositions.length; i++) { var territory = new Territory(territoryPositions[i], Math.floor(Math.random() * 3) + 1); territories.push(territory); game.addChild(territory); } // Establish territory connections based on proximity connectionLines = []; for (var i = 0; i < territories.length; i++) { for (var j = i + 1; j < territories.length; j++) { var distance = Math.sqrt(Math.pow(territories[i].x - territories[j].x, 2) + Math.pow(territories[i].y - territories[j].y, 2)); // Connect territories that are within 300 pixels of each other for tighter strategic gameplay if (distance < 300) { territories[i].connectTo(territories[j]); // Create visual connection line var connectionLine = new ConnectionLine(territories[i], territories[j]); connectionLines.push(connectionLine); game.addChild(connectionLine); } } } // Create countryballs for (var i = 0; i < countryData.length; i++) { var countryball = new Countryball(countryData[i]); // Position countryballs in a circle around the center var angle = i / countryData.length * Math.PI * 2; var radius = 700; countryball.x = 2048 / 2 + Math.cos(angle) * radius; countryball.y = 2732 / 2 + Math.sin(angle) * radius; countryballs.push(countryball); game.addChild(countryball); // Give each countryball a starting territory if (i < territories.length) { territories[i].claim(countryball); } } // The player controls the first countryball selectedCountryball = countryballs[0]; selectedCountryball.setSelected(true); // Give player 3 random territories at start var availableForPlayer = []; for (var i = 0; i < territories.length; i++) { if (!territories[i].owner) { availableForPlayer.push(territories[i]); } } // Shuffle and take first 3 available territories for player for (var i = 0; i < Math.min(3, availableForPlayer.length); i++) { var randomIndex = Math.floor(Math.random() * availableForPlayer.length); var selectedTerritory = availableForPlayer[randomIndex]; selectedTerritory.claim(selectedCountryball); availableForPlayer.splice(randomIndex, 1); } // Create stats display statsDisplay = new StatsDisplay(); statsDisplay.x = 2048 / 2; statsDisplay.y = 2732 - 450; statsDisplay.update(selectedCountryball); game.addChild(statsDisplay); // Create buttons attackButton = new ActionButton("ATTACK", "attack"); attackButton.x = 2048 / 2 - 200; attackButton.y = 2732 - 100; game.addChild(attackButton); allianceButton = new ActionButton("ALLIANCE", "alliance"); allianceButton.x = 2048 / 2; allianceButton.y = 2732 - 100; game.addChild(allianceButton); // Add tech button techButton = new ActionButton("TECH", "tech"); techButton.x = 2048 / 2 + 200; techButton.y = 2732 - 100; game.addChild(techButton); // Create tech upgrades var techList = [{ name: "Advanced Weaponry", cost: 100, effect: function effect(countryball) { countryball.power += 10; }, description: "Increases military power by 10" }, { name: "Economic Reforms", cost: 80, effect: function effect(countryball) { countryball.money += 50; }, description: "Adds $50 immediately" }, { name: "Diplomacy", cost: 35, effect: function effect(countryball) { // Form alliances with two random countries var unalliedCountries = countryballs.filter(function (c) { return c !== countryball && countryball.alliances.indexOf(c) === -1; }); for (var i = 0; i < Math.min(2, unalliedCountries.length); i++) { countryball.formAlliance(unalliedCountries[i]); } }, description: "Form alliances with 2 random countries" }, { name: "Espionage", cost: 45, effect: function effect(countryball) { // Reduce power of all enemies for (var i = 0; i < countryballs.length; i++) { if (countryballs[i] !== countryball && countryball.alliances.indexOf(countryballs[i]) === -1) { countryballs[i].power = Math.max(5, countryballs[i].power - 3); } } }, description: "Reduces enemy power by 3" }]; // Create tech upgrades but don't add them to the stage yet for (var i = 0; i < techList.length; i++) { var tech = new TechUpgrade(techList[i].name, techList[i].cost, techList[i].effect, techList[i].description); tech.x = 2048 / 2; tech.y = 800 + i * 150; tech.visible = false; techUpgrades.push(tech); game.addChild(tech); } // Create event display eventDisplay = new Text2("", { size: 28, fill: 0xFFFFFF }); eventDisplay.anchor.set(0.5, 0); eventDisplay.x = 2048 / 2; eventDisplay.y = 100; eventDisplay.alpha = 0; LK.gui.addChild(eventDisplay); // Initial score game.updateScore(); }; // Update function game.update = function () { // Only update game elements if the game has started if (!game.gameStarted) { // Do nothing when in menu state return; } // Update money display if it exists if (selectedCountryball && moneyText) { moneyText.setText("Money: $" + Math.floor(selectedCountryball.money)); } // Update all countryballs for (var i = 0; i < countryballs.length; i++) { countryballs[i].update(); } // Update stats display if (selectedCountryball) { statsDisplay.update(selectedCountryball); } // Trigger random world events game.triggerRandomEvent(); // Apply territory special ability for China if (selectedCountryball && selectedCountryball.country.name === "Chinaball" && selectedCountryball.territory) { var territoryMultiplier = 1; if (selectedCountryball.country.specialAbility && typeof selectedCountryball.country.specialAbility.effect === 'function') { territoryMultiplier = selectedCountryball.country.specialAbility.effect(selectedCountryball, null, "territory"); } // Apply the bonus every 10 seconds if (LK.ticks % 600 === 0) { selectedCountryball.power += selectedCountryball.territory.value * territoryMultiplier; statsDisplay.update(selectedCountryball); } } // Check for country elimination - countries with no territories and low power are eliminated for (var i = countryballs.length - 1; i >= 0; i--) { var countryball = countryballs[i]; var hasTerritory = false; // Check if country has any territories for (var j = 0; j < territories.length; j++) { if (territories[j].owner === countryball) { hasTerritory = true; break; } } // Eliminate country if they have no territories and very low power if (!hasTerritory && countryball.power <= 3) { // Visual elimination effect tween(countryball, { alpha: 0, scaleX: 0.1, scaleY: 0.1 }, { duration: 1000, onFinish: function onFinish() { // Remove from game if (countryball.parent) { countryball.parent.removeChild(countryball); } } }); // Show elimination notification game.showEventNotification(countryball.country.name + " has been eliminated from the game!"); // Remove from countryballs array countryballs.splice(i, 1); // If eliminated country was selected, select another if (selectedCountryball === countryball) { selectedCountryball = null; targetCountryball = null; // Find the first remaining player country for (var k = 0; k < countryballs.length; k++) { if (!countryballs[k].isAI) { selectedCountryball = countryballs[k]; selectedCountryball.setSelected(true); break; } } } } } // Check if anyone has won the game var remainingCountries = 0; var mostPowerfulCountry = null; for (var i = 0; i < countryballs.length; i++) { var countryball = countryballs[i]; if (countryball.power > 0) { remainingCountries++; if (!mostPowerfulCountry || countryball.power > mostPowerfulCountry.power) { mostPowerfulCountry = countryball; } } } // Check if player has been eliminated from the countryballs array if (selectedCountryball && countryballs.indexOf(selectedCountryball) === -1) { LK.showGameOver(); } // Check if player still exists but has lost all territories and has very low power if (selectedCountryball && countryballs.indexOf(selectedCountryball) !== -1) { var playerHasTerritory = false; // Check if player has any territories for (var j = 0; j < territories.length; j++) { if (territories[j].owner === selectedCountryball) { playerHasTerritory = true; break; } } // Player loses if they have no territories and very low power if (!playerHasTerritory && selectedCountryball.power <= 3) { LK.showGameOver(); } } // Check if only one country remains if (remainingCountries <= 1) { if (mostPowerfulCountry && !mostPowerfulCountry.isAI) { LK.showYouWin(); } else { LK.showGameOver(); } } // Update game state every 5 seconds if (LK.ticks % 300 === 0) { game.updateScore(); if (selectedCountryball && moneyText) { moneyText.setText("Money: $" + Math.floor(selectedCountryball.money)); } } // Update connection lines if (connectionLines) { for (var i = 0; i < connectionLines.length; i++) { connectionLines[i].update(); } } // Add visual effects to territories every 2 seconds if (LK.ticks % 120 === 0) { for (var i = 0; i < territories.length; i++) { if (territories[i].owner) { tween(territories[i], { scaleX: 1.1, scaleY: 1.1 }, { duration: 300 }); //{c7}{c8}{c9}{ca} tween(territories[i], { scaleX: 1, scaleY: 1 }, { duration: 300, delay: 300 }); //{cb}{cc}{cd}{ce}{cf} } } } };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var ActionButton = Container.expand(function (text, action, color) {
var self = Container.call(this);
var buttonGraphics = self.attachAsset(action + 'Button', {
anchorX: 0.5,
anchorY: 0.5
});
var buttonLabel = new Text2(text, {
size: 28,
fill: 0xFFFFFF
});
buttonLabel.anchor.set(0.5, 0.5);
self.addChild(buttonLabel);
self.action = action;
self.down = function (x, y, obj) {
game.handleActionButton(self);
};
return self;
});
var ConnectionLine = Container.expand(function (territory1, territory2) {
var self = Container.call(this);
self.territory1 = territory1;
self.territory2 = territory2;
self.connectionVisible = true;
// Create a simple line representation using two small rectangles
var lineGraphics = self.attachAsset('selectHighlight', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.1,
scaleY: 0.1
});
lineGraphics.alpha = 0.3;
lineGraphics.tint = 0x808080;
self.update = function () {
if (self.connectionVisible) {
// Position the line between the two territories
var midX = (self.territory1.x + self.territory2.x) / 2;
var midY = (self.territory1.y + self.territory2.y) / 2;
self.x = midX;
self.y = midY;
// Calculate distance and scale accordingly
var distance = Math.sqrt(Math.pow(self.territory1.x - self.territory2.x, 2) + Math.pow(self.territory1.y - self.territory2.y, 2));
lineGraphics.scaleX = distance / 1000;
lineGraphics.scaleY = 0.05;
// Calculate rotation
var angle = Math.atan2(self.territory2.y - self.territory1.y, self.territory2.x - self.territory1.x);
lineGraphics.rotation = angle;
}
};
return self;
});
var Countryball = Container.expand(function (country) {
var self = Container.call(this);
self.country = country;
self.selected = false;
self.territory = null;
self.alliances = [];
self.power = country.basePower || 10;
self.resources = country.baseResources || 20;
self.money = country.baseMoney || 100;
self.isAI = country.isAI || false;
var ballGraphics = self.attachAsset('countryball', {
anchorX: 0.5,
anchorY: 0.5,
tint: country.color
});
var countryLabel = new Text2(country.name, {
size: 24,
fill: 0x000000
});
countryLabel.anchor.set(0.5, 0);
countryLabel.y = 60;
self.addChild(countryLabel);
var highlight = self.attachAsset('selectHighlight', {
anchorX: 0.5,
anchorY: 0.5
});
highlight.alpha = 0;
self.setSelected = function (selected) {
self.selected = selected;
highlight.alpha = selected ? 0.5 : 0;
};
self.attack = function (target) {
if (self.resources < 5) {
return false;
}
// Apply special abilities
var attackMultiplier = 1;
var defenseMultiplier = 1;
if (self.country.specialAbility && typeof self.country.specialAbility.effect === 'function') {
attackMultiplier = self.country.specialAbility.effect(self, target, "attack");
}
if (target.country.specialAbility && typeof target.country.specialAbility.effect === 'function') {
defenseMultiplier = target.country.specialAbility.effect(target, self, "defense");
}
var attackStrength = (self.power + Math.floor(Math.random() * 10)) * attackMultiplier;
var defenseStrength = (target.power + Math.floor(Math.random() * 10)) * defenseMultiplier;
self.resources -= 5;
// Animate the attack with scaling
tween({
target: self,
to: {
scaleX: 1.2,
scaleY: 1.2
},
duration: 100
}); //{w}{x}{y}
tween({
target: self,
to: {
scaleX: 1,
scaleY: 1
},
duration: 100,
delay: 100
}); //{z}{A}{B}{C}{D}
if (attackStrength > defenseStrength) {
// Successful attack animation
tween({
target: target,
to: {
rotation: 0.2
},
duration: 200
}); //{E}{F}{G}{H}{I}
tween({
target: target,
to: {
rotation: -0.2
},
duration: 200,
delay: 200
}); //{J}{K}{L}{M}{N}{O}
tween({
target: target,
to: {
rotation: 0
},
duration: 200,
delay: 400
}); //{P}{Q}{R}{S}{T}{U}
target.power = Math.max(1, target.power - 5);
self.power += 3;
// Check if target is weakened enough to lose territory
if (target.power <= 5 && target.territory) {
// Conquer a random territory from the target
var targetTerritories = [];
for (var i = 0; i < territories.length; i++) {
if (territories[i].owner === target) {
targetTerritories.push(territories[i]);
}
}
if (targetTerritories.length > 0) {
var territoryToConquer = targetTerritories[Math.floor(Math.random() * targetTerritories.length)];
territoryToConquer.claim(self);
// Visual effect for territory conquest
tween(territoryToConquer, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 300,
easing: tween.bounceOut
});
tween(territoryToConquer, {
scaleX: 1,
scaleY: 1
}, {
duration: 300,
delay: 300
});
}
}
return true;
} else {
// Failed attack animation
tween({
target: self,
to: {
rotation: 0.2
},
duration: 200
}); //{X}{Y}{Z}{10}{11}
tween({
target: self,
to: {
rotation: -0.2
},
duration: 200,
delay: 200
}); //{12}{13}{14}{15}{16}{17}
tween({
target: self,
to: {
rotation: 0
},
duration: 200,
delay: 400
}); //{18}{19}{1a}{1b}{1c}{1d}
self.power = Math.max(1, self.power - 2);
target.power += 1;
return false;
}
};
self.formAlliance = function (target) {
if (self.alliances.indexOf(target) === -1) {
self.alliances.push(target);
target.alliances.push(self);
return true;
}
return false;
};
self.update = function () {
if (self.territory) {
// Apply resource generation special ability if it exists
var resourceMultiplier = 1;
if (self.country.specialAbility && typeof self.country.specialAbility.effect === 'function') {
resourceMultiplier = self.country.specialAbility.effect(self, null, "resources");
}
self.resources += 0.05 * resourceMultiplier;
// Calculate total territory value for resource generation
var totalTerritoryValue = 0;
for (var t = 0; t < territories.length; t++) {
if (territories[t].owner === self) {
totalTerritoryValue += territories[t].value;
}
}
self.money += 0.1 * resourceMultiplier * totalTerritoryValue;
// Visual effect for resource generation (subtle pulse)
if (LK.ticks % 120 === 0) {
tween({
target: self,
to: {
scaleX: 1.05,
scaleY: 1.05
},
duration: 500
}); //{1o}{1p}{1q}{1r}
tween({
target: self,
to: {
scaleX: 1,
scaleY: 1
},
duration: 500,
delay: 500
}); //{1s}{1t}{1u}{1v}{1w}{1x}
}
}
// Check for collisions with other countryballs
for (var i = 0; i < countryballs.length; i++) {
var otherBall = countryballs[i];
if (otherBall !== self) {
var distance = Math.sqrt(Math.pow(self.x - otherBall.x, 2) + Math.pow(self.y - otherBall.y, 2));
// If countryballs are very close (collision), trigger battle
if (distance < 120) {
// Only trigger battle if they're not allies and both have sufficient resources
if (self.alliances.indexOf(otherBall) === -1 && self.resources >= 5 && otherBall.resources >= 5) {
// Add visual collision effect
tween(self, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 200,
easing: tween.bounceOut
});
tween(self, {
scaleX: 1,
scaleY: 1
}, {
duration: 200,
delay: 200
});
// Trigger automatic battle
if (Math.random() > 0.5) {
self.attack(otherBall);
} else {
otherBall.attack(self);
}
}
}
}
}
// Enhanced AI behavior - more aggressive and strategic with territory expansion
if (self.isAI && LK.ticks % 300 === 0 && Math.random() < 0.3) {
// Territory expansion every 5 seconds (300 ticks) for AI countries
var possibleTargets = [];
var weakTargets = [];
var strongTargets = [];
var allyTargets = [];
var neutralTargets = [];
var availableTerritories = [];
var enemyTerritories = [];
// Find all possible targets and territories
for (var i = 0; i < countryballs.length; i++) {
var target = countryballs[i];
if (target !== self) {
possibleTargets.push(target);
// Categorize targets
if (self.alliances.indexOf(target) !== -1) {
allyTargets.push(target);
} else if (target.power < self.power * 0.8) {
weakTargets.push(target);
} else if (target.power > self.power * 1.2) {
strongTargets.push(target);
} else {
neutralTargets.push(target);
}
}
}
// Find available territories to expand to
for (var i = 0; i < territories.length; i++) {
var territory = territories[i];
if (!territory.owner && self.money >= 25 * territory.value) {
// Check if territory is connected to current territory or close enough
if (self.territory) {
var distance = Math.sqrt(Math.pow(self.territory.x - territory.x, 2) + Math.pow(self.territory.y - territory.y, 2));
if (distance < 400 || self.territory.connections.indexOf(territory) !== -1) {
availableTerritories.push(territory);
}
} else {
availableTerritories.push(territory);
}
} else if (territory.owner && territory.owner !== self && self.alliances.indexOf(territory.owner) === -1) {
enemyTerritories.push(territory);
}
}
// AI Decision Making - Territory expansion priority
if (availableTerritories.length > 0 && Math.random() < 0.4) {
// Expand to available territory
var targetTerritory = availableTerritories[Math.floor(Math.random() * availableTerritories.length)];
if (self.money >= 25 * targetTerritory.value) {
targetTerritory.claim(self);
self.money -= 25 * targetTerritory.value;
self.power += targetTerritory.value;
}
} else if (weakTargets.length > 0 && Math.random() < 0.5) {
// Attack weak targets to take their territories
var targetToAttack = weakTargets[Math.floor(Math.random() * weakTargets.length)];
if (self.resources >= 5 && self.alliances.indexOf(targetToAttack) === -1) {
var attackSuccess = self.attack(targetToAttack);
if (attackSuccess && targetToAttack.power <= 5 && targetToAttack.territory) {
// Take over their territory
targetToAttack.territory.claim(self);
}
}
} else if (possibleTargets.length > 0 && Math.random() < 0.3) {
// Random attacks on any target
var randomTarget = possibleTargets[Math.floor(Math.random() * possibleTargets.length)];
if (self.resources >= 5 && self.alliances.indexOf(randomTarget) === -1) {
var attackSuccess = self.attack(randomTarget);
if (attackSuccess && randomTarget.power <= 5 && randomTarget.territory) {
// Take over their territory
randomTarget.territory.claim(self);
}
}
}
// AI movement strategy - move towards targets or territories
var targetToApproach = null;
if (availableTerritories.length > 0) {
// Move towards unclaimed territories
targetToApproach = availableTerritories[Math.floor(Math.random() * availableTerritories.length)];
} else if (self.power > 15 && weakTargets.length > 0) {
// Strong AI approaches weak targets
targetToApproach = weakTargets[Math.floor(Math.random() * weakTargets.length)];
} else if (neutralTargets.length > 0) {
// Approach neutral targets
targetToApproach = neutralTargets[Math.floor(Math.random() * neutralTargets.length)];
} else if (possibleTargets.length > 0) {
// Fallback to random target
targetToApproach = possibleTargets[Math.floor(Math.random() * possibleTargets.length)];
}
// Move towards target for collision-based combat or territory claiming
if (targetToApproach && self.resources >= 5) {
var dx = targetToApproach.x - self.x;
var dy = targetToApproach.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 120) {
// Move closer to target
var moveSpeed = 3; // Increased speed for more aggressive expansion
self.x += dx / distance * moveSpeed;
self.y += dy / distance * moveSpeed;
}
}
}
};
self.down = function (x, y, obj) {
game.handleCountryballSelect(self);
};
return self;
});
var MainMenu = Container.expand(function () {
var self = Container.call(this);
var menuBackground = self.attachAsset('menuBackground', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 3,
scaleY: 3
});
menuBackground.alpha = 0.8;
// Set initial visibility state
self.visible = true;
// Create the submenus first before trying to access them
self.settingsMenu = new Container();
self.creditsMenu = new Container();
// Ensure submenus are hidden initially
self.settingsMenu.visible = false;
self.creditsMenu.visible = false;
var titleText = new Text2("COUNTRYBALL WARFARE", {
size: 60,
fill: 0xFFFFFF
});
titleText.anchor.set(0.5, 0);
titleText.y = -350;
self.addChild(titleText);
// Add start game button
var startButton = new Text2("START GAME", {
size: 48,
fill: 0xFFFF00
});
startButton.anchor.set(0.5, 0.5);
startButton.y = -100;
startButton.interactive = true;
self.addChild(startButton);
// Add settings button
var settingsButton = new Text2("SETTINGS", {
size: 48,
fill: 0xFFFF00
});
settingsButton.anchor.set(0.5, 0.5);
settingsButton.y = 0;
settingsButton.interactive = true;
self.addChild(settingsButton);
// Add credits button
var creditsButton = new Text2("CREDITS", {
size: 48,
fill: 0xFFFF00
});
creditsButton.anchor.set(0.5, 0.5);
creditsButton.y = 100;
creditsButton.interactive = true;
self.addChild(creditsButton);
// Settings menu (hidden initially)
self.settingsMenu = new Container();
self.settingsMenu.visible = false;
var settingsTitle = new Text2("SETTINGS", {
size: 48,
fill: 0xFFFFFF
});
settingsTitle.anchor.set(0.5, 0);
settingsTitle.y = -300;
self.settingsMenu.addChild(settingsTitle);
// Sound toggle button
self.soundEnabled = storage.soundEnabled !== undefined ? storage.soundEnabled : true;
var soundToggleText = new Text2("SOUND: " + (self.soundEnabled ? "ON" : "OFF"), {
size: 36,
fill: 0xFFFF00
});
soundToggleText.anchor.set(0.5, 0.5);
soundToggleText.y = -150;
soundToggleText.interactive = true;
self.settingsMenu.addChild(soundToggleText);
// Music toggle button
self.musicEnabled = storage.musicEnabled !== undefined ? storage.musicEnabled : true;
var musicToggleText = new Text2("MUSIC: " + (self.musicEnabled ? "ON" : "OFF"), {
size: 36,
fill: 0xFFFF00
});
musicToggleText.anchor.set(0.5, 0.5);
musicToggleText.y = -50;
musicToggleText.interactive = true;
self.settingsMenu.addChild(musicToggleText);
// Back button for settings
var backButton = new Text2("BACK", {
size: 36,
fill: 0xFFFF00
});
backButton.anchor.set(0.5, 0.5);
backButton.y = 150;
backButton.interactive = true;
self.settingsMenu.addChild(backButton);
self.addChild(self.settingsMenu);
// Credits menu (hidden initially)
self.creditsMenu = new Container();
self.creditsMenu.visible = false;
var creditsTitle = new Text2("CREDITS", {
size: 48,
fill: 0xFFFFFF
});
creditsTitle.anchor.set(0.5, 0);
creditsTitle.y = -300;
self.creditsMenu.addChild(creditsTitle);
var creditsDeveloper = new Text2("GAME DEVELOPMENT BY", {
size: 36,
fill: 0xFFFFFF
});
creditsDeveloper.anchor.set(0.5, 0);
creditsDeveloper.y = -200;
self.creditsMenu.addChild(creditsDeveloper);
var creditsUser = new Text2("YOU", {
size: 42,
fill: 0xFFFF00
});
creditsUser.anchor.set(0.5, 0);
creditsUser.y = -130;
self.creditsMenu.addChild(creditsUser);
var creditsAssistant = new Text2("AND", {
size: 36,
fill: 0xFFFFFF
});
creditsAssistant.anchor.set(0.5, 0);
creditsAssistant.y = -70;
self.creditsMenu.addChild(creditsAssistant);
var creditsAI = new Text2("AVA", {
size: 42,
fill: 0xFFFF00
});
creditsAI.anchor.set(0.5, 0);
creditsAI.y = -10;
self.creditsMenu.addChild(creditsAI);
// Back button for credits
var creditsBackButton = new Text2("BACK", {
size: 36,
fill: 0xFFFF00
});
creditsBackButton.anchor.set(0.5, 0.5);
creditsBackButton.y = 150;
creditsBackButton.interactive = true;
self.creditsMenu.addChild(creditsBackButton);
self.addChild(self.creditsMenu);
// Event handlers
startButton.down = function () {
game.startGame();
};
settingsButton.down = function () {
self.showSettings();
};
creditsButton.down = function () {
self.showCredits();
};
backButton.down = function () {
self.hideSettings();
};
creditsBackButton.down = function () {
self.hideCredits();
};
soundToggleText.down = function () {
self.soundEnabled = !self.soundEnabled;
storage.soundEnabled = self.soundEnabled;
soundToggleText.setText("SOUND: " + (self.soundEnabled ? "ON" : "OFF"));
};
musicToggleText.down = function () {
self.musicEnabled = !self.musicEnabled;
storage.musicEnabled = self.musicEnabled;
musicToggleText.setText("MUSIC: " + (self.musicEnabled ? "ON" : "OFF"));
if (self.musicEnabled) {
LK.playMusic('battleMusic');
} else {
LK.stopMusic();
}
};
self.showSettings = function () {
// Hide main menu buttons
startButton.visible = false;
settingsButton.visible = false;
creditsButton.visible = false;
// Show settings menu
self.settingsMenu.visible = true;
// Ensure credits menu is hidden
self.creditsMenu.visible = false;
};
self.hideSettings = function () {
// Show main menu buttons
startButton.visible = true;
settingsButton.visible = true;
creditsButton.visible = true;
// Hide settings menu
self.settingsMenu.visible = false;
};
self.showCredits = function () {
// Hide main menu buttons
startButton.visible = false;
settingsButton.visible = false;
creditsButton.visible = false;
// Show credits menu
self.creditsMenu.visible = true;
// Ensure settings menu is hidden
self.settingsMenu.visible = false;
};
self.hideCredits = function () {
// Show main menu buttons
startButton.visible = true;
settingsButton.visible = true;
creditsButton.visible = true;
// Hide credits menu
self.creditsMenu.visible = false;
};
return self;
});
var StatsDisplay = Container.expand(function () {
var self = Container.call(this);
var background = self.attachAsset('menuBackground', {
anchorX: 0.5,
anchorY: 0
});
background.alpha = 0.7;
self.titleText = new Text2("COUNTRY STATS", {
size: 36,
fill: 0x000000
});
self.titleText.anchor.set(0.5, 0);
self.titleText.y = 20;
self.addChild(self.titleText);
self.nameText = new Text2("", {
size: 30,
fill: 0x000000
});
self.nameText.anchor.set(0.5, 0);
self.nameText.y = 80;
self.addChild(self.nameText);
self.powerText = new Text2("", {
size: 24,
fill: 0x000000
});
self.powerText.anchor.set(0.5, 0);
self.powerText.y = 120;
self.addChild(self.powerText);
self.resourcesText = new Text2("", {
size: 24,
fill: 0x000000
});
self.resourcesText.anchor.set(0.5, 0);
self.resourcesText.y = 160;
self.addChild(self.resourcesText);
self.moneyText = new Text2("", {
size: 24,
fill: 0x008000
});
self.moneyText.anchor.set(0.5, 0);
self.moneyText.y = 190;
self.addChild(self.moneyText);
self.alliancesText = new Text2("", {
size: 24,
fill: 0x000000
});
self.alliancesText.anchor.set(0.5, 0);
self.alliancesText.y = 200;
self.addChild(self.alliancesText);
self.update = function (countryball) {
if (!countryball) {
self.visible = false;
return;
}
self.visible = true;
self.nameText.setText(countryball.country.name);
self.powerText.setText("Military Power: " + Math.floor(countryball.power));
self.resourcesText.setText("Resources: " + Math.floor(countryball.resources));
self.moneyText.setText("Money: $" + Math.floor(countryball.money));
var allianceText = "Alliances: ";
if (countryball.alliances.length === 0) {
allianceText += "None";
} else {
for (var i = 0; i < countryball.alliances.length; i++) {
if (i > 0) {
allianceText += ", ";
}
allianceText += countryball.alliances[i].country.name;
}
}
self.alliancesText.setText(allianceText);
};
return self;
});
var TechUpgrade = Container.expand(function (name, cost, effect, description) {
var self = Container.call(this);
self.name = name;
self.cost = cost;
self.effect = effect;
self.description = description;
self.purchased = false;
var background = self.attachAsset('menuBackground', {
anchorX: 0.5,
anchorY: 0.5,
width: 200,
height: 120
});
background.alpha = 0.8;
var nameText = new Text2(name, {
size: 20,
fill: 0x000000
});
nameText.anchor.set(0.5, 0);
nameText.y = -40;
self.addChild(nameText);
var costText = new Text2("Cost: " + cost, {
size: 16,
fill: 0x000000
});
costText.anchor.set(0.5, 0);
costText.y = -15;
self.addChild(costText);
var descText = new Text2(description, {
size: 12,
fill: 0x000000
});
descText.anchor.set(0.5, 0.5);
descText.y = 10;
self.addChild(descText);
self.down = function (x, y, obj) {
game.purchaseTechUpgrade(self);
};
return self;
});
var Territory = Container.expand(function (position, value) {
var self = Container.call(this);
self.value = value || 1;
self.owner = null;
var territoryGraphics = self.attachAsset('territory', {
anchorX: 0.5,
anchorY: 0.5
});
var valueText = new Text2("+" + self.value, {
size: 24,
fill: 0xFFFFFF
});
valueText.anchor.set(0.5, 0.5);
self.addChild(valueText);
self.x = position.x;
self.y = position.y;
self.connections = []; // Array to store connected territories
self.claim = function (countryball) {
if (self.owner) {
self.owner.territory = null;
}
self.owner = countryball;
countryball.territory = self;
territoryGraphics.tint = countryball.country.color;
};
// Add method to connect territories
self.connectTo = function (otherTerritory) {
if (self.connections.indexOf(otherTerritory) === -1) {
self.connections.push(otherTerritory);
otherTerritory.connections.push(self);
}
};
self.down = function (x, y, obj) {
game.handleTerritorySelect(self);
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB // Sky blue background
});
/****
* Game Code
****/
// Game configuration
var countryData = [{
name: "USAball",
color: 0xff0000,
basePower: 15,
baseResources: 30,
baseMoney: 150,
isAI: false,
specialAbility: {
name: "Air Superiority",
description: "25% more effective when attacking",
effect: function effect(self, target, action) {
if (action === "attack") {
return 1.25;
}
return 1;
}
}
}, {
name: "UKball",
color: 0x0000ff,
basePower: 12,
baseResources: 25,
baseMoney: 125,
isAI: true,
specialAbility: {
name: "Naval Power",
description: "Generates 20% more resources",
effect: function effect(self, target, action) {
if (action === "resources") {
return 1.2;
}
return 1;
}
}
}, {
name: "Germanyball",
color: 0x000000,
basePower: 13,
baseResources: 28,
baseMoney: 135,
isAI: true,
specialAbility: {
name: "Industrial Efficiency",
description: "Technology costs 15% less",
effect: function effect(self, target, action) {
if (action === "tech") {
return 0.85;
}
return 1;
}
}
}, {
name: "Franceball",
color: 0x0055ff,
basePower: 11,
baseResources: 22,
baseMoney: 110,
isAI: true,
specialAbility: {
name: "Diplomatic Influence",
description: "Alliance bonuses increased by 20%",
effect: function effect(self, target, action) {
if (action === "alliance") {
return 1.2;
}
return 1;
}
}
}, {
name: "Russiaball",
color: 0xffffff,
basePower: 14,
baseResources: 20,
baseMoney: 120,
isAI: true,
specialAbility: {
name: "Winter Resistance",
description: "30% more effective when defending",
effect: function effect(self, target, action) {
if (action === "defense") {
return 1.3;
}
return 1;
}
}
}, {
name: "Chinaball",
color: 0xffff00,
basePower: 15,
baseResources: 35,
baseMoney: 160,
isAI: true,
specialAbility: {
name: "Population Advantage",
description: "Territories provide 25% more power",
effect: function effect(self, target, action) {
if (action === "territory") {
return 1.25;
}
return 1;
}
}
}];
// Game variables
var countryballs = [];
var territories = [];
var connectionLines = [];
var selectedCountryball = null;
var targetCountryball = null;
var statsDisplay = null;
var attackButton = null;
var allianceButton = null;
var scoreText = null;
var moneyText = null;
var techUpgrades = [];
var techMenuOpen = false;
var techButton = null;
var eventDisplay = null;
var lastEventTime = 0;
var worldEvents = [{
name: "Economic Crisis",
description: "Resources reduced by 20% for all nations",
effect: function effect() {
for (var i = 0; i < countryballs.length; i++) {
countryballs[i].resources *= 0.8;
}
return "Economic Crisis hit all nations!";
}
}, {
name: "Natural Disaster",
description: "Random territory loses value",
effect: function effect() {
var randomTerritory = territories[Math.floor(Math.random() * territories.length)];
randomTerritory.value = Math.max(1, randomTerritory.value - 1);
var message = "Natural disaster in " + (randomTerritory.owner ? randomTerritory.owner.country.name : "unclaimed territory");
return message;
}
}, {
name: "Technological Breakthrough",
description: "Random nation gains power",
effect: function effect() {
var randomCountry = countryballs[Math.floor(Math.random() * countryballs.length)];
randomCountry.power += 5;
return randomCountry.country.name + " achieved a technological breakthrough!";
}
}, {
name: "Peace Summit",
description: "Relations improve between nations",
effect: function effect() {
for (var i = 0; i < countryballs.length; i++) {
if (Math.random() < 0.3 && !countryballs[i].isAI) {
for (var j = 0; j < countryballs.length; j++) {
if (i !== j && countryballs[i].alliances.indexOf(countryballs[j]) === -1) {
countryballs[i].formAlliance(countryballs[j]);
return countryballs[i].country.name + " and " + countryballs[j].country.name + " formed an alliance at the Peace Summit!";
}
}
}
}
return "Peace Summit ended with minor agreements.";
}
}];
// Initialize the game
game.init = function () {
// Create main menu
var mainMenu = new MainMenu();
mainMenu.x = 2048 / 2;
mainMenu.y = 2732 / 2;
game.mainMenu = mainMenu;
game.addChild(mainMenu);
// Set gameStarted flag to false initially
game.gameStarted = false;
// Create score text but don't add to GUI yet
scoreText = new Text2("Score: 0", {
size: 36,
fill: 0xFFFFFF
});
scoreText.anchor.set(0, 0);
scoreText.x = 120;
scoreText.y = 30;
// Create event display but don't add to GUI yet
eventDisplay = new Text2("", {
size: 28,
fill: 0xFFFFFF
});
eventDisplay.anchor.set(0.5, 0);
eventDisplay.x = 2048 / 2;
eventDisplay.y = 100;
eventDisplay.alpha = 0;
};
game.handleCountryballSelect = function (countryball) {
// Don't allow selecting AI countryballs as the active player
if (countryball.isAI) {
if (selectedCountryball) {
// If we already have a selected countryball, set this as target
if (targetCountryball) {
targetCountryball.setSelected(false);
}
targetCountryball = countryball;
targetCountryball.setSelected(true);
}
} else {
// Set as the active player
if (selectedCountryball) {
selectedCountryball.setSelected(false);
}
if (targetCountryball) {
targetCountryball.setSelected(false);
targetCountryball = null;
}
selectedCountryball = countryball;
selectedCountryball.setSelected(true);
statsDisplay.update(selectedCountryball);
}
};
game.handleTerritorySelect = function (territory) {
// If we have a selected countryball, claim the territory
if (selectedCountryball) {
// Check if territory is already owned by this countryball
if (territory.owner === selectedCountryball) {
return;
}
// Check if we have enough money to claim it
if (selectedCountryball.money >= 25 * territory.value) {
territory.claim(selectedCountryball);
selectedCountryball.money -= 25 * territory.value;
selectedCountryball.power += territory.value;
statsDisplay.update(selectedCountryball);
game.updateScore();
}
}
};
game.handleActionButton = function (button) {
if (button.action === "tech") {
// Toggle tech menu visibility
techMenuOpen = !techMenuOpen;
for (var i = 0; i < techUpgrades.length; i++) {
techUpgrades[i].visible = techMenuOpen;
}
return;
}
if (!selectedCountryball || !targetCountryball && button.action !== "tech") {
return;
}
if (button.action === "attack") {
if (selectedCountryball.attack(targetCountryball)) {
// Successful attack
if (storage.soundEnabled !== false) {
LK.getSound('attack').play();
}
LK.effects.flashObject(targetCountryball, 0xff0000, 500);
// Check if we defeated the target
if (targetCountryball.power <= 5) {
// Take their territory if they have one
if (targetCountryball.territory) {
targetCountryball.territory.claim(selectedCountryball);
}
}
} else {
// Failed attack
LK.effects.flashObject(selectedCountryball, 0xff0000, 500);
}
statsDisplay.update(selectedCountryball);
game.updateScore();
} else if (button.action === "alliance") {
// Apply alliance special ability if it exists
var allianceMultiplier = 1;
if (selectedCountryball.country.specialAbility && typeof selectedCountryball.country.specialAbility.effect === 'function') {
allianceMultiplier = selectedCountryball.country.specialAbility.effect(selectedCountryball, targetCountryball, "alliance");
}
if (selectedCountryball.formAlliance(targetCountryball)) {
if (storage.soundEnabled !== false) {
LK.getSound('alliance').play();
}
LK.effects.flashObject(targetCountryball, 0x00ff00, 500);
// Alliance bonus - both countries get a small power boost
var powerBoost = 2 * allianceMultiplier;
selectedCountryball.power += powerBoost;
targetCountryball.power += powerBoost;
statsDisplay.update(selectedCountryball);
}
}
};
// Add tech upgrade handler
game.purchaseTechUpgrade = function (techUpgrade) {
if (!selectedCountryball) {
return;
}
// Apply tech cost special ability if it exists
var techCostMultiplier = 1;
if (selectedCountryball.country.specialAbility && typeof selectedCountryball.country.specialAbility.effect === 'function') {
techCostMultiplier = selectedCountryball.country.specialAbility.effect(selectedCountryball, null, "tech");
}
var adjustedCost = Math.floor(techUpgrade.cost * techCostMultiplier);
// Check if player has enough money and hasn't purchased it yet
if (selectedCountryball.money >= adjustedCost && !techUpgrade.purchased) {
selectedCountryball.money -= adjustedCost;
techUpgrade.purchased = true;
// Apply the upgrade effect
if (typeof techUpgrade.effect === 'function') {
techUpgrade.effect(selectedCountryball);
}
// Visual feedback
LK.effects.flashObject(techUpgrade, 0x00ff00, 500);
tween({
target: techUpgrade,
to: {
alpha: 0.5
},
duration: 300
}); //{8A}{8B}{8C}
// Update stats
statsDisplay.update(selectedCountryball);
game.updateScore();
// Show event notification
game.showEventNotification(selectedCountryball.country.name + " acquired " + techUpgrade.name + " technology!");
} else if (techUpgrade.purchased) {
// Already purchased feedback
LK.effects.flashObject(techUpgrade, 0xff0000, 500);
} else {
// Not enough resources feedback
LK.effects.flashObject(techUpgrade, 0xffff00, 500);
}
};
// Add world events system
game.triggerRandomEvent = function () {
// Only trigger events if some time has passed since the last one
if (LK.ticks - lastEventTime < 600) {
return;
}
// 5% chance each update to trigger an event
if (Math.random() < 0.05) {
var randomEvent = worldEvents[Math.floor(Math.random() * worldEvents.length)];
var message = randomEvent.effect();
game.showEventNotification(message);
lastEventTime = LK.ticks;
}
};
// Add notification display
game.showEventNotification = function (message) {
eventDisplay.setText(message);
eventDisplay.alpha = 1;
tween({
target: eventDisplay,
to: {
y: 120
},
duration: 500
}); //{8M}{8N}{8O}{8P}
tween({
target: eventDisplay,
to: {
alpha: 0
},
duration: 500,
delay: 3000
}); //{8Q}{8R}{8S}{8T}
tween({
target: eventDisplay,
to: {
y: 100
},
duration: 500,
delay: 3500
}); //{8U}{8V}{8W}{8X}
};
game.updateScore = function () {
var playerScore = 0;
// Calculate score based on power, resources, territories and alliances
var playerBall = countryballs[0]; // First countryball is the player
playerScore += playerBall.power * 5;
playerScore += playerBall.resources * 2;
playerScore += playerBall.alliances.length * 50;
// Add score for territories
for (var i = 0; i < territories.length; i++) {
if (territories[i].owner === playerBall) {
playerScore += territories[i].value * 20;
}
}
LK.setScore(Math.floor(playerScore));
scoreText.setText("Score: " + LK.getScore());
// Check win condition
var playerTerritories = 0;
for (var i = 0; i < territories.length; i++) {
if (territories[i].owner === playerBall) {
playerTerritories++;
}
}
if (playerTerritories >= territories.length / 2) {
LK.showYouWin();
}
// Check lose condition
var playerHasTerritories = false;
for (var i = 0; i < territories.length; i++) {
if (territories[i].owner === playerBall) {
playerHasTerritories = true;
break;
}
}
if (!playerHasTerritories && playerBall.power < 5) {
LK.showGameOver();
}
};
// Initialize the menu
game.init();
// Move event handler
game.move = function (x, y, obj) {
// Nothing to do for move events in this game
};
// Add game start functionality
game.startGame = function () {
// Clear the stage first - remove all children
while (game.children.length > 0) {
game.removeChild(game.children[0]);
}
// Clear any existing game elements
countryballs = [];
territories = [];
techUpgrades = [];
selectedCountryball = null;
targetCountryball = null;
// Set game started flag
game.gameStarted = true;
// Remove main menu from GUI if it exists
if (game.mainMenu) {
if (game.mainMenu.parent) {
game.mainMenu.parent.removeChild(game.mainMenu);
}
game.mainMenu = null;
}
// Play background music if enabled
if (storage.musicEnabled !== false) {
LK.playMusic('battleMusic');
}
// Add GUI elements now that the game is starting
LK.gui.addChild(scoreText);
// Create money display
moneyText = new Text2("Money: $0", {
size: 36,
fill: 0x00FF00
});
moneyText.anchor.set(1, 0);
moneyText.x = 2048 - 120;
moneyText.y = 30;
LK.gui.addChild(moneyText);
// Create the title
var titleText = new Text2("COUNTRYBALL WARFARE", {
size: 48,
fill: 0xFFFFFF
});
titleText.anchor.set(0.5, 0);
titleText.x = 2048 / 2;
titleText.y = 30;
LK.gui.addChild(titleText);
// Create territories with better distribution and connections
var territoryPositions = [{
x: 250,
y: 300
}, {
x: 500,
y: 280
}, {
x: 750,
y: 320
}, {
x: 1000,
y: 280
}, {
x: 1250,
y: 320
}, {
x: 1500,
y: 280
}, {
x: 1750,
y: 320
}, {
x: 150,
y: 500
}, {
x: 400,
y: 480
}, {
x: 650,
y: 520
}, {
x: 900,
y: 480
}, {
x: 1150,
y: 520
}, {
x: 1400,
y: 480
}, {
x: 1650,
y: 520
}, {
x: 1900,
y: 480
}, {
x: 200,
y: 700
}, {
x: 450,
y: 680
}, {
x: 700,
y: 720
}, {
x: 950,
y: 680
}, {
x: 1200,
y: 720
}, {
x: 1450,
y: 680
}, {
x: 1700,
y: 720
}, {
x: 1950,
y: 680
}, {
x: 300,
y: 900
}, {
x: 550,
y: 880
}, {
x: 800,
y: 920
}, {
x: 1050,
y: 880
}, {
x: 1300,
y: 920
}, {
x: 1550,
y: 880
}, {
x: 1800,
y: 920
}, {
x: 150,
y: 1100
}, {
x: 400,
y: 1080
}, {
x: 650,
y: 1120
}, {
x: 900,
y: 1080
}, {
x: 1150,
y: 1120
}, {
x: 1400,
y: 1080
}, {
x: 1650,
y: 1120
}, {
x: 1900,
y: 1080
}, {
x: 250,
y: 1300
}, {
x: 500,
y: 1280
}, {
x: 750,
y: 1320
}, {
x: 1000,
y: 1280
}, {
x: 1250,
y: 1320
}, {
x: 1500,
y: 1280
}, {
x: 1750,
y: 1320
}, {
x: 350,
y: 1500
}, {
x: 600,
y: 1480
}, {
x: 850,
y: 1520
}, {
x: 1100,
y: 1480
}, {
x: 1350,
y: 1520
}, {
x: 1600,
y: 1480
}, {
x: 400,
y: 1700
}, {
x: 700,
y: 1680
}, {
x: 1000,
y: 1720
}, {
x: 1300,
y: 1680
}, {
x: 1600,
y: 1720
}, {
x: 500,
y: 1900
}, {
x: 800,
y: 1880
}, {
x: 1100,
y: 1920
}, {
x: 1400,
y: 1880
}, {
x: 1700,
y: 1920
}, {
x: 600,
y: 2100
}, {
x: 900,
y: 2080
}, {
x: 1200,
y: 2120
}, {
x: 1500,
y: 2080
}, {
x: 750,
y: 2300
}, {
x: 1050,
y: 2280
}, {
x: 1350,
y: 2320
}];
for (var i = 0; i < territoryPositions.length; i++) {
var territory = new Territory(territoryPositions[i], Math.floor(Math.random() * 3) + 1);
territories.push(territory);
game.addChild(territory);
}
// Establish territory connections based on proximity
connectionLines = [];
for (var i = 0; i < territories.length; i++) {
for (var j = i + 1; j < territories.length; j++) {
var distance = Math.sqrt(Math.pow(territories[i].x - territories[j].x, 2) + Math.pow(territories[i].y - territories[j].y, 2));
// Connect territories that are within 300 pixels of each other for tighter strategic gameplay
if (distance < 300) {
territories[i].connectTo(territories[j]);
// Create visual connection line
var connectionLine = new ConnectionLine(territories[i], territories[j]);
connectionLines.push(connectionLine);
game.addChild(connectionLine);
}
}
}
// Create countryballs
for (var i = 0; i < countryData.length; i++) {
var countryball = new Countryball(countryData[i]);
// Position countryballs in a circle around the center
var angle = i / countryData.length * Math.PI * 2;
var radius = 700;
countryball.x = 2048 / 2 + Math.cos(angle) * radius;
countryball.y = 2732 / 2 + Math.sin(angle) * radius;
countryballs.push(countryball);
game.addChild(countryball);
// Give each countryball a starting territory
if (i < territories.length) {
territories[i].claim(countryball);
}
}
// The player controls the first countryball
selectedCountryball = countryballs[0];
selectedCountryball.setSelected(true);
// Give player 3 random territories at start
var availableForPlayer = [];
for (var i = 0; i < territories.length; i++) {
if (!territories[i].owner) {
availableForPlayer.push(territories[i]);
}
}
// Shuffle and take first 3 available territories for player
for (var i = 0; i < Math.min(3, availableForPlayer.length); i++) {
var randomIndex = Math.floor(Math.random() * availableForPlayer.length);
var selectedTerritory = availableForPlayer[randomIndex];
selectedTerritory.claim(selectedCountryball);
availableForPlayer.splice(randomIndex, 1);
}
// Create stats display
statsDisplay = new StatsDisplay();
statsDisplay.x = 2048 / 2;
statsDisplay.y = 2732 - 450;
statsDisplay.update(selectedCountryball);
game.addChild(statsDisplay);
// Create buttons
attackButton = new ActionButton("ATTACK", "attack");
attackButton.x = 2048 / 2 - 200;
attackButton.y = 2732 - 100;
game.addChild(attackButton);
allianceButton = new ActionButton("ALLIANCE", "alliance");
allianceButton.x = 2048 / 2;
allianceButton.y = 2732 - 100;
game.addChild(allianceButton);
// Add tech button
techButton = new ActionButton("TECH", "tech");
techButton.x = 2048 / 2 + 200;
techButton.y = 2732 - 100;
game.addChild(techButton);
// Create tech upgrades
var techList = [{
name: "Advanced Weaponry",
cost: 100,
effect: function effect(countryball) {
countryball.power += 10;
},
description: "Increases military power by 10"
}, {
name: "Economic Reforms",
cost: 80,
effect: function effect(countryball) {
countryball.money += 50;
},
description: "Adds $50 immediately"
}, {
name: "Diplomacy",
cost: 35,
effect: function effect(countryball) {
// Form alliances with two random countries
var unalliedCountries = countryballs.filter(function (c) {
return c !== countryball && countryball.alliances.indexOf(c) === -1;
});
for (var i = 0; i < Math.min(2, unalliedCountries.length); i++) {
countryball.formAlliance(unalliedCountries[i]);
}
},
description: "Form alliances with 2 random countries"
}, {
name: "Espionage",
cost: 45,
effect: function effect(countryball) {
// Reduce power of all enemies
for (var i = 0; i < countryballs.length; i++) {
if (countryballs[i] !== countryball && countryball.alliances.indexOf(countryballs[i]) === -1) {
countryballs[i].power = Math.max(5, countryballs[i].power - 3);
}
}
},
description: "Reduces enemy power by 3"
}];
// Create tech upgrades but don't add them to the stage yet
for (var i = 0; i < techList.length; i++) {
var tech = new TechUpgrade(techList[i].name, techList[i].cost, techList[i].effect, techList[i].description);
tech.x = 2048 / 2;
tech.y = 800 + i * 150;
tech.visible = false;
techUpgrades.push(tech);
game.addChild(tech);
}
// Create event display
eventDisplay = new Text2("", {
size: 28,
fill: 0xFFFFFF
});
eventDisplay.anchor.set(0.5, 0);
eventDisplay.x = 2048 / 2;
eventDisplay.y = 100;
eventDisplay.alpha = 0;
LK.gui.addChild(eventDisplay);
// Initial score
game.updateScore();
};
// Update function
game.update = function () {
// Only update game elements if the game has started
if (!game.gameStarted) {
// Do nothing when in menu state
return;
}
// Update money display if it exists
if (selectedCountryball && moneyText) {
moneyText.setText("Money: $" + Math.floor(selectedCountryball.money));
}
// Update all countryballs
for (var i = 0; i < countryballs.length; i++) {
countryballs[i].update();
}
// Update stats display
if (selectedCountryball) {
statsDisplay.update(selectedCountryball);
}
// Trigger random world events
game.triggerRandomEvent();
// Apply territory special ability for China
if (selectedCountryball && selectedCountryball.country.name === "Chinaball" && selectedCountryball.territory) {
var territoryMultiplier = 1;
if (selectedCountryball.country.specialAbility && typeof selectedCountryball.country.specialAbility.effect === 'function') {
territoryMultiplier = selectedCountryball.country.specialAbility.effect(selectedCountryball, null, "territory");
}
// Apply the bonus every 10 seconds
if (LK.ticks % 600 === 0) {
selectedCountryball.power += selectedCountryball.territory.value * territoryMultiplier;
statsDisplay.update(selectedCountryball);
}
}
// Check for country elimination - countries with no territories and low power are eliminated
for (var i = countryballs.length - 1; i >= 0; i--) {
var countryball = countryballs[i];
var hasTerritory = false;
// Check if country has any territories
for (var j = 0; j < territories.length; j++) {
if (territories[j].owner === countryball) {
hasTerritory = true;
break;
}
}
// Eliminate country if they have no territories and very low power
if (!hasTerritory && countryball.power <= 3) {
// Visual elimination effect
tween(countryball, {
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
}, {
duration: 1000,
onFinish: function onFinish() {
// Remove from game
if (countryball.parent) {
countryball.parent.removeChild(countryball);
}
}
});
// Show elimination notification
game.showEventNotification(countryball.country.name + " has been eliminated from the game!");
// Remove from countryballs array
countryballs.splice(i, 1);
// If eliminated country was selected, select another
if (selectedCountryball === countryball) {
selectedCountryball = null;
targetCountryball = null;
// Find the first remaining player country
for (var k = 0; k < countryballs.length; k++) {
if (!countryballs[k].isAI) {
selectedCountryball = countryballs[k];
selectedCountryball.setSelected(true);
break;
}
}
}
}
}
// Check if anyone has won the game
var remainingCountries = 0;
var mostPowerfulCountry = null;
for (var i = 0; i < countryballs.length; i++) {
var countryball = countryballs[i];
if (countryball.power > 0) {
remainingCountries++;
if (!mostPowerfulCountry || countryball.power > mostPowerfulCountry.power) {
mostPowerfulCountry = countryball;
}
}
}
// Check if player has been eliminated from the countryballs array
if (selectedCountryball && countryballs.indexOf(selectedCountryball) === -1) {
LK.showGameOver();
}
// Check if player still exists but has lost all territories and has very low power
if (selectedCountryball && countryballs.indexOf(selectedCountryball) !== -1) {
var playerHasTerritory = false;
// Check if player has any territories
for (var j = 0; j < territories.length; j++) {
if (territories[j].owner === selectedCountryball) {
playerHasTerritory = true;
break;
}
}
// Player loses if they have no territories and very low power
if (!playerHasTerritory && selectedCountryball.power <= 3) {
LK.showGameOver();
}
}
// Check if only one country remains
if (remainingCountries <= 1) {
if (mostPowerfulCountry && !mostPowerfulCountry.isAI) {
LK.showYouWin();
} else {
LK.showGameOver();
}
}
// Update game state every 5 seconds
if (LK.ticks % 300 === 0) {
game.updateScore();
if (selectedCountryball && moneyText) {
moneyText.setText("Money: $" + Math.floor(selectedCountryball.money));
}
}
// Update connection lines
if (connectionLines) {
for (var i = 0; i < connectionLines.length; i++) {
connectionLines[i].update();
}
}
// Add visual effects to territories every 2 seconds
if (LK.ticks % 120 === 0) {
for (var i = 0; i < territories.length; i++) {
if (territories[i].owner) {
tween(territories[i], {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 300
}); //{c7}{c8}{c9}{ca}
tween(territories[i], {
scaleX: 1,
scaleY: 1
}, {
duration: 300,
delay: 300
}); //{cb}{cc}{cd}{ce}{cf}
}
}
}
};
Fullscreen modern App Store landscape banner, 16:9, high definition, for a game titled "Countryball Warfare" and with the description "A humorous strategic war game featuring Countryballs – the spherical national characters with unique abilities and traits. Command your nation, form alliances, conquer territories, and rise to global dominance through military tactics, resource management, and diplomatic maneuvering.". No text on banner!
Bola con contorno negro. In-Game asset. 2d. High contrast. No shadows
Un pedazo de tierra con árboles y formar de cuadrado y irregular