/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var BloodParticle = Container.expand(function () { var self = Container.call(this); var graphics = self.attachAsset('confetti', { anchorX: 0.5, anchorY: 0.5 }); graphics.tint = 0xFF0000; // Red color for blood graphics.scaleX = 0.3; // Smaller particles graphics.scaleY = 0.3; self.speedX = (Math.random() - 0.5) * 6; self.speedY = Math.random() * -4 - 1; self.gravity = 0.2; self.life = 30; // Short lived particles self.update = function () { self.x += self.speedX; self.y += self.speedY; self.speedY += self.gravity; self.life--; if (self.life <= 0) { self.alpha = 0; } else { // Fade out over time self.alpha = self.life / 30; } }; return self; }); var Confetti = Container.expand(function () { var self = Container.call(this); var graphics = self.attachAsset('confetti', { anchorX: 0.5, anchorY: 0.5 }); self.speedX = (Math.random() - 0.5) * 10; self.speedY = Math.random() * -8 - 2; self.gravity = 0.3; self.life = 120; self.update = function () { self.x += self.speedX; self.y += self.speedY; self.speedY += self.gravity; self.life--; if (self.life <= 0) { self.alpha = 0; } }; return self; }); var Enemy = Container.expand(function () { var self = Container.call(this); self.enemyType = 'aamir'; self.health = 1; self.speed = 2; self.pathIndex = 0; self.goldReward = 10; self.init = function (type) { self.enemyType = type; if (type === 'vega') { self.health = 3; self.speed = 1; self.goldReward = 25; } else if (type === 'sultan') { self.health = 2; self.speed = 1.5; self.goldReward = 20; } else { self.goldReward = 10; } var graphics = self.attachAsset(type, { anchorX: 0.5, anchorY: 0.5 }); }; self.update = function () { // Follow path if available if (enemyPath.length > 0 && self.pathIndex < enemyPath.length - 1) { var currentTarget = enemyPath[self.pathIndex + 1]; var dx = currentTarget.x - self.x; var dy = currentTarget.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 30) { self.pathIndex++; } else { self.x += dx / distance * self.speed; self.y += dy / distance * self.speed; } } else { // Fallback to original movement self.y += self.speed; } }; self.takeDamage = function (damage) { if (damage === undefined) damage = 1; self.health -= damage; if (self.health <= 0) { // Award gold when enemy dies playerGold += self.goldReward; updateGoldDisplay(); return true; } return false; }; return self; }); var Laser = Container.expand(function () { var self = Container.call(this); var graphics = self.attachAsset('laser', { anchorX: 0.5, anchorY: 1.0 }); self.duration = 20; // Laser lasts for 20 frames self.damage = 5; // Higher damage than regular bullets self.update = function () { self.duration--; if (self.duration <= 0) { self.alpha = 0; } else { // Fade out effect self.alpha = self.duration / 20; } }; return self; }); var ModeButton = Container.expand(function () { var self = Container.call(this); var background = self.attachAsset('modeButton', { anchorX: 0.5, anchorY: 0.5 }); self.modeText = new Text2('', { size: 50, fill: '#000000' }); self.modeText.anchor.set(0.5, 0.5); self.addChild(self.modeText); self.setMode = function (text, mode, enemyCount) { // Remove existing text and create new one with proper styling if (self.modeText) { self.removeChild(self.modeText); } self.modeText = new Text2(text, { size: 50, fill: '#000000', stroke: '#FFFFFF', strokeThickness: 3 }); self.modeText.anchor.set(0.5, 0); self.modeText.y = 80; // Position text below the button self.addChild(self.modeText); self.gameMode = mode; self.enemyCount = enemyCount; }; self.down = function (x, y, obj) { startGame(self.gameMode, self.enemyCount); }; return self; }); var Omar = Container.expand(function () { var self = Container.call(this); var graphics = self.attachAsset('omar', { anchorX: 0.5, anchorY: 0.5 }); self.shootCooldown = 0; self.laserCooldown = 0; self.update = function () { if (self.shootCooldown > 0) { self.shootCooldown--; } if (self.laserCooldown > 0) { self.laserCooldown--; } }; self.shoot = function () { if (self.shootCooldown <= 0) { var bullet = new OmarBullet(); bullet.x = self.x; bullet.y = self.y - 40; bullets.push(bullet); game.addChild(bullet); self.shootCooldown = 15; LK.getSound('shoot').play(); // Add shooting animation to Omar tween(self, { scaleX: 1.1, scaleY: 1.1, tint: 0xFFFFAA }, { duration: 100, easing: tween.easeOut, onFinish: function onFinish() { tween(self, { scaleX: 1.0, scaleY: 1.0, tint: 0xFFFFFF }, { duration: 200, easing: tween.easeOut }); } }); } }; self.shootLaser = function () { if (self.laserCooldown <= 0) { var laser = new Laser(); laser.x = self.x; laser.y = self.y - 40; lasers.push(laser); game.addChild(laser); self.laserCooldown = 60; // 1 second cooldown at 60fps LK.getSound('shoot').play(); } }; return self; }); var OmarAI = Container.expand(function () { var self = Container.call(this); self.target = null; self.isActive = false; self.moveSpeed = 3; self.attackRange = 400; self.lastDecisionTime = 0; self.decisionCooldown = 30; // frames between AI decisions self.activate = function () { self.isActive = true; }; self.deactivate = function () { self.isActive = false; }; self.findNearestEnemy = function () { var nearestEnemy = null; var nearestDistance = Infinity; for (var i = 0; i < enemies.length; i++) { var enemy = enemies[i]; var dx = omar.x - enemy.x; var dy = omar.y - enemy.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < nearestDistance) { nearestDistance = distance; nearestEnemy = enemy; } } return nearestEnemy; }; self.update = function () { if (!self.isActive || !omar) return; self.lastDecisionTime++; // Make decisions every few frames for performance if (self.lastDecisionTime >= self.decisionCooldown) { self.target = self.findNearestEnemy(); self.lastDecisionTime = 0; } if (self.target) { // Move towards enemy horizontally var dx = self.target.x - omar.x; if (Math.abs(dx) > 50) { // Dead zone to prevent jittering if (dx > 0) { omar.x += self.moveSpeed; } else { omar.x -= self.moveSpeed; } } // Keep Omar within screen bounds with proper margins omar.x = Math.max(95, Math.min(1953, omar.x)); // Shoot if enemy is within range var distance = Math.sqrt(dx * dx + (self.target.y - omar.y) * (self.target.y - omar.y)); if (distance < self.attackRange) { omar.shoot(); } } }; return self; }); var OmarBullet = Container.expand(function () { var self = Container.call(this); var graphics = self.attachAsset('omarBullet', { anchorX: 0.5, anchorY: 0.5 }); self.speed = -8; self.update = function () { self.y += self.speed; }; return self; }); var Terrain = Container.expand(function () { var self = Container.call(this); self.init = function (type, x, y) { var graphics = self.attachAsset(type, { anchorX: 0.5, anchorY: 0.5 }); self.x = x; self.y = y; }; return self; }); var Tower = Container.expand(function () { var self = Container.call(this); var graphics = self.attachAsset('stone', { anchorX: 0.5, anchorY: 0.5 }); graphics.tint = 0x8B4513; // Brown color for tower self.range = 300; self.damage = 25; self.fireRate = 60; // frames between shots self.cooldown = 0; self.level = 1; self.cost = 50; // Visual range indicator self.rangeIndicator = null; self.showRange = function () { if (!self.rangeIndicator) { self.rangeIndicator = new Text2('◯', { size: self.range * 2, fill: '#00FF00' }); self.rangeIndicator.anchor.set(0.5, 0.5); self.rangeIndicator.alpha = 0.3; self.rangeIndicator.x = 0; self.rangeIndicator.y = 0; self.addChild(self.rangeIndicator); } }; self.hideRange = function () { if (self.rangeIndicator) { self.removeChild(self.rangeIndicator); self.rangeIndicator = null; } }; self.canShoot = function () { return self.cooldown <= 0; }; self.inRange = function (enemy) { var dx = self.x - enemy.x; var dy = self.y - enemy.y; return Math.sqrt(dx * dx + dy * dy) <= self.range; }; self.shoot = function (enemy) { if (self.canShoot() && self.inRange(enemy)) { // Create tower bullet var bullet = new TowerBullet(); bullet.x = self.x; bullet.y = self.y; bullet.targetX = enemy.x; bullet.targetY = enemy.y; bullet.damage = self.damage; towerBullets.push(bullet); game.addChild(bullet); self.cooldown = self.fireRate; LK.getSound('shoot').play(); // Tower shoot animation tween(self, { scaleX: 1.2, scaleY: 1.2, tint: 0xFFFFAA }, { duration: 100, easing: tween.easeOut, onFinish: function onFinish() { tween(self, { scaleX: 1.0, scaleY: 1.0, tint: 0x8B4513 }, { duration: 200, easing: tween.easeOut }); } }); } }; self.upgrade = function () { if (self.level < 3 && playerGold >= self.getUpgradeCost()) { playerGold -= self.getUpgradeCost(); self.level++; self.damage += 15; self.range += 50; self.fireRate = Math.max(20, self.fireRate - 10); // Visual upgrade effect graphics.scaleX *= 1.1; graphics.scaleY *= 1.1; if (self.level === 2) { graphics.tint = 0xC0C0C0; // Silver } else if (self.level === 3) { graphics.tint = 0xFFD700; // Gold } updateGoldDisplay(); } }; self.getUpgradeCost = function () { return self.level * 75; }; self.update = function () { if (self.cooldown > 0) { self.cooldown--; } // Find and shoot at nearest enemy var nearestEnemy = null; var nearestDistance = Infinity; for (var i = 0; i < enemies.length; i++) { var enemy = enemies[i]; if (self.inRange(enemy)) { var dx = self.x - enemy.x; var dy = self.y - enemy.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < nearestDistance) { nearestDistance = distance; nearestEnemy = enemy; } } } if (nearestEnemy) { self.shoot(nearestEnemy); } }; self.down = function (x, y, obj) { if (gameState === 'playing') { self.upgrade(); } }; return self; }); var TowerBullet = Container.expand(function () { var self = Container.call(this); var graphics = self.attachAsset('omarBullet', { anchorX: 0.5, anchorY: 0.5 }); graphics.tint = 0xFF8C00; // Orange color for tower bullets self.speed = 8; self.damage = 25; self.targetX = 0; self.targetY = 0; self.hasHit = false; self.update = function () { if (!self.hasHit) { // Move towards target var dx = self.targetX - self.x; var dy = self.targetY - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > self.speed) { self.x += dx / distance * self.speed; self.y += dy / distance * self.speed; } else { self.hasHit = true; } } // Remove if off screen if (self.y < -100 || self.y > 2800 || self.x < -100 || self.x > 2148) { self.alpha = 0; } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000033 }); /**** * Game Code ****/ // Sound assets // UI assets // Enemy assets // Hero assets // Game state var gameState = 'menu'; // 'menu', 'playing', 'victory' var currentMode = ''; var enemiesRequired = 0; var enemiesKilled = 0; var gameStarted = false; // Game objects var omar; var omarAI; var bullets = []; var enemies = []; var confettiParticles = []; var bloodParticles = []; var terrainElements = []; var lasers = []; var towers = []; var towerBullets = []; var enemyPath = []; var playerGold = 200; var goldText; var selectedTowerType = null; var placementMode = false; // UI elements var titleText; var scoreText; var modeButtons = []; // Enemy spawn timer - optimized for performance var enemySpawnTimer = 0; var enemySpawnRate = 60; // frames between spawns - faster to compensate for limited enemies // Initialize menu function initMenu() { gameState = 'menu'; // Title - Enhanced Sultan Style titleText = new Text2('My Sultan', { size: 120, fill: '#FFD700', // Gold stroke: '#8B0000', // Dark red stroke strokeThickness: 8, dropShadow: true, dropShadowColor: '#000000', dropShadowDistance: 5, dropShadowAngle: Math.PI / 4 }); titleText.anchor.set(0.5, 0.5); titleText.x = 1024; titleText.y = 400; game.addChild(titleText); // Add floating animation with enhanced rotation and scale effects tween(titleText, { y: 380, rotation: 0.1, scaleX: 1.05, scaleY: 1.05 }, { duration: 2500, easing: tween.elasticOut, onFinish: function onFinish() { // Create continuous floating effect with enhanced rotation and scaling function floatUp() { tween(titleText, { y: 370, rotation: 0.08, scaleX: 1.08, scaleY: 1.08 }, { duration: 3000, easing: tween.easeInOut, onFinish: floatDown }); } function floatDown() { tween(titleText, { y: 430, rotation: -0.08, scaleX: 0.98, scaleY: 0.98 }, { duration: 3000, easing: tween.easeInOut, onFinish: floatUp }); } floatDown(); } }); // Add enhanced pulsing color effect with magical transitions function createColorPulse() { tween(titleText, { tint: 0xFFB347 // Orange-gold tint }, { duration: 1200, easing: tween.elasticOut, onFinish: function onFinish() { tween(titleText, { tint: 0xFF6B35 // Deeper orange }, { duration: 800, easing: tween.easeInOut, onFinish: function onFinish() { tween(titleText, { tint: 0xFFD700 // Back to gold }, { duration: 1000, easing: tween.bounceOut, onFinish: createColorPulse }); } }); } }); } createColorPulse(); // Add enhanced scale pulsing with glow effect function createScalePulse() { tween(titleText, { scaleX: 1.15, scaleY: 1.15, alpha: 0.9 }, { duration: 2000, easing: tween.elasticInOut, onFinish: function onFinish() { tween(titleText, { scaleX: 1.0, scaleY: 1.0, alpha: 1.0 }, { duration: 2000, easing: tween.bounceOut, onFinish: createScalePulse }); } }); } createScalePulse(); // Create animated background with floating magical particles - optimized function createBackgroundEffects() { // Add mystical floating orbs - reduced count for (var i = 0; i < 6; i++) { var orb = new Text2('⚫', { size: 15 + Math.random() * 15, fill: '#4B0082' }); orb.anchor.set(0.5, 0.5); orb.x = Math.random() * 2048; orb.y = Math.random() * 2732; orb.alpha = 0.2 + Math.random() * 0.3; orb.tint = 0x9932CC; game.addChild(orb); // Add continuous floating animation (function (orbObj) { function floatOrb() { if (orbObj && orbObj.parent && gameState === 'menu') { tween(orbObj, { y: orbObj.y + (Math.random() - 0.5) * 100, x: orbObj.x + (Math.random() - 0.5) * 75, scaleX: 0.8 + Math.random() * 0.4, scaleY: 0.8 + Math.random() * 0.4, alpha: 0.1 + Math.random() * 0.3, rotation: Math.random() * Math.PI * 2 }, { duration: 3000 + Math.random() * 2000, easing: tween.easeInOut, onFinish: floatOrb }); } } floatOrb(); })(orb); } // Add golden energy streams - optimized for (var i = 0; i < 4; i++) { var stream = new Text2('◊', { size: 10 + Math.random() * 8, fill: '#FFD700' }); stream.anchor.set(0.5, 0.5); stream.x = Math.random() * 2048; stream.y = 2732 + Math.random() * 100; stream.alpha = 0.4; game.addChild(stream); // Add upward floating animation with safety checks (function (streamObj) { function floatUp() { if (streamObj && streamObj.parent && gameState === 'menu') { tween(streamObj, { y: -100, x: streamObj.x + (Math.random() - 0.5) * 150, rotation: Math.PI * 2, alpha: 0, scaleX: 0.5, scaleY: 0.5 }, { duration: 6000 + Math.random() * 2000, easing: tween.easeOut, onFinish: function onFinish() { if (streamObj && streamObj.parent && gameState === 'menu') { streamObj.y = 2732 + Math.random() * 100; streamObj.x = Math.random() * 2048; streamObj.alpha = 0.4; streamObj.scaleX = 1.0; streamObj.scaleY = 1.0; streamObj.rotation = 0; LK.setTimeout(floatUp, 1000); } } }); } } floatUp(); })(stream); } // Add mystical runes that appear and disappear var runeSymbols = ['◈', '◇', '◉', '◎', '⬟', '⬢', '⬡']; for (var i = 0; i < 6; i++) { var rune = new Text2(runeSymbols[Math.floor(Math.random() * runeSymbols.length)], { size: 40 + Math.random() * 20, fill: '#8A2BE2' }); rune.anchor.set(0.5, 0.5); rune.x = Math.random() * 2048; rune.y = Math.random() * 2732; rune.alpha = 0; game.addChild(rune); // Add mystical appearance animation (function (runeObj) { function runeAppear() { LK.setTimeout(function () { tween(runeObj, { alpha: 0.7, scaleX: 1.5, scaleY: 1.5, rotation: Math.PI }, { duration: 2000, easing: tween.easeOut, onFinish: function onFinish() { tween(runeObj, { alpha: 0, scaleX: 0.5, scaleY: 0.5, rotation: Math.PI * 2 }, { duration: 1500, easing: tween.easeIn, onFinish: function onFinish() { runeObj.x = Math.random() * 2048; runeObj.y = Math.random() * 2732; runeAppear(); } }); } }); }, Math.random() * 5000); } runeAppear(); })(rune); } } createBackgroundEffects(); // Add sparkle effects around title - optimized function createSparkles() { for (var i = 0; i < 3; i++) { var sparkle = new Text2('✨', { size: 25 + Math.random() * 15, fill: '#FFD700' }); sparkle.anchor.set(0.5, 0.5); sparkle.x = titleText.x + (Math.random() - 0.5) * 300; sparkle.y = titleText.y + (Math.random() - 0.5) * 150; sparkle.alpha = 0; game.addChild(sparkle); // Animate sparkle with enhanced effects tween(sparkle, { alpha: 1, scaleX: 1.5, scaleY: 1.5, rotation: Math.random() * Math.PI * 2 }, { duration: 800, easing: tween.easeOut, onFinish: function onFinish() { tween(sparkle, { alpha: 0, scaleX: 0.5, scaleY: 0.5, y: sparkle.y - 50 }, { duration: 600, easing: tween.easeIn, onFinish: function onFinish() { if (sparkle && sparkle.parent) { sparkle.destroy(); } } }); } }); } } // Create sparkles periodically - reduced frequency function sparkleTimer() { if (gameState === 'menu') { createSparkles(); LK.setTimeout(sparkleTimer, 3000 + Math.random() * 2000); } } LK.setTimeout(sparkleTimer, 1500); // Subtitle with enhanced effects var subtitle = new Text2('Choose Your Quest', { size: 50, fill: '#FFFFFF', stroke: '#FFD700', strokeThickness: 2 }); subtitle.anchor.set(0.5, 0.5); subtitle.x = 1024; subtitle.y = 500; subtitle.alpha = 0; subtitle.scaleX = 0.5; subtitle.scaleY = 0.5; game.addChild(subtitle); // Animate subtitle entrance LK.setTimeout(function () { tween(subtitle, { alpha: 1, scaleX: 1.0, scaleY: 1.0 }, { duration: 1500, easing: tween.elasticOut }); }, 1000); // Add subtle floating animation to subtitle function subtitleFloat() { tween(subtitle, { y: 490, rotation: 0.01 }, { duration: 3000, easing: tween.easeInOut, onFinish: function onFinish() { tween(subtitle, { y: 510, rotation: -0.01 }, { duration: 3000, easing: tween.easeInOut, onFinish: subtitleFloat }); } }); } LK.setTimeout(subtitleFloat, 2000); // Add color cycling effect to subtitle function subtitleColorCycle() { tween(subtitle, { tint: 0xE6E6FA }, { duration: 2500, easing: tween.easeInOut, onFinish: function onFinish() { tween(subtitle, { tint: 0xFFFFFF }, { duration: 2500, easing: tween.easeInOut, onFinish: subtitleColorCycle }); } }); } LK.setTimeout(subtitleColorCycle, 1500); // Create animated decorative border frame function createMenuBorder() { var borderElements = []; // Top border for (var i = 0; i < 20; i++) { var topBorder = new Text2('◆', { size: 25, fill: '#DAA520' }); topBorder.anchor.set(0.5, 0.5); topBorder.x = 100 + i * 90; topBorder.y = 150; topBorder.alpha = 0.8; game.addChild(topBorder); borderElements.push(topBorder); // Add pulsing animation with delay (function (element, delay) { LK.setTimeout(function () { function pulse() { tween(element, { scaleX: 1.3, scaleY: 1.3, tint: 0xFFD700 }, { duration: 1000, easing: tween.easeInOut, onFinish: function onFinish() { tween(element, { scaleX: 1.0, scaleY: 1.0, tint: 0xDAA520 }, { duration: 1000, easing: tween.easeInOut, onFinish: pulse }); } }); } pulse(); }, delay * 100); })(topBorder, i); } // Bottom border for (var i = 0; i < 20; i++) { var bottomBorder = new Text2('◇', { size: 25, fill: '#DAA520' }); bottomBorder.anchor.set(0.5, 0.5); bottomBorder.x = 100 + i * 90; bottomBorder.y = 2580; bottomBorder.alpha = 0.8; game.addChild(bottomBorder); borderElements.push(bottomBorder); // Add wave animation (function (element, index) { function wave() { tween(element, { y: 2580 + Math.sin(LK.ticks * 0.1 + index * 0.5) * 15, rotation: Math.sin(LK.ticks * 0.05 + index * 0.3) * 0.2 }, { duration: 50, easing: tween.linear, onFinish: wave }); } wave(); })(bottomBorder, i); } // Left border for (var i = 0; i < 25; i++) { var leftBorder = new Text2('◊', { size: 20, fill: '#DAA520' }); leftBorder.anchor.set(0.5, 0.5); leftBorder.x = 100; leftBorder.y = 200 + i * 100; leftBorder.alpha = 0.8; game.addChild(leftBorder); borderElements.push(leftBorder); // Add flowing animation (function (element, index) { LK.setTimeout(function () { function flow() { tween(element, { x: 120, scaleX: 1.2, scaleY: 1.2, tint: 0xB8860B }, { duration: 2000, easing: tween.easeInOut, onFinish: function onFinish() { tween(element, { x: 100, scaleX: 1.0, scaleY: 1.0, tint: 0xDAA520 }, { duration: 2000, easing: tween.easeInOut, onFinish: flow }); } }); } flow(); }, index * 150); })(leftBorder, i); } // Right border for (var i = 0; i < 25; i++) { var rightBorder = new Text2('◈', { size: 20, fill: '#DAA520' }); rightBorder.anchor.set(0.5, 0.5); rightBorder.x = 1948; rightBorder.y = 200 + i * 100; rightBorder.alpha = 0.8; game.addChild(rightBorder); borderElements.push(rightBorder); // Add flowing animation (opposite direction) (function (element, index) { LK.setTimeout(function () { function flow() { tween(element, { x: 1928, scaleX: 1.2, scaleY: 1.2, tint: 0xB8860B }, { duration: 2000, easing: tween.easeInOut, onFinish: function onFinish() { tween(element, { x: 1948, scaleX: 1.0, scaleY: 1.0, tint: 0xDAA520 }, { duration: 2000, easing: tween.easeInOut, onFinish: flow }); } }); } flow(); }, index * 150); })(rightBorder, i); } // Corner ornaments var corners = [{ x: 100, y: 150, symbol: '◉' }, { x: 1948, y: 150, symbol: '◉' }, { x: 100, y: 2580, symbol: '◉' }, { x: 1948, y: 2580, symbol: '◉' }]; corners.forEach(function (corner, index) { var ornament = new Text2(corner.symbol, { size: 40, fill: '#FFD700' }); ornament.anchor.set(0.5, 0.5); ornament.x = corner.x; ornament.y = corner.y; ornament.alpha = 0.9; game.addChild(ornament); // Add rotating glow animation function rotateGlow() { tween(ornament, { rotation: Math.PI * 2, scaleX: 1.5, scaleY: 1.5, tint: 0xFF6347 }, { duration: 3000, easing: tween.easeInOut, onFinish: function onFinish() { ornament.rotation = 0; tween(ornament, { scaleX: 1.0, scaleY: 1.0, tint: 0xFFD700 }, { duration: 1000, easing: tween.easeOut, onFinish: rotateGlow }); } }); } LK.setTimeout(rotateGlow, index * 500); }); } createMenuBorder(); // Mode buttons with enhanced animations var nightButton = new ModeButton(); nightButton.setMode('Night Mode (100 enemies)', 'night', 100); nightButton.x = 1024; nightButton.y = 800; nightButton.alpha = 0; modeButtons.push(nightButton); game.addChild(nightButton); // Enhanced entrance animation for night button with dramatic effects nightButton.scaleX = 0; nightButton.scaleY = 0; nightButton.y = 850; nightButton.rotation = Math.PI; nightButton.tint = 0x000080; tween(nightButton, { alpha: 1, scaleX: 1.0, scaleY: 1.0, y: 800, rotation: 0, tint: 0xFFFFFF }, { duration: 1800, easing: tween.elasticOut }); // Add magical particle trail effect to night button function createNightButtonTrail() { for (var i = 0; i < 4; i++) { var trail = new Text2('⭐', { size: 15 + Math.random() * 10, fill: '#87CEEB' }); trail.anchor.set(0.5, 0.5); trail.x = nightButton.x + (Math.random() - 0.5) * 200; trail.y = nightButton.y + (Math.random() - 0.5) * 100; trail.alpha = 0.8; game.addChild(trail); tween(trail, { y: trail.y - 50, alpha: 0, scaleX: 0.3, scaleY: 0.3, rotation: Math.PI }, { duration: 2000, easing: tween.easeOut, onFinish: function onFinish() { trail.destroy(); } }); } } function nightButtonTrailTimer() { createNightButtonTrail(); LK.setTimeout(nightButtonTrailTimer, 1500 + Math.random() * 1000); } LK.setTimeout(nightButtonTrailTimer, 2000); // Add continuous glow effect to night button function nightButtonGlow() { tween(nightButton, { tint: 0x4169E1, scaleX: 1.05, scaleY: 1.05 }, { duration: 1500, easing: tween.easeInOut, onFinish: function onFinish() { tween(nightButton, { tint: 0xFFFFFF, scaleX: 1.0, scaleY: 1.0 }, { duration: 1500, easing: tween.easeInOut, onFinish: nightButtonGlow }); } }); } LK.setTimeout(nightButtonGlow, 500); var dayButton = new ModeButton(); dayButton.setMode('Day Mode (100 enemies)', 'day', 100); dayButton.x = 1024; dayButton.y = 1000; dayButton.alpha = 0; modeButtons.push(dayButton); game.addChild(dayButton); // Enhanced entrance animation for day button with sun ray effects dayButton.scaleX = 0; dayButton.scaleY = 0; dayButton.y = 1050; dayButton.tint = 0xFFA500; LK.setTimeout(function () { tween(dayButton, { alpha: 1, scaleX: 1.0, scaleY: 1.0, y: 1000, rotation: 0, tint: 0xFFFFFF }, { duration: 1600, easing: tween.elasticOut }); // Add sun ray effects around day button for (var r = 0; r < 12; r++) { var ray = new Text2('|', { size: 60, fill: '#FFD700' }); ray.anchor.set(0.5, 0); ray.x = dayButton.x; ray.y = dayButton.y; ray.rotation = r * Math.PI / 6; ray.alpha = 0; ray.scaleX = 2; game.addChild(ray); // Animate rays appearing (function (rayObj, index) { LK.setTimeout(function () { tween(rayObj, { alpha: 0.4, scaleY: 1.5, y: rayObj.y - 30 }, { duration: 800, easing: tween.easeOut, onFinish: function onFinish() { // Add continuous pulsing to rays function pulsRay() { tween(rayObj, { alpha: 0.6, scaleY: 1.8 }, { duration: 2000, easing: tween.easeInOut, onFinish: function onFinish() { tween(rayObj, { alpha: 0.3, scaleY: 1.2 }, { duration: 2000, easing: tween.easeInOut, onFinish: pulsRay }); } }); } pulsRay(); } }); }, index * 100); })(ray, r); } }, 600); // Add continuous glow effect to day button function dayButtonGlow() { tween(dayButton, { tint: 0xFFD700, scaleX: 1.05, scaleY: 1.05 }, { duration: 1800, easing: tween.easeInOut, onFinish: function onFinish() { tween(dayButton, { tint: 0xFFFFFF, scaleX: 1.0, scaleY: 1.0 }, { duration: 1800, easing: tween.easeInOut, onFinish: dayButtonGlow }); } }); } LK.setTimeout(dayButtonGlow, 800); var betrayalButton = new ModeButton(); betrayalButton.setMode('My Sultan Became My Enemy (400)', 'betrayal', 400); betrayalButton.x = 1024; betrayalButton.y = 1200; betrayalButton.alpha = 0; modeButtons.push(betrayalButton); game.addChild(betrayalButton); // Enhanced dramatic entrance for betrayal button with ominous effects betrayalButton.scaleX = 0; betrayalButton.scaleY = 0; betrayalButton.y = 1250; betrayalButton.tint = 0x800000; LK.setTimeout(function () { // Add screen flash before betrayal button appears LK.effects.flashScreen(0x8B0000, 300); tween(betrayalButton, { alpha: 1, scaleX: 1.0, scaleY: 1.0, y: 1200, rotation: 0, tint: 0xFFFFFF }, { duration: 2000, easing: tween.elasticOut }); // Add ominous smoke effects around betrayal button function createOminousSmoke() { for (var s = 0; s < 6; s++) { var smoke = new Text2('☁', { size: 30 + Math.random() * 20, fill: '#2F2F2F' }); smoke.anchor.set(0.5, 0.5); smoke.x = betrayalButton.x + (Math.random() - 0.5) * 300; smoke.y = betrayalButton.y + 100 + Math.random() * 50; smoke.alpha = 0.4; smoke.tint = 0x8B0000; game.addChild(smoke); tween(smoke, { y: smoke.y - 150, alpha: 0, scaleX: 2.0, scaleY: 2.0, rotation: Math.PI }, { duration: 4000, easing: tween.easeOut, onFinish: function onFinish() { smoke.destroy(); } }); } } function smokeTimer() { createOminousSmoke(); LK.setTimeout(smokeTimer, 2000 + Math.random() * 1500); } smokeTimer(); // Add red lightning effects function createRedLightning() { for (var l = 0; l < 3; l++) { var lightning = new Text2('⚡', { size: 40 + Math.random() * 20, fill: '#FF0000' }); lightning.anchor.set(0.5, 0.5); lightning.x = betrayalButton.x + (Math.random() - 0.5) * 400; lightning.y = betrayalButton.y + (Math.random() - 0.5) * 200; lightning.alpha = 0; game.addChild(lightning); tween(lightning, { alpha: 1, scaleX: 2.0, scaleY: 2.0 }, { duration: 100, easing: tween.easeOut, onFinish: function onFinish() { tween(lightning, { alpha: 0, scaleX: 0.5, scaleY: 0.5 }, { duration: 200, easing: tween.easeIn, onFinish: function onFinish() { lightning.destroy(); } }); } }); } } function lightningTimer() { if (Math.random() < 0.4) { createRedLightning(); } LK.setTimeout(lightningTimer, 1000 + Math.random() * 2000); } LK.setTimeout(lightningTimer, 3000); // Add dramatic shake effect after entrance LK.setTimeout(function () { function shakeEffect() { tween(betrayalButton, { x: 1024 + (Math.random() - 0.5) * 10, rotation: (Math.random() - 0.5) * 0.05 }, { duration: 100, easing: tween.easeOut, onFinish: function onFinish() { tween(betrayalButton, { x: 1024, rotation: 0 }, { duration: 100, easing: tween.easeOut }); } }); } // Random shake every few seconds function randomShake() { if (Math.random() < 0.3) { shakeEffect(); } LK.setTimeout(randomShake, 2000 + Math.random() * 3000); } randomShake(); }, 2000); }, 600); // Add continuous dramatic glow effect to betrayal button function betrayalButtonGlow() { tween(betrayalButton, { tint: 0xFF4500, scaleX: 1.08, scaleY: 1.08, rotation: 0.02 }, { duration: 1200, easing: tween.easeInOut, onFinish: function onFinish() { tween(betrayalButton, { tint: 0xFFFFFF, scaleX: 1.0, scaleY: 1.0, rotation: -0.02 }, { duration: 1200, easing: tween.easeInOut, onFinish: betrayalButtonGlow }); } }); } LK.setTimeout(betrayalButtonGlow, 1100); } function startGame(mode, enemyCount) { gameState = 'playing'; currentMode = mode; enemiesRequired = enemyCount; enemiesKilled = 0; gameStarted = true; // Clear menu while (game.children.length > 0) { var child = game.children[0]; child.destroy(); } // Set background based on mode if (mode === 'night') { // Add moon glow animation var _createMoonGlow = function createMoonGlow() { tween(moon, { scaleX: 1.2, scaleY: 1.2, alpha: 0.8 }, { duration: 3000, easing: tween.easeInOut, onFinish: function onFinish() { tween(moon, { scaleX: 1.0, scaleY: 1.0, alpha: 1.0 }, { duration: 3000, easing: tween.easeInOut, onFinish: _createMoonGlow }); } }); }; game.setBackgroundColor(0x000033); // Add night atmosphere effects // Create moon glow effect var moon = new Text2('🌙', { size: 80, fill: '#F0F8FF' }); moon.anchor.set(0.5, 0.5); moon.x = 1800; moon.y = 300; game.addChild(moon); _createMoonGlow(); // Add twinkling stars for (var s = 0; s < 15; s++) { var star = new Text2('⭐', { size: 20 + Math.random() * 15, fill: '#FFFFFF' }); star.anchor.set(0.5, 0.5); star.x = Math.random() * 2048; star.y = Math.random() * 400 + 50; star.alpha = 0.3 + Math.random() * 0.7; game.addChild(star); // Add twinkling animation with random delay (function (starObj) { var _twinkle = function twinkle() { tween(starObj, { alpha: 0.2, scaleX: 0.5, scaleY: 0.5 }, { duration: 1000 + Math.random() * 1000, easing: tween.easeInOut, onFinish: function onFinish() { tween(starObj, { alpha: 1.0, scaleX: 1.0, scaleY: 1.0 }, { duration: 1000 + Math.random() * 1000, easing: tween.easeInOut, onFinish: _twinkle }); } }); }; LK.setTimeout(_twinkle, Math.random() * 2000); })(star); } } else if (mode === 'day') { game.setBackgroundColor(0x87CEEB); // Add day atmosphere effects // Create sun with rays var sun = new Text2('☀️', { size: 100, fill: '#FFD700' }); sun.anchor.set(0.5, 0.5); sun.x = 250; sun.y = 250; game.addChild(sun); // Add sun rotation animation tween(sun, { rotation: Math.PI * 2 }, { duration: 10000, easing: tween.linear, onFinish: function onFinish() { sun.rotation = 0; // Create recursive rotation arguments.callee(); } }); // Add sun pulsing glow var _sunGlow = function sunGlow() { tween(sun, { scaleX: 1.1, scaleY: 1.1, tint: 0xFFA500 }, { duration: 2000, easing: tween.easeInOut, onFinish: function onFinish() { tween(sun, { scaleX: 1.0, scaleY: 1.0, tint: 0xFFFFFF }, { duration: 2000, easing: tween.easeInOut, onFinish: _sunGlow }); } }); }; _sunGlow(); // Create floating clouds for (var c = 0; c < 6; c++) { var cloud = new Text2('☁️', { size: 60 + Math.random() * 30, fill: '#FFFFFF' }); cloud.anchor.set(0.5, 0.5); cloud.x = Math.random() * 2048; cloud.y = Math.random() * 300 + 100; cloud.alpha = 0.7 + Math.random() * 0.3; game.addChild(cloud); // Add cloud floating animation (function (cloudObj) { var startX = cloudObj.x; var _float2 = function _float() { tween(cloudObj, { x: startX + (Math.random() - 0.5) * 200, scaleX: 0.9 + Math.random() * 0.2, scaleY: 0.9 + Math.random() * 0.2 }, { duration: 8000 + Math.random() * 4000, easing: tween.easeInOut, onFinish: _float2 }); }; _float2(); })(cloud); } // Add light particles floating upward var createDayParticles = function createDayParticles() { for (var p = 0; p < 3; p++) { var particle = new Text2('✨', { size: 15 + Math.random() * 10, fill: '#FFD700' }); particle.anchor.set(0.5, 0.5); particle.x = Math.random() * 2048; particle.y = 2732; particle.alpha = 0.5; game.addChild(particle); tween(particle, { y: -100, alpha: 0, rotation: Math.PI * 4, scaleX: 0.3, scaleY: 0.3 }, { duration: 8000 + Math.random() * 4000, easing: tween.easeOut, onFinish: function onFinish() { particle.destroy(); } }); } }; // Create day particles periodically var _dayParticleTimer = function dayParticleTimer() { createDayParticles(); LK.setTimeout(_dayParticleTimer, 3000 + Math.random() * 2000); }; _dayParticleTimer(); } else if (mode === 'betrayal') { game.setBackgroundColor(0x8B0000); } // Create Omar omar = new Omar(); omar.x = 1024; omar.y = 2200; // Position Omar on the road game.addChild(omar); // Create and activate AI omarAI = new OmarAI(); omarAI.activate(); game.addChild(omarAI); // Generate terrain for the mode generateTerrain(mode); // Create score text scoreText = new Text2('Enemies: 0 / ' + enemiesRequired, { size: 60, fill: '#FFFFFF' }); scoreText.anchor.set(0.5, 0); LK.gui.top.addChild(scoreText); // Create gold display goldText = new Text2('Gold: ' + playerGold, { size: 50, fill: '#FFD700' }); goldText.anchor.set(0, 0); goldText.x = 50; goldText.y = 100; LK.gui.topLeft.addChild(goldText); // Create tower placement buttons var towerButton = new Text2('Build Tower (50g)', { size: 40, fill: '#8B4513', stroke: '#FFFFFF', strokeThickness: 2 }); towerButton.anchor.set(0, 0); towerButton.x = 50; towerButton.y = 200; LK.gui.topLeft.addChild(towerButton); // Create enemy path enemyPath = [{ x: 1024, y: -50 }, { x: 1024, y: 400 }, { x: 500, y: 600 }, { x: 1500, y: 800 }, { x: 1024, y: 1200 }, { x: 1024, y: 2300 }]; // Reset arrays bullets = []; enemies = []; confettiParticles = []; bloodParticles = []; terrainElements = []; lasers = []; towers = []; towerBullets = []; playerGold = 200; placementMode = false; selectedTowerType = null; // Reset spawn timer enemySpawnTimer = 0; // After score 90, spawn enemies much more frequently if (enemiesKilled >= 90) { enemySpawnRate = Math.max(10, 30 - Math.floor((enemiesKilled - 90) / 10) * 5); } else { enemySpawnRate = Math.max(30, 90 - Math.floor(enemiesKilled / 20) * 10); } } function generateTerrain(mode) { // Clear existing terrain for (var i = terrainElements.length - 1; i >= 0; i--) { terrainElements[i].destroy(); } terrainElements = []; // Add road in the center with mode-specific enhancements var road = new Terrain(); road.init('road', 1024, 1366); // Apply mode-specific road effects if (mode === 'night') { road.tint = 0x666699; // Darker bluish road for night road.alpha = 0.9; } else if (mode === 'day') { road.tint = 0xFFFFBB; // Brighter, sunlit road for day road.alpha = 1.0; // Add subtle road shimmer effect for day var _roadShimmer = function roadShimmer() { tween(road, { tint: 0xFFFFDD }, { duration: 3000, easing: tween.easeInOut, onFinish: function onFinish() { tween(road, { tint: 0xFFFFBB }, { duration: 3000, easing: tween.easeInOut, onFinish: _roadShimmer }); } }); }; _roadShimmer(); } else if (mode === 'betrayal') { road.tint = 0xAA6666; // Reddish road for betrayal mode } terrainElements.push(road); game.addChild(road); // Add castle at the top var castle = new Terrain(); castle.init('castle', 1024, 300); terrainElements.push(castle); game.addChild(castle); // Add some decorative terrain elements based on mode if (mode === 'day') { var _loop = function _loop() { terrain = new Terrain(); type = Math.random() > 0.5 ? 'stone' : 'dirt'; terrain.init(type, Math.random() * 1700 + 174, Math.random() * 2000 + 400); // Add bright daylight tint to terrain terrain.tint = 0xFFFF99; // Bright sunny tint terrain.alpha = 1.0; // Add floating animation to terrain objects with enhanced brightness effects terrain.startY = terrain.y; function createTerrainFloat(terrainObj) { tween(terrainObj, { y: terrainObj.startY - 5, rotation: 0.05, tint: 0xFFFFAA, scaleX: 1.02, scaleY: 1.02 }, { duration: 2000 + Math.random() * 1000, easing: tween.easeInOut, onFinish: function onFinish() { tween(terrainObj, { y: terrainObj.startY + 5, rotation: -0.05, tint: 0xFFFF99, scaleX: 1.0, scaleY: 1.0 }, { duration: 2000 + Math.random() * 1000, easing: tween.easeInOut, onFinish: function onFinish() { createTerrainFloat(terrainObj); } }); } }); } createTerrainFloat(terrain); terrainElements.push(terrain); game.addChild(terrain); }, terrain, type; // Add some stones and dirt for day mode for (var i = 0; i < 8; i++) { _loop(); } // Add sun rays effect for (var r = 0; r < 8; r++) { var ray = new Text2('|', { size: 400, fill: '#FFD700' }); ray.anchor.set(0.5, 0); ray.x = 250 + Math.cos(r * Math.PI / 4) * 400; ray.y = 250; ray.rotation = r * Math.PI / 4; ray.alpha = 0.1; ray.scaleX = 3; game.addChild(ray); // Add ray animation (function (rayObj) { var _rayPulse = function rayPulse() { tween(rayObj, { alpha: 0.2, scaleX: 4, scaleY: 1.2 }, { duration: 4000 + Math.random() * 2000, easing: tween.easeInOut, onFinish: function onFinish() { tween(rayObj, { alpha: 0.05, scaleX: 3, scaleY: 1.0 }, { duration: 4000 + Math.random() * 2000, easing: tween.easeInOut, onFinish: _rayPulse }); } }); }; LK.setTimeout(_rayPulse, Math.random() * 2000); })(ray); } } else if (mode === 'night') { // Add fewer, darker terrain for night mode with mystical effects for (var i = 0; i < 5; i++) { var terrain = new Terrain(); terrain.init('stone', Math.random() * 1700 + 174, Math.random() * 2000 + 400); // Add dark tint to terrain for night mode terrain.tint = 0x4444AA; terrain.alpha = 0.8; // Add mystical glow animation to night terrain (function (terrainObj) { var _mysticalGlow = function mysticalGlow() { tween(terrainObj, { tint: 0x6666FF, alpha: 0.9 }, { duration: 3000 + Math.random() * 2000, easing: tween.easeInOut, onFinish: function onFinish() { tween(terrainObj, { tint: 0x4444AA, alpha: 0.8 }, { duration: 3000 + Math.random() * 2000, easing: tween.easeInOut, onFinish: _mysticalGlow }); } }); }; LK.setTimeout(_mysticalGlow, Math.random() * 1000); })(terrain); terrainElements.push(terrain); game.addChild(terrain); } // Add night fog effect var fog = new Text2('🌫️', { size: 150, fill: '#E6E6FA' }); fog.anchor.set(0.5, 0.5); fog.x = 1024; fog.y = 1500; fog.alpha = 0.3; game.addChild(fog); // Add fog movement animation var _fogDrift = function fogDrift() { tween(fog, { x: 1024 + (Math.random() - 0.5) * 300, scaleX: 1.2 + Math.random() * 0.5, scaleY: 1.2 + Math.random() * 0.5, alpha: 0.2 + Math.random() * 0.2 }, { duration: 6000 + Math.random() * 4000, easing: tween.easeInOut, onFinish: _fogDrift }); }; _fogDrift(); } else if (mode === 'betrayal') { // Add strategic terrain for betrayal mode for (var i = 0; i < 10; i++) { var terrain = new Terrain(); var type = Math.random() > 0.3 ? 'stone' : 'dirt'; terrain.init(type, Math.random() * 1700 + 174, Math.random() * 2000 + 400); terrainElements.push(terrain); game.addChild(terrain); } } } function spawnEnemy() { var enemy = new Enemy(); // Determine enemy type based on mode and progress var enemyType = 'aamir'; var progress = enemiesKilled / enemiesRequired; if (currentMode === 'betrayal') { if (Math.random() < 0.3) { enemyType = 'sultan'; } else if (progress > 0.7 && Math.random() < 0.2) { enemyType = 'vega'; } } else { if (progress > 0.8 && Math.random() < 0.15) { enemyType = 'vega'; } } enemy.init(enemyType); enemy.x = Math.random() * 1700 + 174; // Better bounds to keep enemies visible enemy.y = -50; // Add spawn entrance animation enemy.alpha = 0; enemy.scaleX = 0.3; enemy.scaleY = 0.3; enemy.rotation = Math.PI; // Animate enemy entrance tween(enemy, { alpha: 1, scaleX: 1.0, scaleY: 1.0, rotation: 0, tint: 0xFFFFFF }, { duration: 500, easing: tween.elasticOut }); // Add spawn glow effect tween(enemy, { tint: 0xFF6B35 }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { tween(enemy, { tint: 0xFFFFFF }, { duration: 400, easing: tween.easeOut }); } }); enemies.push(enemy); game.addChild(enemy); } function checkVictory() { // Check for sultan meeting in night and day modes at score 50 if ((currentMode === 'night' || currentMode === 'day') && enemiesKilled >= 50 && gameState !== 'sultanMeeting') { gameState = 'sultanMeeting'; LK.getSound('victory').play(); // Create sultan character var sultanChar = new Terrain(); sultanChar.init('sultan', 1024, 1366); game.addChild(sultanChar); tween(sultanChar, { scaleX: 10, scaleY: 10 }, { duration: 2000, easing: tween.easeOut }); // Sultan meeting text var meetingText = new Text2('My Sultan Arrives!', { size: 80, fill: '#FFD700', stroke: '#8B0000', strokeThickness: 4 }); meetingText.anchor.set(0.5, 0.5); meetingText.x = 1024; meetingText.y = 800; game.addChild(meetingText); tween(meetingText, { scaleX: 1.2, scaleY: 1.2, tint: 0xFFB347 }, { duration: 1000, easing: tween.easeInOut }); // Create golden confetti for sultan meeting for (var i = 0; i < 30; i++) { var confetti = new Confetti(); confetti.x = Math.random() * 2048; confetti.y = Math.random() * 500 + 500; confetti.tint = 0xFFD700; // Golden confetti for sultan confettiParticles.push(confetti); game.addChild(confetti); } // Continue game after sultan meeting LK.setTimeout(function () { gameState = 'playing'; meetingText.destroy(); sultanChar.destroy(); }, 3000); return; } // Check for sultan meeting in betrayal mode at exactly 10 enemies killed if (currentMode === 'betrayal' && enemiesKilled === 10 && gameState !== 'sultanMeeting') { gameState = 'sultanMeeting'; LK.getSound('victory').play(); // Create sultan character var sultanChar = new Terrain(); sultanChar.init('sultan', 1024, 1366); game.addChild(sultanChar); tween(sultanChar, { scaleX: 10, scaleY: 10 }, { duration: 2000, easing: tween.easeOut }); // Sultan betrayal meeting text var meetingText = new Text2('The Sultan Has Turned Against Us!', { size: 70, fill: '#FF0000', stroke: '#8B0000', strokeThickness: 4 }); meetingText.anchor.set(0.5, 0.5); meetingText.x = 1024; meetingText.y = 800; game.addChild(meetingText); tween(meetingText, { scaleX: 1.2, scaleY: 1.2, tint: 0xFF4500 }, { duration: 1000, easing: tween.easeInOut }); // Create red confetti for betrayal meeting for (var i = 0; i < 30; i++) { var confetti = new Confetti(); confetti.x = Math.random() * 2048; confetti.y = Math.random() * 500 + 500; confetti.tint = 0xFF0000; // Red confetti for betrayal confettiParticles.push(confetti); game.addChild(confetti); } // Continue game after sultan meeting LK.setTimeout(function () { gameState = 'playing'; meetingText.destroy(); sultanChar.destroy(); }, 3000); return; } if (enemiesKilled >= enemiesRequired) { // Add celebration sparkles around victory text var createVictorySparkles = function createVictorySparkles() { for (var s = 0; s < 10; s++) { var sparkle = new Text2('✨', { size: 40 + Math.random() * 30, fill: '#FFD700' }); sparkle.anchor.set(0.5, 0.5); sparkle.x = victoryText.x + (Math.random() - 0.5) * 500; sparkle.y = victoryText.y + (Math.random() - 0.5) * 300; sparkle.alpha = 0; game.addChild(sparkle); tween(sparkle, { alpha: 1, scaleX: 2.0, scaleY: 2.0, rotation: Math.PI * 2 }, { duration: 1200, easing: tween.easeOut, onFinish: function onFinish() { tween(sparkle, { alpha: 0, scaleX: 0.2, scaleY: 0.2 }, { duration: 800, easing: tween.easeIn, onFinish: function onFinish() { sparkle.destroy(); } }); } }); } }; gameState = 'victory'; LK.getSound('victory').play(); // Create optimized confetti (reduced count for performance) for (var i = 0; i < 20; i++) { var confetti = new Confetti(); confetti.x = Math.random() * 2048; confetti.y = Math.random() * 500 + 500; // Random colors for confetti var colors = [0xFFD700, 0xFF1493, 0x00FF00, 0x00BFFF, 0xFF4500]; confetti.tint = colors[Math.floor(Math.random() * colors.length)]; confettiParticles.push(confetti); game.addChild(confetti); } // Victory text with enhanced entrance animation var victoryText = new Text2('Victory! Love Conquers All!', { size: 70, fill: '#FFD700', stroke: '#8B0000', strokeThickness: 4 }); victoryText.anchor.set(0.5, 0.5); victoryText.x = 1024; victoryText.y = 1366; victoryText.alpha = 0; victoryText.scaleX = 0.3; victoryText.scaleY = 0.3; game.addChild(victoryText); // Animate victory text entrance tween(victoryText, { alpha: 1, scaleX: 1.2, scaleY: 1.2, rotation: 0.1 }, { duration: 1000, easing: tween.elasticOut, onFinish: function onFinish() { // Add continuous celebration animation function celebrateAnimation() { tween(victoryText, { scaleX: 1.3, scaleY: 1.3, tint: 0xFF6B35, rotation: -0.1 }, { duration: 800, easing: tween.easeInOut, onFinish: function onFinish() { tween(victoryText, { scaleX: 1.1, scaleY: 1.1, tint: 0xFFD700, rotation: 0.1 }, { duration: 800, easing: tween.easeInOut, onFinish: celebrateAnimation }); } }); } celebrateAnimation(); } }); createVictorySparkles(); LK.setTimeout(createVictorySparkles, 1500); LK.setTimeout(createVictorySparkles, 3000); // Return to menu after 5 seconds LK.setTimeout(function () { // Clear game while (game.children.length > 0) { var child = game.children[0]; child.destroy(); } while (LK.gui.top.children.length > 0) { var child = LK.gui.top.children[0]; child.destroy(); } // Reset arrays bullets = []; enemies = []; confettiParticles = []; bloodParticles = []; terrainElements = []; lasers = []; modeButtons = []; initMenu(); }, 5000); } } // Touch controls var isTouching = false; var lastTapTime = 0; var doubleTapDelay = 300; // 300ms for double tap detection game.down = function (x, y, obj) { if (gameState === 'playing') { // Check if clicking on tower placement button area if (x < 300 && y < 300) { if (x > 50 && x < 250 && y > 200 && y < 250) { placementMode = !placementMode; selectedTowerType = placementMode ? 'tower' : null; return; } } // Tower placement mode if (placementMode && selectedTowerType === 'tower' && playerGold >= 50) { // Check if position is valid (not too close to path or other towers) var validPosition = true; // Check distance from path for (var i = 0; i < enemyPath.length; i++) { var pathPoint = enemyPath[i]; var dx = x - pathPoint.x; var dy = y - pathPoint.y; if (Math.sqrt(dx * dx + dy * dy) < 100) { validPosition = false; break; } } // Check distance from other towers for (var i = 0; i < towers.length; i++) { var tower = towers[i]; var dx = x - tower.x; var dy = y - tower.y; if (Math.sqrt(dx * dx + dy * dy) < 120) { validPosition = false; break; } } if (validPosition && y > 400 && y < 2200 && x > 200 && x < 1848) { var newTower = new Tower(); newTower.x = x; newTower.y = y; towers.push(newTower); game.addChild(newTower); playerGold -= 50; updateGoldDisplay(); placementMode = false; selectedTowerType = null; } return; } isTouching = true; var currentTime = Date.now(); // Check for double tap to shoot laser if (currentTime - lastTapTime < doubleTapDelay) { // Add screen shake effect for laser var screenShake = function screenShake() { tween(game, { x: (Math.random() - 0.5) * 15, y: (Math.random() - 0.5) * 15 }, { duration: 50, easing: tween.easeOut, onFinish: function onFinish() { tween(game, { x: 0, y: 0 }, { duration: 100, easing: tween.easeOut }); } }); }; omar.shootLaser(); for (var shakeCount = 0; shakeCount < 3; shakeCount++) { LK.setTimeout(screenShake, shakeCount * 100); } } else { omar.shoot(); } lastTapTime = currentTime; } }; game.up = function (x, y, obj) { isTouching = false; }; game.move = function (x, y, obj) { if (gameState === 'playing' && omar) { // Manual control overrides AI if (omarAI) { omarAI.deactivate(); } omar.x = Math.max(40, Math.min(2008, x)); if (isTouching) { omar.shoot(); } // Reactivate AI after a short delay LK.setTimeout(function () { if (omarAI) { omarAI.activate(); } }, 1000); } }; game.update = function () { if (gameState === 'playing') { // Spawn enemies with better control enemySpawnTimer++; if (enemySpawnTimer >= enemySpawnRate && enemies.length < 12) { spawnEnemy(); enemySpawnTimer = 0; // Gradual spawn rate increase with reasonable limits if (enemiesKilled >= 90) { enemySpawnRate = Math.max(20, 45 - Math.floor((enemiesKilled - 90) / 15) * 3); } else { enemySpawnRate = Math.max(40, 80 - Math.floor(enemiesKilled / 25) * 5); } } // Update bullets - remove bullets that go too far off screen for performance for (var i = bullets.length - 1; i >= 0; i--) { var bullet = bullets[i]; if (!bullet || bullet.alpha <= 0) { if (bullet) bullet.destroy(); bullets.splice(i, 1); continue; } if (bullet.lastY === undefined) bullet.lastY = bullet.y; // Remove bullets that are way off screen for performance if (bullet.y < -500 || bullet.y > 2800) { bullet.destroy(); bullets.splice(i, 1); continue; } // Optimized collision detection - only check nearby enemies var hit = false; for (var j = enemies.length - 1; j >= 0 && !hit; j--) { var enemy = enemies[j]; if (!enemy || enemy.alpha <= 0) continue; // Quick distance check before expensive intersection var dx = bullet.x - enemy.x; var dy = bullet.y - enemy.y; if (dx * dx + dy * dy < 8000 && bullet.intersects(enemy)) { // Add bullet impact flash effect tween(enemy, { tint: 0xFFFFFF, scaleX: 1.2, scaleY: 1.2 }, { duration: 80, easing: tween.easeOut, onFinish: function onFinish() { tween(enemy, { tint: 0xFF0000, scaleX: 1.0, scaleY: 1.0 }, { duration: 120, easing: tween.easeOut }); } }); // Create impact explosion particles for (var p = 0; p < 8; p++) { var spark = new BloodParticle(); spark.x = bullet.x; spark.y = bullet.y; var angle = p * Math.PI * 2 / 8; spark.speedX = Math.cos(angle) * 4; spark.speedY = Math.sin(angle) * 4; spark.life = 15; bloodParticles.push(spark); game.addChild(spark); } // Add blood spray even when enemy is just damaged (not killed) for (var k = 0; k < 4; k++) { var blood = new BloodParticle(); blood.x = enemy.x + (Math.random() - 0.5) * 40; blood.y = enemy.y + (Math.random() - 0.5) * 40; blood.speedX = (Math.random() - 0.5) * 8; blood.speedY = Math.random() * -6 - 2; blood.life = 25; blood.scaleX = 0.6; blood.scaleY = 0.6; blood.tint = 0xAA0000; bloodParticles.push(blood); game.addChild(blood); } if (enemy.takeDamage()) { // Enhanced death animation with screen flash LK.effects.flashScreen(0xFF4444, 150); tween(enemy, { scaleX: 1.8, scaleY: 1.8, alpha: 0, rotation: Math.PI * 0.8, tint: 0xFF0000 }, { duration: 400, easing: tween.bounceOut, onFinish: function onFinish() { enemy.destroy(); } }); // Create optimized blood spray effect - reduced particle count if (bloodParticles.length < 50) { // Limit total particles for (var k = 0; k < 6; k++) { var blood = new BloodParticle(); blood.x = enemy.x + (Math.random() - 0.5) * 60; blood.y = enemy.y + (Math.random() - 0.5) * 60; blood.speedX = (Math.random() - 0.5) * 12; blood.speedY = Math.random() * -8 - 3; blood.life = 35; // Shorter life // Add variety to blood particle colors var bloodColors = [0xFF0000, 0xCC0000, 0x990000]; blood.tint = bloodColors[Math.floor(Math.random() * bloodColors.length)]; bloodParticles.push(blood); game.addChild(blood); } } enemies.splice(j, 1); enemiesKilled++; // Update score immediately when each enemy dies scoreText.setText('Enemies: ' + enemiesKilled + ' / ' + enemiesRequired); checkVictory(); } // Bullet continues through enemy - no destruction hit = true; break; } } if (!hit) { bullet.lastY = bullet.y; } } // Limit enemies on screen for performance - increase limit after score 90 var enemyLimit = enemiesKilled >= 90 ? 15 : 8; if (enemies.length > enemyLimit) { var oldEnemy = enemies.shift(); oldEnemy.destroy(); } // Update enemies for (var i = enemies.length - 1; i >= 0; i--) { var enemy = enemies[i]; if (enemy.lastY === undefined) enemy.lastY = enemy.y; // Game over if enemy passes Omar's defensive line (y > 2300) if (enemy.lastY <= 2300 && enemy.y > 2300) { LK.showGameOver(); return; } enemy.lastY = enemy.y; } // Update lasers for (var i = lasers.length - 1; i >= 0; i--) { var laser = lasers[i]; // Add pulsing laser beam effect if (laser.duration > 0) { tween(laser, { scaleX: 1.2 + Math.sin(LK.ticks * 0.3) * 0.2, tint: 0x00FFFF }, { duration: 50, easing: tween.linear }); } // Check laser collision with all enemies in range for (var j = enemies.length - 1; j >= 0; j--) { var enemy = enemies[j]; // Check if enemy intersects with laser beam if (laser.intersects(enemy)) { // Laser instantly kills enemies regardless of health // Create intense explosion effect LK.effects.flashScreen(0x00FFFF, 200); // Create electric spark particles for (var k = 0; k < 12; k++) { var spark = new BloodParticle(); spark.x = enemy.x + (Math.random() - 0.5) * 60; spark.y = enemy.y + (Math.random() - 0.5) * 60; spark.speedX = (Math.random() - 0.5) * 15; spark.speedY = (Math.random() - 0.5) * 15; spark.life = 25; spark.tint = 0x00FFFF; // Electric blue sparks bloodParticles.push(spark); game.addChild(spark); } // Enhanced enemy destruction animation tween(enemy, { scaleX: 2.0, scaleY: 2.0, alpha: 0, rotation: Math.PI * 1.5, tint: 0x00FFFF }, { duration: 200, easing: tween.easeOut, onFinish: function onFinish() { enemy.destroy(); } }); // Create enhanced blood spray effect for laser kills - more dramatic for (var k = 0; k < 12; k++) { var blood = new BloodParticle(); blood.x = enemy.x + (Math.random() - 0.5) * 100; blood.y = enemy.y + (Math.random() - 0.5) * 100; blood.speedX = (Math.random() - 0.5) * 20; // Faster for laser kills blood.speedY = Math.random() * -15 - 5; // Higher velocity blood.life = 60; // Longer lasting blood.tint = 0xFF0000; // Add some variety to blood colors for laser kills var laserBloodColors = [0xFF0000, 0xFF4444, 0xCC0000]; blood.tint = laserBloodColors[Math.floor(Math.random() * laserBloodColors.length)]; bloodParticles.push(blood); game.addChild(blood); // Add animation to blood particles tween(blood, { scaleX: 1.2, scaleY: 1.2, rotation: Math.random() * Math.PI * 2 }, { duration: blood.life * 16, easing: tween.easeOut }); } // Add additional blood splatter effect for laser kills for (var k = 0; k < 10; k++) { var splatter = new BloodParticle(); splatter.x = enemy.x + (Math.random() - 0.5) * 150; splatter.y = enemy.y + (Math.random() - 0.5) * 150; splatter.speedX = (Math.random() - 0.5) * 12; splatter.speedY = (Math.random() - 0.5) * 12; splatter.life = 80; // Longer for dramatic effect splatter.scaleX = 0.4; splatter.scaleY = 0.4; splatter.tint = 0x660000; // Darker blood for contrast bloodParticles.push(splatter); game.addChild(splatter); } enemies.splice(j, 1); enemiesKilled += 5; // Award 5 enemies killed for laser kill // Update score immediately when each enemy dies scoreText.setText('Enemies: ' + enemiesKilled + ' / ' + enemiesRequired); checkVictory(); } } // Remove laser when duration expires if (laser.duration <= 0) { laser.destroy(); lasers.splice(i, 1); } } // Update towers for (var i = 0; i < towers.length; i++) { var tower = towers[i]; tower.update(); } // Update tower bullets for (var i = towerBullets.length - 1; i >= 0; i--) { var bullet = towerBullets[i]; if (bullet.alpha <= 0) { bullet.destroy(); towerBullets.splice(i, 1); continue; } // Check collision with enemies var hit = false; for (var j = enemies.length - 1; j >= 0; j--) { var enemy = enemies[j]; var dx = bullet.x - enemy.x; var dy = bullet.y - enemy.y; if (dx * dx + dy * dy < 2500 && bullet.intersects(enemy)) { // Tower bullet impact tween(enemy, { tint: 0xFFFFFF, scaleX: 1.1, scaleY: 1.1 }, { duration: 60, easing: tween.easeOut, onFinish: function onFinish() { tween(enemy, { tint: 0xFF6666, scaleX: 1.0, scaleY: 1.0 }, { duration: 100, easing: tween.easeOut }); } }); // Create impact particles for (var p = 0; p < 4; p++) { var spark = new BloodParticle(); spark.x = bullet.x; spark.y = bullet.y; var angle = p * Math.PI * 2 / 4; spark.speedX = Math.cos(angle) * 3; spark.speedY = Math.sin(angle) * 3; spark.life = 10; spark.tint = 0xFF8C00; bloodParticles.push(spark); game.addChild(spark); } if (enemy.takeDamage(bullet.damage)) { // Enemy killed by tower tween(enemy, { scaleX: 1.5, scaleY: 1.5, alpha: 0, rotation: Math.PI * 0.5, tint: 0xFF4444 }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { enemy.destroy(); } }); // Create blood spray for (var k = 0; k < 8; k++) { var blood = new BloodParticle(); blood.x = enemy.x + (Math.random() - 0.5) * 60; blood.y = enemy.y + (Math.random() - 0.5) * 60; blood.speedX = (Math.random() - 0.5) * 12; blood.speedY = Math.random() * -8 - 2; blood.life = 35; bloodParticles.push(blood); game.addChild(blood); } enemies.splice(j, 1); enemiesKilled++; scoreText.setText('Enemies: ' + enemiesKilled + ' / ' + enemiesRequired); checkVictory(); } bullet.destroy(); towerBullets.splice(i, 1); hit = true; break; } } } // Update AI if (omarAI) { omarAI.update(); } // Reduced auto shoot frequency for better performance (only when AI is not active) if (LK.ticks % 20 === 0 && (!omarAI || !omarAI.isActive)) { omar.shoot(); } } // Update confetti for (var i = confettiParticles.length - 1; i >= 0; i--) { var confetti = confettiParticles[i]; if (confetti.life <= 0) { confetti.destroy(); confettiParticles.splice(i, 1); } } // Update blood particles with better cleanup for (var i = bloodParticles.length - 1; i >= 0; i--) { var blood = bloodParticles[i]; if (!blood || blood.life <= 0 || blood.alpha <= 0) { if (blood && blood.parent) { blood.destroy(); } bloodParticles.splice(i, 1); } } // Limit total blood particles for performance if (bloodParticles.length > 30) { var excess = bloodParticles.splice(0, bloodParticles.length - 30); for (var i = 0; i < excess.length; i++) { if (excess[i] && excess[i].parent) { excess[i].destroy(); } } } }; function updateGoldDisplay() { if (goldText) { goldText.setText('Gold: ' + playerGold); } } // Initialize the menu initMenu();
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var BloodParticle = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('confetti', {
anchorX: 0.5,
anchorY: 0.5
});
graphics.tint = 0xFF0000; // Red color for blood
graphics.scaleX = 0.3; // Smaller particles
graphics.scaleY = 0.3;
self.speedX = (Math.random() - 0.5) * 6;
self.speedY = Math.random() * -4 - 1;
self.gravity = 0.2;
self.life = 30; // Short lived particles
self.update = function () {
self.x += self.speedX;
self.y += self.speedY;
self.speedY += self.gravity;
self.life--;
if (self.life <= 0) {
self.alpha = 0;
} else {
// Fade out over time
self.alpha = self.life / 30;
}
};
return self;
});
var Confetti = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('confetti', {
anchorX: 0.5,
anchorY: 0.5
});
self.speedX = (Math.random() - 0.5) * 10;
self.speedY = Math.random() * -8 - 2;
self.gravity = 0.3;
self.life = 120;
self.update = function () {
self.x += self.speedX;
self.y += self.speedY;
self.speedY += self.gravity;
self.life--;
if (self.life <= 0) {
self.alpha = 0;
}
};
return self;
});
var Enemy = Container.expand(function () {
var self = Container.call(this);
self.enemyType = 'aamir';
self.health = 1;
self.speed = 2;
self.pathIndex = 0;
self.goldReward = 10;
self.init = function (type) {
self.enemyType = type;
if (type === 'vega') {
self.health = 3;
self.speed = 1;
self.goldReward = 25;
} else if (type === 'sultan') {
self.health = 2;
self.speed = 1.5;
self.goldReward = 20;
} else {
self.goldReward = 10;
}
var graphics = self.attachAsset(type, {
anchorX: 0.5,
anchorY: 0.5
});
};
self.update = function () {
// Follow path if available
if (enemyPath.length > 0 && self.pathIndex < enemyPath.length - 1) {
var currentTarget = enemyPath[self.pathIndex + 1];
var dx = currentTarget.x - self.x;
var dy = currentTarget.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 30) {
self.pathIndex++;
} else {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
}
} else {
// Fallback to original movement
self.y += self.speed;
}
};
self.takeDamage = function (damage) {
if (damage === undefined) damage = 1;
self.health -= damage;
if (self.health <= 0) {
// Award gold when enemy dies
playerGold += self.goldReward;
updateGoldDisplay();
return true;
}
return false;
};
return self;
});
var Laser = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('laser', {
anchorX: 0.5,
anchorY: 1.0
});
self.duration = 20; // Laser lasts for 20 frames
self.damage = 5; // Higher damage than regular bullets
self.update = function () {
self.duration--;
if (self.duration <= 0) {
self.alpha = 0;
} else {
// Fade out effect
self.alpha = self.duration / 20;
}
};
return self;
});
var ModeButton = Container.expand(function () {
var self = Container.call(this);
var background = self.attachAsset('modeButton', {
anchorX: 0.5,
anchorY: 0.5
});
self.modeText = new Text2('', {
size: 50,
fill: '#000000'
});
self.modeText.anchor.set(0.5, 0.5);
self.addChild(self.modeText);
self.setMode = function (text, mode, enemyCount) {
// Remove existing text and create new one with proper styling
if (self.modeText) {
self.removeChild(self.modeText);
}
self.modeText = new Text2(text, {
size: 50,
fill: '#000000',
stroke: '#FFFFFF',
strokeThickness: 3
});
self.modeText.anchor.set(0.5, 0);
self.modeText.y = 80; // Position text below the button
self.addChild(self.modeText);
self.gameMode = mode;
self.enemyCount = enemyCount;
};
self.down = function (x, y, obj) {
startGame(self.gameMode, self.enemyCount);
};
return self;
});
var Omar = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('omar', {
anchorX: 0.5,
anchorY: 0.5
});
self.shootCooldown = 0;
self.laserCooldown = 0;
self.update = function () {
if (self.shootCooldown > 0) {
self.shootCooldown--;
}
if (self.laserCooldown > 0) {
self.laserCooldown--;
}
};
self.shoot = function () {
if (self.shootCooldown <= 0) {
var bullet = new OmarBullet();
bullet.x = self.x;
bullet.y = self.y - 40;
bullets.push(bullet);
game.addChild(bullet);
self.shootCooldown = 15;
LK.getSound('shoot').play();
// Add shooting animation to Omar
tween(self, {
scaleX: 1.1,
scaleY: 1.1,
tint: 0xFFFFAA
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
scaleX: 1.0,
scaleY: 1.0,
tint: 0xFFFFFF
}, {
duration: 200,
easing: tween.easeOut
});
}
});
}
};
self.shootLaser = function () {
if (self.laserCooldown <= 0) {
var laser = new Laser();
laser.x = self.x;
laser.y = self.y - 40;
lasers.push(laser);
game.addChild(laser);
self.laserCooldown = 60; // 1 second cooldown at 60fps
LK.getSound('shoot').play();
}
};
return self;
});
var OmarAI = Container.expand(function () {
var self = Container.call(this);
self.target = null;
self.isActive = false;
self.moveSpeed = 3;
self.attackRange = 400;
self.lastDecisionTime = 0;
self.decisionCooldown = 30; // frames between AI decisions
self.activate = function () {
self.isActive = true;
};
self.deactivate = function () {
self.isActive = false;
};
self.findNearestEnemy = function () {
var nearestEnemy = null;
var nearestDistance = Infinity;
for (var i = 0; i < enemies.length; i++) {
var enemy = enemies[i];
var dx = omar.x - enemy.x;
var dy = omar.y - enemy.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < nearestDistance) {
nearestDistance = distance;
nearestEnemy = enemy;
}
}
return nearestEnemy;
};
self.update = function () {
if (!self.isActive || !omar) return;
self.lastDecisionTime++;
// Make decisions every few frames for performance
if (self.lastDecisionTime >= self.decisionCooldown) {
self.target = self.findNearestEnemy();
self.lastDecisionTime = 0;
}
if (self.target) {
// Move towards enemy horizontally
var dx = self.target.x - omar.x;
if (Math.abs(dx) > 50) {
// Dead zone to prevent jittering
if (dx > 0) {
omar.x += self.moveSpeed;
} else {
omar.x -= self.moveSpeed;
}
}
// Keep Omar within screen bounds with proper margins
omar.x = Math.max(95, Math.min(1953, omar.x));
// Shoot if enemy is within range
var distance = Math.sqrt(dx * dx + (self.target.y - omar.y) * (self.target.y - omar.y));
if (distance < self.attackRange) {
omar.shoot();
}
}
};
return self;
});
var OmarBullet = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('omarBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -8;
self.update = function () {
self.y += self.speed;
};
return self;
});
var Terrain = Container.expand(function () {
var self = Container.call(this);
self.init = function (type, x, y) {
var graphics = self.attachAsset(type, {
anchorX: 0.5,
anchorY: 0.5
});
self.x = x;
self.y = y;
};
return self;
});
var Tower = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('stone', {
anchorX: 0.5,
anchorY: 0.5
});
graphics.tint = 0x8B4513; // Brown color for tower
self.range = 300;
self.damage = 25;
self.fireRate = 60; // frames between shots
self.cooldown = 0;
self.level = 1;
self.cost = 50;
// Visual range indicator
self.rangeIndicator = null;
self.showRange = function () {
if (!self.rangeIndicator) {
self.rangeIndicator = new Text2('◯', {
size: self.range * 2,
fill: '#00FF00'
});
self.rangeIndicator.anchor.set(0.5, 0.5);
self.rangeIndicator.alpha = 0.3;
self.rangeIndicator.x = 0;
self.rangeIndicator.y = 0;
self.addChild(self.rangeIndicator);
}
};
self.hideRange = function () {
if (self.rangeIndicator) {
self.removeChild(self.rangeIndicator);
self.rangeIndicator = null;
}
};
self.canShoot = function () {
return self.cooldown <= 0;
};
self.inRange = function (enemy) {
var dx = self.x - enemy.x;
var dy = self.y - enemy.y;
return Math.sqrt(dx * dx + dy * dy) <= self.range;
};
self.shoot = function (enemy) {
if (self.canShoot() && self.inRange(enemy)) {
// Create tower bullet
var bullet = new TowerBullet();
bullet.x = self.x;
bullet.y = self.y;
bullet.targetX = enemy.x;
bullet.targetY = enemy.y;
bullet.damage = self.damage;
towerBullets.push(bullet);
game.addChild(bullet);
self.cooldown = self.fireRate;
LK.getSound('shoot').play();
// Tower shoot animation
tween(self, {
scaleX: 1.2,
scaleY: 1.2,
tint: 0xFFFFAA
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
scaleX: 1.0,
scaleY: 1.0,
tint: 0x8B4513
}, {
duration: 200,
easing: tween.easeOut
});
}
});
}
};
self.upgrade = function () {
if (self.level < 3 && playerGold >= self.getUpgradeCost()) {
playerGold -= self.getUpgradeCost();
self.level++;
self.damage += 15;
self.range += 50;
self.fireRate = Math.max(20, self.fireRate - 10);
// Visual upgrade effect
graphics.scaleX *= 1.1;
graphics.scaleY *= 1.1;
if (self.level === 2) {
graphics.tint = 0xC0C0C0; // Silver
} else if (self.level === 3) {
graphics.tint = 0xFFD700; // Gold
}
updateGoldDisplay();
}
};
self.getUpgradeCost = function () {
return self.level * 75;
};
self.update = function () {
if (self.cooldown > 0) {
self.cooldown--;
}
// Find and shoot at nearest enemy
var nearestEnemy = null;
var nearestDistance = Infinity;
for (var i = 0; i < enemies.length; i++) {
var enemy = enemies[i];
if (self.inRange(enemy)) {
var dx = self.x - enemy.x;
var dy = self.y - enemy.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < nearestDistance) {
nearestDistance = distance;
nearestEnemy = enemy;
}
}
}
if (nearestEnemy) {
self.shoot(nearestEnemy);
}
};
self.down = function (x, y, obj) {
if (gameState === 'playing') {
self.upgrade();
}
};
return self;
});
var TowerBullet = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('omarBullet', {
anchorX: 0.5,
anchorY: 0.5
});
graphics.tint = 0xFF8C00; // Orange color for tower bullets
self.speed = 8;
self.damage = 25;
self.targetX = 0;
self.targetY = 0;
self.hasHit = false;
self.update = function () {
if (!self.hasHit) {
// Move towards target
var dx = self.targetX - self.x;
var dy = self.targetY - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > self.speed) {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
} else {
self.hasHit = true;
}
}
// Remove if off screen
if (self.y < -100 || self.y > 2800 || self.x < -100 || self.x > 2148) {
self.alpha = 0;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000033
});
/****
* Game Code
****/
// Sound assets
// UI assets
// Enemy assets
// Hero assets
// Game state
var gameState = 'menu'; // 'menu', 'playing', 'victory'
var currentMode = '';
var enemiesRequired = 0;
var enemiesKilled = 0;
var gameStarted = false;
// Game objects
var omar;
var omarAI;
var bullets = [];
var enemies = [];
var confettiParticles = [];
var bloodParticles = [];
var terrainElements = [];
var lasers = [];
var towers = [];
var towerBullets = [];
var enemyPath = [];
var playerGold = 200;
var goldText;
var selectedTowerType = null;
var placementMode = false;
// UI elements
var titleText;
var scoreText;
var modeButtons = [];
// Enemy spawn timer - optimized for performance
var enemySpawnTimer = 0;
var enemySpawnRate = 60; // frames between spawns - faster to compensate for limited enemies
// Initialize menu
function initMenu() {
gameState = 'menu';
// Title - Enhanced Sultan Style
titleText = new Text2('My Sultan', {
size: 120,
fill: '#FFD700',
// Gold
stroke: '#8B0000',
// Dark red stroke
strokeThickness: 8,
dropShadow: true,
dropShadowColor: '#000000',
dropShadowDistance: 5,
dropShadowAngle: Math.PI / 4
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
titleText.y = 400;
game.addChild(titleText);
// Add floating animation with enhanced rotation and scale effects
tween(titleText, {
y: 380,
rotation: 0.1,
scaleX: 1.05,
scaleY: 1.05
}, {
duration: 2500,
easing: tween.elasticOut,
onFinish: function onFinish() {
// Create continuous floating effect with enhanced rotation and scaling
function floatUp() {
tween(titleText, {
y: 370,
rotation: 0.08,
scaleX: 1.08,
scaleY: 1.08
}, {
duration: 3000,
easing: tween.easeInOut,
onFinish: floatDown
});
}
function floatDown() {
tween(titleText, {
y: 430,
rotation: -0.08,
scaleX: 0.98,
scaleY: 0.98
}, {
duration: 3000,
easing: tween.easeInOut,
onFinish: floatUp
});
}
floatDown();
}
});
// Add enhanced pulsing color effect with magical transitions
function createColorPulse() {
tween(titleText, {
tint: 0xFFB347 // Orange-gold tint
}, {
duration: 1200,
easing: tween.elasticOut,
onFinish: function onFinish() {
tween(titleText, {
tint: 0xFF6B35 // Deeper orange
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(titleText, {
tint: 0xFFD700 // Back to gold
}, {
duration: 1000,
easing: tween.bounceOut,
onFinish: createColorPulse
});
}
});
}
});
}
createColorPulse();
// Add enhanced scale pulsing with glow effect
function createScalePulse() {
tween(titleText, {
scaleX: 1.15,
scaleY: 1.15,
alpha: 0.9
}, {
duration: 2000,
easing: tween.elasticInOut,
onFinish: function onFinish() {
tween(titleText, {
scaleX: 1.0,
scaleY: 1.0,
alpha: 1.0
}, {
duration: 2000,
easing: tween.bounceOut,
onFinish: createScalePulse
});
}
});
}
createScalePulse();
// Create animated background with floating magical particles - optimized
function createBackgroundEffects() {
// Add mystical floating orbs - reduced count
for (var i = 0; i < 6; i++) {
var orb = new Text2('⚫', {
size: 15 + Math.random() * 15,
fill: '#4B0082'
});
orb.anchor.set(0.5, 0.5);
orb.x = Math.random() * 2048;
orb.y = Math.random() * 2732;
orb.alpha = 0.2 + Math.random() * 0.3;
orb.tint = 0x9932CC;
game.addChild(orb);
// Add continuous floating animation
(function (orbObj) {
function floatOrb() {
if (orbObj && orbObj.parent && gameState === 'menu') {
tween(orbObj, {
y: orbObj.y + (Math.random() - 0.5) * 100,
x: orbObj.x + (Math.random() - 0.5) * 75,
scaleX: 0.8 + Math.random() * 0.4,
scaleY: 0.8 + Math.random() * 0.4,
alpha: 0.1 + Math.random() * 0.3,
rotation: Math.random() * Math.PI * 2
}, {
duration: 3000 + Math.random() * 2000,
easing: tween.easeInOut,
onFinish: floatOrb
});
}
}
floatOrb();
})(orb);
}
// Add golden energy streams - optimized
for (var i = 0; i < 4; i++) {
var stream = new Text2('◊', {
size: 10 + Math.random() * 8,
fill: '#FFD700'
});
stream.anchor.set(0.5, 0.5);
stream.x = Math.random() * 2048;
stream.y = 2732 + Math.random() * 100;
stream.alpha = 0.4;
game.addChild(stream);
// Add upward floating animation with safety checks
(function (streamObj) {
function floatUp() {
if (streamObj && streamObj.parent && gameState === 'menu') {
tween(streamObj, {
y: -100,
x: streamObj.x + (Math.random() - 0.5) * 150,
rotation: Math.PI * 2,
alpha: 0,
scaleX: 0.5,
scaleY: 0.5
}, {
duration: 6000 + Math.random() * 2000,
easing: tween.easeOut,
onFinish: function onFinish() {
if (streamObj && streamObj.parent && gameState === 'menu') {
streamObj.y = 2732 + Math.random() * 100;
streamObj.x = Math.random() * 2048;
streamObj.alpha = 0.4;
streamObj.scaleX = 1.0;
streamObj.scaleY = 1.0;
streamObj.rotation = 0;
LK.setTimeout(floatUp, 1000);
}
}
});
}
}
floatUp();
})(stream);
}
// Add mystical runes that appear and disappear
var runeSymbols = ['◈', '◇', '◉', '◎', '⬟', '⬢', '⬡'];
for (var i = 0; i < 6; i++) {
var rune = new Text2(runeSymbols[Math.floor(Math.random() * runeSymbols.length)], {
size: 40 + Math.random() * 20,
fill: '#8A2BE2'
});
rune.anchor.set(0.5, 0.5);
rune.x = Math.random() * 2048;
rune.y = Math.random() * 2732;
rune.alpha = 0;
game.addChild(rune);
// Add mystical appearance animation
(function (runeObj) {
function runeAppear() {
LK.setTimeout(function () {
tween(runeObj, {
alpha: 0.7,
scaleX: 1.5,
scaleY: 1.5,
rotation: Math.PI
}, {
duration: 2000,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(runeObj, {
alpha: 0,
scaleX: 0.5,
scaleY: 0.5,
rotation: Math.PI * 2
}, {
duration: 1500,
easing: tween.easeIn,
onFinish: function onFinish() {
runeObj.x = Math.random() * 2048;
runeObj.y = Math.random() * 2732;
runeAppear();
}
});
}
});
}, Math.random() * 5000);
}
runeAppear();
})(rune);
}
}
createBackgroundEffects();
// Add sparkle effects around title - optimized
function createSparkles() {
for (var i = 0; i < 3; i++) {
var sparkle = new Text2('✨', {
size: 25 + Math.random() * 15,
fill: '#FFD700'
});
sparkle.anchor.set(0.5, 0.5);
sparkle.x = titleText.x + (Math.random() - 0.5) * 300;
sparkle.y = titleText.y + (Math.random() - 0.5) * 150;
sparkle.alpha = 0;
game.addChild(sparkle);
// Animate sparkle with enhanced effects
tween(sparkle, {
alpha: 1,
scaleX: 1.5,
scaleY: 1.5,
rotation: Math.random() * Math.PI * 2
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(sparkle, {
alpha: 0,
scaleX: 0.5,
scaleY: 0.5,
y: sparkle.y - 50
}, {
duration: 600,
easing: tween.easeIn,
onFinish: function onFinish() {
if (sparkle && sparkle.parent) {
sparkle.destroy();
}
}
});
}
});
}
}
// Create sparkles periodically - reduced frequency
function sparkleTimer() {
if (gameState === 'menu') {
createSparkles();
LK.setTimeout(sparkleTimer, 3000 + Math.random() * 2000);
}
}
LK.setTimeout(sparkleTimer, 1500);
// Subtitle with enhanced effects
var subtitle = new Text2('Choose Your Quest', {
size: 50,
fill: '#FFFFFF',
stroke: '#FFD700',
strokeThickness: 2
});
subtitle.anchor.set(0.5, 0.5);
subtitle.x = 1024;
subtitle.y = 500;
subtitle.alpha = 0;
subtitle.scaleX = 0.5;
subtitle.scaleY = 0.5;
game.addChild(subtitle);
// Animate subtitle entrance
LK.setTimeout(function () {
tween(subtitle, {
alpha: 1,
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 1500,
easing: tween.elasticOut
});
}, 1000);
// Add subtle floating animation to subtitle
function subtitleFloat() {
tween(subtitle, {
y: 490,
rotation: 0.01
}, {
duration: 3000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(subtitle, {
y: 510,
rotation: -0.01
}, {
duration: 3000,
easing: tween.easeInOut,
onFinish: subtitleFloat
});
}
});
}
LK.setTimeout(subtitleFloat, 2000);
// Add color cycling effect to subtitle
function subtitleColorCycle() {
tween(subtitle, {
tint: 0xE6E6FA
}, {
duration: 2500,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(subtitle, {
tint: 0xFFFFFF
}, {
duration: 2500,
easing: tween.easeInOut,
onFinish: subtitleColorCycle
});
}
});
}
LK.setTimeout(subtitleColorCycle, 1500);
// Create animated decorative border frame
function createMenuBorder() {
var borderElements = [];
// Top border
for (var i = 0; i < 20; i++) {
var topBorder = new Text2('◆', {
size: 25,
fill: '#DAA520'
});
topBorder.anchor.set(0.5, 0.5);
topBorder.x = 100 + i * 90;
topBorder.y = 150;
topBorder.alpha = 0.8;
game.addChild(topBorder);
borderElements.push(topBorder);
// Add pulsing animation with delay
(function (element, delay) {
LK.setTimeout(function () {
function pulse() {
tween(element, {
scaleX: 1.3,
scaleY: 1.3,
tint: 0xFFD700
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(element, {
scaleX: 1.0,
scaleY: 1.0,
tint: 0xDAA520
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: pulse
});
}
});
}
pulse();
}, delay * 100);
})(topBorder, i);
}
// Bottom border
for (var i = 0; i < 20; i++) {
var bottomBorder = new Text2('◇', {
size: 25,
fill: '#DAA520'
});
bottomBorder.anchor.set(0.5, 0.5);
bottomBorder.x = 100 + i * 90;
bottomBorder.y = 2580;
bottomBorder.alpha = 0.8;
game.addChild(bottomBorder);
borderElements.push(bottomBorder);
// Add wave animation
(function (element, index) {
function wave() {
tween(element, {
y: 2580 + Math.sin(LK.ticks * 0.1 + index * 0.5) * 15,
rotation: Math.sin(LK.ticks * 0.05 + index * 0.3) * 0.2
}, {
duration: 50,
easing: tween.linear,
onFinish: wave
});
}
wave();
})(bottomBorder, i);
}
// Left border
for (var i = 0; i < 25; i++) {
var leftBorder = new Text2('◊', {
size: 20,
fill: '#DAA520'
});
leftBorder.anchor.set(0.5, 0.5);
leftBorder.x = 100;
leftBorder.y = 200 + i * 100;
leftBorder.alpha = 0.8;
game.addChild(leftBorder);
borderElements.push(leftBorder);
// Add flowing animation
(function (element, index) {
LK.setTimeout(function () {
function flow() {
tween(element, {
x: 120,
scaleX: 1.2,
scaleY: 1.2,
tint: 0xB8860B
}, {
duration: 2000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(element, {
x: 100,
scaleX: 1.0,
scaleY: 1.0,
tint: 0xDAA520
}, {
duration: 2000,
easing: tween.easeInOut,
onFinish: flow
});
}
});
}
flow();
}, index * 150);
})(leftBorder, i);
}
// Right border
for (var i = 0; i < 25; i++) {
var rightBorder = new Text2('◈', {
size: 20,
fill: '#DAA520'
});
rightBorder.anchor.set(0.5, 0.5);
rightBorder.x = 1948;
rightBorder.y = 200 + i * 100;
rightBorder.alpha = 0.8;
game.addChild(rightBorder);
borderElements.push(rightBorder);
// Add flowing animation (opposite direction)
(function (element, index) {
LK.setTimeout(function () {
function flow() {
tween(element, {
x: 1928,
scaleX: 1.2,
scaleY: 1.2,
tint: 0xB8860B
}, {
duration: 2000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(element, {
x: 1948,
scaleX: 1.0,
scaleY: 1.0,
tint: 0xDAA520
}, {
duration: 2000,
easing: tween.easeInOut,
onFinish: flow
});
}
});
}
flow();
}, index * 150);
})(rightBorder, i);
}
// Corner ornaments
var corners = [{
x: 100,
y: 150,
symbol: '◉'
}, {
x: 1948,
y: 150,
symbol: '◉'
}, {
x: 100,
y: 2580,
symbol: '◉'
}, {
x: 1948,
y: 2580,
symbol: '◉'
}];
corners.forEach(function (corner, index) {
var ornament = new Text2(corner.symbol, {
size: 40,
fill: '#FFD700'
});
ornament.anchor.set(0.5, 0.5);
ornament.x = corner.x;
ornament.y = corner.y;
ornament.alpha = 0.9;
game.addChild(ornament);
// Add rotating glow animation
function rotateGlow() {
tween(ornament, {
rotation: Math.PI * 2,
scaleX: 1.5,
scaleY: 1.5,
tint: 0xFF6347
}, {
duration: 3000,
easing: tween.easeInOut,
onFinish: function onFinish() {
ornament.rotation = 0;
tween(ornament, {
scaleX: 1.0,
scaleY: 1.0,
tint: 0xFFD700
}, {
duration: 1000,
easing: tween.easeOut,
onFinish: rotateGlow
});
}
});
}
LK.setTimeout(rotateGlow, index * 500);
});
}
createMenuBorder();
// Mode buttons with enhanced animations
var nightButton = new ModeButton();
nightButton.setMode('Night Mode (100 enemies)', 'night', 100);
nightButton.x = 1024;
nightButton.y = 800;
nightButton.alpha = 0;
modeButtons.push(nightButton);
game.addChild(nightButton);
// Enhanced entrance animation for night button with dramatic effects
nightButton.scaleX = 0;
nightButton.scaleY = 0;
nightButton.y = 850;
nightButton.rotation = Math.PI;
nightButton.tint = 0x000080;
tween(nightButton, {
alpha: 1,
scaleX: 1.0,
scaleY: 1.0,
y: 800,
rotation: 0,
tint: 0xFFFFFF
}, {
duration: 1800,
easing: tween.elasticOut
});
// Add magical particle trail effect to night button
function createNightButtonTrail() {
for (var i = 0; i < 4; i++) {
var trail = new Text2('⭐', {
size: 15 + Math.random() * 10,
fill: '#87CEEB'
});
trail.anchor.set(0.5, 0.5);
trail.x = nightButton.x + (Math.random() - 0.5) * 200;
trail.y = nightButton.y + (Math.random() - 0.5) * 100;
trail.alpha = 0.8;
game.addChild(trail);
tween(trail, {
y: trail.y - 50,
alpha: 0,
scaleX: 0.3,
scaleY: 0.3,
rotation: Math.PI
}, {
duration: 2000,
easing: tween.easeOut,
onFinish: function onFinish() {
trail.destroy();
}
});
}
}
function nightButtonTrailTimer() {
createNightButtonTrail();
LK.setTimeout(nightButtonTrailTimer, 1500 + Math.random() * 1000);
}
LK.setTimeout(nightButtonTrailTimer, 2000);
// Add continuous glow effect to night button
function nightButtonGlow() {
tween(nightButton, {
tint: 0x4169E1,
scaleX: 1.05,
scaleY: 1.05
}, {
duration: 1500,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(nightButton, {
tint: 0xFFFFFF,
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 1500,
easing: tween.easeInOut,
onFinish: nightButtonGlow
});
}
});
}
LK.setTimeout(nightButtonGlow, 500);
var dayButton = new ModeButton();
dayButton.setMode('Day Mode (100 enemies)', 'day', 100);
dayButton.x = 1024;
dayButton.y = 1000;
dayButton.alpha = 0;
modeButtons.push(dayButton);
game.addChild(dayButton);
// Enhanced entrance animation for day button with sun ray effects
dayButton.scaleX = 0;
dayButton.scaleY = 0;
dayButton.y = 1050;
dayButton.tint = 0xFFA500;
LK.setTimeout(function () {
tween(dayButton, {
alpha: 1,
scaleX: 1.0,
scaleY: 1.0,
y: 1000,
rotation: 0,
tint: 0xFFFFFF
}, {
duration: 1600,
easing: tween.elasticOut
});
// Add sun ray effects around day button
for (var r = 0; r < 12; r++) {
var ray = new Text2('|', {
size: 60,
fill: '#FFD700'
});
ray.anchor.set(0.5, 0);
ray.x = dayButton.x;
ray.y = dayButton.y;
ray.rotation = r * Math.PI / 6;
ray.alpha = 0;
ray.scaleX = 2;
game.addChild(ray);
// Animate rays appearing
(function (rayObj, index) {
LK.setTimeout(function () {
tween(rayObj, {
alpha: 0.4,
scaleY: 1.5,
y: rayObj.y - 30
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
// Add continuous pulsing to rays
function pulsRay() {
tween(rayObj, {
alpha: 0.6,
scaleY: 1.8
}, {
duration: 2000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(rayObj, {
alpha: 0.3,
scaleY: 1.2
}, {
duration: 2000,
easing: tween.easeInOut,
onFinish: pulsRay
});
}
});
}
pulsRay();
}
});
}, index * 100);
})(ray, r);
}
}, 600);
// Add continuous glow effect to day button
function dayButtonGlow() {
tween(dayButton, {
tint: 0xFFD700,
scaleX: 1.05,
scaleY: 1.05
}, {
duration: 1800,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(dayButton, {
tint: 0xFFFFFF,
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 1800,
easing: tween.easeInOut,
onFinish: dayButtonGlow
});
}
});
}
LK.setTimeout(dayButtonGlow, 800);
var betrayalButton = new ModeButton();
betrayalButton.setMode('My Sultan Became My Enemy (400)', 'betrayal', 400);
betrayalButton.x = 1024;
betrayalButton.y = 1200;
betrayalButton.alpha = 0;
modeButtons.push(betrayalButton);
game.addChild(betrayalButton);
// Enhanced dramatic entrance for betrayal button with ominous effects
betrayalButton.scaleX = 0;
betrayalButton.scaleY = 0;
betrayalButton.y = 1250;
betrayalButton.tint = 0x800000;
LK.setTimeout(function () {
// Add screen flash before betrayal button appears
LK.effects.flashScreen(0x8B0000, 300);
tween(betrayalButton, {
alpha: 1,
scaleX: 1.0,
scaleY: 1.0,
y: 1200,
rotation: 0,
tint: 0xFFFFFF
}, {
duration: 2000,
easing: tween.elasticOut
});
// Add ominous smoke effects around betrayal button
function createOminousSmoke() {
for (var s = 0; s < 6; s++) {
var smoke = new Text2('☁', {
size: 30 + Math.random() * 20,
fill: '#2F2F2F'
});
smoke.anchor.set(0.5, 0.5);
smoke.x = betrayalButton.x + (Math.random() - 0.5) * 300;
smoke.y = betrayalButton.y + 100 + Math.random() * 50;
smoke.alpha = 0.4;
smoke.tint = 0x8B0000;
game.addChild(smoke);
tween(smoke, {
y: smoke.y - 150,
alpha: 0,
scaleX: 2.0,
scaleY: 2.0,
rotation: Math.PI
}, {
duration: 4000,
easing: tween.easeOut,
onFinish: function onFinish() {
smoke.destroy();
}
});
}
}
function smokeTimer() {
createOminousSmoke();
LK.setTimeout(smokeTimer, 2000 + Math.random() * 1500);
}
smokeTimer();
// Add red lightning effects
function createRedLightning() {
for (var l = 0; l < 3; l++) {
var lightning = new Text2('⚡', {
size: 40 + Math.random() * 20,
fill: '#FF0000'
});
lightning.anchor.set(0.5, 0.5);
lightning.x = betrayalButton.x + (Math.random() - 0.5) * 400;
lightning.y = betrayalButton.y + (Math.random() - 0.5) * 200;
lightning.alpha = 0;
game.addChild(lightning);
tween(lightning, {
alpha: 1,
scaleX: 2.0,
scaleY: 2.0
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(lightning, {
alpha: 0,
scaleX: 0.5,
scaleY: 0.5
}, {
duration: 200,
easing: tween.easeIn,
onFinish: function onFinish() {
lightning.destroy();
}
});
}
});
}
}
function lightningTimer() {
if (Math.random() < 0.4) {
createRedLightning();
}
LK.setTimeout(lightningTimer, 1000 + Math.random() * 2000);
}
LK.setTimeout(lightningTimer, 3000);
// Add dramatic shake effect after entrance
LK.setTimeout(function () {
function shakeEffect() {
tween(betrayalButton, {
x: 1024 + (Math.random() - 0.5) * 10,
rotation: (Math.random() - 0.5) * 0.05
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(betrayalButton, {
x: 1024,
rotation: 0
}, {
duration: 100,
easing: tween.easeOut
});
}
});
}
// Random shake every few seconds
function randomShake() {
if (Math.random() < 0.3) {
shakeEffect();
}
LK.setTimeout(randomShake, 2000 + Math.random() * 3000);
}
randomShake();
}, 2000);
}, 600);
// Add continuous dramatic glow effect to betrayal button
function betrayalButtonGlow() {
tween(betrayalButton, {
tint: 0xFF4500,
scaleX: 1.08,
scaleY: 1.08,
rotation: 0.02
}, {
duration: 1200,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(betrayalButton, {
tint: 0xFFFFFF,
scaleX: 1.0,
scaleY: 1.0,
rotation: -0.02
}, {
duration: 1200,
easing: tween.easeInOut,
onFinish: betrayalButtonGlow
});
}
});
}
LK.setTimeout(betrayalButtonGlow, 1100);
}
function startGame(mode, enemyCount) {
gameState = 'playing';
currentMode = mode;
enemiesRequired = enemyCount;
enemiesKilled = 0;
gameStarted = true;
// Clear menu
while (game.children.length > 0) {
var child = game.children[0];
child.destroy();
}
// Set background based on mode
if (mode === 'night') {
// Add moon glow animation
var _createMoonGlow = function createMoonGlow() {
tween(moon, {
scaleX: 1.2,
scaleY: 1.2,
alpha: 0.8
}, {
duration: 3000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(moon, {
scaleX: 1.0,
scaleY: 1.0,
alpha: 1.0
}, {
duration: 3000,
easing: tween.easeInOut,
onFinish: _createMoonGlow
});
}
});
};
game.setBackgroundColor(0x000033);
// Add night atmosphere effects
// Create moon glow effect
var moon = new Text2('🌙', {
size: 80,
fill: '#F0F8FF'
});
moon.anchor.set(0.5, 0.5);
moon.x = 1800;
moon.y = 300;
game.addChild(moon);
_createMoonGlow();
// Add twinkling stars
for (var s = 0; s < 15; s++) {
var star = new Text2('⭐', {
size: 20 + Math.random() * 15,
fill: '#FFFFFF'
});
star.anchor.set(0.5, 0.5);
star.x = Math.random() * 2048;
star.y = Math.random() * 400 + 50;
star.alpha = 0.3 + Math.random() * 0.7;
game.addChild(star);
// Add twinkling animation with random delay
(function (starObj) {
var _twinkle = function twinkle() {
tween(starObj, {
alpha: 0.2,
scaleX: 0.5,
scaleY: 0.5
}, {
duration: 1000 + Math.random() * 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(starObj, {
alpha: 1.0,
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 1000 + Math.random() * 1000,
easing: tween.easeInOut,
onFinish: _twinkle
});
}
});
};
LK.setTimeout(_twinkle, Math.random() * 2000);
})(star);
}
} else if (mode === 'day') {
game.setBackgroundColor(0x87CEEB);
// Add day atmosphere effects
// Create sun with rays
var sun = new Text2('☀️', {
size: 100,
fill: '#FFD700'
});
sun.anchor.set(0.5, 0.5);
sun.x = 250;
sun.y = 250;
game.addChild(sun);
// Add sun rotation animation
tween(sun, {
rotation: Math.PI * 2
}, {
duration: 10000,
easing: tween.linear,
onFinish: function onFinish() {
sun.rotation = 0;
// Create recursive rotation
arguments.callee();
}
});
// Add sun pulsing glow
var _sunGlow = function sunGlow() {
tween(sun, {
scaleX: 1.1,
scaleY: 1.1,
tint: 0xFFA500
}, {
duration: 2000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(sun, {
scaleX: 1.0,
scaleY: 1.0,
tint: 0xFFFFFF
}, {
duration: 2000,
easing: tween.easeInOut,
onFinish: _sunGlow
});
}
});
};
_sunGlow();
// Create floating clouds
for (var c = 0; c < 6; c++) {
var cloud = new Text2('☁️', {
size: 60 + Math.random() * 30,
fill: '#FFFFFF'
});
cloud.anchor.set(0.5, 0.5);
cloud.x = Math.random() * 2048;
cloud.y = Math.random() * 300 + 100;
cloud.alpha = 0.7 + Math.random() * 0.3;
game.addChild(cloud);
// Add cloud floating animation
(function (cloudObj) {
var startX = cloudObj.x;
var _float2 = function _float() {
tween(cloudObj, {
x: startX + (Math.random() - 0.5) * 200,
scaleX: 0.9 + Math.random() * 0.2,
scaleY: 0.9 + Math.random() * 0.2
}, {
duration: 8000 + Math.random() * 4000,
easing: tween.easeInOut,
onFinish: _float2
});
};
_float2();
})(cloud);
}
// Add light particles floating upward
var createDayParticles = function createDayParticles() {
for (var p = 0; p < 3; p++) {
var particle = new Text2('✨', {
size: 15 + Math.random() * 10,
fill: '#FFD700'
});
particle.anchor.set(0.5, 0.5);
particle.x = Math.random() * 2048;
particle.y = 2732;
particle.alpha = 0.5;
game.addChild(particle);
tween(particle, {
y: -100,
alpha: 0,
rotation: Math.PI * 4,
scaleX: 0.3,
scaleY: 0.3
}, {
duration: 8000 + Math.random() * 4000,
easing: tween.easeOut,
onFinish: function onFinish() {
particle.destroy();
}
});
}
};
// Create day particles periodically
var _dayParticleTimer = function dayParticleTimer() {
createDayParticles();
LK.setTimeout(_dayParticleTimer, 3000 + Math.random() * 2000);
};
_dayParticleTimer();
} else if (mode === 'betrayal') {
game.setBackgroundColor(0x8B0000);
}
// Create Omar
omar = new Omar();
omar.x = 1024;
omar.y = 2200; // Position Omar on the road
game.addChild(omar);
// Create and activate AI
omarAI = new OmarAI();
omarAI.activate();
game.addChild(omarAI);
// Generate terrain for the mode
generateTerrain(mode);
// Create score text
scoreText = new Text2('Enemies: 0 / ' + enemiesRequired, {
size: 60,
fill: '#FFFFFF'
});
scoreText.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreText);
// Create gold display
goldText = new Text2('Gold: ' + playerGold, {
size: 50,
fill: '#FFD700'
});
goldText.anchor.set(0, 0);
goldText.x = 50;
goldText.y = 100;
LK.gui.topLeft.addChild(goldText);
// Create tower placement buttons
var towerButton = new Text2('Build Tower (50g)', {
size: 40,
fill: '#8B4513',
stroke: '#FFFFFF',
strokeThickness: 2
});
towerButton.anchor.set(0, 0);
towerButton.x = 50;
towerButton.y = 200;
LK.gui.topLeft.addChild(towerButton);
// Create enemy path
enemyPath = [{
x: 1024,
y: -50
}, {
x: 1024,
y: 400
}, {
x: 500,
y: 600
}, {
x: 1500,
y: 800
}, {
x: 1024,
y: 1200
}, {
x: 1024,
y: 2300
}];
// Reset arrays
bullets = [];
enemies = [];
confettiParticles = [];
bloodParticles = [];
terrainElements = [];
lasers = [];
towers = [];
towerBullets = [];
playerGold = 200;
placementMode = false;
selectedTowerType = null;
// Reset spawn timer
enemySpawnTimer = 0;
// After score 90, spawn enemies much more frequently
if (enemiesKilled >= 90) {
enemySpawnRate = Math.max(10, 30 - Math.floor((enemiesKilled - 90) / 10) * 5);
} else {
enemySpawnRate = Math.max(30, 90 - Math.floor(enemiesKilled / 20) * 10);
}
}
function generateTerrain(mode) {
// Clear existing terrain
for (var i = terrainElements.length - 1; i >= 0; i--) {
terrainElements[i].destroy();
}
terrainElements = [];
// Add road in the center with mode-specific enhancements
var road = new Terrain();
road.init('road', 1024, 1366);
// Apply mode-specific road effects
if (mode === 'night') {
road.tint = 0x666699; // Darker bluish road for night
road.alpha = 0.9;
} else if (mode === 'day') {
road.tint = 0xFFFFBB; // Brighter, sunlit road for day
road.alpha = 1.0;
// Add subtle road shimmer effect for day
var _roadShimmer = function roadShimmer() {
tween(road, {
tint: 0xFFFFDD
}, {
duration: 3000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(road, {
tint: 0xFFFFBB
}, {
duration: 3000,
easing: tween.easeInOut,
onFinish: _roadShimmer
});
}
});
};
_roadShimmer();
} else if (mode === 'betrayal') {
road.tint = 0xAA6666; // Reddish road for betrayal mode
}
terrainElements.push(road);
game.addChild(road);
// Add castle at the top
var castle = new Terrain();
castle.init('castle', 1024, 300);
terrainElements.push(castle);
game.addChild(castle);
// Add some decorative terrain elements based on mode
if (mode === 'day') {
var _loop = function _loop() {
terrain = new Terrain();
type = Math.random() > 0.5 ? 'stone' : 'dirt';
terrain.init(type, Math.random() * 1700 + 174, Math.random() * 2000 + 400);
// Add bright daylight tint to terrain
terrain.tint = 0xFFFF99; // Bright sunny tint
terrain.alpha = 1.0;
// Add floating animation to terrain objects with enhanced brightness effects
terrain.startY = terrain.y;
function createTerrainFloat(terrainObj) {
tween(terrainObj, {
y: terrainObj.startY - 5,
rotation: 0.05,
tint: 0xFFFFAA,
scaleX: 1.02,
scaleY: 1.02
}, {
duration: 2000 + Math.random() * 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(terrainObj, {
y: terrainObj.startY + 5,
rotation: -0.05,
tint: 0xFFFF99,
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 2000 + Math.random() * 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
createTerrainFloat(terrainObj);
}
});
}
});
}
createTerrainFloat(terrain);
terrainElements.push(terrain);
game.addChild(terrain);
},
terrain,
type;
// Add some stones and dirt for day mode
for (var i = 0; i < 8; i++) {
_loop();
}
// Add sun rays effect
for (var r = 0; r < 8; r++) {
var ray = new Text2('|', {
size: 400,
fill: '#FFD700'
});
ray.anchor.set(0.5, 0);
ray.x = 250 + Math.cos(r * Math.PI / 4) * 400;
ray.y = 250;
ray.rotation = r * Math.PI / 4;
ray.alpha = 0.1;
ray.scaleX = 3;
game.addChild(ray);
// Add ray animation
(function (rayObj) {
var _rayPulse = function rayPulse() {
tween(rayObj, {
alpha: 0.2,
scaleX: 4,
scaleY: 1.2
}, {
duration: 4000 + Math.random() * 2000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(rayObj, {
alpha: 0.05,
scaleX: 3,
scaleY: 1.0
}, {
duration: 4000 + Math.random() * 2000,
easing: tween.easeInOut,
onFinish: _rayPulse
});
}
});
};
LK.setTimeout(_rayPulse, Math.random() * 2000);
})(ray);
}
} else if (mode === 'night') {
// Add fewer, darker terrain for night mode with mystical effects
for (var i = 0; i < 5; i++) {
var terrain = new Terrain();
terrain.init('stone', Math.random() * 1700 + 174, Math.random() * 2000 + 400);
// Add dark tint to terrain for night mode
terrain.tint = 0x4444AA;
terrain.alpha = 0.8;
// Add mystical glow animation to night terrain
(function (terrainObj) {
var _mysticalGlow = function mysticalGlow() {
tween(terrainObj, {
tint: 0x6666FF,
alpha: 0.9
}, {
duration: 3000 + Math.random() * 2000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(terrainObj, {
tint: 0x4444AA,
alpha: 0.8
}, {
duration: 3000 + Math.random() * 2000,
easing: tween.easeInOut,
onFinish: _mysticalGlow
});
}
});
};
LK.setTimeout(_mysticalGlow, Math.random() * 1000);
})(terrain);
terrainElements.push(terrain);
game.addChild(terrain);
}
// Add night fog effect
var fog = new Text2('🌫️', {
size: 150,
fill: '#E6E6FA'
});
fog.anchor.set(0.5, 0.5);
fog.x = 1024;
fog.y = 1500;
fog.alpha = 0.3;
game.addChild(fog);
// Add fog movement animation
var _fogDrift = function fogDrift() {
tween(fog, {
x: 1024 + (Math.random() - 0.5) * 300,
scaleX: 1.2 + Math.random() * 0.5,
scaleY: 1.2 + Math.random() * 0.5,
alpha: 0.2 + Math.random() * 0.2
}, {
duration: 6000 + Math.random() * 4000,
easing: tween.easeInOut,
onFinish: _fogDrift
});
};
_fogDrift();
} else if (mode === 'betrayal') {
// Add strategic terrain for betrayal mode
for (var i = 0; i < 10; i++) {
var terrain = new Terrain();
var type = Math.random() > 0.3 ? 'stone' : 'dirt';
terrain.init(type, Math.random() * 1700 + 174, Math.random() * 2000 + 400);
terrainElements.push(terrain);
game.addChild(terrain);
}
}
}
function spawnEnemy() {
var enemy = new Enemy();
// Determine enemy type based on mode and progress
var enemyType = 'aamir';
var progress = enemiesKilled / enemiesRequired;
if (currentMode === 'betrayal') {
if (Math.random() < 0.3) {
enemyType = 'sultan';
} else if (progress > 0.7 && Math.random() < 0.2) {
enemyType = 'vega';
}
} else {
if (progress > 0.8 && Math.random() < 0.15) {
enemyType = 'vega';
}
}
enemy.init(enemyType);
enemy.x = Math.random() * 1700 + 174; // Better bounds to keep enemies visible
enemy.y = -50;
// Add spawn entrance animation
enemy.alpha = 0;
enemy.scaleX = 0.3;
enemy.scaleY = 0.3;
enemy.rotation = Math.PI;
// Animate enemy entrance
tween(enemy, {
alpha: 1,
scaleX: 1.0,
scaleY: 1.0,
rotation: 0,
tint: 0xFFFFFF
}, {
duration: 500,
easing: tween.elasticOut
});
// Add spawn glow effect
tween(enemy, {
tint: 0xFF6B35
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(enemy, {
tint: 0xFFFFFF
}, {
duration: 400,
easing: tween.easeOut
});
}
});
enemies.push(enemy);
game.addChild(enemy);
}
function checkVictory() {
// Check for sultan meeting in night and day modes at score 50
if ((currentMode === 'night' || currentMode === 'day') && enemiesKilled >= 50 && gameState !== 'sultanMeeting') {
gameState = 'sultanMeeting';
LK.getSound('victory').play();
// Create sultan character
var sultanChar = new Terrain();
sultanChar.init('sultan', 1024, 1366);
game.addChild(sultanChar);
tween(sultanChar, {
scaleX: 10,
scaleY: 10
}, {
duration: 2000,
easing: tween.easeOut
});
// Sultan meeting text
var meetingText = new Text2('My Sultan Arrives!', {
size: 80,
fill: '#FFD700',
stroke: '#8B0000',
strokeThickness: 4
});
meetingText.anchor.set(0.5, 0.5);
meetingText.x = 1024;
meetingText.y = 800;
game.addChild(meetingText);
tween(meetingText, {
scaleX: 1.2,
scaleY: 1.2,
tint: 0xFFB347
}, {
duration: 1000,
easing: tween.easeInOut
});
// Create golden confetti for sultan meeting
for (var i = 0; i < 30; i++) {
var confetti = new Confetti();
confetti.x = Math.random() * 2048;
confetti.y = Math.random() * 500 + 500;
confetti.tint = 0xFFD700; // Golden confetti for sultan
confettiParticles.push(confetti);
game.addChild(confetti);
}
// Continue game after sultan meeting
LK.setTimeout(function () {
gameState = 'playing';
meetingText.destroy();
sultanChar.destroy();
}, 3000);
return;
}
// Check for sultan meeting in betrayal mode at exactly 10 enemies killed
if (currentMode === 'betrayal' && enemiesKilled === 10 && gameState !== 'sultanMeeting') {
gameState = 'sultanMeeting';
LK.getSound('victory').play();
// Create sultan character
var sultanChar = new Terrain();
sultanChar.init('sultan', 1024, 1366);
game.addChild(sultanChar);
tween(sultanChar, {
scaleX: 10,
scaleY: 10
}, {
duration: 2000,
easing: tween.easeOut
});
// Sultan betrayal meeting text
var meetingText = new Text2('The Sultan Has Turned Against Us!', {
size: 70,
fill: '#FF0000',
stroke: '#8B0000',
strokeThickness: 4
});
meetingText.anchor.set(0.5, 0.5);
meetingText.x = 1024;
meetingText.y = 800;
game.addChild(meetingText);
tween(meetingText, {
scaleX: 1.2,
scaleY: 1.2,
tint: 0xFF4500
}, {
duration: 1000,
easing: tween.easeInOut
});
// Create red confetti for betrayal meeting
for (var i = 0; i < 30; i++) {
var confetti = new Confetti();
confetti.x = Math.random() * 2048;
confetti.y = Math.random() * 500 + 500;
confetti.tint = 0xFF0000; // Red confetti for betrayal
confettiParticles.push(confetti);
game.addChild(confetti);
}
// Continue game after sultan meeting
LK.setTimeout(function () {
gameState = 'playing';
meetingText.destroy();
sultanChar.destroy();
}, 3000);
return;
}
if (enemiesKilled >= enemiesRequired) {
// Add celebration sparkles around victory text
var createVictorySparkles = function createVictorySparkles() {
for (var s = 0; s < 10; s++) {
var sparkle = new Text2('✨', {
size: 40 + Math.random() * 30,
fill: '#FFD700'
});
sparkle.anchor.set(0.5, 0.5);
sparkle.x = victoryText.x + (Math.random() - 0.5) * 500;
sparkle.y = victoryText.y + (Math.random() - 0.5) * 300;
sparkle.alpha = 0;
game.addChild(sparkle);
tween(sparkle, {
alpha: 1,
scaleX: 2.0,
scaleY: 2.0,
rotation: Math.PI * 2
}, {
duration: 1200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(sparkle, {
alpha: 0,
scaleX: 0.2,
scaleY: 0.2
}, {
duration: 800,
easing: tween.easeIn,
onFinish: function onFinish() {
sparkle.destroy();
}
});
}
});
}
};
gameState = 'victory';
LK.getSound('victory').play();
// Create optimized confetti (reduced count for performance)
for (var i = 0; i < 20; i++) {
var confetti = new Confetti();
confetti.x = Math.random() * 2048;
confetti.y = Math.random() * 500 + 500;
// Random colors for confetti
var colors = [0xFFD700, 0xFF1493, 0x00FF00, 0x00BFFF, 0xFF4500];
confetti.tint = colors[Math.floor(Math.random() * colors.length)];
confettiParticles.push(confetti);
game.addChild(confetti);
}
// Victory text with enhanced entrance animation
var victoryText = new Text2('Victory! Love Conquers All!', {
size: 70,
fill: '#FFD700',
stroke: '#8B0000',
strokeThickness: 4
});
victoryText.anchor.set(0.5, 0.5);
victoryText.x = 1024;
victoryText.y = 1366;
victoryText.alpha = 0;
victoryText.scaleX = 0.3;
victoryText.scaleY = 0.3;
game.addChild(victoryText);
// Animate victory text entrance
tween(victoryText, {
alpha: 1,
scaleX: 1.2,
scaleY: 1.2,
rotation: 0.1
}, {
duration: 1000,
easing: tween.elasticOut,
onFinish: function onFinish() {
// Add continuous celebration animation
function celebrateAnimation() {
tween(victoryText, {
scaleX: 1.3,
scaleY: 1.3,
tint: 0xFF6B35,
rotation: -0.1
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(victoryText, {
scaleX: 1.1,
scaleY: 1.1,
tint: 0xFFD700,
rotation: 0.1
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: celebrateAnimation
});
}
});
}
celebrateAnimation();
}
});
createVictorySparkles();
LK.setTimeout(createVictorySparkles, 1500);
LK.setTimeout(createVictorySparkles, 3000);
// Return to menu after 5 seconds
LK.setTimeout(function () {
// Clear game
while (game.children.length > 0) {
var child = game.children[0];
child.destroy();
}
while (LK.gui.top.children.length > 0) {
var child = LK.gui.top.children[0];
child.destroy();
}
// Reset arrays
bullets = [];
enemies = [];
confettiParticles = [];
bloodParticles = [];
terrainElements = [];
lasers = [];
modeButtons = [];
initMenu();
}, 5000);
}
}
// Touch controls
var isTouching = false;
var lastTapTime = 0;
var doubleTapDelay = 300; // 300ms for double tap detection
game.down = function (x, y, obj) {
if (gameState === 'playing') {
// Check if clicking on tower placement button area
if (x < 300 && y < 300) {
if (x > 50 && x < 250 && y > 200 && y < 250) {
placementMode = !placementMode;
selectedTowerType = placementMode ? 'tower' : null;
return;
}
}
// Tower placement mode
if (placementMode && selectedTowerType === 'tower' && playerGold >= 50) {
// Check if position is valid (not too close to path or other towers)
var validPosition = true;
// Check distance from path
for (var i = 0; i < enemyPath.length; i++) {
var pathPoint = enemyPath[i];
var dx = x - pathPoint.x;
var dy = y - pathPoint.y;
if (Math.sqrt(dx * dx + dy * dy) < 100) {
validPosition = false;
break;
}
}
// Check distance from other towers
for (var i = 0; i < towers.length; i++) {
var tower = towers[i];
var dx = x - tower.x;
var dy = y - tower.y;
if (Math.sqrt(dx * dx + dy * dy) < 120) {
validPosition = false;
break;
}
}
if (validPosition && y > 400 && y < 2200 && x > 200 && x < 1848) {
var newTower = new Tower();
newTower.x = x;
newTower.y = y;
towers.push(newTower);
game.addChild(newTower);
playerGold -= 50;
updateGoldDisplay();
placementMode = false;
selectedTowerType = null;
}
return;
}
isTouching = true;
var currentTime = Date.now();
// Check for double tap to shoot laser
if (currentTime - lastTapTime < doubleTapDelay) {
// Add screen shake effect for laser
var screenShake = function screenShake() {
tween(game, {
x: (Math.random() - 0.5) * 15,
y: (Math.random() - 0.5) * 15
}, {
duration: 50,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(game, {
x: 0,
y: 0
}, {
duration: 100,
easing: tween.easeOut
});
}
});
};
omar.shootLaser();
for (var shakeCount = 0; shakeCount < 3; shakeCount++) {
LK.setTimeout(screenShake, shakeCount * 100);
}
} else {
omar.shoot();
}
lastTapTime = currentTime;
}
};
game.up = function (x, y, obj) {
isTouching = false;
};
game.move = function (x, y, obj) {
if (gameState === 'playing' && omar) {
// Manual control overrides AI
if (omarAI) {
omarAI.deactivate();
}
omar.x = Math.max(40, Math.min(2008, x));
if (isTouching) {
omar.shoot();
}
// Reactivate AI after a short delay
LK.setTimeout(function () {
if (omarAI) {
omarAI.activate();
}
}, 1000);
}
};
game.update = function () {
if (gameState === 'playing') {
// Spawn enemies with better control
enemySpawnTimer++;
if (enemySpawnTimer >= enemySpawnRate && enemies.length < 12) {
spawnEnemy();
enemySpawnTimer = 0;
// Gradual spawn rate increase with reasonable limits
if (enemiesKilled >= 90) {
enemySpawnRate = Math.max(20, 45 - Math.floor((enemiesKilled - 90) / 15) * 3);
} else {
enemySpawnRate = Math.max(40, 80 - Math.floor(enemiesKilled / 25) * 5);
}
}
// Update bullets - remove bullets that go too far off screen for performance
for (var i = bullets.length - 1; i >= 0; i--) {
var bullet = bullets[i];
if (!bullet || bullet.alpha <= 0) {
if (bullet) bullet.destroy();
bullets.splice(i, 1);
continue;
}
if (bullet.lastY === undefined) bullet.lastY = bullet.y;
// Remove bullets that are way off screen for performance
if (bullet.y < -500 || bullet.y > 2800) {
bullet.destroy();
bullets.splice(i, 1);
continue;
}
// Optimized collision detection - only check nearby enemies
var hit = false;
for (var j = enemies.length - 1; j >= 0 && !hit; j--) {
var enemy = enemies[j];
if (!enemy || enemy.alpha <= 0) continue;
// Quick distance check before expensive intersection
var dx = bullet.x - enemy.x;
var dy = bullet.y - enemy.y;
if (dx * dx + dy * dy < 8000 && bullet.intersects(enemy)) {
// Add bullet impact flash effect
tween(enemy, {
tint: 0xFFFFFF,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 80,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(enemy, {
tint: 0xFF0000,
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 120,
easing: tween.easeOut
});
}
});
// Create impact explosion particles
for (var p = 0; p < 8; p++) {
var spark = new BloodParticle();
spark.x = bullet.x;
spark.y = bullet.y;
var angle = p * Math.PI * 2 / 8;
spark.speedX = Math.cos(angle) * 4;
spark.speedY = Math.sin(angle) * 4;
spark.life = 15;
bloodParticles.push(spark);
game.addChild(spark);
}
// Add blood spray even when enemy is just damaged (not killed)
for (var k = 0; k < 4; k++) {
var blood = new BloodParticle();
blood.x = enemy.x + (Math.random() - 0.5) * 40;
blood.y = enemy.y + (Math.random() - 0.5) * 40;
blood.speedX = (Math.random() - 0.5) * 8;
blood.speedY = Math.random() * -6 - 2;
blood.life = 25;
blood.scaleX = 0.6;
blood.scaleY = 0.6;
blood.tint = 0xAA0000;
bloodParticles.push(blood);
game.addChild(blood);
}
if (enemy.takeDamage()) {
// Enhanced death animation with screen flash
LK.effects.flashScreen(0xFF4444, 150);
tween(enemy, {
scaleX: 1.8,
scaleY: 1.8,
alpha: 0,
rotation: Math.PI * 0.8,
tint: 0xFF0000
}, {
duration: 400,
easing: tween.bounceOut,
onFinish: function onFinish() {
enemy.destroy();
}
});
// Create optimized blood spray effect - reduced particle count
if (bloodParticles.length < 50) {
// Limit total particles
for (var k = 0; k < 6; k++) {
var blood = new BloodParticle();
blood.x = enemy.x + (Math.random() - 0.5) * 60;
blood.y = enemy.y + (Math.random() - 0.5) * 60;
blood.speedX = (Math.random() - 0.5) * 12;
blood.speedY = Math.random() * -8 - 3;
blood.life = 35; // Shorter life
// Add variety to blood particle colors
var bloodColors = [0xFF0000, 0xCC0000, 0x990000];
blood.tint = bloodColors[Math.floor(Math.random() * bloodColors.length)];
bloodParticles.push(blood);
game.addChild(blood);
}
}
enemies.splice(j, 1);
enemiesKilled++;
// Update score immediately when each enemy dies
scoreText.setText('Enemies: ' + enemiesKilled + ' / ' + enemiesRequired);
checkVictory();
}
// Bullet continues through enemy - no destruction
hit = true;
break;
}
}
if (!hit) {
bullet.lastY = bullet.y;
}
}
// Limit enemies on screen for performance - increase limit after score 90
var enemyLimit = enemiesKilled >= 90 ? 15 : 8;
if (enemies.length > enemyLimit) {
var oldEnemy = enemies.shift();
oldEnemy.destroy();
}
// Update enemies
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
if (enemy.lastY === undefined) enemy.lastY = enemy.y;
// Game over if enemy passes Omar's defensive line (y > 2300)
if (enemy.lastY <= 2300 && enemy.y > 2300) {
LK.showGameOver();
return;
}
enemy.lastY = enemy.y;
}
// Update lasers
for (var i = lasers.length - 1; i >= 0; i--) {
var laser = lasers[i];
// Add pulsing laser beam effect
if (laser.duration > 0) {
tween(laser, {
scaleX: 1.2 + Math.sin(LK.ticks * 0.3) * 0.2,
tint: 0x00FFFF
}, {
duration: 50,
easing: tween.linear
});
}
// Check laser collision with all enemies in range
for (var j = enemies.length - 1; j >= 0; j--) {
var enemy = enemies[j];
// Check if enemy intersects with laser beam
if (laser.intersects(enemy)) {
// Laser instantly kills enemies regardless of health
// Create intense explosion effect
LK.effects.flashScreen(0x00FFFF, 200);
// Create electric spark particles
for (var k = 0; k < 12; k++) {
var spark = new BloodParticle();
spark.x = enemy.x + (Math.random() - 0.5) * 60;
spark.y = enemy.y + (Math.random() - 0.5) * 60;
spark.speedX = (Math.random() - 0.5) * 15;
spark.speedY = (Math.random() - 0.5) * 15;
spark.life = 25;
spark.tint = 0x00FFFF; // Electric blue sparks
bloodParticles.push(spark);
game.addChild(spark);
}
// Enhanced enemy destruction animation
tween(enemy, {
scaleX: 2.0,
scaleY: 2.0,
alpha: 0,
rotation: Math.PI * 1.5,
tint: 0x00FFFF
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
enemy.destroy();
}
});
// Create enhanced blood spray effect for laser kills - more dramatic
for (var k = 0; k < 12; k++) {
var blood = new BloodParticle();
blood.x = enemy.x + (Math.random() - 0.5) * 100;
blood.y = enemy.y + (Math.random() - 0.5) * 100;
blood.speedX = (Math.random() - 0.5) * 20; // Faster for laser kills
blood.speedY = Math.random() * -15 - 5; // Higher velocity
blood.life = 60; // Longer lasting
blood.tint = 0xFF0000;
// Add some variety to blood colors for laser kills
var laserBloodColors = [0xFF0000, 0xFF4444, 0xCC0000];
blood.tint = laserBloodColors[Math.floor(Math.random() * laserBloodColors.length)];
bloodParticles.push(blood);
game.addChild(blood);
// Add animation to blood particles
tween(blood, {
scaleX: 1.2,
scaleY: 1.2,
rotation: Math.random() * Math.PI * 2
}, {
duration: blood.life * 16,
easing: tween.easeOut
});
}
// Add additional blood splatter effect for laser kills
for (var k = 0; k < 10; k++) {
var splatter = new BloodParticle();
splatter.x = enemy.x + (Math.random() - 0.5) * 150;
splatter.y = enemy.y + (Math.random() - 0.5) * 150;
splatter.speedX = (Math.random() - 0.5) * 12;
splatter.speedY = (Math.random() - 0.5) * 12;
splatter.life = 80; // Longer for dramatic effect
splatter.scaleX = 0.4;
splatter.scaleY = 0.4;
splatter.tint = 0x660000; // Darker blood for contrast
bloodParticles.push(splatter);
game.addChild(splatter);
}
enemies.splice(j, 1);
enemiesKilled += 5; // Award 5 enemies killed for laser kill
// Update score immediately when each enemy dies
scoreText.setText('Enemies: ' + enemiesKilled + ' / ' + enemiesRequired);
checkVictory();
}
}
// Remove laser when duration expires
if (laser.duration <= 0) {
laser.destroy();
lasers.splice(i, 1);
}
}
// Update towers
for (var i = 0; i < towers.length; i++) {
var tower = towers[i];
tower.update();
}
// Update tower bullets
for (var i = towerBullets.length - 1; i >= 0; i--) {
var bullet = towerBullets[i];
if (bullet.alpha <= 0) {
bullet.destroy();
towerBullets.splice(i, 1);
continue;
}
// Check collision with enemies
var hit = false;
for (var j = enemies.length - 1; j >= 0; j--) {
var enemy = enemies[j];
var dx = bullet.x - enemy.x;
var dy = bullet.y - enemy.y;
if (dx * dx + dy * dy < 2500 && bullet.intersects(enemy)) {
// Tower bullet impact
tween(enemy, {
tint: 0xFFFFFF,
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 60,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(enemy, {
tint: 0xFF6666,
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 100,
easing: tween.easeOut
});
}
});
// Create impact particles
for (var p = 0; p < 4; p++) {
var spark = new BloodParticle();
spark.x = bullet.x;
spark.y = bullet.y;
var angle = p * Math.PI * 2 / 4;
spark.speedX = Math.cos(angle) * 3;
spark.speedY = Math.sin(angle) * 3;
spark.life = 10;
spark.tint = 0xFF8C00;
bloodParticles.push(spark);
game.addChild(spark);
}
if (enemy.takeDamage(bullet.damage)) {
// Enemy killed by tower
tween(enemy, {
scaleX: 1.5,
scaleY: 1.5,
alpha: 0,
rotation: Math.PI * 0.5,
tint: 0xFF4444
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
enemy.destroy();
}
});
// Create blood spray
for (var k = 0; k < 8; k++) {
var blood = new BloodParticle();
blood.x = enemy.x + (Math.random() - 0.5) * 60;
blood.y = enemy.y + (Math.random() - 0.5) * 60;
blood.speedX = (Math.random() - 0.5) * 12;
blood.speedY = Math.random() * -8 - 2;
blood.life = 35;
bloodParticles.push(blood);
game.addChild(blood);
}
enemies.splice(j, 1);
enemiesKilled++;
scoreText.setText('Enemies: ' + enemiesKilled + ' / ' + enemiesRequired);
checkVictory();
}
bullet.destroy();
towerBullets.splice(i, 1);
hit = true;
break;
}
}
}
// Update AI
if (omarAI) {
omarAI.update();
}
// Reduced auto shoot frequency for better performance (only when AI is not active)
if (LK.ticks % 20 === 0 && (!omarAI || !omarAI.isActive)) {
omar.shoot();
}
}
// Update confetti
for (var i = confettiParticles.length - 1; i >= 0; i--) {
var confetti = confettiParticles[i];
if (confetti.life <= 0) {
confetti.destroy();
confettiParticles.splice(i, 1);
}
}
// Update blood particles with better cleanup
for (var i = bloodParticles.length - 1; i >= 0; i--) {
var blood = bloodParticles[i];
if (!blood || blood.life <= 0 || blood.alpha <= 0) {
if (blood && blood.parent) {
blood.destroy();
}
bloodParticles.splice(i, 1);
}
}
// Limit total blood particles for performance
if (bloodParticles.length > 30) {
var excess = bloodParticles.splice(0, bloodParticles.length - 30);
for (var i = 0; i < excess.length; i++) {
if (excess[i] && excess[i].parent) {
excess[i].destroy();
}
}
}
};
function updateGoldDisplay() {
if (goldText) {
goldText.setText('Gold: ' + playerGold);
}
}
// Initialize the menu
initMenu();
Siyah saçlı,zayıf,uzun boylu bir erkek genç. In-Game asset. 2d. High contrast. No shadows
Uzun saçlı kahverengi renkte iri bir adam. In-Game asset. 2d. High contrast. No shadows
Yaşlı bir adam kısa boylu aksakallı. In-Game asset. 2d. High contrast. No shadows
Kapalı saçlı orta ağırlıkta bir kız bir sultan çok güzel. In-Game asset. 2d. High contrast. No shadows
Dikey bir yol yap kara yolu. In-Game asset. 2d. High contrast. No shadows
Tabanca mermisi tasarla. In-Game asset. 2d. High contrast. No shadows
Mod butonu tasarla böyle tarz olsun. In-Game asset. 2d. High contrast. No shadows
Konfeti tasarla patlayan. In-Game asset. 2d. High contrast. No shadows
Taş tasarla grey. In-Game asset. 2d. High contrast. No shadows
Bir dirt tasarla. In-Game asset. 2d. High contrast. No shadows