/**** * Plugins ****/ var storage = LK.import("@upit/storage.v1"); var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var Aircraft = Container.expand(function () { var self = Container.call(this); // Main aircraft fuselage (body) - enhanced proportions var aircraftGraphics = self.attachAsset('aircraft', { anchorX: 0.5, anchorY: 0.5 }); // Enhanced main wings with better positioning and scale var mainWing = self.attachAsset('aircraftWing', { anchorX: 0.5, anchorY: 0.5 }); mainWing.x = -5; // Move forward for better balance mainWing.y = 5; // Slightly lower on fuselage mainWing.scaleX = 1.3; // Make wings larger mainWing.scaleY = 1.5; // Wing struts for realism var leftWingStrut = self.attachAsset('aircraftEngine', { anchorX: 0.5, anchorY: 0.5 }); leftWingStrut.x = -10; leftWingStrut.y = 18; leftWingStrut.scaleX = 0.3; leftWingStrut.scaleY = 2; leftWingStrut.rotation = Math.PI / 4; var rightWingStrut = self.attachAsset('aircraftEngine', { anchorX: 0.5, anchorY: 0.5 }); rightWingStrut.x = -10; rightWingStrut.y = -8; rightWingStrut.scaleX = 0.3; rightWingStrut.scaleY = 2; rightWingStrut.rotation = -Math.PI / 4; // Enhanced aircraft tail with better proportions var tail = self.attachAsset('aircraftTail', { anchorX: 0.5, anchorY: 0.5 }); tail.x = -65; tail.y = 0; tail.rotation = Math.PI / 2; tail.scaleX = 1.2; // Make tail more prominent tail.scaleY = 0.8; // Horizontal stabilizer with improved positioning var horizontalStab = self.attachAsset('aircraftWing', { anchorX: 0.5, anchorY: 0.5 }); horizontalStab.x = -58; horizontalStab.y = 0; horizontalStab.scaleX = 0.5; horizontalStab.scaleY = 0.7; // Enhanced cockpit with better visibility var cockpit = self.attachAsset('aircraftCockpit', { anchorX: 0.5, anchorY: 0.5 }); cockpit.x = 40; cockpit.y = -3; cockpit.scaleX = 1.4; // Larger, more visible cockpit cockpit.scaleY = 1.2; // Wing tip fuel tanks for modern look var leftWingTip = self.attachAsset('aircraftEngine', { anchorX: 0.5, anchorY: 0.5 }); leftWingTip.x = -5; leftWingTip.y = 25; leftWingTip.scaleX = 0.6; leftWingTip.scaleY = 0.8; var rightWingTip = self.attachAsset('aircraftEngine', { anchorX: 0.5, anchorY: 0.5 }); rightWingTip.x = -5; rightWingTip.y = -15; rightWingTip.scaleX = 0.6; rightWingTip.scaleY = 0.8; // Enhanced engine nacelles with better positioning var leftEngine = self.attachAsset('aircraftEngine', { anchorX: 0.5, anchorY: 0.5 }); leftEngine.x = -15; leftEngine.y = 15; leftEngine.scaleX = 1.2; leftEngine.scaleY = 1.3; var rightEngine = self.attachAsset('aircraftEngine', { anchorX: 0.5, anchorY: 0.5 }); rightEngine.x = -15; rightEngine.y = -5; rightEngine.scaleX = 1.2; rightEngine.scaleY = 1.3; // Landing gear indicators (small details) var leftGear = self.attachAsset('aircraftEngine', { anchorX: 0.5, anchorY: 0.5 }); leftGear.x = 15; leftGear.y = 8; leftGear.scaleX = 0.4; leftGear.scaleY = 0.3; var rightGear = self.attachAsset('aircraftEngine', { anchorX: 0.5, anchorY: 0.5 }); rightGear.x = 15; rightGear.y = -8; rightGear.scaleX = 0.4; rightGear.scaleY = 0.3; // Enhanced propeller with better positioning var propeller = self.attachAsset('aircraftPropeller', { anchorX: 0.5, anchorY: 0.5 }); propeller.x = 75; propeller.y = 0; propeller.scaleX = 1.2; // Larger propeller propeller.scaleY = 1.4; // Secondary propeller blade for depth var propellerBlade2 = self.attachAsset('aircraftPropeller', { anchorX: 0.5, anchorY: 0.5 }); propellerBlade2.x = 75; propellerBlade2.y = 0; propellerBlade2.scaleX = 1.2; propellerBlade2.scaleY = 1.4; propellerBlade2.rotation = Math.PI / 2; // 90 degrees offset // Navigation lights var leftNavLight = self.attachAsset('aircraftCockpit', { anchorX: 0.5, anchorY: 0.5 }); leftNavLight.x = -5; leftNavLight.y = 30; leftNavLight.scaleX = 0.3; leftNavLight.scaleY = 0.3; leftNavLight.tint = 0xFF0000; // Red navigation light var rightNavLight = self.attachAsset('aircraftCockpit', { anchorX: 0.5, anchorY: 0.5 }); rightNavLight.x = -5; rightNavLight.y = -20; rightNavLight.scaleX = 0.3; rightNavLight.scaleY = 0.3; rightNavLight.tint = 0x00FF00; // Green navigation light // Animate propeller rotation with both blades propeller.rotationSpeed = 0.3; propellerBlade2.rotationSpeed = 0.3; // Progressive aircraft speed: starts at 3, increases by 0.1 per level, caps at level 20 (speed 5) self.speed = Math.min(5, 3 + (currentLevel - 1) * 0.1); self.lastY = 0; self.update = function () { // Update last position for collision detection self.lastY = self.y; // Animate both propeller blades spinning with variable speed var propellerSpeed = propeller.rotationSpeed * (1 + self.speed * 0.1); propeller.rotation += propellerSpeed; propellerBlade2.rotation += propellerSpeed; // Animate navigation lights blinking if (LK.ticks % 120 < 60) { // Blink every 2 seconds leftNavLight.alpha = 1; rightNavLight.alpha = 1; } else { leftNavLight.alpha = 0.3; rightNavLight.alpha = 0.3; } // Create enhanced engine trail particles if (LK.ticks % 3 === 0 && gameStarted) { createEngineParticle(self.x - 50, self.y + 10); // Left engine trail createEngineParticle(self.x - 50, self.y - 5); // Right engine trail // Add occasional spark effects from both engines if (Math.random() < 0.3) { createSparkParticle(self.x - 40, self.y + (Math.random() - 0.5) * 20); } } // Add subtle banking animation during movement var bankingAngle = Math.sin(LK.ticks * 0.05) * 0.1; self.rotation = bankingAngle; // Add subtle floating animation for more dynamic feel if (!self.floatingTween) { self.floatingTween = true; var originalY = self.y; tween(self, { y: originalY + 8 }, { duration: 2000, easing: tween.easeInOut, onFinish: function onFinish() { tween(self, { y: originalY - 8 }, { duration: 2000, easing: tween.easeInOut, onFinish: function onFinish() { self.floatingTween = false; } }); } }); } }; return self; }); var Cloud = Container.expand(function () { var self = Container.call(this); // Choose random cloud type var cloudTypes = ['cloud1', 'cloud2', 'cloud3']; var cloudType = cloudTypes[Math.floor(Math.random() * cloudTypes.length)]; // Main cloud body var mainCloud = self.attachAsset(cloudType, { anchorX: 0.5, anchorY: 0.5 }); // Add smaller cloud parts for more realistic shape var cloud2 = self.attachAsset(cloudType, { anchorX: 0.5, anchorY: 0.5 }); cloud2.x = -30 + Math.random() * 60; cloud2.y = -15 + Math.random() * 30; cloud2.scaleX = 0.6 + Math.random() * 0.4; cloud2.scaleY = 0.6 + Math.random() * 0.4; cloud2.alpha = 0.8; var cloud3 = self.attachAsset(cloudType, { anchorX: 0.5, anchorY: 0.5 }); cloud3.x = -20 + Math.random() * 40; cloud3.y = -10 + Math.random() * 20; cloud3.scaleX = 0.4 + Math.random() * 0.3; cloud3.scaleY = 0.4 + Math.random() * 0.3; cloud3.alpha = 0.6; // Set random speed and scale self.speed = 0.5 + Math.random() * 1.5; self.scaleX = 0.8 + Math.random() * 0.6; self.scaleY = 0.8 + Math.random() * 0.6; self.alpha = 0.7 + Math.random() * 0.3; self.update = function () { // Move cloud from right to left self.x -= self.speed; }; return self; }); var Coin = Container.expand(function () { var self = Container.call(this); // Coin visual var coinGraphics = self.attachAsset('coin', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.2, scaleY: 1.2 }); // Floating and spinning animation self.floatOffset = Math.random() * Math.PI * 2; self.collected = false; self.update = function () { // Floating animation self.y += Math.sin(LK.ticks * 0.15 + self.floatOffset) * 0.8; // Spinning animation coinGraphics.rotation += 0.1; // Pulsing scale effect var scale = 1.2 + Math.sin(LK.ticks * 0.08) * 0.2; coinGraphics.scaleX = scale; coinGraphics.scaleY = scale; // Move from right to left var speed = Math.max(1.5, Math.min(6, 1.5 + currentLevel * 0.05)); self.x -= speed; }; return self; }); var FinishLine = Container.expand(function () { var self = Container.call(this); // Main finish line var lineGraphics = self.attachAsset('finishLine', { anchorX: 0.5, anchorY: 0.5 }); // Add flags at top and bottom for visibility var topFlag = self.attachAsset('finishFlag', { anchorX: 0.5, anchorY: 0.5 }); topFlag.y = -1300; var bottomFlag = self.attachAsset('finishFlag', { anchorX: 0.5, anchorY: 0.5 }); bottomFlag.y = 1300; self.lastX = 0; self.crossed = false; self.update = function () { // Update last position before moving self.lastX = self.x; // Move finish line from right to left (match tower speed for levels 1-100) var speed = Math.max(1.5, Math.min(6, 1.5 + currentLevel * 0.05)); // Match tower speed progression self.x -= speed; }; return self; }); var Particle = Container.expand(function () { var self = Container.call(this); // Small particle visual var particleGraphics = self.attachAsset('cloud1', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.1, scaleY: 0.1 }); particleGraphics.alpha = 0.7; particleGraphics.tint = 0xFF6600; // Orange-ish color self.velocityX = -2 - Math.random() * 3; self.velocityY = (Math.random() - 0.5) * 2; self.life = 60; // 1 second at 60fps self.update = function () { self.x += self.velocityX; self.y += self.velocityY; self.life--; particleGraphics.alpha *= 0.98; // Fade out particleGraphics.scaleX *= 0.99; // Shrink particleGraphics.scaleY *= 0.99; if (self.life <= 0) { self.destroy(); var index = particles.indexOf(self); if (index > -1) particles.splice(index, 1); } }; return self; }); var PowerUp = Container.expand(function () { var self = Container.call(this); // Power-up visual var powerUpGraphics = self.attachAsset('finishFlag', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.8, scaleY: 0.8 }); powerUpGraphics.tint = 0x00FFFF; // Cyan color for power-ups // Floating animation self.floatOffset = Math.random() * Math.PI * 2; self.collected = false; self.update = function () { // Floating animation self.y += Math.sin(LK.ticks * 0.1 + self.floatOffset) * 0.5; // Rotation animation powerUpGraphics.rotation += 0.05; // Move from right to left var speed = Math.max(1.5, Math.min(6, 1.5 + currentLevel * 0.05)); self.x -= speed; }; return self; }); var SparkParticle = Container.expand(function () { var self = Container.call(this); // Small spark visual var sparkGraphics = self.attachAsset('coin', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.05, scaleY: 0.05 }); sparkGraphics.alpha = 1; sparkGraphics.tint = 0xFFAA00; // Orange spark color self.velocityX = -1 - Math.random() * 2; self.velocityY = (Math.random() - 0.5) * 3; self.life = 30; // Half second at 60fps self.update = function () { self.x += self.velocityX; self.y += self.velocityY; self.velocityY += 0.1; // Gravity effect self.life--; sparkGraphics.alpha *= 0.95; // Faster fade than regular particles sparkGraphics.scaleX *= 0.98; sparkGraphics.scaleY *= 0.98; sparkGraphics.rotation += 0.2; // Spinning effect if (self.life <= 0) { self.destroy(); var index = sparkParticles.indexOf(self); if (index > -1) sparkParticles.splice(index, 1); } }; return self; }); var Tower = Container.expand(function () { var self = Container.call(this); // Tower base var towerBase = self.attachAsset('towerBase', { anchorX: 0.5, anchorY: 0.5 }); // Tower top var towerTop = self.attachAsset('towerTop', { anchorX: 0.5, anchorY: 0.5 }); towerTop.y = -420; // Position at top of tower // Add windows to make it look more realistic for (var w = 0; w < 3; w++) { var window1 = self.attachAsset('towerWindow', { anchorX: 0.5, anchorY: 0.5 }); window1.x = -30; window1.y = -300 + w * 150; var window2 = self.attachAsset('towerWindow', { anchorX: 0.5, anchorY: 0.5 }); window2.x = 30; window2.y = -300 + w * 150; } self.lastX = 0; self.passed = false; self.update = function () { // Update last position before moving self.lastX = self.x; // Move tower from right to left (progressive speed increase for levels 1-100) var speed = Math.max(1.5, Math.min(6, 1.5 + currentLevel * 0.05)); // Gradual speed increase, capped at 6 self.x -= speed; }; return self; }); /**** * Initialize Game ****/ // Game variables var game = new LK.Game({ backgroundColor: 0x87CEFA // More realistic sky blue background }); /**** * Game Code ****/ //Storage plugin for persistent game data // Game variables // Initialize assets for the tower dodge flight game var aircraft; var towers = []; var clouds = []; var finishLine = null; var showingMenu = false; var currentLevel = storage.currentLevel || 1; var levelScore = 0; var towersToComplete = 5 * currentLevel; // Level 1: 5, Level 2: 10, Level 3: 15, etc. var towerSpawnTimer = 0; var gameStarted = false; var menuContainer = null; var mainMenuContainer = null; var showingMainMenu = true; var showingCodesMenu = false; var codesMenuContainer = null; var adminMode = false; var adminModeEndTime = 0; // Enhanced settings storage var gameSettings = storage.gameSettings || { soundEnabled: true, musicEnabled: true, difficulty: 'normal', highestLevelReached: 1, particlesEnabled: true, screenshakeEnabled: true }; // Additional game variables var powerUps = []; var particles = []; var sparkParticles = []; var powerUpSpawnTimer = 0; var invulnerabilityTime = 0; var comboMultiplier = 1; var lastPowerUpTime = 0; var musicPlaying = false; var coins = []; var coinSpawnTimer = 0; var showingShop = false; var shopContainer = null; // Initialize player coins and shop items var playerCoins = storage.playerCoins || 0; var totalScore = storage.totalScore || 0; var ownedAircraftStyles = storage.ownedAircraftStyles || ['default']; var ownedTowerStyles = storage.ownedTowerStyles || ['default']; var currentAircraftStyle = storage.currentAircraftStyle || 'default'; var currentTowerStyle = storage.currentTowerStyle || 'default'; // Shop items with prices var aircraftStyles = [{ id: 'default', name: 'Classic', price: 0, color: 0xf0f0f0 }, { id: 'red', name: 'Fire Bird', price: 100, color: 0xff4444 }, { id: 'blue', name: 'Sky Runner', price: 150, color: 0x4444ff }, { id: 'green', name: 'Forest Wing', price: 200, color: 0x44ff44 }, { id: 'purple', name: 'Royal Jet', price: 300, color: 0x8844ff }, { id: 'gold', name: 'Golden Eagle', price: 500, color: 0xffd700 }]; // Orange aircraft style - only available through code var orangeAircraftStyle = { id: 'orange', name: 'Orange Flyer', price: 0, color: 0xff8000 }; var towerStyles = [{ id: 'default', name: 'Stone Tower', price: 0, color: 0x8b4513 }, { id: 'metal', name: 'Metal Tower', price: 120, color: 0x778899 }, { id: 'crystal', name: 'Crystal Tower', price: 180, color: 0x99ddff }, { id: 'dark', name: 'Dark Tower', price: 250, color: 0x444444 }, { id: 'rainbow', name: 'Rainbow Tower', price: 400, color: 0xff6699 }]; // Update settings when needed if (currentLevel > gameSettings.highestLevelReached) { gameSettings.highestLevelReached = currentLevel; storage.gameSettings = gameSettings; } // Check if admin mode is still active from previous session var storedAdminEndTime = storage.adminModeEndTime || 0; if (storedAdminEndTime > Date.now()) { adminMode = true; adminModeEndTime = storedAdminEndTime; } // UI Elements var levelText = new Text2('Level: 1', { size: 60, fill: 0xFFFFFF }); levelText.anchor.set(0, 0); LK.gui.topLeft.addChild(levelText); levelText.x = 120; // Avoid top-left menu area levelText.y = 20; var scoreText = new Text2('Score: 0', { size: 60, fill: 0xFFFFFF }); scoreText.anchor.set(1, 0); LK.gui.topRight.addChild(scoreText); var progressText = new Text2('Progress: 0/10', { size: 50, fill: 0xFFFFFF }); progressText.anchor.set(0.5, 0); LK.gui.top.addChild(progressText); progressText.y = 100; var coinsText = new Text2('Coins: ' + playerCoins, { size: 50, fill: 0xFFD700 }); coinsText.anchor.set(0, 0); LK.gui.topLeft.addChild(coinsText); coinsText.x = 120; coinsText.y = 80; // Initialize aircraft aircraft = game.addChild(new Aircraft()); aircraft.x = 300; aircraft.y = 1366; // Center vertically aircraft.lastIntersecting = false; // Show main menu at start createMainMenu(); // Touch controls for aircraft movement var dragActive = false; game.down = function (x, y, obj) { if (showingMainMenu || showingMenu) return; dragActive = true; }; game.up = function (x, y, obj) { if (showingMainMenu || showingMenu) return; dragActive = false; }; game.move = function (x, y, obj) { if (showingMainMenu || showingMenu) return; var targetY = y; if (dragActive) { targetY = y; } // Keep aircraft within screen bounds if (targetY < 50) targetY = 50; if (targetY > 2680) targetY = 2680; // Smooth tween animation for aircraft movement tween.stop(aircraft, { y: true }); tween(aircraft, { y: targetY }, { duration: 200, easing: tween.easeOut }); }; // Function to spawn tower function spawnTower() { // Define imaginary boundary lines to delimit tower generation zone var screenTop = 0; var screenBottom = 2732; var centerY = 1366; // Center of the screen var safeZoneHeight = 1800; // Height of the safe generation zone (smaller than full screen) var upperBoundary = centerY - safeZoneHeight / 2; // Top imaginary line var lowerBoundary = centerY + safeZoneHeight / 2; // Bottom imaginary line // Ensure boundaries are within screen limits with additional margin upperBoundary = Math.max(200, upperBoundary); // Minimum 200px from top lowerBoundary = Math.min(2532, lowerBoundary); // Maximum 200px from bottom // Enhanced gap sizing with more generous minimum and smoother progression var baseGapSize = 450; // Increased base gap size for better playability var levelReduction = Math.min(currentLevel - 1, 30) * 8; // Slower reduction, cap at level 30 var gapSize = Math.max(380, baseGapSize - levelReduction); // Higher minimum gap (380px vs 350px) // Aircraft dimensions for precise gap calculation var aircraftHeight = 140; // Based on aircraft asset height var safetyMargin = 50; // Extra margin for comfortable passage var minRequiredGap = aircraftHeight + safetyMargin * 2; // Minimum theoretical gap needed gapSize = Math.max(gapSize, minRequiredGap); // Ensure gap is never smaller than aircraft needs // Tower generation zone constraints using imaginary boundary lines var towerHeight = 800; // Tower base height from asset var zoneMargin = 100; // Additional margin within the safe zone var minGapCenter = upperBoundary + zoneMargin + gapSize / 2; // Use upper boundary line var maxGapCenter = lowerBoundary - zoneMargin - gapSize / 2; // Use lower boundary line // Ensure we have enough space for gap generation if (maxGapCenter <= minGapCenter) { // Fallback to center area if boundaries are too restrictive minGapCenter = centerY - gapSize / 2; maxGapCenter = centerY + gapSize / 2; } // Enhanced gap connection system to ensure continuity between tower pairs var gapCenter; if (towers.length === 0) { // First tower pair - start in center area for safety gapCenter = centerY; } else { // Find the most recent tower pair to connect with var lastTopTower = null; var lastBottomTower = null; var lastGapCenter = centerY; // Find the last tower pair by looking for the rightmost towers for (var t = towers.length - 1; t >= 0; t--) { var tower = towers[t]; if (!lastTopTower && tower.y < centerY) { lastTopTower = tower; } else if (!lastBottomTower && tower.y > centerY) { lastBottomTower = tower; } if (lastTopTower && lastBottomTower) break; } // Calculate last gap center if we found both towers if (lastTopTower && lastBottomTower) { var lastGapTop = lastTopTower.y + towerHeight / 2; var lastGapBottom = lastBottomTower.y - towerHeight / 2; lastGapCenter = (lastGapTop + lastGapBottom) / 2; } // Create connecting gap within reasonable range of last gap var connectionRange = gapSize * 0.8; // Allow gap to move within 80% of gap size var minConnectionCenter = Math.max(minGapCenter, lastGapCenter - connectionRange); var maxConnectionCenter = Math.min(maxGapCenter, lastGapCenter + connectionRange); // Ensure we still have valid range if (minConnectionCenter > maxConnectionCenter) { minConnectionCenter = minGapCenter; maxConnectionCenter = maxGapCenter; } gapCenter = minConnectionCenter + Math.random() * (maxConnectionCenter - minConnectionCenter); } var gapTop = gapCenter - gapSize / 2; var gapBottom = gapCenter + gapSize / 2; // Final boundary checks to ensure towers stay within imaginary lines gapTop = Math.max(upperBoundary + zoneMargin, gapTop); gapBottom = Math.min(lowerBoundary - zoneMargin, gapBottom); gapSize = gapBottom - gapTop; // Recalculate actual gap size after boundary adjustments // Ensure minimum gap size is maintained if (gapSize < minRequiredGap) { var adjustment = (minRequiredGap - gapSize) / 2; gapTop -= adjustment; gapBottom += adjustment; // Re-check boundaries after adjustment gapTop = Math.max(upperBoundary + zoneMargin, gapTop); gapBottom = Math.min(lowerBoundary - zoneMargin, gapBottom); } // Create top tower with precise positioning var topTower = game.addChild(new Tower()); topTower.x = 2200; // Start from right edge // Position tower so its bottom edge aligns with gap top topTower.y = gapTop - towerHeight / 2; // Center tower above gap topTower.lastIntersecting = false; towers.push(topTower); // Apply current tower style var currentTowerStyleData = towerStyles.find(function (style) { return style.id === currentTowerStyle; }); if (currentTowerStyleData) { topTower.children[0].tint = currentTowerStyleData.color; // Tower base topTower.children[1].tint = currentTowerStyleData.color; // Tower top } // Create bottom tower with precise positioning var bottomTower = game.addChild(new Tower()); bottomTower.x = 2200; // Start from right edge // Position tower so its top edge aligns with gap bottom bottomTower.y = gapBottom + towerHeight / 2; // Center tower below gap bottomTower.lastIntersecting = false; towers.push(bottomTower); // Apply current tower style if (currentTowerStyleData) { bottomTower.children[0].tint = currentTowerStyleData.color; // Tower base bottomTower.children[1].tint = currentTowerStyleData.color; // Tower top } // Debug verification to ensure proper gap and boundary compliance var actualGap = bottomTower.y - towerHeight / 2 - (topTower.y + towerHeight / 2); if (actualGap < minRequiredGap) { console.warn('Gap too small detected:', actualGap, 'Required:', minRequiredGap); } // Verify towers are within boundary lines if (topTower.y + towerHeight / 2 < upperBoundary || bottomTower.y - towerHeight / 2 > lowerBoundary) { console.warn('Tower positioned outside boundary lines'); } } // Function to spawn clouds function spawnCloud() { var cloud = new Cloud(); cloud.x = 2200 + Math.random() * 400; // Start from right edge with some variation cloud.y = 200 + Math.random() * 2300; // Random height across screen clouds.push(cloud); game.addChild(cloud); } // Function to spawn finish line function spawnFinishLine() { if (finishLine) return; // Don't spawn if already exists finishLine = game.addChild(new FinishLine()); finishLine.x = aircraft.x + 400; // Position finish line ahead of aircraft when progress completes finishLine.y = 1366; // Center vertically finishLine.lastIntersecting = false; } // Function to create engine particles function createEngineParticle(x, y) { if (!gameSettings.particlesEnabled || particles.length > 20) return; var particle = new Particle(); particle.x = x + (Math.random() - 0.5) * 20; particle.y = y + (Math.random() - 0.5) * 10; particles.push(particle); game.addChild(particle); } // Function to create spark particles function createSparkParticle(x, y) { if (!gameSettings.particlesEnabled || sparkParticles.length > 15) return; var spark = new SparkParticle(); spark.x = x; spark.y = y; sparkParticles.push(spark); game.addChild(spark); } // Function to create tower destruction effect function createTowerDestructionEffect(x, y) { if (!gameSettings.particlesEnabled) return; // Create multiple debris particles for (var i = 0; i < 8; i++) { var debris = new Particle(); debris.x = x + (Math.random() - 0.5) * 100; debris.y = y + (Math.random() - 0.5) * 200; debris.children[0].tint = 0x8B4513; // Brown debris color debris.velocityX = (Math.random() - 0.5) * 8; debris.velocityY = -Math.random() * 5; debris.life = 120; // Longer life for debris particles.push(debris); game.addChild(debris); } // Create sparks for (var j = 0; j < 5; j++) { createSparkParticle(x + (Math.random() - 0.5) * 80, y + (Math.random() - 0.5) * 150); } } // Function to spawn coin function spawnCoin() { var coin = new Coin(); coin.x = 2200; coin.y = 200 + Math.random() * 2300; coin.lastIntersecting = false; coins.push(coin); game.addChild(coin); } // Function to spawn power-up function spawnPowerUp() { var powerUp = new PowerUp(); powerUp.x = 2200; powerUp.y = 200 + Math.random() * 2300; powerUp.lastIntersecting = false; powerUps.push(powerUp); game.addChild(powerUp); } // Function to apply power-up effect function applyPowerUpEffect() { invulnerabilityTime = 300; // 5 seconds at 60fps comboMultiplier = Math.min(comboMultiplier + 0.5, 3); // Max 3x multiplier lastPowerUpTime = LK.ticks; // Visual feedback LK.effects.flashObject(aircraft, 0x00FFFF, 500); LK.getSound('powerup').play(); // Update aircraft appearance during invulnerability tween(aircraft, { alpha: 0.7 }, { duration: 100, onFinish: function onFinish() { tween(aircraft, { alpha: 1 }, { duration: 100 }); } }); } // Function to create level completion menu function createLevelMenu() { showingMenu = true; menuContainer = new Container(); game.addChild(menuContainer); // Semi-transparent background var menuBg = LK.getAsset('towerBase', { anchorX: 0.5, anchorY: 0.5, scaleX: 8, scaleY: 2, alpha: 0.8 }); menuBg.x = 1024; menuBg.y = 1366; menuContainer.addChild(menuBg); // Title text var titleText = new Text2('Level ' + currentLevel + ' Complete!', { size: 80, fill: 0xFFFFFF }); titleText.anchor.set(0.5, 0.5); titleText.x = 1024; titleText.y = 1200; menuContainer.addChild(titleText); // Retry button var retryText = new Text2('Retry Level', { size: 60, fill: 0x00FF00 }); retryText.anchor.set(0.5, 0.5); retryText.x = 1024; retryText.y = 1300; retryText.interactive = true; retryText.down = function () { restartCurrentLevel(); }; menuContainer.addChild(retryText); // Next level button var nextText = new Text2('Next Level', { size: 60, fill: 0x0080FF }); nextText.anchor.set(0.5, 0.5); nextText.x = 1024; nextText.y = 1400; nextText.interactive = true; nextText.down = function () { goToNextLevel(); }; menuContainer.addChild(nextText); // Return to level 1 button var returnText = new Text2('Return to Level 1', { size: 60, fill: 0xFF8000 }); returnText.anchor.set(0.5, 0.5); returnText.x = 1024; returnText.y = 1500; returnText.interactive = true; returnText.down = function () { returnToLevel1(); }; menuContainer.addChild(returnText); } // Function to restart current level function restartCurrentLevel() { hideMenu(); levelScore = 0; // Clear existing towers and finish line clearLevel(); // Reset aircraft position aircraft.x = 300; aircraft.y = 1366; // Update aircraft speed for current level aircraft.speed = Math.min(5, 3 + (currentLevel - 1) * 0.1); // Update UI progressText.setText('Progress: 0/' + towersToComplete); } // Function to go to next level function goToNextLevel() { hideMenu(); completeLevel(); } // Function to return to level 1 function returnToLevel1() { hideMenu(); currentLevel = 1; storage.currentLevel = 1; levelScore = 0; towersToComplete = 5 * currentLevel; // Clear existing towers and finish line clearLevel(); // Reset aircraft position aircraft.x = 300; aircraft.y = 1366; // Update aircraft speed for level 1 aircraft.speed = Math.min(5, 3 + (currentLevel - 1) * 0.1); // Update UI levelText.setText('Level: ' + currentLevel); progressText.setText('Progress: 0/' + towersToComplete); } // Function to create main menu function createMainMenu() { showingMainMenu = true; mainMenuContainer = new Container(); game.addChild(mainMenuContainer); // Start menu music if (gameSettings.musicEnabled) { LK.stopMusic(); LK.playMusic('menuMusic', { loop: true }); musicPlaying = false; // Reset flag so game music can start } // Semi-transparent background var menuBg = LK.getAsset('towerBase', { anchorX: 0.5, anchorY: 0.5, scaleX: 10, scaleY: 4, alpha: 0.9 }); menuBg.x = 1024; menuBg.y = 1366; mainMenuContainer.addChild(menuBg); // Game title var titleText = new Text2('TOWER DODGE', { size: 120, fill: 0xFFD700 }); titleText.anchor.set(0.5, 0.5); titleText.x = 1024; titleText.y = 600; titleText.alpha = 0; mainMenuContainer.addChild(titleText); // Animate title entrance tween(titleText, { y: 750, alpha: 1 }, { duration: 1000, easing: tween.bounceOut }); // Subtitle var subtitleText = new Text2('Navigate through the towers!', { size: 60, fill: 0xFFFFFF }); subtitleText.anchor.set(0.5, 0.5); subtitleText.x = 1024; subtitleText.y = 850; mainMenuContainer.addChild(subtitleText); // Play button var playText = new Text2('PLAY', { size: 80, fill: 0x00FF00 }); playText.anchor.set(0.5, 0.5); playText.x = 1024; playText.y = 1000; playText.alpha = 0; playText.scaleX = 0.5; playText.scaleY = 0.5; playText.interactive = true; playText.down = function () { // Add button press animation tween(playText, { scaleX: 1.2, scaleY: 1.2 }, { duration: 100, onFinish: function onFinish() { tween(playText, { scaleX: 1, scaleY: 1 }, { duration: 100 }); } }); hideMainMenu(); startGame(); }; mainMenuContainer.addChild(playText); // Animate play button entrance with delay tween(playText, { y: 1050, alpha: 1, scaleX: 1, scaleY: 1 }, { duration: 800, easing: tween.elasticOut }); // Shop button var shopText = new Text2('SHOP', { size: 80, fill: 0x00FFFF }); shopText.anchor.set(0.5, 0.5); shopText.x = 724; // Position to the left of center shopText.y = 1150; shopText.interactive = true; shopText.down = function () { hideMainMenu(); showShop(); }; mainMenuContainer.addChild(shopText); // Skins button var skinsText = new Text2('SKINS', { size: 80, fill: 0x9932CC }); skinsText.anchor.set(0.5, 0.5); skinsText.x = 1324; // Position to the right of center skinsText.y = 1150; // Same Y level as shop skinsText.interactive = true; skinsText.down = function () { hideMainMenu(); showSkinsMenu(); }; mainMenuContainer.addChild(skinsText); // Codes button var codesText = new Text2('CODES', { size: 80, fill: 0xFF8000 }); codesText.anchor.set(0.5, 0.5); codesText.x = 1024; codesText.y = 1250; codesText.interactive = true; codesText.down = function () { hideMainMenu(); showCodesMenu(); }; mainMenuContainer.addChild(codesText); // Current level indicator var levelIndicatorText = new Text2('Continue from Level ' + currentLevel, { size: 50, fill: 0xFFFF00 }); levelIndicatorText.anchor.set(0.5, 0.5); levelIndicatorText.x = 1024; levelIndicatorText.y = 1350; mainMenuContainer.addChild(levelIndicatorText); // Enhanced coins display section with background var coinsDisplayBg = LK.getAsset('towerTop', { anchorX: 0.5, anchorY: 0.5, scaleX: 3.5, scaleY: 0.7, alpha: 0.4 }); coinsDisplayBg.x = 1024; coinsDisplayBg.y = 1450; mainMenuContainer.addChild(coinsDisplayBg); // Coins icon simulation using coin asset var coinsIcon = LK.getAsset('coin', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.5, scaleY: 1.5 }); coinsIcon.x = 850; coinsIcon.y = 1450; mainMenuContainer.addChild(coinsIcon); // Enhanced coins indicator with larger, more prominent text var coinsIndicatorText = new Text2('Your Coins: ' + playerCoins, { size: 55, fill: 0xFFD700 }); coinsIndicatorText.anchor.set(0.5, 0.5); coinsIndicatorText.x = 1100; coinsIndicatorText.y = 1450; mainMenuContainer.addChild(coinsIndicatorText); // Add subtle animation to coins display coinsIcon.rotationSpeed = 0.02; tween(coinsIcon, { rotation: Math.PI * 2 }, { duration: 3000, loop: true, easing: tween.linear }); // Add pulsing effect to coins text tween(coinsIndicatorText, { scaleX: 1.1, scaleY: 1.1 }, { duration: 1500, loop: true, yoyo: true, easing: tween.easeInOut }); // Enhanced total score display section with background var totalScoreDisplayBg = LK.getAsset('towerTop', { anchorX: 0.5, anchorY: 0.5, scaleX: 3.5, scaleY: 0.7, alpha: 0.4 }); totalScoreDisplayBg.x = 1024; totalScoreDisplayBg.y = 1520; mainMenuContainer.addChild(totalScoreDisplayBg); // Total score icon simulation using finish flag asset var scoreIcon = LK.getAsset('finishFlag', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.2, scaleY: 1.2 }); scoreIcon.x = 850; scoreIcon.y = 1520; scoreIcon.tint = 0x00FF00; mainMenuContainer.addChild(scoreIcon); // Enhanced total score indicator with larger, more prominent text var totalScoreIndicatorText = new Text2('Total Score: ' + totalScore, { size: 55, fill: 0x00FF00 }); totalScoreIndicatorText.anchor.set(0.5, 0.5); totalScoreIndicatorText.x = 1100; totalScoreIndicatorText.y = 1520; mainMenuContainer.addChild(totalScoreIndicatorText); // Add subtle animation to score display scoreIcon.rotationSpeed = 0.015; tween(scoreIcon, { rotation: Math.PI * 2 }, { duration: 4000, loop: true, easing: tween.linear }); // Add pulsing effect to total score text tween(totalScoreIndicatorText, { scaleX: 1.1, scaleY: 1.1 }, { duration: 1800, loop: true, yoyo: true, easing: tween.easeInOut }); // Version display at bottom of menu var versionText = new Text2('Version: 0.00.02', { size: 45, fill: 0x888888 }); versionText.anchor.set(0.5, 0.5); versionText.x = 1024; versionText.y = 1620; mainMenuContainer.addChild(versionText); // Add subtle fade animation to version text versionText.alpha = 0.7; tween(versionText, { alpha: 1 }, { duration: 2000, loop: true, yoyo: true, easing: tween.easeInOut }); } // Function to show codes menu function showCodesMenu() { showingCodesMenu = true; codesMenuContainer = new Container(); game.addChild(codesMenuContainer); // Create layered background for depth effect var outerBorder = LK.getAsset('towerBase', { anchorX: 0.5, anchorY: 0.5, scaleX: 11, scaleY: 4.5, alpha: 0.2 }); outerBorder.x = 1024; outerBorder.y = 1366; codesMenuContainer.addChild(outerBorder); // Main background with gradient effect var codesBg = LK.getAsset('towerBase', { anchorX: 0.5, anchorY: 0.5, scaleX: 10.5, scaleY: 4.2, alpha: 0.95 }); codesBg.x = 1024; codesBg.y = 1366; codesMenuContainer.addChild(codesBg); // Inner frame for modern look var innerFrame = LK.getAsset('towerBase', { anchorX: 0.5, anchorY: 0.5, scaleX: 10, scaleY: 4, alpha: 0.15 }); innerFrame.x = 1024; innerFrame.y = 1366; codesMenuContainer.addChild(innerFrame); // Title with enhanced styling and glow effect var titleBg = LK.getAsset('towerTop', { anchorX: 0.5, anchorY: 0.5, scaleX: 4, scaleY: 1, alpha: 0.4 }); titleBg.x = 1024; titleBg.y = 750; codesMenuContainer.addChild(titleBg); var titleText = new Text2('ENTER CODE', { size: 95, fill: 0xFFD700 }); titleText.anchor.set(0.5, 0.5); titleText.x = 1024; titleText.y = 750; codesMenuContainer.addChild(titleText); // Add animated title underline var titleUnderline = LK.getAsset('finishLine', { anchorX: 0.5, anchorY: 0.5, scaleX: 0, scaleY: 0.15 }); titleUnderline.x = 1024; titleUnderline.y = 815; codesMenuContainer.addChild(titleUnderline); // Animate underline appearance tween(titleUnderline, { scaleX: 5 }, { duration: 800, easing: tween.easeOut }); // Enhanced code input display with multiple layers var inputOuterBorder = LK.getAsset('towerBase', { anchorX: 0.5, anchorY: 0.5, scaleX: 6.5, scaleY: 0.65, alpha: 0.2 }); inputOuterBorder.x = 1024; inputOuterBorder.y = 950; codesMenuContainer.addChild(inputOuterBorder); var inputBg = LK.getAsset('towerBase', { anchorX: 0.5, anchorY: 0.5, scaleX: 6, scaleY: 0.55, alpha: 0.4 }); inputBg.x = 1024; inputBg.y = 950; codesMenuContainer.addChild(inputBg); var inputInner = LK.getAsset('towerTop', { anchorX: 0.5, anchorY: 0.5, scaleX: 5.5, scaleY: 0.45, alpha: 0.8 }); inputInner.x = 1024; inputInner.y = 950; codesMenuContainer.addChild(inputInner); var codeInputText = new Text2('', { size: 70, fill: 0x000000 }); codeInputText.anchor.set(0.5, 0.5); codeInputText.x = 1024; codeInputText.y = 950; codesMenuContainer.addChild(codeInputText); // Enhanced instructions with icon-like styling var instructionBg = LK.getAsset('towerTop', { anchorX: 0.5, anchorY: 0.5, scaleX: 4.5, scaleY: 0.4, alpha: 0.3 }); instructionBg.x = 1024; instructionBg.y = 1050; codesMenuContainer.addChild(instructionBg); var instructionText = new Text2('Tap keys below to enter your code', { size: 48, fill: 0xF0F0F0 }); instructionText.anchor.set(0.5, 0.5); instructionText.x = 1024; instructionText.y = 1050; codesMenuContainer.addChild(instructionText); // Create enhanced virtual keyboard with modern styling var currentCode = ''; var keyboardRows = ['QWERTYUIOP', 'ASDFGHJKL', 'ZXCVBNM']; var keySize = 70; var keySpacing = 130; var rowSpacing = 140; // Calculate starting positions for each row to center them perfectly with improved spacing var rowStartPositions = [1024 - (keyboardRows[0].length - 1) * keySpacing / 2, // QWERTY row 1024 - (keyboardRows[1].length - 1) * keySpacing / 2, // ASDF row 1024 - (keyboardRows[2].length - 1) * keySpacing / 2 // ZXCV row ]; for (var row = 0; row < keyboardRows.length; row++) { var letters = keyboardRows[row]; for (var col = 0; col < letters.length; col++) { var letter = letters[col]; // Create layered key design for modern look var keyShadow = LK.getAsset('towerBase', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.45, scaleY: 0.65, alpha: 0.3 }); keyShadow.x = rowStartPositions[row] + col * keySpacing + 2; keyShadow.y = 1320 + row * rowSpacing + 2; codesMenuContainer.addChild(keyShadow); var keyBg = LK.getAsset('towerTop', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.48, scaleY: 0.65, alpha: 0.9 }); keyBg.x = rowStartPositions[row] + col * keySpacing; keyBg.y = 1320 + row * rowSpacing; codesMenuContainer.addChild(keyBg); var keyHighlight = LK.getAsset('towerTop', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.44, scaleY: 0.61, alpha: 0.6 }); keyHighlight.x = rowStartPositions[row] + col * keySpacing; keyHighlight.y = 1315 + row * rowSpacing; codesMenuContainer.addChild(keyHighlight); var keyText = new Text2(letter, { size: 140, fill: 0x000000 }); keyText.anchor.set(0.5, 0.5); keyText.x = rowStartPositions[row] + col * keySpacing; keyText.y = 1320 + row * rowSpacing; keyText.interactive = true; keyText.letter = letter; keyText.keyBg = keyBg; keyText.keyHighlight = keyHighlight; keyText.keyShadow = keyShadow; keyText.down = function () { // Enhanced button press animation with multiple elements tween(this, { scaleX: 1.15, scaleY: 1.15, y: this.y + 3 }, { duration: 80, onFinish: function () { tween(this, { scaleX: 1, scaleY: 1, y: this.y - 3 }, { duration: 120, easing: tween.easeOut }); }.bind(this) }); // Animate key background tween(this.keyBg, { scaleX: 0.48, scaleY: 0.68, alpha: 1 }, { duration: 80, onFinish: function () { tween(this.keyBg, { scaleX: 0.42, scaleY: 0.62, alpha: 0.9 }, { duration: 120 }); }.bind(this) }); // Animate highlight tween(this.keyHighlight, { scaleX: 0.44, scaleY: 0.64, alpha: 0.8 }, { duration: 80, onFinish: function () { tween(this.keyHighlight, { scaleX: 0.38, scaleY: 0.58, alpha: 0.6 }, { duration: 120 }); }.bind(this) }); if (currentCode.length < 25) { currentCode += this.letter; codeInputText.setText(currentCode); // Animate input text when adding character tween(codeInputText, { scaleX: 1.1, scaleY: 1.1 }, { duration: 100, onFinish: function onFinish() { tween(codeInputText, { scaleX: 1, scaleY: 1 }, { duration: 100 }); } }); } }; codesMenuContainer.addChild(keyText); } } // Add numbers row (0-9) above the letters var numbersRow = '0123456789'; var numberRowY = 1120; var numberRowStartX = 1024 - (numbersRow.length - 1) * keySpacing / 2; for (var numCol = 0; numCol < numbersRow.length; numCol++) { var number = numbersRow[numCol]; // Add number key shadow for depth var numKeyShadow = LK.getAsset('towerBase', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.51, scaleY: 0.68, alpha: 0.3 }); numKeyShadow.x = numberRowStartX + numCol * keySpacing + 2; numKeyShadow.y = numberRowY + 2; codesMenuContainer.addChild(numKeyShadow); // Add number key background var numKeyBg = LK.getAsset('towerTop', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.48, scaleY: 0.65, alpha: 0.9 }); numKeyBg.x = numberRowStartX + numCol * keySpacing; numKeyBg.y = numberRowY; codesMenuContainer.addChild(numKeyBg); // Add number key highlight var numKeyHighlight = LK.getAsset('towerTop', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.44, scaleY: 0.61, alpha: 0.6 }); numKeyHighlight.x = numberRowStartX + numCol * keySpacing; numKeyHighlight.y = numberRowY - 2; codesMenuContainer.addChild(numKeyHighlight); var numKeyText = new Text2(number, { size: 135, fill: 0x0080FF }); numKeyText.anchor.set(0.5, 0.5); numKeyText.x = numberRowStartX + numCol * keySpacing; numKeyText.y = numberRowY; numKeyText.interactive = true; numKeyText.letter = number; numKeyText.keyBg = numKeyBg; numKeyText.keyHighlight = numKeyHighlight; numKeyText.keyShadow = numKeyShadow; numKeyText.down = function () { // Enhanced button press animation matching letter keys tween(this, { scaleX: 1.15, scaleY: 1.15, y: this.y + 3 }, { duration: 80, onFinish: function () { tween(this, { scaleX: 1, scaleY: 1, y: this.y - 3 }, { duration: 120, easing: tween.easeOut }); }.bind(this) }); // Animate key background tween(this.keyBg, { scaleX: 0.54, scaleY: 0.71, alpha: 1 }, { duration: 80, onFinish: function () { tween(this.keyBg, { scaleX: 0.48, scaleY: 0.65, alpha: 0.9 }, { duration: 120 }); }.bind(this) }); // Animate highlight tween(this.keyHighlight, { scaleX: 0.50, scaleY: 0.67, alpha: 0.8 }, { duration: 80, onFinish: function () { tween(this.keyHighlight, { scaleX: 0.44, scaleY: 0.61, alpha: 0.6 }, { duration: 120 }); }.bind(this) }); if (currentCode.length < 25) { currentCode += this.letter; codeInputText.setText(currentCode); // Animate input text when adding character tween(codeInputText, { scaleX: 1.1, scaleY: 1.1 }, { duration: 100, onFinish: function onFinish() { tween(codeInputText, { scaleX: 1, scaleY: 1 }, { duration: 100 }); } }); } }; codesMenuContainer.addChild(numKeyText); } // Create enhanced control button layout with improved design var buttonY = 1720; var buttonSpacing = 280; // Clear button with layered design (left) var clearShadow = LK.getAsset('towerBase', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.3, scaleY: 0.85, alpha: 0.3 }); clearShadow.x = 1024 - buttonSpacing + 3; clearShadow.y = buttonY + 3; codesMenuContainer.addChild(clearShadow); var clearBg = LK.getAsset('towerTop', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.25, scaleY: 0.82, alpha: 0.9 }); clearBg.x = 1024 - buttonSpacing; clearBg.y = buttonY; codesMenuContainer.addChild(clearBg); var clearHighlight = LK.getAsset('towerTop', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.1, scaleY: 0.68, alpha: 0.4 }); clearHighlight.x = 1024 - buttonSpacing; clearHighlight.y = buttonY - 5; codesMenuContainer.addChild(clearHighlight); var clearText = new Text2('CLEAR', { size: 58, fill: 0x000000 }); clearText.anchor.set(0.5, 0.5); clearText.x = 1024 - buttonSpacing; clearText.y = buttonY; clearText.interactive = true; clearText.clearBg = clearBg; clearText.clearHighlight = clearHighlight; clearText.down = function () { // Enhanced button animation with 3D effect tween(this, { scaleX: 1.05, scaleY: 1.05, y: this.y + 2 }, { duration: 80, onFinish: function () { tween(this, { scaleX: 1, scaleY: 1, y: this.y - 2 }, { duration: 120, easing: tween.easeOut }); }.bind(this) }); // Animate background elements tween(this.clearBg, { scaleX: 1.35, scaleY: 0.9, alpha: 1 }, { duration: 80, onFinish: function () { tween(this.clearBg, { scaleX: 1.25, scaleY: 0.82, alpha: 0.9 }, { duration: 120 }); }.bind(this) }); currentCode = ''; codeInputText.setText(''); // Animate input clearing tween(codeInputText, { alpha: 0.3 }, { duration: 200, onFinish: function onFinish() { tween(codeInputText, { alpha: 1 }, { duration: 200 }); } }); }; codesMenuContainer.addChild(clearText); // Submit button with layered design (right) var submitShadow = LK.getAsset('towerBase', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.3, scaleY: 0.85, alpha: 0.3 }); submitShadow.x = 1024 + buttonSpacing + 3; submitShadow.y = buttonY + 3; codesMenuContainer.addChild(submitShadow); var submitBg = LK.getAsset('towerTop', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.25, scaleY: 0.82, alpha: 0.9 }); submitBg.x = 1024 + buttonSpacing; submitBg.y = buttonY; codesMenuContainer.addChild(submitBg); var submitHighlight = LK.getAsset('towerTop', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.1, scaleY: 0.68, alpha: 0.4 }); submitHighlight.x = 1024 + buttonSpacing; submitHighlight.y = buttonY - 5; codesMenuContainer.addChild(submitHighlight); var submitText = new Text2('SUBMIT', { size: 58, fill: 0x000000 }); submitText.anchor.set(0.5, 0.5); submitText.x = 1024 + buttonSpacing; submitText.y = buttonY; submitText.interactive = true; submitText.submitBg = submitBg; submitText.down = function () { // Enhanced button animation tween(this, { scaleX: 1.05, scaleY: 1.05, y: this.y + 2 }, { duration: 80, onFinish: function () { tween(this, { scaleX: 1, scaleY: 1, y: this.y - 2 }, { duration: 120, easing: tween.easeOut }); }.bind(this) }); tween(this.submitBg, { scaleX: 1.35, scaleY: 0.9, alpha: 1 }, { duration: 80, onFinish: function () { tween(this.submitBg, { scaleX: 1.25, scaleY: 0.82, alpha: 0.9 }, { duration: 120 }); }.bind(this) }); if (currentCode === 'ZKUIT1GAMESSTAFFMODE') { // Success animation before activating admin mode tween(codeInputText, { fill: 0x00FF00, scaleX: 1.2, scaleY: 1.2 }, { duration: 300, onFinish: function onFinish() { // Activate admin mode for 15 minutes adminMode = true; adminModeEndTime = Date.now() + 15 * 60 * 1000; // 15 minutes in milliseconds storage.adminModeEndTime = adminModeEndTime; hideCodesMenu(); showAdminMenu(); } }); } else if (currentCode === 'LEVELS') { // Success animation before showing levels menu tween(codeInputText, { fill: 0x00FF00, scaleX: 1.2, scaleY: 1.2 }, { duration: 300, onFinish: function onFinish() { hideCodesMenu(); showLevelsMenu(); } }); } else if (currentCode === 'RESETALL') { // Success animation before resetting to level 1 tween(codeInputText, { fill: 0x00FF00, scaleX: 1.2, scaleY: 1.2 }, { duration: 300, onFinish: function onFinish() { // Reset player progress to level 1 currentLevel = 1; storage.currentLevel = 1; levelScore = 0; towersToComplete = 5 * currentLevel; // Update game settings gameSettings.highestLevelReached = 1; storage.gameSettings = gameSettings; // Clear level and reset aircraft clearLevel(); aircraft.x = 300; aircraft.y = 1366; hideCodesMenu(); createMainMenu(); } }); } else if (currentCode === 'FREEMONEYBETA2025') { // Check if this code has already been used var usedCodes = storage.usedCodes || []; if (usedCodes.indexOf('FREEMONEYBETA2025') >= 0) { // Code already used - show error tween(codeInputText, { scaleX: 1.3, scaleY: 0.8, fill: 0xFF0000 }, { duration: 150, easing: tween.easeOut, onFinish: function onFinish() { tween(codeInputText, { scaleX: 1, scaleY: 1, fill: 0x000000 }, { duration: 300, easing: tween.easeInOut }); } }); currentCode = ''; codeInputText.setText('CODE ALREADY USED'); LK.setTimeout(function () { codeInputText.setText(''); }, 2000); } else { // Success animation before awarding coins tween(codeInputText, { fill: 0x00FF00, scaleX: 1.2, scaleY: 1.2 }, { duration: 300, onFinish: function onFinish() { // Award 200 coins playerCoins += 200; storage.playerCoins = playerCoins; // Mark code as used usedCodes.push('FREEMONEYBETA2025'); storage.usedCodes = usedCodes; // Flash screen gold for success LK.effects.flashScreen(0xFFD700, 500); // Play coin sound if available if (LK.getSound('coinCollect')) { LK.getSound('coinCollect').play(); } hideCodesMenu(); createMainMenu(); } }); } } else if (currentCode === 'ORANGEFREESKIN') { // Check if this code has already been used var usedCodes = storage.usedCodes || []; if (usedCodes.indexOf('ORANGEFREESKIN') >= 0) { // Code already used - show error tween(codeInputText, { scaleX: 1.3, scaleY: 0.8, fill: 0xFF0000 }, { duration: 150, easing: tween.easeOut, onFinish: function onFinish() { tween(codeInputText, { scaleX: 1, scaleY: 1, fill: 0x000000 }, { duration: 300, easing: tween.easeInOut }); } }); currentCode = ''; codeInputText.setText('CODE ALREADY USED'); LK.setTimeout(function () { codeInputText.setText(''); }, 2000); } else { // Success animation before awarding orange skin tween(codeInputText, { fill: 0xFF8000, scaleX: 1.2, scaleY: 1.2 }, { duration: 300, onFinish: function onFinish() { // Add orange aircraft to owned styles if not already owned if (ownedAircraftStyles.indexOf('orange') < 0) { ownedAircraftStyles.push('orange'); storage.ownedAircraftStyles = ownedAircraftStyles; } // Equip the orange skin immediately currentAircraftStyle = 'orange'; storage.currentAircraftStyle = currentAircraftStyle; updateAircraftStyle(); // Mark code as used usedCodes.push('ORANGEFREESKIN'); storage.usedCodes = usedCodes; // Flash screen orange for success LK.effects.flashScreen(0xFF8000, 500); // Play coin sound if available if (LK.getSound('coinCollect')) { LK.getSound('coinCollect').play(); } hideCodesMenu(); createMainMenu(); } }); } } else if (currentCode.indexOf('TPLEVELSTAFFLV') === 0) { // Extract level number from code (format: TPLEVELSTAFFLVnumero) var levelNumberStr = currentCode.substring(14); // Remove 'TPLEVELSTAFFLV' prefix var targetLevel = parseInt(levelNumberStr, 10); // Validate level number (must be between 1 and 100) if (!isNaN(targetLevel) && targetLevel >= 1 && targetLevel <= 100) { // Success animation before teleporting to level tween(codeInputText, { fill: 0x00FF00, scaleX: 1.2, scaleY: 1.2 }, { duration: 300, onFinish: function onFinish() { // Transport player to specified level currentLevel = targetLevel; storage.currentLevel = currentLevel; levelScore = 0; towersToComplete = 5 * currentLevel; // Update game settings if new level is higher than previous highest if (currentLevel > gameSettings.highestLevelReached) { gameSettings.highestLevelReached = currentLevel; storage.gameSettings = gameSettings; } // Clear level and reset aircraft clearLevel(); aircraft.x = 300; aircraft.y = 1366; hideCodesMenu(); createMainMenu(); } }); } else { // Invalid level number - treat as wrong code tween(codeInputText, { scaleX: 1.3, scaleY: 0.8, fill: 0xFF0000 }, { duration: 150, easing: tween.easeOut, onFinish: function onFinish() { tween(codeInputText, { scaleX: 1, scaleY: 1, fill: 0x000000 }, { duration: 300, easing: tween.easeInOut }); } }); currentCode = ''; codeInputText.setText('INVALID LEVEL'); LK.setTimeout(function () { codeInputText.setText(''); }, 2000); } } else { // Enhanced wrong code animation tween(codeInputText, { scaleX: 1.3, scaleY: 0.8, fill: 0xFF0000 }, { duration: 150, easing: tween.easeOut, onFinish: function onFinish() { tween(codeInputText, { scaleX: 1, scaleY: 1, fill: 0x000000 }, { duration: 300, easing: tween.easeInOut }); } }); currentCode = ''; codeInputText.setText('INVALID CODE'); LK.setTimeout(function () { codeInputText.setText(''); }, 2000); } }; codesMenuContainer.addChild(submitText); // Back button with enhanced design (centered at bottom) var backShadow = LK.getAsset('towerBase', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.1, scaleY: 0.75, alpha: 0.3 }); backShadow.x = 1024 + 2; backShadow.y = 1870 + 2; codesMenuContainer.addChild(backShadow); var backBg = LK.getAsset('towerTop', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.05, scaleY: 0.72, alpha: 0.9 }); backBg.x = 1024; backBg.y = 1870; codesMenuContainer.addChild(backBg); var backText = new Text2('BACK', { size: 58, fill: 0x000000 }); backText.anchor.set(0.5, 0.5); backText.x = 1024; backText.y = 1870; backText.interactive = true; backText.backBg = backBg; backText.down = function () { // Enhanced back button animation tween(this, { scaleX: 1.05, scaleY: 1.05, y: this.y + 2 }, { duration: 80, onFinish: function () { tween(this, { scaleX: 1, scaleY: 1, y: this.y - 2 }, { duration: 120, easing: tween.easeOut }); }.bind(this) }); tween(this.backBg, { scaleX: 1.15, scaleY: 0.8, alpha: 1 }, { duration: 80, onFinish: function () { tween(this.backBg, { scaleX: 1.05, scaleY: 0.72, alpha: 0.9 }, { duration: 120 }); }.bind(this) }); hideCodesMenu(); createMainMenu(); }; codesMenuContainer.addChild(backText); // Add sophisticated entrance animations with staggered timing // Animate title with bounce effect titleText.alpha = 0; titleText.scaleX = 0.3; titleText.scaleY = 0.3; titleText.y = titleText.y - 50; tween(titleText, { alpha: 1, scaleX: 1, scaleY: 1, y: titleText.y + 50 }, { duration: 800, easing: tween.bounceOut }); // Animate input area with cascading effect inputOuterBorder.alpha = 0; inputBg.alpha = 0; inputInner.alpha = 0; codeInputText.alpha = 0; instructionText.alpha = 0; instructionBg.alpha = 0; // Staggered input area animations tween(inputOuterBorder, { alpha: 0.2 }, { duration: 300 }); LK.setTimeout(function () { tween(inputBg, { alpha: 0.4 }, { duration: 300 }); }, 100); LK.setTimeout(function () { tween(inputInner, { alpha: 0.8 }, { duration: 300 }); }, 200); LK.setTimeout(function () { tween(codeInputText, { alpha: 1 }, { duration: 400 }); }, 300); LK.setTimeout(function () { tween(instructionBg, { alpha: 0.3 }, { duration: 300 }); }, 400); LK.setTimeout(function () { tween(instructionText, { alpha: 1 }, { duration: 400 }); }, 500); // Animate keyboard keys with wave effect for (var animRow = 0; animRow < keyboardRows.length; animRow++) { for (var animCol = 0; animCol < keyboardRows[animRow].length; animCol++) { (function (row, col) { LK.setTimeout(function () { var keyIndex = row * 10 + col; // Approximate index for timing var targetKey = codesMenuContainer.children.filter(function (child) { return child.letter && child.x === rowStartPositions[row] + col * keySpacing && child.y === 1320 + row * rowSpacing; })[0]; if (targetKey) { targetKey.alpha = 0; targetKey.scaleX = 0.5; targetKey.scaleY = 0.5; tween(targetKey, { alpha: 1, scaleX: 1, scaleY: 1 }, { duration: 300, easing: tween.easeOut }); } }, 600 + row * 50 + col * 20); })(animRow, animCol); } } // Animate number keys for (var numAnimCol = 0; numAnimCol < numbersRow.length; numAnimCol++) { (function (col) { LK.setTimeout(function () { var targetNumKey = codesMenuContainer.children.filter(function (child) { return child.letter && child.x === numberRowStartX + col * keySpacing && child.y === numberRowY; })[0]; if (targetNumKey) { targetNumKey.alpha = 0; targetNumKey.scaleX = 0.5; targetNumKey.scaleY = 0.5; tween(targetNumKey, { alpha: 1, scaleX: 1, scaleY: 1 }, { duration: 300, easing: tween.easeOut }); } }, 550 + col * 25); })(numAnimCol); } // Animate control buttons with final cascade LK.setTimeout(function () { clearText.alpha = 0; clearText.scaleX = 0.8; clearText.scaleY = 0.8; tween(clearText, { alpha: 1, scaleX: 1, scaleY: 1 }, { duration: 400, easing: tween.easeOut }); }, 1200); LK.setTimeout(function () { submitText.alpha = 0; submitText.scaleX = 0.8; submitText.scaleY = 0.8; tween(submitText, { alpha: 1, scaleX: 1, scaleY: 1 }, { duration: 400, easing: tween.easeOut }); }, 1300); LK.setTimeout(function () { backText.alpha = 0; backText.scaleX = 0.8; backText.scaleY = 0.8; tween(backText, { alpha: 1, scaleX: 1, scaleY: 1 }, { duration: 400, easing: tween.easeOut }); }, 1400); } // Function to show skins menu function showSkinsMenu() { var skinsMenuContainer = new Container(); game.addChild(skinsMenuContainer); // Main background var skinsBg = LK.getAsset('towerBase', { anchorX: 0.5, anchorY: 0.5, scaleX: 10, scaleY: 4.5, alpha: 0.9 }); skinsBg.x = 1024; skinsBg.y = 1366; skinsMenuContainer.addChild(skinsBg); // Title var titleText = new Text2('MY SKINS', { size: 80, fill: 0x9932CC }); titleText.anchor.set(0.5, 0.5); titleText.x = 1024; titleText.y = 450; skinsMenuContainer.addChild(titleText); // Display owned aircraft skins var centerX = 1024; var itemStartY = 700; var itemSpacing = 140; // Get all aircraft styles including orange if unlocked var searchAircraftStyles = aircraftStyles.slice(); var usedCodes = storage.usedCodes || []; if (usedCodes.indexOf('ORANGEFREESKIN') >= 0) { searchAircraftStyles.push(orangeAircraftStyle); } // Filter to show only owned skins var ownedSkins = searchAircraftStyles.filter(function (style) { return ownedAircraftStyles.indexOf(style.id) >= 0; }); // Aircraft skins section title var aircraftTitleText = new Text2('OWNED AIRCRAFT SKINS', { size: 55, fill: 0xFFFFFF }); aircraftTitleText.anchor.set(0.5, 0.5); aircraftTitleText.x = centerX; aircraftTitleText.y = 620; skinsMenuContainer.addChild(aircraftTitleText); // Display owned skins for (var s = 0; s < ownedSkins.length; s++) { var skinItem = ownedSkins[s]; var isEquipped = currentAircraftStyle === skinItem.id; // Item card var itemBg = LK.getAsset('towerTop', { anchorX: 0.5, anchorY: 0.5, scaleX: 6, scaleY: 1.2, alpha: isEquipped ? 0.9 : 0.7 }); itemBg.x = centerX; itemBg.y = itemStartY + s * itemSpacing; if (isEquipped) itemBg.tint = 0x00AA66; skinsMenuContainer.addChild(itemBg); // Aircraft preview var previewAircraft = LK.getAsset('aircraft', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.2, scaleY: 1.2 }); previewAircraft.x = centerX - 250; previewAircraft.y = itemStartY + s * itemSpacing; previewAircraft.tint = skinItem.color; skinsMenuContainer.addChild(previewAircraft); // Skin name var skinNameText = new Text2(skinItem.name, { size: 44, fill: 0x000000 }); skinNameText.anchor.set(0, 0.5); skinNameText.x = centerX - 120; skinNameText.y = itemStartY + s * itemSpacing; skinsMenuContainer.addChild(skinNameText); // Status or equip button var buttonText = isEquipped ? 'EQUIPPED' : 'EQUIP'; var buttonColor = isEquipped ? 0x888888 : 0x00AA00; var skinButton = new Text2(buttonText, { size: 38, fill: buttonColor }); skinButton.anchor.set(0.5, 0.5); skinButton.x = centerX + 200; skinButton.y = itemStartY + s * itemSpacing; skinButton.skinItem = skinItem; skinButton.isEquipped = isEquipped; if (!isEquipped) { skinButton.interactive = true; skinButton.down = function () { // Equip skin currentAircraftStyle = this.skinItem.id; storage.currentAircraftStyle = currentAircraftStyle; updateAircraftStyle(); LK.effects.flashScreen(0x00FF00, 300); // Refresh skins menu skinsMenuContainer.destroy(); showSkinsMenu(); }; } skinsMenuContainer.addChild(skinButton); } // Back button var backText = new Text2('BACK', { size: 50, fill: 0xFFFFFF }); backText.anchor.set(0.5, 0.5); backText.x = 1024; backText.y = 1800; backText.interactive = true; backText.down = function () { skinsMenuContainer.destroy(); createMainMenu(); }; skinsMenuContainer.addChild(backText); // Fade-in animation skinsMenuContainer.alpha = 0; tween(skinsMenuContainer, { alpha: 1 }, { duration: 300 }); } // Function to show shop function showShop() { showingShop = true; shopContainer = new Container(); game.addChild(shopContainer); // Simple main background var shopBg = LK.getAsset('towerBase', { anchorX: 0.5, anchorY: 0.5, scaleX: 10, scaleY: 4.5, alpha: 0.9 }); shopBg.x = 1024; shopBg.y = 1366; shopContainer.addChild(shopBg); // Clean title var titleText = new Text2('SHOP', { size: 80, fill: 0xFFD700 }); titleText.anchor.set(0.5, 0.5); titleText.x = 1024; titleText.y = 400; shopContainer.addChild(titleText); // Simple coins display var coinsDisplayText = new Text2('Coins: ' + playerCoins, { size: 50, fill: 0xFFD700 }); coinsDisplayText.anchor.set(0.5, 0.5); coinsDisplayText.x = 1024; coinsDisplayText.y = 480; shopContainer.addChild(coinsDisplayText); // Store reference to update coins display throughout shop shopContainer.coinsDisplayText = coinsDisplayText; // Add function to update coins display with animation shopContainer.updateCoinsDisplay = function (newAmount) { // Flash effect on coins change tween(this.coinsDisplayText, { scaleX: 1.2, scaleY: 1.2, fill: 0x00FF00 }, { duration: 200, onFinish: function () { this.coinsDisplayText.setText('Coins: ' + newAmount); tween(this.coinsDisplayText, { scaleX: 1, scaleY: 1, fill: 0xFFD700 }, { duration: 300, easing: tween.bounceOut }); }.bind(this) }); }; // Simple centered layout with increased spacing var centerX = 1024; var itemStartY = 600; var itemSpacing = 120; // Aircraft styles section title var aircraftTitleText = new Text2('AIRCRAFT STYLES', { size: 55, fill: 0xFFFFFF }); aircraftTitleText.anchor.set(0.5, 0.5); aircraftTitleText.x = centerX; aircraftTitleText.y = 560; shopContainer.addChild(aircraftTitleText); // Create display array without orange skin and filter out owned skins var displayAircraftStyles = aircraftStyles.filter(function (style) { return ownedAircraftStyles.indexOf(style.id) < 0; // Only show unowned skins }); // Aircraft items with clean design for (var a = 0; a < displayAircraftStyles.length; a++) { var aircraftItem = displayAircraftStyles[a]; var isOwned = ownedAircraftStyles.indexOf(aircraftItem.id) >= 0; var isEquipped = currentAircraftStyle === aircraftItem.id; // Simple item card var itemBg = LK.getAsset('towerTop', { anchorX: 0.5, anchorY: 0.5, scaleX: 6, scaleY: 1.2, alpha: isEquipped ? 0.9 : 0.7 }); itemBg.x = centerX; itemBg.y = itemStartY + a * itemSpacing; if (isEquipped) itemBg.tint = 0x00AA66; shopContainer.addChild(itemBg); // Aircraft preview var previewAircraft = LK.getAsset('aircraft', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.2, scaleY: 1.2 }); previewAircraft.x = centerX - 250; previewAircraft.y = itemStartY + a * itemSpacing; previewAircraft.tint = aircraftItem.color; shopContainer.addChild(previewAircraft); // Item name var itemNameText = new Text2(aircraftItem.name, { size: 44, fill: 0x000000 }); itemNameText.anchor.set(0, 0.5); itemNameText.x = centerX - 120; itemNameText.y = itemStartY + a * itemSpacing; shopContainer.addChild(itemNameText); // Purchase button var buttonText = isOwned ? isEquipped ? 'EQUIPPED' : 'EQUIP' : 'BUY ' + aircraftItem.price; var buttonColor = isOwned ? isEquipped ? 0x888888 : 0x00AA00 : playerCoins >= aircraftItem.price ? 0x0066CC : 0xCC0000; var itemButton = new Text2(buttonText, { size: 38, fill: buttonColor }); itemButton.anchor.set(0.5, 0.5); itemButton.x = centerX + 200; itemButton.y = itemStartY + a * itemSpacing; itemButton.aircraftItem = aircraftItem; itemButton.isOwned = isOwned; itemButton.isEquipped = isEquipped; if (!isEquipped) { itemButton.interactive = true; itemButton.down = function () { // Simple button animation tween(this, { scaleX: 1.1, scaleY: 1.1 }, { duration: 100, easing: tween.easeOut, onFinish: function () { tween(this, { scaleX: 1, scaleY: 1 }, { duration: 100 }); }.bind(this) }); if (this.isOwned) { // Equip item currentAircraftStyle = this.aircraftItem.id; storage.currentAircraftStyle = currentAircraftStyle; updateAircraftStyle(); LK.effects.flashScreen(0x00FF00, 300); hideShop(); showShop(); } else if (playerCoins >= this.aircraftItem.price) { // Purchase item playerCoins -= this.aircraftItem.price; storage.playerCoins = playerCoins; ownedAircraftStyles.push(this.aircraftItem.id); storage.ownedAircraftStyles = ownedAircraftStyles; currentAircraftStyle = this.aircraftItem.id; storage.currentAircraftStyle = currentAircraftStyle; updateAircraftStyle(); LK.effects.flashScreen(0xFFD700, 500); if (LK.getSound('coinCollect')) { LK.getSound('coinCollect').play(); } // Refresh shop to remove purchased item hideShop(); showShop(); } else { // Insufficient funds LK.effects.flashObject(this, 0xFF0000, 300); } }; } shopContainer.addChild(itemButton); } // Simple back button var backText = new Text2('BACK', { size: 50, fill: 0xFFFFFF }); backText.anchor.set(0.5, 0.5); backText.x = 1024; backText.y = 1800; backText.interactive = true; backText.down = function () { // Simple button animation tween(this, { scaleX: 1.1, scaleY: 1.1 }, { duration: 100, onFinish: function () { tween(this, { scaleX: 1, scaleY: 1 }, { duration: 100 }); }.bind(this) }); hideShop(); createMainMenu(); }; shopContainer.addChild(backText); // Simple fade-in animation shopContainer.alpha = 0; tween(shopContainer, { alpha: 1 }, { duration: 300 }); } // Function to hide shop function hideShop() { if (shopContainer) { shopContainer.destroy(); shopContainer = null; } showingShop = false; } // Function to update aircraft style function updateAircraftStyle() { // Create search array that includes orange skin if unlocked var searchAircraftStyles = aircraftStyles.slice(); var usedCodes = storage.usedCodes || []; if (usedCodes.indexOf('ORANGEFREESKIN') >= 0) { searchAircraftStyles.push(orangeAircraftStyle); } var styleData = searchAircraftStyles.find(function (style) { return style.id === currentAircraftStyle; }); if (styleData && aircraft) { // Apply color to main aircraft components aircraft.children[0].tint = styleData.color; // Main aircraft body aircraft.children[1].tint = styleData.color; // Main wing aircraft.children[4].tint = styleData.color; // Tail aircraft.children[5].tint = styleData.color; // Horizontal stabilizer // Apply slightly darker tint to engines and details var darkerTint = styleData.color * 0.8; if (aircraft.children[8]) aircraft.children[8].tint = darkerTint; // Left engine if (aircraft.children[9]) aircraft.children[9].tint = darkerTint; // Right engine if (aircraft.children[10]) aircraft.children[10].tint = darkerTint; // Left gear if (aircraft.children[11]) aircraft.children[11].tint = darkerTint; // Right gear } } // Function to hide codes menu function hideCodesMenu() { if (codesMenuContainer) { codesMenuContainer.destroy(); codesMenuContainer = null; } showingCodesMenu = false; } // Function to show levels menu function showLevelsMenu() { var levelsMenuContainer = new Container(); game.addChild(levelsMenuContainer); // Semi-transparent background var levelsBg = LK.getAsset('towerBase', { anchorX: 0.5, anchorY: 0.5, scaleX: 10, scaleY: 4.5, alpha: 0.95 }); levelsBg.x = 1024; levelsBg.y = 1366; levelsMenuContainer.addChild(levelsBg); // Title var titleText = new Text2('ALL LEVELS', { size: 90, fill: 0xFFD700 }); titleText.anchor.set(0.5, 0.5); titleText.x = 1024; titleText.y = 400; levelsMenuContainer.addChild(titleText); // Subtitle with completion info var completedLevels = gameSettings.highestLevelReached; var subtitleText = new Text2('Completed: ' + completedLevels + '/100', { size: 60, fill: 0x00FF00 }); subtitleText.anchor.set(0.5, 0.5); subtitleText.x = 1024; subtitleText.y = 500; levelsMenuContainer.addChild(subtitleText); // Add coins balance display in levels menu var levelCoinsDisplayBg = LK.getAsset('towerTop', { anchorX: 0.5, anchorY: 0.5, scaleX: 2.5, scaleY: 0.5, alpha: 0.4 }); levelCoinsDisplayBg.x = 1024; levelCoinsDisplayBg.y = 550; levelsMenuContainer.addChild(levelCoinsDisplayBg); var levelCoinsText = new Text2('Your Coins: ' + playerCoins, { size: 45, fill: 0xFFD700 }); levelCoinsText.anchor.set(0.5, 0.5); levelCoinsText.x = 1024; levelCoinsText.y = 550; levelsMenuContainer.addChild(levelCoinsText); // Create scrollable container for levels var scrollContainer = new Container(); levelsMenuContainer.addChild(scrollContainer); // Create level display in grid format (10 columns, 10 rows for 100 levels) for (var level = 1; level <= 100; level++) { var isCompleted = level <= completedLevels; var levelButton = new Text2(level.toString(), { size: 35, fill: isCompleted ? 0x00FF00 : 0x888888 // Green if completed, gray if not }); levelButton.anchor.set(0.5, 0.5); // Position in 10x10 grid levelButton.x = 300 + (level - 1) % 10 * 145; levelButton.y = 650 + Math.floor((level - 1) / 10) * 60; // Add background for better visibility var levelBg = LK.getAsset('towerTop', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.7, scaleY: 0.7, alpha: isCompleted ? 0.8 : 0.3 }); levelBg.x = levelButton.x; levelBg.y = levelButton.y; scrollContainer.addChild(levelBg); scrollContainer.addChild(levelButton); // Add completion checkmark for completed levels if (isCompleted) { var checkmark = new Text2('✓', { size: 25, fill: 0xFFD700 }); checkmark.anchor.set(0.5, 0.5); checkmark.x = levelButton.x + 25; checkmark.y = levelButton.y - 25; scrollContainer.addChild(checkmark); } } // Add scroll instruction var scrollText = new Text2('Scroll to see all levels', { size: 45, fill: 0xFFFF00 }); scrollText.anchor.set(0.5, 0.5); scrollText.x = 1024; scrollText.y = 600; levelsMenuContainer.addChild(scrollText); // Add scroll functionality var scrollY = 0; var maxScroll = Math.max(0, Math.ceil(100 / 10) * 60 - 500); levelsMenuContainer.interactive = true; levelsMenuContainer.move = function (x, y, obj) { if (obj.deltaY) { scrollY -= obj.deltaY * 2; scrollY = Math.max(-maxScroll, Math.min(0, scrollY)); scrollContainer.y = scrollY; } }; // Back button var backText = new Text2('BACK', { size: 60, fill: 0xFF8000 }); backText.anchor.set(0.5, 0.5); backText.x = 1024; backText.y = 1600; backText.interactive = true; backText.down = function () { levelsMenuContainer.destroy(); createMainMenu(); }; levelsMenuContainer.addChild(backText); // Add entrance animation levelsMenuContainer.alpha = 0; tween(levelsMenuContainer, { alpha: 1 }, { duration: 500, easing: tween.easeOut }); } // Function to show admin menu function showAdminMenu() { var adminMenuContainer = new Container(); game.addChild(adminMenuContainer); // Semi-transparent background var adminBg = LK.getAsset('towerBase', { anchorX: 0.5, anchorY: 0.5, scaleX: 8, scaleY: 4, alpha: 0.9 }); adminBg.x = 1024; adminBg.y = 1366; adminMenuContainer.addChild(adminBg); // Title var titleText = new Text2('ADMIN MODE ACTIVATED', { size: 70, fill: 0xFF0000 }); titleText.anchor.set(0.5, 0.5); titleText.x = 1024; titleText.y = 600; adminMenuContainer.addChild(titleText); // Level selection title var levelSelectText = new Text2('SELECT LEVEL:', { size: 60, fill: 0xFFFFFF }); levelSelectText.anchor.set(0.5, 0.5); levelSelectText.x = 1024; levelSelectText.y = 800; adminMenuContainer.addChild(levelSelectText); // Create scrollable level buttons (1-100) var scrollContainer = new Container(); adminMenuContainer.addChild(scrollContainer); // Create level buttons in a grid layout for (var level = 1; level <= 100; level++) { var levelButton = new Text2(level.toString(), { size: 35, fill: 0x00FF00 }); levelButton.anchor.set(0.5, 0.5); // 10 columns, 10 rows for 100 levels levelButton.x = 300 + (level - 1) % 10 * 145; levelButton.y = 900 + Math.floor((level - 1) / 10) * 60; levelButton.interactive = true; levelButton.targetLevel = level; levelButton.down = function () { currentLevel = this.targetLevel; storage.currentLevel = currentLevel; adminMenuContainer.destroy(); createMainMenu(); }; scrollContainer.addChild(levelButton); } // Add scroll instruction text var scrollText = new Text2('Scroll to see all 100 levels', { size: 40, fill: 0xFFFF00 }); scrollText.anchor.set(0.5, 0.5); scrollText.x = 1024; scrollText.y = 850; adminMenuContainer.addChild(scrollText); // Add scroll functionality var scrollY = 0; var maxScroll = Math.max(0, Math.ceil(100 / 10) * 60 - 400); // Adjust based on visible area adminMenuContainer.interactive = true; adminMenuContainer.move = function (x, y, obj) { if (obj.deltaY) { scrollY -= obj.deltaY * 2; scrollY = Math.max(-maxScroll, Math.min(0, scrollY)); scrollContainer.y = scrollY; } }; // Back button var backText = new Text2('BACK TO MENU', { size: 50, fill: 0xFF8000 }); backText.anchor.set(0.5, 0.5); backText.x = 1024; backText.y = 1500; backText.interactive = true; backText.down = function () { adminMenuContainer.destroy(); createMainMenu(); }; adminMenuContainer.addChild(backText); } // Function to hide main menu function hideMainMenu() { if (mainMenuContainer) { mainMenuContainer.destroy(); mainMenuContainer = null; } showingMainMenu = false; } // Function to start game function startGame() { gameStarted = true; // Reset game state levelScore = 0; towersToComplete = 5 * currentLevel; invulnerabilityTime = 0; comboMultiplier = 1; powerUpSpawnTimer = 0; // Clear any existing game objects clearLevel(); // Reset aircraft position aircraft.x = 300; aircraft.y = 1366; // Update UI levelText.setText('Level: ' + currentLevel); progressText.setText('Progress: 0/' + towersToComplete); scoreText.setText('Score: ' + LK.getScore()); coinsText.setText('Coins: ' + playerCoins); // Apply current aircraft style updateAircraftStyle(); // Update aircraft speed for current level aircraft.speed = Math.min(5, 3 + (currentLevel - 1) * 0.1); // Start background music if (gameSettings.musicEnabled && !musicPlaying) { LK.stopMusic(); // Stop any menu music LK.playMusic('backgroundMusic', { loop: true }); musicPlaying = true; } } // Function to hide menu function hideMenu() { if (menuContainer) { menuContainer.destroy(); menuContainer = null; } showingMenu = false; gameStarted = true; } // Function to clear level objects function clearLevel() { // Clear existing towers for (var i = towers.length - 1; i >= 0; i--) { towers[i].destroy(); towers.splice(i, 1); } // Clear finish line if (finishLine) { finishLine.destroy(); finishLine = null; } // Clear existing clouds for (var c = clouds.length - 1; c >= 0; c--) { clouds[c].destroy(); clouds.splice(c, 1); } // Clear power-ups for (var p = powerUps.length - 1; p >= 0; p--) { powerUps[p].destroy(); powerUps.splice(p, 1); } // Clear particles for (var pt = particles.length - 1; pt >= 0; pt--) { particles[pt].destroy(); particles.splice(pt, 1); } // Clear spark particles for (var sp = sparkParticles.length - 1; sp >= 0; sp--) { sparkParticles[sp].destroy(); sparkParticles.splice(sp, 1); } // Clear coins for (var co = coins.length - 1; co >= 0; co--) { coins[co].destroy(); coins.splice(co, 1); } } // Function to complete level function completeLevel() { currentLevel++; // Save progress to storage storage.currentLevel = currentLevel; levelScore = 0; towersToComplete = 5 * currentLevel; // Level 1: 5, Level 2: 10, Level 3: 15, etc. // Reset power-up system invulnerabilityTime = 0; comboMultiplier = 1; powerUpSpawnTimer = 0; // Clear existing towers and finish line clearLevel(); // Reset aircraft position aircraft.x = 300; aircraft.y = 1366; // Update aircraft speed for new level aircraft.speed = Math.min(5, 3 + (currentLevel - 1) * 0.1); // Update UI levelText.setText('Level: ' + currentLevel); progressText.setText('Progress: 0/' + towersToComplete); // Enhanced level completion effects with camera shake startCameraShake(10, 60); // Gentle celebration shake LK.effects.flashScreen(0x00ff00, 1000); LK.getSound('levelComplete').play(); // Bonus score for completing level with progressive rewards var bonusScore = 100 * currentLevel * comboMultiplier; var milestoneBonus = 0; // Milestone bonuses for every 10 levels if (currentLevel % 10 === 0) { milestoneBonus = 1000 * (currentLevel / 10); playerCoins += 50; // Bonus coins for milestone storage.playerCoins = playerCoins; coinsText.setText('Coins: ' + playerCoins); } LK.setScore(LK.getScore() + bonusScore + milestoneBonus); scoreText.setText('Score: ' + LK.getScore()); // Update total score with session progress totalScore += bonusScore + milestoneBonus; storage.totalScore = totalScore; // Create celebration particles for (var i = 0; i < 10; i++) { LK.setTimeout(function () { createSparkParticle(aircraft.x + (Math.random() - 0.5) * 200, aircraft.y + (Math.random() - 0.5) * 100); }, i * 50); } } // Enhanced camera shake system var cameraShake = { active: false, intensity: 0, duration: 0, originalX: 0, originalY: 0 }; function startCameraShake(intensity, duration) { if (!gameSettings.screenshakeEnabled) return; cameraShake.active = true; cameraShake.intensity = intensity; cameraShake.duration = duration; cameraShake.originalX = game.x; cameraShake.originalY = game.y; } function updateCameraShake() { if (!cameraShake.active) return; cameraShake.duration--; if (cameraShake.duration <= 0) { cameraShake.active = false; game.x = cameraShake.originalX; game.y = cameraShake.originalY; return; } var shakeX = (Math.random() - 0.5) * cameraShake.intensity; var shakeY = (Math.random() - 0.5) * cameraShake.intensity; game.x = cameraShake.originalX + shakeX; game.y = cameraShake.originalY + shakeY; } // Function to handle game over function gameOver() { // Add current session score to total score totalScore += LK.getScore(); storage.totalScore = totalScore; // Save current level to storage so player can restart from this level storage.currentLevel = currentLevel; // Enhanced screen shake for dramatic effect startCameraShake(25, 120); LK.effects.flashScreen(0xff0000, 1000); LK.getSound('crash').play(); LK.showGameOver(); } // Main game update loop game.update = function () { // Update camera shake system updateCameraShake(); // Check if admin mode has expired if (adminMode && Date.now() > adminModeEndTime) { adminMode = false; adminModeEndTime = 0; storage.adminModeEndTime = 0; } if (!gameStarted || showingMenu || showingMainMenu || showingCodesMenu || showingShop) return; // Update invulnerability if (invulnerabilityTime > 0) { invulnerabilityTime--; if (invulnerabilityTime === 0) { aircraft.alpha = 1; // Restore normal appearance } } // Update combo multiplier decay if (LK.ticks - lastPowerUpTime > 1800) { // 30 seconds comboMultiplier = Math.max(1, comboMultiplier - 0.01); } // Spawn clouds for background atmosphere if (LK.ticks % 180 === 0) { // Spawn cloud every 3 seconds at 60fps spawnCloud(); } // Spawn coins coinSpawnTimer++; if (coinSpawnTimer > 180 + Math.random() * 120) { // Every 3-5 seconds spawnCoin(); coinSpawnTimer = 0; } // Spawn power-ups powerUpSpawnTimer++; if (powerUpSpawnTimer > 600 + Math.random() * 300) { // Every 10-15 seconds spawnPowerUp(); powerUpSpawnTimer = 0; } // Update clouds for (var c = clouds.length - 1; c >= 0; c--) { var cloud = clouds[c]; // Remove clouds that have moved off screen if (cloud.x < -200) { cloud.destroy(); clouds.splice(c, 1); } } // Update coins for (var co = coins.length - 1; co >= 0; co--) { var coin = coins[co]; // Remove if off screen if (coin.x < -100) { coin.destroy(); coins.splice(co, 1); continue; } // Check collection var coinIntersecting = aircraft.intersects(coin); if (!coin.lastIntersecting && coinIntersecting && !coin.collected) { coin.collected = true; playerCoins += 5; // Award 5 coins per collection storage.playerCoins = playerCoins; coinsText.setText('Coins: ' + playerCoins); // Coin collection effect LK.effects.flashObject(coin, 0xFFD700, 300); LK.getSound('coinCollect').play(); // Create coin text popup var coinPopup = new Text2('+5', { size: 40, fill: 0xFFD700 }); coinPopup.anchor.set(0.5, 0.5); coinPopup.x = coin.x; coinPopup.y = coin.y; game.addChild(coinPopup); tween(coinPopup, { y: coinPopup.y - 80, alpha: 0 }, { duration: 1000, easing: tween.easeOut, onFinish: function onFinish() { coinPopup.destroy(); } }); coin.destroy(); coins.splice(co, 1); continue; } coin.lastIntersecting = coinIntersecting; } // Update spark particles for (var sp = sparkParticles.length - 1; sp >= 0; sp--) { var spark = sparkParticles[sp]; // Particles are automatically removed in their update method } // Update power-ups for (var p = powerUps.length - 1; p >= 0; p--) { var powerUp = powerUps[p]; // Remove if off screen if (powerUp.x < -100) { powerUp.destroy(); powerUps.splice(p, 1); continue; } // Check collection var currentIntersecting = aircraft.intersects(powerUp); if (!powerUp.lastIntersecting && currentIntersecting && !powerUp.collected) { powerUp.collected = true; applyPowerUpEffect(); powerUp.destroy(); powerUps.splice(p, 1); continue; } powerUp.lastIntersecting = currentIntersecting; } // Spawn towers based on level difficulty (adjusted for levels 1-100) with increased separation var spawnRate = Math.max(90, 420 - Math.min(currentLevel, 15) * 20); // Increased base separation between tower pairs if (LK.ticks % spawnRate === 0) { spawnTower(); } // Check if we should spawn finish line - spawn exactly when progress reaches target var progress = Math.floor(levelScore / 2); if (progress === towersToComplete && !finishLine) { spawnFinishLine(); } // Update finish line if (finishLine) { // Check if finish line went off screen if (finishLine.lastX >= -200 && finishLine.x < -200) { finishLine.destroy(); finishLine = null; } // Check if aircraft crossed finish line if (!finishLine.crossed && finishLine.x < aircraft.x) { finishLine.crossed = true; createLevelMenu(); return; } } // Update towers for (var i = towers.length - 1; i >= 0; i--) { var tower = towers[i]; // Check if tower went off screen if (tower.lastX >= -200 && tower.x < -200) { towers.splice(i, 1); tower.destroy(); continue; } // Check collision with aircraft (skip if invulnerable) var currentIntersecting = aircraft.intersects(tower); if (!tower.lastIntersecting && currentIntersecting && invulnerabilityTime <= 0) { // Create dramatic collision effect createTowerDestructionEffect(tower.x, tower.y); startCameraShake(30, 100); LK.getSound('crash').play(); gameOver(); return; } tower.lastIntersecting = currentIntersecting; // Check if aircraft passed tower (score point) if (!tower.passed && tower.x < aircraft.x - 100) { tower.passed = true; levelScore++; var basePoints = 10 * currentLevel; var bonusPoints = Math.floor(basePoints * comboMultiplier); LK.setScore(LK.getScore() + bonusPoints); LK.getSound('dodge').play(); LK.getSound('whoosh').play(); // Update progress - count obstacles (pairs of towers) correctly var progress = Math.floor(levelScore / 2); // Two towers per obstacle pair progressText.setText('Progress: ' + progress + '/' + towersToComplete); scoreText.setText('Score: ' + LK.getScore()); // Create score popup for bonus points if (comboMultiplier > 1) { var bonusText = new Text2('+' + bonusPoints + ' (x' + comboMultiplier.toFixed(1) + ')', { size: 40, fill: 0xFFD700 }); bonusText.anchor.set(0.5, 0.5); bonusText.x = aircraft.x; bonusText.y = aircraft.y - 50; game.addChild(bonusText); // Animate bonus text tween(bonusText, { y: bonusText.y - 100, alpha: 0 }, { duration: 1000, easing: tween.easeOut, onFinish: function onFinish() { bonusText.destroy(); } }); } // Animate score text to highlight points earned tween.stop(scoreText, { scaleX: true, scaleY: true }); tween(scoreText, { scaleX: 1.3, scaleY: 1.3 }, { duration: 200, easing: tween.easeOut, onFinish: function onFinish() { tween(scoreText, { scaleX: 1, scaleY: 1 }, { duration: 200, easing: tween.easeIn }); } }); } } // Dynamic background color system based on level var targetBackgroundColor = 0x87CEFA; // Default sky blue if (currentLevel >= 80) { targetBackgroundColor = 0x2F1B69; // Deep purple for high levels } else if (currentLevel >= 60) { targetBackgroundColor = 0x1a1a2e; // Dark blue } else if (currentLevel >= 40) { targetBackgroundColor = 0x16213e; // Navy blue } else if (currentLevel >= 20) { targetBackgroundColor = 0x0f3460; // Medium blue } // Gradually transition background color every few seconds if (LK.ticks % 300 === 0) { // Every 5 seconds var currentBg = game.backgroundColor || 0x87CEFA; if (currentBg !== targetBackgroundColor) { // Simple color transition by setting it directly game.setBackgroundColor(targetBackgroundColor); } } // Aircraft stays stationary while towers move to create forward movement illusion };
/****
* Plugins
****/
var storage = LK.import("@upit/storage.v1");
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Aircraft = Container.expand(function () {
var self = Container.call(this);
// Main aircraft fuselage (body) - enhanced proportions
var aircraftGraphics = self.attachAsset('aircraft', {
anchorX: 0.5,
anchorY: 0.5
});
// Enhanced main wings with better positioning and scale
var mainWing = self.attachAsset('aircraftWing', {
anchorX: 0.5,
anchorY: 0.5
});
mainWing.x = -5; // Move forward for better balance
mainWing.y = 5; // Slightly lower on fuselage
mainWing.scaleX = 1.3; // Make wings larger
mainWing.scaleY = 1.5;
// Wing struts for realism
var leftWingStrut = self.attachAsset('aircraftEngine', {
anchorX: 0.5,
anchorY: 0.5
});
leftWingStrut.x = -10;
leftWingStrut.y = 18;
leftWingStrut.scaleX = 0.3;
leftWingStrut.scaleY = 2;
leftWingStrut.rotation = Math.PI / 4;
var rightWingStrut = self.attachAsset('aircraftEngine', {
anchorX: 0.5,
anchorY: 0.5
});
rightWingStrut.x = -10;
rightWingStrut.y = -8;
rightWingStrut.scaleX = 0.3;
rightWingStrut.scaleY = 2;
rightWingStrut.rotation = -Math.PI / 4;
// Enhanced aircraft tail with better proportions
var tail = self.attachAsset('aircraftTail', {
anchorX: 0.5,
anchorY: 0.5
});
tail.x = -65;
tail.y = 0;
tail.rotation = Math.PI / 2;
tail.scaleX = 1.2; // Make tail more prominent
tail.scaleY = 0.8;
// Horizontal stabilizer with improved positioning
var horizontalStab = self.attachAsset('aircraftWing', {
anchorX: 0.5,
anchorY: 0.5
});
horizontalStab.x = -58;
horizontalStab.y = 0;
horizontalStab.scaleX = 0.5;
horizontalStab.scaleY = 0.7;
// Enhanced cockpit with better visibility
var cockpit = self.attachAsset('aircraftCockpit', {
anchorX: 0.5,
anchorY: 0.5
});
cockpit.x = 40;
cockpit.y = -3;
cockpit.scaleX = 1.4; // Larger, more visible cockpit
cockpit.scaleY = 1.2;
// Wing tip fuel tanks for modern look
var leftWingTip = self.attachAsset('aircraftEngine', {
anchorX: 0.5,
anchorY: 0.5
});
leftWingTip.x = -5;
leftWingTip.y = 25;
leftWingTip.scaleX = 0.6;
leftWingTip.scaleY = 0.8;
var rightWingTip = self.attachAsset('aircraftEngine', {
anchorX: 0.5,
anchorY: 0.5
});
rightWingTip.x = -5;
rightWingTip.y = -15;
rightWingTip.scaleX = 0.6;
rightWingTip.scaleY = 0.8;
// Enhanced engine nacelles with better positioning
var leftEngine = self.attachAsset('aircraftEngine', {
anchorX: 0.5,
anchorY: 0.5
});
leftEngine.x = -15;
leftEngine.y = 15;
leftEngine.scaleX = 1.2;
leftEngine.scaleY = 1.3;
var rightEngine = self.attachAsset('aircraftEngine', {
anchorX: 0.5,
anchorY: 0.5
});
rightEngine.x = -15;
rightEngine.y = -5;
rightEngine.scaleX = 1.2;
rightEngine.scaleY = 1.3;
// Landing gear indicators (small details)
var leftGear = self.attachAsset('aircraftEngine', {
anchorX: 0.5,
anchorY: 0.5
});
leftGear.x = 15;
leftGear.y = 8;
leftGear.scaleX = 0.4;
leftGear.scaleY = 0.3;
var rightGear = self.attachAsset('aircraftEngine', {
anchorX: 0.5,
anchorY: 0.5
});
rightGear.x = 15;
rightGear.y = -8;
rightGear.scaleX = 0.4;
rightGear.scaleY = 0.3;
// Enhanced propeller with better positioning
var propeller = self.attachAsset('aircraftPropeller', {
anchorX: 0.5,
anchorY: 0.5
});
propeller.x = 75;
propeller.y = 0;
propeller.scaleX = 1.2; // Larger propeller
propeller.scaleY = 1.4;
// Secondary propeller blade for depth
var propellerBlade2 = self.attachAsset('aircraftPropeller', {
anchorX: 0.5,
anchorY: 0.5
});
propellerBlade2.x = 75;
propellerBlade2.y = 0;
propellerBlade2.scaleX = 1.2;
propellerBlade2.scaleY = 1.4;
propellerBlade2.rotation = Math.PI / 2; // 90 degrees offset
// Navigation lights
var leftNavLight = self.attachAsset('aircraftCockpit', {
anchorX: 0.5,
anchorY: 0.5
});
leftNavLight.x = -5;
leftNavLight.y = 30;
leftNavLight.scaleX = 0.3;
leftNavLight.scaleY = 0.3;
leftNavLight.tint = 0xFF0000; // Red navigation light
var rightNavLight = self.attachAsset('aircraftCockpit', {
anchorX: 0.5,
anchorY: 0.5
});
rightNavLight.x = -5;
rightNavLight.y = -20;
rightNavLight.scaleX = 0.3;
rightNavLight.scaleY = 0.3;
rightNavLight.tint = 0x00FF00; // Green navigation light
// Animate propeller rotation with both blades
propeller.rotationSpeed = 0.3;
propellerBlade2.rotationSpeed = 0.3;
// Progressive aircraft speed: starts at 3, increases by 0.1 per level, caps at level 20 (speed 5)
self.speed = Math.min(5, 3 + (currentLevel - 1) * 0.1);
self.lastY = 0;
self.update = function () {
// Update last position for collision detection
self.lastY = self.y;
// Animate both propeller blades spinning with variable speed
var propellerSpeed = propeller.rotationSpeed * (1 + self.speed * 0.1);
propeller.rotation += propellerSpeed;
propellerBlade2.rotation += propellerSpeed;
// Animate navigation lights blinking
if (LK.ticks % 120 < 60) {
// Blink every 2 seconds
leftNavLight.alpha = 1;
rightNavLight.alpha = 1;
} else {
leftNavLight.alpha = 0.3;
rightNavLight.alpha = 0.3;
}
// Create enhanced engine trail particles
if (LK.ticks % 3 === 0 && gameStarted) {
createEngineParticle(self.x - 50, self.y + 10); // Left engine trail
createEngineParticle(self.x - 50, self.y - 5); // Right engine trail
// Add occasional spark effects from both engines
if (Math.random() < 0.3) {
createSparkParticle(self.x - 40, self.y + (Math.random() - 0.5) * 20);
}
}
// Add subtle banking animation during movement
var bankingAngle = Math.sin(LK.ticks * 0.05) * 0.1;
self.rotation = bankingAngle;
// Add subtle floating animation for more dynamic feel
if (!self.floatingTween) {
self.floatingTween = true;
var originalY = self.y;
tween(self, {
y: originalY + 8
}, {
duration: 2000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(self, {
y: originalY - 8
}, {
duration: 2000,
easing: tween.easeInOut,
onFinish: function onFinish() {
self.floatingTween = false;
}
});
}
});
}
};
return self;
});
var Cloud = Container.expand(function () {
var self = Container.call(this);
// Choose random cloud type
var cloudTypes = ['cloud1', 'cloud2', 'cloud3'];
var cloudType = cloudTypes[Math.floor(Math.random() * cloudTypes.length)];
// Main cloud body
var mainCloud = self.attachAsset(cloudType, {
anchorX: 0.5,
anchorY: 0.5
});
// Add smaller cloud parts for more realistic shape
var cloud2 = self.attachAsset(cloudType, {
anchorX: 0.5,
anchorY: 0.5
});
cloud2.x = -30 + Math.random() * 60;
cloud2.y = -15 + Math.random() * 30;
cloud2.scaleX = 0.6 + Math.random() * 0.4;
cloud2.scaleY = 0.6 + Math.random() * 0.4;
cloud2.alpha = 0.8;
var cloud3 = self.attachAsset(cloudType, {
anchorX: 0.5,
anchorY: 0.5
});
cloud3.x = -20 + Math.random() * 40;
cloud3.y = -10 + Math.random() * 20;
cloud3.scaleX = 0.4 + Math.random() * 0.3;
cloud3.scaleY = 0.4 + Math.random() * 0.3;
cloud3.alpha = 0.6;
// Set random speed and scale
self.speed = 0.5 + Math.random() * 1.5;
self.scaleX = 0.8 + Math.random() * 0.6;
self.scaleY = 0.8 + Math.random() * 0.6;
self.alpha = 0.7 + Math.random() * 0.3;
self.update = function () {
// Move cloud from right to left
self.x -= self.speed;
};
return self;
});
var Coin = Container.expand(function () {
var self = Container.call(this);
// Coin visual
var coinGraphics = self.attachAsset('coin', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1.2
});
// Floating and spinning animation
self.floatOffset = Math.random() * Math.PI * 2;
self.collected = false;
self.update = function () {
// Floating animation
self.y += Math.sin(LK.ticks * 0.15 + self.floatOffset) * 0.8;
// Spinning animation
coinGraphics.rotation += 0.1;
// Pulsing scale effect
var scale = 1.2 + Math.sin(LK.ticks * 0.08) * 0.2;
coinGraphics.scaleX = scale;
coinGraphics.scaleY = scale;
// Move from right to left
var speed = Math.max(1.5, Math.min(6, 1.5 + currentLevel * 0.05));
self.x -= speed;
};
return self;
});
var FinishLine = Container.expand(function () {
var self = Container.call(this);
// Main finish line
var lineGraphics = self.attachAsset('finishLine', {
anchorX: 0.5,
anchorY: 0.5
});
// Add flags at top and bottom for visibility
var topFlag = self.attachAsset('finishFlag', {
anchorX: 0.5,
anchorY: 0.5
});
topFlag.y = -1300;
var bottomFlag = self.attachAsset('finishFlag', {
anchorX: 0.5,
anchorY: 0.5
});
bottomFlag.y = 1300;
self.lastX = 0;
self.crossed = false;
self.update = function () {
// Update last position before moving
self.lastX = self.x;
// Move finish line from right to left (match tower speed for levels 1-100)
var speed = Math.max(1.5, Math.min(6, 1.5 + currentLevel * 0.05)); // Match tower speed progression
self.x -= speed;
};
return self;
});
var Particle = Container.expand(function () {
var self = Container.call(this);
// Small particle visual
var particleGraphics = self.attachAsset('cloud1', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.1,
scaleY: 0.1
});
particleGraphics.alpha = 0.7;
particleGraphics.tint = 0xFF6600; // Orange-ish color
self.velocityX = -2 - Math.random() * 3;
self.velocityY = (Math.random() - 0.5) * 2;
self.life = 60; // 1 second at 60fps
self.update = function () {
self.x += self.velocityX;
self.y += self.velocityY;
self.life--;
particleGraphics.alpha *= 0.98; // Fade out
particleGraphics.scaleX *= 0.99; // Shrink
particleGraphics.scaleY *= 0.99;
if (self.life <= 0) {
self.destroy();
var index = particles.indexOf(self);
if (index > -1) particles.splice(index, 1);
}
};
return self;
});
var PowerUp = Container.expand(function () {
var self = Container.call(this);
// Power-up visual
var powerUpGraphics = self.attachAsset('finishFlag', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8
});
powerUpGraphics.tint = 0x00FFFF; // Cyan color for power-ups
// Floating animation
self.floatOffset = Math.random() * Math.PI * 2;
self.collected = false;
self.update = function () {
// Floating animation
self.y += Math.sin(LK.ticks * 0.1 + self.floatOffset) * 0.5;
// Rotation animation
powerUpGraphics.rotation += 0.05;
// Move from right to left
var speed = Math.max(1.5, Math.min(6, 1.5 + currentLevel * 0.05));
self.x -= speed;
};
return self;
});
var SparkParticle = Container.expand(function () {
var self = Container.call(this);
// Small spark visual
var sparkGraphics = self.attachAsset('coin', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.05,
scaleY: 0.05
});
sparkGraphics.alpha = 1;
sparkGraphics.tint = 0xFFAA00; // Orange spark color
self.velocityX = -1 - Math.random() * 2;
self.velocityY = (Math.random() - 0.5) * 3;
self.life = 30; // Half second at 60fps
self.update = function () {
self.x += self.velocityX;
self.y += self.velocityY;
self.velocityY += 0.1; // Gravity effect
self.life--;
sparkGraphics.alpha *= 0.95; // Faster fade than regular particles
sparkGraphics.scaleX *= 0.98;
sparkGraphics.scaleY *= 0.98;
sparkGraphics.rotation += 0.2; // Spinning effect
if (self.life <= 0) {
self.destroy();
var index = sparkParticles.indexOf(self);
if (index > -1) sparkParticles.splice(index, 1);
}
};
return self;
});
var Tower = Container.expand(function () {
var self = Container.call(this);
// Tower base
var towerBase = self.attachAsset('towerBase', {
anchorX: 0.5,
anchorY: 0.5
});
// Tower top
var towerTop = self.attachAsset('towerTop', {
anchorX: 0.5,
anchorY: 0.5
});
towerTop.y = -420; // Position at top of tower
// Add windows to make it look more realistic
for (var w = 0; w < 3; w++) {
var window1 = self.attachAsset('towerWindow', {
anchorX: 0.5,
anchorY: 0.5
});
window1.x = -30;
window1.y = -300 + w * 150;
var window2 = self.attachAsset('towerWindow', {
anchorX: 0.5,
anchorY: 0.5
});
window2.x = 30;
window2.y = -300 + w * 150;
}
self.lastX = 0;
self.passed = false;
self.update = function () {
// Update last position before moving
self.lastX = self.x;
// Move tower from right to left (progressive speed increase for levels 1-100)
var speed = Math.max(1.5, Math.min(6, 1.5 + currentLevel * 0.05)); // Gradual speed increase, capped at 6
self.x -= speed;
};
return self;
});
/****
* Initialize Game
****/
// Game variables
var game = new LK.Game({
backgroundColor: 0x87CEFA // More realistic sky blue background
});
/****
* Game Code
****/
//Storage plugin for persistent game data
// Game variables
// Initialize assets for the tower dodge flight game
var aircraft;
var towers = [];
var clouds = [];
var finishLine = null;
var showingMenu = false;
var currentLevel = storage.currentLevel || 1;
var levelScore = 0;
var towersToComplete = 5 * currentLevel; // Level 1: 5, Level 2: 10, Level 3: 15, etc.
var towerSpawnTimer = 0;
var gameStarted = false;
var menuContainer = null;
var mainMenuContainer = null;
var showingMainMenu = true;
var showingCodesMenu = false;
var codesMenuContainer = null;
var adminMode = false;
var adminModeEndTime = 0;
// Enhanced settings storage
var gameSettings = storage.gameSettings || {
soundEnabled: true,
musicEnabled: true,
difficulty: 'normal',
highestLevelReached: 1,
particlesEnabled: true,
screenshakeEnabled: true
};
// Additional game variables
var powerUps = [];
var particles = [];
var sparkParticles = [];
var powerUpSpawnTimer = 0;
var invulnerabilityTime = 0;
var comboMultiplier = 1;
var lastPowerUpTime = 0;
var musicPlaying = false;
var coins = [];
var coinSpawnTimer = 0;
var showingShop = false;
var shopContainer = null;
// Initialize player coins and shop items
var playerCoins = storage.playerCoins || 0;
var totalScore = storage.totalScore || 0;
var ownedAircraftStyles = storage.ownedAircraftStyles || ['default'];
var ownedTowerStyles = storage.ownedTowerStyles || ['default'];
var currentAircraftStyle = storage.currentAircraftStyle || 'default';
var currentTowerStyle = storage.currentTowerStyle || 'default';
// Shop items with prices
var aircraftStyles = [{
id: 'default',
name: 'Classic',
price: 0,
color: 0xf0f0f0
}, {
id: 'red',
name: 'Fire Bird',
price: 100,
color: 0xff4444
}, {
id: 'blue',
name: 'Sky Runner',
price: 150,
color: 0x4444ff
}, {
id: 'green',
name: 'Forest Wing',
price: 200,
color: 0x44ff44
}, {
id: 'purple',
name: 'Royal Jet',
price: 300,
color: 0x8844ff
}, {
id: 'gold',
name: 'Golden Eagle',
price: 500,
color: 0xffd700
}];
// Orange aircraft style - only available through code
var orangeAircraftStyle = {
id: 'orange',
name: 'Orange Flyer',
price: 0,
color: 0xff8000
};
var towerStyles = [{
id: 'default',
name: 'Stone Tower',
price: 0,
color: 0x8b4513
}, {
id: 'metal',
name: 'Metal Tower',
price: 120,
color: 0x778899
}, {
id: 'crystal',
name: 'Crystal Tower',
price: 180,
color: 0x99ddff
}, {
id: 'dark',
name: 'Dark Tower',
price: 250,
color: 0x444444
}, {
id: 'rainbow',
name: 'Rainbow Tower',
price: 400,
color: 0xff6699
}];
// Update settings when needed
if (currentLevel > gameSettings.highestLevelReached) {
gameSettings.highestLevelReached = currentLevel;
storage.gameSettings = gameSettings;
}
// Check if admin mode is still active from previous session
var storedAdminEndTime = storage.adminModeEndTime || 0;
if (storedAdminEndTime > Date.now()) {
adminMode = true;
adminModeEndTime = storedAdminEndTime;
}
// UI Elements
var levelText = new Text2('Level: 1', {
size: 60,
fill: 0xFFFFFF
});
levelText.anchor.set(0, 0);
LK.gui.topLeft.addChild(levelText);
levelText.x = 120; // Avoid top-left menu area
levelText.y = 20;
var scoreText = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreText.anchor.set(1, 0);
LK.gui.topRight.addChild(scoreText);
var progressText = new Text2('Progress: 0/10', {
size: 50,
fill: 0xFFFFFF
});
progressText.anchor.set(0.5, 0);
LK.gui.top.addChild(progressText);
progressText.y = 100;
var coinsText = new Text2('Coins: ' + playerCoins, {
size: 50,
fill: 0xFFD700
});
coinsText.anchor.set(0, 0);
LK.gui.topLeft.addChild(coinsText);
coinsText.x = 120;
coinsText.y = 80;
// Initialize aircraft
aircraft = game.addChild(new Aircraft());
aircraft.x = 300;
aircraft.y = 1366; // Center vertically
aircraft.lastIntersecting = false;
// Show main menu at start
createMainMenu();
// Touch controls for aircraft movement
var dragActive = false;
game.down = function (x, y, obj) {
if (showingMainMenu || showingMenu) return;
dragActive = true;
};
game.up = function (x, y, obj) {
if (showingMainMenu || showingMenu) return;
dragActive = false;
};
game.move = function (x, y, obj) {
if (showingMainMenu || showingMenu) return;
var targetY = y;
if (dragActive) {
targetY = y;
}
// Keep aircraft within screen bounds
if (targetY < 50) targetY = 50;
if (targetY > 2680) targetY = 2680;
// Smooth tween animation for aircraft movement
tween.stop(aircraft, {
y: true
});
tween(aircraft, {
y: targetY
}, {
duration: 200,
easing: tween.easeOut
});
};
// Function to spawn tower
function spawnTower() {
// Define imaginary boundary lines to delimit tower generation zone
var screenTop = 0;
var screenBottom = 2732;
var centerY = 1366; // Center of the screen
var safeZoneHeight = 1800; // Height of the safe generation zone (smaller than full screen)
var upperBoundary = centerY - safeZoneHeight / 2; // Top imaginary line
var lowerBoundary = centerY + safeZoneHeight / 2; // Bottom imaginary line
// Ensure boundaries are within screen limits with additional margin
upperBoundary = Math.max(200, upperBoundary); // Minimum 200px from top
lowerBoundary = Math.min(2532, lowerBoundary); // Maximum 200px from bottom
// Enhanced gap sizing with more generous minimum and smoother progression
var baseGapSize = 450; // Increased base gap size for better playability
var levelReduction = Math.min(currentLevel - 1, 30) * 8; // Slower reduction, cap at level 30
var gapSize = Math.max(380, baseGapSize - levelReduction); // Higher minimum gap (380px vs 350px)
// Aircraft dimensions for precise gap calculation
var aircraftHeight = 140; // Based on aircraft asset height
var safetyMargin = 50; // Extra margin for comfortable passage
var minRequiredGap = aircraftHeight + safetyMargin * 2; // Minimum theoretical gap needed
gapSize = Math.max(gapSize, minRequiredGap); // Ensure gap is never smaller than aircraft needs
// Tower generation zone constraints using imaginary boundary lines
var towerHeight = 800; // Tower base height from asset
var zoneMargin = 100; // Additional margin within the safe zone
var minGapCenter = upperBoundary + zoneMargin + gapSize / 2; // Use upper boundary line
var maxGapCenter = lowerBoundary - zoneMargin - gapSize / 2; // Use lower boundary line
// Ensure we have enough space for gap generation
if (maxGapCenter <= minGapCenter) {
// Fallback to center area if boundaries are too restrictive
minGapCenter = centerY - gapSize / 2;
maxGapCenter = centerY + gapSize / 2;
}
// Enhanced gap connection system to ensure continuity between tower pairs
var gapCenter;
if (towers.length === 0) {
// First tower pair - start in center area for safety
gapCenter = centerY;
} else {
// Find the most recent tower pair to connect with
var lastTopTower = null;
var lastBottomTower = null;
var lastGapCenter = centerY;
// Find the last tower pair by looking for the rightmost towers
for (var t = towers.length - 1; t >= 0; t--) {
var tower = towers[t];
if (!lastTopTower && tower.y < centerY) {
lastTopTower = tower;
} else if (!lastBottomTower && tower.y > centerY) {
lastBottomTower = tower;
}
if (lastTopTower && lastBottomTower) break;
}
// Calculate last gap center if we found both towers
if (lastTopTower && lastBottomTower) {
var lastGapTop = lastTopTower.y + towerHeight / 2;
var lastGapBottom = lastBottomTower.y - towerHeight / 2;
lastGapCenter = (lastGapTop + lastGapBottom) / 2;
}
// Create connecting gap within reasonable range of last gap
var connectionRange = gapSize * 0.8; // Allow gap to move within 80% of gap size
var minConnectionCenter = Math.max(minGapCenter, lastGapCenter - connectionRange);
var maxConnectionCenter = Math.min(maxGapCenter, lastGapCenter + connectionRange);
// Ensure we still have valid range
if (minConnectionCenter > maxConnectionCenter) {
minConnectionCenter = minGapCenter;
maxConnectionCenter = maxGapCenter;
}
gapCenter = minConnectionCenter + Math.random() * (maxConnectionCenter - minConnectionCenter);
}
var gapTop = gapCenter - gapSize / 2;
var gapBottom = gapCenter + gapSize / 2;
// Final boundary checks to ensure towers stay within imaginary lines
gapTop = Math.max(upperBoundary + zoneMargin, gapTop);
gapBottom = Math.min(lowerBoundary - zoneMargin, gapBottom);
gapSize = gapBottom - gapTop; // Recalculate actual gap size after boundary adjustments
// Ensure minimum gap size is maintained
if (gapSize < minRequiredGap) {
var adjustment = (minRequiredGap - gapSize) / 2;
gapTop -= adjustment;
gapBottom += adjustment;
// Re-check boundaries after adjustment
gapTop = Math.max(upperBoundary + zoneMargin, gapTop);
gapBottom = Math.min(lowerBoundary - zoneMargin, gapBottom);
}
// Create top tower with precise positioning
var topTower = game.addChild(new Tower());
topTower.x = 2200; // Start from right edge
// Position tower so its bottom edge aligns with gap top
topTower.y = gapTop - towerHeight / 2; // Center tower above gap
topTower.lastIntersecting = false;
towers.push(topTower);
// Apply current tower style
var currentTowerStyleData = towerStyles.find(function (style) {
return style.id === currentTowerStyle;
});
if (currentTowerStyleData) {
topTower.children[0].tint = currentTowerStyleData.color; // Tower base
topTower.children[1].tint = currentTowerStyleData.color; // Tower top
}
// Create bottom tower with precise positioning
var bottomTower = game.addChild(new Tower());
bottomTower.x = 2200; // Start from right edge
// Position tower so its top edge aligns with gap bottom
bottomTower.y = gapBottom + towerHeight / 2; // Center tower below gap
bottomTower.lastIntersecting = false;
towers.push(bottomTower);
// Apply current tower style
if (currentTowerStyleData) {
bottomTower.children[0].tint = currentTowerStyleData.color; // Tower base
bottomTower.children[1].tint = currentTowerStyleData.color; // Tower top
}
// Debug verification to ensure proper gap and boundary compliance
var actualGap = bottomTower.y - towerHeight / 2 - (topTower.y + towerHeight / 2);
if (actualGap < minRequiredGap) {
console.warn('Gap too small detected:', actualGap, 'Required:', minRequiredGap);
}
// Verify towers are within boundary lines
if (topTower.y + towerHeight / 2 < upperBoundary || bottomTower.y - towerHeight / 2 > lowerBoundary) {
console.warn('Tower positioned outside boundary lines');
}
}
// Function to spawn clouds
function spawnCloud() {
var cloud = new Cloud();
cloud.x = 2200 + Math.random() * 400; // Start from right edge with some variation
cloud.y = 200 + Math.random() * 2300; // Random height across screen
clouds.push(cloud);
game.addChild(cloud);
}
// Function to spawn finish line
function spawnFinishLine() {
if (finishLine) return; // Don't spawn if already exists
finishLine = game.addChild(new FinishLine());
finishLine.x = aircraft.x + 400; // Position finish line ahead of aircraft when progress completes
finishLine.y = 1366; // Center vertically
finishLine.lastIntersecting = false;
}
// Function to create engine particles
function createEngineParticle(x, y) {
if (!gameSettings.particlesEnabled || particles.length > 20) return;
var particle = new Particle();
particle.x = x + (Math.random() - 0.5) * 20;
particle.y = y + (Math.random() - 0.5) * 10;
particles.push(particle);
game.addChild(particle);
}
// Function to create spark particles
function createSparkParticle(x, y) {
if (!gameSettings.particlesEnabled || sparkParticles.length > 15) return;
var spark = new SparkParticle();
spark.x = x;
spark.y = y;
sparkParticles.push(spark);
game.addChild(spark);
}
// Function to create tower destruction effect
function createTowerDestructionEffect(x, y) {
if (!gameSettings.particlesEnabled) return;
// Create multiple debris particles
for (var i = 0; i < 8; i++) {
var debris = new Particle();
debris.x = x + (Math.random() - 0.5) * 100;
debris.y = y + (Math.random() - 0.5) * 200;
debris.children[0].tint = 0x8B4513; // Brown debris color
debris.velocityX = (Math.random() - 0.5) * 8;
debris.velocityY = -Math.random() * 5;
debris.life = 120; // Longer life for debris
particles.push(debris);
game.addChild(debris);
}
// Create sparks
for (var j = 0; j < 5; j++) {
createSparkParticle(x + (Math.random() - 0.5) * 80, y + (Math.random() - 0.5) * 150);
}
}
// Function to spawn coin
function spawnCoin() {
var coin = new Coin();
coin.x = 2200;
coin.y = 200 + Math.random() * 2300;
coin.lastIntersecting = false;
coins.push(coin);
game.addChild(coin);
}
// Function to spawn power-up
function spawnPowerUp() {
var powerUp = new PowerUp();
powerUp.x = 2200;
powerUp.y = 200 + Math.random() * 2300;
powerUp.lastIntersecting = false;
powerUps.push(powerUp);
game.addChild(powerUp);
}
// Function to apply power-up effect
function applyPowerUpEffect() {
invulnerabilityTime = 300; // 5 seconds at 60fps
comboMultiplier = Math.min(comboMultiplier + 0.5, 3); // Max 3x multiplier
lastPowerUpTime = LK.ticks;
// Visual feedback
LK.effects.flashObject(aircraft, 0x00FFFF, 500);
LK.getSound('powerup').play();
// Update aircraft appearance during invulnerability
tween(aircraft, {
alpha: 0.7
}, {
duration: 100,
onFinish: function onFinish() {
tween(aircraft, {
alpha: 1
}, {
duration: 100
});
}
});
}
// Function to create level completion menu
function createLevelMenu() {
showingMenu = true;
menuContainer = new Container();
game.addChild(menuContainer);
// Semi-transparent background
var menuBg = LK.getAsset('towerBase', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 8,
scaleY: 2,
alpha: 0.8
});
menuBg.x = 1024;
menuBg.y = 1366;
menuContainer.addChild(menuBg);
// Title text
var titleText = new Text2('Level ' + currentLevel + ' Complete!', {
size: 80,
fill: 0xFFFFFF
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
titleText.y = 1200;
menuContainer.addChild(titleText);
// Retry button
var retryText = new Text2('Retry Level', {
size: 60,
fill: 0x00FF00
});
retryText.anchor.set(0.5, 0.5);
retryText.x = 1024;
retryText.y = 1300;
retryText.interactive = true;
retryText.down = function () {
restartCurrentLevel();
};
menuContainer.addChild(retryText);
// Next level button
var nextText = new Text2('Next Level', {
size: 60,
fill: 0x0080FF
});
nextText.anchor.set(0.5, 0.5);
nextText.x = 1024;
nextText.y = 1400;
nextText.interactive = true;
nextText.down = function () {
goToNextLevel();
};
menuContainer.addChild(nextText);
// Return to level 1 button
var returnText = new Text2('Return to Level 1', {
size: 60,
fill: 0xFF8000
});
returnText.anchor.set(0.5, 0.5);
returnText.x = 1024;
returnText.y = 1500;
returnText.interactive = true;
returnText.down = function () {
returnToLevel1();
};
menuContainer.addChild(returnText);
}
// Function to restart current level
function restartCurrentLevel() {
hideMenu();
levelScore = 0;
// Clear existing towers and finish line
clearLevel();
// Reset aircraft position
aircraft.x = 300;
aircraft.y = 1366;
// Update aircraft speed for current level
aircraft.speed = Math.min(5, 3 + (currentLevel - 1) * 0.1);
// Update UI
progressText.setText('Progress: 0/' + towersToComplete);
}
// Function to go to next level
function goToNextLevel() {
hideMenu();
completeLevel();
}
// Function to return to level 1
function returnToLevel1() {
hideMenu();
currentLevel = 1;
storage.currentLevel = 1;
levelScore = 0;
towersToComplete = 5 * currentLevel;
// Clear existing towers and finish line
clearLevel();
// Reset aircraft position
aircraft.x = 300;
aircraft.y = 1366;
// Update aircraft speed for level 1
aircraft.speed = Math.min(5, 3 + (currentLevel - 1) * 0.1);
// Update UI
levelText.setText('Level: ' + currentLevel);
progressText.setText('Progress: 0/' + towersToComplete);
}
// Function to create main menu
function createMainMenu() {
showingMainMenu = true;
mainMenuContainer = new Container();
game.addChild(mainMenuContainer);
// Start menu music
if (gameSettings.musicEnabled) {
LK.stopMusic();
LK.playMusic('menuMusic', {
loop: true
});
musicPlaying = false; // Reset flag so game music can start
}
// Semi-transparent background
var menuBg = LK.getAsset('towerBase', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 10,
scaleY: 4,
alpha: 0.9
});
menuBg.x = 1024;
menuBg.y = 1366;
mainMenuContainer.addChild(menuBg);
// Game title
var titleText = new Text2('TOWER DODGE', {
size: 120,
fill: 0xFFD700
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
titleText.y = 600;
titleText.alpha = 0;
mainMenuContainer.addChild(titleText);
// Animate title entrance
tween(titleText, {
y: 750,
alpha: 1
}, {
duration: 1000,
easing: tween.bounceOut
});
// Subtitle
var subtitleText = new Text2('Navigate through the towers!', {
size: 60,
fill: 0xFFFFFF
});
subtitleText.anchor.set(0.5, 0.5);
subtitleText.x = 1024;
subtitleText.y = 850;
mainMenuContainer.addChild(subtitleText);
// Play button
var playText = new Text2('PLAY', {
size: 80,
fill: 0x00FF00
});
playText.anchor.set(0.5, 0.5);
playText.x = 1024;
playText.y = 1000;
playText.alpha = 0;
playText.scaleX = 0.5;
playText.scaleY = 0.5;
playText.interactive = true;
playText.down = function () {
// Add button press animation
tween(playText, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 100,
onFinish: function onFinish() {
tween(playText, {
scaleX: 1,
scaleY: 1
}, {
duration: 100
});
}
});
hideMainMenu();
startGame();
};
mainMenuContainer.addChild(playText);
// Animate play button entrance with delay
tween(playText, {
y: 1050,
alpha: 1,
scaleX: 1,
scaleY: 1
}, {
duration: 800,
easing: tween.elasticOut
});
// Shop button
var shopText = new Text2('SHOP', {
size: 80,
fill: 0x00FFFF
});
shopText.anchor.set(0.5, 0.5);
shopText.x = 724; // Position to the left of center
shopText.y = 1150;
shopText.interactive = true;
shopText.down = function () {
hideMainMenu();
showShop();
};
mainMenuContainer.addChild(shopText);
// Skins button
var skinsText = new Text2('SKINS', {
size: 80,
fill: 0x9932CC
});
skinsText.anchor.set(0.5, 0.5);
skinsText.x = 1324; // Position to the right of center
skinsText.y = 1150; // Same Y level as shop
skinsText.interactive = true;
skinsText.down = function () {
hideMainMenu();
showSkinsMenu();
};
mainMenuContainer.addChild(skinsText);
// Codes button
var codesText = new Text2('CODES', {
size: 80,
fill: 0xFF8000
});
codesText.anchor.set(0.5, 0.5);
codesText.x = 1024;
codesText.y = 1250;
codesText.interactive = true;
codesText.down = function () {
hideMainMenu();
showCodesMenu();
};
mainMenuContainer.addChild(codesText);
// Current level indicator
var levelIndicatorText = new Text2('Continue from Level ' + currentLevel, {
size: 50,
fill: 0xFFFF00
});
levelIndicatorText.anchor.set(0.5, 0.5);
levelIndicatorText.x = 1024;
levelIndicatorText.y = 1350;
mainMenuContainer.addChild(levelIndicatorText);
// Enhanced coins display section with background
var coinsDisplayBg = LK.getAsset('towerTop', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 3.5,
scaleY: 0.7,
alpha: 0.4
});
coinsDisplayBg.x = 1024;
coinsDisplayBg.y = 1450;
mainMenuContainer.addChild(coinsDisplayBg);
// Coins icon simulation using coin asset
var coinsIcon = LK.getAsset('coin', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
});
coinsIcon.x = 850;
coinsIcon.y = 1450;
mainMenuContainer.addChild(coinsIcon);
// Enhanced coins indicator with larger, more prominent text
var coinsIndicatorText = new Text2('Your Coins: ' + playerCoins, {
size: 55,
fill: 0xFFD700
});
coinsIndicatorText.anchor.set(0.5, 0.5);
coinsIndicatorText.x = 1100;
coinsIndicatorText.y = 1450;
mainMenuContainer.addChild(coinsIndicatorText);
// Add subtle animation to coins display
coinsIcon.rotationSpeed = 0.02;
tween(coinsIcon, {
rotation: Math.PI * 2
}, {
duration: 3000,
loop: true,
easing: tween.linear
});
// Add pulsing effect to coins text
tween(coinsIndicatorText, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 1500,
loop: true,
yoyo: true,
easing: tween.easeInOut
});
// Enhanced total score display section with background
var totalScoreDisplayBg = LK.getAsset('towerTop', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 3.5,
scaleY: 0.7,
alpha: 0.4
});
totalScoreDisplayBg.x = 1024;
totalScoreDisplayBg.y = 1520;
mainMenuContainer.addChild(totalScoreDisplayBg);
// Total score icon simulation using finish flag asset
var scoreIcon = LK.getAsset('finishFlag', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1.2
});
scoreIcon.x = 850;
scoreIcon.y = 1520;
scoreIcon.tint = 0x00FF00;
mainMenuContainer.addChild(scoreIcon);
// Enhanced total score indicator with larger, more prominent text
var totalScoreIndicatorText = new Text2('Total Score: ' + totalScore, {
size: 55,
fill: 0x00FF00
});
totalScoreIndicatorText.anchor.set(0.5, 0.5);
totalScoreIndicatorText.x = 1100;
totalScoreIndicatorText.y = 1520;
mainMenuContainer.addChild(totalScoreIndicatorText);
// Add subtle animation to score display
scoreIcon.rotationSpeed = 0.015;
tween(scoreIcon, {
rotation: Math.PI * 2
}, {
duration: 4000,
loop: true,
easing: tween.linear
});
// Add pulsing effect to total score text
tween(totalScoreIndicatorText, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 1800,
loop: true,
yoyo: true,
easing: tween.easeInOut
});
// Version display at bottom of menu
var versionText = new Text2('Version: 0.00.02', {
size: 45,
fill: 0x888888
});
versionText.anchor.set(0.5, 0.5);
versionText.x = 1024;
versionText.y = 1620;
mainMenuContainer.addChild(versionText);
// Add subtle fade animation to version text
versionText.alpha = 0.7;
tween(versionText, {
alpha: 1
}, {
duration: 2000,
loop: true,
yoyo: true,
easing: tween.easeInOut
});
}
// Function to show codes menu
function showCodesMenu() {
showingCodesMenu = true;
codesMenuContainer = new Container();
game.addChild(codesMenuContainer);
// Create layered background for depth effect
var outerBorder = LK.getAsset('towerBase', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 11,
scaleY: 4.5,
alpha: 0.2
});
outerBorder.x = 1024;
outerBorder.y = 1366;
codesMenuContainer.addChild(outerBorder);
// Main background with gradient effect
var codesBg = LK.getAsset('towerBase', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 10.5,
scaleY: 4.2,
alpha: 0.95
});
codesBg.x = 1024;
codesBg.y = 1366;
codesMenuContainer.addChild(codesBg);
// Inner frame for modern look
var innerFrame = LK.getAsset('towerBase', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 10,
scaleY: 4,
alpha: 0.15
});
innerFrame.x = 1024;
innerFrame.y = 1366;
codesMenuContainer.addChild(innerFrame);
// Title with enhanced styling and glow effect
var titleBg = LK.getAsset('towerTop', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 4,
scaleY: 1,
alpha: 0.4
});
titleBg.x = 1024;
titleBg.y = 750;
codesMenuContainer.addChild(titleBg);
var titleText = new Text2('ENTER CODE', {
size: 95,
fill: 0xFFD700
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
titleText.y = 750;
codesMenuContainer.addChild(titleText);
// Add animated title underline
var titleUnderline = LK.getAsset('finishLine', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0,
scaleY: 0.15
});
titleUnderline.x = 1024;
titleUnderline.y = 815;
codesMenuContainer.addChild(titleUnderline);
// Animate underline appearance
tween(titleUnderline, {
scaleX: 5
}, {
duration: 800,
easing: tween.easeOut
});
// Enhanced code input display with multiple layers
var inputOuterBorder = LK.getAsset('towerBase', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 6.5,
scaleY: 0.65,
alpha: 0.2
});
inputOuterBorder.x = 1024;
inputOuterBorder.y = 950;
codesMenuContainer.addChild(inputOuterBorder);
var inputBg = LK.getAsset('towerBase', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 6,
scaleY: 0.55,
alpha: 0.4
});
inputBg.x = 1024;
inputBg.y = 950;
codesMenuContainer.addChild(inputBg);
var inputInner = LK.getAsset('towerTop', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 5.5,
scaleY: 0.45,
alpha: 0.8
});
inputInner.x = 1024;
inputInner.y = 950;
codesMenuContainer.addChild(inputInner);
var codeInputText = new Text2('', {
size: 70,
fill: 0x000000
});
codeInputText.anchor.set(0.5, 0.5);
codeInputText.x = 1024;
codeInputText.y = 950;
codesMenuContainer.addChild(codeInputText);
// Enhanced instructions with icon-like styling
var instructionBg = LK.getAsset('towerTop', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 4.5,
scaleY: 0.4,
alpha: 0.3
});
instructionBg.x = 1024;
instructionBg.y = 1050;
codesMenuContainer.addChild(instructionBg);
var instructionText = new Text2('Tap keys below to enter your code', {
size: 48,
fill: 0xF0F0F0
});
instructionText.anchor.set(0.5, 0.5);
instructionText.x = 1024;
instructionText.y = 1050;
codesMenuContainer.addChild(instructionText);
// Create enhanced virtual keyboard with modern styling
var currentCode = '';
var keyboardRows = ['QWERTYUIOP', 'ASDFGHJKL', 'ZXCVBNM'];
var keySize = 70;
var keySpacing = 130;
var rowSpacing = 140;
// Calculate starting positions for each row to center them perfectly with improved spacing
var rowStartPositions = [1024 - (keyboardRows[0].length - 1) * keySpacing / 2,
// QWERTY row
1024 - (keyboardRows[1].length - 1) * keySpacing / 2,
// ASDF row
1024 - (keyboardRows[2].length - 1) * keySpacing / 2 // ZXCV row
];
for (var row = 0; row < keyboardRows.length; row++) {
var letters = keyboardRows[row];
for (var col = 0; col < letters.length; col++) {
var letter = letters[col];
// Create layered key design for modern look
var keyShadow = LK.getAsset('towerBase', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.45,
scaleY: 0.65,
alpha: 0.3
});
keyShadow.x = rowStartPositions[row] + col * keySpacing + 2;
keyShadow.y = 1320 + row * rowSpacing + 2;
codesMenuContainer.addChild(keyShadow);
var keyBg = LK.getAsset('towerTop', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.48,
scaleY: 0.65,
alpha: 0.9
});
keyBg.x = rowStartPositions[row] + col * keySpacing;
keyBg.y = 1320 + row * rowSpacing;
codesMenuContainer.addChild(keyBg);
var keyHighlight = LK.getAsset('towerTop', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.44,
scaleY: 0.61,
alpha: 0.6
});
keyHighlight.x = rowStartPositions[row] + col * keySpacing;
keyHighlight.y = 1315 + row * rowSpacing;
codesMenuContainer.addChild(keyHighlight);
var keyText = new Text2(letter, {
size: 140,
fill: 0x000000
});
keyText.anchor.set(0.5, 0.5);
keyText.x = rowStartPositions[row] + col * keySpacing;
keyText.y = 1320 + row * rowSpacing;
keyText.interactive = true;
keyText.letter = letter;
keyText.keyBg = keyBg;
keyText.keyHighlight = keyHighlight;
keyText.keyShadow = keyShadow;
keyText.down = function () {
// Enhanced button press animation with multiple elements
tween(this, {
scaleX: 1.15,
scaleY: 1.15,
y: this.y + 3
}, {
duration: 80,
onFinish: function () {
tween(this, {
scaleX: 1,
scaleY: 1,
y: this.y - 3
}, {
duration: 120,
easing: tween.easeOut
});
}.bind(this)
});
// Animate key background
tween(this.keyBg, {
scaleX: 0.48,
scaleY: 0.68,
alpha: 1
}, {
duration: 80,
onFinish: function () {
tween(this.keyBg, {
scaleX: 0.42,
scaleY: 0.62,
alpha: 0.9
}, {
duration: 120
});
}.bind(this)
});
// Animate highlight
tween(this.keyHighlight, {
scaleX: 0.44,
scaleY: 0.64,
alpha: 0.8
}, {
duration: 80,
onFinish: function () {
tween(this.keyHighlight, {
scaleX: 0.38,
scaleY: 0.58,
alpha: 0.6
}, {
duration: 120
});
}.bind(this)
});
if (currentCode.length < 25) {
currentCode += this.letter;
codeInputText.setText(currentCode);
// Animate input text when adding character
tween(codeInputText, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 100,
onFinish: function onFinish() {
tween(codeInputText, {
scaleX: 1,
scaleY: 1
}, {
duration: 100
});
}
});
}
};
codesMenuContainer.addChild(keyText);
}
}
// Add numbers row (0-9) above the letters
var numbersRow = '0123456789';
var numberRowY = 1120;
var numberRowStartX = 1024 - (numbersRow.length - 1) * keySpacing / 2;
for (var numCol = 0; numCol < numbersRow.length; numCol++) {
var number = numbersRow[numCol];
// Add number key shadow for depth
var numKeyShadow = LK.getAsset('towerBase', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.51,
scaleY: 0.68,
alpha: 0.3
});
numKeyShadow.x = numberRowStartX + numCol * keySpacing + 2;
numKeyShadow.y = numberRowY + 2;
codesMenuContainer.addChild(numKeyShadow);
// Add number key background
var numKeyBg = LK.getAsset('towerTop', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.48,
scaleY: 0.65,
alpha: 0.9
});
numKeyBg.x = numberRowStartX + numCol * keySpacing;
numKeyBg.y = numberRowY;
codesMenuContainer.addChild(numKeyBg);
// Add number key highlight
var numKeyHighlight = LK.getAsset('towerTop', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.44,
scaleY: 0.61,
alpha: 0.6
});
numKeyHighlight.x = numberRowStartX + numCol * keySpacing;
numKeyHighlight.y = numberRowY - 2;
codesMenuContainer.addChild(numKeyHighlight);
var numKeyText = new Text2(number, {
size: 135,
fill: 0x0080FF
});
numKeyText.anchor.set(0.5, 0.5);
numKeyText.x = numberRowStartX + numCol * keySpacing;
numKeyText.y = numberRowY;
numKeyText.interactive = true;
numKeyText.letter = number;
numKeyText.keyBg = numKeyBg;
numKeyText.keyHighlight = numKeyHighlight;
numKeyText.keyShadow = numKeyShadow;
numKeyText.down = function () {
// Enhanced button press animation matching letter keys
tween(this, {
scaleX: 1.15,
scaleY: 1.15,
y: this.y + 3
}, {
duration: 80,
onFinish: function () {
tween(this, {
scaleX: 1,
scaleY: 1,
y: this.y - 3
}, {
duration: 120,
easing: tween.easeOut
});
}.bind(this)
});
// Animate key background
tween(this.keyBg, {
scaleX: 0.54,
scaleY: 0.71,
alpha: 1
}, {
duration: 80,
onFinish: function () {
tween(this.keyBg, {
scaleX: 0.48,
scaleY: 0.65,
alpha: 0.9
}, {
duration: 120
});
}.bind(this)
});
// Animate highlight
tween(this.keyHighlight, {
scaleX: 0.50,
scaleY: 0.67,
alpha: 0.8
}, {
duration: 80,
onFinish: function () {
tween(this.keyHighlight, {
scaleX: 0.44,
scaleY: 0.61,
alpha: 0.6
}, {
duration: 120
});
}.bind(this)
});
if (currentCode.length < 25) {
currentCode += this.letter;
codeInputText.setText(currentCode);
// Animate input text when adding character
tween(codeInputText, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 100,
onFinish: function onFinish() {
tween(codeInputText, {
scaleX: 1,
scaleY: 1
}, {
duration: 100
});
}
});
}
};
codesMenuContainer.addChild(numKeyText);
}
// Create enhanced control button layout with improved design
var buttonY = 1720;
var buttonSpacing = 280;
// Clear button with layered design (left)
var clearShadow = LK.getAsset('towerBase', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.3,
scaleY: 0.85,
alpha: 0.3
});
clearShadow.x = 1024 - buttonSpacing + 3;
clearShadow.y = buttonY + 3;
codesMenuContainer.addChild(clearShadow);
var clearBg = LK.getAsset('towerTop', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.25,
scaleY: 0.82,
alpha: 0.9
});
clearBg.x = 1024 - buttonSpacing;
clearBg.y = buttonY;
codesMenuContainer.addChild(clearBg);
var clearHighlight = LK.getAsset('towerTop', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.1,
scaleY: 0.68,
alpha: 0.4
});
clearHighlight.x = 1024 - buttonSpacing;
clearHighlight.y = buttonY - 5;
codesMenuContainer.addChild(clearHighlight);
var clearText = new Text2('CLEAR', {
size: 58,
fill: 0x000000
});
clearText.anchor.set(0.5, 0.5);
clearText.x = 1024 - buttonSpacing;
clearText.y = buttonY;
clearText.interactive = true;
clearText.clearBg = clearBg;
clearText.clearHighlight = clearHighlight;
clearText.down = function () {
// Enhanced button animation with 3D effect
tween(this, {
scaleX: 1.05,
scaleY: 1.05,
y: this.y + 2
}, {
duration: 80,
onFinish: function () {
tween(this, {
scaleX: 1,
scaleY: 1,
y: this.y - 2
}, {
duration: 120,
easing: tween.easeOut
});
}.bind(this)
});
// Animate background elements
tween(this.clearBg, {
scaleX: 1.35,
scaleY: 0.9,
alpha: 1
}, {
duration: 80,
onFinish: function () {
tween(this.clearBg, {
scaleX: 1.25,
scaleY: 0.82,
alpha: 0.9
}, {
duration: 120
});
}.bind(this)
});
currentCode = '';
codeInputText.setText('');
// Animate input clearing
tween(codeInputText, {
alpha: 0.3
}, {
duration: 200,
onFinish: function onFinish() {
tween(codeInputText, {
alpha: 1
}, {
duration: 200
});
}
});
};
codesMenuContainer.addChild(clearText);
// Submit button with layered design (right)
var submitShadow = LK.getAsset('towerBase', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.3,
scaleY: 0.85,
alpha: 0.3
});
submitShadow.x = 1024 + buttonSpacing + 3;
submitShadow.y = buttonY + 3;
codesMenuContainer.addChild(submitShadow);
var submitBg = LK.getAsset('towerTop', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.25,
scaleY: 0.82,
alpha: 0.9
});
submitBg.x = 1024 + buttonSpacing;
submitBg.y = buttonY;
codesMenuContainer.addChild(submitBg);
var submitHighlight = LK.getAsset('towerTop', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.1,
scaleY: 0.68,
alpha: 0.4
});
submitHighlight.x = 1024 + buttonSpacing;
submitHighlight.y = buttonY - 5;
codesMenuContainer.addChild(submitHighlight);
var submitText = new Text2('SUBMIT', {
size: 58,
fill: 0x000000
});
submitText.anchor.set(0.5, 0.5);
submitText.x = 1024 + buttonSpacing;
submitText.y = buttonY;
submitText.interactive = true;
submitText.submitBg = submitBg;
submitText.down = function () {
// Enhanced button animation
tween(this, {
scaleX: 1.05,
scaleY: 1.05,
y: this.y + 2
}, {
duration: 80,
onFinish: function () {
tween(this, {
scaleX: 1,
scaleY: 1,
y: this.y - 2
}, {
duration: 120,
easing: tween.easeOut
});
}.bind(this)
});
tween(this.submitBg, {
scaleX: 1.35,
scaleY: 0.9,
alpha: 1
}, {
duration: 80,
onFinish: function () {
tween(this.submitBg, {
scaleX: 1.25,
scaleY: 0.82,
alpha: 0.9
}, {
duration: 120
});
}.bind(this)
});
if (currentCode === 'ZKUIT1GAMESSTAFFMODE') {
// Success animation before activating admin mode
tween(codeInputText, {
fill: 0x00FF00,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 300,
onFinish: function onFinish() {
// Activate admin mode for 15 minutes
adminMode = true;
adminModeEndTime = Date.now() + 15 * 60 * 1000; // 15 minutes in milliseconds
storage.adminModeEndTime = adminModeEndTime;
hideCodesMenu();
showAdminMenu();
}
});
} else if (currentCode === 'LEVELS') {
// Success animation before showing levels menu
tween(codeInputText, {
fill: 0x00FF00,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 300,
onFinish: function onFinish() {
hideCodesMenu();
showLevelsMenu();
}
});
} else if (currentCode === 'RESETALL') {
// Success animation before resetting to level 1
tween(codeInputText, {
fill: 0x00FF00,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 300,
onFinish: function onFinish() {
// Reset player progress to level 1
currentLevel = 1;
storage.currentLevel = 1;
levelScore = 0;
towersToComplete = 5 * currentLevel;
// Update game settings
gameSettings.highestLevelReached = 1;
storage.gameSettings = gameSettings;
// Clear level and reset aircraft
clearLevel();
aircraft.x = 300;
aircraft.y = 1366;
hideCodesMenu();
createMainMenu();
}
});
} else if (currentCode === 'FREEMONEYBETA2025') {
// Check if this code has already been used
var usedCodes = storage.usedCodes || [];
if (usedCodes.indexOf('FREEMONEYBETA2025') >= 0) {
// Code already used - show error
tween(codeInputText, {
scaleX: 1.3,
scaleY: 0.8,
fill: 0xFF0000
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(codeInputText, {
scaleX: 1,
scaleY: 1,
fill: 0x000000
}, {
duration: 300,
easing: tween.easeInOut
});
}
});
currentCode = '';
codeInputText.setText('CODE ALREADY USED');
LK.setTimeout(function () {
codeInputText.setText('');
}, 2000);
} else {
// Success animation before awarding coins
tween(codeInputText, {
fill: 0x00FF00,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 300,
onFinish: function onFinish() {
// Award 200 coins
playerCoins += 200;
storage.playerCoins = playerCoins;
// Mark code as used
usedCodes.push('FREEMONEYBETA2025');
storage.usedCodes = usedCodes;
// Flash screen gold for success
LK.effects.flashScreen(0xFFD700, 500);
// Play coin sound if available
if (LK.getSound('coinCollect')) {
LK.getSound('coinCollect').play();
}
hideCodesMenu();
createMainMenu();
}
});
}
} else if (currentCode === 'ORANGEFREESKIN') {
// Check if this code has already been used
var usedCodes = storage.usedCodes || [];
if (usedCodes.indexOf('ORANGEFREESKIN') >= 0) {
// Code already used - show error
tween(codeInputText, {
scaleX: 1.3,
scaleY: 0.8,
fill: 0xFF0000
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(codeInputText, {
scaleX: 1,
scaleY: 1,
fill: 0x000000
}, {
duration: 300,
easing: tween.easeInOut
});
}
});
currentCode = '';
codeInputText.setText('CODE ALREADY USED');
LK.setTimeout(function () {
codeInputText.setText('');
}, 2000);
} else {
// Success animation before awarding orange skin
tween(codeInputText, {
fill: 0xFF8000,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 300,
onFinish: function onFinish() {
// Add orange aircraft to owned styles if not already owned
if (ownedAircraftStyles.indexOf('orange') < 0) {
ownedAircraftStyles.push('orange');
storage.ownedAircraftStyles = ownedAircraftStyles;
}
// Equip the orange skin immediately
currentAircraftStyle = 'orange';
storage.currentAircraftStyle = currentAircraftStyle;
updateAircraftStyle();
// Mark code as used
usedCodes.push('ORANGEFREESKIN');
storage.usedCodes = usedCodes;
// Flash screen orange for success
LK.effects.flashScreen(0xFF8000, 500);
// Play coin sound if available
if (LK.getSound('coinCollect')) {
LK.getSound('coinCollect').play();
}
hideCodesMenu();
createMainMenu();
}
});
}
} else if (currentCode.indexOf('TPLEVELSTAFFLV') === 0) {
// Extract level number from code (format: TPLEVELSTAFFLVnumero)
var levelNumberStr = currentCode.substring(14); // Remove 'TPLEVELSTAFFLV' prefix
var targetLevel = parseInt(levelNumberStr, 10);
// Validate level number (must be between 1 and 100)
if (!isNaN(targetLevel) && targetLevel >= 1 && targetLevel <= 100) {
// Success animation before teleporting to level
tween(codeInputText, {
fill: 0x00FF00,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 300,
onFinish: function onFinish() {
// Transport player to specified level
currentLevel = targetLevel;
storage.currentLevel = currentLevel;
levelScore = 0;
towersToComplete = 5 * currentLevel;
// Update game settings if new level is higher than previous highest
if (currentLevel > gameSettings.highestLevelReached) {
gameSettings.highestLevelReached = currentLevel;
storage.gameSettings = gameSettings;
}
// Clear level and reset aircraft
clearLevel();
aircraft.x = 300;
aircraft.y = 1366;
hideCodesMenu();
createMainMenu();
}
});
} else {
// Invalid level number - treat as wrong code
tween(codeInputText, {
scaleX: 1.3,
scaleY: 0.8,
fill: 0xFF0000
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(codeInputText, {
scaleX: 1,
scaleY: 1,
fill: 0x000000
}, {
duration: 300,
easing: tween.easeInOut
});
}
});
currentCode = '';
codeInputText.setText('INVALID LEVEL');
LK.setTimeout(function () {
codeInputText.setText('');
}, 2000);
}
} else {
// Enhanced wrong code animation
tween(codeInputText, {
scaleX: 1.3,
scaleY: 0.8,
fill: 0xFF0000
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(codeInputText, {
scaleX: 1,
scaleY: 1,
fill: 0x000000
}, {
duration: 300,
easing: tween.easeInOut
});
}
});
currentCode = '';
codeInputText.setText('INVALID CODE');
LK.setTimeout(function () {
codeInputText.setText('');
}, 2000);
}
};
codesMenuContainer.addChild(submitText);
// Back button with enhanced design (centered at bottom)
var backShadow = LK.getAsset('towerBase', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.1,
scaleY: 0.75,
alpha: 0.3
});
backShadow.x = 1024 + 2;
backShadow.y = 1870 + 2;
codesMenuContainer.addChild(backShadow);
var backBg = LK.getAsset('towerTop', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.05,
scaleY: 0.72,
alpha: 0.9
});
backBg.x = 1024;
backBg.y = 1870;
codesMenuContainer.addChild(backBg);
var backText = new Text2('BACK', {
size: 58,
fill: 0x000000
});
backText.anchor.set(0.5, 0.5);
backText.x = 1024;
backText.y = 1870;
backText.interactive = true;
backText.backBg = backBg;
backText.down = function () {
// Enhanced back button animation
tween(this, {
scaleX: 1.05,
scaleY: 1.05,
y: this.y + 2
}, {
duration: 80,
onFinish: function () {
tween(this, {
scaleX: 1,
scaleY: 1,
y: this.y - 2
}, {
duration: 120,
easing: tween.easeOut
});
}.bind(this)
});
tween(this.backBg, {
scaleX: 1.15,
scaleY: 0.8,
alpha: 1
}, {
duration: 80,
onFinish: function () {
tween(this.backBg, {
scaleX: 1.05,
scaleY: 0.72,
alpha: 0.9
}, {
duration: 120
});
}.bind(this)
});
hideCodesMenu();
createMainMenu();
};
codesMenuContainer.addChild(backText);
// Add sophisticated entrance animations with staggered timing
// Animate title with bounce effect
titleText.alpha = 0;
titleText.scaleX = 0.3;
titleText.scaleY = 0.3;
titleText.y = titleText.y - 50;
tween(titleText, {
alpha: 1,
scaleX: 1,
scaleY: 1,
y: titleText.y + 50
}, {
duration: 800,
easing: tween.bounceOut
});
// Animate input area with cascading effect
inputOuterBorder.alpha = 0;
inputBg.alpha = 0;
inputInner.alpha = 0;
codeInputText.alpha = 0;
instructionText.alpha = 0;
instructionBg.alpha = 0;
// Staggered input area animations
tween(inputOuterBorder, {
alpha: 0.2
}, {
duration: 300
});
LK.setTimeout(function () {
tween(inputBg, {
alpha: 0.4
}, {
duration: 300
});
}, 100);
LK.setTimeout(function () {
tween(inputInner, {
alpha: 0.8
}, {
duration: 300
});
}, 200);
LK.setTimeout(function () {
tween(codeInputText, {
alpha: 1
}, {
duration: 400
});
}, 300);
LK.setTimeout(function () {
tween(instructionBg, {
alpha: 0.3
}, {
duration: 300
});
}, 400);
LK.setTimeout(function () {
tween(instructionText, {
alpha: 1
}, {
duration: 400
});
}, 500);
// Animate keyboard keys with wave effect
for (var animRow = 0; animRow < keyboardRows.length; animRow++) {
for (var animCol = 0; animCol < keyboardRows[animRow].length; animCol++) {
(function (row, col) {
LK.setTimeout(function () {
var keyIndex = row * 10 + col; // Approximate index for timing
var targetKey = codesMenuContainer.children.filter(function (child) {
return child.letter && child.x === rowStartPositions[row] + col * keySpacing && child.y === 1320 + row * rowSpacing;
})[0];
if (targetKey) {
targetKey.alpha = 0;
targetKey.scaleX = 0.5;
targetKey.scaleY = 0.5;
tween(targetKey, {
alpha: 1,
scaleX: 1,
scaleY: 1
}, {
duration: 300,
easing: tween.easeOut
});
}
}, 600 + row * 50 + col * 20);
})(animRow, animCol);
}
}
// Animate number keys
for (var numAnimCol = 0; numAnimCol < numbersRow.length; numAnimCol++) {
(function (col) {
LK.setTimeout(function () {
var targetNumKey = codesMenuContainer.children.filter(function (child) {
return child.letter && child.x === numberRowStartX + col * keySpacing && child.y === numberRowY;
})[0];
if (targetNumKey) {
targetNumKey.alpha = 0;
targetNumKey.scaleX = 0.5;
targetNumKey.scaleY = 0.5;
tween(targetNumKey, {
alpha: 1,
scaleX: 1,
scaleY: 1
}, {
duration: 300,
easing: tween.easeOut
});
}
}, 550 + col * 25);
})(numAnimCol);
}
// Animate control buttons with final cascade
LK.setTimeout(function () {
clearText.alpha = 0;
clearText.scaleX = 0.8;
clearText.scaleY = 0.8;
tween(clearText, {
alpha: 1,
scaleX: 1,
scaleY: 1
}, {
duration: 400,
easing: tween.easeOut
});
}, 1200);
LK.setTimeout(function () {
submitText.alpha = 0;
submitText.scaleX = 0.8;
submitText.scaleY = 0.8;
tween(submitText, {
alpha: 1,
scaleX: 1,
scaleY: 1
}, {
duration: 400,
easing: tween.easeOut
});
}, 1300);
LK.setTimeout(function () {
backText.alpha = 0;
backText.scaleX = 0.8;
backText.scaleY = 0.8;
tween(backText, {
alpha: 1,
scaleX: 1,
scaleY: 1
}, {
duration: 400,
easing: tween.easeOut
});
}, 1400);
}
// Function to show skins menu
function showSkinsMenu() {
var skinsMenuContainer = new Container();
game.addChild(skinsMenuContainer);
// Main background
var skinsBg = LK.getAsset('towerBase', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 10,
scaleY: 4.5,
alpha: 0.9
});
skinsBg.x = 1024;
skinsBg.y = 1366;
skinsMenuContainer.addChild(skinsBg);
// Title
var titleText = new Text2('MY SKINS', {
size: 80,
fill: 0x9932CC
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
titleText.y = 450;
skinsMenuContainer.addChild(titleText);
// Display owned aircraft skins
var centerX = 1024;
var itemStartY = 700;
var itemSpacing = 140;
// Get all aircraft styles including orange if unlocked
var searchAircraftStyles = aircraftStyles.slice();
var usedCodes = storage.usedCodes || [];
if (usedCodes.indexOf('ORANGEFREESKIN') >= 0) {
searchAircraftStyles.push(orangeAircraftStyle);
}
// Filter to show only owned skins
var ownedSkins = searchAircraftStyles.filter(function (style) {
return ownedAircraftStyles.indexOf(style.id) >= 0;
});
// Aircraft skins section title
var aircraftTitleText = new Text2('OWNED AIRCRAFT SKINS', {
size: 55,
fill: 0xFFFFFF
});
aircraftTitleText.anchor.set(0.5, 0.5);
aircraftTitleText.x = centerX;
aircraftTitleText.y = 620;
skinsMenuContainer.addChild(aircraftTitleText);
// Display owned skins
for (var s = 0; s < ownedSkins.length; s++) {
var skinItem = ownedSkins[s];
var isEquipped = currentAircraftStyle === skinItem.id;
// Item card
var itemBg = LK.getAsset('towerTop', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 6,
scaleY: 1.2,
alpha: isEquipped ? 0.9 : 0.7
});
itemBg.x = centerX;
itemBg.y = itemStartY + s * itemSpacing;
if (isEquipped) itemBg.tint = 0x00AA66;
skinsMenuContainer.addChild(itemBg);
// Aircraft preview
var previewAircraft = LK.getAsset('aircraft', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1.2
});
previewAircraft.x = centerX - 250;
previewAircraft.y = itemStartY + s * itemSpacing;
previewAircraft.tint = skinItem.color;
skinsMenuContainer.addChild(previewAircraft);
// Skin name
var skinNameText = new Text2(skinItem.name, {
size: 44,
fill: 0x000000
});
skinNameText.anchor.set(0, 0.5);
skinNameText.x = centerX - 120;
skinNameText.y = itemStartY + s * itemSpacing;
skinsMenuContainer.addChild(skinNameText);
// Status or equip button
var buttonText = isEquipped ? 'EQUIPPED' : 'EQUIP';
var buttonColor = isEquipped ? 0x888888 : 0x00AA00;
var skinButton = new Text2(buttonText, {
size: 38,
fill: buttonColor
});
skinButton.anchor.set(0.5, 0.5);
skinButton.x = centerX + 200;
skinButton.y = itemStartY + s * itemSpacing;
skinButton.skinItem = skinItem;
skinButton.isEquipped = isEquipped;
if (!isEquipped) {
skinButton.interactive = true;
skinButton.down = function () {
// Equip skin
currentAircraftStyle = this.skinItem.id;
storage.currentAircraftStyle = currentAircraftStyle;
updateAircraftStyle();
LK.effects.flashScreen(0x00FF00, 300);
// Refresh skins menu
skinsMenuContainer.destroy();
showSkinsMenu();
};
}
skinsMenuContainer.addChild(skinButton);
}
// Back button
var backText = new Text2('BACK', {
size: 50,
fill: 0xFFFFFF
});
backText.anchor.set(0.5, 0.5);
backText.x = 1024;
backText.y = 1800;
backText.interactive = true;
backText.down = function () {
skinsMenuContainer.destroy();
createMainMenu();
};
skinsMenuContainer.addChild(backText);
// Fade-in animation
skinsMenuContainer.alpha = 0;
tween(skinsMenuContainer, {
alpha: 1
}, {
duration: 300
});
}
// Function to show shop
function showShop() {
showingShop = true;
shopContainer = new Container();
game.addChild(shopContainer);
// Simple main background
var shopBg = LK.getAsset('towerBase', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 10,
scaleY: 4.5,
alpha: 0.9
});
shopBg.x = 1024;
shopBg.y = 1366;
shopContainer.addChild(shopBg);
// Clean title
var titleText = new Text2('SHOP', {
size: 80,
fill: 0xFFD700
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
titleText.y = 400;
shopContainer.addChild(titleText);
// Simple coins display
var coinsDisplayText = new Text2('Coins: ' + playerCoins, {
size: 50,
fill: 0xFFD700
});
coinsDisplayText.anchor.set(0.5, 0.5);
coinsDisplayText.x = 1024;
coinsDisplayText.y = 480;
shopContainer.addChild(coinsDisplayText);
// Store reference to update coins display throughout shop
shopContainer.coinsDisplayText = coinsDisplayText;
// Add function to update coins display with animation
shopContainer.updateCoinsDisplay = function (newAmount) {
// Flash effect on coins change
tween(this.coinsDisplayText, {
scaleX: 1.2,
scaleY: 1.2,
fill: 0x00FF00
}, {
duration: 200,
onFinish: function () {
this.coinsDisplayText.setText('Coins: ' + newAmount);
tween(this.coinsDisplayText, {
scaleX: 1,
scaleY: 1,
fill: 0xFFD700
}, {
duration: 300,
easing: tween.bounceOut
});
}.bind(this)
});
};
// Simple centered layout with increased spacing
var centerX = 1024;
var itemStartY = 600;
var itemSpacing = 120;
// Aircraft styles section title
var aircraftTitleText = new Text2('AIRCRAFT STYLES', {
size: 55,
fill: 0xFFFFFF
});
aircraftTitleText.anchor.set(0.5, 0.5);
aircraftTitleText.x = centerX;
aircraftTitleText.y = 560;
shopContainer.addChild(aircraftTitleText);
// Create display array without orange skin and filter out owned skins
var displayAircraftStyles = aircraftStyles.filter(function (style) {
return ownedAircraftStyles.indexOf(style.id) < 0; // Only show unowned skins
});
// Aircraft items with clean design
for (var a = 0; a < displayAircraftStyles.length; a++) {
var aircraftItem = displayAircraftStyles[a];
var isOwned = ownedAircraftStyles.indexOf(aircraftItem.id) >= 0;
var isEquipped = currentAircraftStyle === aircraftItem.id;
// Simple item card
var itemBg = LK.getAsset('towerTop', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 6,
scaleY: 1.2,
alpha: isEquipped ? 0.9 : 0.7
});
itemBg.x = centerX;
itemBg.y = itemStartY + a * itemSpacing;
if (isEquipped) itemBg.tint = 0x00AA66;
shopContainer.addChild(itemBg);
// Aircraft preview
var previewAircraft = LK.getAsset('aircraft', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1.2
});
previewAircraft.x = centerX - 250;
previewAircraft.y = itemStartY + a * itemSpacing;
previewAircraft.tint = aircraftItem.color;
shopContainer.addChild(previewAircraft);
// Item name
var itemNameText = new Text2(aircraftItem.name, {
size: 44,
fill: 0x000000
});
itemNameText.anchor.set(0, 0.5);
itemNameText.x = centerX - 120;
itemNameText.y = itemStartY + a * itemSpacing;
shopContainer.addChild(itemNameText);
// Purchase button
var buttonText = isOwned ? isEquipped ? 'EQUIPPED' : 'EQUIP' : 'BUY ' + aircraftItem.price;
var buttonColor = isOwned ? isEquipped ? 0x888888 : 0x00AA00 : playerCoins >= aircraftItem.price ? 0x0066CC : 0xCC0000;
var itemButton = new Text2(buttonText, {
size: 38,
fill: buttonColor
});
itemButton.anchor.set(0.5, 0.5);
itemButton.x = centerX + 200;
itemButton.y = itemStartY + a * itemSpacing;
itemButton.aircraftItem = aircraftItem;
itemButton.isOwned = isOwned;
itemButton.isEquipped = isEquipped;
if (!isEquipped) {
itemButton.interactive = true;
itemButton.down = function () {
// Simple button animation
tween(this, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function () {
tween(this, {
scaleX: 1,
scaleY: 1
}, {
duration: 100
});
}.bind(this)
});
if (this.isOwned) {
// Equip item
currentAircraftStyle = this.aircraftItem.id;
storage.currentAircraftStyle = currentAircraftStyle;
updateAircraftStyle();
LK.effects.flashScreen(0x00FF00, 300);
hideShop();
showShop();
} else if (playerCoins >= this.aircraftItem.price) {
// Purchase item
playerCoins -= this.aircraftItem.price;
storage.playerCoins = playerCoins;
ownedAircraftStyles.push(this.aircraftItem.id);
storage.ownedAircraftStyles = ownedAircraftStyles;
currentAircraftStyle = this.aircraftItem.id;
storage.currentAircraftStyle = currentAircraftStyle;
updateAircraftStyle();
LK.effects.flashScreen(0xFFD700, 500);
if (LK.getSound('coinCollect')) {
LK.getSound('coinCollect').play();
}
// Refresh shop to remove purchased item
hideShop();
showShop();
} else {
// Insufficient funds
LK.effects.flashObject(this, 0xFF0000, 300);
}
};
}
shopContainer.addChild(itemButton);
}
// Simple back button
var backText = new Text2('BACK', {
size: 50,
fill: 0xFFFFFF
});
backText.anchor.set(0.5, 0.5);
backText.x = 1024;
backText.y = 1800;
backText.interactive = true;
backText.down = function () {
// Simple button animation
tween(this, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 100,
onFinish: function () {
tween(this, {
scaleX: 1,
scaleY: 1
}, {
duration: 100
});
}.bind(this)
});
hideShop();
createMainMenu();
};
shopContainer.addChild(backText);
// Simple fade-in animation
shopContainer.alpha = 0;
tween(shopContainer, {
alpha: 1
}, {
duration: 300
});
}
// Function to hide shop
function hideShop() {
if (shopContainer) {
shopContainer.destroy();
shopContainer = null;
}
showingShop = false;
}
// Function to update aircraft style
function updateAircraftStyle() {
// Create search array that includes orange skin if unlocked
var searchAircraftStyles = aircraftStyles.slice();
var usedCodes = storage.usedCodes || [];
if (usedCodes.indexOf('ORANGEFREESKIN') >= 0) {
searchAircraftStyles.push(orangeAircraftStyle);
}
var styleData = searchAircraftStyles.find(function (style) {
return style.id === currentAircraftStyle;
});
if (styleData && aircraft) {
// Apply color to main aircraft components
aircraft.children[0].tint = styleData.color; // Main aircraft body
aircraft.children[1].tint = styleData.color; // Main wing
aircraft.children[4].tint = styleData.color; // Tail
aircraft.children[5].tint = styleData.color; // Horizontal stabilizer
// Apply slightly darker tint to engines and details
var darkerTint = styleData.color * 0.8;
if (aircraft.children[8]) aircraft.children[8].tint = darkerTint; // Left engine
if (aircraft.children[9]) aircraft.children[9].tint = darkerTint; // Right engine
if (aircraft.children[10]) aircraft.children[10].tint = darkerTint; // Left gear
if (aircraft.children[11]) aircraft.children[11].tint = darkerTint; // Right gear
}
}
// Function to hide codes menu
function hideCodesMenu() {
if (codesMenuContainer) {
codesMenuContainer.destroy();
codesMenuContainer = null;
}
showingCodesMenu = false;
}
// Function to show levels menu
function showLevelsMenu() {
var levelsMenuContainer = new Container();
game.addChild(levelsMenuContainer);
// Semi-transparent background
var levelsBg = LK.getAsset('towerBase', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 10,
scaleY: 4.5,
alpha: 0.95
});
levelsBg.x = 1024;
levelsBg.y = 1366;
levelsMenuContainer.addChild(levelsBg);
// Title
var titleText = new Text2('ALL LEVELS', {
size: 90,
fill: 0xFFD700
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
titleText.y = 400;
levelsMenuContainer.addChild(titleText);
// Subtitle with completion info
var completedLevels = gameSettings.highestLevelReached;
var subtitleText = new Text2('Completed: ' + completedLevels + '/100', {
size: 60,
fill: 0x00FF00
});
subtitleText.anchor.set(0.5, 0.5);
subtitleText.x = 1024;
subtitleText.y = 500;
levelsMenuContainer.addChild(subtitleText);
// Add coins balance display in levels menu
var levelCoinsDisplayBg = LK.getAsset('towerTop', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.5,
scaleY: 0.5,
alpha: 0.4
});
levelCoinsDisplayBg.x = 1024;
levelCoinsDisplayBg.y = 550;
levelsMenuContainer.addChild(levelCoinsDisplayBg);
var levelCoinsText = new Text2('Your Coins: ' + playerCoins, {
size: 45,
fill: 0xFFD700
});
levelCoinsText.anchor.set(0.5, 0.5);
levelCoinsText.x = 1024;
levelCoinsText.y = 550;
levelsMenuContainer.addChild(levelCoinsText);
// Create scrollable container for levels
var scrollContainer = new Container();
levelsMenuContainer.addChild(scrollContainer);
// Create level display in grid format (10 columns, 10 rows for 100 levels)
for (var level = 1; level <= 100; level++) {
var isCompleted = level <= completedLevels;
var levelButton = new Text2(level.toString(), {
size: 35,
fill: isCompleted ? 0x00FF00 : 0x888888 // Green if completed, gray if not
});
levelButton.anchor.set(0.5, 0.5);
// Position in 10x10 grid
levelButton.x = 300 + (level - 1) % 10 * 145;
levelButton.y = 650 + Math.floor((level - 1) / 10) * 60;
// Add background for better visibility
var levelBg = LK.getAsset('towerTop', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.7,
scaleY: 0.7,
alpha: isCompleted ? 0.8 : 0.3
});
levelBg.x = levelButton.x;
levelBg.y = levelButton.y;
scrollContainer.addChild(levelBg);
scrollContainer.addChild(levelButton);
// Add completion checkmark for completed levels
if (isCompleted) {
var checkmark = new Text2('✓', {
size: 25,
fill: 0xFFD700
});
checkmark.anchor.set(0.5, 0.5);
checkmark.x = levelButton.x + 25;
checkmark.y = levelButton.y - 25;
scrollContainer.addChild(checkmark);
}
}
// Add scroll instruction
var scrollText = new Text2('Scroll to see all levels', {
size: 45,
fill: 0xFFFF00
});
scrollText.anchor.set(0.5, 0.5);
scrollText.x = 1024;
scrollText.y = 600;
levelsMenuContainer.addChild(scrollText);
// Add scroll functionality
var scrollY = 0;
var maxScroll = Math.max(0, Math.ceil(100 / 10) * 60 - 500);
levelsMenuContainer.interactive = true;
levelsMenuContainer.move = function (x, y, obj) {
if (obj.deltaY) {
scrollY -= obj.deltaY * 2;
scrollY = Math.max(-maxScroll, Math.min(0, scrollY));
scrollContainer.y = scrollY;
}
};
// Back button
var backText = new Text2('BACK', {
size: 60,
fill: 0xFF8000
});
backText.anchor.set(0.5, 0.5);
backText.x = 1024;
backText.y = 1600;
backText.interactive = true;
backText.down = function () {
levelsMenuContainer.destroy();
createMainMenu();
};
levelsMenuContainer.addChild(backText);
// Add entrance animation
levelsMenuContainer.alpha = 0;
tween(levelsMenuContainer, {
alpha: 1
}, {
duration: 500,
easing: tween.easeOut
});
}
// Function to show admin menu
function showAdminMenu() {
var adminMenuContainer = new Container();
game.addChild(adminMenuContainer);
// Semi-transparent background
var adminBg = LK.getAsset('towerBase', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 8,
scaleY: 4,
alpha: 0.9
});
adminBg.x = 1024;
adminBg.y = 1366;
adminMenuContainer.addChild(adminBg);
// Title
var titleText = new Text2('ADMIN MODE ACTIVATED', {
size: 70,
fill: 0xFF0000
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
titleText.y = 600;
adminMenuContainer.addChild(titleText);
// Level selection title
var levelSelectText = new Text2('SELECT LEVEL:', {
size: 60,
fill: 0xFFFFFF
});
levelSelectText.anchor.set(0.5, 0.5);
levelSelectText.x = 1024;
levelSelectText.y = 800;
adminMenuContainer.addChild(levelSelectText);
// Create scrollable level buttons (1-100)
var scrollContainer = new Container();
adminMenuContainer.addChild(scrollContainer);
// Create level buttons in a grid layout
for (var level = 1; level <= 100; level++) {
var levelButton = new Text2(level.toString(), {
size: 35,
fill: 0x00FF00
});
levelButton.anchor.set(0.5, 0.5);
// 10 columns, 10 rows for 100 levels
levelButton.x = 300 + (level - 1) % 10 * 145;
levelButton.y = 900 + Math.floor((level - 1) / 10) * 60;
levelButton.interactive = true;
levelButton.targetLevel = level;
levelButton.down = function () {
currentLevel = this.targetLevel;
storage.currentLevel = currentLevel;
adminMenuContainer.destroy();
createMainMenu();
};
scrollContainer.addChild(levelButton);
}
// Add scroll instruction text
var scrollText = new Text2('Scroll to see all 100 levels', {
size: 40,
fill: 0xFFFF00
});
scrollText.anchor.set(0.5, 0.5);
scrollText.x = 1024;
scrollText.y = 850;
adminMenuContainer.addChild(scrollText);
// Add scroll functionality
var scrollY = 0;
var maxScroll = Math.max(0, Math.ceil(100 / 10) * 60 - 400); // Adjust based on visible area
adminMenuContainer.interactive = true;
adminMenuContainer.move = function (x, y, obj) {
if (obj.deltaY) {
scrollY -= obj.deltaY * 2;
scrollY = Math.max(-maxScroll, Math.min(0, scrollY));
scrollContainer.y = scrollY;
}
};
// Back button
var backText = new Text2('BACK TO MENU', {
size: 50,
fill: 0xFF8000
});
backText.anchor.set(0.5, 0.5);
backText.x = 1024;
backText.y = 1500;
backText.interactive = true;
backText.down = function () {
adminMenuContainer.destroy();
createMainMenu();
};
adminMenuContainer.addChild(backText);
}
// Function to hide main menu
function hideMainMenu() {
if (mainMenuContainer) {
mainMenuContainer.destroy();
mainMenuContainer = null;
}
showingMainMenu = false;
}
// Function to start game
function startGame() {
gameStarted = true;
// Reset game state
levelScore = 0;
towersToComplete = 5 * currentLevel;
invulnerabilityTime = 0;
comboMultiplier = 1;
powerUpSpawnTimer = 0;
// Clear any existing game objects
clearLevel();
// Reset aircraft position
aircraft.x = 300;
aircraft.y = 1366;
// Update UI
levelText.setText('Level: ' + currentLevel);
progressText.setText('Progress: 0/' + towersToComplete);
scoreText.setText('Score: ' + LK.getScore());
coinsText.setText('Coins: ' + playerCoins);
// Apply current aircraft style
updateAircraftStyle();
// Update aircraft speed for current level
aircraft.speed = Math.min(5, 3 + (currentLevel - 1) * 0.1);
// Start background music
if (gameSettings.musicEnabled && !musicPlaying) {
LK.stopMusic(); // Stop any menu music
LK.playMusic('backgroundMusic', {
loop: true
});
musicPlaying = true;
}
}
// Function to hide menu
function hideMenu() {
if (menuContainer) {
menuContainer.destroy();
menuContainer = null;
}
showingMenu = false;
gameStarted = true;
}
// Function to clear level objects
function clearLevel() {
// Clear existing towers
for (var i = towers.length - 1; i >= 0; i--) {
towers[i].destroy();
towers.splice(i, 1);
}
// Clear finish line
if (finishLine) {
finishLine.destroy();
finishLine = null;
}
// Clear existing clouds
for (var c = clouds.length - 1; c >= 0; c--) {
clouds[c].destroy();
clouds.splice(c, 1);
}
// Clear power-ups
for (var p = powerUps.length - 1; p >= 0; p--) {
powerUps[p].destroy();
powerUps.splice(p, 1);
}
// Clear particles
for (var pt = particles.length - 1; pt >= 0; pt--) {
particles[pt].destroy();
particles.splice(pt, 1);
}
// Clear spark particles
for (var sp = sparkParticles.length - 1; sp >= 0; sp--) {
sparkParticles[sp].destroy();
sparkParticles.splice(sp, 1);
}
// Clear coins
for (var co = coins.length - 1; co >= 0; co--) {
coins[co].destroy();
coins.splice(co, 1);
}
}
// Function to complete level
function completeLevel() {
currentLevel++;
// Save progress to storage
storage.currentLevel = currentLevel;
levelScore = 0;
towersToComplete = 5 * currentLevel; // Level 1: 5, Level 2: 10, Level 3: 15, etc.
// Reset power-up system
invulnerabilityTime = 0;
comboMultiplier = 1;
powerUpSpawnTimer = 0;
// Clear existing towers and finish line
clearLevel();
// Reset aircraft position
aircraft.x = 300;
aircraft.y = 1366;
// Update aircraft speed for new level
aircraft.speed = Math.min(5, 3 + (currentLevel - 1) * 0.1);
// Update UI
levelText.setText('Level: ' + currentLevel);
progressText.setText('Progress: 0/' + towersToComplete);
// Enhanced level completion effects with camera shake
startCameraShake(10, 60); // Gentle celebration shake
LK.effects.flashScreen(0x00ff00, 1000);
LK.getSound('levelComplete').play();
// Bonus score for completing level with progressive rewards
var bonusScore = 100 * currentLevel * comboMultiplier;
var milestoneBonus = 0;
// Milestone bonuses for every 10 levels
if (currentLevel % 10 === 0) {
milestoneBonus = 1000 * (currentLevel / 10);
playerCoins += 50; // Bonus coins for milestone
storage.playerCoins = playerCoins;
coinsText.setText('Coins: ' + playerCoins);
}
LK.setScore(LK.getScore() + bonusScore + milestoneBonus);
scoreText.setText('Score: ' + LK.getScore());
// Update total score with session progress
totalScore += bonusScore + milestoneBonus;
storage.totalScore = totalScore;
// Create celebration particles
for (var i = 0; i < 10; i++) {
LK.setTimeout(function () {
createSparkParticle(aircraft.x + (Math.random() - 0.5) * 200, aircraft.y + (Math.random() - 0.5) * 100);
}, i * 50);
}
}
// Enhanced camera shake system
var cameraShake = {
active: false,
intensity: 0,
duration: 0,
originalX: 0,
originalY: 0
};
function startCameraShake(intensity, duration) {
if (!gameSettings.screenshakeEnabled) return;
cameraShake.active = true;
cameraShake.intensity = intensity;
cameraShake.duration = duration;
cameraShake.originalX = game.x;
cameraShake.originalY = game.y;
}
function updateCameraShake() {
if (!cameraShake.active) return;
cameraShake.duration--;
if (cameraShake.duration <= 0) {
cameraShake.active = false;
game.x = cameraShake.originalX;
game.y = cameraShake.originalY;
return;
}
var shakeX = (Math.random() - 0.5) * cameraShake.intensity;
var shakeY = (Math.random() - 0.5) * cameraShake.intensity;
game.x = cameraShake.originalX + shakeX;
game.y = cameraShake.originalY + shakeY;
}
// Function to handle game over
function gameOver() {
// Add current session score to total score
totalScore += LK.getScore();
storage.totalScore = totalScore;
// Save current level to storage so player can restart from this level
storage.currentLevel = currentLevel;
// Enhanced screen shake for dramatic effect
startCameraShake(25, 120);
LK.effects.flashScreen(0xff0000, 1000);
LK.getSound('crash').play();
LK.showGameOver();
}
// Main game update loop
game.update = function () {
// Update camera shake system
updateCameraShake();
// Check if admin mode has expired
if (adminMode && Date.now() > adminModeEndTime) {
adminMode = false;
adminModeEndTime = 0;
storage.adminModeEndTime = 0;
}
if (!gameStarted || showingMenu || showingMainMenu || showingCodesMenu || showingShop) return;
// Update invulnerability
if (invulnerabilityTime > 0) {
invulnerabilityTime--;
if (invulnerabilityTime === 0) {
aircraft.alpha = 1; // Restore normal appearance
}
}
// Update combo multiplier decay
if (LK.ticks - lastPowerUpTime > 1800) {
// 30 seconds
comboMultiplier = Math.max(1, comboMultiplier - 0.01);
}
// Spawn clouds for background atmosphere
if (LK.ticks % 180 === 0) {
// Spawn cloud every 3 seconds at 60fps
spawnCloud();
}
// Spawn coins
coinSpawnTimer++;
if (coinSpawnTimer > 180 + Math.random() * 120) {
// Every 3-5 seconds
spawnCoin();
coinSpawnTimer = 0;
}
// Spawn power-ups
powerUpSpawnTimer++;
if (powerUpSpawnTimer > 600 + Math.random() * 300) {
// Every 10-15 seconds
spawnPowerUp();
powerUpSpawnTimer = 0;
}
// Update clouds
for (var c = clouds.length - 1; c >= 0; c--) {
var cloud = clouds[c];
// Remove clouds that have moved off screen
if (cloud.x < -200) {
cloud.destroy();
clouds.splice(c, 1);
}
}
// Update coins
for (var co = coins.length - 1; co >= 0; co--) {
var coin = coins[co];
// Remove if off screen
if (coin.x < -100) {
coin.destroy();
coins.splice(co, 1);
continue;
}
// Check collection
var coinIntersecting = aircraft.intersects(coin);
if (!coin.lastIntersecting && coinIntersecting && !coin.collected) {
coin.collected = true;
playerCoins += 5; // Award 5 coins per collection
storage.playerCoins = playerCoins;
coinsText.setText('Coins: ' + playerCoins);
// Coin collection effect
LK.effects.flashObject(coin, 0xFFD700, 300);
LK.getSound('coinCollect').play();
// Create coin text popup
var coinPopup = new Text2('+5', {
size: 40,
fill: 0xFFD700
});
coinPopup.anchor.set(0.5, 0.5);
coinPopup.x = coin.x;
coinPopup.y = coin.y;
game.addChild(coinPopup);
tween(coinPopup, {
y: coinPopup.y - 80,
alpha: 0
}, {
duration: 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
coinPopup.destroy();
}
});
coin.destroy();
coins.splice(co, 1);
continue;
}
coin.lastIntersecting = coinIntersecting;
}
// Update spark particles
for (var sp = sparkParticles.length - 1; sp >= 0; sp--) {
var spark = sparkParticles[sp];
// Particles are automatically removed in their update method
}
// Update power-ups
for (var p = powerUps.length - 1; p >= 0; p--) {
var powerUp = powerUps[p];
// Remove if off screen
if (powerUp.x < -100) {
powerUp.destroy();
powerUps.splice(p, 1);
continue;
}
// Check collection
var currentIntersecting = aircraft.intersects(powerUp);
if (!powerUp.lastIntersecting && currentIntersecting && !powerUp.collected) {
powerUp.collected = true;
applyPowerUpEffect();
powerUp.destroy();
powerUps.splice(p, 1);
continue;
}
powerUp.lastIntersecting = currentIntersecting;
}
// Spawn towers based on level difficulty (adjusted for levels 1-100) with increased separation
var spawnRate = Math.max(90, 420 - Math.min(currentLevel, 15) * 20); // Increased base separation between tower pairs
if (LK.ticks % spawnRate === 0) {
spawnTower();
}
// Check if we should spawn finish line - spawn exactly when progress reaches target
var progress = Math.floor(levelScore / 2);
if (progress === towersToComplete && !finishLine) {
spawnFinishLine();
}
// Update finish line
if (finishLine) {
// Check if finish line went off screen
if (finishLine.lastX >= -200 && finishLine.x < -200) {
finishLine.destroy();
finishLine = null;
}
// Check if aircraft crossed finish line
if (!finishLine.crossed && finishLine.x < aircraft.x) {
finishLine.crossed = true;
createLevelMenu();
return;
}
}
// Update towers
for (var i = towers.length - 1; i >= 0; i--) {
var tower = towers[i];
// Check if tower went off screen
if (tower.lastX >= -200 && tower.x < -200) {
towers.splice(i, 1);
tower.destroy();
continue;
}
// Check collision with aircraft (skip if invulnerable)
var currentIntersecting = aircraft.intersects(tower);
if (!tower.lastIntersecting && currentIntersecting && invulnerabilityTime <= 0) {
// Create dramatic collision effect
createTowerDestructionEffect(tower.x, tower.y);
startCameraShake(30, 100);
LK.getSound('crash').play();
gameOver();
return;
}
tower.lastIntersecting = currentIntersecting;
// Check if aircraft passed tower (score point)
if (!tower.passed && tower.x < aircraft.x - 100) {
tower.passed = true;
levelScore++;
var basePoints = 10 * currentLevel;
var bonusPoints = Math.floor(basePoints * comboMultiplier);
LK.setScore(LK.getScore() + bonusPoints);
LK.getSound('dodge').play();
LK.getSound('whoosh').play();
// Update progress - count obstacles (pairs of towers) correctly
var progress = Math.floor(levelScore / 2); // Two towers per obstacle pair
progressText.setText('Progress: ' + progress + '/' + towersToComplete);
scoreText.setText('Score: ' + LK.getScore());
// Create score popup for bonus points
if (comboMultiplier > 1) {
var bonusText = new Text2('+' + bonusPoints + ' (x' + comboMultiplier.toFixed(1) + ')', {
size: 40,
fill: 0xFFD700
});
bonusText.anchor.set(0.5, 0.5);
bonusText.x = aircraft.x;
bonusText.y = aircraft.y - 50;
game.addChild(bonusText);
// Animate bonus text
tween(bonusText, {
y: bonusText.y - 100,
alpha: 0
}, {
duration: 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
bonusText.destroy();
}
});
}
// Animate score text to highlight points earned
tween.stop(scoreText, {
scaleX: true,
scaleY: true
});
tween(scoreText, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(scoreText, {
scaleX: 1,
scaleY: 1
}, {
duration: 200,
easing: tween.easeIn
});
}
});
}
}
// Dynamic background color system based on level
var targetBackgroundColor = 0x87CEFA; // Default sky blue
if (currentLevel >= 80) {
targetBackgroundColor = 0x2F1B69; // Deep purple for high levels
} else if (currentLevel >= 60) {
targetBackgroundColor = 0x1a1a2e; // Dark blue
} else if (currentLevel >= 40) {
targetBackgroundColor = 0x16213e; // Navy blue
} else if (currentLevel >= 20) {
targetBackgroundColor = 0x0f3460; // Medium blue
}
// Gradually transition background color every few seconds
if (LK.ticks % 300 === 0) {
// Every 5 seconds
var currentBg = game.backgroundColor || 0x87CEFA;
if (currentBg !== targetBackgroundColor) {
// Simple color transition by setting it directly
game.setBackgroundColor(targetBackgroundColor);
}
}
// Aircraft stays stationary while towers move to create forward movement illusion
};