User prompt
top arkdaki kale ve ev lerin olduğu yere gelince patlama olmuş gibi partiküller şıksın ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
topu biraz büyüt ve topla orantılı şrekilde çubukların boyunu kısalt
User prompt
evler biraz daha yayılsın sağdakiler sağa doğru soldakiler de sola
User prompt
ayrıntıları kaldır
User prompt
zemindeki ayrımtılar daha yeşillin koyu hali olsun
User prompt
evler yanyana dursun sıralı ve zemine ayrıntılar ekle çizgiler fln
User prompt
kalelerin yanına ek daha küçük ek evler ekle her tarfa 3 tane hem kalenin sağına hemde soluna
User prompt
zemini yeşil yap zemin clash royalin zeminine benzesin
User prompt
topu biraz yavaşlat
User prompt
topu biraz daha hızlandır
User prompt
çubukları birasz tukarı al
User prompt
topu dahada hızlandır kale yi büyüt
User prompt
tamam boyutlaru biraz büyüt ve topu biraz hızlandır ve bizde tıkladığımız yere gidelim
Code edit (1 edits merged)
Please save this source code
User prompt
Paddle Castle Defender
Initial prompt
oyunda iki çubuk olacak karşılıklı arkaların dada kaleleri ve ortadada bir top olacak ve bu top rastgele bir yerden başlayacak ya sağ yada sol ve çubuğuğa değerse sekecek ve göze batmayan ufak partiküller saçacak ve eğer top arkadaki kalelere değerse atan kiçi 1 puan alacak maşın süresi 1 buçuk dakka olacak biz bu iki çubuktan birisi olacağız karşı rakip ise bot olacak ve biz karakterimizi alttaki ok tuşları koy onlarla hareket ettireceğiz
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var BackgroundCloud = Container.expand(function () { var self = Container.call(this); var cloud = self.attachAsset('cloud', { anchorX: 0.5, anchorY: 0.5 }); cloud.alpha = 0.7; self.speed = 0.3 + Math.random() * 0.5; // Floating animation self.update = function () { self.x += self.speed; if (self.x > 2200) { self.x = -150; } var time = LK.ticks * 0.01; self.y += Math.sin(time) * 0.1; }; return self; }); var BackgroundFlower = Container.expand(function () { var self = Container.call(this); var flower = self.attachAsset('flower', { anchorX: 0.5, anchorY: 0.5 }); flower.alpha = 0.9; // Gentle bobbing self.update = function () { var time = LK.ticks * 0.025; flower.scaleX = 1 + Math.sin(time) * 0.1; flower.scaleY = 1 + Math.sin(time) * 0.1; }; return self; }); var BackgroundGrass = Container.expand(function () { var self = Container.call(this); var grass = self.attachAsset('grass', { anchorX: 0.5, anchorY: 0.5 }); grass.alpha = 0.8; // Gentle swaying self.update = function () { var time = LK.ticks * 0.03; grass.rotation = Math.sin(time) * 0.05; }; return self; }); var BackgroundMountain = Container.expand(function () { var self = Container.call(this); var mountain = self.attachAsset('mountain', { anchorX: 0.5, anchorY: 1 }); mountain.alpha = 0.3; mountain.tint = 0x4682B4; return self; }); var BackgroundTree = Container.expand(function () { var self = Container.call(this); var trunk = self.attachAsset('tree', { anchorX: 0.5, anchorY: 1 }); var leaves = self.attachAsset('treeLeaves', { anchorX: 0.5, anchorY: 1 }); leaves.y = -40; // Add subtle swaying animation self.update = function () { var time = LK.ticks * 0.02; leaves.rotation = Math.sin(time) * 0.1; trunk.rotation = Math.sin(time) * 0.05; }; return self; }); var Ball = Container.expand(function () { var self = Container.call(this); var ballGraphics = self.attachAsset('ball', { anchorX: 0.5, anchorY: 0.5 }); self.velocityX = 0; self.velocityY = 0; self.speed = 12; self.reset = function () { self.x = 1024; self.y = 1366; var angle = (Math.random() > 0.5 ? 1 : -1) * (Math.PI / 6 + Math.random() * Math.PI / 3); self.velocityX = Math.sin(angle) * self.speed; // Ball only goes towards player (positive Y) or AI (negative Y), not random self.velocityY = Math.cos(angle) * self.speed * (Math.random() > 0.5 ? 1 : -1); }; self.update = function () { self.x += self.velocityX; self.y += self.velocityY; // Bounce off left and right walls if (self.x <= 30 || self.x >= 2018) { self.velocityX = -self.velocityX; } }; return self; }); var Card = Container.expand(function (cardType) { var self = Container.call(this); var cardGraphics = self.attachAsset('card', { anchorX: 0.5, anchorY: 0.5 }); self.cardType = cardType; self.used = false; self.cooldown = 0; self.usageCount = 0; // Track how many times this card has been used self.maxUsage = 2; // Maximum number of times this card can be used var iconAsset = ''; var emojiText = ''; switch (cardType) { case 'speed': iconAsset = 'speedBoostIcon'; emojiText = '⚡'; break; case 'explosion': iconAsset = 'explosionIcon'; emojiText = '💥'; break; case 'pierce': iconAsset = 'pierceIcon'; emojiText = '🔥'; break; case 'slow': iconAsset = 'slowIcon'; emojiText = '❄️'; break; case 'illusion': iconAsset = 'illusionIcon'; emojiText = '🎭'; break; } var icon = self.attachAsset(iconAsset, { anchorX: 0.5, anchorY: 0.5 }); var emoji = new Text2(emojiText, { size: 40, fill: '#FFFFFF' }); emoji.anchor.set(0.5, 0.5); self.addChild(emoji); self.down = function (x, y, obj) { if (!self.used && self.cooldown <= 0 && self.usageCount < self.maxUsage) { self.used = true; self.cooldown = 300; // 5 seconds at 60fps self.usageCount++; // Increment usage counter // Play card selection sound LK.getSound('cardSelect').play(); // Card activation animation tween(self, { scaleX: 1.3, scaleY: 1.3 }, { duration: 150, easing: tween.easeOut, onFinish: function onFinish() { tween(self, { scaleX: 1, scaleY: 1 }, { duration: 150, easing: tween.easeOut }); } }); // Glowing effect tween(cardGraphics, { tint: 0xFFFFFF }, { duration: 100, onFinish: function onFinish() { tween(cardGraphics, { alpha: 0.5, tint: 0x666666 }, { duration: 200 }); } }); tween(icon, { alpha: 0.5, scaleX: 1.2, scaleY: 1.2 }, { duration: 200, onFinish: function onFinish() { tween(icon, { scaleX: 1, scaleY: 1 }, { duration: 200 }); } }); // Floating particles from card for (var i = 0; i < 3; i++) { var particle = game.addChild(new Particle()); particle.x = self.x + (Math.random() - 0.5) * 60; particle.y = self.y + (Math.random() - 0.5) * 60; particle.velocityX = (Math.random() - 0.5) * 6; particle.velocityY = -Math.random() * 8 - 2; particle.life = 40; particle.maxLife = 40; particles.push(particle); } switch (self.cardType) { case 'speed': activateSpeedBoost(); break; case 'explosion': activateExplosion(); break; case 'pierce': activatePierce(); break; case 'slow': activateSlow(); break; case 'illusion': activateIllusion(); break; } // Check if card has reached usage limit - trigger destruction immediately if (self.usageCount >= self.maxUsage) { self.hasExploded = true; // Create explosion particles around the card for (var i = 0; i < 12; i++) { var particle = game.addChild(new Particle()); particle.x = self.x + (Math.random() - 0.5) * 100; particle.y = self.y + (Math.random() - 0.5) * 120; particle.velocityX = (Math.random() - 0.5) * 15; particle.velocityY = (Math.random() - 0.5) * 15; particle.life = 60; particle.maxLife = 60; // Random bright colors for explosion effect var colors = [0xff4444, 0xffaa44, 0xffff44, 0xff8844, 0xaa44ff]; var randomColor = colors[Math.floor(Math.random() * colors.length)]; tween(particle, { tint: randomColor }, { duration: 200 }); particles.push(particle); } // Create card fragments that fly out for (var i = 0; i < 6; i++) { var fragment = game.addChild(new Container()); var fragmentGraphics = fragment.attachAsset('card', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.3, scaleY: 0.3 }); fragment.x = self.x; fragment.y = self.y; var angle = i / 6 * Math.PI * 2; var speed = 8 + Math.random() * 6; var fragmentVelX = Math.cos(angle) * speed; var fragmentVelY = Math.sin(angle) * speed; // Fragment animation - fly out and fade tween(fragment, { x: fragment.x + fragmentVelX * 20, y: fragment.y + fragmentVelY * 20, rotation: (Math.random() - 0.5) * 4, alpha: 0, scaleX: 0.1, scaleY: 0.1 }, { duration: 1000 + Math.random() * 500, easing: tween.easeOut, onFinish: function onFinish() { fragment.destroy(); } }); } // Card shake and explosion effect var originalX = self.x; var originalY = self.y; tween(self, { x: originalX + 15, y: originalY + 15, scaleX: 1.3, scaleY: 1.3 }, { duration: 100, onFinish: function onFinish() { tween(self, { x: originalX - 15, y: originalY - 15, scaleX: 1.1, scaleY: 1.1 }, { duration: 100, onFinish: function onFinish() { tween(self, { x: originalX, y: originalY, scaleX: 0.8, scaleY: 0.8 }, { duration: 100 }); } }); } }); // Card is permanently disabled - make it visually distinct tween(cardGraphics, { alpha: 0.3, tint: 0x666666 }, { duration: 300, easing: tween.easeOut }); tween(icon, { alpha: 0.3 }, { duration: 300, easing: tween.easeOut }); } } }; self.move = function (x, y, obj) { // Hover effect removed }; self.up = function (x, y, obj) { if (!self.used && self.cooldown <= 0) { // Card unhover animation - return to normal size tween(self, { scaleX: 0.8, scaleY: 0.8 }, { duration: 100, easing: tween.easeOut }); } }; self.update = function () { if (self.cooldown > 0) { self.cooldown--; if (self.cooldown <= 0 && self.usageCount < self.maxUsage) { self.used = false; // Card reactivation animation tween(cardGraphics, { alpha: 1, tint: 0xFFFFFF }, { duration: 300, easing: tween.easeOut }); tween(icon, { alpha: 1 }, { duration: 300, easing: tween.easeOut }); // Sparkle effect on reactivation for (var i = 0; i < 5; i++) { var particle = game.addChild(new Particle()); particle.x = self.x + (Math.random() - 0.5) * 80; particle.y = self.y + (Math.random() - 0.5) * 100; particle.velocityX = (Math.random() - 0.5) * 4; particle.velocityY = (Math.random() - 0.5) * 4; particle.life = 20; particle.maxLife = 20; tween(particle, { tint: 0xFFFFFF }, { duration: 100 }); particles.push(particle); } } else if (self.cooldown <= 0 && self.usageCount >= self.maxUsage) { // Card destruction effect - only trigger once if (!self.hasExploded) { self.hasExploded = true; // Create explosion particles around the card for (var i = 0; i < 12; i++) { var particle = game.addChild(new Particle()); particle.x = self.x + (Math.random() - 0.5) * 100; particle.y = self.y + (Math.random() - 0.5) * 120; particle.velocityX = (Math.random() - 0.5) * 15; particle.velocityY = (Math.random() - 0.5) * 15; particle.life = 60; particle.maxLife = 60; // Random bright colors for explosion effect var colors = [0xff4444, 0xffaa44, 0xffff44, 0xff8844, 0xaa44ff]; var randomColor = colors[Math.floor(Math.random() * colors.length)]; tween(particle, { tint: randomColor }, { duration: 200 }); particles.push(particle); } // Create card fragments that fly out for (var i = 0; i < 6; i++) { var fragment = game.addChild(new Container()); var fragmentGraphics = fragment.attachAsset('card', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.3, scaleY: 0.3 }); fragment.x = self.x; fragment.y = self.y; var angle = i / 6 * Math.PI * 2; var speed = 8 + Math.random() * 6; var fragmentVelX = Math.cos(angle) * speed; var fragmentVelY = Math.sin(angle) * speed; // Fragment animation - fly out and fade tween(fragment, { x: fragment.x + fragmentVelX * 20, y: fragment.y + fragmentVelY * 20, rotation: (Math.random() - 0.5) * 4, alpha: 0, scaleX: 0.1, scaleY: 0.1 }, { duration: 1000 + Math.random() * 500, easing: tween.easeOut, onFinish: function onFinish() { fragment.destroy(); } }); } // Card shake and explosion effect var originalX = self.x; var originalY = self.y; tween(self, { x: originalX + 15, y: originalY + 15, scaleX: 1.3, scaleY: 1.3 }, { duration: 100, onFinish: function onFinish() { tween(self, { x: originalX - 15, y: originalY - 15, scaleX: 1.1, scaleY: 1.1 }, { duration: 100, onFinish: function onFinish() { tween(self, { x: originalX, y: originalY, scaleX: 0.8, scaleY: 0.8 }, { duration: 100 }); } }); } }); } // Card is permanently disabled - make it visually distinct tween(cardGraphics, { alpha: 0.3, tint: 0x666666 }, { duration: 300, easing: tween.easeOut }); tween(icon, { alpha: 0.3 }, { duration: 300, easing: tween.easeOut }); } } else if (!self.used) { // Idle floating animation - maintain original Y position with small float var time = LK.ticks * 0.1; var originalY = self.y; if (self.originalY === undefined) { self.originalY = self.y; } self.y = self.originalY + Math.sin(time + self.cardType.length) * 5; // Subtle glow effect if (LK.ticks % 180 === 0) { tween(cardGraphics, { tint: 0xFFFFFF }, { duration: 200, easing: tween.easeInOut, onFinish: function onFinish() { tween(cardGraphics, { tint: 0x4a90e2 }, { duration: 200, easing: tween.easeInOut }); } }); } } }; return self; }); var Castle = Container.expand(function () { var self = Container.call(this); var castleGraphics = self.attachAsset('castle', { anchorX: 0.5, anchorY: 0.5 }); return self; }); var House = Container.expand(function () { var self = Container.call(this); var houseGraphics = self.attachAsset('house', { anchorX: 0.5, anchorY: 0.5 }); return self; }); var Paddle = Container.expand(function () { var self = Container.call(this); var paddleGraphics = self.attachAsset('paddle', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 8; self.targetX = self.x; self.moveTowards = function (targetX) { self.targetX = targetX; if (self.targetX < 100) self.targetX = 100; if (self.targetX > 1948) self.targetX = 1948; }; self.update = function () { if (Math.abs(self.x - self.targetX) > 2) { if (self.x < self.targetX) { self.x += self.speed; } else { self.x -= self.speed; } } }; return self; }); var Particle = Container.expand(function () { var self = Container.call(this); var particleGraphics = self.attachAsset('particle', { anchorX: 0.5, anchorY: 0.5 }); self.velocityX = (Math.random() - 0.5) * 8; self.velocityY = (Math.random() - 0.5) * 8; self.life = 30; self.maxLife = 30; self.update = function () { self.x += self.velocityX; self.y += self.velocityY; self.life--; var alpha = self.life / self.maxLife; particleGraphics.alpha = alpha; if (self.life <= 0) { self.destroy(); particles.splice(particles.indexOf(self), 1); } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x228B22 }); /**** * Game Code ****/ // Simple background - removed complex gradient overlay var gameTime = 90; var playerScore = 0; var aiScore = 0; var particles = []; var cards = []; var speedBoostActive = false; var speedBoostTimer = 0; var explosionActive = false; var pierceActive = false; var pierceTimer = 0; var pierceUser = null; // Track who used pierce power-up var slowActive = false; var slowTimer = 0; var illusionActive = false; var illusionTimer = 0; var illusionBalls = []; var aiStunned = false; var aiStunTimer = 0; var playerStunned = false; var playerStunTimer = 0; // Create UI elements var timerText = new Text2('90', { size: 80, fill: 0xFFFFFF }); timerText.anchor.set(0.5, 0); LK.gui.top.addChild(timerText); var playerScoreText = new Text2('0', { size: 60, fill: 0x4A90E2 }); playerScoreText.anchor.set(0, 1); LK.gui.bottomLeft.addChild(playerScoreText); var aiScoreText = new Text2('0', { size: 60, fill: 0xE24A4A }); aiScoreText.anchor.set(0, 0); LK.gui.topLeft.addChild(aiScoreText); // Create tutorial overlay var tutorialOverlay = game.addChild(new Container()); tutorialOverlay.x = 0; tutorialOverlay.y = 0; // Create semi-transparent background var tutorialBg = tutorialOverlay.attachAsset('card', { anchorX: 0, anchorY: 0, scaleX: 25.6, scaleY: 27.32, alpha: 0.8 }); tutorialBg.tint = 0x000000; // Create tutorial title var tutorialTitle = new Text2('POWER-UPS TUTORIAL', { size: 80, fill: '#FFFFFF' }); tutorialTitle.anchor.set(0.5, 0.5); tutorialTitle.x = 1024; tutorialTitle.y = 400; tutorialOverlay.addChild(tutorialTitle); // Create game objective text var objectiveText = new Text2('GAME OBJECTIVE: Score more goals than your opponent in 90 seconds!', { size: 55, fill: '#FFD700' }); objectiveText.anchor.set(0.5, 0.5); objectiveText.x = 1024; objectiveText.y = 550; tutorialOverlay.addChild(objectiveText); // Create power-up instruction texts var instructions = ['⚡ SPEED BOOST: Makes ball move faster for 5 seconds', '💥 EXPLOSION: Ball explodes and stuns opponent for 5 seconds', '🔥 PIERCE: Ball goes through opponent paddle for 3 seconds', '❄️ SLOW: Makes ball move slower for 5 seconds']; var instructionTexts = []; for (var i = 0; i < instructions.length; i++) { var instructionText = new Text2(instructions[i], { size: 50, fill: '#FFFFFF' }); instructionText.anchor.set(0.5, 0.5); instructionText.x = 1024; instructionText.y = 650 + i * 120; tutorialOverlay.addChild(instructionText); instructionTexts.push(instructionText); } // Create start button var startButton = tutorialOverlay.attachAsset('card', { anchorX: 0.5, anchorY: 0.5, scaleX: 3, scaleY: 1.5 }); startButton.x = 1024; startButton.y = 1400; startButton.tint = 0x4A90E2; var startButtonText = new Text2('TAP TO START', { size: 60, fill: '#FFFFFF' }); startButtonText.anchor.set(0.5, 0.5); startButtonText.x = 1024; startButtonText.y = 1400; tutorialOverlay.addChild(startButtonText); // Add tutorial click handler tutorialOverlay.down = function (x, y, obj) { // Hide tutorial with fade animation tween(tutorialOverlay, { alpha: 0 }, { duration: 500, easing: tween.easeOut, onFinish: function onFinish() { tutorialOverlay.visible = false; } }); }; // Create game objects var playerPaddle = game.addChild(new Paddle()); playerPaddle.x = 1024; playerPaddle.y = 2300; var aiPaddle = game.addChild(new Paddle()); aiPaddle.x = 1024; aiPaddle.y = 432; var playerCastle = game.addChild(new Castle()); playerCastle.x = 1024; playerCastle.y = 2542; // Add houses around player castle // Left side houses in a row var playerHouse1L = game.addChild(new House()); playerHouse1L.x = 350; playerHouse1L.y = 2500; var playerHouse2L = game.addChild(new House()); playerHouse2L.x = 500; playerHouse2L.y = 2500; var playerHouse3L = game.addChild(new House()); playerHouse3L.x = 650; playerHouse3L.y = 2500; // Right side houses in a row var playerHouse1R = game.addChild(new House()); playerHouse1R.x = 1398; playerHouse1R.y = 2500; var playerHouse2R = game.addChild(new House()); playerHouse2R.x = 1548; playerHouse2R.y = 2500; var playerHouse3R = game.addChild(new House()); playerHouse3R.x = 1698; playerHouse3R.y = 2500; var aiCastle = game.addChild(new Castle()); aiCastle.x = 1024; aiCastle.y = 190; // Add houses around AI castle // Left side houses in a row var aiHouse1L = game.addChild(new House()); aiHouse1L.x = 350; aiHouse1L.y = 232; var aiHouse2L = game.addChild(new House()); aiHouse2L.x = 500; aiHouse2L.y = 232; var aiHouse3L = game.addChild(new House()); aiHouse3L.x = 650; aiHouse3L.y = 232; // Right side houses in a row var aiHouse1R = game.addChild(new House()); aiHouse1R.x = 1398; aiHouse1R.y = 232; var aiHouse2R = game.addChild(new House()); aiHouse2R.x = 1548; aiHouse2R.y = 232; var aiHouse3R = game.addChild(new House()); aiHouse3R.x = 1698; aiHouse3R.y = 232; // Clean green background - no decorative elements var ball = game.addChild(new Ball()); ball.reset(); // Create player cards stacked vertically on left side var cardTypes = ['speed', 'explosion', 'pierce', 'slow', 'illusion']; var cardX = 150; // Left side position var cardStartY = 1600; // Starting Y position (moved up for 5 cards) var cardSpacing = 160; // Space between cards (reduced for 5 cards) for (var i = 0; i < 5; i++) { var card = game.addChild(new Card(cardTypes[i])); card.x = cardX; card.y = cardStartY + i * cardSpacing; card.scaleX = 0.8; card.scaleY = 0.8; cards.push(card); } // Create AI cards stacked vertically on right side - hidden from player var aiCards = []; var aiCardX = 1898; // Right side position var aiCardStartY = 800; // Starting Y position for AI for (var i = 0; i < 5; i++) { var aiCard = game.addChild(new Card(cardTypes[i])); aiCard.x = aiCardX; aiCard.y = aiCardStartY + i * cardSpacing; // Hide AI cards from player aiCard.visible = false; // Disable AI card interaction aiCard.down = function () {}; // Override down function to prevent interaction aiCards.push(aiCard); } // AI power-up usage logic with enhanced tracking var aiPowerUpTimer = 0; var aiPowerUpCooldown = 300; // 5 seconds between AI power-up usage var aiCardUsageHistory = []; var aiLastUsedCard = null; var aiPreferredCards = ['explosion', 'slow', 'speed', 'pierce']; // AI preference order function destroyBuildings() { // Determine which side lost and which buildings to destroy var losingBuildings = []; var winningCastle = null; var winningHouses = []; if (playerScore > aiScore) { // Player won, destroy AI buildings losingBuildings = [aiCastle, aiHouse1L, aiHouse2L, aiHouse3L, aiHouse1R, aiHouse2R, aiHouse3R]; winningCastle = playerCastle; winningHouses = [playerHouse1L, playerHouse2L, playerHouse3L, playerHouse1R, playerHouse2R, playerHouse3R]; } else { // AI won, destroy player buildings losingBuildings = [playerCastle, playerHouse1L, playerHouse2L, playerHouse3L, playerHouse1R, playerHouse2R, playerHouse3R]; winningCastle = aiCastle; winningHouses = [aiHouse1L, aiHouse2L, aiHouse3L, aiHouse1R, aiHouse2R, aiHouse3R]; } // Apply blue tint to winning castle and houses if (winningCastle) { tween(winningCastle, { tint: 0x4A90E2 }, { duration: 500, easing: tween.easeOut }); } for (var j = 0; j < winningHouses.length; j++) { tween(winningHouses[j], { tint: 0x4A90E2 }, { duration: 500, easing: tween.easeOut }); } // Destroy losing buildings with staggered timing for (var i = 0; i < losingBuildings.length; i++) { var building = losingBuildings[i]; var delay = i * 100; // 100ms delay between each building LK.setTimeout(function (currentBuilding) { return function () { // Create explosion effect at building location createExplosionEffect(currentBuilding.x, currentBuilding.y); // Animate building destruction tween(currentBuilding, { alpha: 0, scaleX: 0.3, scaleY: 0.3, rotation: Math.random() * 0.5 - 0.25 }, { duration: 800, easing: tween.easeOut, onFinish: function onFinish() { currentBuilding.visible = false; } }); }; }(building), delay); } } var gameTimer = LK.setInterval(function () { gameTime--; timerText.setText(gameTime.toString()); if (gameTime <= 0) { LK.clearInterval(gameTimer); // Start destruction animation before showing game over destroyBuildings(); // Show game over after destruction animation completes LK.setTimeout(function () { if (playerScore > aiScore) { LK.showYouWin(); } else { LK.showGameOver(); } }, 2000); // Wait 2 seconds for destruction animation to complete } }, 1000); var touchX = 1024; function createParticles(x, y) { for (var i = 0; i < 8; i++) { var particle = game.addChild(new Particle()); particle.x = x; particle.y = y; particles.push(particle); } } function activateSpeedBoost(isAI) { if (isAI) { // AI version - use AI card for (var i = 0; i < aiCards.length; i++) { if (aiCards[i].cardType === 'speed' && !aiCards[i].used && aiCards[i].cooldown <= 0 && aiCards[i].usageCount < aiCards[i].maxUsage) { aiCards[i].used = true; aiCards[i].cooldown = 300; aiCards[i].usageCount++; // Increment AI card usage counter // Track AI card usage aiLastUsedCard = 'speed'; aiCardUsageHistory.push({ type: 'speed', time: LK.ticks }); // Create visual effect at AI paddle to show card usage createParticles(aiPaddle.x, aiPaddle.y); break; } } } speedBoostActive = true; speedBoostTimer = 300; // 5 seconds at 60fps ball.speed = 24; // Increased from 18 to 24 for more noticeable effect // Play speed boost sound LK.getSound('speedSound').play(); // Speed boost animation with pulsing glow tween(ball, { tint: 0xFFFF00 }, { duration: 200 }); tween(ball, { scaleX: 1.2, scaleY: 1.2 }, { duration: 200, easing: tween.easeOut }); // Create pulsing effect function createPulse() { if (speedBoostActive) { tween(ball, { scaleX: 1.3, scaleY: 1.3 }, { duration: 300, easing: tween.easeInOut, onFinish: function onFinish() { if (speedBoostActive) { tween(ball, { scaleX: 1.1, scaleY: 1.1 }, { duration: 300, easing: tween.easeInOut, onFinish: createPulse }); } } }); } } createPulse(); // Create lightning particles around ball for (var i = 0; i < 5; i++) { var particle = game.addChild(new Particle()); particle.x = ball.x + (Math.random() - 0.5) * 80; particle.y = ball.y + (Math.random() - 0.5) * 80; particle.velocityX = (Math.random() - 0.5) * 12; particle.velocityY = (Math.random() - 0.5) * 12; particle.life = 20; particle.maxLife = 20; tween(particle, { tint: 0xFFFF00 }, { duration: 100 }); particles.push(particle); } // Create lightning trail effect that follows ball function createLightningTrail() { if (speedBoostActive) { // Create zigzag lightning behind ball for (var i = 0; i < 3; i++) { var particle = game.addChild(new Particle()); // Create zigzag pattern var angle = Math.random() * Math.PI * 2; var distance = 40 + Math.random() * 60; particle.x = ball.x - ball.velocityX * (i + 1) * 2 + Math.cos(angle) * distance; particle.y = ball.y - ball.velocityY * (i + 1) * 2 + Math.sin(angle) * distance; particle.velocityX = (Math.random() - 0.5) * 8; particle.velocityY = (Math.random() - 0.5) * 8; particle.life = 15; particle.maxLife = 15; tween(particle, { tint: 0xFFFFFF, scaleX: 1.5, scaleY: 0.3 }, { duration: 50, onFinish: function onFinish() { tween(particle, { tint: 0xFFFF00, scaleX: 0.8, scaleY: 0.8 }, { duration: 100 }); } }); particles.push(particle); } LK.setTimeout(createLightningTrail, 50); } } createLightningTrail(); } function activateExplosion(isAI) { if (isAI) { // AI version - use AI card for (var i = 0; i < aiCards.length; i++) { if (aiCards[i].cardType === 'explosion' && !aiCards[i].used && aiCards[i].cooldown <= 0 && aiCards[i].usageCount < aiCards[i].maxUsage) { aiCards[i].used = true; aiCards[i].cooldown = 300; aiCards[i].usageCount++; // Increment AI card usage counter // Track AI card usage aiLastUsedCard = 'explosion'; aiCardUsageHistory.push({ type: 'explosion', time: LK.ticks }); // Create visual effect at AI paddle to show card usage createParticles(aiPaddle.x, aiPaddle.y); break; } } } explosionActive = true; // Create multiple explosion waves createExplosionEffect(ball.x, ball.y); LK.setTimeout(function () { createExplosionEffect(ball.x, ball.y); }, 150); LK.setTimeout(function () { createExplosionEffect(ball.x, ball.y); }, 300); // Create expanding shockwave tween(ball, { scaleX: 3, scaleY: 3, alpha: 0.3 }, { duration: 500, easing: tween.easeOut, onFinish: function onFinish() { tween(ball, { scaleX: 1, scaleY: 1, alpha: 1 }, { duration: 200 }); } }); // Determine target based on who used explosion var targetPaddle = isAI ? playerPaddle : aiPaddle; var targetStunned = isAI ? 'playerStunned' : 'aiStunned'; var targetStunTimer = isAI ? 'playerStunTimer' : 'aiStunTimer'; // Make target paddle shake var _shakeTarget = function shakeTarget() { var isTargetStunned = isAI ? playerStunned : aiStunned; if (isTargetStunned) { var originalX = targetPaddle.x; tween(targetPaddle, { x: originalX + 5 }, { duration: 50, onFinish: function onFinish() { tween(targetPaddle, { x: originalX - 5 }, { duration: 50, onFinish: function onFinish() { tween(targetPaddle, { x: originalX }, { duration: 50, onFinish: _shakeTarget }); } }); } }); } }; // Stun the correct target if (isAI) { playerStunned = true; playerStunTimer = 300; // 5 seconds at 60fps } else { aiStunned = true; aiStunTimer = 300; // 5 seconds at 60fps } // Visual effect for stunned target with shaking tween(targetPaddle, { tint: 0xFF0000 }, { duration: 100 }); _shakeTarget(); } function activatePierce(isAI) { if (isAI) { // AI version - use AI card for (var i = 0; i < aiCards.length; i++) { if (aiCards[i].cardType === 'pierce' && !aiCards[i].used && aiCards[i].cooldown <= 0 && aiCards[i].usageCount < aiCards[i].maxUsage) { aiCards[i].used = true; aiCards[i].cooldown = 300; aiCards[i].usageCount++; // Increment AI card usage counter // Track AI card usage aiLastUsedCard = 'pierce'; aiCardUsageHistory.push({ type: 'pierce', time: LK.ticks }); // Create visual effect at AI paddle to show card usage createParticles(aiPaddle.x, aiPaddle.y); break; } } } pierceActive = true; pierceTimer = 180; // 3 seconds at 60fps pierceUser = isAI ? 'ai' : 'player'; // Track who used pierce // Pierce animation with glowing effect tween(ball, { tint: 0x44FF44 }, { duration: 200 }); // Make ball semi-transparent when AI uses pierce to show it's non-collidable if (isAI) { tween(ball, { alpha: 0.5 }, { duration: 200 }); } // Create rotating energy effect function createEnergyRing() { if (pierceActive) { for (var i = 0; i < 6; i++) { var particle = game.addChild(new Particle()); var angle = i / 6 * Math.PI * 2; var radius = 50; particle.x = ball.x + Math.cos(angle) * radius; particle.y = ball.y + Math.sin(angle) * radius; particle.velocityX = Math.cos(angle) * 3; particle.velocityY = Math.sin(angle) * 3; particle.life = 15; particle.maxLife = 15; tween(particle, { tint: 0x44FF44 }, { duration: 100 }); particles.push(particle); } LK.setTimeout(createEnergyRing, 200); } } createEnergyRing(); // Create glowing aura tween(ball, { scaleX: 1.1, scaleY: 1.1 }, { duration: 300, easing: tween.easeInOut, onFinish: function onFinish() { if (pierceActive) { tween(ball, { scaleX: 1.3, scaleY: 1.3 }, { duration: 300, easing: tween.easeInOut, onFinish: function onFinish() { if (pierceActive) { activatePierce(); } } }); } } }); // Auto-disable pierce after exactly 3 seconds LK.setTimeout(function () { if (pierceActive) { pierceActive = false; pierceTimer = 0; pierceUser = null; // Reset ball to original state tween(ball, { tint: 0xFFFFFF, scaleX: 1, scaleY: 1, alpha: 1 }, { duration: 200, easing: tween.easeOut }); } }, 3000); } function activateIllusion(isAI) { if (isAI) { // AI version - use AI card for (var i = 0; i < aiCards.length; i++) { if (aiCards[i].cardType === 'illusion' && !aiCards[i].used && aiCards[i].cooldown <= 0 && aiCards[i].usageCount < aiCards[i].maxUsage) { aiCards[i].used = true; aiCards[i].cooldown = 300; aiCards[i].usageCount++; // Track AI card usage aiLastUsedCard = 'illusion'; aiCardUsageHistory.push({ type: 'illusion', time: LK.ticks }); // Create visual effect at AI paddle to show card usage createParticles(aiPaddle.x, aiPaddle.y); break; } } } illusionActive = true; illusionTimer = 300; // 5 seconds at 60fps // Clear any existing illusion balls for (var i = illusionBalls.length - 1; i >= 0; i--) { illusionBalls[i].destroy(); } illusionBalls = []; // Create 4 fake balls around the real ball for (var i = 0; i < 4; i++) { var fakeBall = game.addChild(new Ball()); var angle = i / 4 * Math.PI * 2; var radius = 80 + Math.random() * 40; fakeBall.x = ball.x + Math.cos(angle) * radius; fakeBall.y = ball.y + Math.sin(angle) * radius; // Make fake balls move at exactly the same speed as real ball fakeBall.velocityX = ball.velocityX; fakeBall.velocityY = ball.velocityY; fakeBall.speed = ball.speed; // Make fake balls same size as real ball fakeBall.scaleX = 1; fakeBall.scaleY = 1; fakeBall.alpha = 0.8; fakeBall.tint = 0x9966cc; illusionBalls.push(fakeBall); // Add floating animation to fake balls tween(fakeBall, { scaleX: 1.1, scaleY: 1.1 }, { duration: 500, easing: tween.easeInOut, onFinish: function onFinish() { if (illusionActive) { tween(fakeBall, { scaleX: 0.9, scaleY: 0.9 }, { duration: 500, easing: tween.easeInOut }); } } }); } // Add shimmer effect to real ball tween(ball, { tint: 0x9966cc, alpha: 0.9 }, { duration: 200 }); // Create magical particles around all balls function createMagicalParticles() { if (illusionActive) { // Particles around real ball for (var i = 0; i < 3; i++) { var particle = game.addChild(new Particle()); var angle = Math.random() * Math.PI * 2; var radius = 50; particle.x = ball.x + Math.cos(angle) * radius; particle.y = ball.y + Math.sin(angle) * radius; particle.velocityX = Math.cos(angle) * 2; particle.velocityY = Math.sin(angle) * 2; particle.life = 25; particle.maxLife = 25; tween(particle, { tint: 0xcc66ff }, { duration: 100 }); particles.push(particle); } // Particles around fake balls for (var j = 0; j < illusionBalls.length; j++) { var fakeBall = illusionBalls[j]; if (fakeBall && !fakeBall.destroyed) { var particle = game.addChild(new Particle()); var angle = Math.random() * Math.PI * 2; var radius = 40; particle.x = fakeBall.x + Math.cos(angle) * radius; particle.y = fakeBall.y + Math.sin(angle) * radius; particle.velocityX = Math.cos(angle) * 1.5; particle.velocityY = Math.sin(angle) * 1.5; particle.life = 20; particle.maxLife = 20; tween(particle, { tint: 0x9966cc }, { duration: 100 }); particles.push(particle); } } LK.setTimeout(createMagicalParticles, 300); } } createMagicalParticles(); } function activateSlow(isAI) { if (isAI) { // AI version - use AI card for (var i = 0; i < aiCards.length; i++) { if (aiCards[i].cardType === 'slow' && !aiCards[i].used && aiCards[i].cooldown <= 0 && aiCards[i].usageCount < aiCards[i].maxUsage) { aiCards[i].used = true; aiCards[i].cooldown = 300; aiCards[i].usageCount++; // Increment AI card usage counter // Track AI card usage aiLastUsedCard = 'slow'; aiCardUsageHistory.push({ type: 'slow', time: LK.ticks }); // Create visual effect at AI paddle to show card usage createParticles(aiPaddle.x, aiPaddle.y); break; } } } slowActive = true; slowTimer = 300; // 5 seconds at 60fps ball.speed = 6; // Slow animation with ice effect tween(ball, { tint: 0x4444FF }, { duration: 200 }); tween(ball, { scaleX: 0.8, scaleY: 0.8 }, { duration: 200, easing: tween.easeOut }); // Create ice crystal particles function createIceCrystals() { if (slowActive) { for (var i = 0; i < 8; i++) { var particle = game.addChild(new Particle()); var angle = i / 8 * Math.PI * 2; var radius = 60; particle.x = ball.x + Math.cos(angle) * radius; particle.y = ball.y + Math.sin(angle) * radius; particle.velocityX = Math.cos(angle) * 2; particle.velocityY = Math.sin(angle) * 2; particle.life = 30; particle.maxLife = 30; tween(particle, { tint: 0x88CCFF }, { duration: 150 }); particles.push(particle); } LK.setTimeout(createIceCrystals, 400); } } createIceCrystals(); // Create freezing aura that pulses function createFreezingAura() { if (slowActive) { tween(ball, { scaleX: 0.6, scaleY: 0.6 }, { duration: 500, easing: tween.easeInOut, onFinish: function onFinish() { if (slowActive) { tween(ball, { scaleX: 0.9, scaleY: 0.9 }, { duration: 500, easing: tween.easeInOut, onFinish: createFreezingAura }); } } }); } } createFreezingAura(); } function createExplosionEffect(x, y) { // Create screen shake effect var originalX = game.x; var originalY = game.y; tween(game, { x: originalX + 10, y: originalY + 10 }, { duration: 50, onFinish: function onFinish() { tween(game, { x: originalX - 10, y: originalY - 10 }, { duration: 50, onFinish: function onFinish() { tween(game, { x: originalX, y: originalY }, { duration: 50 }); } }); } }); // Create explosion particles with color variations for (var i = 0; i < 15; i++) { var particle = game.addChild(new Particle()); particle.x = x + (Math.random() - 0.5) * 120; particle.y = y + (Math.random() - 0.5) * 120; particle.velocityX = (Math.random() - 0.5) * 15; particle.velocityY = (Math.random() - 0.5) * 15; particle.life = 40; particle.maxLife = 40; // Add color tinting with tween var colors = [0xff4444, 0xffaa44, 0xffff44, 0xff8844]; var randomColor = colors[Math.floor(Math.random() * colors.length)]; tween(particle, { tint: randomColor }, { duration: 200 }); particles.push(particle); } } function checkPaddleCollision(paddle, ball) { var paddleLeft = paddle.x - 100; var paddleRight = paddle.x + 100; var paddleTop = paddle.y - 20; var paddleBottom = paddle.y + 20; var ballLeft = ball.x - 30; var ballRight = ball.x + 30; var ballTop = ball.y - 30; var ballBottom = ball.y + 30; return ballRight > paddleLeft && ballLeft < paddleRight && ballBottom > paddleTop && ballTop < paddleBottom; } game.down = function (x, y, obj) { // Don't handle paddle movement during tutorial if (tutorialOverlay.visible) { return; } touchX = x; if (!playerStunned) { playerPaddle.moveTowards(x); } }; game.move = function (x, y, obj) { // Don't handle paddle movement during tutorial if (tutorialOverlay.visible) { return; } touchX = x; if (!playerStunned) { playerPaddle.moveTowards(x); } // Card hover effects removed }; game.update = function () { // Don't run game logic during tutorial if (tutorialOverlay.visible) { return; } // Handle power-up timers if (speedBoostActive) { speedBoostTimer--; if (speedBoostTimer <= 0) { speedBoostActive = false; ball.speed = 12; tween(ball, { tint: 0xFFFFFF }, { duration: 200 }); tween(ball, { scaleX: 1, scaleY: 1 }, { duration: 200, easing: tween.easeOut }); } } if (slowActive) { slowTimer--; if (slowTimer <= 0) { slowActive = false; ball.speed = 12; tween(ball, { tint: 0xFFFFFF }, { duration: 200 }); tween(ball, { scaleX: 1, scaleY: 1 }, { duration: 200, easing: tween.easeOut }); } } if (illusionActive) { illusionTimer--; if (illusionTimer <= 0) { illusionActive = false; // Reset real ball appearance tween(ball, { tint: 0xFFFFFF, alpha: 1 }, { duration: 300 }); // Remove all fake balls with fade effect for (var i = 0; i < illusionBalls.length; i++) { var fakeBall = illusionBalls[i]; if (fakeBall && !fakeBall.destroyed) { tween(fakeBall, { alpha: 0, scaleX: 0.5, scaleY: 0.5 }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { if (fakeBall && !fakeBall.destroyed) { fakeBall.destroy(); } } }); } } illusionBalls = []; } } if (pierceActive) { pierceTimer--; if (pierceTimer <= 0) { pierceActive = false; pierceUser = null; // Reset pierce user tween(ball, { tint: 0xFFFFFF, alpha: 1 }, { duration: 200 }); tween(ball, { scaleX: 1, scaleY: 1 }, { duration: 200, easing: tween.easeOut }); } } if (aiStunned) { aiStunTimer--; if (aiStunTimer <= 0) { aiStunned = false; tween(aiPaddle, { tint: 0xFFFFFF }, { duration: 200 }); } } if (playerStunned) { playerStunTimer--; if (playerStunTimer <= 0) { playerStunned = false; tween(playerPaddle, { tint: 0xFFFFFF }, { duration: 200 }); } } // Update fake balls during illusion if (illusionActive) { for (var i = illusionBalls.length - 1; i >= 0; i--) { var fakeBall = illusionBalls[i]; if (fakeBall && !fakeBall.destroyed) { // Apply speed boost effect to fake balls too if (speedBoostActive) { fakeBall.speed = 24; } else if (slowActive) { fakeBall.speed = 6; } else { fakeBall.speed = 12; } // Update fake ball position fakeBall.x += fakeBall.velocityX; fakeBall.y += fakeBall.velocityY; // Bounce fake balls off walls if (fakeBall.x <= 30 || fakeBall.x >= 2018) { fakeBall.velocityX = -fakeBall.velocityX; } // Remove fake balls that go off screen if (fakeBall.y < -100 || fakeBall.y > 2832) { fakeBall.destroy(); illusionBalls.splice(i, 1); } } else { illusionBalls.splice(i, 1); } } } // AI paddle follows ball with some delay (unless stunned) if (!aiStunned) { var targetBall = ball; // Default to real ball // If illusion is active, AI gets confused and targets random ball if (illusionActive && illusionBalls.length > 0) { // AI picks a random ball to follow (including real ball) var allBalls = [ball]; for (var i = 0; i < illusionBalls.length; i++) { if (illusionBalls[i] && !illusionBalls[i].destroyed) { allBalls.push(illusionBalls[i]); } } // AI randomly switches target every 30 frames during illusion if (LK.ticks % 30 === 0) { targetBall = allBalls[Math.floor(Math.random() * allBalls.length)]; } else if (game.aiTargetBall && !game.aiTargetBall.destroyed) { targetBall = game.aiTargetBall; } game.aiTargetBall = targetBall; } var targetX = targetBall.x + targetBall.velocityX * 10; if (targetX < 100) targetX = 100; if (targetX > 1948) targetX = 1948; aiPaddle.moveTowards(targetX); } // AI power-up usage logic with strategic decision making aiPowerUpTimer++; if (aiPowerUpTimer >= aiPowerUpCooldown) { // Use the ball AI is currently tracking for strategic decisions var currentTargetBall = ball; if (illusionActive && game.aiTargetBall && !game.aiTargetBall.destroyed) { currentTargetBall = game.aiTargetBall; } // Calculate strategic variables based on AI's current target var ballDistanceToAI = Math.abs(currentTargetBall.y - aiPaddle.y); var ballDistanceToPlayer = Math.abs(currentTargetBall.y - playerPaddle.y); var ballMovingTowardAI = currentTargetBall.velocityY < 0; var ballMovingTowardPlayer = currentTargetBall.velocityY > 0; var aiScore_playerScore_diff = aiScore - playerScore; var ballSpeed = Math.sqrt(currentTargetBall.velocityX * currentTargetBall.velocityX + currentTargetBall.velocityY * currentTargetBall.velocityY); var timeToReachAI = ballDistanceToAI / Math.abs(currentTargetBall.velocityY); var timeToReachPlayer = ballDistanceToPlayer / Math.abs(currentTargetBall.velocityY); var paddleCanReach = Math.abs(aiPaddle.x - (currentTargetBall.x + currentTargetBall.velocityX * timeToReachAI)) < 150; var ballNearAIGoal = currentTargetBall.y < 542 && ballMovingTowardAI; var ballNearPlayerGoal = currentTargetBall.y > 2190 && ballMovingTowardPlayer; var needsToScore = aiScore_playerScore_diff < 0; var gameTimeRunningOut = gameTime < 30; // Priority 1: Critical defense - ball about to hit AI goal if (ballNearAIGoal && ballMovingTowardAI && ballDistanceToAI < 550) { // Use slow to prevent goal when ball is about to hit AI castle for (var i = 0; i < aiCards.length; i++) { if (aiCards[i].cardType === 'slow' && !aiCards[i].used && aiCards[i].cooldown <= 0 && aiCards[i].usageCount < aiCards[i].maxUsage) { activateSlow(true); aiPowerUpTimer = 0; aiPowerUpCooldown = 180; // Quick cooldown for critical defense return; } } // If no slow available, use explosion as backup for (var i = 0; i < aiCards.length; i++) { if (aiCards[i].cardType === 'explosion' && !aiCards[i].used && aiCards[i].cooldown <= 0 && aiCards[i].usageCount < aiCards[i].maxUsage) { activateExplosion(true); aiPowerUpTimer = 0; aiPowerUpCooldown = 180; return; } } } // Priority 2: Aggressive scoring when AI needs points and ball is approaching AI if ((needsToScore || gameTimeRunningOut) && ballMovingTowardAI && ballDistanceToAI < 600 && ballDistanceToAI > 200) { // Use pierce to score when ball is approaching and AI needs points for (var i = 0; i < aiCards.length; i++) { if (aiCards[i].cardType === 'pierce' && !aiCards[i].used && aiCards[i].cooldown <= 0 && aiCards[i].usageCount < aiCards[i].maxUsage) { activatePierce(true); aiPowerUpTimer = 0; aiPowerUpCooldown = 250; return; } } } // Priority 3: Speed boost when AI can't reach ball in time if (ballMovingTowardAI && ballDistanceToAI < 500 && !paddleCanReach && timeToReachAI < 45) { // Use speed boost to make ball move faster so AI can potentially reach it for (var i = 0; i < aiCards.length; i++) { if (aiCards[i].cardType === 'speed' && !aiCards[i].used && aiCards[i].cooldown <= 0 && aiCards[i].usageCount < aiCards[i].maxUsage) { activateSpeedBoost(true); aiPowerUpTimer = 0; aiPowerUpCooldown = 300; return; } } } // Priority 4: Explosion when ball is approaching AI (general defense) if (ballMovingTowardAI && ballDistanceToAI < 400 && ballDistanceToAI > 100) { // Use explosion to stun and disrupt when ball is approaching for (var i = 0; i < aiCards.length; i++) { if (aiCards[i].cardType === 'explosion' && !aiCards[i].used && aiCards[i].cooldown <= 0) { activateExplosion(true); aiPowerUpTimer = 0; aiPowerUpCooldown = 320; return; } } } // Priority 5: Opportunistic offensive moves if (ballMovingTowardPlayer && needsToScore && Math.random() < 0.6) { // Use speed when ball is going toward player and AI needs to score for (var i = 0; i < aiCards.length; i++) { if (aiCards[i].cardType === 'speed' && !aiCards[i].used && aiCards[i].cooldown <= 0) { activateSpeedBoost(true); aiPowerUpTimer = 0; aiPowerUpCooldown = 400; return; } } } // Priority 6: Strategic slow usage if (ballMovingTowardPlayer && ballSpeed > 10 && ballDistanceToPlayer < 300 && Math.random() < 0.4) { // Use slow to make it harder for player to return the ball for (var i = 0; i < aiCards.length; i++) { if (aiCards[i].cardType === 'slow' && !aiCards[i].used && aiCards[i].cooldown <= 0) { activateSlow(true); aiPowerUpTimer = 0; aiPowerUpCooldown = 350; return; } } } // Priority 7: Illusion when ball is moving toward player and AI wants to confuse if (ballMovingTowardPlayer && ballDistanceToPlayer < 800 && Math.random() < 0.3) { // Use illusion to confuse player when ball is approaching them for (var i = 0; i < aiCards.length; i++) { if (aiCards[i].cardType === 'illusion' && !aiCards[i].used && aiCards[i].cooldown <= 0 && aiCards[i].usageCount < aiCards[i].maxUsage) { activateIllusion(true); aiPowerUpTimer = 0; aiPowerUpCooldown = 400; return; } } } // Priority 8: Random usage with low probability to add unpredictability if (Math.random() < 0.1) { var availableCards = []; for (var i = 0; i < aiCards.length; i++) { if (!aiCards[i].used && aiCards[i].cooldown <= 0 && aiCards[i].usageCount < aiCards[i].maxUsage) { availableCards.push(aiCards[i].cardType); } } if (availableCards.length > 0) { var randomCard = availableCards[Math.floor(Math.random() * availableCards.length)]; if (randomCard === 'speed') { activateSpeedBoost(true); } else if (randomCard === 'explosion') { activateExplosion(true); } else if (randomCard === 'pierce') { activatePierce(true); } else if (randomCard === 'slow') { activateSlow(true); } else if (randomCard === 'illusion') { activateIllusion(true); } aiPowerUpTimer = 0; aiPowerUpCooldown = 500 + Math.random() * 200; } } } // Check paddle collisions if (checkPaddleCollision(playerPaddle, ball) && !(pierceActive && pierceUser === 'ai')) { if (ball.velocityY > 0) { ball.velocityY = -ball.velocityY; var hitOffset = (ball.x - playerPaddle.x) / 100; ball.velocityX += hitOffset * 2; createParticles(ball.x, ball.y); LK.getSound('paddleHit').play(); } } if (checkPaddleCollision(aiPaddle, ball) && !(pierceActive && pierceUser === 'player')) { if (ball.velocityY < 0) { ball.velocityY = -ball.velocityY; var hitOffset = (ball.x - aiPaddle.x) / 100; ball.velocityX += hitOffset * 2; createParticles(ball.x, ball.y); LK.getSound('paddleHit').play(); } } // Check goal scoring if (ball.y < 90) { playerScore++; playerScoreText.setText(playerScore.toString()); LK.setScore(playerScore); ball.reset(); LK.getSound('goal').play(); } if (ball.y > 2642) { aiScore++; aiScoreText.setText(aiScore.toString()); ball.reset(); LK.getSound('goal').play(); } // Check collision with castle areas to create explosion particles if (ball.y <= 422 && ball.y >= 90 && ball.x >= 200 && ball.x <= 1848) { // Ball hit AI castle/houses area createExplosionEffect(ball.x, ball.y); } if (ball.y >= 2310 && ball.y <= 2642 && ball.x >= 200 && ball.x <= 1848) { // Ball hit player castle/houses area createExplosionEffect(ball.x, ball.y); } // Limit ball speed var maxSpeed = 12; var currentSpeed = Math.sqrt(ball.velocityX * ball.velocityX + ball.velocityY * ball.velocityY); if (currentSpeed > maxSpeed) { ball.velocityX = ball.velocityX / currentSpeed * maxSpeed; ball.velocityY = ball.velocityY / currentSpeed * maxSpeed; } };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var BackgroundCloud = Container.expand(function () {
var self = Container.call(this);
var cloud = self.attachAsset('cloud', {
anchorX: 0.5,
anchorY: 0.5
});
cloud.alpha = 0.7;
self.speed = 0.3 + Math.random() * 0.5;
// Floating animation
self.update = function () {
self.x += self.speed;
if (self.x > 2200) {
self.x = -150;
}
var time = LK.ticks * 0.01;
self.y += Math.sin(time) * 0.1;
};
return self;
});
var BackgroundFlower = Container.expand(function () {
var self = Container.call(this);
var flower = self.attachAsset('flower', {
anchorX: 0.5,
anchorY: 0.5
});
flower.alpha = 0.9;
// Gentle bobbing
self.update = function () {
var time = LK.ticks * 0.025;
flower.scaleX = 1 + Math.sin(time) * 0.1;
flower.scaleY = 1 + Math.sin(time) * 0.1;
};
return self;
});
var BackgroundGrass = Container.expand(function () {
var self = Container.call(this);
var grass = self.attachAsset('grass', {
anchorX: 0.5,
anchorY: 0.5
});
grass.alpha = 0.8;
// Gentle swaying
self.update = function () {
var time = LK.ticks * 0.03;
grass.rotation = Math.sin(time) * 0.05;
};
return self;
});
var BackgroundMountain = Container.expand(function () {
var self = Container.call(this);
var mountain = self.attachAsset('mountain', {
anchorX: 0.5,
anchorY: 1
});
mountain.alpha = 0.3;
mountain.tint = 0x4682B4;
return self;
});
var BackgroundTree = Container.expand(function () {
var self = Container.call(this);
var trunk = self.attachAsset('tree', {
anchorX: 0.5,
anchorY: 1
});
var leaves = self.attachAsset('treeLeaves', {
anchorX: 0.5,
anchorY: 1
});
leaves.y = -40;
// Add subtle swaying animation
self.update = function () {
var time = LK.ticks * 0.02;
leaves.rotation = Math.sin(time) * 0.1;
trunk.rotation = Math.sin(time) * 0.05;
};
return self;
});
var Ball = Container.expand(function () {
var self = Container.call(this);
var ballGraphics = self.attachAsset('ball', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityX = 0;
self.velocityY = 0;
self.speed = 12;
self.reset = function () {
self.x = 1024;
self.y = 1366;
var angle = (Math.random() > 0.5 ? 1 : -1) * (Math.PI / 6 + Math.random() * Math.PI / 3);
self.velocityX = Math.sin(angle) * self.speed;
// Ball only goes towards player (positive Y) or AI (negative Y), not random
self.velocityY = Math.cos(angle) * self.speed * (Math.random() > 0.5 ? 1 : -1);
};
self.update = function () {
self.x += self.velocityX;
self.y += self.velocityY;
// Bounce off left and right walls
if (self.x <= 30 || self.x >= 2018) {
self.velocityX = -self.velocityX;
}
};
return self;
});
var Card = Container.expand(function (cardType) {
var self = Container.call(this);
var cardGraphics = self.attachAsset('card', {
anchorX: 0.5,
anchorY: 0.5
});
self.cardType = cardType;
self.used = false;
self.cooldown = 0;
self.usageCount = 0; // Track how many times this card has been used
self.maxUsage = 2; // Maximum number of times this card can be used
var iconAsset = '';
var emojiText = '';
switch (cardType) {
case 'speed':
iconAsset = 'speedBoostIcon';
emojiText = '⚡';
break;
case 'explosion':
iconAsset = 'explosionIcon';
emojiText = '💥';
break;
case 'pierce':
iconAsset = 'pierceIcon';
emojiText = '🔥';
break;
case 'slow':
iconAsset = 'slowIcon';
emojiText = '❄️';
break;
case 'illusion':
iconAsset = 'illusionIcon';
emojiText = '🎭';
break;
}
var icon = self.attachAsset(iconAsset, {
anchorX: 0.5,
anchorY: 0.5
});
var emoji = new Text2(emojiText, {
size: 40,
fill: '#FFFFFF'
});
emoji.anchor.set(0.5, 0.5);
self.addChild(emoji);
self.down = function (x, y, obj) {
if (!self.used && self.cooldown <= 0 && self.usageCount < self.maxUsage) {
self.used = true;
self.cooldown = 300; // 5 seconds at 60fps
self.usageCount++; // Increment usage counter
// Play card selection sound
LK.getSound('cardSelect').play();
// Card activation animation
tween(self, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
scaleX: 1,
scaleY: 1
}, {
duration: 150,
easing: tween.easeOut
});
}
});
// Glowing effect
tween(cardGraphics, {
tint: 0xFFFFFF
}, {
duration: 100,
onFinish: function onFinish() {
tween(cardGraphics, {
alpha: 0.5,
tint: 0x666666
}, {
duration: 200
});
}
});
tween(icon, {
alpha: 0.5,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 200,
onFinish: function onFinish() {
tween(icon, {
scaleX: 1,
scaleY: 1
}, {
duration: 200
});
}
});
// Floating particles from card
for (var i = 0; i < 3; i++) {
var particle = game.addChild(new Particle());
particle.x = self.x + (Math.random() - 0.5) * 60;
particle.y = self.y + (Math.random() - 0.5) * 60;
particle.velocityX = (Math.random() - 0.5) * 6;
particle.velocityY = -Math.random() * 8 - 2;
particle.life = 40;
particle.maxLife = 40;
particles.push(particle);
}
switch (self.cardType) {
case 'speed':
activateSpeedBoost();
break;
case 'explosion':
activateExplosion();
break;
case 'pierce':
activatePierce();
break;
case 'slow':
activateSlow();
break;
case 'illusion':
activateIllusion();
break;
}
// Check if card has reached usage limit - trigger destruction immediately
if (self.usageCount >= self.maxUsage) {
self.hasExploded = true;
// Create explosion particles around the card
for (var i = 0; i < 12; i++) {
var particle = game.addChild(new Particle());
particle.x = self.x + (Math.random() - 0.5) * 100;
particle.y = self.y + (Math.random() - 0.5) * 120;
particle.velocityX = (Math.random() - 0.5) * 15;
particle.velocityY = (Math.random() - 0.5) * 15;
particle.life = 60;
particle.maxLife = 60;
// Random bright colors for explosion effect
var colors = [0xff4444, 0xffaa44, 0xffff44, 0xff8844, 0xaa44ff];
var randomColor = colors[Math.floor(Math.random() * colors.length)];
tween(particle, {
tint: randomColor
}, {
duration: 200
});
particles.push(particle);
}
// Create card fragments that fly out
for (var i = 0; i < 6; i++) {
var fragment = game.addChild(new Container());
var fragmentGraphics = fragment.attachAsset('card', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.3,
scaleY: 0.3
});
fragment.x = self.x;
fragment.y = self.y;
var angle = i / 6 * Math.PI * 2;
var speed = 8 + Math.random() * 6;
var fragmentVelX = Math.cos(angle) * speed;
var fragmentVelY = Math.sin(angle) * speed;
// Fragment animation - fly out and fade
tween(fragment, {
x: fragment.x + fragmentVelX * 20,
y: fragment.y + fragmentVelY * 20,
rotation: (Math.random() - 0.5) * 4,
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
}, {
duration: 1000 + Math.random() * 500,
easing: tween.easeOut,
onFinish: function onFinish() {
fragment.destroy();
}
});
}
// Card shake and explosion effect
var originalX = self.x;
var originalY = self.y;
tween(self, {
x: originalX + 15,
y: originalY + 15,
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 100,
onFinish: function onFinish() {
tween(self, {
x: originalX - 15,
y: originalY - 15,
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 100,
onFinish: function onFinish() {
tween(self, {
x: originalX,
y: originalY,
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 100
});
}
});
}
});
// Card is permanently disabled - make it visually distinct
tween(cardGraphics, {
alpha: 0.3,
tint: 0x666666
}, {
duration: 300,
easing: tween.easeOut
});
tween(icon, {
alpha: 0.3
}, {
duration: 300,
easing: tween.easeOut
});
}
}
};
self.move = function (x, y, obj) {
// Hover effect removed
};
self.up = function (x, y, obj) {
if (!self.used && self.cooldown <= 0) {
// Card unhover animation - return to normal size
tween(self, {
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 100,
easing: tween.easeOut
});
}
};
self.update = function () {
if (self.cooldown > 0) {
self.cooldown--;
if (self.cooldown <= 0 && self.usageCount < self.maxUsage) {
self.used = false;
// Card reactivation animation
tween(cardGraphics, {
alpha: 1,
tint: 0xFFFFFF
}, {
duration: 300,
easing: tween.easeOut
});
tween(icon, {
alpha: 1
}, {
duration: 300,
easing: tween.easeOut
});
// Sparkle effect on reactivation
for (var i = 0; i < 5; i++) {
var particle = game.addChild(new Particle());
particle.x = self.x + (Math.random() - 0.5) * 80;
particle.y = self.y + (Math.random() - 0.5) * 100;
particle.velocityX = (Math.random() - 0.5) * 4;
particle.velocityY = (Math.random() - 0.5) * 4;
particle.life = 20;
particle.maxLife = 20;
tween(particle, {
tint: 0xFFFFFF
}, {
duration: 100
});
particles.push(particle);
}
} else if (self.cooldown <= 0 && self.usageCount >= self.maxUsage) {
// Card destruction effect - only trigger once
if (!self.hasExploded) {
self.hasExploded = true;
// Create explosion particles around the card
for (var i = 0; i < 12; i++) {
var particle = game.addChild(new Particle());
particle.x = self.x + (Math.random() - 0.5) * 100;
particle.y = self.y + (Math.random() - 0.5) * 120;
particle.velocityX = (Math.random() - 0.5) * 15;
particle.velocityY = (Math.random() - 0.5) * 15;
particle.life = 60;
particle.maxLife = 60;
// Random bright colors for explosion effect
var colors = [0xff4444, 0xffaa44, 0xffff44, 0xff8844, 0xaa44ff];
var randomColor = colors[Math.floor(Math.random() * colors.length)];
tween(particle, {
tint: randomColor
}, {
duration: 200
});
particles.push(particle);
}
// Create card fragments that fly out
for (var i = 0; i < 6; i++) {
var fragment = game.addChild(new Container());
var fragmentGraphics = fragment.attachAsset('card', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.3,
scaleY: 0.3
});
fragment.x = self.x;
fragment.y = self.y;
var angle = i / 6 * Math.PI * 2;
var speed = 8 + Math.random() * 6;
var fragmentVelX = Math.cos(angle) * speed;
var fragmentVelY = Math.sin(angle) * speed;
// Fragment animation - fly out and fade
tween(fragment, {
x: fragment.x + fragmentVelX * 20,
y: fragment.y + fragmentVelY * 20,
rotation: (Math.random() - 0.5) * 4,
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
}, {
duration: 1000 + Math.random() * 500,
easing: tween.easeOut,
onFinish: function onFinish() {
fragment.destroy();
}
});
}
// Card shake and explosion effect
var originalX = self.x;
var originalY = self.y;
tween(self, {
x: originalX + 15,
y: originalY + 15,
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 100,
onFinish: function onFinish() {
tween(self, {
x: originalX - 15,
y: originalY - 15,
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 100,
onFinish: function onFinish() {
tween(self, {
x: originalX,
y: originalY,
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 100
});
}
});
}
});
}
// Card is permanently disabled - make it visually distinct
tween(cardGraphics, {
alpha: 0.3,
tint: 0x666666
}, {
duration: 300,
easing: tween.easeOut
});
tween(icon, {
alpha: 0.3
}, {
duration: 300,
easing: tween.easeOut
});
}
} else if (!self.used) {
// Idle floating animation - maintain original Y position with small float
var time = LK.ticks * 0.1;
var originalY = self.y;
if (self.originalY === undefined) {
self.originalY = self.y;
}
self.y = self.originalY + Math.sin(time + self.cardType.length) * 5;
// Subtle glow effect
if (LK.ticks % 180 === 0) {
tween(cardGraphics, {
tint: 0xFFFFFF
}, {
duration: 200,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(cardGraphics, {
tint: 0x4a90e2
}, {
duration: 200,
easing: tween.easeInOut
});
}
});
}
}
};
return self;
});
var Castle = Container.expand(function () {
var self = Container.call(this);
var castleGraphics = self.attachAsset('castle', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
var House = Container.expand(function () {
var self = Container.call(this);
var houseGraphics = self.attachAsset('house', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
var Paddle = Container.expand(function () {
var self = Container.call(this);
var paddleGraphics = self.attachAsset('paddle', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 8;
self.targetX = self.x;
self.moveTowards = function (targetX) {
self.targetX = targetX;
if (self.targetX < 100) self.targetX = 100;
if (self.targetX > 1948) self.targetX = 1948;
};
self.update = function () {
if (Math.abs(self.x - self.targetX) > 2) {
if (self.x < self.targetX) {
self.x += self.speed;
} else {
self.x -= self.speed;
}
}
};
return self;
});
var Particle = Container.expand(function () {
var self = Container.call(this);
var particleGraphics = self.attachAsset('particle', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityX = (Math.random() - 0.5) * 8;
self.velocityY = (Math.random() - 0.5) * 8;
self.life = 30;
self.maxLife = 30;
self.update = function () {
self.x += self.velocityX;
self.y += self.velocityY;
self.life--;
var alpha = self.life / self.maxLife;
particleGraphics.alpha = alpha;
if (self.life <= 0) {
self.destroy();
particles.splice(particles.indexOf(self), 1);
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x228B22
});
/****
* Game Code
****/
// Simple background - removed complex gradient overlay
var gameTime = 90;
var playerScore = 0;
var aiScore = 0;
var particles = [];
var cards = [];
var speedBoostActive = false;
var speedBoostTimer = 0;
var explosionActive = false;
var pierceActive = false;
var pierceTimer = 0;
var pierceUser = null; // Track who used pierce power-up
var slowActive = false;
var slowTimer = 0;
var illusionActive = false;
var illusionTimer = 0;
var illusionBalls = [];
var aiStunned = false;
var aiStunTimer = 0;
var playerStunned = false;
var playerStunTimer = 0;
// Create UI elements
var timerText = new Text2('90', {
size: 80,
fill: 0xFFFFFF
});
timerText.anchor.set(0.5, 0);
LK.gui.top.addChild(timerText);
var playerScoreText = new Text2('0', {
size: 60,
fill: 0x4A90E2
});
playerScoreText.anchor.set(0, 1);
LK.gui.bottomLeft.addChild(playerScoreText);
var aiScoreText = new Text2('0', {
size: 60,
fill: 0xE24A4A
});
aiScoreText.anchor.set(0, 0);
LK.gui.topLeft.addChild(aiScoreText);
// Create tutorial overlay
var tutorialOverlay = game.addChild(new Container());
tutorialOverlay.x = 0;
tutorialOverlay.y = 0;
// Create semi-transparent background
var tutorialBg = tutorialOverlay.attachAsset('card', {
anchorX: 0,
anchorY: 0,
scaleX: 25.6,
scaleY: 27.32,
alpha: 0.8
});
tutorialBg.tint = 0x000000;
// Create tutorial title
var tutorialTitle = new Text2('POWER-UPS TUTORIAL', {
size: 80,
fill: '#FFFFFF'
});
tutorialTitle.anchor.set(0.5, 0.5);
tutorialTitle.x = 1024;
tutorialTitle.y = 400;
tutorialOverlay.addChild(tutorialTitle);
// Create game objective text
var objectiveText = new Text2('GAME OBJECTIVE: Score more goals than your opponent in 90 seconds!', {
size: 55,
fill: '#FFD700'
});
objectiveText.anchor.set(0.5, 0.5);
objectiveText.x = 1024;
objectiveText.y = 550;
tutorialOverlay.addChild(objectiveText);
// Create power-up instruction texts
var instructions = ['⚡ SPEED BOOST: Makes ball move faster for 5 seconds', '💥 EXPLOSION: Ball explodes and stuns opponent for 5 seconds', '🔥 PIERCE: Ball goes through opponent paddle for 3 seconds', '❄️ SLOW: Makes ball move slower for 5 seconds'];
var instructionTexts = [];
for (var i = 0; i < instructions.length; i++) {
var instructionText = new Text2(instructions[i], {
size: 50,
fill: '#FFFFFF'
});
instructionText.anchor.set(0.5, 0.5);
instructionText.x = 1024;
instructionText.y = 650 + i * 120;
tutorialOverlay.addChild(instructionText);
instructionTexts.push(instructionText);
}
// Create start button
var startButton = tutorialOverlay.attachAsset('card', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 3,
scaleY: 1.5
});
startButton.x = 1024;
startButton.y = 1400;
startButton.tint = 0x4A90E2;
var startButtonText = new Text2('TAP TO START', {
size: 60,
fill: '#FFFFFF'
});
startButtonText.anchor.set(0.5, 0.5);
startButtonText.x = 1024;
startButtonText.y = 1400;
tutorialOverlay.addChild(startButtonText);
// Add tutorial click handler
tutorialOverlay.down = function (x, y, obj) {
// Hide tutorial with fade animation
tween(tutorialOverlay, {
alpha: 0
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
tutorialOverlay.visible = false;
}
});
};
// Create game objects
var playerPaddle = game.addChild(new Paddle());
playerPaddle.x = 1024;
playerPaddle.y = 2300;
var aiPaddle = game.addChild(new Paddle());
aiPaddle.x = 1024;
aiPaddle.y = 432;
var playerCastle = game.addChild(new Castle());
playerCastle.x = 1024;
playerCastle.y = 2542;
// Add houses around player castle
// Left side houses in a row
var playerHouse1L = game.addChild(new House());
playerHouse1L.x = 350;
playerHouse1L.y = 2500;
var playerHouse2L = game.addChild(new House());
playerHouse2L.x = 500;
playerHouse2L.y = 2500;
var playerHouse3L = game.addChild(new House());
playerHouse3L.x = 650;
playerHouse3L.y = 2500;
// Right side houses in a row
var playerHouse1R = game.addChild(new House());
playerHouse1R.x = 1398;
playerHouse1R.y = 2500;
var playerHouse2R = game.addChild(new House());
playerHouse2R.x = 1548;
playerHouse2R.y = 2500;
var playerHouse3R = game.addChild(new House());
playerHouse3R.x = 1698;
playerHouse3R.y = 2500;
var aiCastle = game.addChild(new Castle());
aiCastle.x = 1024;
aiCastle.y = 190;
// Add houses around AI castle
// Left side houses in a row
var aiHouse1L = game.addChild(new House());
aiHouse1L.x = 350;
aiHouse1L.y = 232;
var aiHouse2L = game.addChild(new House());
aiHouse2L.x = 500;
aiHouse2L.y = 232;
var aiHouse3L = game.addChild(new House());
aiHouse3L.x = 650;
aiHouse3L.y = 232;
// Right side houses in a row
var aiHouse1R = game.addChild(new House());
aiHouse1R.x = 1398;
aiHouse1R.y = 232;
var aiHouse2R = game.addChild(new House());
aiHouse2R.x = 1548;
aiHouse2R.y = 232;
var aiHouse3R = game.addChild(new House());
aiHouse3R.x = 1698;
aiHouse3R.y = 232;
// Clean green background - no decorative elements
var ball = game.addChild(new Ball());
ball.reset();
// Create player cards stacked vertically on left side
var cardTypes = ['speed', 'explosion', 'pierce', 'slow', 'illusion'];
var cardX = 150; // Left side position
var cardStartY = 1600; // Starting Y position (moved up for 5 cards)
var cardSpacing = 160; // Space between cards (reduced for 5 cards)
for (var i = 0; i < 5; i++) {
var card = game.addChild(new Card(cardTypes[i]));
card.x = cardX;
card.y = cardStartY + i * cardSpacing;
card.scaleX = 0.8;
card.scaleY = 0.8;
cards.push(card);
}
// Create AI cards stacked vertically on right side - hidden from player
var aiCards = [];
var aiCardX = 1898; // Right side position
var aiCardStartY = 800; // Starting Y position for AI
for (var i = 0; i < 5; i++) {
var aiCard = game.addChild(new Card(cardTypes[i]));
aiCard.x = aiCardX;
aiCard.y = aiCardStartY + i * cardSpacing;
// Hide AI cards from player
aiCard.visible = false;
// Disable AI card interaction
aiCard.down = function () {}; // Override down function to prevent interaction
aiCards.push(aiCard);
}
// AI power-up usage logic with enhanced tracking
var aiPowerUpTimer = 0;
var aiPowerUpCooldown = 300; // 5 seconds between AI power-up usage
var aiCardUsageHistory = [];
var aiLastUsedCard = null;
var aiPreferredCards = ['explosion', 'slow', 'speed', 'pierce']; // AI preference order
function destroyBuildings() {
// Determine which side lost and which buildings to destroy
var losingBuildings = [];
var winningCastle = null;
var winningHouses = [];
if (playerScore > aiScore) {
// Player won, destroy AI buildings
losingBuildings = [aiCastle, aiHouse1L, aiHouse2L, aiHouse3L, aiHouse1R, aiHouse2R, aiHouse3R];
winningCastle = playerCastle;
winningHouses = [playerHouse1L, playerHouse2L, playerHouse3L, playerHouse1R, playerHouse2R, playerHouse3R];
} else {
// AI won, destroy player buildings
losingBuildings = [playerCastle, playerHouse1L, playerHouse2L, playerHouse3L, playerHouse1R, playerHouse2R, playerHouse3R];
winningCastle = aiCastle;
winningHouses = [aiHouse1L, aiHouse2L, aiHouse3L, aiHouse1R, aiHouse2R, aiHouse3R];
}
// Apply blue tint to winning castle and houses
if (winningCastle) {
tween(winningCastle, {
tint: 0x4A90E2
}, {
duration: 500,
easing: tween.easeOut
});
}
for (var j = 0; j < winningHouses.length; j++) {
tween(winningHouses[j], {
tint: 0x4A90E2
}, {
duration: 500,
easing: tween.easeOut
});
}
// Destroy losing buildings with staggered timing
for (var i = 0; i < losingBuildings.length; i++) {
var building = losingBuildings[i];
var delay = i * 100; // 100ms delay between each building
LK.setTimeout(function (currentBuilding) {
return function () {
// Create explosion effect at building location
createExplosionEffect(currentBuilding.x, currentBuilding.y);
// Animate building destruction
tween(currentBuilding, {
alpha: 0,
scaleX: 0.3,
scaleY: 0.3,
rotation: Math.random() * 0.5 - 0.25
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
currentBuilding.visible = false;
}
});
};
}(building), delay);
}
}
var gameTimer = LK.setInterval(function () {
gameTime--;
timerText.setText(gameTime.toString());
if (gameTime <= 0) {
LK.clearInterval(gameTimer);
// Start destruction animation before showing game over
destroyBuildings();
// Show game over after destruction animation completes
LK.setTimeout(function () {
if (playerScore > aiScore) {
LK.showYouWin();
} else {
LK.showGameOver();
}
}, 2000); // Wait 2 seconds for destruction animation to complete
}
}, 1000);
var touchX = 1024;
function createParticles(x, y) {
for (var i = 0; i < 8; i++) {
var particle = game.addChild(new Particle());
particle.x = x;
particle.y = y;
particles.push(particle);
}
}
function activateSpeedBoost(isAI) {
if (isAI) {
// AI version - use AI card
for (var i = 0; i < aiCards.length; i++) {
if (aiCards[i].cardType === 'speed' && !aiCards[i].used && aiCards[i].cooldown <= 0 && aiCards[i].usageCount < aiCards[i].maxUsage) {
aiCards[i].used = true;
aiCards[i].cooldown = 300;
aiCards[i].usageCount++; // Increment AI card usage counter
// Track AI card usage
aiLastUsedCard = 'speed';
aiCardUsageHistory.push({
type: 'speed',
time: LK.ticks
});
// Create visual effect at AI paddle to show card usage
createParticles(aiPaddle.x, aiPaddle.y);
break;
}
}
}
speedBoostActive = true;
speedBoostTimer = 300; // 5 seconds at 60fps
ball.speed = 24; // Increased from 18 to 24 for more noticeable effect
// Play speed boost sound
LK.getSound('speedSound').play();
// Speed boost animation with pulsing glow
tween(ball, {
tint: 0xFFFF00
}, {
duration: 200
});
tween(ball, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 200,
easing: tween.easeOut
});
// Create pulsing effect
function createPulse() {
if (speedBoostActive) {
tween(ball, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 300,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (speedBoostActive) {
tween(ball, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 300,
easing: tween.easeInOut,
onFinish: createPulse
});
}
}
});
}
}
createPulse();
// Create lightning particles around ball
for (var i = 0; i < 5; i++) {
var particle = game.addChild(new Particle());
particle.x = ball.x + (Math.random() - 0.5) * 80;
particle.y = ball.y + (Math.random() - 0.5) * 80;
particle.velocityX = (Math.random() - 0.5) * 12;
particle.velocityY = (Math.random() - 0.5) * 12;
particle.life = 20;
particle.maxLife = 20;
tween(particle, {
tint: 0xFFFF00
}, {
duration: 100
});
particles.push(particle);
}
// Create lightning trail effect that follows ball
function createLightningTrail() {
if (speedBoostActive) {
// Create zigzag lightning behind ball
for (var i = 0; i < 3; i++) {
var particle = game.addChild(new Particle());
// Create zigzag pattern
var angle = Math.random() * Math.PI * 2;
var distance = 40 + Math.random() * 60;
particle.x = ball.x - ball.velocityX * (i + 1) * 2 + Math.cos(angle) * distance;
particle.y = ball.y - ball.velocityY * (i + 1) * 2 + Math.sin(angle) * distance;
particle.velocityX = (Math.random() - 0.5) * 8;
particle.velocityY = (Math.random() - 0.5) * 8;
particle.life = 15;
particle.maxLife = 15;
tween(particle, {
tint: 0xFFFFFF,
scaleX: 1.5,
scaleY: 0.3
}, {
duration: 50,
onFinish: function onFinish() {
tween(particle, {
tint: 0xFFFF00,
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 100
});
}
});
particles.push(particle);
}
LK.setTimeout(createLightningTrail, 50);
}
}
createLightningTrail();
}
function activateExplosion(isAI) {
if (isAI) {
// AI version - use AI card
for (var i = 0; i < aiCards.length; i++) {
if (aiCards[i].cardType === 'explosion' && !aiCards[i].used && aiCards[i].cooldown <= 0 && aiCards[i].usageCount < aiCards[i].maxUsage) {
aiCards[i].used = true;
aiCards[i].cooldown = 300;
aiCards[i].usageCount++; // Increment AI card usage counter
// Track AI card usage
aiLastUsedCard = 'explosion';
aiCardUsageHistory.push({
type: 'explosion',
time: LK.ticks
});
// Create visual effect at AI paddle to show card usage
createParticles(aiPaddle.x, aiPaddle.y);
break;
}
}
}
explosionActive = true;
// Create multiple explosion waves
createExplosionEffect(ball.x, ball.y);
LK.setTimeout(function () {
createExplosionEffect(ball.x, ball.y);
}, 150);
LK.setTimeout(function () {
createExplosionEffect(ball.x, ball.y);
}, 300);
// Create expanding shockwave
tween(ball, {
scaleX: 3,
scaleY: 3,
alpha: 0.3
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(ball, {
scaleX: 1,
scaleY: 1,
alpha: 1
}, {
duration: 200
});
}
});
// Determine target based on who used explosion
var targetPaddle = isAI ? playerPaddle : aiPaddle;
var targetStunned = isAI ? 'playerStunned' : 'aiStunned';
var targetStunTimer = isAI ? 'playerStunTimer' : 'aiStunTimer';
// Make target paddle shake
var _shakeTarget = function shakeTarget() {
var isTargetStunned = isAI ? playerStunned : aiStunned;
if (isTargetStunned) {
var originalX = targetPaddle.x;
tween(targetPaddle, {
x: originalX + 5
}, {
duration: 50,
onFinish: function onFinish() {
tween(targetPaddle, {
x: originalX - 5
}, {
duration: 50,
onFinish: function onFinish() {
tween(targetPaddle, {
x: originalX
}, {
duration: 50,
onFinish: _shakeTarget
});
}
});
}
});
}
};
// Stun the correct target
if (isAI) {
playerStunned = true;
playerStunTimer = 300; // 5 seconds at 60fps
} else {
aiStunned = true;
aiStunTimer = 300; // 5 seconds at 60fps
}
// Visual effect for stunned target with shaking
tween(targetPaddle, {
tint: 0xFF0000
}, {
duration: 100
});
_shakeTarget();
}
function activatePierce(isAI) {
if (isAI) {
// AI version - use AI card
for (var i = 0; i < aiCards.length; i++) {
if (aiCards[i].cardType === 'pierce' && !aiCards[i].used && aiCards[i].cooldown <= 0 && aiCards[i].usageCount < aiCards[i].maxUsage) {
aiCards[i].used = true;
aiCards[i].cooldown = 300;
aiCards[i].usageCount++; // Increment AI card usage counter
// Track AI card usage
aiLastUsedCard = 'pierce';
aiCardUsageHistory.push({
type: 'pierce',
time: LK.ticks
});
// Create visual effect at AI paddle to show card usage
createParticles(aiPaddle.x, aiPaddle.y);
break;
}
}
}
pierceActive = true;
pierceTimer = 180; // 3 seconds at 60fps
pierceUser = isAI ? 'ai' : 'player'; // Track who used pierce
// Pierce animation with glowing effect
tween(ball, {
tint: 0x44FF44
}, {
duration: 200
});
// Make ball semi-transparent when AI uses pierce to show it's non-collidable
if (isAI) {
tween(ball, {
alpha: 0.5
}, {
duration: 200
});
}
// Create rotating energy effect
function createEnergyRing() {
if (pierceActive) {
for (var i = 0; i < 6; i++) {
var particle = game.addChild(new Particle());
var angle = i / 6 * Math.PI * 2;
var radius = 50;
particle.x = ball.x + Math.cos(angle) * radius;
particle.y = ball.y + Math.sin(angle) * radius;
particle.velocityX = Math.cos(angle) * 3;
particle.velocityY = Math.sin(angle) * 3;
particle.life = 15;
particle.maxLife = 15;
tween(particle, {
tint: 0x44FF44
}, {
duration: 100
});
particles.push(particle);
}
LK.setTimeout(createEnergyRing, 200);
}
}
createEnergyRing();
// Create glowing aura
tween(ball, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 300,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (pierceActive) {
tween(ball, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 300,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (pierceActive) {
activatePierce();
}
}
});
}
}
});
// Auto-disable pierce after exactly 3 seconds
LK.setTimeout(function () {
if (pierceActive) {
pierceActive = false;
pierceTimer = 0;
pierceUser = null;
// Reset ball to original state
tween(ball, {
tint: 0xFFFFFF,
scaleX: 1,
scaleY: 1,
alpha: 1
}, {
duration: 200,
easing: tween.easeOut
});
}
}, 3000);
}
function activateIllusion(isAI) {
if (isAI) {
// AI version - use AI card
for (var i = 0; i < aiCards.length; i++) {
if (aiCards[i].cardType === 'illusion' && !aiCards[i].used && aiCards[i].cooldown <= 0 && aiCards[i].usageCount < aiCards[i].maxUsage) {
aiCards[i].used = true;
aiCards[i].cooldown = 300;
aiCards[i].usageCount++;
// Track AI card usage
aiLastUsedCard = 'illusion';
aiCardUsageHistory.push({
type: 'illusion',
time: LK.ticks
});
// Create visual effect at AI paddle to show card usage
createParticles(aiPaddle.x, aiPaddle.y);
break;
}
}
}
illusionActive = true;
illusionTimer = 300; // 5 seconds at 60fps
// Clear any existing illusion balls
for (var i = illusionBalls.length - 1; i >= 0; i--) {
illusionBalls[i].destroy();
}
illusionBalls = [];
// Create 4 fake balls around the real ball
for (var i = 0; i < 4; i++) {
var fakeBall = game.addChild(new Ball());
var angle = i / 4 * Math.PI * 2;
var radius = 80 + Math.random() * 40;
fakeBall.x = ball.x + Math.cos(angle) * radius;
fakeBall.y = ball.y + Math.sin(angle) * radius;
// Make fake balls move at exactly the same speed as real ball
fakeBall.velocityX = ball.velocityX;
fakeBall.velocityY = ball.velocityY;
fakeBall.speed = ball.speed;
// Make fake balls same size as real ball
fakeBall.scaleX = 1;
fakeBall.scaleY = 1;
fakeBall.alpha = 0.8;
fakeBall.tint = 0x9966cc;
illusionBalls.push(fakeBall);
// Add floating animation to fake balls
tween(fakeBall, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 500,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (illusionActive) {
tween(fakeBall, {
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 500,
easing: tween.easeInOut
});
}
}
});
}
// Add shimmer effect to real ball
tween(ball, {
tint: 0x9966cc,
alpha: 0.9
}, {
duration: 200
});
// Create magical particles around all balls
function createMagicalParticles() {
if (illusionActive) {
// Particles around real ball
for (var i = 0; i < 3; i++) {
var particle = game.addChild(new Particle());
var angle = Math.random() * Math.PI * 2;
var radius = 50;
particle.x = ball.x + Math.cos(angle) * radius;
particle.y = ball.y + Math.sin(angle) * radius;
particle.velocityX = Math.cos(angle) * 2;
particle.velocityY = Math.sin(angle) * 2;
particle.life = 25;
particle.maxLife = 25;
tween(particle, {
tint: 0xcc66ff
}, {
duration: 100
});
particles.push(particle);
}
// Particles around fake balls
for (var j = 0; j < illusionBalls.length; j++) {
var fakeBall = illusionBalls[j];
if (fakeBall && !fakeBall.destroyed) {
var particle = game.addChild(new Particle());
var angle = Math.random() * Math.PI * 2;
var radius = 40;
particle.x = fakeBall.x + Math.cos(angle) * radius;
particle.y = fakeBall.y + Math.sin(angle) * radius;
particle.velocityX = Math.cos(angle) * 1.5;
particle.velocityY = Math.sin(angle) * 1.5;
particle.life = 20;
particle.maxLife = 20;
tween(particle, {
tint: 0x9966cc
}, {
duration: 100
});
particles.push(particle);
}
}
LK.setTimeout(createMagicalParticles, 300);
}
}
createMagicalParticles();
}
function activateSlow(isAI) {
if (isAI) {
// AI version - use AI card
for (var i = 0; i < aiCards.length; i++) {
if (aiCards[i].cardType === 'slow' && !aiCards[i].used && aiCards[i].cooldown <= 0 && aiCards[i].usageCount < aiCards[i].maxUsage) {
aiCards[i].used = true;
aiCards[i].cooldown = 300;
aiCards[i].usageCount++; // Increment AI card usage counter
// Track AI card usage
aiLastUsedCard = 'slow';
aiCardUsageHistory.push({
type: 'slow',
time: LK.ticks
});
// Create visual effect at AI paddle to show card usage
createParticles(aiPaddle.x, aiPaddle.y);
break;
}
}
}
slowActive = true;
slowTimer = 300; // 5 seconds at 60fps
ball.speed = 6;
// Slow animation with ice effect
tween(ball, {
tint: 0x4444FF
}, {
duration: 200
});
tween(ball, {
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 200,
easing: tween.easeOut
});
// Create ice crystal particles
function createIceCrystals() {
if (slowActive) {
for (var i = 0; i < 8; i++) {
var particle = game.addChild(new Particle());
var angle = i / 8 * Math.PI * 2;
var radius = 60;
particle.x = ball.x + Math.cos(angle) * radius;
particle.y = ball.y + Math.sin(angle) * radius;
particle.velocityX = Math.cos(angle) * 2;
particle.velocityY = Math.sin(angle) * 2;
particle.life = 30;
particle.maxLife = 30;
tween(particle, {
tint: 0x88CCFF
}, {
duration: 150
});
particles.push(particle);
}
LK.setTimeout(createIceCrystals, 400);
}
}
createIceCrystals();
// Create freezing aura that pulses
function createFreezingAura() {
if (slowActive) {
tween(ball, {
scaleX: 0.6,
scaleY: 0.6
}, {
duration: 500,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (slowActive) {
tween(ball, {
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 500,
easing: tween.easeInOut,
onFinish: createFreezingAura
});
}
}
});
}
}
createFreezingAura();
}
function createExplosionEffect(x, y) {
// Create screen shake effect
var originalX = game.x;
var originalY = game.y;
tween(game, {
x: originalX + 10,
y: originalY + 10
}, {
duration: 50,
onFinish: function onFinish() {
tween(game, {
x: originalX - 10,
y: originalY - 10
}, {
duration: 50,
onFinish: function onFinish() {
tween(game, {
x: originalX,
y: originalY
}, {
duration: 50
});
}
});
}
});
// Create explosion particles with color variations
for (var i = 0; i < 15; i++) {
var particle = game.addChild(new Particle());
particle.x = x + (Math.random() - 0.5) * 120;
particle.y = y + (Math.random() - 0.5) * 120;
particle.velocityX = (Math.random() - 0.5) * 15;
particle.velocityY = (Math.random() - 0.5) * 15;
particle.life = 40;
particle.maxLife = 40;
// Add color tinting with tween
var colors = [0xff4444, 0xffaa44, 0xffff44, 0xff8844];
var randomColor = colors[Math.floor(Math.random() * colors.length)];
tween(particle, {
tint: randomColor
}, {
duration: 200
});
particles.push(particle);
}
}
function checkPaddleCollision(paddle, ball) {
var paddleLeft = paddle.x - 100;
var paddleRight = paddle.x + 100;
var paddleTop = paddle.y - 20;
var paddleBottom = paddle.y + 20;
var ballLeft = ball.x - 30;
var ballRight = ball.x + 30;
var ballTop = ball.y - 30;
var ballBottom = ball.y + 30;
return ballRight > paddleLeft && ballLeft < paddleRight && ballBottom > paddleTop && ballTop < paddleBottom;
}
game.down = function (x, y, obj) {
// Don't handle paddle movement during tutorial
if (tutorialOverlay.visible) {
return;
}
touchX = x;
if (!playerStunned) {
playerPaddle.moveTowards(x);
}
};
game.move = function (x, y, obj) {
// Don't handle paddle movement during tutorial
if (tutorialOverlay.visible) {
return;
}
touchX = x;
if (!playerStunned) {
playerPaddle.moveTowards(x);
}
// Card hover effects removed
};
game.update = function () {
// Don't run game logic during tutorial
if (tutorialOverlay.visible) {
return;
}
// Handle power-up timers
if (speedBoostActive) {
speedBoostTimer--;
if (speedBoostTimer <= 0) {
speedBoostActive = false;
ball.speed = 12;
tween(ball, {
tint: 0xFFFFFF
}, {
duration: 200
});
tween(ball, {
scaleX: 1,
scaleY: 1
}, {
duration: 200,
easing: tween.easeOut
});
}
}
if (slowActive) {
slowTimer--;
if (slowTimer <= 0) {
slowActive = false;
ball.speed = 12;
tween(ball, {
tint: 0xFFFFFF
}, {
duration: 200
});
tween(ball, {
scaleX: 1,
scaleY: 1
}, {
duration: 200,
easing: tween.easeOut
});
}
}
if (illusionActive) {
illusionTimer--;
if (illusionTimer <= 0) {
illusionActive = false;
// Reset real ball appearance
tween(ball, {
tint: 0xFFFFFF,
alpha: 1
}, {
duration: 300
});
// Remove all fake balls with fade effect
for (var i = 0; i < illusionBalls.length; i++) {
var fakeBall = illusionBalls[i];
if (fakeBall && !fakeBall.destroyed) {
tween(fakeBall, {
alpha: 0,
scaleX: 0.5,
scaleY: 0.5
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
if (fakeBall && !fakeBall.destroyed) {
fakeBall.destroy();
}
}
});
}
}
illusionBalls = [];
}
}
if (pierceActive) {
pierceTimer--;
if (pierceTimer <= 0) {
pierceActive = false;
pierceUser = null; // Reset pierce user
tween(ball, {
tint: 0xFFFFFF,
alpha: 1
}, {
duration: 200
});
tween(ball, {
scaleX: 1,
scaleY: 1
}, {
duration: 200,
easing: tween.easeOut
});
}
}
if (aiStunned) {
aiStunTimer--;
if (aiStunTimer <= 0) {
aiStunned = false;
tween(aiPaddle, {
tint: 0xFFFFFF
}, {
duration: 200
});
}
}
if (playerStunned) {
playerStunTimer--;
if (playerStunTimer <= 0) {
playerStunned = false;
tween(playerPaddle, {
tint: 0xFFFFFF
}, {
duration: 200
});
}
}
// Update fake balls during illusion
if (illusionActive) {
for (var i = illusionBalls.length - 1; i >= 0; i--) {
var fakeBall = illusionBalls[i];
if (fakeBall && !fakeBall.destroyed) {
// Apply speed boost effect to fake balls too
if (speedBoostActive) {
fakeBall.speed = 24;
} else if (slowActive) {
fakeBall.speed = 6;
} else {
fakeBall.speed = 12;
}
// Update fake ball position
fakeBall.x += fakeBall.velocityX;
fakeBall.y += fakeBall.velocityY;
// Bounce fake balls off walls
if (fakeBall.x <= 30 || fakeBall.x >= 2018) {
fakeBall.velocityX = -fakeBall.velocityX;
}
// Remove fake balls that go off screen
if (fakeBall.y < -100 || fakeBall.y > 2832) {
fakeBall.destroy();
illusionBalls.splice(i, 1);
}
} else {
illusionBalls.splice(i, 1);
}
}
}
// AI paddle follows ball with some delay (unless stunned)
if (!aiStunned) {
var targetBall = ball; // Default to real ball
// If illusion is active, AI gets confused and targets random ball
if (illusionActive && illusionBalls.length > 0) {
// AI picks a random ball to follow (including real ball)
var allBalls = [ball];
for (var i = 0; i < illusionBalls.length; i++) {
if (illusionBalls[i] && !illusionBalls[i].destroyed) {
allBalls.push(illusionBalls[i]);
}
}
// AI randomly switches target every 30 frames during illusion
if (LK.ticks % 30 === 0) {
targetBall = allBalls[Math.floor(Math.random() * allBalls.length)];
} else if (game.aiTargetBall && !game.aiTargetBall.destroyed) {
targetBall = game.aiTargetBall;
}
game.aiTargetBall = targetBall;
}
var targetX = targetBall.x + targetBall.velocityX * 10;
if (targetX < 100) targetX = 100;
if (targetX > 1948) targetX = 1948;
aiPaddle.moveTowards(targetX);
}
// AI power-up usage logic with strategic decision making
aiPowerUpTimer++;
if (aiPowerUpTimer >= aiPowerUpCooldown) {
// Use the ball AI is currently tracking for strategic decisions
var currentTargetBall = ball;
if (illusionActive && game.aiTargetBall && !game.aiTargetBall.destroyed) {
currentTargetBall = game.aiTargetBall;
}
// Calculate strategic variables based on AI's current target
var ballDistanceToAI = Math.abs(currentTargetBall.y - aiPaddle.y);
var ballDistanceToPlayer = Math.abs(currentTargetBall.y - playerPaddle.y);
var ballMovingTowardAI = currentTargetBall.velocityY < 0;
var ballMovingTowardPlayer = currentTargetBall.velocityY > 0;
var aiScore_playerScore_diff = aiScore - playerScore;
var ballSpeed = Math.sqrt(currentTargetBall.velocityX * currentTargetBall.velocityX + currentTargetBall.velocityY * currentTargetBall.velocityY);
var timeToReachAI = ballDistanceToAI / Math.abs(currentTargetBall.velocityY);
var timeToReachPlayer = ballDistanceToPlayer / Math.abs(currentTargetBall.velocityY);
var paddleCanReach = Math.abs(aiPaddle.x - (currentTargetBall.x + currentTargetBall.velocityX * timeToReachAI)) < 150;
var ballNearAIGoal = currentTargetBall.y < 542 && ballMovingTowardAI;
var ballNearPlayerGoal = currentTargetBall.y > 2190 && ballMovingTowardPlayer;
var needsToScore = aiScore_playerScore_diff < 0;
var gameTimeRunningOut = gameTime < 30;
// Priority 1: Critical defense - ball about to hit AI goal
if (ballNearAIGoal && ballMovingTowardAI && ballDistanceToAI < 550) {
// Use slow to prevent goal when ball is about to hit AI castle
for (var i = 0; i < aiCards.length; i++) {
if (aiCards[i].cardType === 'slow' && !aiCards[i].used && aiCards[i].cooldown <= 0 && aiCards[i].usageCount < aiCards[i].maxUsage) {
activateSlow(true);
aiPowerUpTimer = 0;
aiPowerUpCooldown = 180; // Quick cooldown for critical defense
return;
}
}
// If no slow available, use explosion as backup
for (var i = 0; i < aiCards.length; i++) {
if (aiCards[i].cardType === 'explosion' && !aiCards[i].used && aiCards[i].cooldown <= 0 && aiCards[i].usageCount < aiCards[i].maxUsage) {
activateExplosion(true);
aiPowerUpTimer = 0;
aiPowerUpCooldown = 180;
return;
}
}
}
// Priority 2: Aggressive scoring when AI needs points and ball is approaching AI
if ((needsToScore || gameTimeRunningOut) && ballMovingTowardAI && ballDistanceToAI < 600 && ballDistanceToAI > 200) {
// Use pierce to score when ball is approaching and AI needs points
for (var i = 0; i < aiCards.length; i++) {
if (aiCards[i].cardType === 'pierce' && !aiCards[i].used && aiCards[i].cooldown <= 0 && aiCards[i].usageCount < aiCards[i].maxUsage) {
activatePierce(true);
aiPowerUpTimer = 0;
aiPowerUpCooldown = 250;
return;
}
}
}
// Priority 3: Speed boost when AI can't reach ball in time
if (ballMovingTowardAI && ballDistanceToAI < 500 && !paddleCanReach && timeToReachAI < 45) {
// Use speed boost to make ball move faster so AI can potentially reach it
for (var i = 0; i < aiCards.length; i++) {
if (aiCards[i].cardType === 'speed' && !aiCards[i].used && aiCards[i].cooldown <= 0 && aiCards[i].usageCount < aiCards[i].maxUsage) {
activateSpeedBoost(true);
aiPowerUpTimer = 0;
aiPowerUpCooldown = 300;
return;
}
}
}
// Priority 4: Explosion when ball is approaching AI (general defense)
if (ballMovingTowardAI && ballDistanceToAI < 400 && ballDistanceToAI > 100) {
// Use explosion to stun and disrupt when ball is approaching
for (var i = 0; i < aiCards.length; i++) {
if (aiCards[i].cardType === 'explosion' && !aiCards[i].used && aiCards[i].cooldown <= 0) {
activateExplosion(true);
aiPowerUpTimer = 0;
aiPowerUpCooldown = 320;
return;
}
}
}
// Priority 5: Opportunistic offensive moves
if (ballMovingTowardPlayer && needsToScore && Math.random() < 0.6) {
// Use speed when ball is going toward player and AI needs to score
for (var i = 0; i < aiCards.length; i++) {
if (aiCards[i].cardType === 'speed' && !aiCards[i].used && aiCards[i].cooldown <= 0) {
activateSpeedBoost(true);
aiPowerUpTimer = 0;
aiPowerUpCooldown = 400;
return;
}
}
}
// Priority 6: Strategic slow usage
if (ballMovingTowardPlayer && ballSpeed > 10 && ballDistanceToPlayer < 300 && Math.random() < 0.4) {
// Use slow to make it harder for player to return the ball
for (var i = 0; i < aiCards.length; i++) {
if (aiCards[i].cardType === 'slow' && !aiCards[i].used && aiCards[i].cooldown <= 0) {
activateSlow(true);
aiPowerUpTimer = 0;
aiPowerUpCooldown = 350;
return;
}
}
}
// Priority 7: Illusion when ball is moving toward player and AI wants to confuse
if (ballMovingTowardPlayer && ballDistanceToPlayer < 800 && Math.random() < 0.3) {
// Use illusion to confuse player when ball is approaching them
for (var i = 0; i < aiCards.length; i++) {
if (aiCards[i].cardType === 'illusion' && !aiCards[i].used && aiCards[i].cooldown <= 0 && aiCards[i].usageCount < aiCards[i].maxUsage) {
activateIllusion(true);
aiPowerUpTimer = 0;
aiPowerUpCooldown = 400;
return;
}
}
}
// Priority 8: Random usage with low probability to add unpredictability
if (Math.random() < 0.1) {
var availableCards = [];
for (var i = 0; i < aiCards.length; i++) {
if (!aiCards[i].used && aiCards[i].cooldown <= 0 && aiCards[i].usageCount < aiCards[i].maxUsage) {
availableCards.push(aiCards[i].cardType);
}
}
if (availableCards.length > 0) {
var randomCard = availableCards[Math.floor(Math.random() * availableCards.length)];
if (randomCard === 'speed') {
activateSpeedBoost(true);
} else if (randomCard === 'explosion') {
activateExplosion(true);
} else if (randomCard === 'pierce') {
activatePierce(true);
} else if (randomCard === 'slow') {
activateSlow(true);
} else if (randomCard === 'illusion') {
activateIllusion(true);
}
aiPowerUpTimer = 0;
aiPowerUpCooldown = 500 + Math.random() * 200;
}
}
}
// Check paddle collisions
if (checkPaddleCollision(playerPaddle, ball) && !(pierceActive && pierceUser === 'ai')) {
if (ball.velocityY > 0) {
ball.velocityY = -ball.velocityY;
var hitOffset = (ball.x - playerPaddle.x) / 100;
ball.velocityX += hitOffset * 2;
createParticles(ball.x, ball.y);
LK.getSound('paddleHit').play();
}
}
if (checkPaddleCollision(aiPaddle, ball) && !(pierceActive && pierceUser === 'player')) {
if (ball.velocityY < 0) {
ball.velocityY = -ball.velocityY;
var hitOffset = (ball.x - aiPaddle.x) / 100;
ball.velocityX += hitOffset * 2;
createParticles(ball.x, ball.y);
LK.getSound('paddleHit').play();
}
}
// Check goal scoring
if (ball.y < 90) {
playerScore++;
playerScoreText.setText(playerScore.toString());
LK.setScore(playerScore);
ball.reset();
LK.getSound('goal').play();
}
if (ball.y > 2642) {
aiScore++;
aiScoreText.setText(aiScore.toString());
ball.reset();
LK.getSound('goal').play();
}
// Check collision with castle areas to create explosion particles
if (ball.y <= 422 && ball.y >= 90 && ball.x >= 200 && ball.x <= 1848) {
// Ball hit AI castle/houses area
createExplosionEffect(ball.x, ball.y);
}
if (ball.y >= 2310 && ball.y <= 2642 && ball.x >= 200 && ball.x <= 1848) {
// Ball hit player castle/houses area
createExplosionEffect(ball.x, ball.y);
}
// Limit ball speed
var maxSpeed = 12;
var currentSpeed = Math.sqrt(ball.velocityX * ball.velocityX + ball.velocityY * ball.velocityY);
if (currentSpeed > maxSpeed) {
ball.velocityX = ball.velocityX / currentSpeed * maxSpeed;
ball.velocityY = ball.velocityY / currentSpeed * maxSpeed;
}
};