User prompt
Add the Airport Comissary button (Buy boosts and cosmetic items with varying Point levels.) ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Now, lore button! ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Add a tutorial button which introduces new players and tells them how to play. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Drakens keep firing after duration
User prompt
Add a menu when pressing the ally button to select the ally ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Add different types of allies you can summon (2x Draken, Bandkanon, Strv 103 and Naval Barrage) ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Add a ally button where you can summon Swedish forces for a monent to fight for you ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
No, I meant as guns, cannons and missiles fir the Viggen.
User prompt
Add an armament button
User prompt
Add optimization
User prompt
Fix it. ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Make it harder to unlock (so only me and the coworkers can access)
User prompt
Add a Dev Mode where you can spawn infinite points and every unit ↪💡 Consider importing and using the following plugins: @upit/storage.v1
Remix started
Copy Viggen Strike: Soviet Skies
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var AllyBandkanon = Container.expand(function () { var self = Container.call(this); var graphics = self.attachAsset('bandkanon', { anchorX: 0.5, anchorY: 0.5 }); graphics.tint = 0x88ff88; self.speed = 1; self.fireTimer = 0; self.fireRate = 45; // Slower but powerful self.targetEnemy = null; self.positionSet = false; self.update = function () { // Stay at bottom of screen providing artillery support if (!self.positionSet) { self.x = Math.random() * 800 + 600; // Random position at bottom self.y = 2500; self.positionSet = true; } // Find nearest enemy for artillery strike var nearestEnemy = null; var nearestDistance = Infinity; var allEnemies = interceptors.concat(drones).concat(samSites).concat(shilkas); for (var i = 0; i < allEnemies.length; i++) { var enemy = allEnemies[i]; var distance = Math.sqrt(Math.pow(enemy.x - self.x, 2) + Math.pow(enemy.y - self.y, 2)); if (distance < nearestDistance && enemy.y < 2000) { // Only target enemies on screen nearestDistance = distance; nearestEnemy = enemy; } } self.targetEnemy = nearestEnemy; // Fire artillery barrage self.fireTimer++; if (self.fireTimer >= self.fireRate && self.targetEnemy) { self.fireTimer = 0; // Fire 3 high-damage artillery shells for (var j = 0; j < 3; j++) { var bullet = new ViggenBullet(); bullet.damage = 3; // High damage bullet.x = self.x; bullet.y = self.y; // Predict target position var targetDx = self.targetEnemy.x + (j - 1) * 40 - bullet.x; var targetDy = self.targetEnemy.y - bullet.y; var targetDistance = Math.sqrt(targetDx * targetDx + targetDy * targetDy); if (targetDistance > 0) { bullet.targetDx = targetDx / targetDistance; bullet.targetDy = targetDy / targetDistance; } else { bullet.targetDx = 0; bullet.targetDy = -1; } // Override bullet update with artillery arc var originalUpdate = bullet.update; bullet.arcHeight = 0; bullet.update = function () { if (bullet.targetDx !== undefined && bullet.targetDy !== undefined) { bullet.x += bullet.targetDx * bullet.speed * 0.8; bullet.y += bullet.targetDy * bullet.speed * 0.8; // Add artillery arc effect bullet.arcHeight += 0.1; bullet.y += Math.sin(bullet.arcHeight) * 2; } else { originalUpdate.call(bullet); } }; game.addChild(bullet); viggenBullets.push(bullet); } LK.getSound('missile').play(); // Use missile sound for artillery } }; return self; }); var AllyDraken = Container.expand(function () { var self = Container.call(this); var graphics = self.attachAsset('draken', { anchorX: 0.5, anchorY: 0.5 }); graphics.tint = 0x88ff88; // Green tint to distinguish from enemies self.speed = 4; self.fireTimer = 0; self.fireRate = 12; // Faster than Viggen self.targetEnemy = null; self.formationOffset = 0; self.maneuverTimer = 0; self.terminated = false; self.update = function () { // Stop all actions if terminated if (self.terminated) { return; } // More aggressive patrol pattern self.formationOffset += 0.05; self.maneuverTimer += 0.02; var baseX = viggen.x + Math.cos(self.formationOffset) * 200; var baseY = viggen.y + Math.sin(self.formationOffset) * 150 - 300; // Add barrel roll maneuvers var rollOffset = Math.sin(self.maneuverTimer * 3) * 30; var desiredX = baseX + rollOffset; var desiredY = baseY; var dx = desiredX - self.x; var dy = desiredY - self.y; self.x += dx * 0.15; self.y += dy * 0.15; // Find nearest enemy var nearestEnemy = null; var nearestDistance = Infinity; // Check all enemy types var allEnemies = interceptors.concat(drones).concat(samSites).concat(shilkas); for (var i = 0; i < allEnemies.length; i++) { var enemy = allEnemies[i]; var distance = Math.sqrt(Math.pow(enemy.x - self.x, 2) + Math.pow(enemy.y - self.y, 2)); if (distance < nearestDistance) { nearestDistance = distance; nearestEnemy = enemy; } } self.targetEnemy = nearestEnemy; // Fire at enemies self.fireTimer++; if (self.fireTimer >= self.fireRate && self.targetEnemy) { self.fireTimer = 0; // Fire twin bullets (like real Draken) for (var j = 0; j < 2; j++) { var bullet = new ViggenBullet(); bullet.x = self.x + (j === 0 ? -15 : 15); bullet.y = self.y; // Aim towards target var targetDx = self.targetEnemy.x - bullet.x; var targetDy = self.targetEnemy.y - bullet.y; var targetDistance = Math.sqrt(targetDx * targetDx + targetDy * targetDy); if (targetDistance > 0) { bullet.targetDx = targetDx / targetDistance; bullet.targetDy = targetDy / targetDistance; } else { bullet.targetDx = 0; bullet.targetDy = -1; } // Override bullet update var originalUpdate = bullet.update; bullet.update = function () { if (bullet.targetDx !== undefined && bullet.targetDy !== undefined) { bullet.x += bullet.targetDx * bullet.speed; bullet.y += bullet.targetDy * bullet.speed; } else { originalUpdate.call(bullet); } }; game.addChild(bullet); viggenBullets.push(bullet); } LK.getSound('shoot').play(); } }; return self; }); var AllyStrv103 = Container.expand(function () { var self = Container.call(this); var graphics = self.attachAsset('strv103', { anchorX: 0.5, anchorY: 0.5 }); graphics.tint = 0x88ff88; self.speed = 0.5; self.fireTimer = 0; self.fireRate = 30; self.targetEnemy = null; self.positionX = 0; self.movementDirection = 1; self.update = function () { // Tank movement - slow horizontal movement at bottom self.y = 2400; self.positionX += self.speed * self.movementDirection; self.x = 400 + self.positionX; // Reverse at edges if (self.positionX >= 1200 || self.positionX <= 0) { self.movementDirection *= -1; } // Find enemies in range var nearestEnemy = null; var nearestDistance = Infinity; var allEnemies = interceptors.concat(drones).concat(samSites).concat(shilkas); for (var i = 0; i < allEnemies.length; i++) { var enemy = allEnemies[i]; var distance = Math.sqrt(Math.pow(enemy.x - self.x, 2) + Math.pow(enemy.y - self.y, 2)); if (distance < nearestDistance && enemy.y > 800) { // Only target enemies in range nearestDistance = distance; nearestEnemy = enemy; } } self.targetEnemy = nearestEnemy; // Fire precise tank rounds self.fireTimer++; if (self.fireTimer >= self.fireRate && self.targetEnemy) { self.fireTimer = 0; var bullet = new ViggenBullet(); bullet.damage = 2.5; // High damage tank round bullet.speed = 10; // Fast projectile bullet.x = self.x; bullet.y = self.y - 30; // Precise targeting var targetDx = self.targetEnemy.x - bullet.x; var targetDy = self.targetEnemy.y - bullet.y; var targetDistance = Math.sqrt(targetDx * targetDx + targetDy * targetDy); if (targetDistance > 0) { bullet.targetDx = targetDx / targetDistance; bullet.targetDy = targetDy / targetDistance; } else { bullet.targetDx = 0; bullet.targetDy = -1; } // Override bullet update var originalUpdate = bullet.update; bullet.update = function () { if (bullet.targetDx !== undefined && bullet.targetDy !== undefined) { bullet.x += bullet.targetDx * bullet.speed; bullet.y += bullet.targetDy * bullet.speed; } else { originalUpdate.call(bullet); } }; game.addChild(bullet); viggenBullets.push(bullet); LK.getSound('shoot').play(); } }; return self; }); var AllyViggen = Container.expand(function () { var self = Container.call(this); var graphics = self.attachAsset('viggen', { anchorX: 0.5, anchorY: 0.5 }); graphics.tint = 0x88ff88; // Green tint to distinguish from player self.speed = 3; self.fireTimer = 0; self.fireRate = 20; self.targetEnemy = null; self.formationOffset = 0; self.update = function () { // Formation flying around player self.formationOffset += 0.03; var desiredX = viggen.x + Math.cos(self.formationOffset) * 150; var desiredY = viggen.y + Math.sin(self.formationOffset) * 100 - 200; // Smooth movement towards formation position var dx = desiredX - self.x; var dy = desiredY - self.y; self.x += dx * 0.1; self.y += dy * 0.1; // Find nearest enemy to attack var nearestEnemy = null; var nearestDistance = Infinity; // Check interceptors for (var i = 0; i < interceptors.length; i++) { var enemy = interceptors[i]; var distance = Math.sqrt(Math.pow(enemy.x - self.x, 2) + Math.pow(enemy.y - self.y, 2)); if (distance < nearestDistance) { nearestDistance = distance; nearestEnemy = enemy; } } // Check drones for (var i = 0; i < drones.length; i++) { var enemy = drones[i]; var distance = Math.sqrt(Math.pow(enemy.x - self.x, 2) + Math.pow(enemy.y - self.y, 2)); if (distance < nearestDistance) { nearestDistance = distance; nearestEnemy = enemy; } } self.targetEnemy = nearestEnemy; // Fire at enemies self.fireTimer++; if (self.fireTimer >= self.fireRate && self.targetEnemy) { self.fireTimer = 0; var bullet = new ViggenBullet(); bullet.x = self.x; bullet.y = self.y; // Aim towards target enemy var targetDx = self.targetEnemy.x - self.x; var targetDy = self.targetEnemy.y - self.y; var targetDistance = Math.sqrt(targetDx * targetDx + targetDy * targetDy); if (targetDistance > 0) { bullet.targetDx = targetDx / targetDistance; bullet.targetDy = targetDy / targetDistance; } else { bullet.targetDx = 0; bullet.targetDy = -1; } // Override bullet update to aim at enemies var originalUpdate = bullet.update; bullet.update = function () { if (bullet.targetDx !== undefined && bullet.targetDy !== undefined) { bullet.x += bullet.targetDx * bullet.speed; bullet.y += bullet.targetDy * bullet.speed; } else { originalUpdate.call(bullet); } }; game.addChild(bullet); viggenBullets.push(bullet); LK.getSound('shoot').play(); } }; return self; }); var Drone = Container.expand(function () { var self = Container.call(this); var graphics = self.attachAsset('drone', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 1.5; self.direction = 1; self.fireTimer = 0; self.fireRate = 45; self.update = function () { var speedMultiplier = currentSSR ? currentSSR.enemySpeedMultiplier : 1.0; self.x += self.speed * self.direction * speedMultiplier; self.y += self.speed * 0.5 * speedMultiplier; if (self.x <= 50 || self.x >= 1998) { self.direction *= -1; } self.fireTimer++; if (self.fireTimer >= self.fireRate) { self.fireTimer = 0; var bullet = new EnemyBullet(); bullet.x = self.x; bullet.y = self.y; bullet.targetX = viggen.x; bullet.targetY = viggen.y; bullet.age = 0; game.addChild(bullet); enemyBullets.push(bullet); } graphics.rotation += 0.05; }; return self; }); var EnemyBullet = Container.expand(function () { var self = Container.call(this); var graphics = self.attachAsset('enemyBullet', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 4; self.targetX = 0; self.targetY = 0; self.update = function () { self.age = (self.age || 0) + 1; var dx = self.targetX - self.x; var dy = self.targetY - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 0) { var speedMultiplier = currentSSR ? currentSSR.enemySpeedMultiplier : 1.0; self.x += dx / distance * self.speed * speedMultiplier; self.y += dy / distance * self.speed * speedMultiplier; } }; return self; }); var MiG23 = Container.expand(function () { var self = Container.call(this); var graphics = self.attachAsset('mig23', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 2; self.fireTimer = 0; self.fireRate = 60; self.interceptorType = 'mig23'; self.scoreValue = 100; self.update = function () { var speedMultiplier = currentSSR ? currentSSR.enemySpeedMultiplier : 1.0; self.y += self.speed * speedMultiplier; self.fireTimer++; if (self.fireTimer >= self.fireRate) { self.fireTimer = 0; var bullet = new EnemyBullet(); bullet.x = self.x; bullet.y = self.y; bullet.targetX = viggen.x; bullet.targetY = viggen.y; bullet.age = 0; game.addChild(bullet); enemyBullets.push(bullet); } }; return self; }); var NavalBarrage = Container.expand(function () { var self = Container.call(this); // No visible graphics - this is an effect self.barrageTimer = 0; self.barrageCount = 0; self.maxBarrages = 12; // 12 barrages over duration self.barrageInterval = 75; // Every 1.25 seconds self.update = function () { self.barrageTimer++; if (self.barrageTimer >= self.barrageInterval && self.barrageCount < self.maxBarrages) { self.barrageTimer = 0; self.barrageCount++; // Create barrage at random location with enemies nearby var targetX = Math.random() * 1600 + 200; var targetY = Math.random() * 1500 + 200; // Check if enemies are nearby and adjust target var allEnemies = interceptors.concat(drones).concat(samSites).concat(shilkas); if (allEnemies.length > 0) { var randomEnemy = allEnemies[Math.floor(Math.random() * allEnemies.length)]; targetX = randomEnemy.x + (Math.random() - 0.5) * 200; targetY = randomEnemy.y + (Math.random() - 0.5) * 200; } // Create multiple shells for this barrage for (var i = 0; i < 4; i++) { var shell = new ViggenBullet(); shell.damage = 4; // Very high damage shell.speed = 15; shell.x = targetX + (Math.random() - 0.5) * 100; shell.y = -100 - i * 20; // Staggered arrival shell.targetX = targetX + (Math.random() - 0.5) * 80; shell.targetY = targetY + (Math.random() - 0.5) * 80; // Naval shell behavior var originalUpdate = shell.update; shell.navalShell = true; shell.arcProgress = 0; shell.update = function () { shell.arcProgress += 0.08; var progress = Math.min(shell.arcProgress, 1); // Arc trajectory shell.x = shell.x + (shell.targetX - shell.x) * 0.08; shell.y += shell.speed; // Add arc effect if (progress < 0.5) { shell.y -= Math.sin(progress * Math.PI) * 5; } }; game.addChild(shell); viggenBullets.push(shell); } // Screen shake effect for naval barrage tween(game, { x: game.x + 5 }, { duration: 100, onFinish: function onFinish() { tween(game, { x: game.x - 10 }, { duration: 100, onFinish: function onFinish() { tween(game, { x: 0 }, { duration: 100 }); } }); } }); LK.getSound('explosion').play(); } // Self-destruct when done if (self.barrageCount >= self.maxBarrages) { self.destroy(); } }; return self; }); var Powerup = Container.expand(function () { var self = Container.call(this); self.powerupType = 'speed'; // 'speed', 'shield', 'rapidfire' self.speed = 2; self.bobOffset = 0; self.bobSpeed = 0.1; self.setPowerupType = function (type) { self.powerupType = type; if (self.graphics) { self.removeChild(self.graphics); } var assetName = 'powerupSpeed'; if (type === 'shield') { assetName = 'powerupShield'; } else if (type === 'rapidfire') { assetName = 'powerupRapidFire'; } self.graphics = self.attachAsset(assetName, { anchorX: 0.5, anchorY: 0.5 }); }; self.update = function () { self.y += self.speed; self.bobOffset += self.bobSpeed; self.graphics.y = Math.sin(self.bobOffset) * 10; self.graphics.rotation += 0.05; }; return self; }); var SAMMissile = Container.expand(function () { var self = Container.call(this); var graphics = self.attachAsset('samMissile', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 6; self.targetX = 0; self.targetY = 0; self.update = function () { var dx = self.targetX - self.x; var dy = self.targetY - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 0) { self.x += dx / distance * self.speed; self.y += dy / distance * self.speed; } graphics.rotation += 0.1; }; return self; }); var SAMSite = Container.expand(function () { var self = Container.call(this); var graphics = self.attachAsset('sam', { anchorX: 0.5, anchorY: 0.5 }); self.fireTimer = 0; self.fireRate = 90; self.update = function () { self.fireTimer++; if (self.fireTimer >= self.fireRate) { self.fireTimer = 0; var missile = new SAMMissile(); missile.x = self.x; missile.y = self.y; missile.targetX = viggen.x; missile.targetY = viggen.y; game.addChild(missile); samMissiles.push(missile); LK.getSound('missile').play(); } }; return self; }); var SSR = Container.expand(function () { var self = Container.call(this); self.name = ''; self.difficultyMultiplier = 1.0; self.enemySpeedMultiplier = 1.0; self.spawnRateMultiplier = 1.0; self.scoreMultiplier = 1.0; self.backgroundColor = 0x1a1a2e; self.description = ''; self.setSSRData = function (data) { self.name = data.name; self.difficultyMultiplier = data.difficultyMultiplier; self.enemySpeedMultiplier = data.enemySpeedMultiplier; self.spawnRateMultiplier = data.spawnRateMultiplier; self.scoreMultiplier = data.scoreMultiplier; self.backgroundColor = data.backgroundColor; self.description = data.description; if (self.graphics) { self.removeChild(self.graphics); } self.graphics = self.attachAsset(data.assetName, { anchorX: 0.5, anchorY: 0.5 }); }; return self; }); var Shilka = Container.expand(function () { var self = Container.call(this); var graphics = self.attachAsset('shilka', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 1.2; self.direction = 1; self.fireTimer = 0; self.fireRate = 120; // Time between bursts self.burstStage = 0; // 0 = waiting, 1-5 = firing burst self.burstTimer = 0; self.burstDelay = 8; // Ticks between shots in burst self.rollRotation = 0; self.update = function () { var speedMultiplier = currentSSR ? currentSSR.enemySpeedMultiplier : 1.0; // Vertical rolling movement like drone self.x += self.speed * self.direction * speedMultiplier; self.y += self.speed * 0.4 * speedMultiplier; if (self.x <= 50 || self.x >= 1998) { self.direction *= -1; } // Vertical rolling animation self.rollRotation += 0.08; graphics.rotation = Math.sin(self.rollRotation) * 0.3; // Burst firing logic self.fireTimer++; if (self.burstStage === 0) { // Waiting for next burst if (self.fireTimer >= self.fireRate) { self.fireTimer = 0; self.burstStage = 1; self.burstTimer = 0; } } else if (self.burstStage <= 5) { // Firing burst (5 groups of 3 bullets) self.burstTimer++; if (self.burstTimer >= self.burstDelay) { self.burstTimer = 0; // Fire 3 bullets in current group for (var i = 0; i < 3; i++) { var bullet = new EnemyBullet(); bullet.x = self.x + (i - 1) * 15; // Spread bullets slightly bullet.y = self.y; bullet.targetX = viggen.x + (i - 1) * 20; // Slight target spread bullet.targetY = viggen.y; bullet.age = 0; game.addChild(bullet); enemyBullets.push(bullet); } self.burstStage++; if (self.burstStage > 5) { self.burstStage = 0; // Reset to waiting state } } } }; return self; }); var Su15 = Container.expand(function () { var self = Container.call(this); var graphics = self.attachAsset('su15', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 2.5; self.fireTimer = 0; self.fireRate = 45; self.interceptorType = 'su15'; self.scoreValue = 150; self.update = function () { var speedMultiplier = currentSSR ? currentSSR.enemySpeedMultiplier : 1.0; self.y += self.speed * speedMultiplier; self.fireTimer++; if (self.fireTimer >= self.fireRate) { self.fireTimer = 0; // Su-15 fires two bullets for (var i = 0; i < 2; i++) { var bullet = new EnemyBullet(); bullet.x = self.x + (i === 0 ? -10 : 10); bullet.y = self.y; bullet.targetX = viggen.x; bullet.targetY = viggen.y; bullet.age = 0; game.addChild(bullet); enemyBullets.push(bullet); } } }; return self; }); var Viggen = Container.expand(function () { var self = Container.call(this); var graphics = self.attachAsset('viggen', { anchorX: 0.5, anchorY: 0.5 }); return self; }); var ViggenBullet = Container.expand(function () { var self = Container.call(this); var graphics = self.attachAsset('viggenBullet', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 8 + (upgrades.bulletSpeed - 1) * 2; self.damage = upgrades.bulletDamage; self.update = function () { self.y -= self.speed; }; return self; }); var Yak38 = Container.expand(function () { var self = Container.call(this); var graphics = self.attachAsset('yak38', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 1.5; self.fireTimer = 0; self.fireRate = 90; self.interceptorType = 'yak38'; self.scoreValue = 80; self.sideMovement = 0; self.update = function () { var speedMultiplier = currentSSR ? currentSSR.enemySpeedMultiplier : 1.0; self.y += self.speed * speedMultiplier; // Yak-38 has slight side-to-side movement self.sideMovement += 0.05; self.x += Math.sin(self.sideMovement) * 0.8; self.fireTimer++; if (self.fireTimer >= self.fireRate) { self.fireTimer = 0; var bullet = new EnemyBullet(); bullet.x = self.x; bullet.y = self.y; bullet.targetX = viggen.x; bullet.targetY = viggen.y; bullet.age = 0; game.addChild(bullet); enemyBullets.push(bullet); } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x1a1a2e }); /**** * Game Code ****/ var viggen = game.addChild(new Viggen()); viggen.x = 1024; viggen.y = 2400; var shieldEffect = null; // Upgrade system variables var upgradeMenuOpen = false; var upgradeButton = null; var upgradeMenu = null; var upgrades = { fireRate: storage.fireRateLevel || 1, bulletSpeed: storage.bulletSpeedLevel || 1, bulletDamage: storage.bulletDamageLevel || 1, shieldDuration: storage.shieldDurationLevel || 1 }; var upgradeCosts = { fireRate: [100, 250, 500, 1000, 2000], bulletSpeed: [150, 300, 600, 1200, 2400], bulletDamage: [200, 400, 800, 1600, 3200], shieldDuration: [300, 600, 1200, 2400, 4800] }; var upgradeTexts = []; // SSR Travel System var currentSSR = null; var ssrMenuOpen = false; var ssrButton = null; var ssrMenu = null; var ssrUnlocked = { ukraine: true, russia: storage.russiaUnlocked || false, kazakh: storage.kazakhUnlocked || false, belarus: storage.belarusUnlocked || false }; // Enemy Codex System var codexMenuOpen = false; var codexMenu = null; // Guide System var guideMenuOpen = false; var guideMenu = null; var currentGuideSection = 'enemies'; // 'enemies', 'travel', 'upgrades', 'maneuvers' // Tutorial System var tutorialMenuOpen = false; var tutorialMenu = null; var currentTutorialStep = 0; // Tutorial progression tracking // Lore System var loreMenuOpen = false; var loreMenu = null; var currentLoreSection = 'background'; // 'background', 'conflict', 'technology', 'nations' // Airport Commissary System var commissaryMenuOpen = false; var commissaryMenu = null; var currentCommissarySection = 'boosts'; // 'boosts', 'cosmetics' var commissaryInventory = { scoreMultiplier: storage.scoreMultiplier || 1, bonusLives: storage.bonusLives || 0, startingShield: storage.startingShield || false, doubleFireRate: storage.doubleFireRate || false, viggenSkin: storage.viggenSkin || 'default', bulletTrail: storage.bulletTrail || 'default' }; // Armament System var armamentMenuOpen = false; var armamentMenu = null; var currentWeapon = 'cannon'; // 'cannon', 'machinegun', 'missiles' var armamentData = { cannon: { name: '30mm Akan M/70 Cannon', description: 'Standard Viggen cannon with balanced performance', fireRate: 15, bulletSpeed: 8, damage: 1, unlocked: true }, machinegun: { name: '20mm Machine Gun Pod', description: 'High rate of fire with lighter rounds', fireRate: 8, bulletSpeed: 6, damage: 0.7, unlocked: false, unlockScore: 5000 }, missiles: { name: 'AIM-9 Sidewinder Missiles', description: 'Heavy hitting missiles with slower rate of fire', fireRate: 25, bulletSpeed: 12, damage: 2.0, unlocked: false, unlockScore: 15000 } }; // Ally System var allyActive = false; var allyTimer = 0; var allyDuration = 900; // 15 seconds at 60fps var allyCooldown = 1800; // 30 seconds cooldown var allyCooldownTimer = 0; var allyViggens = []; var currentAllyType = 0; // 0=Viggen, 1=Draken, 2=Bandkanon, 3=Strv103, 4=Naval var allyTypes = ['VIGGEN', 'DRAKEN', 'BANDKANON', 'STRV 103', 'NAVAL']; var allAllyUnits = []; // All active ally units // Ally Menu System var allyMenuOpen = false; var allyMenu = null; // Dev Mode System var devModeOpen = false; var devMenu = null; var devModeEnabled = storage.devModeEnabled || false; var enemiesEncountered = { mig23: storage.mig23Encountered || false, su15: storage.su15Encountered || false, yak38: storage.yak38Encountered || false, drone: storage.droneEncountered || false, samSite: storage.samSiteEncountered || false, shilka: storage.shilkaEncountered || false }; var enemyCodexData = { mig23: { name: 'MiG-23 Flogger', description: 'Standard Soviet interceptor. Fast attack aircraft with guided missiles. Flies straight down and fires single tracking bullets.', threat: 'Medium', speed: 'Fast', fireRate: 'Medium', health: '1 Hit', tips: 'Predictable flight path makes them easy targets', assetName: 'mig23' }, su15: { name: 'Su-15 Flagon', description: 'Heavy interceptor with twin cannons. Faster than MiG-23 and fires dual tracking bullets simultaneously.', threat: 'High', speed: 'Very Fast', fireRate: 'Fast', health: '1 Hit', tips: 'Dual fire pattern - dodge sideways to avoid both bullets', assetName: 'su15' }, yak38: { name: 'Yak-38 Forger', description: 'VTOL light interceptor with erratic movement. Slower but unpredictable side-to-side flight pattern.', threat: 'Medium-Low', speed: 'Slow', fireRate: 'Slow', health: '1 Hit', tips: 'Unpredictable movement but slower fire rate. Lead your shots.', assetName: 'yak38' }, drone: { name: 'Reconnaissance Drone', description: 'Agile unmanned aircraft with side-to-side movement. Fires tracking bullets while weaving.', threat: 'High', speed: 'Medium', fireRate: 'Fast', health: '1 Hit', tips: 'Unpredictable movement pattern. Lead your shots.', assetName: 'drone' }, samSite: { name: 'SA-6 SAM Site', description: 'Surface-to-Air Missile launcher. Fires homing missiles that track your position.', threat: 'Very High', speed: 'Stationary', fireRate: 'Slow', health: '1 Hit', tips: 'Priority target. Missiles are fast and accurate.', assetName: 'sam' }, shilka: { name: 'ZSU-23-4 Shilka', description: 'Anti-aircraft gun with quad cannons. Fires in devastating bursts of 5x 3-bullet groups while rolling vertically.', threat: 'Very High', speed: 'Medium', fireRate: 'Burst', health: '1 Hit', tips: 'Take cover during bursts - 15 bullets come fast!', assetName: 'shilka' } }; var ssrData = { ukraine: { name: 'Ukrainian SSR', assetName: 'ssrUkraine', difficultyMultiplier: 1.0, enemySpeedMultiplier: 1.0, spawnRateMultiplier: 1.0, scoreMultiplier: 1.0, backgroundColor: 0x1a1a2e, description: 'Starting region with standard difficulty', unlockScore: 0 }, russia: { name: 'Russian SFSR', assetName: 'ssrRussia', difficultyMultiplier: 1.3, enemySpeedMultiplier: 1.2, spawnRateMultiplier: 1.1, scoreMultiplier: 1.5, backgroundColor: 0x2e1a1a, description: 'Harsh winter conditions, faster enemies', unlockScore: 2000 }, kazakh: { name: 'Kazakh SSR', assetName: 'ssrKazakh', difficultyMultiplier: 1.5, enemySpeedMultiplier: 1.1, spawnRateMultiplier: 1.3, scoreMultiplier: 2.0, backgroundColor: 0x2e2e1a, description: 'Desert warfare, more frequent spawns', unlockScore: 5000 }, belarus: { name: 'Byelorussian SSR', assetName: 'ssrBelarus', difficultyMultiplier: 1.8, enemySpeedMultiplier: 1.4, spawnRateMultiplier: 1.2, scoreMultiplier: 2.5, backgroundColor: 0x1a2e1a, description: 'Forest combat, elite enemy units', unlockScore: 10000 } }; var interceptors = []; var mig23s = []; var su15s = []; var yak38s = []; var shilkas = []; var samSites = []; var drones = []; var enemyBullets = []; var samMissiles = []; var viggenBullets = []; var powerups = []; // Entity pooling system for better performance var entityPools = { viggenBullets: [], enemyBullets: [], powerups: [] }; function getPooledViggenBullet() { if (entityPools.viggenBullets.length > 0) { return entityPools.viggenBullets.pop(); } return new ViggenBullet(); } function returnPooledViggenBullet(bullet) { bullet.x = 0; bullet.y = 0; if (entityPools.viggenBullets.length < 50) { entityPools.viggenBullets.push(bullet); } else { bullet.destroy(); } } function getPooledEnemyBullet() { if (entityPools.enemyBullets.length > 0) { var bullet = entityPools.enemyBullets.pop(); bullet.age = 0; return bullet; } return new EnemyBullet(); } function returnPooledEnemyBullet(bullet) { bullet.x = 0; bullet.y = 0; bullet.targetX = 0; bullet.targetY = 0; bullet.age = 0; if (entityPools.enemyBullets.length < 100) { entityPools.enemyBullets.push(bullet); } else { bullet.destroy(); } } var spawnTimer = 0; var powerupSpawnTimer = 0; var fireTimer = 0; var difficultyTimer = 0; var survivalTime = 0; var baseSpawnRate = 180; var currentSpawnRate = baseSpawnRate; var dragNode = null; var lastIntersecting = false; var speedBoostActive = false; var speedBoostTimer = 0; var shieldActive = false; var shieldTimer = 0; var rapidFireActive = false; var rapidFireTimer = 0; var normalFireRate = 15; var scoreTxt = new Text2('Score: 0', { size: 60, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); var timeTxt = new Text2('Time: 0s', { size: 50, fill: 0xFFFFFF }); timeTxt.anchor.set(1, 0); timeTxt.x = -20; timeTxt.y = 20; LK.gui.topRight.addChild(timeTxt); upgradeButton = new Text2('UPGRADES', { size: 40, fill: 0x00ff00 }); upgradeButton.anchor.set(0.5, 0); upgradeButton.x = 0; upgradeButton.y = 100; upgradeButton.interactive = true; LK.gui.top.addChild(upgradeButton); ssrButton = new Text2('TRAVEL', { size: 40, fill: 0x0088ff }); ssrButton.anchor.set(0.5, 0); ssrButton.x = 0; ssrButton.y = 160; ssrButton.interactive = true; LK.gui.top.addChild(ssrButton); var codexButton = new Text2('CODEX', { size: 40, fill: 0xff8800 }); codexButton.anchor.set(0.5, 0); codexButton.x = 0; codexButton.y = 220; codexButton.interactive = true; LK.gui.top.addChild(codexButton); var guideButton = new Text2('GUIDE', { size: 40, fill: 0xffff00 }); guideButton.anchor.set(0.5, 0); guideButton.x = 0; guideButton.y = 280; guideButton.interactive = true; LK.gui.top.addChild(guideButton); var tutorialButton = new Text2('TUTORIAL', { size: 40, fill: 0xff4499 }); tutorialButton.anchor.set(0.5, 0); tutorialButton.x = 0; tutorialButton.y = 340; tutorialButton.interactive = true; LK.gui.top.addChild(tutorialButton); var loreButton = new Text2('LORE', { size: 40, fill: 0xaa44ff }); loreButton.anchor.set(0.5, 0); loreButton.x = 0; loreButton.y = 400; loreButton.interactive = true; LK.gui.top.addChild(loreButton); var commissaryButton = new Text2('COMMISSARY', { size: 40, fill: 0x44aaff }); commissaryButton.anchor.set(0.5, 0); commissaryButton.x = 0; commissaryButton.y = 460; commissaryButton.interactive = true; LK.gui.top.addChild(commissaryButton); var armamentButton = new Text2('ARMAMENT', { size: 40, fill: 0x00ffff }); armamentButton.anchor.set(0.5, 0); armamentButton.x = 0; armamentButton.y = 520; armamentButton.interactive = true; LK.gui.top.addChild(armamentButton); var allyButton = new Text2('ALLIES: VIGGEN', { size: 40, fill: 0x00ff88 }); allyButton.anchor.set(0.5, 0); allyButton.x = 0; allyButton.y = 580; allyButton.interactive = true; LK.gui.top.addChild(allyButton); var devButton = new Text2('DEV', { size: 40, fill: 0xff00ff }); devButton.anchor.set(0.5, 0); devButton.x = 0; devButton.y = 640; devButton.interactive = true; LK.gui.top.addChild(devButton); // Initialize with Ukrainian SSR currentSSR = new SSR(); currentSSR.setSSRData(ssrData.ukraine); game.setBackgroundColor(currentSSR.backgroundColor); // Load saved weapon selection if (storage.currentWeapon && armamentData[storage.currentWeapon]) { currentWeapon = storage.currentWeapon; } else { currentWeapon = 'cannon'; // Default to cannon if no saved weapon } function handleMove(x, y, obj) { if (dragNode) { var moveSpeed = speedBoostActive ? 1.5 : 1.0; var targetX = x; var targetY = y; if (speedBoostActive) { // Smoother movement with speed boost var dx = targetX - dragNode.x; var dy = targetY - dragNode.y; dragNode.x = Math.max(40, Math.min(2008, dragNode.x + dx * moveSpeed)); dragNode.y = Math.max(60, Math.min(2672, dragNode.y + dy * moveSpeed)); } else { dragNode.x = Math.max(40, Math.min(2008, targetX)); dragNode.y = Math.max(60, Math.min(2672, targetY)); } } // Check viggen bullets vs enemies (optimized) var ssrMultiplier = currentSSR ? currentSSR.scoreMultiplier : 1.0; for (var i = viggenBullets.length - 1; i >= 0; i--) { var bullet = viggenBullets[i]; var hit = false; var hitTarget = null; var hitArray = null; var hitIndex = -1; var baseScore = 0; // Check vs interceptors for (var j = interceptors.length - 1; j >= 0; j--) { if (bullet.intersects(interceptors[j])) { var interceptor = interceptors[j]; var interceptorType = interceptor.interceptorType; // Find in specific array without nested loop var typeArray = interceptorType === 'mig23' ? mig23s : interceptorType === 'su15' ? su15s : yak38s; var typeIndex = typeArray.indexOf(interceptor); if (typeIndex !== -1) typeArray.splice(typeIndex, 1); hitTarget = interceptor; hitArray = interceptors; hitIndex = j; baseScore = (interceptor.scoreValue || 100) * bullet.damage; hit = true; break; } } if (!hit) { // Check vs drones for (var j = drones.length - 1; j >= 0; j--) { if (bullet.intersects(drones[j])) { hitTarget = drones[j]; hitArray = drones; hitIndex = j; baseScore = 150 * bullet.damage; hit = true; break; } } } if (!hit) { // Check vs SAM sites for (var j = samSites.length - 1; j >= 0; j--) { if (bullet.intersects(samSites[j])) { hitTarget = samSites[j]; hitArray = samSites; hitIndex = j; baseScore = 200 * bullet.damage; hit = true; break; } } } if (!hit) { // Check vs Shilkas for (var j = shilkas.length - 1; j >= 0; j--) { if (bullet.intersects(shilkas[j])) { hitTarget = shilkas[j]; hitArray = shilkas; hitIndex = j; baseScore = 250 * bullet.damage; hit = true; break; } } } if (hit) { LK.effects.flashObject(hitTarget, 0xff0000, 200); hitTarget.destroy(); hitArray.splice(hitIndex, 1); bullet.destroy(); viggenBullets.splice(i, 1); LK.setScore(LK.getScore() + Math.floor(baseScore * ssrMultiplier)); } } // Check viggen vs powerups for (var i = powerups.length - 1; i >= 0; i--) { var powerup = powerups[i]; if (viggen.intersects(powerup)) { // Apply powerup effect if (powerup.powerupType === 'speed') { speedBoostActive = true; speedBoostTimer = 300; // 5 seconds at 60fps LK.effects.flashObject(viggen, 0x00ff00, 300); } else if (powerup.powerupType === 'shield') { shieldActive = true; shieldTimer = 600 + (upgrades.shieldDuration - 1) * 180; // Base 10s + upgrades if (!shieldEffect) { shieldEffect = LK.getAsset('powerupShield', { anchorX: 0.5, anchorY: 0.5, scaleX: 2.5, scaleY: 2.5 }); shieldEffect.alpha = 0.3; viggen.addChild(shieldEffect); } } else if (powerup.powerupType === 'rapidfire') { rapidFireActive = true; rapidFireTimer = 450; // 7.5 seconds at 60fps LK.effects.flashObject(viggen, 0xff8800, 300); } LK.getSound('powerup').play(); LK.setScore(LK.getScore() + 50); powerup.destroy(); powerups.splice(i, 1); } } } game.move = handleMove; game.down = function (x, y, obj) { dragNode = viggen; handleMove(x, y, obj); }; game.up = function (x, y, obj) { dragNode = null; }; upgradeButton.down = function (x, y, obj) { if (!upgradeMenuOpen) { openUpgradeMenu(); } else { closeUpgradeMenu(); } }; ssrButton.down = function (x, y, obj) { // Check if we're in code input mode (dev mode not yet unlocked) if (!devModeEnabled && !ssrMenuOpen) { // Cycle through SSR sequence for secret code input (independent of actual travel) var ssrSequence = ['ukraine', 'russia', 'kazakh', 'belarus', 'ukraine']; var currentIndex = currentCodeInput.length % ssrSequence.length; var expectedSSR = ssrSequence[currentIndex]; // Add the expected next SSR to sequence currentCodeInput.push(expectedSSR); codeInputTimer = 0; // Reset timer // Show which SSR was "selected" in the sequence var ssrNames = { 'ukraine': 'Ukrainian SSR', 'russia': 'Russian SFSR', 'kazakh': 'Kazakh SSR', 'belarus': 'Byelorussian SSR' }; var sequenceText = new Text2('Sequence: ' + ssrNames[expectedSSR], { size: 35, fill: 0x00FFFF }); sequenceText.anchor.set(0.5, 0.5); sequenceText.x = 1024; sequenceText.y = 150; game.addChild(sequenceText); LK.setTimeout(function () { if (sequenceText.parent) { game.removeChild(sequenceText); } }, 1000); // Check if sequence is complete if (currentCodeInput.length === secretCode.length) { devModeEnabled = true; storage.devModeEnabled = true; currentCodeInput = []; LK.effects.flashScreen(0x00FF00, 1000); var unlockText = new Text2('DEV MODE UNLOCKED!', { size: 60, fill: 0x00FF00 }); unlockText.anchor.set(0.5, 0.5); unlockText.x = 1024; unlockText.y = 1366; game.addChild(unlockText); LK.setTimeout(function () { if (unlockText.parent) { game.removeChild(unlockText); } }, 3000); return; // Don't open SSR menu } // Show progress hint var progressText = new Text2('Code Progress: ' + currentCodeInput.length + '/' + secretCode.length, { size: 30, fill: 0xFFFF00 }); progressText.anchor.set(0.5, 0.5); progressText.x = 1024; progressText.y = 100; game.addChild(progressText); LK.setTimeout(function () { if (progressText.parent) { game.removeChild(progressText); } }, 1500); return; // Don't open SSR menu while in code input mode } // Normal SSR menu functionality if (!ssrMenuOpen) { openSSRMenu(); } else { closeSSRMenu(); } }; codexButton.down = function (x, y, obj) { if (!codexMenuOpen) { openCodexMenu(); } else { closeCodexMenu(); } }; guideButton.down = function (x, y, obj) { if (!guideMenuOpen) { openGuideMenu(); } else { closeGuideMenu(); } }; tutorialButton.down = function (x, y, obj) { if (!tutorialMenuOpen) { openTutorialMenu(); } else { closeTutorialMenu(); } }; loreButton.down = function (x, y, obj) { if (!loreMenuOpen) { openLoreMenu(); } else { closeLoreMenu(); } }; commissaryButton.down = function (x, y, obj) { if (!commissaryMenuOpen) { openCommissaryMenu(); } else { closeCommissaryMenu(); } }; armamentButton.down = function (x, y, obj) { if (!armamentMenuOpen) { openArmamentMenu(); } else { closeArmamentMenu(); } }; allyButton.down = function (x, y, obj) { if (allyCooldownTimer <= 0 && !allyActive) { if (!allyMenuOpen) { openAllyMenu(); } else { closeAllyMenu(); } } else { // Show cooldown message if allies not available var cooldownText = new Text2(allyActive ? 'ALLIES ACTIVE' : 'ALLIES ON COOLDOWN', { size: 40, fill: 0xFF6666 }); cooldownText.anchor.set(0.5, 0.5); cooldownText.x = 1024; cooldownText.y = 1366; game.addChild(cooldownText); LK.setTimeout(function () { if (cooldownText.parent) { game.removeChild(cooldownText); } }, 1500); } }; // Secret code system for dev mode access var secretCode = ['ukraine', 'russia', 'kazakh', 'belarus', 'ukraine']; // SSR sequence var currentCodeInput = []; var codeInputTimer = 0; var maxCodeInputTime = 300; // 5 seconds at 60fps to complete sequence devButton.down = function (x, y, obj) { if (!devModeEnabled) { // Show hint that dev mode requires unlock var hintText = new Text2('DEV MODE LOCKED\nRequires secret sequence...', { size: 25, fill: 0xFF6666 }); hintText.anchor.set(0.5, 0.5); hintText.x = 1024; hintText.y = 1366; game.addChild(hintText); // Remove hint after 2 seconds LK.setTimeout(function () { if (hintText.parent) { game.removeChild(hintText); } }, 2000); } else if (!devModeOpen) { openDevMenu(); } else { closeDevMenu(); } }; function spawnInterceptor() { var interceptorType = Math.random(); var interceptor; if (interceptorType < 0.5) { interceptor = new MiG23(); mig23s.push(interceptor); markEnemyEncountered('mig23'); } else if (interceptorType < 0.8) { interceptor = new Su15(); su15s.push(interceptor); markEnemyEncountered('su15'); } else { interceptor = new Yak38(); yak38s.push(interceptor); markEnemyEncountered('yak38'); } interceptor.x = Math.random() * 1848 + 100; interceptor.y = -100; game.addChild(interceptor); interceptors.push(interceptor); } function spawnSAMSite() { var sam = new SAMSite(); sam.x = Math.random() * 1848 + 100; sam.y = Math.random() * 400 + 100; game.addChild(sam); samSites.push(sam); markEnemyEncountered('samSite'); } function spawnDrone() { var drone = new Drone(); drone.x = Math.random() * 1848 + 100; drone.y = -50; game.addChild(drone); drones.push(drone); markEnemyEncountered('drone'); } function spawnShilka() { var shilka = new Shilka(); shilka.x = Math.random() * 1848 + 100; shilka.y = -50; game.addChild(shilka); shilkas.push(shilka); markEnemyEncountered('shilka'); } function spawnPowerup() { var powerup = new Powerup(); powerup.x = Math.random() * 1600 + 224; powerup.y = -50; var powerupTypes = ['speed', 'shield', 'rapidfire']; var randomType = powerupTypes[Math.floor(Math.random() * powerupTypes.length)]; powerup.setPowerupType(randomType); game.addChild(powerup); powerups.push(powerup); } function openUpgradeMenu() { upgradeMenuOpen = true; upgradeButton.setText('CLOSE'); upgradeMenu = new Container(); upgradeMenu.x = 0; upgradeMenu.y = 0; game.addChild(upgradeMenu); var menuBg = LK.getAsset('sam', { anchorX: 0.5, anchorY: 0.5, scaleX: 15, scaleY: 20 }); menuBg.x = 1024; menuBg.y = 1366; menuBg.alpha = 0.9; menuBg.tint = 0x000066; upgradeMenu.addChild(menuBg); var titleText = new Text2('UPGRADES', { size: 80, fill: 0xFFFFFF }); titleText.anchor.set(0.5, 0.5); titleText.x = 1024; titleText.y = 1000; upgradeMenu.addChild(titleText); var currentScore = LK.getScore(); var scoreText = new Text2('Score: ' + currentScore, { size: 50, fill: 0xFFFF00 }); scoreText.anchor.set(0.5, 0.5); scoreText.x = 1024; scoreText.y = 1100; upgradeMenu.addChild(scoreText); createUpgradeOption('Fire Rate', 'fireRate', 1200); createUpgradeOption('Bullet Speed', 'bulletSpeed', 1300); createUpgradeOption('Bullet Damage', 'bulletDamage', 1400); createUpgradeOption('Shield Duration', 'shieldDuration', 1500); } function createUpgradeOption(name, upgradeType, yPos) { var level = upgrades[upgradeType]; var maxLevel = upgradeCosts[upgradeType].length; var cost = level < maxLevel ? upgradeCosts[upgradeType][level - 1] : 'MAX'; var upgradeText = new Text2(name + ' Lv.' + level + ' - Cost: ' + cost, { size: 40, fill: level < maxLevel && LK.getScore() >= cost ? 0x00ff00 : 0xff6666 }); upgradeText.anchor.set(0.5, 0.5); upgradeText.x = 1024; upgradeText.y = yPos; upgradeText.interactive = true; upgradeMenu.addChild(upgradeText); upgradeTexts.push({ text: upgradeText, type: upgradeType }); if (level < maxLevel && LK.getScore() >= cost) { upgradeText.down = function () { buyUpgrade(upgradeType); }; } } function buyUpgrade(upgradeType) { var level = upgrades[upgradeType]; var maxLevel = upgradeCosts[upgradeType].length; var cost = upgradeCosts[upgradeType][level - 1]; if (level < maxLevel && LK.getScore() >= cost) { LK.setScore(LK.getScore() - cost); upgrades[upgradeType]++; // Save to storage if (upgradeType === 'fireRate') storage.fireRateLevel = upgrades[upgradeType];else if (upgradeType === 'bulletSpeed') storage.bulletSpeedLevel = upgrades[upgradeType];else if (upgradeType === 'bulletDamage') storage.bulletDamageLevel = upgrades[upgradeType];else if (upgradeType === 'shieldDuration') storage.shieldDurationLevel = upgrades[upgradeType]; scoreTxt.setText('Score: ' + LK.getScore()); LK.getSound('powerup').play(); closeUpgradeMenu(); } } function closeUpgradeMenu() { upgradeMenuOpen = false; upgradeButton.setText('UPGRADES'); if (upgradeMenu) { game.removeChild(upgradeMenu); upgradeMenu = null; upgradeTexts = []; } } function openSSRMenu() { ssrMenuOpen = true; ssrButton.setText('CLOSE'); ssrMenu = new Container(); ssrMenu.x = 0; ssrMenu.y = 0; game.addChild(ssrMenu); var menuBg = LK.getAsset('sam', { anchorX: 0.5, anchorY: 0.5, scaleX: 15, scaleY: 20 }); menuBg.x = 1024; menuBg.y = 1366; menuBg.alpha = 0.9; menuBg.tint = 0x006666; ssrMenu.addChild(menuBg); var titleText = new Text2('SOVIET SOCIALIST REPUBLICS', { size: 60, fill: 0xFFFFFF }); titleText.anchor.set(0.5, 0.5); titleText.x = 1024; titleText.y = 900; ssrMenu.addChild(titleText); var currentText = new Text2('Current: ' + currentSSR.name, { size: 40, fill: 0xFFFF00 }); currentText.anchor.set(0.5, 0.5); currentText.x = 1024; currentText.y = 980; ssrMenu.addChild(currentText); var yPos = 1100; for (var ssrKey in ssrData) { createSSROption(ssrKey, ssrData[ssrKey], yPos); yPos += 100; } // Check for unlocks checkSSRUnlocks(); } function createSSROption(ssrKey, data, yPos) { var isUnlocked = ssrUnlocked[ssrKey]; var isCurrent = currentSSR.name === data.name; var statusText = isCurrent ? ' (CURRENT)' : isUnlocked ? ' - AVAILABLE' : ' - LOCKED (Score: ' + data.unlockScore + ')'; var optionText = new Text2(data.name + statusText, { size: 35, fill: isCurrent ? 0xFFFF00 : isUnlocked ? 0x00ff00 : 0xff6666 }); optionText.anchor.set(0.5, 0.5); optionText.x = 1024; optionText.y = yPos; optionText.interactive = true; ssrMenu.addChild(optionText); var descText = new Text2(data.description, { size: 25, fill: 0xCCCCCC }); descText.anchor.set(0.5, 0.5); descText.x = 1024; descText.y = yPos + 30; ssrMenu.addChild(descText); if (isUnlocked && !isCurrent) { optionText.down = function () { travelToSSR(ssrKey); }; } } function travelToSSR(ssrKey) { var data = ssrData[ssrKey]; currentSSR.setSSRData(data); game.setBackgroundColor(currentSSR.backgroundColor); LK.getSound('travel').play(); LK.effects.flashScreen(0x00ffff, 500); // Reset some game state for new region spawnTimer = 0; currentSpawnRate = Math.floor(baseSpawnRate / currentSSR.spawnRateMultiplier); closeSSRMenu(); } function closeSSRMenu() { ssrMenuOpen = false; ssrButton.setText('TRAVEL'); if (ssrMenu) { game.removeChild(ssrMenu); ssrMenu = null; } } function checkSSRUnlocks() { var currentScore = LK.getScore(); for (var ssrKey in ssrData) { if (!ssrUnlocked[ssrKey] && currentScore >= ssrData[ssrKey].unlockScore) { ssrUnlocked[ssrKey] = true; // Save unlock status if (ssrKey === 'russia') storage.russiaUnlocked = true;else if (ssrKey === 'kazakh') storage.kazakhUnlocked = true;else if (ssrKey === 'belarus') storage.belarusUnlocked = true; LK.effects.flashScreen(0x00ff00, 300); } } } function openCodexMenu() { codexMenuOpen = true; codexButton.setText('CLOSE'); codexMenu = new Container(); codexMenu.x = 0; codexMenu.y = 0; game.addChild(codexMenu); var menuBg = LK.getAsset('sam', { anchorX: 0.5, anchorY: 0.5, scaleX: 15, scaleY: 20 }); menuBg.x = 1024; menuBg.y = 1366; menuBg.alpha = 0.9; menuBg.tint = 0x660066; codexMenu.addChild(menuBg); var titleText = new Text2('ENEMY CODEX', { size: 80, fill: 0xFFFFFF }); titleText.anchor.set(0.5, 0.5); titleText.x = 1024; titleText.y = 900; codexMenu.addChild(titleText); var instructionText = new Text2('Encounter enemies to unlock their data', { size: 35, fill: 0xCCCCCC }); instructionText.anchor.set(0.5, 0.5); instructionText.x = 1024; instructionText.y = 980; codexMenu.addChild(instructionText); var yPos = 1100; for (var enemyKey in enemyCodexData) { createCodexEntry(enemyKey, enemyCodexData[enemyKey], yPos); yPos += 200; } } function createCodexEntry(enemyKey, data, yPos) { var isEncountered = enemiesEncountered[enemyKey]; var nameText = new Text2(isEncountered ? data.name : '??? CLASSIFIED ???', { size: 45, fill: isEncountered ? 0x00ff00 : 0x666666 }); nameText.anchor.set(0.5, 0.5); nameText.x = 1024; nameText.y = yPos; codexMenu.addChild(nameText); if (isEncountered) { var descText = new Text2(data.description, { size: 30, fill: 0xFFFFFF }); descText.anchor.set(0.5, 0.5); descText.x = 1024; descText.y = yPos + 40; codexMenu.addChild(descText); var statsText = new Text2('Threat: ' + data.threat + ' | Speed: ' + data.speed + ' | Fire Rate: ' + data.fireRate, { size: 25, fill: 0xFFFF88 }); statsText.anchor.set(0.5, 0.5); statsText.x = 1024; statsText.y = yPos + 75; codexMenu.addChild(statsText); var tipsText = new Text2('Tips: ' + data.tips, { size: 25, fill: 0x88FF88 }); tipsText.anchor.set(0.5, 0.5); tipsText.x = 1024; tipsText.y = yPos + 105; codexMenu.addChild(tipsText); } else { var lockedText = new Text2('Encounter this enemy type to unlock data', { size: 25, fill: 0x666666 }); lockedText.anchor.set(0.5, 0.5); lockedText.x = 1024; lockedText.y = yPos + 40; codexMenu.addChild(lockedText); } } function closeCodexMenu() { codexMenuOpen = false; codexButton.setText('CODEX'); if (codexMenu) { game.removeChild(codexMenu); codexMenu = null; } } function markEnemyEncountered(enemyType) { if (!enemiesEncountered[enemyType]) { enemiesEncountered[enemyType] = true; // Save to storage if (enemyType === 'mig23') storage.mig23Encountered = true;else if (enemyType === 'su15') storage.su15Encountered = true;else if (enemyType === 'yak38') storage.yak38Encountered = true;else if (enemyType === 'drone') storage.droneEncountered = true;else if (enemyType === 'samSite') storage.samSiteEncountered = true;else if (enemyType === 'shilka') storage.shilkaEncountered = true; // Flash effect for discovery LK.effects.flashScreen(0x00ffff, 200); } } function openGuideMenu() { guideMenuOpen = true; guideButton.setText('CLOSE'); guideMenu = new Container(); guideMenu.x = 0; guideMenu.y = 0; game.addChild(guideMenu); var menuBg = LK.getAsset('sam', { anchorX: 0.5, anchorY: 0.5, scaleX: 15, scaleY: 20 }); menuBg.x = 1024; menuBg.y = 1366; menuBg.alpha = 0.95; menuBg.tint = 0x003366; guideMenu.addChild(menuBg); var titleText = new Text2('GAME GUIDE', { size: 80, fill: 0xFFFFFF }); titleText.anchor.set(0.5, 0.5); titleText.x = 1024; titleText.y = 700; guideMenu.addChild(titleText); // Section buttons var enemiesBtn = new Text2('[ENEMIES]', { size: 35, fill: currentGuideSection === 'enemies' ? 0xFFFF00 : 0x88CCFF }); enemiesBtn.anchor.set(0.5, 0.5); enemiesBtn.x = 700; enemiesBtn.y = 800; enemiesBtn.interactive = true; guideMenu.addChild(enemiesBtn); var travelBtn = new Text2('[TRAVEL]', { size: 35, fill: currentGuideSection === 'travel' ? 0xFFFF00 : 0x88CCFF }); travelBtn.anchor.set(0.5, 0.5); travelBtn.x = 900; travelBtn.y = 800; travelBtn.interactive = true; guideMenu.addChild(travelBtn); var upgradesBtn = new Text2('[UPGRADES]', { size: 35, fill: currentGuideSection === 'upgrades' ? 0xFFFF00 : 0x88CCFF }); upgradesBtn.anchor.set(0.5, 0.5); upgradesBtn.x = 1100; upgradesBtn.y = 800; upgradesBtn.interactive = true; guideMenu.addChild(upgradesBtn); var maneuversBtn = new Text2('[MANEUVERS]', { size: 35, fill: currentGuideSection === 'maneuvers' ? 0xFFFF00 : 0x88CCFF }); maneuversBtn.anchor.set(0.5, 0.5); maneuversBtn.x = 1350; maneuversBtn.y = 800; maneuversBtn.interactive = true; guideMenu.addChild(maneuversBtn); // Event handlers for section buttons enemiesBtn.down = function () { currentGuideSection = 'enemies'; closeGuideMenu(); openGuideMenu(); }; travelBtn.down = function () { currentGuideSection = 'travel'; closeGuideMenu(); openGuideMenu(); }; upgradesBtn.down = function () { currentGuideSection = 'upgrades'; closeGuideMenu(); openGuideMenu(); }; maneuversBtn.down = function () { currentGuideSection = 'maneuvers'; closeGuideMenu(); openGuideMenu(); }; // Display content based on current section if (currentGuideSection === 'enemies') { displayEnemyTips(); } else if (currentGuideSection === 'travel') { displayTravelGuide(); } else if (currentGuideSection === 'upgrades') { displayUpgradeGuide(); } else if (currentGuideSection === 'maneuvers') { displayManeuverGuide(); } } function displayEnemyTips() { var enemyTips = { mig23: { name: 'MiG-23 Flogger', tip1: '• Keep moving - they fire straight at your position', tip2: '• Destroy quickly before they crowd the screen' }, su15: { name: 'Su-15 Flagon', tip1: '• Watch for dual bullets - dodge sideways not just up/down', tip2: '• Priority target due to high fire rate and speed' }, yak38: { name: 'Yak-38 Forger', tip1: '• Slow but erratic - lead your shots ahead', tip2: '• Use their slow fire rate to get close safely' }, drone: { name: 'Reconnaissance Drone', tip1: '• Never stay still - they track while weaving', tip2: '• Focus fire when they reverse direction at edges' }, samSite: { name: 'SAM Site', tip1: '• Destroy immediately - missiles are hard to dodge', tip2: '• Move in circles to confuse missile tracking' }, shilka: { name: 'Shilka SPAA', tip1: '• Take cover during burst phases - 15 bullets incoming!', tip2: '• Attack between bursts when it\'s reloading' } }; var yPos = 900; for (var key in enemyTips) { var enemy = enemyTips[key]; var nameText = new Text2(enemy.name, { size: 35, fill: 0xFFFF00 }); nameText.anchor.set(0.5, 0.5); nameText.x = 1024; nameText.y = yPos; guideMenu.addChild(nameText); var tip1Text = new Text2(enemy.tip1, { size: 25, fill: 0xFFFFFF }); tip1Text.anchor.set(0.5, 0.5); tip1Text.x = 1024; tip1Text.y = yPos + 30; guideMenu.addChild(tip1Text); var tip2Text = new Text2(enemy.tip2, { size: 25, fill: 0xFFFFFF }); tip2Text.anchor.set(0.5, 0.5); tip2Text.x = 1024; tip2Text.y = yPos + 55; guideMenu.addChild(tip2Text); yPos += 100; } } function displayTravelGuide() { var travelGuideText = ['TRAVEL SYSTEM GUIDE', '', '• Unlock new SSRs by reaching score thresholds', '• Each SSR has unique difficulty modifiers:', ' - Enemy speed multiplier', ' - Spawn rate multiplier', ' - Score multiplier (risk vs reward!)', '', 'SSR ENEMY PATTERNS:', '• Ukraine: MiG-23s, Yak-38s, Drones', '• Russia: MiG-23s, Su-15s, SAM Sites', '• Kazakhstan: Yak-38 swarms, Drones, Shilkas', '• Belarus: SAMs, Su-15s, Shilkas, MiG-23s', '', 'STRATEGY TIPS:', '• Farm easy points in Ukraine first', '• Move to Russia (2000 pts) for 1.5x score', '• Kazakhstan (5000 pts) has more enemies', '• Belarus (10000 pts) is ultimate challenge', '', '• Higher difficulty = Higher score multiplier', '• Return to easier SSRs if struggling', '• Upgrades carry between all SSRs']; var yPos = 900; for (var i = 0; i < travelGuideText.length; i++) { var text = new Text2(travelGuideText[i], { size: i === 0 ? 40 : 28, fill: i === 0 ? 0xFFFF00 : travelGuideText[i].includes('SSR ENEMY PATTERNS:') || travelGuideText[i].includes('STRATEGY TIPS:') ? 0x88FF88 : 0xFFFFFF }); text.anchor.set(0.5, 0.5); text.x = 1024; text.y = yPos; guideMenu.addChild(text); yPos += i === 0 ? 50 : 35; } } function displayUpgradeGuide() { var upgradeGuideText = ['UPGRADE SYSTEM GUIDE', '', 'FIRE RATE (100-2000 pts):', '• Essential first upgrade', '• Reduces time between shots', '', 'BULLET SPEED (150-2400 pts):', '• Helps hit fast-moving enemies', '• Great for interceptors', '', 'BULLET DAMAGE (200-3200 pts):', '• Multiplies score per kill', '• Best long-term investment', '', 'SHIELD DURATION (300-4800 pts):', '• Extends power-up shield time', '• Crucial for high difficulty SSRs', '', 'TIP: Balance upgrades for best results!']; var yPos = 900; for (var i = 0; i < upgradeGuideText.length; i++) { var text = new Text2(upgradeGuideText[i], { size: i === 0 ? 40 : upgradeGuideText[i].includes(':') ? 30 : 25, fill: i === 0 ? 0xFFFF00 : upgradeGuideText[i].includes(':') ? 0x88FF88 : 0xFFFFFF }); text.anchor.set(0.5, 0.5); text.x = 1024; text.y = yPos; guideMenu.addChild(text); yPos += i === 0 ? 50 : 35; } } function displayManeuverGuide() { var maneuverGuideText = ['BASIC MANEUVERS', '', 'DEFENSIVE MOVES:', '• Circle Strafe - Move in circles vs SAMs', '• Edge Hugging - Use screen edges safely', '• Weaving - Small zigzags vs tracking', '', 'OFFENSIVE TACTICS:', '• Lead Shots - Aim ahead of moving targets', '• Focus Fire - One enemy at a time', '• Priority Targeting - SAMs > Su-15 > Rest', '', 'POWER-UP USAGE:', '• Speed (Green) - For dodging clusters', '• Shield (Blue) - Save for emergencies', '• Rapid Fire (Orange) - Clear screens fast', '', 'SURVIVAL TIP: Keep moving, never stop!']; var yPos = 900; for (var i = 0; i < maneuverGuideText.length; i++) { var text = new Text2(maneuverGuideText[i], { size: i === 0 ? 40 : maneuverGuideText[i].includes(':') ? 30 : 25, fill: i === 0 ? 0xFFFF00 : maneuverGuideText[i].includes(':') ? 0x88CCFF : 0xFFFFFF }); text.anchor.set(0.5, 0.5); text.x = 1024; text.y = yPos; guideMenu.addChild(text); yPos += i === 0 ? 50 : 32; } } function closeGuideMenu() { guideMenuOpen = false; guideButton.setText('GUIDE'); if (guideMenu) { game.removeChild(guideMenu); guideMenu = null; } } function openLoreMenu() { loreMenuOpen = true; loreButton.setText('CLOSE'); loreMenu = new Container(); loreMenu.x = 0; loreMenu.y = 0; game.addChild(loreMenu); var menuBg = LK.getAsset('sam', { anchorX: 0.5, anchorY: 0.5, scaleX: 15, scaleY: 20 }); menuBg.x = 1024; menuBg.y = 1366; menuBg.alpha = 0.95; menuBg.tint = 0x440066; loreMenu.addChild(menuBg); var titleText = new Text2('VIGGEN LORE', { size: 80, fill: 0xAA44FF }); titleText.anchor.set(0.5, 0.5); titleText.x = 1024; titleText.y = 700; loreMenu.addChild(titleText); // Section buttons var backgroundBtn = new Text2('[BACKGROUND]', { size: 32, fill: currentLoreSection === 'background' ? 0xFFFF00 : 0x88CCFF }); backgroundBtn.anchor.set(0.5, 0.5); backgroundBtn.x = 600; backgroundBtn.y = 800; backgroundBtn.interactive = true; loreMenu.addChild(backgroundBtn); var conflictBtn = new Text2('[CONFLICT]', { size: 32, fill: currentLoreSection === 'conflict' ? 0xFFFF00 : 0x88CCFF }); conflictBtn.anchor.set(0.5, 0.5); conflictBtn.x = 850; conflictBtn.y = 800; conflictBtn.interactive = true; loreMenu.addChild(conflictBtn); var technologyBtn = new Text2('[TECHNOLOGY]', { size: 32, fill: currentLoreSection === 'technology' ? 0xFFFF00 : 0x88CCFF }); technologyBtn.anchor.set(0.5, 0.5); technologyBtn.x = 1200; technologyBtn.y = 800; technologyBtn.interactive = true; loreMenu.addChild(technologyBtn); var nationsBtn = new Text2('[NATIONS]', { size: 32, fill: currentLoreSection === 'nations' ? 0xFFFF00 : 0x88CCFF }); nationsBtn.anchor.set(0.5, 0.5); nationsBtn.x = 1450; nationsBtn.y = 800; nationsBtn.interactive = true; loreMenu.addChild(nationsBtn); // Event handlers for section buttons backgroundBtn.down = function () { currentLoreSection = 'background'; closeLoreMenu(); openLoreMenu(); }; conflictBtn.down = function () { currentLoreSection = 'conflict'; closeLoreMenu(); openLoreMenu(); }; technologyBtn.down = function () { currentLoreSection = 'technology'; closeLoreMenu(); openLoreMenu(); }; nationsBtn.down = function () { currentLoreSection = 'nations'; closeLoreMenu(); openLoreMenu(); }; // Display content based on current section if (currentLoreSection === 'background') { displayBackgroundLore(); } else if (currentLoreSection === 'conflict') { displayConflictLore(); } else if (currentLoreSection === 'technology') { displayTechnologyLore(); } else if (currentLoreSection === 'nations') { displayNationsLore(); } } function displayBackgroundLore() { var backgroundLoreText = ['THE COLD WAR INTENSIFIES', '', 'Year: 1987', 'Location: Scandinavian Peninsula', '', 'SITUATION REPORT:', '• Warsaw Pact forces have violated Swedish airspace', '• Multiple Soviet aircraft detected over neutral territory', '• Swedish Air Force scrambled to defend sovereignty', '', 'MISSION BRIEFING:', 'You are piloting a JAS 39 Viggen, Sweden\'s premier', 'fighter-interceptor. Your mission is to patrol Swedish', 'airspace and neutralize any hostile aircraft.', '', 'Sweden maintains strict neutrality, but will defend', 'its borders against any aggression. The Cold War', 'tensions have reached a breaking point, and Soviet', 'forces are testing Western resolve.', '', 'Intelligence reports suggest coordinated incursions', 'across multiple Socialist Republics. Stay vigilant,', 'pilot - the defense of Sweden rests in your hands.']; var yPos = 900; for (var i = 0; i < backgroundLoreText.length; i++) { var text = new Text2(backgroundLoreText[i], { size: i === 0 ? 42 : 28, fill: i === 0 ? 0xFFFF00 : backgroundLoreText[i].includes('SITUATION REPORT:') || backgroundLoreText[i].includes('MISSION BRIEFING:') ? 0x88FF88 : 0xFFFFFF }); text.anchor.set(0.5, 0.5); text.x = 1024; text.y = yPos; loreMenu.addChild(text); yPos += i === 0 ? 50 : 32; } } function displayConflictLore() { var conflictLoreText = ['THE BALTIC CRISIS', '', 'ESCALATION TIMELINE:', '', '1985: Increased Soviet submarine activity detected', 'in Swedish territorial waters. Several incidents', 'involving foreign submarines near naval bases.', '', '1986: Warsaw Pact military exercises near Baltic', 'borders intensify. NATO responds with increased', 'reconnaissance flights over Scandinavia.', '', '1987: The current crisis begins with coordinated', 'airspace violations across multiple Soviet republics.', 'Swedish neutrality policy tested to its limits.', '', 'RULES OF ENGAGEMENT:', '• Hostile aircraft are to be warned once', '• If warnings ignored, weapons free authorized', '• Protect civilian aircraft at all costs', '• Maintain Swedish territorial integrity', '', 'The world watches as this crisis unfolds.', 'Your actions may determine if this conflict', 'escalates into full-scale war.']; var yPos = 900; for (var i = 0; i < conflictLoreText.length; i++) { var text = new Text2(conflictLoreText[i], { size: i === 0 ? 42 : conflictLoreText[i].includes('ESCALATION TIMELINE:') || conflictLoreText[i].includes('RULES OF ENGAGEMENT:') ? 32 : 28, fill: i === 0 ? 0xFFFF00 : conflictLoreText[i].includes('ESCALATION TIMELINE:') || conflictLoreText[i].includes('RULES OF ENGAGEMENT:') ? 0x88FF88 : 0xFFFFFF }); text.anchor.set(0.5, 0.5); text.x = 1024; text.y = yPos; loreMenu.addChild(text); yPos += i === 0 ? 50 : 32; } } function displayTechnologyLore() { var technologyLoreText = ['VIGGEN FIGHTER SPECIFICATIONS', '', 'JAS 39 VIGGEN MULTIROLE FIGHTER:', '', 'POWERPLANT:', '• Volvo RM12 afterburning turbofan', '• 18,100 lbf thrust with afterburner', '• Advanced fuel injection system', '', 'PERFORMANCE:', '• Max Speed: Mach 2+ at altitude', '• Service Ceiling: 50,000+ feet', '• Combat Range: 800+ nautical miles', '', 'ARMAMENT SYSTEMS:', '• 30mm Akan M/70 cannon (standard)', '• AIM-9 Sidewinder air-to-air missiles', '• Advanced fire control radar', '', 'DEFENSIVE SYSTEMS:', '• Electronic countermeasures suite', '• Chaff and flare dispensers', '• Radar warning receivers', '', 'The Viggen represents Swedish engineering', 'excellence - built for short runway operations', 'and optimized for Baltic air defense missions.']; var yPos = 900; for (var i = 0; i < technologyLoreText.length; i++) { var text = new Text2(technologyLoreText[i], { size: i === 0 ? 42 : technologyLoreText[i].includes(':') && technologyLoreText[i].length < 30 ? 30 : 28, fill: i === 0 ? 0xFFFF00 : technologyLoreText[i].includes(':') && technologyLoreText[i].length < 30 ? 0x88CCFF : 0xFFFFFF }); text.anchor.set(0.5, 0.5); text.x = 1024; text.y = yPos; loreMenu.addChild(text); yPos += i === 0 ? 50 : 32; } } function displayNationsLore() { var nationsLoreText = ['NATIONS IN CONFLICT', '', 'KINGDOM OF SWEDEN:', '• Neutral nation maintaining armed defense', '• Home to advanced aerospace industry', '• Strategic position controlling Baltic access', '', 'SOVIET UNION:', '• Superpower seeking regional influence', '• Large military with diverse aircraft fleet', '• Testing Western resolve through provocations', '', 'WARSAW PACT REPUBLICS:', '', 'Ukrainian SSR: Industrial heartland, standard forces', 'Russian SFSR: Core republic, elite units deployed', 'Kazakh SSR: Vast territory, desert-trained pilots', 'Byelorussian SSR: Western frontier, heavily armed', '', 'NATO ALLIANCE:', '• Monitoring situation closely', '• Ready to support Swedish sovereignty', '• Complex web of mutual defense treaties', '', 'The delicate balance of Cold War politics', 'hangs on every engagement in Swedish skies.', 'One wrong move could trigger global conflict.']; var yPos = 900; for (var i = 0; i < nationsLoreText.length; i++) { var text = new Text2(nationsLoreText[i], { size: i === 0 ? 42 : nationsLoreText[i].includes(':') && nationsLoreText[i].length < 30 ? 30 : 28, fill: i === 0 ? 0xFFFF00 : nationsLoreText[i].includes(':') && nationsLoreText[i].length < 30 ? 0x88FF88 : 0xFFFFFF }); text.anchor.set(0.5, 0.5); text.x = 1024; text.y = yPos; loreMenu.addChild(text); yPos += i === 0 ? 50 : 32; } } function closeLoreMenu() { loreMenuOpen = false; loreButton.setText('LORE'); if (loreMenu) { game.removeChild(loreMenu); loreMenu = null; } } function openTutorialMenu() { tutorialMenuOpen = true; tutorialButton.setText('CLOSE'); tutorialMenu = new Container(); tutorialMenu.x = 0; tutorialMenu.y = 0; game.addChild(tutorialMenu); var menuBg = LK.getAsset('sam', { anchorX: 0.5, anchorY: 0.5, scaleX: 15, scaleY: 20 }); menuBg.x = 1024; menuBg.y = 1366; menuBg.alpha = 0.95; menuBg.tint = 0x330066; tutorialMenu.addChild(menuBg); var titleText = new Text2('VIGGEN PILOT TRAINING', { size: 70, fill: 0xFF4499 }); titleText.anchor.set(0.5, 0.5); titleText.x = 1024; titleText.y = 700; tutorialMenu.addChild(titleText); var stepText = new Text2('Step ' + (currentTutorialStep + 1) + ' of 5', { size: 35, fill: 0xFFFF88 }); stepText.anchor.set(0.5, 0.5); stepText.x = 1024; stepText.y = 780; tutorialMenu.addChild(stepText); // Navigation buttons var prevBtn = new Text2('< PREVIOUS', { size: 35, fill: currentTutorialStep > 0 ? 0x88CCFF : 0x666666 }); prevBtn.anchor.set(0.5, 0.5); prevBtn.x = 700; prevBtn.y = 2000; prevBtn.interactive = currentTutorialStep > 0; tutorialMenu.addChild(prevBtn); var nextBtn = new Text2('NEXT >', { size: 35, fill: currentTutorialStep < 4 ? 0x88CCFF : 0x666666 }); nextBtn.anchor.set(0.5, 0.5); nextBtn.x = 1348; nextBtn.y = 2000; nextBtn.interactive = currentTutorialStep < 4; tutorialMenu.addChild(nextBtn); // Event handlers for navigation if (currentTutorialStep > 0) { prevBtn.down = function () { currentTutorialStep--; closeTutorialMenu(); openTutorialMenu(); }; } if (currentTutorialStep < 4) { nextBtn.down = function () { currentTutorialStep++; closeTutorialMenu(); openTutorialMenu(); }; } // Display current tutorial step content displayTutorialStep(currentTutorialStep); } function displayTutorialStep(step) { var tutorialSteps = [{ title: 'BASIC CONTROLS', content: ['Welcome to the JAS 39 Viggen Fighter!', '', 'MOVEMENT:', '• Touch and drag anywhere to move your fighter', '• Keep your finger on screen to maintain control', '• Your fighter follows your finger position', '', 'COMBAT:', '• Your fighter automatically shoots forward', '• No need to tap - just focus on movement!', '• Destroy enemies by flying bullets into them', '', 'OBJECTIVE:', '• Survive as long as possible', '• Shoot down enemy aircraft and ground units', '• Score increases with time and kills'] }, { title: 'ENEMY THREATS', content: ['Learn to identify enemy aircraft:', '', 'INTERCEPTORS (Flying down):', '• MiG-23 Flogger - Standard fighter', '• Su-15 Flagon - Fast with twin guns', '• Yak-38 Forger - Slow but unpredictable', '', 'GROUND THREATS:', '• SAM Sites - Launch tracking missiles', '• Shilka SPAA - Deadly burst fire', '• Drones - Weave side to side', '', 'WARNING:', '• All enemies shoot at your position', '• One hit destroys your fighter!', '• Keep moving to survive'] }, { title: 'POWER-UPS', content: ['Collect power-ups to gain advantages:', '', 'SPEED BOOST (Green):', '• Increases movement speed temporarily', '• Great for dodging enemy clusters', '• Lasts 5 seconds', '', 'SHIELD (Blue):', '• Protects from all damage', '• Save for emergency situations', '• Duration can be upgraded', '', 'RAPID FIRE (Orange):', '• Triples your fire rate', '• Perfect for clearing enemy waves', '• Lasts 7.5 seconds', '', 'TIP: Fly into power-ups to collect them!'] }, { title: 'UPGRADE SYSTEM', content: ['Spend points to upgrade your fighter:', '', 'FIRE RATE (Essential):', '• Shoots bullets faster', '• Cheaper early upgrades', '• Upgrade first for survival', '', 'BULLET SPEED:', '• Bullets travel faster', '• Easier to hit moving enemies', '• Great against interceptors', '', 'BULLET DAMAGE:', '• More points per kill', '• Best long-term investment', '• Expensive but worth it', '', 'SHIELD DURATION:', '• Power-up shields last longer', '• Crucial for harder regions'] }, { title: 'SURVIVAL TIPS', content: ['Master these tactics to survive:', '', 'MOVEMENT PATTERNS:', '• Never stop moving - constant motion', '• Use circular patterns vs SAM missiles', '• Stay near screen edges for quick escapes', '', 'TARGET PRIORITY:', '1. SAM Sites (most dangerous)', '2. Su-15 Interceptors (fast & deadly)', '3. Shilkas during reload breaks', '4. Other enemies', '', 'ADVANCED TACTICS:', '• Lead your shots ahead of moving targets', '• Use screen edges to limit enemy angles', '• Collect power-ups before tough waves', '', 'Good luck, pilot! Sweden is counting on you!'] }]; var stepData = tutorialSteps[step]; var yPos = 850; // Step title var stepTitleText = new Text2(stepData.title, { size: 50, fill: 0xFFFF00 }); stepTitleText.anchor.set(0.5, 0.5); stepTitleText.x = 1024; stepTitleText.y = yPos; tutorialMenu.addChild(stepTitleText); yPos += 80; // Step content for (var i = 0; i < stepData.content.length; i++) { var line = stepData.content[i]; var isHeader = line.includes(':') && !line.includes('•'); var isBullet = line.includes('•'); var isEmpty = line.trim() === ''; var textSize = isEmpty ? 15 : isHeader ? 32 : isBullet ? 26 : 28; var textColor = isEmpty ? 0x000000 : isHeader ? 0x88FF88 : isBullet ? 0xFFFFFF : 0xCCCCCC; var contentText = new Text2(line, { size: textSize, fill: textColor }); contentText.anchor.set(0.5, 0.5); contentText.x = 1024; contentText.y = yPos; tutorialMenu.addChild(contentText); yPos += isEmpty ? 20 : isHeader ? 45 : 35; } } function closeTutorialMenu() { tutorialMenuOpen = false; tutorialButton.setText('TUTORIAL'); if (tutorialMenu) { game.removeChild(tutorialMenu); tutorialMenu = null; } } function openDevMenu() { devModeOpen = true; devButton.setText('CLOSE'); devMenu = new Container(); devMenu.x = 0; devMenu.y = 0; game.addChild(devMenu); var menuBg = LK.getAsset('sam', { anchorX: 0.5, anchorY: 0.5, scaleX: 15, scaleY: 20 }); menuBg.x = 1024; menuBg.y = 1366; menuBg.alpha = 0.95; menuBg.tint = 0x660000; devMenu.addChild(menuBg); var titleText = new Text2('DEV MODE', { size: 80, fill: 0xFF0000 }); titleText.anchor.set(0.5, 0.5); titleText.x = 1024; titleText.y = 700; devMenu.addChild(titleText); var statusText = new Text2('Status: ' + (devModeEnabled ? 'ENABLED' : 'DISABLED'), { size: 40, fill: devModeEnabled ? 0x00FF00 : 0xFF6666 }); statusText.anchor.set(0.5, 0.5); statusText.x = 1024; statusText.y = 800; devMenu.addChild(statusText); // Toggle dev mode button var toggleBtn = new Text2(devModeEnabled ? 'DISABLE DEV MODE' : 'ENABLE DEV MODE', { size: 35, fill: 0xFFFF00 }); toggleBtn.anchor.set(0.5, 0.5); toggleBtn.x = 1024; toggleBtn.y = 900; toggleBtn.interactive = true; devMenu.addChild(toggleBtn); toggleBtn.down = function () { devModeEnabled = !devModeEnabled; storage.devModeEnabled = devModeEnabled; closeDevMenu(); openDevMenu(); }; if (devModeEnabled) { // Add 10000 points button var pointsBtn = new Text2('ADD 10000 POINTS', { size: 35, fill: 0x00FF00 }); pointsBtn.anchor.set(0.5, 0.5); pointsBtn.x = 1024; pointsBtn.y = 1000; pointsBtn.interactive = true; devMenu.addChild(pointsBtn); pointsBtn.down = function () { LK.setScore(LK.getScore() + 10000); scoreTxt.setText('Score: ' + LK.getScore()); LK.effects.flashScreen(0x00FF00, 300); }; // Spawn enemy buttons var spawnMig23Btn = new Text2('SPAWN MIG-23', { size: 30, fill: 0xFFAAAA }); spawnMig23Btn.anchor.set(0.5, 0.5); spawnMig23Btn.x = 700; spawnMig23Btn.y = 1100; spawnMig23Btn.interactive = true; devMenu.addChild(spawnMig23Btn); spawnMig23Btn.down = function () { var interceptor = new MiG23(); interceptor.x = Math.random() * 1848 + 100; interceptor.y = -100; game.addChild(interceptor); mig23s.push(interceptor); interceptors.push(interceptor); markEnemyEncountered('mig23'); }; var spawnSu15Btn = new Text2('SPAWN SU-15', { size: 30, fill: 0xAAAAFF }); spawnSu15Btn.anchor.set(0.5, 0.5); spawnSu15Btn.x = 1024; spawnSu15Btn.y = 1100; spawnSu15Btn.interactive = true; devMenu.addChild(spawnSu15Btn); spawnSu15Btn.down = function () { var interceptor = new Su15(); interceptor.x = Math.random() * 1848 + 100; interceptor.y = -100; game.addChild(interceptor); su15s.push(interceptor); interceptors.push(interceptor); markEnemyEncountered('su15'); }; var spawnYak38Btn = new Text2('SPAWN YAK-38', { size: 30, fill: 0xFFFFAA }); spawnYak38Btn.anchor.set(0.5, 0.5); spawnYak38Btn.x = 1348; spawnYak38Btn.y = 1100; spawnYak38Btn.interactive = true; devMenu.addChild(spawnYak38Btn); spawnYak38Btn.down = function () { var interceptor = new Yak38(); interceptor.x = Math.random() * 1848 + 100; interceptor.y = -100; game.addChild(interceptor); yak38s.push(interceptor); interceptors.push(interceptor); markEnemyEncountered('yak38'); }; var spawnDroneBtn = new Text2('SPAWN DRONE', { size: 30, fill: 0xAAFFAA }); spawnDroneBtn.anchor.set(0.5, 0.5); spawnDroneBtn.x = 700; spawnDroneBtn.y = 1200; spawnDroneBtn.interactive = true; devMenu.addChild(spawnDroneBtn); spawnDroneBtn.down = function () { spawnDrone(); }; var spawnSAMBtn = new Text2('SPAWN SAM', { size: 30, fill: 0xFFAAFF }); spawnSAMBtn.anchor.set(0.5, 0.5); spawnSAMBtn.x = 1024; spawnSAMBtn.y = 1200; spawnSAMBtn.interactive = true; devMenu.addChild(spawnSAMBtn); spawnSAMBtn.down = function () { spawnSAMSite(); }; var spawnShilkaBtn = new Text2('SPAWN SHILKA', { size: 30, fill: 0xAAAA00 }); spawnShilkaBtn.anchor.set(0.5, 0.5); spawnShilkaBtn.x = 1348; spawnShilkaBtn.y = 1200; spawnShilkaBtn.interactive = true; devMenu.addChild(spawnShilkaBtn); spawnShilkaBtn.down = function () { spawnShilka(); }; // Powerup spawn buttons var spawnSpeedBtn = new Text2('SPAWN SPEED', { size: 30, fill: 0x00FF00 }); spawnSpeedBtn.anchor.set(0.5, 0.5); spawnSpeedBtn.x = 700; spawnSpeedBtn.y = 1300; spawnSpeedBtn.interactive = true; devMenu.addChild(spawnSpeedBtn); spawnSpeedBtn.down = function () { var powerup = new Powerup(); powerup.x = viggen.x; powerup.y = viggen.y - 100; powerup.setPowerupType('speed'); game.addChild(powerup); powerups.push(powerup); }; var spawnShieldBtn = new Text2('SPAWN SHIELD', { size: 30, fill: 0x0000FF }); spawnShieldBtn.anchor.set(0.5, 0.5); spawnShieldBtn.x = 1024; spawnShieldBtn.y = 1300; spawnShieldBtn.interactive = true; devMenu.addChild(spawnShieldBtn); spawnShieldBtn.down = function () { var powerup = new Powerup(); powerup.x = viggen.x; powerup.y = viggen.y - 100; powerup.setPowerupType('shield'); game.addChild(powerup); powerups.push(powerup); }; var spawnRapidBtn = new Text2('SPAWN RAPID', { size: 30, fill: 0xFF8800 }); spawnRapidBtn.anchor.set(0.5, 0.5); spawnRapidBtn.x = 1348; spawnRapidBtn.y = 1300; spawnRapidBtn.interactive = true; devMenu.addChild(spawnRapidBtn); spawnRapidBtn.down = function () { var powerup = new Powerup(); powerup.x = viggen.x; powerup.y = viggen.y - 100; powerup.setPowerupType('rapidfire'); game.addChild(powerup); powerups.push(powerup); }; // Clear all enemies button var clearBtn = new Text2('CLEAR ALL ENEMIES', { size: 30, fill: 0xFF0000 }); clearBtn.anchor.set(0.5, 0.5); clearBtn.x = 1024; clearBtn.y = 1400; clearBtn.interactive = true; devMenu.addChild(clearBtn); clearBtn.down = function () { // Clear all enemy arrays and destroy objects for (var i = interceptors.length - 1; i >= 0; i--) { interceptors[i].destroy(); } interceptors = []; mig23s = []; su15s = []; yak38s = []; for (var i = drones.length - 1; i >= 0; i--) { drones[i].destroy(); } drones = []; for (var i = shilkas.length - 1; i >= 0; i--) { shilkas[i].destroy(); } shilkas = []; for (var i = samSites.length - 1; i >= 0; i--) { samSites[i].destroy(); } samSites = []; for (var i = enemyBullets.length - 1; i >= 0; i--) { enemyBullets[i].destroy(); } enemyBullets = []; for (var i = samMissiles.length - 1; i >= 0; i--) { samMissiles[i].destroy(); } samMissiles = []; LK.effects.flashScreen(0xFF0000, 500); }; } } function openArmamentMenu() { armamentMenuOpen = true; armamentButton.setText('CLOSE'); armamentMenu = new Container(); armamentMenu.x = 0; armamentMenu.y = 0; game.addChild(armamentMenu); var menuBg = LK.getAsset('sam', { anchorX: 0.5, anchorY: 0.5, scaleX: 15, scaleY: 20 }); menuBg.x = 1024; menuBg.y = 1366; menuBg.alpha = 0.9; menuBg.tint = 0x003366; armamentMenu.addChild(menuBg); var titleText = new Text2('VIGGEN ARMAMENT', { size: 70, fill: 0xFFFFFF }); titleText.anchor.set(0.5, 0.5); titleText.x = 1024; titleText.y = 800; armamentMenu.addChild(titleText); var currentText = new Text2('Current: ' + armamentData[currentWeapon].name, { size: 40, fill: 0x00FFFF }); currentText.anchor.set(0.5, 0.5); currentText.x = 1024; currentText.y = 900; armamentMenu.addChild(currentText); var yPos = 1100; for (var weaponKey in armamentData) { createArmamentOption(weaponKey, armamentData[weaponKey], yPos); yPos += 120; } // Check for unlocks checkArmamentUnlocks(); } function createArmamentOption(weaponKey, data, yPos) { var isUnlocked = data.unlocked || storage['weapon' + weaponKey] === true; var isCurrent = currentWeapon === weaponKey; var statusText = isCurrent ? ' (EQUIPPED)' : isUnlocked ? ' - AVAILABLE' : ' - LOCKED (' + data.unlockScore + ' pts)'; var optionText = new Text2(data.name + statusText, { size: 35, fill: isCurrent ? 0xFFFF00 : isUnlocked ? 0x00ff00 : 0xff6666 }); optionText.anchor.set(0.5, 0.5); optionText.x = 1024; optionText.y = yPos; optionText.interactive = true; armamentMenu.addChild(optionText); var descText = new Text2(data.description, { size: 25, fill: 0xCCCCCC }); descText.anchor.set(0.5, 0.5); descText.x = 1024; descText.y = yPos + 30; armamentMenu.addChild(descText); var statsText = new Text2('Fire Rate: ' + data.fireRate + ' | Speed: ' + data.bulletSpeed + ' | Damage: ' + data.damage, { size: 23, fill: 0x88FFAA }); statsText.anchor.set(0.5, 0.5); statsText.x = 1024; statsText.y = yPos + 60; armamentMenu.addChild(statsText); if (isUnlocked && !isCurrent) { optionText.down = function () { equipWeapon(weaponKey); }; } } function equipWeapon(weaponKey) { currentWeapon = weaponKey; storage.currentWeapon = weaponKey; LK.getSound('powerup').play(); LK.effects.flashScreen(0x00FFFF, 300); closeArmamentMenu(); } function checkArmamentUnlocks() { var currentScore = LK.getScore(); for (var weaponKey in armamentData) { var weapon = armamentData[weaponKey]; if (!weapon.unlocked && !storage['weapon' + weaponKey] && currentScore >= weapon.unlockScore) { weapon.unlocked = true; storage['weapon' + weaponKey] = true; LK.effects.flashScreen(0x00ff00, 500); var unlockText = new Text2('WEAPON UNLOCKED: ' + weapon.name, { size: 50, fill: 0x00FF00 }); unlockText.anchor.set(0.5, 0.5); unlockText.x = 1024; unlockText.y = 1366; game.addChild(unlockText); LK.setTimeout(function () { if (unlockText.parent) { game.removeChild(unlockText); } }, 3000); } } } function closeArmamentMenu() { armamentMenuOpen = false; armamentButton.setText('ARMAMENT'); if (armamentMenu) { game.removeChild(armamentMenu); armamentMenu = null; } } function closeDevMenu() { devModeOpen = false; devButton.setText('DEV'); if (devMenu) { game.removeChild(devMenu); devMenu = null; } } function summonSwedishAllies() { allyActive = true; allyTimer = allyDuration; allyCooldownTimer = allyCooldown; var allyTypeName = allyTypes[currentAllyType]; // Update button text to show cooldown allyButton.setText('ALLIES (15s)'); allyButton.fill = 0xffff00; // Screen flash effect LK.effects.flashScreen(0x00ff88, 500); // Show ally arrival message var allyText = new Text2('SWEDISH ' + allyTypeName + ' INCOMING!', { size: 60, fill: 0x00FF88 }); allyText.anchor.set(0.5, 0.5); allyText.x = 1024; allyText.y = 300; game.addChild(allyText); // Spawn different ally types based on currentAllyType if (currentAllyType === 0) { // Viggen Squadron (3 units) for (var i = 0; i < 3; i++) { var ally = new AllyViggen(); ally.x = viggen.x + (i - 1) * 100; ally.y = viggen.y + 400; ally.formationOffset = i * (Math.PI * 2 / 3); game.addChild(ally); allyViggens.push(ally); allAllyUnits.push(ally); tween(ally, { y: viggen.y - 200 }, { duration: 1000, easing: tween.easeOut }); } } else if (currentAllyType === 1) { // Draken Pair (2 units) for (var i = 0; i < 2; i++) { var ally = new AllyDraken(); ally.x = viggen.x + (i === 0 ? -120 : 120); ally.y = viggen.y + 500; ally.formationOffset = i * Math.PI; game.addChild(ally); allAllyUnits.push(ally); tween(ally, { y: viggen.y - 250 }, { duration: 1200, easing: tween.easeOut }); } } else if (currentAllyType === 2) { // Bandkanon Artillery (1 unit) var ally = new AllyBandkanon(); game.addChild(ally); allAllyUnits.push(ally); // Bandkanon appears at bottom with flash effect tween(ally, { alpha: 0.5 }, { duration: 300, onFinish: function onFinish() { tween(ally, { alpha: 1.0 }, { duration: 300 }); } }); } else if (currentAllyType === 3) { // Strv 103 Tank (1 unit) var ally = new AllyStrv103(); game.addChild(ally); allAllyUnits.push(ally); // Tank rumbles onto screen tween(ally, { x: ally.x + 50 }, { duration: 800, easing: tween.easeInOut, onFinish: function onFinish() { tween(ally, { x: ally.x - 50 }, { duration: 800, easing: tween.easeInOut }); } }); } else if (currentAllyType === 4) { // Naval Barrage (special effect) var barrage = new NavalBarrage(); game.addChild(barrage); allAllyUnits.push(barrage); // Extended duration for naval barrage allyTimer = 900; // 15 seconds of bombardment } // Animate message with tween tween(allyText, { scaleX: 1.2, scaleY: 1.2 }, { duration: 500, easing: tween.easeOut }); tween(allyText, { alpha: 0 }, { duration: 1000, onFinish: function onFinish() { if (allyText.parent) { game.removeChild(allyText); } } }); // Don't advance ally type - player selects from menu LK.getSound('powerup').play(); } function checkCollisions() { if (shieldActive) { // Shield protects from all damage return; } for (var i = 0; i < enemyBullets.length; i++) { if (viggen.intersects(enemyBullets[i])) { LK.effects.flashScreen(0xff0000, 1000); LK.getSound('explosion').play(); LK.showGameOver(); return; } } for (var i = 0; i < samMissiles.length; i++) { if (viggen.intersects(samMissiles[i])) { LK.effects.flashScreen(0xff0000, 1000); LK.getSound('explosion').play(); LK.showGameOver(); return; } } for (var i = 0; i < interceptors.length; i++) { if (viggen.intersects(interceptors[i])) { LK.effects.flashScreen(0xff0000, 1000); LK.getSound('explosion').play(); LK.showGameOver(); return; } } for (var i = 0; i < drones.length; i++) { if (viggen.intersects(drones[i])) { LK.effects.flashScreen(0xff0000, 1000); LK.getSound('explosion').play(); LK.showGameOver(); return; } } for (var i = 0; i < shilkas.length; i++) { if (viggen.intersects(shilkas[i])) { LK.effects.flashScreen(0xff0000, 1000); LK.getSound('explosion').play(); LK.showGameOver(); return; } } } function cleanupOffscreenEntities() { // Clean up interceptors with optimized type array removal for (var i = interceptors.length - 1; i >= 0; i--) { if (interceptors[i].y > 2800) { var interceptor = interceptors[i]; var interceptorType = interceptor.interceptorType; // Remove from specific type array using indexOf (faster than nested loop) var typeArray = interceptorType === 'mig23' ? mig23s : interceptorType === 'su15' ? su15s : yak38s; var typeIndex = typeArray.indexOf(interceptor); if (typeIndex !== -1) typeArray.splice(typeIndex, 1); interceptor.destroy(); interceptors.splice(i, 1); } } // Batch cleanup for simple entities var entitiesToClean = [{ array: drones, limit: 2800, yCheck: true }, { array: shilkas, limit: 2800, yCheck: true }, { array: samSites, limit: 2800, yCheck: true, xCheck: true }, { array: viggenBullets, limit: -50, yCheck: true, reverse: true }, { array: powerups, limit: 2800, yCheck: true }]; for (var e = 0; e < entitiesToClean.length; e++) { var entityGroup = entitiesToClean[e]; for (var i = entityGroup.array.length - 1; i >= 0; i--) { var entity = entityGroup.array[i]; var shouldRemove = false; if (entityGroup.yCheck) { shouldRemove = entityGroup.reverse ? entity.y < entityGroup.limit : entity.y > entityGroup.limit; } if (!shouldRemove && entityGroup.xCheck) { shouldRemove = entity.x < -100 || entity.x > 2148; } if (shouldRemove) { entity.destroy(); entityGroup.array.splice(i, 1); } } } // Special cleanup for bullets with bounds checking for (var i = enemyBullets.length - 1; i >= 0; i--) { var bullet = enemyBullets[i]; if (bullet.x < -20 || bullet.x > 2068 || bullet.y < -20 || bullet.y > 2752 || bullet.age && bullet.age > 300) { bullet.destroy(); enemyBullets.splice(i, 1); } } // Special cleanup for missiles for (var i = samMissiles.length - 1; i >= 0; i--) { var missile = samMissiles[i]; if (missile.x < -50 || missile.x > 2098 || missile.y < -50 || missile.y > 2782) { missile.destroy(); samMissiles.splice(i, 1); } } } game.update = function () { survivalTime++; difficultyTimer++; spawnTimer++; // Update UI less frequently for better performance if (LK.ticks % 60 === 0) { var timeInSeconds = Math.floor(survivalTime / 60); timeTxt.setText('Time: ' + timeInSeconds + 's'); var score = timeInSeconds * 10 + Math.floor(survivalTime / 6); LK.setScore(score); scoreTxt.setText('Score: ' + score); } if (difficultyTimer >= 300) { difficultyTimer = 0; currentSpawnRate = Math.max(60, currentSpawnRate - 10); } // Optimized spawning system var ssrSpawnRate = currentSSR ? Math.floor(currentSpawnRate / currentSSR.spawnRateMultiplier) : currentSpawnRate; if (spawnTimer >= ssrSpawnRate) { // Helper function to create interceptor var createInterceptor = function createInterceptor(InterceptorClass, typeArray, encounterType) { var interceptor = new InterceptorClass(); typeArray.push(interceptor); markEnemyEncountered(encounterType); interceptor.x = randomX; interceptor.y = -100; game.addChild(interceptor); interceptors.push(interceptor); return interceptor; }; // SSR-specific enemy spawning patterns (optimized) spawnTimer = 0; var spawnType = Math.random(); var randomX = Math.random() * 1848 + 100; var ssrName = currentSSR ? currentSSR.name : ''; switch (ssrName) { case 'Ukrainian SSR': // Ukraine: MiG-23, Yak-38 and Drones if (spawnType < 0.4) { createInterceptor(MiG23, mig23s, 'mig23'); } else if (spawnType < 0.7) { createInterceptor(Yak38, yak38s, 'yak38'); } else { spawnDrone(); } break; case 'Russian SFSR': // Russia: MiG-23, Su-15, SAMs if (spawnType < 0.4) { createInterceptor(MiG23, mig23s, 'mig23'); } else if (spawnType < 0.7) { createInterceptor(Su15, su15s, 'su15'); } else { spawnSAMSite(); } break; case 'Kazakh SSR': // Kazakhstan: Yak-38 (swarms), drones and Shilkas if (spawnType < 0.5) { createInterceptor(Yak38, yak38s, 'yak38'); } else if (spawnType < 0.75) { spawnDrone(); } else { spawnShilka(); } break; case 'Byelorussian SSR': // Belarus: SAMs, Su-15s, Shilkas and MiG-23s if (spawnType < 0.3) { spawnSAMSite(); } else if (spawnType < 0.55) { createInterceptor(Su15, su15s, 'su15'); } else if (spawnType < 0.8) { spawnShilka(); } else { createInterceptor(MiG23, mig23s, 'mig23'); } break; default: // Default spawning (fallback) if (spawnType < 0.35) { spawnInterceptor(); } else if (spawnType < 0.7) { spawnDrone(); } else if (spawnType < 0.9) { spawnSAMSite(); } else { spawnShilka(); } } } // Check for SSR unlocks less frequently if (LK.ticks % 30 === 0) { checkSSRUnlocks(); checkArmamentUnlocks(); } // Spawn powerups occasionally powerupSpawnTimer++; if (powerupSpawnTimer >= 900) { // Every 15 seconds powerupSpawnTimer = 0; spawnPowerup(); } // Update powerup effects if (speedBoostTimer > 0) { speedBoostTimer--; if (speedBoostTimer === 0) { speedBoostActive = false; } } if (shieldTimer > 0) { shieldTimer--; if (shieldTimer === 0) { shieldActive = false; if (shieldEffect) { viggen.removeChild(shieldEffect); shieldEffect = null; } } } if (rapidFireTimer > 0) { rapidFireTimer--; if (rapidFireTimer === 0) { rapidFireActive = false; } } // Fire viggen bullets fireTimer++; var weaponStats = armamentData[currentWeapon] || armamentData.viggen; var baseFireRate = weaponStats.fireRate; var upgradeFireRate = Math.max(5, baseFireRate - (upgrades.fireRate - 1) * 2); var currentFireRate = rapidFireActive ? Math.floor(upgradeFireRate / 3) : upgradeFireRate; if (fireTimer >= currentFireRate) { fireTimer = 0; var bullet = new ViggenBullet(); bullet.speed = weaponStats.bulletSpeed + (upgrades.bulletSpeed - 1) * 2; bullet.damage = weaponStats.damage * upgrades.bulletDamage; bullet.x = viggen.x; bullet.y = viggen.y - 60; game.addChild(bullet); viggenBullets.push(bullet); LK.getSound('shoot').play(); } checkCollisions(); cleanupOffscreenEntities(); if (enemyBullets.length > 200) { for (var i = 0; i < 50; i++) { if (enemyBullets[i]) { enemyBullets[i].destroy(); enemyBullets.splice(i, 1); } } } if (samMissiles.length > 100) { for (var i = 0; i < 25; i++) { if (samMissiles[i]) { samMissiles[i].destroy(); samMissiles.splice(i, 1); } } } // Handle ally system if (allyActive) { allyTimer--; if (allyTimer <= 0) { // Terminate all ally units to stop their actions immediately for (var i = 0; i < allAllyUnits.length; i++) { var ally = allAllyUnits[i]; if (ally.terminated !== undefined) { ally.terminated = true; } } // Dismiss allies with tween effect for (var i = allyViggens.length - 1; i >= 0; i--) { var ally = allyViggens[i]; tween(ally, { y: ally.y - 300, alpha: 0 }, { duration: 800, easing: tween.easeIn, onFinish: function onFinish() { if (ally.parent) { ally.destroy(); } } }); } // Clean up all ally units for (var i = allAllyUnits.length - 1; i >= 0; i--) { var ally = allAllyUnits[i]; if (ally.parent) { tween(ally, { alpha: 0 }, { duration: 600, onFinish: function onFinish() { if (ally.parent) { ally.destroy(); } } }); } } allyViggens = []; allAllyUnits = []; allyActive = false; } } // Handle ally cooldown if (allyCooldownTimer > 0) { allyCooldownTimer--; var secondsLeft = Math.ceil(allyCooldownTimer / 60); if (secondsLeft > 0) { allyButton.setText('ALLIES (' + secondsLeft + 's)'); allyButton.fill = 0x666666; } else { allyButton.setText('ALLIES: ' + allyTypes[currentAllyType]); allyButton.fill = 0x00ff88; } } // Clean up ally units that go off screen for (var i = allyViggens.length - 1; i >= 0; i--) { var ally = allyViggens[i]; if (ally.y < -100 || ally.y > 2800 || ally.x < -100 || ally.x > 2148) { ally.destroy(); allyViggens.splice(i, 1); } } // Clean up all ally units that go off screen for (var i = allAllyUnits.length - 1; i >= 0; i--) { var ally = allAllyUnits[i]; if (ally.x < -200 || ally.x > 2248 || ally.y < -200 || ally.y > 2932) { ally.destroy(); allAllyUnits.splice(i, 1); } } // Handle secret code input timeout if (!devModeEnabled && currentCodeInput.length > 0) { codeInputTimer++; if (codeInputTimer >= maxCodeInputTime) { currentCodeInput = []; // Reset if too much time passes codeInputTimer = 0; } } }; LK.playMusic('combat'); function openAllyMenu() { allyMenuOpen = true; allyButton.setText('CLOSE'); allyMenu = new Container(); allyMenu.x = 0; allyMenu.y = 0; game.addChild(allyMenu); var menuBg = LK.getAsset('sam', { anchorX: 0.5, anchorY: 0.5, scaleX: 15, scaleY: 20 }); menuBg.x = 1024; menuBg.y = 1366; menuBg.alpha = 0.9; menuBg.tint = 0x004400; allyMenu.addChild(menuBg); var titleText = new Text2('SWEDISH ARMED FORCES', { size: 70, fill: 0xFFFFFF }); titleText.anchor.set(0.5, 0.5); titleText.x = 1024; titleText.y = 800; allyMenu.addChild(titleText); var instructionText = new Text2('Select Allied Unit to Deploy', { size: 40, fill: 0x88FF88 }); instructionText.anchor.set(0.5, 0.5); instructionText.x = 1024; instructionText.y = 880; allyMenu.addChild(instructionText); // Create ally type options var allyOptions = [{ name: 'Viggen Squadron', description: '3x JAS 39 Viggen fighters in formation\nBalanced attack and defense', type: 0, duration: '15 seconds' }, { name: 'Draken Wing', description: '2x J35 Draken interceptors with twin cannons\nFast and aggressive air superiority', type: 1, duration: '15 seconds' }, { name: 'Bandkanon Artillery', description: '155mm self-propelled artillery support\nHigh damage bombardment from rear', type: 2, duration: '15 seconds' }, { name: 'Strv 103 Tank', description: 'S-tank with 105mm cannon\nGround-based precision fire support', type: 3, duration: '15 seconds' }, { name: 'Naval Barrage', description: 'Offshore destroyer fire mission\nArea bombardment with explosive shells', type: 4, duration: '15 seconds' }]; var yPos = 1000; for (var i = 0; i < allyOptions.length; i++) { createAllyOption(allyOptions[i], yPos); yPos += 160; } } function createAllyOption(option, yPos) { var optionText = new Text2(option.name, { size: 42, fill: 0x00FF88 }); optionText.anchor.set(0.5, 0.5); optionText.x = 1024; optionText.y = yPos; optionText.interactive = true; allyMenu.addChild(optionText); var descText = new Text2(option.description, { size: 28, fill: 0xCCCCCC }); descText.anchor.set(0.5, 0.5); descText.x = 1024; descText.y = yPos + 35; allyMenu.addChild(descText); var durationText = new Text2('Duration: ' + option.duration, { size: 25, fill: 0xFFFF88 }); durationText.anchor.set(0.5, 0.5); durationText.x = 1024; durationText.y = yPos + 75; allyMenu.addChild(durationText); // Add tween hover effect optionText.down = function () { currentAllyType = option.type; // Flash selection effect tween(optionText, { scaleX: 1.1, scaleY: 1.1 }, { duration: 150, onFinish: function onFinish() { tween(optionText, { scaleX: 1.0, scaleY: 1.0 }, { duration: 150 }); } }); closeAllyMenu(); summonSwedishAllies(); }; // Add hover effect var originalScale = 1.0; optionText.move = function () { if (!optionText.isHover) { optionText.isHover = true; tween(optionText, { scaleX: 1.05, scaleY: 1.05 }, { duration: 200, easing: tween.easeOut }); } }; } function closeAllyMenu() { allyMenuOpen = false; allyButton.setText('ALLIES: ' + allyTypes[currentAllyType]); if (allyMenu) { game.removeChild(allyMenu); allyMenu = null; } } function openCommissaryMenu() { commissaryMenuOpen = true; commissaryButton.setText('CLOSE'); commissaryMenu = new Container(); commissaryMenu.x = 0; commissaryMenu.y = 0; game.addChild(commissaryMenu); var menuBg = LK.getAsset('sam', { anchorX: 0.5, anchorY: 0.5, scaleX: 15, scaleY: 20 }); menuBg.x = 1024; menuBg.y = 1366; menuBg.alpha = 0.95; menuBg.tint = 0x004466; commissaryMenu.addChild(menuBg); var titleText = new Text2('AIRPORT COMMISSARY', { size: 70, fill: 0x44AAFF }); titleText.anchor.set(0.5, 0.5); titleText.x = 1024; titleText.y = 700; commissaryMenu.addChild(titleText); var pointsText = new Text2('Available Points: ' + LK.getScore(), { size: 45, fill: 0xFFFF00 }); pointsText.anchor.set(0.5, 0.5); pointsText.x = 1024; pointsText.y = 780; commissaryMenu.addChild(pointsText); // Section buttons var boostsBtn = new Text2('[BOOSTS]', { size: 35, fill: currentCommissarySection === 'boosts' ? 0xFFFF00 : 0x88CCFF }); boostsBtn.anchor.set(0.5, 0.5); boostsBtn.x = 800; boostsBtn.y = 850; boostsBtn.interactive = true; commissaryMenu.addChild(boostsBtn); var cosmeticsBtn = new Text2('[COSMETICS]', { size: 35, fill: currentCommissarySection === 'cosmetics' ? 0xFFFF00 : 0x88CCFF }); cosmeticsBtn.anchor.set(0.5, 0.5); cosmeticsBtn.x = 1248; cosmeticsBtn.y = 850; cosmeticsBtn.interactive = true; commissaryMenu.addChild(cosmeticsBtn); // Section button handlers boostsBtn.down = function () { currentCommissarySection = 'boosts'; closeCommissaryMenu(); openCommissaryMenu(); }; cosmeticsBtn.down = function () { currentCommissarySection = 'cosmetics'; closeCommissaryMenu(); openCommissaryMenu(); }; // Display content based on section if (currentCommissarySection === 'boosts') { displayBoostShop(); } else if (currentCommissarySection === 'cosmetics') { displayCosmeticShop(); } } function displayBoostShop() { var boostItems = [{ name: '2x Score Multiplier', description: 'Double all score gains permanently', cost: 25000, owned: commissaryInventory.scoreMultiplier >= 2, itemKey: 'scoreMultiplier' }, { name: 'Bonus Life', description: 'Start each game with an extra life', cost: 50000, owned: commissaryInventory.bonusLives > 0, itemKey: 'bonusLives' }, { name: 'Starting Shield', description: 'Begin each game with shield active', cost: 30000, owned: commissaryInventory.startingShield, itemKey: 'startingShield' }, { name: 'Double Fire Rate Boost', description: 'Fire rate power-ups are twice as effective', cost: 40000, owned: commissaryInventory.doubleFireRate, itemKey: 'doubleFireRate' }]; var yPos = 950; for (var i = 0; i < boostItems.length; i++) { createCommissaryItem(boostItems[i], yPos); yPos += 180; } } function displayCosmeticShop() { var cosmeticItems = [{ name: 'Elite Viggen Skin', description: 'Premium Swedish Air Force livery', cost: 15000, owned: commissaryInventory.viggenSkin === 'elite', itemKey: 'viggenSkin', itemValue: 'elite' }, { name: 'Stealth Viggen Skin', description: 'Dark tactical camouflage pattern', cost: 20000, owned: commissaryInventory.viggenSkin === 'stealth', itemKey: 'viggenSkin', itemValue: 'stealth' }, { name: 'Golden Bullet Trails', description: 'Luxurious gold-tinted projectiles', cost: 12000, owned: commissaryInventory.bulletTrail === 'gold', itemKey: 'bulletTrail', itemValue: 'gold' }, { name: 'Lightning Bullet Trails', description: 'Electric blue energy projectiles', cost: 18000, owned: commissaryInventory.bulletTrail === 'lightning', itemKey: 'bulletTrail', itemValue: 'lightning' }]; var yPos = 950; for (var i = 0; i < cosmeticItems.length; i++) { createCommissaryItem(cosmeticItems[i], yPos); yPos += 180; } } function createCommissaryItem(item, yPos) { var canAfford = LK.getScore() >= item.cost; var statusText = item.owned ? ' (OWNED)' : ' - ' + item.cost + ' pts'; var itemText = new Text2(item.name + statusText, { size: 38, fill: item.owned ? 0x00FF00 : canAfford ? 0x44AAFF : 0x666666 }); itemText.anchor.set(0.5, 0.5); itemText.x = 1024; itemText.y = yPos; itemText.interactive = !item.owned && canAfford; commissaryMenu.addChild(itemText); var descText = new Text2(item.description, { size: 26, fill: 0xCCCCCC }); descText.anchor.set(0.5, 0.5); descText.x = 1024; descText.y = yPos + 35; commissaryMenu.addChild(descText); if (!item.owned && canAfford) { itemText.down = function () { purchaseCommissaryItem(item); }; // Add purchase button animation tween(itemText, { scaleX: 1.05, scaleY: 1.05 }, { duration: 1000, easing: tween.easeInOut, onFinish: function onFinish() { tween(itemText, { scaleX: 1.0, scaleY: 1.0 }, { duration: 1000, easing: tween.easeInOut }); } }); } } function purchaseCommissaryItem(item) { if (LK.getScore() >= item.cost) { LK.setScore(LK.getScore() - item.cost); // Update inventory if (item.itemKey === 'scoreMultiplier') { commissaryInventory.scoreMultiplier = 2; storage.scoreMultiplier = 2; } else if (item.itemKey === 'bonusLives') { commissaryInventory.bonusLives = 1; storage.bonusLives = 1; } else if (item.itemKey === 'startingShield') { commissaryInventory.startingShield = true; storage.startingShield = true; } else if (item.itemKey === 'doubleFireRate') { commissaryInventory.doubleFireRate = true; storage.doubleFireRate = true; } else if (item.itemKey === 'viggenSkin') { commissaryInventory.viggenSkin = item.itemValue; storage.viggenSkin = item.itemValue; } else if (item.itemKey === 'bulletTrail') { commissaryInventory.bulletTrail = item.itemValue; storage.bulletTrail = item.itemValue; } // Purchase success effects LK.getSound('powerup').play(); LK.effects.flashScreen(0x00FF00, 500); var purchaseText = new Text2('PURCHASE COMPLETE!', { size: 50, fill: 0x00FF00 }); purchaseText.anchor.set(0.5, 0.5); purchaseText.x = 1024; purchaseText.y = 1366; game.addChild(purchaseText); tween(purchaseText, { scaleX: 1.2, scaleY: 1.2 }, { duration: 600, easing: tween.easeOut, onFinish: function onFinish() { tween(purchaseText, { alpha: 0 }, { duration: 800, onFinish: function onFinish() { if (purchaseText.parent) { game.removeChild(purchaseText); } } }); } }); // Refresh commissary menu closeCommissaryMenu(); openCommissaryMenu(); } } function closeCommissaryMenu() { commissaryMenuOpen = false; commissaryButton.setText('COMMISSARY'); if (commissaryMenu) { game.removeChild(commissaryMenu); commissaryMenu = null; } } ;
===================================================================
--- original.js
+++ change.js
@@ -785,8 +785,20 @@
// Lore System
var loreMenuOpen = false;
var loreMenu = null;
var currentLoreSection = 'background'; // 'background', 'conflict', 'technology', 'nations'
+// Airport Commissary System
+var commissaryMenuOpen = false;
+var commissaryMenu = null;
+var currentCommissarySection = 'boosts'; // 'boosts', 'cosmetics'
+var commissaryInventory = {
+ scoreMultiplier: storage.scoreMultiplier || 1,
+ bonusLives: storage.bonusLives || 0,
+ startingShield: storage.startingShield || false,
+ doubleFireRate: storage.doubleFireRate || false,
+ viggenSkin: storage.viggenSkin || 'default',
+ bulletTrail: storage.bulletTrail || 'default'
+};
// Armament System
var armamentMenuOpen = false;
var armamentMenu = null;
var currentWeapon = 'cannon'; // 'cannon', 'machinegun', 'missiles'
@@ -1086,33 +1098,42 @@
loreButton.x = 0;
loreButton.y = 400;
loreButton.interactive = true;
LK.gui.top.addChild(loreButton);
+var commissaryButton = new Text2('COMMISSARY', {
+ size: 40,
+ fill: 0x44aaff
+});
+commissaryButton.anchor.set(0.5, 0);
+commissaryButton.x = 0;
+commissaryButton.y = 460;
+commissaryButton.interactive = true;
+LK.gui.top.addChild(commissaryButton);
var armamentButton = new Text2('ARMAMENT', {
size: 40,
fill: 0x00ffff
});
armamentButton.anchor.set(0.5, 0);
armamentButton.x = 0;
-armamentButton.y = 460;
+armamentButton.y = 520;
armamentButton.interactive = true;
LK.gui.top.addChild(armamentButton);
var allyButton = new Text2('ALLIES: VIGGEN', {
size: 40,
fill: 0x00ff88
});
allyButton.anchor.set(0.5, 0);
allyButton.x = 0;
-allyButton.y = 520;
+allyButton.y = 580;
allyButton.interactive = true;
LK.gui.top.addChild(allyButton);
var devButton = new Text2('DEV', {
size: 40,
fill: 0xff00ff
});
devButton.anchor.set(0.5, 0);
devButton.x = 0;
-devButton.y = 580;
+devButton.y = 640;
devButton.interactive = true;
LK.gui.top.addChild(devButton);
// Initialize with Ukrainian SSR
currentSSR = new SSR();
@@ -1364,8 +1385,15 @@
} else {
closeLoreMenu();
}
};
+commissaryButton.down = function (x, y, obj) {
+ if (!commissaryMenuOpen) {
+ openCommissaryMenu();
+ } else {
+ closeCommissaryMenu();
+ }
+};
armamentButton.down = function (x, y, obj) {
if (!armamentMenuOpen) {
openArmamentMenu();
} else {
@@ -3263,5 +3291,254 @@
if (allyMenu) {
game.removeChild(allyMenu);
allyMenu = null;
}
-}
\ No newline at end of file
+}
+function openCommissaryMenu() {
+ commissaryMenuOpen = true;
+ commissaryButton.setText('CLOSE');
+ commissaryMenu = new Container();
+ commissaryMenu.x = 0;
+ commissaryMenu.y = 0;
+ game.addChild(commissaryMenu);
+ var menuBg = LK.getAsset('sam', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ scaleX: 15,
+ scaleY: 20
+ });
+ menuBg.x = 1024;
+ menuBg.y = 1366;
+ menuBg.alpha = 0.95;
+ menuBg.tint = 0x004466;
+ commissaryMenu.addChild(menuBg);
+ var titleText = new Text2('AIRPORT COMMISSARY', {
+ size: 70,
+ fill: 0x44AAFF
+ });
+ titleText.anchor.set(0.5, 0.5);
+ titleText.x = 1024;
+ titleText.y = 700;
+ commissaryMenu.addChild(titleText);
+ var pointsText = new Text2('Available Points: ' + LK.getScore(), {
+ size: 45,
+ fill: 0xFFFF00
+ });
+ pointsText.anchor.set(0.5, 0.5);
+ pointsText.x = 1024;
+ pointsText.y = 780;
+ commissaryMenu.addChild(pointsText);
+ // Section buttons
+ var boostsBtn = new Text2('[BOOSTS]', {
+ size: 35,
+ fill: currentCommissarySection === 'boosts' ? 0xFFFF00 : 0x88CCFF
+ });
+ boostsBtn.anchor.set(0.5, 0.5);
+ boostsBtn.x = 800;
+ boostsBtn.y = 850;
+ boostsBtn.interactive = true;
+ commissaryMenu.addChild(boostsBtn);
+ var cosmeticsBtn = new Text2('[COSMETICS]', {
+ size: 35,
+ fill: currentCommissarySection === 'cosmetics' ? 0xFFFF00 : 0x88CCFF
+ });
+ cosmeticsBtn.anchor.set(0.5, 0.5);
+ cosmeticsBtn.x = 1248;
+ cosmeticsBtn.y = 850;
+ cosmeticsBtn.interactive = true;
+ commissaryMenu.addChild(cosmeticsBtn);
+ // Section button handlers
+ boostsBtn.down = function () {
+ currentCommissarySection = 'boosts';
+ closeCommissaryMenu();
+ openCommissaryMenu();
+ };
+ cosmeticsBtn.down = function () {
+ currentCommissarySection = 'cosmetics';
+ closeCommissaryMenu();
+ openCommissaryMenu();
+ };
+ // Display content based on section
+ if (currentCommissarySection === 'boosts') {
+ displayBoostShop();
+ } else if (currentCommissarySection === 'cosmetics') {
+ displayCosmeticShop();
+ }
+}
+function displayBoostShop() {
+ var boostItems = [{
+ name: '2x Score Multiplier',
+ description: 'Double all score gains permanently',
+ cost: 25000,
+ owned: commissaryInventory.scoreMultiplier >= 2,
+ itemKey: 'scoreMultiplier'
+ }, {
+ name: 'Bonus Life',
+ description: 'Start each game with an extra life',
+ cost: 50000,
+ owned: commissaryInventory.bonusLives > 0,
+ itemKey: 'bonusLives'
+ }, {
+ name: 'Starting Shield',
+ description: 'Begin each game with shield active',
+ cost: 30000,
+ owned: commissaryInventory.startingShield,
+ itemKey: 'startingShield'
+ }, {
+ name: 'Double Fire Rate Boost',
+ description: 'Fire rate power-ups are twice as effective',
+ cost: 40000,
+ owned: commissaryInventory.doubleFireRate,
+ itemKey: 'doubleFireRate'
+ }];
+ var yPos = 950;
+ for (var i = 0; i < boostItems.length; i++) {
+ createCommissaryItem(boostItems[i], yPos);
+ yPos += 180;
+ }
+}
+function displayCosmeticShop() {
+ var cosmeticItems = [{
+ name: 'Elite Viggen Skin',
+ description: 'Premium Swedish Air Force livery',
+ cost: 15000,
+ owned: commissaryInventory.viggenSkin === 'elite',
+ itemKey: 'viggenSkin',
+ itemValue: 'elite'
+ }, {
+ name: 'Stealth Viggen Skin',
+ description: 'Dark tactical camouflage pattern',
+ cost: 20000,
+ owned: commissaryInventory.viggenSkin === 'stealth',
+ itemKey: 'viggenSkin',
+ itemValue: 'stealth'
+ }, {
+ name: 'Golden Bullet Trails',
+ description: 'Luxurious gold-tinted projectiles',
+ cost: 12000,
+ owned: commissaryInventory.bulletTrail === 'gold',
+ itemKey: 'bulletTrail',
+ itemValue: 'gold'
+ }, {
+ name: 'Lightning Bullet Trails',
+ description: 'Electric blue energy projectiles',
+ cost: 18000,
+ owned: commissaryInventory.bulletTrail === 'lightning',
+ itemKey: 'bulletTrail',
+ itemValue: 'lightning'
+ }];
+ var yPos = 950;
+ for (var i = 0; i < cosmeticItems.length; i++) {
+ createCommissaryItem(cosmeticItems[i], yPos);
+ yPos += 180;
+ }
+}
+function createCommissaryItem(item, yPos) {
+ var canAfford = LK.getScore() >= item.cost;
+ var statusText = item.owned ? ' (OWNED)' : ' - ' + item.cost + ' pts';
+ var itemText = new Text2(item.name + statusText, {
+ size: 38,
+ fill: item.owned ? 0x00FF00 : canAfford ? 0x44AAFF : 0x666666
+ });
+ itemText.anchor.set(0.5, 0.5);
+ itemText.x = 1024;
+ itemText.y = yPos;
+ itemText.interactive = !item.owned && canAfford;
+ commissaryMenu.addChild(itemText);
+ var descText = new Text2(item.description, {
+ size: 26,
+ fill: 0xCCCCCC
+ });
+ descText.anchor.set(0.5, 0.5);
+ descText.x = 1024;
+ descText.y = yPos + 35;
+ commissaryMenu.addChild(descText);
+ if (!item.owned && canAfford) {
+ itemText.down = function () {
+ purchaseCommissaryItem(item);
+ };
+ // Add purchase button animation
+ tween(itemText, {
+ scaleX: 1.05,
+ scaleY: 1.05
+ }, {
+ duration: 1000,
+ easing: tween.easeInOut,
+ onFinish: function onFinish() {
+ tween(itemText, {
+ scaleX: 1.0,
+ scaleY: 1.0
+ }, {
+ duration: 1000,
+ easing: tween.easeInOut
+ });
+ }
+ });
+ }
+}
+function purchaseCommissaryItem(item) {
+ if (LK.getScore() >= item.cost) {
+ LK.setScore(LK.getScore() - item.cost);
+ // Update inventory
+ if (item.itemKey === 'scoreMultiplier') {
+ commissaryInventory.scoreMultiplier = 2;
+ storage.scoreMultiplier = 2;
+ } else if (item.itemKey === 'bonusLives') {
+ commissaryInventory.bonusLives = 1;
+ storage.bonusLives = 1;
+ } else if (item.itemKey === 'startingShield') {
+ commissaryInventory.startingShield = true;
+ storage.startingShield = true;
+ } else if (item.itemKey === 'doubleFireRate') {
+ commissaryInventory.doubleFireRate = true;
+ storage.doubleFireRate = true;
+ } else if (item.itemKey === 'viggenSkin') {
+ commissaryInventory.viggenSkin = item.itemValue;
+ storage.viggenSkin = item.itemValue;
+ } else if (item.itemKey === 'bulletTrail') {
+ commissaryInventory.bulletTrail = item.itemValue;
+ storage.bulletTrail = item.itemValue;
+ }
+ // Purchase success effects
+ LK.getSound('powerup').play();
+ LK.effects.flashScreen(0x00FF00, 500);
+ var purchaseText = new Text2('PURCHASE COMPLETE!', {
+ size: 50,
+ fill: 0x00FF00
+ });
+ purchaseText.anchor.set(0.5, 0.5);
+ purchaseText.x = 1024;
+ purchaseText.y = 1366;
+ game.addChild(purchaseText);
+ tween(purchaseText, {
+ scaleX: 1.2,
+ scaleY: 1.2
+ }, {
+ duration: 600,
+ easing: tween.easeOut,
+ onFinish: function onFinish() {
+ tween(purchaseText, {
+ alpha: 0
+ }, {
+ duration: 800,
+ onFinish: function onFinish() {
+ if (purchaseText.parent) {
+ game.removeChild(purchaseText);
+ }
+ }
+ });
+ }
+ });
+ // Refresh commissary menu
+ closeCommissaryMenu();
+ openCommissaryMenu();
+ }
+}
+function closeCommissaryMenu() {
+ commissaryMenuOpen = false;
+ commissaryButton.setText('COMMISSARY');
+ if (commissaryMenu) {
+ game.removeChild(commissaryMenu);
+ commissaryMenu = null;
+ }
+}
+;
\ No newline at end of file
Modern App Store icon, high definition, square with rounded corners, for a game titled "Viggen Strike: Soviet Skies" and with the description "Pilot a Saab 37 Viggen through Soviet airspace in this intense bullet hell game, dodging interceptors, SAMs, and drones in a test of aerial survival.". No text on icon!
A Saab 37 Viggen fighter jet.. In-Game asset. 2d. High contrast. No shadows. Top down view
A surface-to-air (SAM) missile.. In-Game asset. 2d. High contrast. No shadows
A surface-to-air (SAM) missile launcher.. In-Game asset. 2d. High contrast. No shadows. Top down view
A Orion fighter UAV.. In-Game asset. 2d. High contrast. No shadows. Top down view
A Su-15 Flagon heavy Interceptor aircraft.. In-Game asset. 2d. High contrast. No shadows. Top down view
Saab 35 Dakem fighter.. In-Game asset. 2d. High contrast. No shadows. Top down view