User prompt
Add SSR spawns to the guide. ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Add enemy SSR bias (MiG-23, Yak-38 and Drones in Ukraine, MiG-23, Su-15, SAMs in Russia, Yak-38 (swarms), drones and Shilkas in Kazakhstan and SAMs, Su-15s, Shilkas and MiG-23s in Belarus)
User prompt
Add a Shilka SPAA enemy (Behaves similarly to a drone, but shoots in bursts (bursts include 5x 3-bullet groups) and rolls vertically)
User prompt
Now make a guide with 2 tips on each enemy, how to use travel and upgrades and Basic maneuvers.
User prompt
Now the Interceptor Split (MiG-23, Su-15, Yak-38) ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
You can do a Enemy CODEX, as I'm planning the Interceptor Type Split. ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Add traveling to different Soviet SSRs.
User prompt
No, the popup for the store is either invisible or does not show.
User prompt
Upgrade store won't show.
User prompt
Add upgrades for the Viggen that you buy with score ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Make SAM spawning rarer, it's the main challenge
User prompt
Add powerups
User prompt
Make the viggen shoot bullets at the enemies
User prompt
Clean up shots from interceptor after a bit, should help
User prompt
Game starts lagging significantly after a few dodges
Code edit (1 edits merged)
Please save this source code
User prompt
Viggen Strike: Soviet Skies
Initial prompt
A bullet hell videogame where you control an Saab 37 Viggen through Soviet airspace while dodging interceptors, SAMs and drones.
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ 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 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' 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 = []; 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); // Initialize with Ukrainian SSR currentSSR = new SSR(); currentSSR.setSSRData(ssrData.ukraine); game.setBackgroundColor(currentSSR.backgroundColor); 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 for (var i = viggenBullets.length - 1; i >= 0; i--) { var bullet = viggenBullets[i]; var hit = false; // Check vs interceptors for (var j = interceptors.length - 1; j >= 0; j--) { if (bullet.intersects(interceptors[j])) { LK.effects.flashObject(interceptors[j], 0xff0000, 200); var scoreValue = interceptors[j].scoreValue || 100; var interceptorType = interceptors[j].interceptorType; // Remove from specific type array if (interceptorType === 'mig23') { for (var k = mig23s.length - 1; k >= 0; k--) { if (mig23s[k] === interceptors[j]) { mig23s.splice(k, 1); break; } } } else if (interceptorType === 'su15') { for (var k = su15s.length - 1; k >= 0; k--) { if (su15s[k] === interceptors[j]) { su15s.splice(k, 1); break; } } } else if (interceptorType === 'yak38') { for (var k = yak38s.length - 1; k >= 0; k--) { if (yak38s[k] === interceptors[j]) { yak38s.splice(k, 1); break; } } } interceptors[j].destroy(); interceptors.splice(j, 1); bullet.destroy(); viggenBullets.splice(i, 1); var baseScore = scoreValue * bullet.damage; var ssrMultiplier = currentSSR ? currentSSR.scoreMultiplier : 1.0; LK.setScore(LK.getScore() + Math.floor(baseScore * ssrMultiplier)); hit = true; break; } } if (hit) continue; // Check vs drones for (var j = drones.length - 1; j >= 0; j--) { if (bullet.intersects(drones[j])) { LK.effects.flashObject(drones[j], 0xff0000, 200); drones[j].destroy(); drones.splice(j, 1); bullet.destroy(); viggenBullets.splice(i, 1); var baseScore = 150 * bullet.damage; var ssrMultiplier = currentSSR ? currentSSR.scoreMultiplier : 1.0; LK.setScore(LK.getScore() + Math.floor(baseScore * ssrMultiplier)); hit = true; break; } } if (hit) continue; // Check vs SAM sites for (var j = samSites.length - 1; j >= 0; j--) { if (bullet.intersects(samSites[j])) { LK.effects.flashObject(samSites[j], 0xff0000, 200); samSites[j].destroy(); samSites.splice(j, 1); bullet.destroy(); viggenBullets.splice(i, 1); var baseScore = 200 * bullet.damage; var ssrMultiplier = currentSSR ? currentSSR.scoreMultiplier : 1.0; LK.setScore(LK.getScore() + Math.floor(baseScore * ssrMultiplier)); hit = true; break; } } if (hit) continue; // Check vs Shilkas for (var j = shilkas.length - 1; j >= 0; j--) { if (bullet.intersects(shilkas[j])) { LK.effects.flashObject(shilkas[j], 0xff0000, 200); shilkas[j].destroy(); shilkas.splice(j, 1); bullet.destroy(); viggenBullets.splice(i, 1); var baseScore = 250 * bullet.damage; var ssrMultiplier = currentSSR ? currentSSR.scoreMultiplier : 1.0; LK.setScore(LK.getScore() + Math.floor(baseScore * ssrMultiplier)); hit = true; break; } } } // 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) { 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(); } }; 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 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() { for (var i = interceptors.length - 1; i >= 0; i--) { if (interceptors[i].y > 2800) { var interceptorType = interceptors[i].interceptorType; // Remove from specific type array if (interceptorType === 'mig23') { for (var k = mig23s.length - 1; k >= 0; k--) { if (mig23s[k] === interceptors[i]) { mig23s.splice(k, 1); break; } } } else if (interceptorType === 'su15') { for (var k = su15s.length - 1; k >= 0; k--) { if (su15s[k] === interceptors[i]) { su15s.splice(k, 1); break; } } } else if (interceptorType === 'yak38') { for (var k = yak38s.length - 1; k >= 0; k--) { if (yak38s[k] === interceptors[i]) { yak38s.splice(k, 1); break; } } } interceptors[i].destroy(); interceptors.splice(i, 1); } } for (var i = drones.length - 1; i >= 0; i--) { if (drones[i].y > 2800) { drones[i].destroy(); drones.splice(i, 1); } } for (var i = shilkas.length - 1; i >= 0; i--) { if (shilkas[i].y > 2800) { shilkas[i].destroy(); shilkas.splice(i, 1); } } 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); } } 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); } } for (var i = samSites.length - 1; i >= 0; i--) { if (samSites[i].y > 2800 || samSites[i].x < -100 || samSites[i].x > 2148) { samSites[i].destroy(); samSites.splice(i, 1); } } // Clean up viggen bullets for (var i = viggenBullets.length - 1; i >= 0; i--) { if (viggenBullets[i].y < -50) { viggenBullets[i].destroy(); viggenBullets.splice(i, 1); } } // Clean up powerups for (var i = powerups.length - 1; i >= 0; i--) { if (powerups[i].y > 2800) { powerups[i].destroy(); powerups.splice(i, 1); } } } game.update = function () { survivalTime++; difficultyTimer++; spawnTimer++; 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); } // Apply SSR spawn rate multiplier var ssrSpawnRate = currentSSR ? Math.floor(currentSpawnRate / currentSSR.spawnRateMultiplier) : currentSpawnRate; if (spawnTimer >= ssrSpawnRate) { spawnTimer = 0; var spawnType = Math.random(); // SSR-specific enemy spawning patterns if (currentSSR && currentSSR.name === 'Ukrainian SSR') { // Ukraine: MiG-23, Yak-38 and Drones if (spawnType < 0.4) { // Spawn MiG-23 specifically var interceptor = new MiG23(); mig23s.push(interceptor); markEnemyEncountered('mig23'); interceptor.x = Math.random() * 1848 + 100; interceptor.y = -100; game.addChild(interceptor); interceptors.push(interceptor); } else if (spawnType < 0.7) { // Spawn Yak-38 specifically var interceptor = new Yak38(); yak38s.push(interceptor); markEnemyEncountered('yak38'); interceptor.x = Math.random() * 1848 + 100; interceptor.y = -100; game.addChild(interceptor); interceptors.push(interceptor); } else { spawnDrone(); } } else if (currentSSR && currentSSR.name === 'Russian SFSR') { // Russia: MiG-23, Su-15, SAMs if (spawnType < 0.4) { // Spawn MiG-23 specifically var interceptor = new MiG23(); mig23s.push(interceptor); markEnemyEncountered('mig23'); interceptor.x = Math.random() * 1848 + 100; interceptor.y = -100; game.addChild(interceptor); interceptors.push(interceptor); } else if (spawnType < 0.7) { // Spawn Su-15 specifically var interceptor = new Su15(); su15s.push(interceptor); markEnemyEncountered('su15'); interceptor.x = Math.random() * 1848 + 100; interceptor.y = -100; game.addChild(interceptor); interceptors.push(interceptor); } else { spawnSAMSite(); } } else if (currentSSR && currentSSR.name === 'Kazakh SSR') { // Kazakhstan: Yak-38 (swarms), drones and Shilkas if (spawnType < 0.5) { // Spawn Yak-38 specifically (swarms) var interceptor = new Yak38(); yak38s.push(interceptor); markEnemyEncountered('yak38'); interceptor.x = Math.random() * 1848 + 100; interceptor.y = -100; game.addChild(interceptor); interceptors.push(interceptor); } else if (spawnType < 0.75) { spawnDrone(); } else { spawnShilka(); } } else if (currentSSR && currentSSR.name === 'Byelorussian SSR') { // Belarus: SAMs, Su-15s, Shilkas and MiG-23s if (spawnType < 0.3) { spawnSAMSite(); } else if (spawnType < 0.55) { // Spawn Su-15 specifically var interceptor = new Su15(); su15s.push(interceptor); markEnemyEncountered('su15'); interceptor.x = Math.random() * 1848 + 100; interceptor.y = -100; game.addChild(interceptor); interceptors.push(interceptor); } else if (spawnType < 0.8) { spawnShilka(); } else { // Spawn MiG-23 specifically var interceptor = new MiG23(); mig23s.push(interceptor); markEnemyEncountered('mig23'); interceptor.x = Math.random() * 1848 + 100; interceptor.y = -100; game.addChild(interceptor); interceptors.push(interceptor); } } else { // 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 checkSSRUnlocks(); // 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 upgradeFireRate = Math.max(5, normalFireRate - (upgrades.fireRate - 1) * 2); var currentFireRate = rapidFireActive ? Math.floor(upgradeFireRate / 3) : upgradeFireRate; if (fireTimer >= currentFireRate) { fireTimer = 0; var bullet = new ViggenBullet(); 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); } } } }; LK.playMusic('combat');
===================================================================
--- original.js
+++ change.js
@@ -1265,14 +1265,14 @@
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!)', '', '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 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 : 0xFFFFFF
+ 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;
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